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"
113#include "tide_time.h"
120#include "s57_ocpn_utils.h"
123#include "androidUTIL.h"
133#include <wx/msw/msvcrt.h>
142#define printf printf2
144int __cdecl printf2(
const char *format, ...) {
148 va_start(argptr, format);
149 int ret = vsnprintf(str,
sizeof(str), format, argptr);
151 OutputDebugStringA(str);
156#if defined(__MSVC__) && (_MSC_VER < 1700)
157#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
163#define OCPN_ALT_MENUBAR 1
171extern ColorScheme global_color_scheme;
172extern wxColor GetDimColor(wxColor c);
174static bool g_bSmoothRecenter =
true;
175static bool bDrawCurrentValues;
196static bool mouse_leftisdown;
197static bool g_brouteCreating;
198static int r_gamma_mult;
199static int g_gamma_mult;
200static int b_gamma_mult;
201static int gamma_state;
202static bool g_brightness_init;
203static int last_brightness;
204static wxGLContext *g_pGLcontext;
207static wxDialog *g_pcurtain;
209static wxString g_lastS52PLIBPluginMessage;
212#define MAX_BRIGHT 100
219EVT_ACTIVATE(ChartCanvas::OnActivate)
220EVT_SIZE(ChartCanvas::OnSize)
221#ifndef HAVE_WX_GESTURE_EVENTS
222EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
224EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
225EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
226EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
227EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
228EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
229EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
230EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
231EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
232EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
233EVT_KEY_UP(ChartCanvas::OnKeyUp)
234EVT_CHAR(ChartCanvas::OnKeyChar)
235EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
236EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
237EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
238EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
239EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
240EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
241EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
242EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
243EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
244EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
250 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
251 m_nmea_log(nmea_log) {
252 parent_frame = (
MyFrame *)frame;
253 m_canvasIndex = canvasIndex;
257 SetBackgroundColour(wxColour(0, 0, 0));
258 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
262 m_bDrawingRoute =
false;
263 m_bRouteEditing =
false;
264 m_bMarkEditing =
false;
265 m_bRoutePoinDragging =
false;
266 m_bIsInRadius =
false;
267 m_bMayToggleMenuBar =
true;
270 m_bShowNavobjects =
true;
272 m_bAppendingRoute =
false;
273 pThumbDIBShow = NULL;
274 m_bShowCurrent =
false;
276 bShowingCurrent =
false;
280 m_b_paint_enable =
true;
283 pss_overlay_bmp = NULL;
284 pss_overlay_mask = NULL;
285 m_bChartDragging =
false;
286 m_bMeasure_Active =
false;
287 m_bMeasure_DistCircle =
false;
288 m_pMeasureRoute = NULL;
289 m_pTrackRolloverWin = NULL;
290 m_pRouteRolloverWin = NULL;
291 m_pAISRolloverWin = NULL;
293 m_disable_edge_pan =
false;
294 m_dragoffsetSet =
false;
298 m_singleChart = NULL;
299 m_upMode = NORTH_UP_MODE;
301 m_bShowAISScaled =
false;
302 m_timed_move_vp_active =
false;
304 m_disable_adjust_on_zoom =
false;
311 m_pSelectedRoute = NULL;
312 m_pSelectedTrack = NULL;
313 m_pRoutePointEditTarget = NULL;
314 m_pFoundPoint = NULL;
315 m_pMouseRoute = NULL;
316 m_prev_pMousePoint = NULL;
317 m_pEditRouteArray = NULL;
318 m_pFoundRoutePoint = NULL;
319 m_FinishRouteOnKillFocus =
true;
321 m_pRolloverRouteSeg = NULL;
322 m_pRolloverTrackSeg = NULL;
323 m_bsectors_shown =
false;
325 m_bbrightdir =
false;
330 m_pos_image_user_day = NULL;
331 m_pos_image_user_dusk = NULL;
332 m_pos_image_user_night = NULL;
333 m_pos_image_user_grey_day = NULL;
334 m_pos_image_user_grey_dusk = NULL;
335 m_pos_image_user_grey_night = NULL;
338 m_rotation_speed = 0;
344 m_pos_image_user_yellow_day = NULL;
345 m_pos_image_user_yellow_dusk = NULL;
346 m_pos_image_user_yellow_night = NULL;
348 SetOwnShipState(SHIP_INVALID);
350 undo =
new Undo(
this);
356 m_focus_indicator_pix = 1;
358 m_pCurrentStack = NULL;
359 m_bpersistent_quilt =
false;
360 m_piano_ctx_menu = NULL;
362 m_NotificationsList = NULL;
363 m_notification_button = NULL;
365 g_ChartNotRenderScaleFactor = 2.0;
366 m_bShowScaleInStatusBar =
true;
369 m_bShowScaleInStatusBar =
false;
370 m_show_focus_bar =
true;
372 m_bShowOutlines =
false;
373 m_bDisplayGrid =
false;
374 m_bShowDepthUnits =
true;
375 m_encDisplayCategory = (int)STANDARD;
377 m_encShowLights =
true;
378 m_encShowAnchor =
true;
379 m_encShowDataQual =
false;
381 m_pQuilt =
new Quilt(
this);
386 g_PrintingInProgress =
false;
388#ifdef HAVE_WX_GESTURE_EVENTS
389 m_oldVPSScale = -1.0;
390 m_popupWanted =
false;
393 m_inLongPress =
false;
396 m_sw_left_down.Start();
397 m_sw_left_up.Start();
401 singleClickEventIsValid =
false;
410 pCursorPencil = NULL;
415 SetCursor(*pCursorArrow);
417 pPanTimer =
new wxTimer(
this, m_MouseDragging);
420 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
421 pMovementTimer->Stop();
423 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
424 pMovementStopTimer->Stop();
426 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
427 pRotDefTimer->Stop();
429 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
430 m_DoubleClickTimer->Stop();
432 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
433 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
434 m_chart_drag_inertia_active =
false;
436 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
437 m_animationActive =
false;
438 m_menuTimer.SetOwner(
this, MENU_TIMER);
439 m_tap_timer.SetOwner(
this, TAP_TIMER);
443 m_panx_target_final = m_pany_target_final = 0;
444 m_panx_target_now = m_pany_target_now = 0;
447 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
448 pCurTrackTimer->Stop();
449 m_curtrack_timer_msec = 10;
451 m_wheelzoom_stop_oneshot = 0;
452 m_last_wheel_dir = 0;
454 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
456 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
458 m_rollover_popup_timer_msec = 20;
460 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
462 m_b_rot_hidef =
true;
467 m_upMode = NORTH_UP_MODE;
468 m_bLookAhead =
false;
472 m_cs = GLOBAL_COLOR_SCHEME_DAY;
475 VPoint.view_scale_ppm = 1;
479 m_canvas_scale_factor = 1.;
481 m_canvas_width = 1000;
483 m_overzoomTextWidth = 0;
484 m_overzoomTextHeight = 0;
493 m_pEM_Fathoms = NULL;
495 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
497 m_pEM_OverZoom = NULL;
499 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
507 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
510 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
513 double factor_dusk = 0.5;
514 double factor_night = 0.25;
517 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
519 int rimg_width = m_os_image_red_day.GetWidth();
520 int rimg_height = m_os_image_red_day.GetHeight();
522 m_os_image_red_dusk = m_os_image_red_day.Copy();
523 m_os_image_red_night = m_os_image_red_day.Copy();
525 for (
int iy = 0; iy < rimg_height; iy++) {
526 for (
int ix = 0; ix < rimg_width; ix++) {
527 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
528 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
529 m_os_image_red_day.GetGreen(ix, iy),
530 m_os_image_red_day.GetBlue(ix, iy));
531 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
532 hsv.value = hsv.value * factor_dusk;
533 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
534 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
536 hsv = wxImage::RGBtoHSV(rgb);
537 hsv.value = hsv.value * factor_night;
538 nrgb = wxImage::HSVtoRGB(hsv);
539 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
545 m_os_image_grey_day =
546 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
548 int gimg_width = m_os_image_grey_day.GetWidth();
549 int gimg_height = m_os_image_grey_day.GetHeight();
551 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
552 m_os_image_grey_night = m_os_image_grey_day.Copy();
554 for (
int iy = 0; iy < gimg_height; iy++) {
555 for (
int ix = 0; ix < gimg_width; ix++) {
556 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
557 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
558 m_os_image_grey_day.GetGreen(ix, iy),
559 m_os_image_grey_day.GetBlue(ix, iy));
560 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
561 hsv.value = hsv.value * factor_dusk;
562 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
563 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
565 hsv = wxImage::RGBtoHSV(rgb);
566 hsv.value = hsv.value * factor_night;
567 nrgb = wxImage::HSVtoRGB(hsv);
568 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
574 m_os_image_yellow_day = m_os_image_red_day.Copy();
576 gimg_width = m_os_image_yellow_day.GetWidth();
577 gimg_height = m_os_image_yellow_day.GetHeight();
579 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
580 m_os_image_yellow_night = m_os_image_red_day.Copy();
582 for (
int iy = 0; iy < gimg_height; iy++) {
583 for (
int ix = 0; ix < gimg_width; ix++) {
584 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
585 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
586 m_os_image_yellow_day.GetGreen(ix, iy),
587 m_os_image_yellow_day.GetBlue(ix, iy));
588 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
589 hsv.hue += 60. / 360.;
590 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
591 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
593 hsv = wxImage::RGBtoHSV(rgb);
594 hsv.value = hsv.value * factor_dusk;
595 hsv.hue += 60. / 360.;
596 nrgb = wxImage::HSVtoRGB(hsv);
597 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
599 hsv = wxImage::RGBtoHSV(rgb);
600 hsv.hue += 60. / 360.;
601 hsv.value = hsv.value * factor_night;
602 nrgb = wxImage::HSVtoRGB(hsv);
603 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
609 m_pos_image_red = &m_os_image_red_day;
610 m_pos_image_yellow = &m_os_image_yellow_day;
611 m_pos_image_grey = &m_os_image_grey_day;
615 m_pBrightPopup = NULL;
618 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
623 m_Piano =
new Piano(
this);
625 m_bShowCompassWin =
true;
627 m_Compass->SetScaleFactor(g_compass_scalefactor);
628 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
630 if (IsPrimaryCanvas()) {
632 m_notification_button->SetScaleFactor(g_compass_scalefactor);
633 m_notification_button->Show(
true);
636 m_pianoFrozen =
false;
638 SetMinSize(wxSize(200, 200));
640 m_displayScale = 1.0;
641#if defined(__WXOSX__) || defined(__WXGTK3__)
643 m_displayScale = GetContentScaleFactor();
645 VPoint.SetPixelScale(m_displayScale);
647#ifdef HAVE_WX_GESTURE_EVENTS
650 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
651 wxLogError(
"Failed to enable touch events");
656 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
657 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
659 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
660 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
662 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
663 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
665 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
666 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
671 auto ¬eman = NotificationManager::GetInstance();
673 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
674 evt_notificationlist_change_listener.Listen(
675 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
676 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
677 if (m_NotificationsList && m_NotificationsList->IsShown()) {
678 m_NotificationsList->ReloadNotificationList();
684ChartCanvas::~ChartCanvas() {
685 delete pThumbDIBShow;
693 delete pCursorPencil;
697 delete pMovementTimer;
698 delete pMovementStopTimer;
699 delete pCurTrackTimer;
701 delete m_DoubleClickTimer;
703 delete m_pTrackRolloverWin;
704 delete m_pRouteRolloverWin;
705 delete m_pAISRolloverWin;
706 delete m_pBrightPopup;
712 m_dc_route.SelectObject(wxNullBitmap);
715 delete pWorldBackgroundChart;
716 delete pss_overlay_bmp;
720 delete m_pEM_Fathoms;
722 delete m_pEM_OverZoom;
727 delete m_pos_image_user_day;
728 delete m_pos_image_user_dusk;
729 delete m_pos_image_user_night;
730 delete m_pos_image_user_grey_day;
731 delete m_pos_image_user_grey_dusk;
732 delete m_pos_image_user_grey_night;
733 delete m_pos_image_user_yellow_day;
734 delete m_pos_image_user_yellow_dusk;
735 delete m_pos_image_user_yellow_night;
739 if (!g_bdisable_opengl) {
742#if wxCHECK_VERSION(2, 9, 0)
743 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
750 MUIBar *muiBar = m_muiBar;
754 delete m_pCurrentStack;
759void ChartCanvas::SetupGridFont() {
760 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
762 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
764 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
765 FALSE, wxString(
"Arial"));
768void ChartCanvas::RebuildCursors() {
774 delete pCursorPencil;
778 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
782 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
783 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
784 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
785 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
786 wxImage ICursorPencil =
787 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
788 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
790#if !defined(__WXMSW__) && !defined(__WXQT__)
791 ICursorLeft.ConvertAlphaToMask(128);
792 ICursorRight.ConvertAlphaToMask(128);
793 ICursorUp.ConvertAlphaToMask(128);
794 ICursorDown.ConvertAlphaToMask(128);
795 ICursorPencil.ConvertAlphaToMask(10);
796 ICursorCross.ConvertAlphaToMask(10);
799 if (ICursorLeft.Ok()) {
800 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
801 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
802 pCursorLeft =
new wxCursor(ICursorLeft);
804 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
806 if (ICursorRight.Ok()) {
807 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
808 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
809 pCursorRight =
new wxCursor(ICursorRight);
811 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
813 if (ICursorUp.Ok()) {
814 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
815 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
816 pCursorUp =
new wxCursor(ICursorUp);
818 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
820 if (ICursorDown.Ok()) {
821 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
822 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
823 pCursorDown =
new wxCursor(ICursorDown);
825 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
827 if (ICursorPencil.Ok()) {
828 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
829 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
830 pCursorPencil =
new wxCursor(ICursorPencil);
832 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
834 if (ICursorCross.Ok()) {
835 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
836 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
837 pCursorCross =
new wxCursor(ICursorCross);
839 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
841 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
842 pPlugIn_Cursor = NULL;
845void ChartCanvas::CanvasApplyLocale() {
846 CreateDepthUnitEmbossMaps(m_cs);
847 CreateOZEmbossMapData(m_cs);
850void ChartCanvas::SetupGlCanvas() {
853 if (!g_bdisable_opengl) {
855 wxLogMessage(
"Creating glChartCanvas");
860 if (IsPrimaryCanvas()) {
867 wxGLContext *pctx =
new wxGLContext(m_glcc);
868 m_glcc->SetContext(pctx);
872 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
874 m_glcc->SetContext(g_pGLcontext);
884 if (!g_bdisable_opengl) {
887 wxLogMessage(
"Creating glChartCanvas");
891 if (IsPrimaryCanvas()) {
892 qDebug() <<
"Creating Primary glChartCanvas";
900 wxGLContext *pctx =
new wxGLContext(m_glcc);
901 m_glcc->SetContext(pctx);
903 m_glcc->m_pParentCanvas =
this;
906 qDebug() <<
"Creating Secondary glChartCanvas";
912 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
915 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
916 m_glcc->SetContext(pwxctx);
917 m_glcc->m_pParentCanvas =
this;
925void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
926 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
941 if (m_routeState && m_FinishRouteOnKillFocus)
942 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
944 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
948void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
949 m_routeFinishTimer.Stop();
953 gFrame->UpdateGlobalMenuItems(
this);
955 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
958void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
959 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
962#ifdef HAVE_WX_GESTURE_EVENTS
963void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
970 m_popupWanted =
true;
972 m_inLongPress = !g_bhide_context_menus;
975 m_menuPos =
event.GetPosition();
976 wxMouseEvent ev(wxEVT_LEFT_UP);
977 ev.m_x = m_menuPos.x;
978 ev.m_y = m_menuPos.y;
979 wxPostEvent(
this, ev);
983 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
984 ev_right_click.m_x = m_menuPos.x;
985 ev_right_click.m_y = m_menuPos.y;
986 MouseEvent(ev_right_click);
991void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
995void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
997void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
999void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1001 long dt = m_sw_left_up.Time() - m_sw_up_time;
1002 m_sw_up_time = m_sw_left_up.Time();
1013 wxPoint pos =
event.GetPosition();
1017 if (!m_popupWanted) {
1018 wxMouseEvent ev(wxEVT_LEFT_UP);
1025 m_popupWanted =
false;
1027 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1034void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1039 long dt = m_sw_left_down.Time() - m_sw_down_time;
1040 m_sw_down_time = m_sw_left_down.Time();
1064 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1066 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1067 m_lastTapPos.y - max_double_click_distance,
1068 max_double_click_distance * 2, max_double_click_distance * 2);
1071 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1077 m_lastTapPos =
event.GetPosition();
1078 m_tap_timer.StartOnce(
1082 if (m_tap_count == 2) {
1086 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1099void ChartCanvas::OnMotion(wxMouseEvent &event) {
1104 event.m_leftDown = m_leftdown;
1108void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1110 if (event.IsGestureEnd())
return;
1112 double factor =
event.GetZoomFactor();
1114 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1119 double wanted_factor = m_oldVPSScale / current_vps * factor;
1124 if (event.IsGestureStart()) {
1125 m_zoomStartPoint =
event.GetPosition();
1127 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1129 m_zoomStartPoint =
event.GetPosition();
1133void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1135void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1136 DoRotateCanvas(0.0);
1140void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1145void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1146 m_FinishRouteOnKillFocus =
false;
1147 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1148 m_FinishRouteOnKillFocus =
true;
1151void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1156 m_restore_dbindex = pcc->DBindex;
1158 if (pcc->GroupID < 0) pcc->GroupID = 0;
1163 m_groupIndex = pcc->GroupID;
1165 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1179 m_encDisplayCategory = pcc->nENCDisplayCategory;
1180 m_encShowDepth = pcc->bShowENCDepths;
1181 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1182 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1183 m_encShowLights = pcc->bShowENCLights;
1184 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1185 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1186 m_encShowDataQual = pcc->bShowENCDataQuality;
1190 m_upMode = NORTH_UP_MODE;
1192 m_upMode = COURSE_UP_MODE;
1194 m_upMode = HEAD_UP_MODE;
1198 m_singleChart = NULL;
1201void ChartCanvas::ApplyGlobalSettings() {
1204 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1205 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1207 if (m_notification_button) m_notification_button->UpdateStatus();
1210void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1211 bool groupOK = CheckGroup(m_groupIndex);
1214 SetGroupIndex(m_groupIndex,
true);
1218void ChartCanvas::SetShowGPS(
bool bshow) {
1219 if (m_bShowGPS != bshow) {
1222 m_Compass->SetScaleFactor(g_compass_scalefactor);
1223 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1228void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1229 m_bShowCompassWin = bshow;
1231 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1232 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1236int ChartCanvas::GetPianoHeight() {
1238 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1243void ChartCanvas::ConfigureChartBar() {
1246 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1247 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1249 if (GetQuiltMode()) {
1250 m_Piano->SetRoundedRectangles(
true);
1252 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1253 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1254 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1257void ChartCanvas::ShowTides(
bool bShow) {
1258 gFrame->LoadHarmonics();
1261 SetbShowTide(bShow);
1263 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1265 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1266 SetbShowTide(
false);
1267 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1270 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1271 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1282void ChartCanvas::ShowCurrents(
bool bShow) {
1283 gFrame->LoadHarmonics();
1286 SetbShowCurrent(bShow);
1287 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1289 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1290 SetbShowCurrent(
false);
1291 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1294 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1295 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1312void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1314void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1317 int new_index = index;
1320 bool bgroup_override =
false;
1321 int old_group_index = new_index;
1323 if (!CheckGroup(new_index)) {
1325 bgroup_override =
true;
1328 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1332 int current_chart_native_scale = GetCanvasChartNativeScale();
1335 m_groupIndex = new_index;
1341 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1345 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1349 g_sticky_chart = -1;
1353 UpdateCanvasOnGroupChange();
1356 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1358 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1361 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1362 double best_scale = GetBestStartScale(dbi_hint, vp);
1366 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1370 canvasChartsRefresh(dbi_hint);
1372 UpdateCanvasControlBar();
1374 if (!autoSwitch && bgroup_override) {
1376 wxString msg(_(
"Group \""));
1379 msg += pGroup->m_group_name;
1381 msg += _(
"\" is empty.");
1383 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1390 if (bgroup_override) {
1391 wxString msg(_(
"Group \""));
1394 msg += pGroup->m_group_name;
1396 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1398 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1402bool ChartCanvas::CheckGroup(
int igroup) {
1405 if (igroup == 0)
return true;
1412 if (pGroup->m_element_array.empty())
1416 for (
const auto &elem : pGroup->m_element_array) {
1417 for (
unsigned int ic = 0;
1418 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1420 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1422 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1427 for (
const auto &elem : pGroup->m_element_array) {
1428 const wxString &element_root = elem.m_element_name;
1429 wxString test_string =
"GSHH";
1430 if (element_root.Upper().Contains(test_string))
return true;
1436void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1439 AbstractPlatform::ShowBusySpinner();
1443 SetQuiltRefChart(-1);
1445 m_singleChart = NULL;
1451 if (!m_pCurrentStack) {
1453 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1456 if (-1 != dbi_hint) {
1457 if (GetQuiltMode()) {
1458 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1459 SetQuiltRefChart(dbi_hint);
1463 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1465 if (pTentative_Chart) {
1468 if (m_singleChart) m_singleChart->Deactivate();
1470 m_singleChart = pTentative_Chart;
1471 m_singleChart->Activate();
1473 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1474 GetpCurrentStack(), m_singleChart->GetFullPath());
1482 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1483 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1484 SetQuiltRefChart(selected_index);
1488 SetupCanvasQuiltMode();
1489 if (!GetQuiltMode() && m_singleChart == 0) {
1491 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1492 m_singleChart = pDummyChart;
1498 UpdateCanvasControlBar();
1499 UpdateGPSCompassStatusBox(
true);
1501 SetCursor(wxCURSOR_ARROW);
1503 AbstractPlatform::HideBusySpinner();
1506bool ChartCanvas::DoCanvasUpdate() {
1508 double vpLat, vpLon;
1509 bool blong_jump =
false;
1510 meters_to_shift = 0;
1513 bool bNewChart =
false;
1514 bool bNewView =
false;
1515 bool bCanvasChartAutoOpen =
true;
1517 bool bNewPiano =
false;
1518 bool bOpenSpecified;
1524 if (bDBUpdateInProgress)
return false;
1528 if (m_chart_drag_inertia_active)
return false;
1554 double dx = m_OSoffsetx;
1555 double dy = m_OSoffsety;
1559 if (GetUpMode() == NORTH_UP_MODE) {
1560 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1562 double offset_angle = atan2(d_north, d_east);
1563 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1564 double chart_angle = GetVPRotation();
1565 double target_angle = chart_angle + offset_angle;
1566 double d_east_mod = offset_distance * cos(target_angle);
1567 double d_north_mod = offset_distance * sin(target_angle);
1568 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1572 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1573 double cog_to_use =
gCog;
1575 (fabs(
gCog - gCog_gt) > 20)) {
1576 cog_to_use = gCog_gt;
1579 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1581 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1583 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1584 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1586 double pixel_delta_tent =
1587 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1589 double pixel_delta = 0;
1594 if (!std::isnan(
gSog)) {
1598 pixel_delta = pixel_delta_tent;
1601 meters_to_shift = 0;
1603 if (!std::isnan(
gCog)) {
1604 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1605 dir_to_shift = cog_to_use;
1606 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1612 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1626 if (GetQuiltMode()) {
1627 int current_db_index = -1;
1628 if (m_pCurrentStack)
1631 ->GetCurrentEntrydbIndex();
1639 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1641 if (m_pCurrentStack->nEntry) {
1642 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1644 SelectQuiltRefdbChart(new_dbIndex,
true);
1645 m_bautofind =
false;
1649 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1650 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1655 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1661 double proposed_scale_onscreen =
1664 int initial_db_index = m_restore_dbindex;
1665 if (initial_db_index < 0) {
1666 if (m_pCurrentStack->nEntry) {
1668 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1673 if (m_pCurrentStack->nEntry) {
1674 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1679 if (!IsChartQuiltableRef(initial_db_index)) {
1683 int stack_index = 0;
1685 if (stack_index >= 0) {
1686 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1687 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1688 if (IsChartQuiltableRef(test_db_index) &&
1690 ChartData->GetDBChartType(initial_db_index))) {
1691 initial_db_index = test_db_index;
1701 SetQuiltRefChart(initial_db_index);
1702 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1710 0, GetVPRotation());
1715 bool super_jump =
false;
1717 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1718 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1719 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1722 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1724 if (blong_jump) nstep = 20;
1725 StartTimedMovementVP(vpLat, vpLon, nstep);
1736 pLast_Ch = m_singleChart;
1737 ChartTypeEnum new_open_type;
1738 ChartFamilyEnum new_open_family;
1740 new_open_type = pLast_Ch->GetChartType();
1741 new_open_family = pLast_Ch->GetChartFamily();
1743 new_open_type = CHART_TYPE_KAP;
1744 new_open_family = CHART_FAMILY_RASTER;
1747 bOpenSpecified = m_bFirstAuto;
1750 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1753 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1755 if (NULL == pDummyChart) {
1761 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1763 m_singleChart = pDummyChart;
1768 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1770 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1773 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1774 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1781 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1787 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1792 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1795 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1800 if (NULL != m_singleChart)
1801 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1802 m_singleChart->GetFullPath());
1805 m_pCurrentStack->CurrentStackEntry = tEntry;
1815 if (bCanvasChartAutoOpen) {
1816 bool search_direction =
1818 int start_index = 0;
1822 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1823 (LastStack.nEntry == 0)) {
1824 search_direction =
true;
1825 start_index = m_pCurrentStack->nEntry - 1;
1829 if (bOpenSpecified) {
1830 search_direction =
false;
1832 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1835 new_open_type = CHART_TYPE_DONTCARE;
1838 pProposed =
ChartData->OpenStackChartConditional(
1839 m_pCurrentStack, start_index, search_direction, new_open_type,
1843 if (NULL == pProposed)
1844 pProposed =
ChartData->OpenStackChartConditional(
1845 m_pCurrentStack, start_index, search_direction,
1846 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1848 if (NULL == pProposed)
1849 pProposed =
ChartData->OpenStackChartConditional(
1850 m_pCurrentStack, start_index, search_direction,
1851 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1862 if (NULL == pProposed) {
1863 if (NULL == pDummyChart) {
1869 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1871 pProposed = pDummyChart;
1875 if (m_singleChart) m_singleChart->Deactivate();
1876 m_singleChart = pProposed;
1878 if (m_singleChart) {
1879 m_singleChart->Activate();
1880 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1881 m_pCurrentStack, m_singleChart->GetFullPath());
1886 if (NULL != m_singleChart) {
1892 if (!GetVP().IsValid())
1893 set_scale = 1. / 20000.;
1895 double proposed_scale_onscreen;
1898 double new_scale_ppm =
1899 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1907 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1908 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1909 double equivalent_vp_scale =
1911 double new_scale_ppm =
1912 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1917 proposed_scale_onscreen =
1918 wxMin(proposed_scale_onscreen,
1921 proposed_scale_onscreen =
1922 wxMax(proposed_scale_onscreen,
1931 m_singleChart->GetChartSkew() * PI / 180.,
1938 if ((m_bFollow) && m_singleChart)
1940 m_singleChart->GetChartSkew() * PI / 180.,
1949 m_bFirstAuto =
false;
1953 if (bNewChart && !bNewView) Refresh(
false);
1958 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1961 return bNewChart | bNewView;
1964void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1965 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1967 SetQuiltRefChart(db_index);
1972 double best_scale_ppm = GetBestVPScale(pc);
1976 SetQuiltRefChart(-1);
1978 SetQuiltRefChart(-1);
1981void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1982 std::vector<int> piano_chart_index_array =
1983 GetQuiltExtendedStackdbIndexArray();
1984 int current_db_index = piano_chart_index_array[selected_index];
1986 SelectQuiltRefdbChart(current_db_index);
1989double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1993 if ((g_bPreserveScaleOnX) ||
1994 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2000 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2001 double equivalent_vp_scale =
2003 double new_scale_ppm =
2004 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2011 double max_underzoom_multiplier = 2.0;
2012 if (GetVP().b_quilt) {
2013 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2014 pchart->GetChartType(),
2015 pchart->GetChartFamily());
2016 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2019 proposed_scale_onscreen = wxMin(
2020 proposed_scale_onscreen,
2022 max_underzoom_multiplier);
2025 proposed_scale_onscreen =
2026 wxMax(proposed_scale_onscreen,
2034void ChartCanvas::SetupCanvasQuiltMode() {
2039 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2043 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2044 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2045 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2046 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2048 m_Piano->SetRoundedRectangles(
true);
2051 int target_new_dbindex = -1;
2052 if (m_pCurrentStack) {
2053 target_new_dbindex =
2054 GetQuiltReferenceChartIndex();
2056 if (-1 != target_new_dbindex) {
2057 if (!IsChartQuiltableRef(target_new_dbindex)) {
2058 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2059 int type =
ChartData->GetDBChartType(target_new_dbindex);
2062 int stack_index = m_pCurrentStack->CurrentStackEntry;
2064 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2065 (stack_index >= 0)) {
2066 int proj_tent =
ChartData->GetDBChartProj(
2067 m_pCurrentStack->GetDBIndex(stack_index));
2068 int type_tent =
ChartData->GetDBChartType(
2069 m_pCurrentStack->GetDBIndex(stack_index));
2071 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2072 if ((proj == proj_tent) && (type_tent == type)) {
2073 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2083 if (IsChartQuiltableRef(target_new_dbindex))
2084 SelectQuiltRefdbChart(target_new_dbindex,
2087 SelectQuiltRefdbChart(-1,
false);
2089 m_singleChart = NULL;
2092 AdjustQuiltRefChart();
2100 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2104 std::vector<int> empty_array;
2105 m_Piano->SetActiveKeyArray(empty_array);
2106 m_Piano->SetNoshowIndexArray(empty_array);
2107 m_Piano->SetEclipsedIndexArray(empty_array);
2110 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2111 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2112 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2113 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2115 m_Piano->SetRoundedRectangles(
false);
2121 if (!GetQuiltMode()) {
2126 if (m_bFollow ==
true) {
2134 if (!m_singleChart) {
2137 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2145 int cur_max_scale = (int)1e8;
2147 ChartBase *pChart = GetFirstQuiltChart();
2151 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2153 if (pChart->GetNativeScale() < cur_max_scale) {
2154 Candidate_Chart = pChart;
2155 cur_max_scale = pChart->GetNativeScale();
2158 pChart = GetNextQuiltChart();
2161 m_singleChart = Candidate_Chart;
2165 if (NULL == m_singleChart) {
2166 m_singleChart =
ChartData->OpenStackChartConditional(
2167 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2168 CHART_FAMILY_DONTCARE);
2174 InvalidateAllQuiltPatchs();
2176 if (m_singleChart) {
2177 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2178 std::vector<int> one_array;
2179 one_array.push_back(dbi);
2180 m_Piano->SetActiveKeyArray(one_array);
2183 if (m_singleChart) {
2184 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2188 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2192bool ChartCanvas::IsTempMenuBarEnabled() {
2195 wxGetOsVersion(&major);
2203double ChartCanvas::GetCanvasRangeMeters() {
2205 GetSize(&width, &height);
2206 int minDimension = wxMin(width, height);
2209 range *= cos(GetVP().clat * PI / 180.);
2213void ChartCanvas::SetCanvasRangeMeters(
double range) {
2215 GetSize(&width, &height);
2216 int minDimension = wxMin(width, height);
2218 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2222bool ChartCanvas::SetUserOwnship() {
2226 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2227 double factor_dusk = 0.5;
2228 double factor_night = 0.25;
2230 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2231 m_pos_image_user_day =
new wxImage;
2232 *m_pos_image_user_day = pbmp->ConvertToImage();
2233 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2235 int gimg_width = m_pos_image_user_day->GetWidth();
2236 int gimg_height = m_pos_image_user_day->GetHeight();
2239 m_pos_image_user_dusk =
new wxImage;
2240 m_pos_image_user_night =
new wxImage;
2242 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2243 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2245 for (
int iy = 0; iy < gimg_height; iy++) {
2246 for (
int ix = 0; ix < gimg_width; ix++) {
2247 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2248 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2249 m_pos_image_user_day->GetGreen(ix, iy),
2250 m_pos_image_user_day->GetBlue(ix, iy));
2251 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2252 hsv.value = hsv.value * factor_dusk;
2253 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2254 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2257 hsv = wxImage::RGBtoHSV(rgb);
2258 hsv.value = hsv.value * factor_night;
2259 nrgb = wxImage::HSVtoRGB(hsv);
2260 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2267 m_pos_image_user_grey_day =
new wxImage;
2268 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2270 m_pos_image_user_grey_dusk =
new wxImage;
2271 m_pos_image_user_grey_night =
new wxImage;
2273 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2274 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2276 for (
int iy = 0; iy < gimg_height; iy++) {
2277 for (
int ix = 0; ix < gimg_width; ix++) {
2278 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2279 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2280 m_pos_image_user_grey_day->GetGreen(ix, iy),
2281 m_pos_image_user_grey_day->GetBlue(ix, iy));
2282 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2283 hsv.value = hsv.value * factor_dusk;
2284 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2285 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2288 hsv = wxImage::RGBtoHSV(rgb);
2289 hsv.value = hsv.value * factor_night;
2290 nrgb = wxImage::HSVtoRGB(hsv);
2291 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2298 m_pos_image_user_yellow_day =
new wxImage;
2299 m_pos_image_user_yellow_dusk =
new wxImage;
2300 m_pos_image_user_yellow_night =
new wxImage;
2302 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2303 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2304 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2306 for (
int iy = 0; iy < gimg_height; iy++) {
2307 for (
int ix = 0; ix < gimg_width; ix++) {
2308 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2309 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2310 m_pos_image_user_grey_day->GetGreen(ix, iy),
2311 m_pos_image_user_grey_day->GetBlue(ix, iy));
2315 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2316 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2317 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2319 hsv = wxImage::RGBtoHSV(rgb);
2320 hsv.value = hsv.value * factor_dusk;
2321 nrgb = wxImage::HSVtoRGB(hsv);
2322 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2324 hsv = wxImage::RGBtoHSV(rgb);
2325 hsv.value = hsv.value * factor_night;
2326 nrgb = wxImage::HSVtoRGB(hsv);
2327 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2339 m_display_size_mm = size;
2346 double horizontal = sd.x;
2350 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2351 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2355 ps52plib->SetPPMM(m_pix_per_mm);
2360 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2362 m_display_size_mm, sd.x, sd.y);
2368 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2371 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2374void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2376 wxString msg(event.m_string.c_str(), wxConvUTF8);
2378 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2379 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2382 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2384 compress_msg_array.RemoveAt(event.thread);
2385 compress_msg_array.Insert( msg, event.thread);
2388 compress_msg_array.Add(msg);
2391 wxString combined_msg;
2392 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2393 combined_msg += compress_msg_array[i];
2394 combined_msg +=
"\n";
2398 pprog->Update(pprog_count, combined_msg, &skip );
2399 pprog->SetSize(pprog_size);
2404void ChartCanvas::InvalidateGL() {
2405 if (!m_glcc)
return;
2407 if (g_bopengl) m_glcc->Invalidate();
2409 if (m_Compass) m_Compass->UpdateStatus(
true);
2412int ChartCanvas::GetCanvasChartNativeScale() {
2414 if (!VPoint.b_quilt) {
2415 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2417 ret = (int)m_pQuilt->GetRefNativeScale();
2422ChartBase *ChartCanvas::GetChartAtCursor() {
2424 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2425 target_chart = m_singleChart;
2426 else if (VPoint.b_quilt)
2427 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2429 target_chart = NULL;
2430 return target_chart;
2433ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2437 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2439 target_chart = NULL;
2440 return target_chart;
2443int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2444 int new_dbIndex = -1;
2445 if (!VPoint.b_quilt) {
2446 if (m_pCurrentStack) {
2447 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2448 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2450 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2460 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2462 for (
unsigned int is = 0; is < im; is++) {
2464 m_pQuilt->GetExtendedStackIndexArray()[is]);
2467 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2477void ChartCanvas::EnablePaint(
bool b_enable) {
2478 m_b_paint_enable = b_enable;
2480 if (m_glcc) m_glcc->EnablePaint(b_enable);
2484bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2486void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2488std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2489 return m_pQuilt->GetQuiltIndexArray();
2493void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2494 VPoint.b_quilt = b_quilt;
2495 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2498bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2500int ChartCanvas::GetQuiltReferenceChartIndex() {
2501 return m_pQuilt->GetRefChartdbIndex();
2504void ChartCanvas::InvalidateAllQuiltPatchs() {
2505 m_pQuilt->InvalidateAllQuiltPatchs();
2508ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2509 return m_pQuilt->GetLargestScaleChart();
2512ChartBase *ChartCanvas::GetFirstQuiltChart() {
2513 return m_pQuilt->GetFirstChart();
2516ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2518int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2520void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2521 m_pQuilt->SetHiliteIndex(dbIndex);
2524void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2525 m_pQuilt->SetHiliteIndexArray(hilite_array);
2528void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2529 m_pQuilt->ClearHiliteIndexArray();
2532std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2534 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2537int ChartCanvas::GetQuiltRefChartdbIndex() {
2538 return m_pQuilt->GetRefChartdbIndex();
2541std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2542 return m_pQuilt->GetExtendedStackIndexArray();
2545std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2546 return m_pQuilt->GetFullscreenIndexArray();
2549std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2550 return m_pQuilt->GetEclipsedStackIndexArray();
2553void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2555double ChartCanvas::GetQuiltMaxErrorFactor() {
2556 return m_pQuilt->GetMaxErrorFactor();
2559bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2560 return m_pQuilt->IsChartQuiltableRef(db_index);
2564 double chartMaxScale =
2566 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2569void ChartCanvas::StartMeasureRoute() {
2570 if (!m_routeState) {
2571 if (m_bMeasure_Active) {
2573 m_pMeasureRoute = NULL;
2576 m_bMeasure_Active =
true;
2577 m_nMeasureState = 1;
2578 m_bDrawingRoute =
false;
2580 SetCursor(*pCursorPencil);
2585void ChartCanvas::CancelMeasureRoute() {
2586 m_bMeasure_Active =
false;
2587 m_nMeasureState = 0;
2588 m_bDrawingRoute =
false;
2591 m_pMeasureRoute = NULL;
2593 SetCursor(*pCursorArrow);
2596ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2598void ChartCanvas::SetVP(
ViewPort &vp) {
2609void ChartCanvas::TriggerDeferredFocus() {
2612 m_deferredFocusTimer.Start(20,
true);
2614#if defined(__WXGTK__) || defined(__WXOSX__)
2625void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2630void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2631 if (SendKeyEventToPlugins(event))
2635 int key_char =
event.GetKeyCode();
2638 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2644 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2649 if (g_benable_rotate) {
2670void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2671 if (SendKeyEventToPlugins(event))
2675 bool b_handled =
false;
2677 m_modkeys =
event.GetModifiers();
2679 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2681#ifdef OCPN_ALT_MENUBAR
2687 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2689 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2690 if (!g_bTempShowMenuBar) {
2691 g_bTempShowMenuBar =
true;
2692 parent_frame->ApplyGlobalSettings(
false);
2694 m_bMayToggleMenuBar =
false;
2700 if (event.GetKeyCode() != WXK_ALT) {
2701 m_bMayToggleMenuBar =
false;
2708 switch (event.GetKeyCode()) {
2715 event.GetPosition(&x, &y);
2716 m_FinishRouteOnKillFocus =
false;
2717 CallPopupMenu(x, y);
2718 m_FinishRouteOnKillFocus =
true;
2722 m_modkeys |= wxMOD_ALT;
2726 m_modkeys |= wxMOD_CONTROL;
2731 case WXK_RAW_CONTROL:
2732 m_modkeys |= wxMOD_RAW_CONTROL;
2737 if (m_modkeys == wxMOD_CONTROL)
2738 parent_frame->DoStackDown(
this);
2740 StartTimedMovement();
2750 StartTimedMovement();
2758 if (m_modkeys == wxMOD_CONTROL)
2759 parent_frame->DoStackUp(
this);
2761 StartTimedMovement();
2771 StartTimedMovement();
2783 SetShowENCText(!GetShowENCText());
2789 if (!m_bMeasure_Active) {
2790 if (event.ShiftDown())
2791 m_bMeasure_DistCircle =
true;
2793 m_bMeasure_DistCircle =
false;
2795 StartMeasureRoute();
2797 CancelMeasureRoute();
2799 SetCursor(*pCursorArrow);
2809 parent_frame->ToggleColorScheme();
2811 TriggerDeferredFocus();
2815 int mod = m_modkeys & wxMOD_SHIFT;
2816 if (mod != m_brightmod) {
2818 m_bbrightdir = !m_bbrightdir;
2821 if (!m_bbrightdir) {
2822 g_nbrightness -= 10;
2823 if (g_nbrightness <= MIN_BRIGHT) {
2824 g_nbrightness = MIN_BRIGHT;
2825 m_bbrightdir =
true;
2828 g_nbrightness += 10;
2829 if (g_nbrightness >= MAX_BRIGHT) {
2830 g_nbrightness = MAX_BRIGHT;
2831 m_bbrightdir =
false;
2835 SetScreenBrightness(g_nbrightness);
2836 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2845 parent_frame->DoStackDown(
this);
2849 parent_frame->DoStackUp(
this);
2854 ToggleCanvasQuiltMode();
2860 parent_frame->ToggleFullScreen();
2865 if (m_modkeys == wxMOD_ALT) {
2868 ToggleChartOutlines();
2874 parent_frame->ActivateMOB();
2878 case WXK_NUMPAD_ADD:
2883 case WXK_NUMPAD_SUBTRACT:
2884 case WXK_PAGEDOWN: {
2885 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2890 if (m_bMeasure_Active) {
2891 if (m_nMeasureState > 2) {
2892 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2894 m_pMeasureRoute->GetnPoints();
2896 gFrame->RefreshAllCanvas();
2898 CancelMeasureRoute();
2899 StartMeasureRoute();
2907 if (event.GetKeyCode() < 128)
2909 int key_char =
event.GetKeyCode();
2913 if (!g_b_assume_azerty) {
2915 if (g_benable_rotate) {
2947 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2954 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2955 m_modkeys & wxMOD_RAW_CONTROL) {
2956 parent_frame->ToggleFullScreen();
2961 if (event.ControlDown()) key_char -= 64;
2963 if (key_char >=
'0' && key_char <=
'9')
2964 SetGroupIndex(key_char -
'0');
2969 SetShowENCAnchor(!GetShowENCAnchor());
2975 parent_frame->ToggleColorScheme();
2980 event.GetPosition(&x, &y);
2981 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2982 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2985 if (VPoint.b_quilt) {
2987 if (m_pQuilt->GetChartAtPix(
2992 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2994 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2999 if (m_singleChart) {
3000 ChartType = m_singleChart->GetChartType();
3001 ChartFam = m_singleChart->GetChartFamily();
3005 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3006 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3008 this, -1, ChartType, ChartFam,
3009 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3010 wxDefaultSize, wxSIMPLE_BORDER,
"");
3023 m_nmea_log->Raise();
3027 SetShowENCLights(!GetShowENCLights());
3033 if (event.ShiftDown())
3034 m_bMeasure_DistCircle =
true;
3036 m_bMeasure_DistCircle =
false;
3038 StartMeasureRoute();
3042 if (g_bInlandEcdis && ps52plib) {
3043 SetENCDisplayCategory((_DisCat)STANDARD);
3048 ToggleChartOutlines();
3052 ToggleCanvasQuiltMode();
3056 parent_frame->ToggleTestPause();
3059 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3060 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3061 g_iNavAidRadarRingsNumberVisible = 1;
3062 else if (!g_bNavAidRadarRingsShown &&
3063 g_iNavAidRadarRingsNumberVisible == 1)
3064 g_iNavAidRadarRingsNumberVisible = 0;
3067 SetShowENCDepth(!m_encShowDepth);
3072 SetShowENCText(!GetShowENCText());
3077 SetShowENCDataQual(!GetShowENCDataQual());
3082 m_bShowNavobjects = !m_bShowNavobjects;
3097 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3102 if (event.ControlDown()) gFrame->DropMarker(
false);
3109 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3110 if ((indexActive + 1) <= r->GetnPoints()) {
3121 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3127 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3133 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3140 parent_frame->DoSettings();
3144 parent_frame->Close();
3160 if (undo->AnythingToRedo()) {
3161 undo->RedoNextAction();
3168 if (event.ShiftDown()) {
3169 if (undo->AnythingToRedo()) {
3170 undo->RedoNextAction();
3175 if (undo->AnythingToUndo()) {
3176 undo->UndoLastAction();
3185 if (m_bMeasure_Active) {
3186 CancelMeasureRoute();
3188 SetCursor(*pCursorArrow);
3191 gFrame->RefreshAllCanvas();
3205 switch (gamma_state) {
3225 SetScreenBrightness(g_nbrightness);
3230 if (event.ControlDown()) {
3231 m_bShowCompassWin = !m_bShowCompassWin;
3232 SetShowGPSCompassWindow(m_bShowCompassWin);
3249void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3250 if (SendKeyEventToPlugins(event))
3254 switch (event.GetKeyCode()) {
3256 parent_frame->SwitchKBFocus(
this);
3262 if (!m_pany) m_panspeed = 0;
3268 if (!m_panx) m_panspeed = 0;
3271 case WXK_NUMPAD_ADD:
3272 case WXK_NUMPAD_SUBTRACT:
3281 m_modkeys &= ~wxMOD_ALT;
3282#ifdef OCPN_ALT_MENUBAR
3287 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3288 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3289 parent_frame->ApplyGlobalSettings(
false);
3291 m_bMayToggleMenuBar =
true;
3297 m_modkeys &= ~wxMOD_CONTROL;
3301 if (event.GetKeyCode() < 128)
3303 int key_char =
event.GetKeyCode();
3307 if (!g_b_assume_azerty) {
3322 m_rotation_speed = 0;
3340void ChartCanvas::ToggleChartOutlines() {
3341 m_bShowOutlines = !m_bShowOutlines;
3347 if (g_bopengl) InvalidateGL();
3351void ChartCanvas::ToggleLookahead() {
3352 m_bLookAhead = !m_bLookAhead;
3357void ChartCanvas::SetUpMode(
int mode) {
3360 if (mode != NORTH_UP_MODE) {
3363 if (!std::isnan(
gCog)) stuff =
gCog;
3366 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3369 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3371 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3372 SetVPRotation(GetVPSkew());
3377 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3378 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3380 UpdateGPSCompassStatusBox(
true);
3381 gFrame->DoChartUpdate();
3384bool ChartCanvas::DoCanvasCOGSet() {
3385 if (GetUpMode() == NORTH_UP_MODE)
return false;
3387 if (g_btenhertz) cog_use =
gCog;
3389 double rotation = 0;
3390 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3391 rotation = -
gHdt * PI / 180.;
3392 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3393 rotation = -cog_use * PI / 180.;
3395 SetVPRotation(rotation);
3399double easeOutCubic(
double t) {
3401 return 1.0 - pow(1.0 - t, 3.0);
3404void ChartCanvas::StartChartDragInertia() {
3405 m_bChartDragging =
false;
3408 m_chart_drag_inertia_time = 750;
3409 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3414 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3418 size_t length = m_drag_vec_t.size();
3419 for (
size_t i = 0; i < n_vel; i++) {
3420 xacc += m_drag_vec_x.at(length - 1 - i);
3421 yacc += m_drag_vec_y.at(length - 1 - i);
3422 tacc += m_drag_vec_t.at(length - 1 - i);
3425 if (tacc == 0)
return;
3427 double drag_velocity_x = xacc / tacc;
3428 double drag_velocity_y = yacc / tacc;
3434 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3436 m_chart_drag_velocity_x = drag_velocity_x;
3437 m_chart_drag_velocity_y = drag_velocity_y;
3439 m_chart_drag_inertia_active =
true;
3441 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3444void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3445 if (!m_chart_drag_inertia_active)
return;
3447 wxLongLong now = wxGetLocalTimeMillis();
3448 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3449 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3450 if (t > 1.0) t = 1.0;
3451 double e = 1.0 - easeOutCubic(t);
3454 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3456 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3458 m_last_elapsed = elapsed;
3462 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3463 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3464 double inertia_lat, inertia_lon;
3468 if (!IsOwnshipOnScreen()) {
3470 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3471 UpdateFollowButtonState();
3482 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3483 m_chart_drag_inertia_timer.Stop();
3486 m_target_lat = GetVP().
clat;
3487 m_target_lon = GetVP().
clon;
3488 m_pan_drag.x = m_pan_drag.y = 0;
3489 m_panx = m_pany = 0;
3490 m_chart_drag_inertia_active =
false;
3494 int target_redraw_interval = 40;
3495 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3499void ChartCanvas::StopMovement() {
3500 m_panx = m_pany = 0;
3503 m_rotation_speed = 0;
3506#if !defined(__WXGTK__) && !defined(__WXQT__)
3517bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3519 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3521 if (!pMovementTimer->IsRunning()) {
3522 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3525 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3530 m_last_movement_time = wxDateTime::UNow();
3534void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3537 m_target_lat = target_lat;
3538 m_target_lon = target_lon;
3541 m_start_lat = GetVP().
clat;
3542 m_start_lon = GetVP().
clon;
3544 m_VPMovementTimer.Start(1,
true);
3545 m_timed_move_vp_active =
true;
3547 m_timedVP_step = nstep;
3550void ChartCanvas::DoTimedMovementVP() {
3551 if (!m_timed_move_vp_active)
return;
3552 if (m_stvpc++ > m_timedVP_step * 2) {
3559 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3574 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3575 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3577 m_run_lat = new_lat;
3578 m_run_lon = new_lon;
3583void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3585void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3587void ChartCanvas::StartTimedMovementTarget() {}
3589void ChartCanvas::DoTimedMovementTarget() {}
3591void ChartCanvas::StopMovementTarget() {}
3594void ChartCanvas::DoTimedMovement() {
3595 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3599 wxDateTime now = wxDateTime::UNow();
3601 if (m_last_movement_time.IsValid())
3602 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3604 m_last_movement_time = now;
3614 if (dt == 0) dt = 1;
3617 if (m_mustmove < 0) m_mustmove = 0;
3620 if (m_pan_drag.x || m_pan_drag.y) {
3622 m_pan_drag.x = m_pan_drag.y = 0;
3625 if (m_panx || m_pany) {
3626 const double slowpan = .1, maxpan = 2;
3627 if (m_modkeys == wxMOD_ALT)
3628 m_panspeed = slowpan;
3630 m_panspeed += (double)dt / 500;
3631 m_panspeed = wxMin(maxpan, m_panspeed);
3633 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3636 if (m_zoom_factor != 1) {
3637 double alpha = 400, beta = 1.5;
3638 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3640 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3642 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3647 if (zoom_factor > 1) {
3648 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3652 else if (zoom_factor < 1) {
3653 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3658 if (fabs(zoom_factor - 1) > 1e-4) {
3659 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3664 if (m_wheelzoom_stop_oneshot > 0) {
3665 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3666 m_wheelzoom_stop_oneshot = 0;
3671 if (zoom_factor > 1) {
3673 m_wheelzoom_stop_oneshot = 0;
3676 }
else if (zoom_factor < 1) {
3678 m_wheelzoom_stop_oneshot = 0;
3685 if (m_rotation_speed) {
3686 double speed = m_rotation_speed;
3687 if (m_modkeys == wxMOD_ALT) speed /= 10;
3688 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3692void ChartCanvas::SetColorScheme(ColorScheme cs) {
3697 case GLOBAL_COLOR_SCHEME_DAY:
3698 m_pos_image_red = &m_os_image_red_day;
3699 m_pos_image_grey = &m_os_image_grey_day;
3700 m_pos_image_yellow = &m_os_image_yellow_day;
3701 m_pos_image_user = m_pos_image_user_day;
3702 m_pos_image_user_grey = m_pos_image_user_grey_day;
3703 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3704 m_cTideBitmap = m_bmTideDay;
3705 m_cCurrentBitmap = m_bmCurrentDay;
3708 case GLOBAL_COLOR_SCHEME_DUSK:
3709 m_pos_image_red = &m_os_image_red_dusk;
3710 m_pos_image_grey = &m_os_image_grey_dusk;
3711 m_pos_image_yellow = &m_os_image_yellow_dusk;
3712 m_pos_image_user = m_pos_image_user_dusk;
3713 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3714 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3715 m_cTideBitmap = m_bmTideDusk;
3716 m_cCurrentBitmap = m_bmCurrentDusk;
3718 case GLOBAL_COLOR_SCHEME_NIGHT:
3719 m_pos_image_red = &m_os_image_red_night;
3720 m_pos_image_grey = &m_os_image_grey_night;
3721 m_pos_image_yellow = &m_os_image_yellow_night;
3722 m_pos_image_user = m_pos_image_user_night;
3723 m_pos_image_user_grey = m_pos_image_user_grey_night;
3724 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3725 m_cTideBitmap = m_bmTideNight;
3726 m_cCurrentBitmap = m_bmCurrentNight;
3729 m_pos_image_red = &m_os_image_red_day;
3730 m_pos_image_grey = &m_os_image_grey_day;
3731 m_pos_image_yellow = &m_os_image_yellow_day;
3732 m_pos_image_user = m_pos_image_user_day;
3733 m_pos_image_user_grey = m_pos_image_user_grey_day;
3734 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3735 m_cTideBitmap = m_bmTideDay;
3736 m_cCurrentBitmap = m_bmCurrentDay;
3740 CreateDepthUnitEmbossMaps(cs);
3741 CreateOZEmbossMapData(cs);
3744 m_fog_color = wxColor(
3748 case GLOBAL_COLOR_SCHEME_DUSK:
3751 case GLOBAL_COLOR_SCHEME_NIGHT:
3757 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3758 m_fog_color.Blue() * dim);
3762 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3763 SetBackgroundColour( wxColour(0,0,0) );
3765 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3768 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3770 SetBackgroundColour( wxNullColour );
3777 m_Piano->SetColorScheme(cs);
3779 m_Compass->SetColorScheme(cs);
3781 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3783 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3785 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3786 if (m_notification_button) {
3787 m_notification_button->SetColorScheme(cs);
3791 if (g_bopengl && m_glcc) {
3792 m_glcc->SetColorScheme(cs);
3798 m_brepaint_piano =
true;
3805wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3806 wxImage img = Bitmap.ConvertToImage();
3807 int sx = img.GetWidth();
3808 int sy = img.GetHeight();
3810 wxImage new_img(img);
3812 for (
int i = 0; i < sx; i++) {
3813 for (
int j = 0; j < sy; j++) {
3814 if (!img.IsTransparent(i, j)) {
3815 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3816 (
unsigned char)(img.GetGreen(i, j) * factor),
3817 (
unsigned char)(img.GetBlue(i, j) * factor));
3822 wxBitmap ret = wxBitmap(new_img);
3827void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3830 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3832 if (!m_pBrightPopup) {
3835 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3839 m_pBrightPopup->SetSize(x, y);
3840 m_pBrightPopup->Move(120, 120);
3843 int bmpsx = m_pBrightPopup->GetSize().x;
3844 int bmpsy = m_pBrightPopup->GetSize().y;
3846 wxBitmap bmp(bmpsx, bmpsx);
3847 wxMemoryDC mdc(bmp);
3849 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3850 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3851 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3852 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3855 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3857 mdc.SetFont(*pfont);
3860 if (brightness == max)
3862 else if (brightness == min)
3865 val.Printf(
"%3d", brightness);
3867 mdc.DrawText(val, 0, 0);
3869 mdc.SelectObject(wxNullBitmap);
3871 m_pBrightPopup->SetBitmap(bmp);
3872 m_pBrightPopup->Show();
3873 m_pBrightPopup->Refresh();
3876void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3877 m_b_rot_hidef =
true;
3881void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3884 bool b_need_refresh =
false;
3886 wxSize win_size = GetSize() * m_displayScale;
3890 bool showAISRollover =
false;
3892 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3896 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3897 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3900 showAISRollover =
true;
3902 if (NULL == m_pAISRolloverWin) {
3904 m_pAISRolloverWin->IsActive(
false);
3905 b_need_refresh =
true;
3906 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3907 m_AISRollover_MMSI != FoundAIS_MMSI) {
3913 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3914 m_pAISRolloverWin->IsActive(
false);
3915 m_AISRollover_MMSI = 0;
3920 m_AISRollover_MMSI = FoundAIS_MMSI;
3922 if (!m_pAISRolloverWin->IsActive()) {
3923 wxString s = ptarget->GetRolloverString();
3924 m_pAISRolloverWin->SetString(s);
3926 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3927 AIS_ROLLOVER, win_size);
3928 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3929 m_pAISRolloverWin->IsActive(
true);
3930 b_need_refresh =
true;
3934 m_AISRollover_MMSI = 0;
3935 showAISRollover =
false;
3940 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3941 m_pAISRolloverWin->IsActive(
false);
3942 m_AISRollover_MMSI = 0;
3943 b_need_refresh =
true;
3948 bool showRouteRollover =
false;
3950 if (NULL == m_pRolloverRouteSeg) {
3954 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3955 SelectableItemList SelList =
pSelect->FindSelectionList(
3957 auto node = SelList.begin();
3958 while (node != SelList.end()) {
3963 if (pr && pr->IsVisible()) {
3964 m_pRolloverRouteSeg = pFindSel;
3965 showRouteRollover =
true;
3967 if (NULL == m_pRouteRolloverWin) {
3969 m_pRouteRolloverWin->IsActive(
false);
3972 if (!m_pRouteRolloverWin->IsActive()) {
3980 DistanceBearingMercator(
3981 segShow_point_b->m_lat, segShow_point_b->m_lon,
3982 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3984 if (!pr->m_bIsInLayer)
3985 s.Append(_(
"Route") +
": ");
3987 s.Append(_(
"Layer Route: "));
3989 if (pr->m_RouteNameString.IsEmpty())
3990 s.Append(_(
"(unnamed)"));
3992 s.Append(pr->m_RouteNameString);
3997 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3998 << segShow_point_b->GetName() <<
"\n";
4001 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4002 (
int)floor(brg + 0.5), 0x00B0);
4005 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4007 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4008 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4010 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4011 (
int)floor(varBrg + 0.5), 0x00B0);
4019 double shiptoEndLeg = 0.;
4020 bool validActive =
false;
4021 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4024 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4025 auto node = pr->pRoutePointList->begin();
4027 float dist_to_endleg = 0;
4030 for (++node; node != pr->pRoutePointList->end(); ++node) {
4037 if (prp->IsSame(segShow_point_a))
break;
4045 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4048 ->GetCurrentRngToActivePoint();
4057 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4062 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4063 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4065 << wxString(ttg_sec > SECONDS_PER_DAY
4066 ? ttg_span.Format(_(
"%Dd %H:%M"))
4067 : ttg_span.Format(_(
"%H:%M")));
4068 wxDateTime dtnow, eta;
4069 eta = dtnow.SetToCurrent().Add(ttg_span);
4070 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4071 << eta.Format(
" %d %H:%M");
4075 m_pRouteRolloverWin->SetString(s);
4077 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4078 LEG_ROLLOVER, win_size);
4079 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4080 m_pRouteRolloverWin->IsActive(
true);
4081 b_need_refresh =
true;
4082 showRouteRollover =
true;
4091 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4093 m_pRolloverRouteSeg))
4094 showRouteRollover =
false;
4095 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4096 showRouteRollover =
false;
4098 showRouteRollover =
true;
4102 if (m_routeState) showRouteRollover =
false;
4105 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4106 showRouteRollover =
false;
4108 if (m_pRouteRolloverWin &&
4109 !showRouteRollover) {
4110 m_pRouteRolloverWin->IsActive(
false);
4111 m_pRolloverRouteSeg = NULL;
4112 m_pRouteRolloverWin->Destroy();
4113 m_pRouteRolloverWin = NULL;
4114 b_need_refresh =
true;
4115 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4116 m_pRouteRolloverWin->IsActive(
true);
4117 b_need_refresh =
true;
4122 bool showTrackRollover =
false;
4124 if (NULL == m_pRolloverTrackSeg) {
4128 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4129 SelectableItemList SelList =
pSelect->FindSelectionList(
4132 auto node = SelList.begin();
4133 while (node != SelList.end()) {
4138 if (pt && pt->IsVisible()) {
4139 m_pRolloverTrackSeg = pFindSel;
4140 showTrackRollover =
true;
4142 if (NULL == m_pTrackRolloverWin) {
4144 m_pTrackRolloverWin->IsActive(
false);
4147 if (!m_pTrackRolloverWin->IsActive()) {
4155 DistanceBearingMercator(
4156 segShow_point_b->m_lat, segShow_point_b->m_lon,
4157 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4159 if (!pt->m_bIsInLayer)
4160 s.Append(_(
"Track") +
": ");
4162 s.Append(_(
"Layer Track: "));
4164 if (pt->GetName().IsEmpty())
4165 s.Append(_(
"(unnamed)"));
4167 s.Append(pt->GetName());
4168 double tlenght = pt->Length();
4170 if (pt->GetLastPoint()->GetTimeString() &&
4171 pt->GetPoint(0)->GetTimeString()) {
4172 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4173 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4174 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4175 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4176 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4177 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4178 << getUsrSpeedUnit();
4179 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4180 : ttime.Format(
" %H:%M"));
4184 if (g_bShowTrackPointTime &&
4185 strlen(segShow_point_b->GetTimeString())) {
4186 wxString stamp = segShow_point_b->GetTimeString();
4187 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4188 if (timestamp.IsValid()) {
4192 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4194 s <<
"\n" << _(
"Segment Created: ") << stamp;
4199 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4204 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4206 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4207 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4209 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4215 if (segShow_point_a->GetTimeString() &&
4216 segShow_point_b->GetTimeString()) {
4217 wxDateTime apoint = segShow_point_a->GetCreateTime();
4218 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4219 if (apoint.IsValid() && bpoint.IsValid()) {
4220 double segmentSpeed = toUsrSpeed(
4221 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4222 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4223 << getUsrSpeedUnit();
4227 m_pTrackRolloverWin->SetString(s);
4229 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4230 LEG_ROLLOVER, win_size);
4231 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4232 m_pTrackRolloverWin->IsActive(
true);
4233 b_need_refresh =
true;
4234 showTrackRollover =
true;
4243 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4245 m_pRolloverTrackSeg))
4246 showTrackRollover =
false;
4247 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4248 showTrackRollover =
false;
4250 showTrackRollover =
true;
4254 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4255 showTrackRollover =
false;
4258 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4259 showTrackRollover =
false;
4265 if (m_pTrackRolloverWin &&
4266 !showTrackRollover) {
4267 m_pTrackRolloverWin->IsActive(
false);
4268 m_pRolloverTrackSeg = NULL;
4269 m_pTrackRolloverWin->Destroy();
4270 m_pTrackRolloverWin = NULL;
4271 b_need_refresh =
true;
4272 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4273 m_pTrackRolloverWin->IsActive(
true);
4274 b_need_refresh =
true;
4277 if (b_need_refresh) Refresh();
4280void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4281 if ((GetShowENCLights() || m_bsectors_shown) &&
4282 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4283 extendedSectorLegs)) {
4284 if (!m_bsectors_shown) {
4286 m_bsectors_shown =
true;
4289 if (m_bsectors_shown) {
4291 m_bsectors_shown =
false;
4299#if defined(__WXGTK__) || defined(__WXQT__)
4304 double cursor_lat, cursor_lon;
4307 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4308 while (cursor_lon < -180.) cursor_lon += 360.;
4310 while (cursor_lon > 180.) cursor_lon -= 360.;
4312 SetCursorStatus(cursor_lat, cursor_lon);
4318void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4319 if (!parent_frame->m_pStatusBar)
return;
4323 s1 += toSDMM(1, cursor_lat);
4325 s1 += toSDMM(2, cursor_lon);
4327 if (STAT_FIELD_CURSOR_LL >= 0)
4328 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4330 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4335 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4336 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4337 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4339 wxString s = st + sm;
4352 if (g_bShowLiveETA) {
4355 float boatSpeedDefault = g_defaultBoatSpeed;
4360 if (!std::isnan(
gSog)) {
4362 if (boatSpeed < 0.5) {
4365 realTimeETA = dist / boatSpeed * 60;
4374 s << minutesToHoursDays(realTimeETA);
4379 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4380 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4382 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4387 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4395wxString minutesToHoursDays(
float timeInMinutes) {
4398 if (timeInMinutes == 0) {
4403 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4404 s << wxString::Format(
"%d", (
int)timeInMinutes);
4409 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4412 hours = (int)timeInMinutes / 60;
4413 min = (int)timeInMinutes % 60;
4416 s << wxString::Format(
"%d", hours);
4419 s << wxString::Format(
"%d", hours);
4421 s << wxString::Format(
"%d", min);
4428 else if (timeInMinutes > 24 * 60) {
4431 days = (int)(timeInMinutes / 60) / 24;
4432 hours = (int)(timeInMinutes / 60) % 24;
4435 s << wxString::Format(
"%d", days);
4438 s << wxString::Format(
"%d", days);
4440 s << wxString::Format(
"%d", hours);
4452void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4460 wxPoint2DDouble *r) {
4465 double rlon, wxPoint2DDouble *r) {
4476 if (!g_bopengl && m_singleChart &&
4477 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4478 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4479 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4480 (m_singleChart->GetChartProjectionType() !=
4481 PROJECTION_TRANSVERSE_MERCATOR) &&
4482 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4483 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4484 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4498 Cur_BSB_Ch->SetVPRasterParms(vp);
4499 double rpixxd, rpixyd;
4500 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4526 if (std::isnan(p.m_x)) {
4527 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4531 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4532 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4534 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4553 if (!g_bopengl && m_singleChart &&
4554 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4555 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4556 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4557 (m_singleChart->GetChartProjectionType() !=
4558 PROJECTION_TRANSVERSE_MERCATOR) &&
4559 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4560 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4561 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4572 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4575 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4580 else if (slon > 180.)
4591 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4597 DoZoomCanvas(factor,
false);
4598 extendedSectorLegs.clear();
4603 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4606 if (StartTimedMovement(stoptimer)) {
4608 m_zoom_factor = factor;
4613 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4615 DoZoomCanvas(factor, can_zoom_to_cursor);
4618 extendedSectorLegs.clear();
4621void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4624 if (!m_pCurrentStack)
return;
4630 if (m_bzooming)
return;
4639 double proposed_scale_onscreen =
4642 bool b_do_zoom =
false;
4651 if (!VPoint.b_quilt) {
4654 if (!m_disable_adjust_on_zoom) {
4655 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4656 if (new_db_index >= 0)
4657 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4661 int current_ref_stack_index = -1;
4662 if (m_pCurrentStack->nEntry) {
4664 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4665 m_pQuilt->SetReferenceChart(trial_index);
4666 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4667 if (new_db_index >= 0)
4668 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4672 if (m_pCurrentStack)
4673 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4684 double min_allowed_scale =
4687 if (proposed_scale_onscreen < min_allowed_scale) {
4692 proposed_scale_onscreen = min_allowed_scale;
4696 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4699 }
else if (factor < 1) {
4704 bool b_smallest =
false;
4706 if (!VPoint.b_quilt) {
4711 LLBBox viewbox = VPoint.GetBBox();
4713 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4714 double max_allowed_scale;
4728 if (proposed_scale_onscreen > max_allowed_scale) {
4730 proposed_scale_onscreen = max_allowed_scale;
4735 if (!m_disable_adjust_on_zoom) {
4737 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4738 if (new_db_index >= 0)
4739 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4741 if (m_pCurrentStack)
4742 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4745 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4747 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4748 proposed_scale_onscreen =
4749 wxMin(proposed_scale_onscreen,
4755 m_absolute_min_scale_ppm)
4756 proposed_scale_onscreen =
4765 bool b_allow_ztc =
true;
4766 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4767 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4769 double brg, distance;
4770 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4773 meters_to_shift = distance * 1852;
4781 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4784 if (m_bFollow) DoCanvasUpdate();
4791void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4793 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4797void ChartCanvas::RotateCanvas(
double dir) {
4801 if (StartTimedMovement()) {
4803 m_rotation_speed = dir * 60;
4806 double speed = dir * 10;
4807 if (m_modkeys == wxMOD_ALT) speed /= 20;
4808 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4812void ChartCanvas::DoRotateCanvas(
double rotation) {
4813 while (rotation < 0) rotation += 2 * PI;
4814 while (rotation > 2 * PI) rotation -= 2 * PI;
4816 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4818 SetVPRotation(rotation);
4819 parent_frame->UpdateRotationState(VPoint.
rotation);
4822void ChartCanvas::DoTiltCanvas(
double tilt) {
4823 while (tilt < 0) tilt = 0;
4824 while (tilt > .95) tilt = .95;
4826 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4832void ChartCanvas::TogglebFollow() {
4839void ChartCanvas::ClearbFollow() {
4842 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4844 UpdateFollowButtonState();
4848 parent_frame->SetChartUpdatePeriod();
4851void ChartCanvas::SetbFollow() {
4854 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4855 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4863 p.m_x += m_OSoffsetx;
4864 p.m_y -= m_OSoffsety;
4873 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4874 UpdateFollowButtonState();
4876 if (!g_bSmoothRecenter) {
4880 parent_frame->SetChartUpdatePeriod();
4883void ChartCanvas::UpdateFollowButtonState() {
4886 m_muiBar->SetFollowButtonState(0);
4889 m_muiBar->SetFollowButtonState(2);
4891 m_muiBar->SetFollowButtonState(1);
4897 androidSetFollowTool(0);
4900 androidSetFollowTool(2);
4902 androidSetFollowTool(1);
4909 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4910 if (pic->m_enabled && pic->m_init_state) {
4911 switch (pic->m_api_version) {
4914 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4925void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4926 if (g_bSmoothRecenter && !m_routeState) {
4927 if (StartSmoothJump(lat, lon, scale_ppm))
4931 double gcDist, gcBearingEnd;
4932 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4934 gcBearingEnd += 180;
4935 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4938 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4939 double new_lat = lat + (lat_offset / (1852 * 60));
4940 double new_lon = lon + (lon_offset / (1852 * 60));
4943 StartSmoothJump(lat, lon, scale_ppm);
4948 if (lon > 180.0) lon -= 360.0;
4954 if (!GetQuiltMode()) {
4956 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4957 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4961 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4962 AdjustQuiltRefChart();
4969 UpdateFollowButtonState();
4977bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4982 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4983 double distance_pixels = gcDist *
GetVPScale();
4984 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4990 m_startLat = m_vLat;
4991 m_startLon = m_vLon;
4996 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4997 m_endScale = scale_ppm;
5000 m_animationDuration = 600;
5001 m_animationStart = wxGetLocalTimeMillis();
5008 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5009 m_animationActive =
true;
5014void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5016 wxLongLong now = wxGetLocalTimeMillis();
5017 double elapsed = (now - m_animationStart).ToDouble();
5018 double t = elapsed / m_animationDuration.ToDouble();
5019 if (t > 1.0) t = 1.0;
5022 double e = easeOutCubic(t);
5025 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5026 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5027 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5032 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5038 m_animationActive =
false;
5039 UpdateFollowButtonState();
5048 extendedSectorLegs.clear();
5057 if (iters++ > 5)
return false;
5058 if (!std::isnan(dlat))
break;
5061 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5067 else if (dlat < -90)
5070 if (dlon > 360.) dlon -= 360.;
5071 if (dlon < -360.) dlon += 360.;
5086 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5090 if (VPoint.b_quilt) {
5091 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5092 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5096 double tweak_scale_ppm =
5102 if (new_ref_dbIndex == -1) {
5103#pragma GCC diagnostic push
5104#pragma GCC diagnostic ignored "-Warray-bounds"
5111 int trial_index = -1;
5112 if (m_pCurrentStack->nEntry) {
5114 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5117 if (trial_index < 0) {
5118 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5119 if (full_screen_array.size())
5120 trial_index = full_screen_array[full_screen_array.size() - 1];
5123 if (trial_index >= 0) {
5124 m_pQuilt->SetReferenceChart(trial_index);
5129#pragma GCC diagnostic pop
5136 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5138 double offset_angle = atan2(offy, offx);
5139 double offset_distance = sqrt((offy * offy) + (offx * offx));
5140 double chart_angle = GetVPRotation();
5141 double target_angle = chart_angle - offset_angle;
5142 double d_east_mod = offset_distance * cos(target_angle);
5143 double d_north_mod = offset_distance * sin(target_angle);
5148 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5149 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5151 UpdateFollowButtonState();
5157 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5162bool ChartCanvas::IsOwnshipOnScreen() {
5165 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5166 ((r.y > 0) && r.y < GetCanvasHeight()))
5172void ChartCanvas::ReloadVP(
bool b_adjust) {
5173 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5175 LoadVP(VPoint, b_adjust);
5178void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5180 if (g_bopengl && m_glcc) {
5181 m_glcc->Invalidate();
5182 if (m_glcc->GetSize() != GetSize()) {
5183 m_glcc->SetSize(GetSize());
5188 m_cache_vp.Invalidate();
5189 m_bm_cache_vp.Invalidate();
5192 VPoint.Invalidate();
5194 if (m_pQuilt) m_pQuilt->Invalidate();
5203 vp.m_projection_type, b_adjust);
5206void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5207 m_pQuilt->SetReferenceChart(dbIndex);
5208 VPoint.Invalidate();
5209 m_pQuilt->Invalidate();
5212double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5214 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5221int ChartCanvas::AdjustQuiltRefChart() {
5226 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5228 double min_ref_scale =
5229 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5230 double max_ref_scale =
5231 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5234 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5235 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5236 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5238 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5241 int target_stack_index = wxNOT_FOUND;
5243 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5244 if (index == m_pQuilt->GetRefChartdbIndex()) {
5245 target_stack_index = il;
5250 if (wxNOT_FOUND == target_stack_index)
5251 target_stack_index = 0;
5253 int ref_family = pc->GetChartFamily();
5254 int extended_array_count =
5255 m_pQuilt->GetExtendedStackIndexArray().size();
5256 while ((!brender_ok) &&
5257 ((
int)target_stack_index < (extended_array_count - 1))) {
5258 target_stack_index++;
5260 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5262 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5263 IsChartQuiltableRef(test_db_index)) {
5266 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5268 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5275 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5276 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5277 IsChartQuiltableRef(new_db_index)) {
5278 m_pQuilt->SetReferenceChart(new_db_index);
5281 ret = m_pQuilt->GetRefChartdbIndex();
5283 ret = m_pQuilt->GetRefChartdbIndex();
5286 ret = m_pQuilt->GetRefChartdbIndex();
5295void ChartCanvas::UpdateCanvasOnGroupChange() {
5296 delete m_pCurrentStack;
5308bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5309 double latNE,
double lonNE) {
5311 double latc = (latSW + latNE) / 2.0;
5312 double lonc = (lonSW + lonNE) / 2.0;
5315 double ne_easting, ne_northing;
5316 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5318 double sw_easting, sw_northing;
5319 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5321 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5328 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5331bool ChartCanvas::SetVPProjection(
int projection) {
5337 double prev_true_scale_ppm = m_true_scale_ppm;
5342 m_absolute_min_scale_ppm));
5350bool ChartCanvas::SetVPRotation(
double angle) {
5352 VPoint.
skew, angle);
5355 double skew,
double rotation,
int projection,
5356 bool b_adjust,
bool b_refresh) {
5361 if (VPoint.IsValid()) {
5362 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5363 (fabs(VPoint.
skew - skew) < 1e-9) &&
5364 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5365 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5366 (VPoint.m_projection_type == projection ||
5367 projection == PROJECTION_UNKNOWN))
5370 if (VPoint.m_projection_type != projection)
5371 VPoint.InvalidateTransformCache();
5381 if (projection != PROJECTION_UNKNOWN)
5382 VPoint.SetProjectionType(projection);
5383 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5384 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5387 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5388 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5389 if (VPoint.
clat > 89.5)
5391 else if (VPoint.
clat < -89.5)
5392 VPoint.
clat = -89.5;
5397 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5398 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5410 bool bwasValid = VPoint.IsValid();
5415 m_cache_vp.Invalidate();
5420 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5424 int mouseX = mouse_x;
5425 int mouseY = mouse_y;
5426 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5432 SendCursorLatLonToAllPlugIns(lat, lon);
5435 if (!VPoint.b_quilt && m_singleChart) {
5440 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5444 if ((!m_cache_vp.IsValid()) ||
5449 wxPoint cp_last, cp_this;
5453 if (cp_last != cp_this) {
5459 if (m_pCurrentStack) {
5461 int current_db_index;
5463 m_pCurrentStack->GetCurrentEntrydbIndex();
5465 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5467 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5470 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5474 if (VPoint.b_quilt) {
5478 m_pQuilt->InvalidateAllQuiltPatchs();
5482 if (!m_pCurrentStack)
return false;
5484 int current_db_index;
5486 m_pCurrentStack->GetCurrentEntrydbIndex();
5488 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5489 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5492 int current_ref_stack_index = -1;
5493 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5494 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5495 current_ref_stack_index = i;
5498 if (g_bFullScreenQuilt) {
5499 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5503 bool b_needNewRef =
false;
5506 if ((-1 == current_ref_stack_index) &&
5507 (m_pQuilt->GetRefChartdbIndex() >= 0))
5508 b_needNewRef =
true;
5515 bool renderable =
true;
5517 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5518 if (referenceChart) {
5519 double chartMaxScale = referenceChart->GetNormalScaleMax(
5521 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5523 if (!renderable) b_needNewRef =
true;
5526 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5528 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5529 int target_scale = cte_ref.GetScale();
5530 int target_type = cte_ref.GetChartType();
5531 int candidate_stack_index;
5538 candidate_stack_index = 0;
5539 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5541 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5542 int candidate_scale = cte_candidate.GetScale();
5543 int candidate_type = cte_candidate.GetChartType();
5545 if ((candidate_scale >= target_scale) &&
5546 (candidate_type == target_type)) {
5547 bool renderable =
true;
5549 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5550 if (tentative_referenceChart) {
5551 double chartMaxScale =
5552 tentative_referenceChart->GetNormalScaleMax(
5554 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5557 if (renderable)
break;
5560 candidate_stack_index++;
5565 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5566 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5567 while (candidate_stack_index >= 0) {
5568 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5572 int candidate_scale = cte_candidate.GetScale();
5573 int candidate_type = cte_candidate.GetChartType();
5575 if ((candidate_scale <= target_scale) &&
5576 (candidate_type == target_type))
5579 candidate_stack_index--;
5584 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5585 (candidate_stack_index < 0))
5586 candidate_stack_index = 0;
5588 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5590 m_pQuilt->SetReferenceChart(new_ref_index);
5596 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5601 bool renderable =
true;
5603 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5604 if (referenceChart) {
5605 double chartMaxScale = referenceChart->GetNormalScaleMax(
5607 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5608 proj =
ChartData->GetDBChartProj(ref_db_index);
5610 proj = PROJECTION_MERCATOR;
5612 VPoint.b_MercatorProjectionOverride =
5613 (m_pQuilt->GetnCharts() == 0 || !renderable);
5615 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5617 VPoint.SetProjectionType(proj);
5622 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5627 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5647 m_pQuilt->Invalidate();
5664 if (b_refresh) Refresh(
false);
5671 }
else if (!g_bopengl) {
5672 OcpnProjType projection = PROJECTION_UNKNOWN;
5675 projection = m_singleChart->GetChartProjectionType();
5676 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5677 VPoint.SetProjectionType(projection);
5681 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5682 m_cache_vp.Invalidate();
5686 UpdateCanvasControlBar();
5690 if (VPoint.GetBBox().GetValid()) {
5693 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5702 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5705 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5712 wxPoint2DDouble r, r1;
5714 double delta_check =
5718 double check_point = wxMin(89., VPoint.
clat);
5720 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5723 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5724 VPoint.
clon, 0, &rhumbDist);
5729 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5730 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5732 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5736 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5742 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5744 if (m_true_scale_ppm)
5745 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5750 double round_factor = 1000.;
5754 round_factor = 100.;
5756 round_factor = 1000.;
5759 double retina_coef = 1;
5763 retina_coef = GetContentScaleFactor();
5774 double true_scale_display =
5775 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5780 if (m_displayed_scale_factor > 10.0)
5781 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5782 m_displayed_scale_factor);
5783 else if (m_displayed_scale_factor > 1.0)
5784 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5785 m_displayed_scale_factor);
5786 else if (m_displayed_scale_factor > 0.1) {
5787 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5788 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5789 }
else if (m_displayed_scale_factor > 0.01) {
5790 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5791 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5794 "%s %4.0f (---)", _(
"Scale"),
5795 true_scale_display);
5798 m_scaleValue = true_scale_display;
5800 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5802 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5803 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5805 bool b_noshow =
false;
5809 wxClientDC dc(parent_frame->GetStatusBar());
5811 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5812 dc.SetFont(*templateFont);
5813 dc.GetTextExtent(text, &w, &h);
5818 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5819 if (w && w > rect.width) {
5820 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5824 dc.GetTextExtent(text, &w, &h);
5826 if (w && w > rect.width) {
5832 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5837 m_vLat = VPoint.
clat;
5838 m_vLon = VPoint.
clon;
5852static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5856static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5857 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5859wxColour ChartCanvas::PredColor() {
5862 if (SHIP_NORMAL == m_ownship_state)
5863 return GetGlobalColor(
"URED");
5865 else if (SHIP_LOWACCURACY == m_ownship_state)
5866 return GetGlobalColor(
"YELO1");
5868 return GetGlobalColor(
"NODTA");
5871wxColour ChartCanvas::ShipColor() {
5875 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5877 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5879 return GetGlobalColor(
"URED");
5882void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5883 wxPoint2DDouble lShipMidPoint) {
5884 dc.SetPen(wxPen(PredColor(), 2));
5886 if (SHIP_NORMAL == m_ownship_state)
5887 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5889 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5891 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5892 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5894 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5896 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5897 lShipMidPoint.m_y + 12);
5900void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5901 wxPoint GPSOffsetPixels,
5902 wxPoint2DDouble lGPSPoint) {
5907 float ref_dim = m_display_size_mm / 24;
5908 ref_dim = wxMin(ref_dim, 12);
5909 ref_dim = wxMax(ref_dim, 6);
5912 cPred.Set(g_cog_predictor_color);
5913 if (cPred == wxNullColour) cPred = PredColor();
5920 double nominal_line_width_pix = wxMax(
5922 floor(m_pix_per_mm / 2));
5926 if (nominal_line_width_pix > g_cog_predictor_width)
5927 g_cog_predictor_width = nominal_line_width_pix;
5930 wxPoint lPredPoint, lHeadPoint;
5932 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5933 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5935 double pred_lat, pred_lon;
5936 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5937 &pred_lat, &pred_lon);
5948 float ndelta_pix = 10.;
5949 double hdg_pred_lat, hdg_pred_lon;
5950 bool b_render_hdt =
false;
5951 if (!std::isnan(
gHdt)) {
5953 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5956 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5957 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5958 if (dist > ndelta_pix ) {
5959 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5960 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5965 wxPoint lShipMidPoint;
5966 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5967 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5968 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5969 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5971 if (lpp >= img_height / 2) {
5972 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5973 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5974 !std::isnan(
gSog)) {
5976 float dash_length = ref_dim;
5977 wxDash dash_long[2];
5979 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5980 g_cog_predictor_width);
5981 dash_long[1] = dash_long[0] / 2.0;
5985 if (dash_length > 250.) {
5986 dash_long[0] = 250. / g_cog_predictor_width;
5987 dash_long[1] = dash_long[0] / 2;
5990 wxPen ppPen2(cPred, g_cog_predictor_width,
5991 (wxPenStyle)g_cog_predictor_style);
5992 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5993 ppPen2.SetDashes(2, dash_long);
5996 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5997 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5999 if (g_cog_predictor_width > 1) {
6000 float line_width = g_cog_predictor_width / 3.;
6002 wxDash dash_long3[2];
6003 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6004 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6006 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6007 (wxPenStyle)g_cog_predictor_style);
6008 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6009 ppPen3.SetDashes(2, dash_long3);
6011 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6012 lGPSPoint.m_y + GPSOffsetPixels.y,
6013 lPredPoint.x + GPSOffsetPixels.x,
6014 lPredPoint.y + GPSOffsetPixels.y);
6017 if (g_cog_predictor_endmarker) {
6019 double png_pred_icon_scale_factor = .4;
6020 if (g_ShipScaleFactorExp > 1.0)
6021 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6022 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6026 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6027 (
float)(lPredPoint.x - lShipMidPoint.x));
6028 cog_rad += (float)PI;
6030 for (
int i = 0; i < 4; i++) {
6032 double pxa = (double)(s_png_pred_icon[j]);
6033 double pya = (double)(s_png_pred_icon[j + 1]);
6035 pya *= png_pred_icon_scale_factor;
6036 pxa *= png_pred_icon_scale_factor;
6038 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6039 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6041 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6042 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6046 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6049 dc.SetBrush(wxBrush(cPred));
6051 dc.StrokePolygon(4, icon);
6058 float hdt_dash_length = ref_dim * 0.4;
6060 cPred.Set(g_ownship_HDTpredictor_color);
6061 if (cPred == wxNullColour) cPred = PredColor();
6063 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6064 : g_cog_predictor_width * 0.8);
6065 wxDash dash_short[2];
6067 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6070 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6073 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6074 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6075 ppPen2.SetDashes(2, dash_short);
6079 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6080 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6082 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6084 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6086 if (g_ownship_HDTpredictor_endmarker) {
6087 double nominal_circle_size_pixels = wxMax(
6088 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6091 if (g_ShipScaleFactorExp > 1.0)
6092 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6094 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6095 lHeadPoint.y + GPSOffsetPixels.y,
6096 nominal_circle_size_pixels / 2);
6101 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6102 double factor = 1.00;
6103 if (g_pNavAidRadarRingsStepUnits == 1)
6105 else if (g_pNavAidRadarRingsStepUnits == 2) {
6106 if (std::isnan(
gSog))
6111 factor *= g_fNavAidRadarRingsStep;
6115 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6118 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6119 pow((
double)(lGPSPoint.m_y - r.y), 2));
6120 int pix_radius = (int)lpp;
6122 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6124 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6127 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6129 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6130 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6134void ChartCanvas::ComputeShipScaleFactor(
6135 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6136 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6137 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6138 float screenResolution = m_pix_per_mm;
6141 double ship_bow_lat, ship_bow_lon;
6142 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6143 &ship_bow_lat, &ship_bow_lon);
6144 wxPoint lShipBowPoint;
6145 wxPoint2DDouble b_point =
6149 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6150 powf((
float)(b_point.m_y - a_point.m_y), 2));
6153 float shipLength_mm = shipLength_px / screenResolution;
6156 float ownship_min_mm = g_n_ownship_min_mm;
6157 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6160 float hdt_ant = icon_hdt + 180.;
6161 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6162 float dx = g_n_gps_antenna_offset_x / 1852.;
6163 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6171 if (shipLength_mm < ownship_min_mm) {
6172 dy /= shipLength_mm / ownship_min_mm;
6173 dx /= shipLength_mm / ownship_min_mm;
6176 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6178 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6179 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6185 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6186 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6188 float scale_factor = shipLength_px / ownShipLength;
6191 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6194 scale_factor = wxMax(scale_factor, scale_factor_min);
6196 scale_factor_y = scale_factor;
6197 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6198 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6201void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6202 if (!GetVP().IsValid())
return;
6204 wxPoint GPSOffsetPixels(0, 0);
6205 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6208 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6209 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6213 lShipMidPoint = lGPSPoint;
6217 float icon_hdt = pCog;
6218 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6221 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6225 double osd_head_lat, osd_head_lon;
6226 wxPoint osd_head_point;
6228 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6233 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6234 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6235 icon_rad += (float)PI;
6237 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6241 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6245 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6246 if (GetVP().chart_scale >
6249 ShipDrawLargeScale(dc, lShipMidPoint);
6255 if (m_pos_image_user)
6256 pos_image = m_pos_image_user->Copy();
6257 else if (SHIP_NORMAL == m_ownship_state)
6258 pos_image = m_pos_image_red->Copy();
6259 if (SHIP_LOWACCURACY == m_ownship_state)
6260 pos_image = m_pos_image_yellow->Copy();
6261 else if (SHIP_NORMAL != m_ownship_state)
6262 pos_image = m_pos_image_grey->Copy();
6265 if (m_pos_image_user) {
6266 pos_image = m_pos_image_user->Copy();
6268 if (SHIP_LOWACCURACY == m_ownship_state)
6269 pos_image = m_pos_image_user_yellow->Copy();
6270 else if (SHIP_NORMAL != m_ownship_state)
6271 pos_image = m_pos_image_user_grey->Copy();
6274 img_height = pos_image.GetHeight();
6276 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6277 g_OwnShipIconType > 0)
6279 int ownShipWidth = 22;
6280 int ownShipLength = 84;
6281 if (g_OwnShipIconType == 1) {
6282 ownShipWidth = pos_image.GetWidth();
6283 ownShipLength = pos_image.GetHeight();
6286 float scale_factor_x, scale_factor_y;
6287 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6288 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6289 scale_factor_x, scale_factor_y);
6291 if (g_OwnShipIconType == 1) {
6292 pos_image.Rescale(ownShipWidth * scale_factor_x,
6293 ownShipLength * scale_factor_y,
6294 wxIMAGE_QUALITY_HIGH);
6295 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6297 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6300 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6301 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6302 if (rot_image.GetAlpha(ip, jp) > 64)
6303 rot_image.SetAlpha(ip, jp, 255);
6305 wxBitmap os_bm(rot_image);
6307 int w = os_bm.GetWidth();
6308 int h = os_bm.GetHeight();
6311 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6312 lShipMidPoint.m_y - h / 2,
true);
6315 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6316 lShipMidPoint.m_y - h / 2);
6317 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6318 lShipMidPoint.m_y - h / 2 + h);
6321 else if (g_OwnShipIconType == 2) {
6322 wxPoint ownship_icon[10];
6324 for (
int i = 0; i < 10; i++) {
6326 float pxa = (float)(s_ownship_icon[j]);
6327 float pya = (float)(s_ownship_icon[j + 1]);
6328 pya *= scale_factor_y;
6329 pxa *= scale_factor_x;
6331 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6332 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6334 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6335 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6338 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6340 dc.SetBrush(wxBrush(ShipColor()));
6342 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6345 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6347 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6351 img_height = ownShipLength * scale_factor_y;
6355 if (m_pos_image_user) circle_rad = 1;
6357 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6358 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6359 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6362 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6364 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6367 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6368 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6369 if (rot_image.GetAlpha(ip, jp) > 64)
6370 rot_image.SetAlpha(ip, jp, 255);
6372 wxBitmap os_bm(rot_image);
6374 if (g_ShipScaleFactorExp > 1) {
6375 wxImage scaled_image = os_bm.ConvertToImage();
6376 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6378 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6379 scaled_image.GetHeight() * factor,
6380 wxIMAGE_QUALITY_HIGH));
6382 int w = os_bm.GetWidth();
6383 int h = os_bm.GetHeight();
6386 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6387 lShipMidPoint.m_y - h / 2,
true);
6391 if (m_pos_image_user) circle_rad = 1;
6393 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6394 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6395 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6398 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6399 lShipMidPoint.m_y - h / 2);
6400 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6401 lShipMidPoint.m_y - h / 2 + h);
6406 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6419void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6420 float &MinorSpacing) {
6425 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6426 {.000001f, 45.0f, 15.0f},
6427 {.0002f, 30.0f, 10.0f},
6428 {.0003f, 10.0f, 2.0f},
6429 {.0008f, 5.0f, 1.0f},
6430 {.001f, 2.0f, 30.0f / 60.0f},
6431 {.003f, 1.0f, 20.0f / 60.0f},
6432 {.006f, 0.5f, 10.0f / 60.0f},
6433 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6434 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6435 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6436 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6437 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6438 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6439 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6440 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6443 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6444 if (view_scale_ppm < lltab[tabi][0])
break;
6445 MajorSpacing = lltab[tabi][1];
6446 MinorSpacing = lltab[tabi][2];
6460wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6461 int deg = (int)fabs(latlon);
6462 float min = fabs((fabs(latlon) - deg) * 60.0);
6472 }
else if (latlon < 0.0) {
6484 if (spacing >= 1.0) {
6485 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6486 }
else if (spacing >= (1.0 / 60.0)) {
6487 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6489 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6506void ChartCanvas::GridDraw(
ocpnDC &dc) {
6507 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6509 double nlat, elon, slat, wlon;
6512 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6514 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6516 if (!m_pgridFont) SetupGridFont();
6517 dc.SetFont(*m_pgridFont);
6518 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6521 h = m_canvas_height;
6532 dlon = dlon + 360.0;
6535 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6538 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6541 while (lat < nlat) {
6544 CalcGridText(lat, gridlatMajor,
true);
6546 dc.
DrawLine(0, r.y, w, r.y,
false);
6547 dc.DrawText(st, 0, r.y);
6548 lat = lat + gridlatMajor;
6550 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6554 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6557 while (lat < nlat) {
6560 dc.
DrawLine(0, r.y, 10, r.y,
false);
6561 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6562 lat = lat + gridlatMinor;
6566 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6569 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6572 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6574 wxString st = CalcGridText(lon, gridlonMajor,
false);
6576 dc.
DrawLine(r.x, 0, r.x, h,
false);
6577 dc.DrawText(st, r.x, 0);
6578 lon = lon + gridlonMajor;
6583 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6587 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6589 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6592 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6593 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6594 lon = lon + gridlonMinor;
6601void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6603 double blat, blon, tlat, tlon;
6606 int x_origin = m_bDisplayGrid ? 60 : 20;
6607 int y_origin = m_canvas_height - 50;
6613 if (GetVP().chart_scale > 80000)
6617 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6618 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6623 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6624 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6628 double rotation = -VPoint.
rotation;
6630 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6632 int l1 = (y_origin - r.y) / count;
6634 for (
int i = 0; i < count; i++) {
6641 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6644 double blat, blon, tlat, tlon;
6651 int y_origin = m_canvas_height - chartbar_height - 5;
6655 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6662 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6667 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6668 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6672 float places = floor(logdist), rem = logdist - places;
6673 dist = pow(10, places);
6680 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6681 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6682 double rotation = -VPoint.
rotation;
6688 int l1 = r.x - x_origin;
6690 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6695 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6696 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6697 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6699 if (!m_pgridFont) SetupGridFont();
6700 dc.SetFont(*m_pgridFont);
6701 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6703 dc.GetTextExtent(s, &w, &h);
6709 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6713void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6718 double ra_max = 40.;
6720 wxPen pen_save = dc.GetPen();
6722 wxDateTime now = wxDateTime::Now();
6728 x0 = x1 = x + radius;
6733 while (angle < 360.) {
6734 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6737 if (angle > 360.) angle = 360.;
6739 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6747 x1 = (int)(x + cos(angle * PI / 180.) * r);
6748 y1 = (int)(y + sin(angle * PI / 180.) * r);
6758 dc.
DrawLine(x + radius, y, x1, y1);
6760 dc.SetPen(pen_save);
6763static bool bAnchorSoundPlaying =
false;
6765static void onAnchorSoundFinished(
void *ptr) {
6766 o_sound::g_anchorwatch_sound->UnLoad();
6767 bAnchorSoundPlaying =
false;
6770void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6771 using namespace o_sound;
6773 bool play_sound =
false;
6775 if (AnchorAlertOn1) {
6776 wxPoint TargetPoint;
6779 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6780 TargetPoint.y, 100);
6784 AnchorAlertOn1 =
false;
6787 if (AnchorAlertOn2) {
6788 wxPoint TargetPoint;
6791 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6792 TargetPoint.y, 100);
6796 AnchorAlertOn2 =
false;
6799 if (!bAnchorSoundPlaying) {
6800 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6801 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6802 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6803 if (g_anchorwatch_sound->IsOk()) {
6804 bAnchorSoundPlaying =
true;
6805 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6806 g_anchorwatch_sound->Play();
6812void ChartCanvas::UpdateShips() {
6815 wxClientDC dc(
this);
6816 if (!dc.IsOk())
return;
6818 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6819 if (!test_bitmap.IsOk())
return;
6821 wxMemoryDC temp_dc(test_bitmap);
6823 temp_dc.ResetBoundingBox();
6824 temp_dc.DestroyClippingRegion();
6825 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6836 ocpndc.CalcBoundingBox(px.x, px.y);
6841 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6842 temp_dc.MaxY() - temp_dc.MinY());
6844 wxRect own_ship_update_rect = ship_draw_rect;
6846 if (!own_ship_update_rect.IsEmpty()) {
6849 own_ship_update_rect.Union(ship_draw_last_rect);
6850 own_ship_update_rect.Inflate(2);
6853 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6855 ship_draw_last_rect = ship_draw_rect;
6857 temp_dc.SelectObject(wxNullBitmap);
6860void ChartCanvas::UpdateAlerts() {
6865 wxClientDC dc(
this);
6869 dc.GetSize(&sx, &sy);
6872 wxBitmap test_bitmap(sx, sy, -1);
6876 temp_dc.SelectObject(test_bitmap);
6878 temp_dc.ResetBoundingBox();
6879 temp_dc.DestroyClippingRegion();
6880 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6887 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6888 temp_dc.MaxX() - temp_dc.MinX(),
6889 temp_dc.MaxY() - temp_dc.MinY());
6891 if (!alert_rect.IsEmpty())
6892 alert_rect.Inflate(2);
6894 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6897 wxRect alert_update_rect = alert_draw_rect;
6898 alert_update_rect.Union(alert_rect);
6901 RefreshRect(alert_update_rect,
false);
6905 alert_draw_rect = alert_rect;
6907 temp_dc.SelectObject(wxNullBitmap);
6910void ChartCanvas::UpdateAIS() {
6916 wxClientDC dc(
this);
6920 dc.GetSize(&sx, &sy);
6928 if (
g_pAIS->GetTargetList().size() > 10) {
6929 ais_rect = wxRect(0, 0, sx, sy);
6932 wxBitmap test_bitmap(sx, sy, -1);
6936 temp_dc.SelectObject(test_bitmap);
6938 temp_dc.ResetBoundingBox();
6939 temp_dc.DestroyClippingRegion();
6940 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6944 AISDraw(ocpndc, GetVP(),
this);
6945 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6949 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6950 temp_dc.MaxY() - temp_dc.MinY());
6952 if (!ais_rect.IsEmpty())
6953 ais_rect.Inflate(2);
6955 temp_dc.SelectObject(wxNullBitmap);
6958 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6961 wxRect ais_update_rect = ais_draw_rect;
6962 ais_update_rect.Union(ais_rect);
6965 RefreshRect(ais_update_rect,
false);
6969 ais_draw_rect = ais_rect;
6972void ChartCanvas::ToggleCPAWarn() {
6973 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6979 g_bTCPA_Max =
false;
6983 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6984 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6986 if (!g_AisFirstTimeUse) {
6987 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
6988 _(
"CPA") +
" " + mess, 4, 4);
6993void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6995void ChartCanvas::OnSize(wxSizeEvent &event) {
6996 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6998 GetClientSize(&m_canvas_width, &m_canvas_height);
7002 m_displayScale = GetContentScaleFactor();
7006 m_canvas_width *= m_displayScale;
7007 m_canvas_height *= m_displayScale;
7020 m_absolute_min_scale_ppm =
7022 (1.2 * WGS84_semimajor_axis_meters * PI);
7025 gFrame->ProcessCanvasResize();
7035 SetMUIBarPosition();
7036 UpdateFollowButtonState();
7037 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7041 xr_margin = m_canvas_width * 95 / 100;
7042 xl_margin = m_canvas_width * 5 / 100;
7043 yt_margin = m_canvas_height * 5 / 100;
7044 yb_margin = m_canvas_height * 95 / 100;
7047 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7052 m_brepaint_piano =
true;
7055 m_dc_route.SelectObject(wxNullBitmap);
7058 m_dc_route.SelectObject(*proute_bm);
7072 m_glcc->OnSize(event);
7081void ChartCanvas::ProcessNewGUIScale() {
7089void ChartCanvas::CreateMUIBar() {
7090 if (g_useMUI && !m_muiBar) {
7091 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7092 m_muiBar->SetColorScheme(m_cs);
7093 m_muiBarHOSize = m_muiBar->m_size;
7101 SetMUIBarPosition();
7102 UpdateFollowButtonState();
7103 m_muiBar->UpdateDynamicValues();
7104 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7108void ChartCanvas::SetMUIBarPosition() {
7112 int pianoWidth = GetClientSize().x * 0.6f;
7117 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7118 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7120 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7121 m_muiBar->SetColorScheme(m_cs);
7125 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7126 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7128 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7129 m_muiBar->SetColorScheme(m_cs);
7133 m_muiBar->SetBestPosition();
7137void ChartCanvas::DestroyMuiBar() {
7144void ChartCanvas::ShowCompositeInfoWindow(
7145 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7147 if (NULL == m_pCIWin) {
7152 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7155 s = _(
"Composite of ");
7158 s1.Printf(
"%d ", n_charts);
7166 s1.Printf(_(
"Chart scale"));
7169 s2.Printf(
"1:%d\n",
scale);
7173 s1 = _(
"Zoom in for more information");
7177 int char_width = s1.Length();
7178 int char_height = 3;
7180 if (g_bChartBarEx) {
7183 for (
int i : index_vector) {
7185 wxString path = cte.GetFullSystemPath();
7189 char_width = wxMax(char_width, path.Length());
7190 if (j++ >= 9)
break;
7193 s +=
" .\n .\n .\n";
7202 m_pCIWin->SetString(s);
7204 m_pCIWin->FitToChars(char_width, char_height);
7207 p.x = x / GetContentScaleFactor();
7208 if ((p.x + m_pCIWin->GetWinSize().x) >
7209 (m_canvas_width / GetContentScaleFactor()))
7210 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7211 m_pCIWin->GetWinSize().x) /
7214 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7215 4 - m_pCIWin->GetWinSize().y;
7217 m_pCIWin->dbIndex = 0;
7218 m_pCIWin->chart_scale = 0;
7219 m_pCIWin->SetPosition(p);
7220 m_pCIWin->SetBitmap();
7221 m_pCIWin->Refresh();
7225 HideChartInfoWindow();
7229void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7231 if (NULL == m_pCIWin) {
7236 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7245 dbIndex, FULL_INIT);
7247 int char_width, char_height;
7248 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7249 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7251 m_pCIWin->SetString(s);
7252 m_pCIWin->FitToChars(char_width, char_height);
7255 p.x = x / GetContentScaleFactor();
7256 if ((p.x + m_pCIWin->GetWinSize().x) >
7257 (m_canvas_width / GetContentScaleFactor()))
7258 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7259 m_pCIWin->GetWinSize().x) /
7262 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7263 4 - m_pCIWin->GetWinSize().y;
7265 m_pCIWin->dbIndex = dbIndex;
7266 m_pCIWin->SetPosition(p);
7267 m_pCIWin->SetBitmap();
7268 m_pCIWin->Refresh();
7272 HideChartInfoWindow();
7276void ChartCanvas::HideChartInfoWindow() {
7279 m_pCIWin->Destroy();
7283 androidForceFullRepaint();
7288void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7289 wxMouseEvent ev(wxEVT_MOTION);
7292 ev.m_leftDown = mouse_leftisdown;
7294 wxEvtHandler *evthp = GetEventHandler();
7296 ::wxPostEvent(evthp, ev);
7299void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7300 if ((m_panx_target_final - m_panx_target_now) ||
7301 (m_pany_target_final - m_pany_target_now)) {
7302 DoTimedMovementTarget();
7307void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7309bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7311 if (m_disable_edge_pan)
return false;
7314 int pan_margin = m_canvas_width * margin / 100;
7315 int pan_timer_set = 200;
7316 double pan_delta = GetVP().
pix_width * delta / 100;
7320 if (x > m_canvas_width - pan_margin) {
7325 else if (x < pan_margin) {
7330 if (y < pan_margin) {
7335 else if (y > m_canvas_height - pan_margin) {
7344 wxMouseState state = ::wxGetMouseState();
7345#if wxCHECK_VERSION(3, 0, 0)
7346 if (!state.LeftIsDown())
7348 if (!state.LeftDown())
7353 if ((bft) && !pPanTimer->IsRunning()) {
7355 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7361 if ((!bft) && pPanTimer->IsRunning()) {
7371void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7372 bool setBeingEdited) {
7373 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7374 m_pRoutePointEditTarget = NULL;
7375 m_pFoundPoint = NULL;
7378 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7379 SelectableItemList SelList =
pSelect->FindSelectionList(
7389 bool brp_viz =
false;
7390 if (m_pEditRouteArray) {
7391 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7392 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7393 if (pr->IsVisible()) {
7399 brp_viz = frp->IsVisible();
7403 if (m_pEditRouteArray)
7405 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7406 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7409 m_bRouteEditing = setBeingEdited;
7412 frp->m_bRPIsBeingEdited = setBeingEdited;
7413 m_bMarkEditing = setBeingEdited;
7416 m_pRoutePointEditTarget = frp;
7417 m_pFoundPoint = pFind;
7422std::shared_ptr<HostApi121::PiPointContext>
7423ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7437 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7438 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7439 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7440 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7441 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7445 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7448 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7453 int FoundAIS_MMSI = 0;
7455 FoundAIS_MMSI = pFindAIS->GetUserData();
7458 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7459 seltype |= SELTYPE_AISTARGET;
7465 Route *SelectedRoute = NULL;
7471 Route *pSelectedActiveRoute = NULL;
7472 Route *pSelectedVizRoute = NULL;
7475 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7476 SelectableItemList SelList =
7477 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7485 bool brp_viz =
false;
7487 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7489 if (pr->IsVisible()) {
7494 if (!brp_viz && prp->IsShared())
7496 brp_viz = prp->IsVisible();
7499 brp_viz = prp->IsVisible();
7501 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7507 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7510 pSelectedActiveRoute = pr;
7511 pFoundActiveRoutePoint = prp;
7516 if (NULL == pSelectedVizRoute) {
7517 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7519 if (pr->IsVisible()) {
7520 pSelectedVizRoute = pr;
7521 pFoundVizRoutePoint = prp;
7527 delete proute_array;
7532 if (pFoundActiveRoutePoint) {
7533 FoundRoutePoint = pFoundActiveRoutePoint;
7534 SelectedRoute = pSelectedActiveRoute;
7535 }
else if (pFoundVizRoutePoint) {
7536 FoundRoutePoint = pFoundVizRoutePoint;
7537 SelectedRoute = pSelectedVizRoute;
7540 FoundRoutePoint = pFirstVizPoint;
7542 if (SelectedRoute) {
7543 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7544 }
else if (FoundRoutePoint) {
7545 seltype |= SELTYPE_MARKPOINT;
7550 if (m_pFoundRoutePoint) {
7554 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7555 RefreshRect(wp_rect,
true);
7564 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7565 SelectableItemList SelList =
7566 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7568 if (NULL == SelectedRoute)
7573 if (pr->IsVisible()) {
7580 if (SelectedRoute) {
7581 if (NULL == FoundRoutePoint)
7582 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7585 seltype |= SELTYPE_ROUTESEGMENT;
7590 if (pFindTrackSeg) {
7591 m_pSelectedTrack = NULL;
7592 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7593 SelectableItemList SelList =
7594 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7597 wxSelectableItemListNode *node = SelList.GetFirst();
7602 if (pt->IsVisible()) {
7603 m_pSelectedTrack = pt;
7606 node = node->GetNext();
7609 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7613 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7616 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7617 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7618 rstruct->object_ident =
"";
7620 if (seltype == SELTYPE_AISTARGET) {
7621 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7623 val.Printf(
"%d", FoundAIS_MMSI);
7624 rstruct->object_ident = val.ToStdString();
7625 }
else if (seltype & SELTYPE_MARKPOINT) {
7626 if (FoundRoutePoint) {
7627 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7628 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7630 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7631 if (SelectedRoute) {
7632 rstruct->object_type =
7633 HostApi121::PiContextObjectType::kObjectRoutesegment;
7634 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7641void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7642 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7643 singleClickEventIsValid =
false;
7644 m_DoubleClickTimer->Stop();
7649bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7650 if (!m_bChartDragging && !m_bDrawingRoute) {
7655 if (m_Compass && m_Compass->IsShown()) {
7657 bool isInCompass = logicalRect.Contains(event.GetPosition());
7658 if (isInCompass || m_mouseWasInCompass) {
7659 if (m_Compass->MouseEvent(event)) {
7660 cursor_region = CENTER;
7661 if (!g_btouch) SetCanvasCursor(event);
7662 m_mouseWasInCompass = isInCompass;
7666 m_mouseWasInCompass = isInCompass;
7669 if (m_notification_button && m_notification_button->IsShown()) {
7671 bool isinButton = logicalRect.Contains(event.GetPosition());
7673 SetCursor(*pCursorArrow);
7674 if (event.LeftDown()) HandleNotificationMouseClick();
7679 if (MouseEventToolbar(event))
return true;
7681 if (MouseEventChartBar(event))
return true;
7683 if (MouseEventMUIBar(event))
return true;
7685 if (MouseEventIENCBar(event))
return true;
7690void ChartCanvas::HandleNotificationMouseClick() {
7691 if (!m_NotificationsList) {
7695 m_NotificationsList->RecalculateSize();
7696 m_NotificationsList->Hide();
7699 if (m_NotificationsList->IsShown()) {
7700 m_NotificationsList->Hide();
7702 m_NotificationsList->RecalculateSize();
7703 m_NotificationsList->ReloadNotificationList();
7704 m_NotificationsList->Show();
7707bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7708 if (!g_bShowChartBar)
return false;
7710 if (!m_Piano->MouseEvent(event))
return false;
7712 cursor_region = CENTER;
7713 if (!g_btouch) SetCanvasCursor(event);
7717bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7718 if (!IsPrimaryCanvas())
return false;
7727 cursor_region = CENTER;
7728 if (!g_btouch) SetCanvasCursor(event);
7732bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7733 if (!IsPrimaryCanvas())
return false;
7746bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7748 if (!m_muiBar->MouseEvent(event))
return false;
7751 cursor_region = CENTER;
7752 if (!g_btouch) SetCanvasCursor(event);
7764 event.GetPosition(&x, &y);
7766 x *= m_displayScale;
7767 y *= m_displayScale;
7769 m_MouseDragging =
event.Dragging();
7775 if (event.Dragging()) {
7776 if ((x == mouse_x) && (y == mouse_y))
return true;
7782 mouse_leftisdown =
event.LeftDown();
7786 cursor_region = CENTER;
7790 if (m_Compass && m_Compass->IsShown() &&
7791 m_Compass->
GetRect().Contains(event.GetPosition())) {
7792 cursor_region = CENTER;
7793 }
else if (x > xr_margin) {
7794 cursor_region = MID_RIGHT;
7795 }
else if (x < xl_margin) {
7796 cursor_region = MID_LEFT;
7797 }
else if (y > yb_margin - chartbar_height &&
7798 y < m_canvas_height - chartbar_height) {
7799 cursor_region = MID_TOP;
7800 }
else if (y < yt_margin) {
7801 cursor_region = MID_BOT;
7803 cursor_region = CENTER;
7806 if (!g_btouch) SetCanvasCursor(event);
7810 leftIsDown =
event.LeftDown();
7813 if (event.LeftDown()) {
7814 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7817 g_bTempShowMenuBar =
false;
7818 parent_frame->ApplyGlobalSettings(
false);
7826 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7827 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7831 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7832 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7835 event.SetEventObject(
this);
7836 if (SendMouseEventToPlugins(event))
7843 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7844 StartChartDragInertia();
7847 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7848 !singleClickEventIsValid) {
7850 if (m_DoubleClickTimer->IsRunning()) {
7851 m_DoubleClickTimer->Stop();
7856 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7857 singleClickEvent = event;
7858 singleClickEventIsValid =
true;
7867 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7868 if (g_click_stop > 0) {
7876 if (GetUpMode() == COURSE_UP_MODE) {
7877 m_b_rot_hidef =
false;
7878 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7880 pRotDefTimer->Stop();
7883 bool bRoll = !g_btouch;
7888 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7889 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7890 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7891 m_RolloverPopupTimer.Start(
7895 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7899 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7908#if !defined(__WXGTK__) && !defined(__WXQT__)
7916 if ((x >= 0) && (y >= 0))
7921 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7922 wxPoint p = ClientToScreen(wxPoint(x, y));
7928 if (m_routeState >= 2) {
7931 m_bDrawingRoute =
true;
7933 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7938 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7941 m_bDrawingRoute =
true;
7943 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7956#if defined(__WXMAC__) || defined(__ANDROID__)
7960 wxClientDC cdc(GetParent());
7972 if (m_pSelectedRoute) {
7974 m_pSelectedRoute->DeSelectRoute();
7976 if (g_bopengl && m_glcc) {
7981 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7984 if (m_pFoundRoutePoint) {
7992 if (g_btouch && m_pRoutePointEditTarget) {
7995 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7999 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8000 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8001 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8002 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8003 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8007 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8010 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8016 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8019 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8020 seltype |= SELTYPE_AISTARGET;
8025 m_pFoundRoutePoint = NULL;
8030 Route *pSelectedActiveRoute = NULL;
8031 Route *pSelectedVizRoute = NULL;
8034 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8035 SelectableItemList SelList =
8036 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8044 bool brp_viz =
false;
8046 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8048 if (pr->IsVisible()) {
8053 if (!brp_viz && prp->IsShared())
8055 brp_viz = prp->IsVisible();
8058 brp_viz = prp->IsVisible();
8060 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8065 m_pSelectedRoute = NULL;
8067 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8070 pSelectedActiveRoute = pr;
8071 pFoundActiveRoutePoint = prp;
8076 if (NULL == pSelectedVizRoute) {
8077 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8079 if (pr->IsVisible()) {
8080 pSelectedVizRoute = pr;
8081 pFoundVizRoutePoint = prp;
8087 delete proute_array;
8092 if (pFoundActiveRoutePoint) {
8093 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8094 m_pSelectedRoute = pSelectedActiveRoute;
8095 }
else if (pFoundVizRoutePoint) {
8096 m_pFoundRoutePoint = pFoundVizRoutePoint;
8097 m_pSelectedRoute = pSelectedVizRoute;
8100 m_pFoundRoutePoint = pFirstVizPoint;
8102 if (m_pSelectedRoute) {
8103 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8104 }
else if (m_pFoundRoutePoint) {
8105 seltype |= SELTYPE_MARKPOINT;
8109 if (m_pFoundRoutePoint) {
8113 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8114 RefreshRect(wp_rect,
true);
8122 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8123 SelectableItemList SelList =
8124 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8126 if (NULL == m_pSelectedRoute)
8131 if (pr->IsVisible()) {
8132 m_pSelectedRoute = pr;
8138 if (m_pSelectedRoute) {
8139 if (NULL == m_pFoundRoutePoint)
8140 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8145 if (g_bopengl && m_glcc) {
8150 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8152 seltype |= SELTYPE_ROUTESEGMENT;
8156 if (pFindTrackSeg) {
8157 m_pSelectedTrack = NULL;
8158 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8159 SelectableItemList SelList =
8160 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8165 if (pt->IsVisible()) {
8166 m_pSelectedTrack = pt;
8170 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8176 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8177 seltype |= SELTYPE_CURRENTPOINT;
8180 else if (pFindTide) {
8181 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8182 seltype |= SELTYPE_TIDEPOINT;
8187 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8192IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8202 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8203 SelectableItemList SelList =
8204 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8207 pFind = *SelList.begin();
8208 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8210 auto node = SelList.begin();
8211 if (SelList.size() > 1) {
8212 for (++node; node != SelList.end(); ++node) {
8215 if (pIDX_candidate->
IDX_type ==
'c') {
8216 pIDX_best_candidate = pIDX_candidate;
8221 pFind = *SelList.begin();
8222 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8225 return pIDX_best_candidate;
8227void ChartCanvas::CallPopupMenu(
int x,
int y) {
8231 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8239 if (SELTYPE_CURRENTPOINT == seltype) {
8245 if (SELTYPE_TIDEPOINT == seltype) {
8251 InvokeCanvasMenu(x, y, seltype);
8254 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8258 m_pSelectedRoute = NULL;
8260 if (m_pFoundRoutePoint) {
8261 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8264 m_pFoundRoutePoint = NULL;
8270bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8278 event.GetPosition(&x, &y);
8284 SelectRadius = g_Platform->GetSelectRadiusPix() /
8285 (m_true_scale_ppm * 1852 * 60);
8292 if (event.LeftDClick() && (cursor_region == CENTER)) {
8293 m_DoubleClickTimer->Start();
8294 singleClickEventIsValid =
false;
8300 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8303 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8306 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8307 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8308 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8314 SelectableItemList rpSelList =
8315 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8316 bool b_onRPtarget =
false;
8319 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8320 b_onRPtarget =
true;
8327 if (m_pRoutePointEditTarget) {
8329 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8335 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8338 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8339 m_pRoutePointEditTarget = NULL;
8340 RefreshRect(wp_rect,
true);
8344 auto node = rpSelList.begin();
8345 if (node != rpSelList.end()) {
8349 wxArrayPtrVoid *proute_array =
8354 bool brp_viz =
false;
8356 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8358 if (pr->IsVisible()) {
8363 delete proute_array;
8367 brp_viz = frp->IsVisible();
8369 brp_viz = frp->IsVisible();
8372 ShowMarkPropertiesDialog(frp);
8380 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8384 if (pr->IsVisible()) {
8385 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8390 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8394 if (pt->IsVisible()) {
8395 ShowTrackPropertiesDialog(pt);
8404 if (m_bShowCurrent) {
8406 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8408 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8416 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8418 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8426 ShowObjectQueryWindow(x, y, zlat, zlon);
8431 if (event.LeftDown()) {
8447 bool appending =
false;
8448 bool inserting =
false;
8451 SetCursor(*pCursorPencil);
8455 m_bRouteEditing =
true;
8457 if (m_routeState == 1) {
8458 m_pMouseRoute =
new Route();
8459 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8469 double nearby_radius_meters =
8470 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8473 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8474 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8475 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8476 wxArrayPtrVoid *proute_array =
8481 bool brp_viz =
false;
8483 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8485 if (pr->IsVisible()) {
8490 delete proute_array;
8492 pNearbyPoint->IsShared())
8495 pNearbyPoint->IsVisible();
8497 brp_viz = pNearbyPoint->IsVisible();
8500 wxString msg = _(
"Use nearby waypoint?");
8502 const bool noname(pNearbyPoint->GetName() ==
"");
8505 _(
"Use nearby nameless waypoint and name it M with"
8506 " a unique number?");
8509 m_FinishRouteOnKillFocus =
false;
8511 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8512 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8513 m_FinishRouteOnKillFocus =
true;
8514 if (dlg_return == wxID_YES) {
8516 if (m_pMouseRoute) {
8517 int last_wp_num = m_pMouseRoute->GetnPoints();
8519 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8520 wxString wp_name = wxString::Format(
8521 "M%002i-%s", last_wp_num + 1, guid_short);
8522 pNearbyPoint->SetName(wp_name);
8524 pNearbyPoint->SetName(
"WPXX");
8526 pMousePoint = pNearbyPoint;
8529 if (m_routeState > 1)
8530 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8531 Undo_HasParent, NULL);
8534 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8535 bool procede =
false;
8539 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8545 m_FinishRouteOnKillFocus =
false;
8551 _(
"Insert first part of this route in the new route?");
8552 if (tail->GetIndexOf(pMousePoint) ==
8555 dmsg = _(
"Insert this route in the new route?");
8557 if (tail->GetIndexOf(pMousePoint) != 1) {
8558 dlg_return = OCPNMessageBox(
8559 this, dmsg, _(
"OpenCPN Route Create"),
8560 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8561 m_FinishRouteOnKillFocus =
true;
8563 if (dlg_return == wxID_YES) {
8570 _(
"Append last part of this route to the new route?");
8571 if (tail->GetIndexOf(pMousePoint) == 1)
8573 "Append this route to the new route?");
8578 if (tail->GetLastPoint() != pMousePoint) {
8579 dlg_return = OCPNMessageBox(
8580 this, dmsg, _(
"OpenCPN Route Create"),
8581 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8582 m_FinishRouteOnKillFocus =
true;
8584 if (dlg_return == wxID_YES) {
8595 if (!FindRouteContainingWaypoint(pMousePoint))
8596 pMousePoint->SetShared(
true);
8601 if (NULL == pMousePoint) {
8602 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8604 pMousePoint->SetNameShown(
false);
8608 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8610 if (m_routeState > 1)
8611 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8612 Undo_IsOrphanded, NULL);
8615 if (m_pMouseRoute) {
8616 if (m_routeState == 1) {
8618 m_pMouseRoute->AddPoint(pMousePoint);
8622 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8623 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8624 &rhumbBearing, &rhumbDist);
8625 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8626 rlat, &gcDist, &gcBearing, NULL);
8627 double gcDistNM = gcDist / 1852.0;
8630 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8631 pow(rhumbDist - gcDistNM - 1, 0.5);
8634 msg << _(
"For this leg the Great Circle route is ")
8636 << _(
" shorter than rhumbline.\n\n")
8637 << _(
"Would you like include the Great Circle routing points "
8640 m_FinishRouteOnKillFocus =
false;
8641 m_disable_edge_pan =
true;
8644 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8645 wxYES_NO | wxNO_DEFAULT);
8647 m_disable_edge_pan =
false;
8648 m_FinishRouteOnKillFocus =
true;
8650 if (answer == wxID_YES) {
8652 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8653 wxRealPoint gcCoord;
8655 for (
int i = 1; i <= segmentCount; i++) {
8656 double fraction = (double)i * (1.0 / (
double)segmentCount);
8657 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8658 gcDist * fraction, gcBearing,
8659 &gcCoord.x, &gcCoord.y, NULL);
8661 if (i < segmentCount) {
8662 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8664 gcPoint->SetNameShown(
false);
8666 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8668 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8671 gcPoint = pMousePoint;
8674 m_pMouseRoute->AddPoint(gcPoint);
8675 pSelect->AddSelectableRouteSegment(
8676 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8677 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8678 prevGcPoint = gcPoint;
8681 undo->CancelUndoableAction(
true);
8684 m_pMouseRoute->AddPoint(pMousePoint);
8685 pSelect->AddSelectableRouteSegment(
8686 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8687 pMousePoint, m_pMouseRoute);
8688 undo->AfterUndoableAction(m_pMouseRoute);
8692 m_pMouseRoute->AddPoint(pMousePoint);
8693 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8694 rlon, m_prev_pMousePoint,
8695 pMousePoint, m_pMouseRoute);
8696 undo->AfterUndoableAction(m_pMouseRoute);
8702 m_prev_pMousePoint = pMousePoint;
8710 int connect = tail->GetIndexOf(pMousePoint);
8715 int length = tail->GetnPoints();
8720 start = connect + 1;
8725 m_pMouseRoute->RemovePoint(
8729 for (i = start; i <= stop; i++) {
8730 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8733 m_pMouseRoute->GetnPoints();
8735 gFrame->RefreshAllCanvas();
8739 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8741 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8742 m_pMouseRoute->FinalizeForRendering();
8744 gFrame->RefreshAllCanvas();
8748 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8750 SetCursor(*pCursorPencil);
8752 if (!m_pMeasureRoute) {
8753 m_pMeasureRoute =
new Route();
8757 if (m_nMeasureState == 1) {
8764 wxEmptyString, wxEmptyString);
8766 pMousePoint->SetShowWaypointRangeRings(
false);
8768 m_pMeasureRoute->AddPoint(pMousePoint);
8772 m_prev_pMousePoint = pMousePoint;
8776 gFrame->RefreshAllCanvas();
8781 FindRoutePointsAtCursor(SelectRadius,
true);
8785 m_last_touch_down_pos =
event.GetPosition();
8787 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8795 if (ret)
return true;
8798 if (event.Dragging()) {
8801 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8803 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8805 SelectableItemList SelList =
pSelect->FindSelectionList(
8809 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8814 if (m_pRoutePointEditTarget &&
8815 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8817 SelectableItemList SelList =
pSelect->FindSelectionList(
8821 if (m_pRoutePointEditTarget == frp) {
8822 m_bIsInRadius =
true;
8827 if (!m_dragoffsetSet) {
8829 .PresetDragOffset(
this, mouse_x, mouse_y);
8830 m_dragoffsetSet =
true;
8835 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8836 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8839 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8841 DraggingAllowed =
false;
8843 if (m_pRoutePointEditTarget &&
8844 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8845 DraggingAllowed =
false;
8847 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8849 if (DraggingAllowed) {
8850 if (!undo->InUndoableAction()) {
8851 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8852 Undo_NeedsCopy, m_pFoundPoint);
8858 if (!g_bopengl && m_pEditRouteArray) {
8859 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8860 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8867 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8868 pre_rect.Union(route_rect);
8876 if (CheckEdgePan(x, y,
true, 5, 2))
8884 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8886 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8887 m_pRoutePointEditTarget,
8888 SELTYPE_DRAGHANDLE);
8889 m_pFoundPoint->m_slat =
8890 m_pRoutePointEditTarget->m_lat;
8891 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8893 m_pRoutePointEditTarget->m_lat =
8895 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8896 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8897 m_pFoundPoint->m_slat =
8899 m_pFoundPoint->m_slon = new_cursor_lon;
8915 if (m_pEditRouteArray) {
8916 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8918 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8921 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8922 post_rect.Union(route_rect);
8928 pre_rect.Union(post_rect);
8929 RefreshRect(pre_rect,
false);
8931 gFrame->RefreshCanvasOther(
this);
8932 m_bRoutePoinDragging =
true;
8937 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8938 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8941 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8943 DraggingAllowed =
false;
8945 if (m_pRoutePointEditTarget &&
8946 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8947 DraggingAllowed =
false;
8949 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8951 if (DraggingAllowed) {
8952 if (!undo->InUndoableAction()) {
8953 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8954 Undo_NeedsCopy, m_pFoundPoint);
8968 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8974 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8975 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8976 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8977 (
int)(lppmax - (pre_rect.height / 2)));
8985 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8988 m_pRoutePointEditTarget,
8989 SELTYPE_DRAGHANDLE);
8990 m_pFoundPoint->m_slat =
8991 m_pRoutePointEditTarget->m_lat;
8992 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8994 m_pRoutePointEditTarget->m_lat =
8997 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9010 if (!g_btouch) InvalidateGL();
9016 .CalculateDCRect(m_dc_route,
this, &post_rect);
9017 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9018 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9019 (
int)(lppmax - (post_rect.height / 2)));
9022 pre_rect.Union(post_rect);
9023 RefreshRect(pre_rect,
false);
9025 gFrame->RefreshCanvasOther(
this);
9026 m_bRoutePoinDragging =
true;
9028 ret = g_btouch ? m_bRoutePoinDragging :
true;
9031 if (ret)
return true;
9034 if (event.LeftUp()) {
9035 bool b_startedit_route =
false;
9036 m_dragoffsetSet =
false;
9039 m_bChartDragging =
false;
9040 m_bIsInRadius =
false;
9045 m_bedge_pan =
false;
9050 bool appending =
false;
9051 bool inserting =
false;
9057 if (m_pRoutePointEditTarget) {
9063 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9064 RefreshRect(wp_rect,
true);
9066 m_pRoutePointEditTarget = NULL;
9068 m_bRouteEditing =
true;
9070 if (m_routeState == 1) {
9071 m_pMouseRoute =
new Route();
9072 m_pMouseRoute->SetHiLite(50);
9076 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9083 double nearby_radius_meters =
9084 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9087 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9088 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9089 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9092 m_FinishRouteOnKillFocus =
9094 dlg_return = OCPNMessageBox(
9095 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9096 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9097 m_FinishRouteOnKillFocus =
true;
9099 dlg_return = wxID_YES;
9101 if (dlg_return == wxID_YES) {
9102 pMousePoint = pNearbyPoint;
9105 if (m_routeState > 1)
9106 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9107 Undo_HasParent, NULL);
9108 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9110 bool procede =
false;
9114 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9120 m_FinishRouteOnKillFocus =
false;
9121 if (m_routeState == 1) {
9125 _(
"Insert first part of this route in the new route?");
9126 if (tail->GetIndexOf(pMousePoint) ==
9129 dmsg = _(
"Insert this route in the new route?");
9131 if (tail->GetIndexOf(pMousePoint) != 1) {
9133 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9134 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9135 m_FinishRouteOnKillFocus =
true;
9137 if (dlg_return == wxID_YES) {
9144 _(
"Append last part of this route to the new route?");
9145 if (tail->GetIndexOf(pMousePoint) == 1)
9147 "Append this route to the new route?");
9151 if (tail->GetLastPoint() != pMousePoint) {
9153 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9154 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9155 m_FinishRouteOnKillFocus =
true;
9157 if (dlg_return == wxID_YES) {
9168 if (!FindRouteContainingWaypoint(pMousePoint))
9169 pMousePoint->SetShared(
true);
9173 if (NULL == pMousePoint) {
9174 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9176 pMousePoint->SetNameShown(
false);
9178 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9180 if (m_routeState > 1)
9181 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9182 Undo_IsOrphanded, NULL);
9185 if (m_routeState == 1) {
9187 m_pMouseRoute->AddPoint(pMousePoint);
9188 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9192 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9193 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9194 &rhumbBearing, &rhumbDist);
9195 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9196 &gcDist, &gcBearing, NULL);
9197 double gcDistNM = gcDist / 1852.0;
9200 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9201 pow(rhumbDist - gcDistNM - 1, 0.5);
9204 msg << _(
"For this leg the Great Circle route is ")
9206 << _(
" shorter than rhumbline.\n\n")
9207 << _(
"Would you like include the Great Circle routing points "
9211 m_FinishRouteOnKillFocus =
false;
9212 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9213 wxYES_NO | wxNO_DEFAULT);
9214 m_FinishRouteOnKillFocus =
true;
9216 int answer = wxID_NO;
9219 if (answer == wxID_YES) {
9221 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9222 wxRealPoint gcCoord;
9224 for (
int i = 1; i <= segmentCount; i++) {
9225 double fraction = (double)i * (1.0 / (
double)segmentCount);
9226 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9227 gcDist * fraction, gcBearing,
9228 &gcCoord.x, &gcCoord.y, NULL);
9230 if (i < segmentCount) {
9231 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9233 gcPoint->SetNameShown(
false);
9234 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9237 gcPoint = pMousePoint;
9240 m_pMouseRoute->AddPoint(gcPoint);
9241 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9243 pSelect->AddSelectableRouteSegment(
9244 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9245 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9246 prevGcPoint = gcPoint;
9249 undo->CancelUndoableAction(
true);
9252 m_pMouseRoute->AddPoint(pMousePoint);
9253 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9254 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9255 rlon, m_prev_pMousePoint,
9256 pMousePoint, m_pMouseRoute);
9257 undo->AfterUndoableAction(m_pMouseRoute);
9261 m_pMouseRoute->AddPoint(pMousePoint);
9262 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9264 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9265 rlon, m_prev_pMousePoint,
9266 pMousePoint, m_pMouseRoute);
9267 undo->AfterUndoableAction(m_pMouseRoute);
9273 m_prev_pMousePoint = pMousePoint;
9280 int connect = tail->GetIndexOf(pMousePoint);
9285 int length = tail->GetnPoints();
9290 start = connect + 1;
9295 m_pMouseRoute->RemovePoint(
9299 for (i = start; i <= stop; i++) {
9300 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9303 m_pMouseRoute->GetnPoints();
9305 gFrame->RefreshAllCanvas();
9309 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9311 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9312 m_pMouseRoute->FinalizeForRendering();
9317 }
else if (m_bMeasure_Active && m_nMeasureState)
9320 m_bedge_pan =
false;
9324 if (m_nMeasureState == 1) {
9325 m_pMeasureRoute =
new Route();
9331 if (m_pMeasureRoute) {
9334 wxEmptyString, wxEmptyString);
9337 m_pMeasureRoute->AddPoint(pMousePoint);
9341 m_prev_pMousePoint = pMousePoint;
9343 m_pMeasureRoute->GetnPoints();
9347 CancelMeasureRoute();
9353 bool bSelectAllowed =
true;
9355 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9357 bSelectAllowed =
false;
9361 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9362 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9363 significant_drag) ||
9364 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9365 significant_drag)) {
9366 bSelectAllowed =
false;
9374 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9376 if (bSelectAllowed) {
9377 bool b_was_editing_mark = m_bMarkEditing;
9378 bool b_was_editing_route = m_bRouteEditing;
9379 FindRoutePointsAtCursor(SelectRadius,
9385 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9386 m_pRoutePointEditTarget = NULL;
9388 if (!b_was_editing_route) {
9389 if (m_pEditRouteArray) {
9390 b_startedit_route =
true;
9394 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9395 m_pTrackRolloverWin->IsActive(
false);
9397 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9398 m_pRouteRolloverWin->IsActive(
false);
9402 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9404 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9412 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9413 pre_rect.Union(route_rect);
9416 RefreshRect(pre_rect,
true);
9419 b_startedit_route =
false;
9423 if (m_pRoutePointEditTarget) {
9424 if (b_was_editing_mark ||
9425 b_was_editing_route) {
9426 if (m_lastRoutePointEditTarget) {
9430 .EnableDragHandle(
false);
9431 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9432 SELTYPE_DRAGHANDLE);
9436 if (m_pRoutePointEditTarget) {
9439 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9440 wxPoint2DDouble dragHandlePoint =
9442 .GetDragHandlePoint(
this);
9444 dragHandlePoint.m_y, dragHandlePoint.m_x,
9445 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9448 if (m_lastRoutePointEditTarget) {
9452 .EnableDragHandle(
false);
9453 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9454 SELTYPE_DRAGHANDLE);
9457 wxArrayPtrVoid *lastEditRouteArray =
9459 m_lastRoutePointEditTarget);
9460 if (lastEditRouteArray) {
9461 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9463 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9468 delete lastEditRouteArray;
9479 if (m_lastRoutePointEditTarget) {
9482 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9483 RefreshRect(wp_rect,
true);
9486 if (m_pRoutePointEditTarget) {
9489 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9490 RefreshRect(wp_rect,
true);
9498 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9499 bool b_start_rollover =
false;
9503 if (pFind) b_start_rollover =
true;
9506 if (!b_start_rollover && !b_startedit_route) {
9507 SelectableItemList SelList =
pSelect->FindSelectionList(
9511 if (pr && pr->IsVisible()) {
9512 b_start_rollover =
true;
9518 if (!b_start_rollover && !b_startedit_route) {
9519 SelectableItemList SelList =
pSelect->FindSelectionList(
9523 if (tr && tr->IsVisible()) {
9524 b_start_rollover =
true;
9530 if (b_start_rollover)
9531 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9535 bool appending =
false;
9536 bool inserting =
false;
9538 if (m_bRouteEditing ) {
9540 if (m_pRoutePointEditTarget) {
9546 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9547 double nearby_radius_meters =
9548 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9549 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9550 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9551 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9553 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9557 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9559 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9563 std::find(list->begin(), list->end(), pNearbyPoint);
9564 if (pos != list->end()) {
9576 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9581 OCPNMessageBox(
this,
9582 _(
"Replace this RoutePoint by the nearby "
9584 _(
"OpenCPN RoutePoint change"),
9585 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9586 if (dlg_return == wxID_YES) {
9591 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9594 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9596 if (tail && current && (tail != current)) {
9598 connect = tail->GetIndexOf(pNearbyPoint);
9599 int index_current_route =
9600 current->GetIndexOf(m_pRoutePointEditTarget);
9601 index_last = current->GetIndexOf(current->GetLastPoint());
9602 dlg_return1 = wxID_NO;
9604 index_current_route) {
9606 if (connect != tail->GetnPoints()) {
9609 _(
"Last part of route to be appended to dragged "
9613 _(
"Full route to be appended to dragged route?");
9615 dlg_return1 = OCPNMessageBox(
9616 this, dmsg, _(
"OpenCPN Route Create"),
9617 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9618 if (dlg_return1 == wxID_YES) {
9622 }
else if (index_current_route ==
9627 _(
"First part of route to be inserted into dragged "
9629 if (connect == tail->GetnPoints())
9631 "Full route to be inserted into dragged route?");
9633 dlg_return1 = OCPNMessageBox(
9634 this, dmsg, _(
"OpenCPN Route Create"),
9635 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9636 if (dlg_return1 == wxID_YES) {
9643 if (m_pRoutePointEditTarget->IsShared()) {
9645 dlg_return = OCPNMessageBox(
9647 _(
"Do you really want to delete and replace this "
9649 "\n" + _(
"which has been created manually?"),
9650 (
"OpenCPN RoutePoint warning"),
9651 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9654 if (dlg_return == wxID_YES) {
9655 pMousePoint = pNearbyPoint;
9657 pMousePoint->SetShared(
true);
9667 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9669 if (m_pEditRouteArray) {
9670 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9672 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9677 auto pos = std::find(list->begin(), list->end(),
9678 m_pRoutePointEditTarget);
9680 pSelect->DeleteAllSelectableRoutePoints(pr);
9681 pSelect->DeleteAllSelectableRouteSegments(pr);
9684 pos = std::find(list->begin(), list->end(),
9685 m_pRoutePointEditTarget);
9688 pSelect->AddAllSelectableRouteSegments(pr);
9689 pSelect->AddAllSelectableRoutePoints(pr);
9691 pr->FinalizeForRendering();
9692 pr->UpdateSegmentDistances();
9693 if (m_bRoutePoinDragging) {
9695 NavObj_dB::GetInstance().UpdateRoute(pr);
9703 if (m_pEditRouteArray) {
9704 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9706 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9725 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9732 delete m_pRoutePointEditTarget;
9733 m_lastRoutePointEditTarget = NULL;
9734 m_pRoutePointEditTarget = NULL;
9735 undo->AfterUndoableAction(pMousePoint);
9736 undo->InvalidateUndo();
9741 else if (m_bMarkEditing) {
9742 if (m_pRoutePointEditTarget)
9743 if (m_bRoutePoinDragging) {
9745 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9749 if (m_pRoutePointEditTarget)
9750 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9752 if (!m_pRoutePointEditTarget) {
9753 delete m_pEditRouteArray;
9754 m_pEditRouteArray = NULL;
9755 m_bRouteEditing =
false;
9757 m_bRoutePoinDragging =
false;
9764 int length = tail->GetnPoints();
9765 for (
int i = connect + 1; i <= length; i++) {
9766 current->AddPointAndSegment(tail->GetPoint(i),
false);
9769 gFrame->RefreshAllCanvas();
9772 current->FinalizeForRendering();
9778 pSelect->DeleteAllSelectableRoutePoints(current);
9779 pSelect->DeleteAllSelectableRouteSegments(current);
9780 for (
int i = 1; i < connect; i++) {
9781 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9783 pSelect->AddAllSelectableRouteSegments(current);
9784 pSelect->AddAllSelectableRoutePoints(current);
9785 current->FinalizeForRendering();
9792 if (m_pEditRouteArray) {
9793 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9794 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9807 if (m_bRouteEditing) {
9810 bool appending =
false;
9811 bool inserting =
false;
9814 if (m_pRoutePointEditTarget) {
9815 m_pRoutePointEditTarget->
m_bBlink =
false;
9819 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9820 double nearby_radius_meters =
9821 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9822 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9823 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9824 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9826 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9827 bool duplicate =
false;
9829 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9831 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9835 std::find(list->begin(), list->end(), pNearbyPoint);
9836 if (pos != list->end()) {
9848 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9853 OCPNMessageBox(
this,
9854 _(
"Replace this RoutePoint by the nearby "
9856 _(
"OpenCPN RoutePoint change"),
9857 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9858 if (dlg_return == wxID_YES) {
9862 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9865 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9867 if (tail && current && (tail != current)) {
9869 connect = tail->GetIndexOf(pNearbyPoint);
9870 int index_current_route =
9871 current->GetIndexOf(m_pRoutePointEditTarget);
9872 index_last = current->GetIndexOf(current->GetLastPoint());
9873 dlg_return1 = wxID_NO;
9875 index_current_route) {
9877 if (connect != tail->GetnPoints()) {
9880 _(
"Last part of route to be appended to dragged "
9884 _(
"Full route to be appended to dragged route?");
9886 dlg_return1 = OCPNMessageBox(
9887 this, dmsg, _(
"OpenCPN Route Create"),
9888 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9889 if (dlg_return1 == wxID_YES) {
9893 }
else if (index_current_route ==
9898 _(
"First part of route to be inserted into dragged "
9900 if (connect == tail->GetnPoints())
9902 "Full route to be inserted into dragged route?");
9904 dlg_return1 = OCPNMessageBox(
9905 this, dmsg, _(
"OpenCPN Route Create"),
9906 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9907 if (dlg_return1 == wxID_YES) {
9914 if (m_pRoutePointEditTarget->IsShared()) {
9915 dlg_return = wxID_NO;
9916 dlg_return = OCPNMessageBox(
9918 _(
"Do you really want to delete and replace this "
9920 "\n" + _(
"which has been created manually?"),
9921 (
"OpenCPN RoutePoint warning"),
9922 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9925 if (dlg_return == wxID_YES) {
9926 pMousePoint = pNearbyPoint;
9928 pMousePoint->SetShared(
true);
9938 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9940 if (m_pEditRouteArray) {
9941 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9943 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9947 auto pos = std::find(list->begin(), list->end(),
9948 m_pRoutePointEditTarget);
9950 pSelect->DeleteAllSelectableRoutePoints(pr);
9951 pSelect->DeleteAllSelectableRouteSegments(pr);
9954 pos = std::find(list->begin(), list->end(),
9955 m_pRoutePointEditTarget);
9956 if (pos != list->end()) list->erase(pos);
9959 pSelect->AddAllSelectableRouteSegments(pr);
9960 pSelect->AddAllSelectableRoutePoints(pr);
9962 pr->FinalizeForRendering();
9963 pr->UpdateSegmentDistances();
9966 if (m_bRoutePoinDragging) {
9971 NavObj_dB::GetInstance().UpdateRoutePoint(
9972 m_pRoutePointEditTarget);
9974 NavObj_dB::GetInstance().UpdateRoute(pr);
9986 int length = tail->GetnPoints();
9987 for (
int i = connect + 1; i <= length; i++) {
9988 current->AddPointAndSegment(tail->GetPoint(i),
false);
9992 gFrame->RefreshAllCanvas();
9995 current->FinalizeForRendering();
10001 pSelect->DeleteAllSelectableRoutePoints(current);
10002 pSelect->DeleteAllSelectableRouteSegments(current);
10003 for (
int i = 1; i < connect; i++) {
10004 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10006 pSelect->AddAllSelectableRouteSegments(current);
10007 pSelect->AddAllSelectableRoutePoints(current);
10008 current->FinalizeForRendering();
10015 if (m_pEditRouteArray) {
10016 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10018 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10030 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10037 delete m_pRoutePointEditTarget;
10038 m_lastRoutePointEditTarget = NULL;
10039 undo->AfterUndoableAction(pMousePoint);
10040 undo->InvalidateUndo();
10045 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10048 delete m_pEditRouteArray;
10049 m_pEditRouteArray = NULL;
10053 m_bRouteEditing =
false;
10054 m_pRoutePointEditTarget = NULL;
10060 else if (m_bMarkEditing) {
10061 if (m_pRoutePointEditTarget) {
10062 if (m_bRoutePoinDragging) {
10064 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10066 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10071 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10073 RefreshRect(wp_rect,
true);
10076 m_pRoutePointEditTarget = NULL;
10077 m_bMarkEditing =
false;
10082 else if (leftIsDown) {
10083 leftIsDown =
false;
10087 if (!m_bChartDragging && !m_bMeasure_Active) {
10089 m_bChartDragging =
false;
10093 m_bRoutePoinDragging =
false;
10096 if (ret)
return true;
10099 if (event.RightDown()) {
10110 m_FinishRouteOnKillFocus =
false;
10111 CallPopupMenu(mx, my);
10112 m_FinishRouteOnKillFocus =
true;
10122 if (event.ShiftDown()) {
10126 event.GetPosition(&x, &y);
10128 x *= m_displayScale;
10129 y *= m_displayScale;
10135 int wheel_dir =
event.GetWheelRotation();
10138 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10139 wheel_dir = wheel_dir > 0 ? 1 : -1;
10141 double factor = g_mouse_zoom_sensitivity;
10142 if (wheel_dir < 0) factor = 1 / factor;
10145 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10146 if (wheel_dir == m_last_wheel_dir) {
10147 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10152 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10153 m_wheelstopwatch.Start(0);
10158 m_last_wheel_dir = wheel_dir;
10163 if (event.LeftDown()) {
10169 last_drag.x = x, last_drag.y = y;
10170 panleftIsDown =
true;
10173 if (event.LeftUp()) {
10174 if (panleftIsDown) {
10176 panleftIsDown =
false;
10179 if (!m_bChartDragging && !m_bMeasure_Active) {
10180 switch (cursor_region) {
10202 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10207 m_bChartDragging =
false;
10213 if (event.Dragging() && event.LeftIsDown()) {
10229 if (g_btouch && !m_inPinch) {
10230 struct timespec now;
10231 clock_gettime(CLOCK_MONOTONIC, &now);
10232 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10234 bool trigger_hold =
false;
10235 if (
false == m_bChartDragging) {
10236 if (m_DragTrigger < 0) {
10239 m_DragTriggerStartTime = tnow;
10240 trigger_hold =
true;
10242 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10243 m_DragTrigger = -1;
10248 if (trigger_hold)
return true;
10250 if (
false == m_bChartDragging) {
10253 last_drag.x = x - 1, last_drag.y = y - 1;
10254 m_bChartDragging =
true;
10255 m_chart_drag_total_time = 0;
10256 m_chart_drag_total_x = 0;
10257 m_chart_drag_total_y = 0;
10258 m_inertia_last_drag_x = x;
10259 m_inertia_last_drag_y = y;
10260 m_drag_vec_x.clear();
10261 m_drag_vec_y.clear();
10262 m_drag_vec_t.clear();
10263 m_last_drag_time = tnow;
10267 uint64_t delta_t = tnow - m_last_drag_time;
10268 double delta_tf = delta_t / 1e9;
10270 m_chart_drag_total_time += delta_tf;
10271 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10272 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10274 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10275 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10276 m_drag_vec_t.push_back(delta_tf);
10278 m_inertia_last_drag_x = x;
10279 m_inertia_last_drag_y = y;
10280 m_last_drag_time = tnow;
10282 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10283 if (!m_routeState) {
10286 m_bChartDragging =
true;
10288 StartTimedMovement();
10289 m_pan_drag.x += last_drag.x - x;
10290 m_pan_drag.y += last_drag.y - y;
10291 last_drag.x = x, last_drag.y = y;
10294 }
else if (!g_btouch) {
10295 if ((last_drag.x != x) || (last_drag.y != y)) {
10296 if (!m_routeState) {
10299 m_bChartDragging =
true;
10300 StartTimedMovement();
10301 m_pan_drag.x += last_drag.x - x;
10302 m_pan_drag.y += last_drag.y - y;
10303 last_drag.x = x, last_drag.y = y;
10310 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10312 m_DoubleClickTimer->Start();
10313 singleClickEventIsValid =
false;
10321void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10322 if (MouseEventOverlayWindows(event))
return;
10326 bool nm = MouseEventProcessObjects(event);
10330void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10333 wxCursor *ptarget_cursor = pCursorArrow;
10334 if (!pPlugIn_Cursor) {
10335 ptarget_cursor = pCursorArrow;
10336 if ((!m_routeState) &&
10337 (!m_bMeasure_Active) ) {
10338 if (cursor_region == MID_RIGHT) {
10339 ptarget_cursor = pCursorRight;
10340 }
else if (cursor_region == MID_LEFT) {
10341 ptarget_cursor = pCursorLeft;
10342 }
else if (cursor_region == MID_TOP) {
10343 ptarget_cursor = pCursorDown;
10344 }
else if (cursor_region == MID_BOT) {
10345 ptarget_cursor = pCursorUp;
10347 ptarget_cursor = pCursorArrow;
10349 }
else if (m_bMeasure_Active ||
10351 ptarget_cursor = pCursorPencil;
10353 ptarget_cursor = pPlugIn_Cursor;
10356 SetCursor(*ptarget_cursor);
10359void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10360 SetCursor(*pCursorArrow);
10363void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10367 wxArrayString files;
10369 ChartBase *target_chart = GetChartAtCursor();
10370 if (target_chart) {
10371 file.Assign(target_chart->GetFullPath());
10372 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10373 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10376 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10378 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10379 unsigned int im = stackIndexArray.size();
10380 int scale = 2147483647;
10381 if (VPoint.b_quilt && im > 0) {
10382 for (
unsigned int is = 0; is < im; is++) {
10383 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10384 CHART_TYPE_MBTILES) {
10385 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10387 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10388 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10390 .Contains(lat, lon)) {
10391 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10394 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10395 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10403 std::vector<Ais8_001_22 *> area_notices;
10405 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10408 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10409 auto target_data = target.second;
10410 if (!target_data->area_notices.empty()) {
10411 for (
auto &ani : target_data->area_notices) {
10416 for (Ais8_001_22_SubAreaList::iterator sa =
10417 area_notice.sub_areas.begin();
10418 sa != area_notice.sub_areas.end(); ++sa) {
10419 switch (sa->shape) {
10420 case AIS8_001_22_SHAPE_CIRCLE: {
10421 wxPoint target_point;
10423 bbox.Expand(target_point);
10424 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10427 case AIS8_001_22_SHAPE_RECT: {
10428 wxPoint target_point;
10430 bbox.Expand(target_point);
10431 if (sa->e_dim_m > sa->n_dim_m)
10432 bbox.EnLarge(sa->e_dim_m * vp_scale);
10434 bbox.EnLarge(sa->n_dim_m * vp_scale);
10437 case AIS8_001_22_SHAPE_POLYGON:
10438 case AIS8_001_22_SHAPE_POLYLINE: {
10439 for (
int i = 0; i < 4; ++i) {
10440 double lat = sa->latitude;
10441 double lon = sa->longitude;
10442 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10444 wxPoint target_point;
10446 bbox.Expand(target_point);
10450 case AIS8_001_22_SHAPE_SECTOR: {
10451 double lat1 = sa->latitude;
10452 double lon1 = sa->longitude;
10454 wxPoint target_point;
10456 bbox.Expand(target_point);
10457 for (
int i = 0; i < 18; ++i) {
10460 sa->left_bound_deg +
10461 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10462 sa->radius_m / 1852.0, &lat, &lon);
10464 bbox.Expand(target_point);
10466 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10469 bbox.Expand(target_point);
10475 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10476 area_notices.push_back(&area_notice);
10483 if (target_chart || !area_notices.empty() || file.HasName()) {
10485 int sel_rad_pix = 5;
10486 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10491 SetCursor(wxCURSOR_WAIT);
10492 bool lightsVis = m_encShowLights;
10493 if (!lightsVis) SetShowENCLights(
true);
10496 ListOfObjRazRules *rule_list = NULL;
10497 ListOfPI_S57Obj *pi_rule_list = NULL;
10500 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10501 else if (target_plugin_chart)
10502 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10503 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10505 ListOfObjRazRules *overlay_rule_list = NULL;
10506 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10509 if (CHs57_Overlay) {
10510 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10511 zlat, zlon, SelectRadius, &GetVP());
10514 if (!lightsVis) SetShowENCLights(
false);
10517 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10518 wxString face = dFont->GetFaceName();
10522 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10523 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10527 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10535 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10536 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10539 int points = dFont->GetPointSize();
10541 int points = dFont->GetPointSize() + 1;
10545 for (
int i = -2; i < 5; i++) {
10546 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10550 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10552 if (overlay_rule_list && CHs57_Overlay) {
10553 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10554 objText <<
"<hr noshade>";
10557 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10558 an != area_notices.end(); ++an) {
10559 objText <<
"<b>AIS Area Notice:</b> ";
10560 objText << ais8_001_22_notice_names[(*an)->notice_type];
10561 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10562 (*an)->sub_areas.begin();
10563 sa != (*an)->sub_areas.end(); ++sa)
10564 if (!sa->text.empty()) objText << sa->text;
10565 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10566 objText <<
"<hr noshade>";
10570 objText << Chs57->CreateObjDescriptions(rule_list);
10571 else if (target_plugin_chart)
10572 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10575 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10578 wxString AddFiles, filenameOK;
10580 if (!target_plugin_chart) {
10583 AddFiles = wxString::Format(
10584 "<hr noshade><br><b>Additional info files attached to: </b> "
10586 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10588 file.GetFullName());
10590 file.Assign(file.GetPath(),
"");
10591 wxDir dir(file.GetFullPath());
10593 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10595 file.Assign(dir.GetNameWithSep().append(filename));
10596 wxString FormatString =
10597 "<td valign=top><font size=-2><a "
10598 "href=\"%s\">%s</a></font></td>";
10599 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10600 filenameOK = file.GetFullPath();
10602 if (3 * ((
int)filecount / 3) == filecount)
10603 FormatString.Prepend(
"<tr>");
10605 FormatString.Prepend(
10606 "<td>  </td>");
10609 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10610 file.GetFullName());
10613 cont = dir.GetNext(&filename);
10615 objText << AddFiles <<
"</table>";
10617 objText <<
"</font>";
10618 objText <<
"</body></html>";
10620 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10624 if ((!Chs57 && filecount == 1)) {
10626 wxHtmlLinkInfo hli(filenameOK);
10627 wxHtmlLinkEvent hle(1, hli);
10631 if (rule_list) rule_list->Clear();
10634 if (overlay_rule_list) overlay_rule_list->Clear();
10635 delete overlay_rule_list;
10637 if (pi_rule_list) pi_rule_list->Clear();
10638 delete pi_rule_list;
10640 SetCursor(wxCURSOR_ARROW);
10644void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10653 wxSize canvas_size = GetSize();
10660 wxPoint canvas_pos = GetPosition();
10663 bool newFit =
false;
10664 if (canvas_size.x < fitted_size.x) {
10665 fitted_size.x = canvas_size.x - 40;
10666 if (canvas_size.y < fitted_size.y)
10667 fitted_size.y -= 40;
10669 if (canvas_size.y < fitted_size.y) {
10670 fitted_size.y = canvas_size.y - 40;
10671 if (canvas_size.x < fitted_size.x)
10672 fitted_size.x -= 40;
10683 wxString title_base = _(
"Mark Properties");
10685 title_base = _(
"Waypoint Properties");
10690 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10702void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10712 if (g_bresponsive) {
10713 wxSize canvas_size = GetSize();
10714 wxPoint canvas_pos = GetPosition();
10718 if (canvas_size.x < fitted_size.x) {
10719 fitted_size.x = canvas_size.x;
10720 if (canvas_size.y < fitted_size.y)
10721 fitted_size.y -= 20;
10723 if (canvas_size.y < fitted_size.y) {
10724 fitted_size.y = canvas_size.y;
10725 if (canvas_size.x < fitted_size.x)
10726 fitted_size.x -= 20;
10735 wxPoint xxp = ClientToScreen(canvas_pos);
10746void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10758void pupHandler_PasteWaypoint() {
10761 int pasteBuffer = kml.ParsePasteBuffer();
10762 RoutePoint *pasted = kml.GetParsedRoutePoint();
10763 if (!pasted)
return;
10765 double nearby_radius_meters =
10766 g_Platform->GetSelectRadiusPix() /
10767 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10769 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10770 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10772 int answer = wxID_NO;
10776 "There is an existing waypoint at the same location as the one you are "
10777 "pasting. Would you like to merge the pasted data with it?\n\n");
10778 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10779 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10780 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10783 if (answer == wxID_YES) {
10784 nearPoint->SetName(pasted->GetName());
10786 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10787 pRouteManagerDialog->UpdateWptListCtrl();
10790 if (answer == wxID_NO) {
10793 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10796 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10799 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10800 pRouteManagerDialog->UpdateWptListCtrl();
10805 gFrame->InvalidateAllGL();
10806 gFrame->RefreshAllCanvas(
false);
10809void pupHandler_PasteRoute() {
10812 int pasteBuffer = kml.ParsePasteBuffer();
10813 Route *pasted = kml.GetParsedRoute();
10814 if (!pasted)
return;
10816 double nearby_radius_meters =
10817 g_Platform->GetSelectRadiusPix() /
10818 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10824 bool mergepoints =
false;
10825 bool createNewRoute =
true;
10826 int existingWaypointCounter = 0;
10828 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10829 curPoint = pasted->GetPoint(i);
10830 nearPoint = pWayPointMan->GetNearbyWaypoint(
10831 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10833 mergepoints =
true;
10834 existingWaypointCounter++;
10842 int answer = wxID_NO;
10846 "There are existing waypoints at the same location as some of the ones "
10847 "you are pasting. Would you like to just merge the pasted data into "
10849 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10850 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10851 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10853 if (answer == wxID_CANCEL) {
10860 if (mergepoints && answer == wxID_YES &&
10861 existingWaypointCounter == pasted->GetnPoints()) {
10864 createNewRoute =
false;
10870 Route *newRoute = 0;
10873 if (createNewRoute) {
10874 newRoute =
new Route();
10878 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10879 curPoint = pasted->GetPoint(i);
10882 newPoint = pWayPointMan->GetNearbyWaypoint(
10883 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10884 newPoint->SetName(curPoint->GetName());
10887 if (createNewRoute) newRoute->AddPoint(newPoint);
10893 newPoint->SetIconName(
"circle");
10896 newPoint->SetShared(
false);
10898 newRoute->AddPoint(newPoint);
10899 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10902 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10905 if (i > 1 && createNewRoute)
10906 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10907 curPoint->m_lat, curPoint->m_lon,
10908 prevPoint, newPoint, newRoute);
10909 prevPoint = newPoint;
10912 if (createNewRoute) {
10915 NavObj_dB::GetInstance().InsertRoute(newRoute);
10921 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10922 pRouteManagerDialog->UpdateRouteListCtrl();
10923 pRouteManagerDialog->UpdateWptListCtrl();
10925 gFrame->InvalidateAllGL();
10926 gFrame->RefreshAllCanvas(
false);
10932void pupHandler_PasteTrack() {
10935 int pasteBuffer = kml.ParsePasteBuffer();
10936 Track *pasted = kml.GetParsedTrack();
10937 if (!pasted)
return;
10945 newTrack->SetName(pasted->GetName());
10947 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10948 curPoint = pasted->GetPoint(i);
10952 wxDateTime now = wxDateTime::Now();
10955 newTrack->AddPoint(newPoint);
10958 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10959 newPoint->m_lat, newPoint->m_lon,
10960 prevPoint, newPoint, newTrack);
10962 prevPoint = newPoint;
10967 NavObj_dB::GetInstance().InsertTrack(newTrack);
10969 gFrame->InvalidateAllGL();
10970 gFrame->RefreshAllCanvas(
false);
10973bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10976 v[
"CursorPosition_x"] = x;
10977 v[
"CursorPosition_y"] = y;
10980 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10981 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10982 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
10987 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
10989 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
10992#define SELTYPE_UNKNOWN 0x0001
10993#define SELTYPE_ROUTEPOINT 0x0002
10994#define SELTYPE_ROUTESEGMENT 0x0004
10995#define SELTYPE_TIDEPOINT 0x0008
10996#define SELTYPE_CURRENTPOINT 0x0010
10997#define SELTYPE_ROUTECREATE 0x0020
10998#define SELTYPE_AISTARGET 0x0040
10999#define SELTYPE_MARKPOINT 0x0080
11000#define SELTYPE_TRACKSEGMENT 0x0100
11001#define SELTYPE_DRAGHANDLE 0x0200
11004 if (g_bhide_context_menus)
return true;
11006 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11007 m_pIDXCandidate, m_nmea_log);
11010 wxEVT_COMMAND_MENU_SELECTED,
11011 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11017 if (m_inLongPress) {
11018 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11019 m_inLongPress =
false;
11023 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11026 wxEVT_COMMAND_MENU_SELECTED,
11027 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11029 delete m_canvasMenu;
11030 m_canvasMenu = NULL;
11040void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11043 if (m_canvasMenu) {
11044 m_canvasMenu->PopupMenuHandler(event);
11049void ChartCanvas::StartRoute() {
11051 if (g_brouteCreating)
return;
11055 g_brouteCreating =
true;
11057 m_bDrawingRoute =
false;
11058 SetCursor(*pCursorPencil);
11060 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11062 HideGlobalToolbar();
11065 androidSetRouteAnnunciator(
true);
11069wxString ChartCanvas::FinishRoute() {
11071 m_prev_pMousePoint = NULL;
11072 m_bDrawingRoute =
false;
11074 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11077 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11079 androidSetRouteAnnunciator(
false);
11082 SetCursor(*pCursorArrow);
11084 if (m_pMouseRoute) {
11085 if (m_bAppendingRoute) {
11087 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11089 if (m_pMouseRoute->GetnPoints() > 1) {
11091 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11094 m_pMouseRoute = NULL;
11097 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11104 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11105 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11106 pRouteManagerDialog->UpdateRouteListCtrl();
11109 m_bAppendingRoute =
false;
11110 m_pMouseRoute = NULL;
11112 m_pSelectedRoute = NULL;
11114 undo->InvalidateUndo();
11115 gFrame->RefreshAllCanvas(
true);
11119 ShowGlobalToolbar();
11121 g_brouteCreating =
false;
11126void ChartCanvas::HideGlobalToolbar() {
11127 if (m_canvasIndex == 0) {
11128 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11132void ChartCanvas::ShowGlobalToolbar() {
11133 if (m_canvasIndex == 0) {
11134 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11138void ChartCanvas::ShowAISTargetList() {
11139 if (NULL == g_pAISTargetList) {
11143 g_pAISTargetList->UpdateAISTargetList();
11146void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11147 if (!m_bShowOutlines)
return;
11151 int nEntry =
ChartData->GetChartTableEntries();
11153 for (
int i = 0; i < nEntry; i++) {
11157 bool b_group_draw =
false;
11158 if (m_groupIndex > 0) {
11159 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11160 int index = pt->GetGroupArray()[ig];
11161 if (m_groupIndex == index) {
11162 b_group_draw =
true;
11167 b_group_draw =
true;
11169 if (b_group_draw) RenderChartOutline(dc, i, vp);
11175 if (VPoint.b_quilt) {
11176 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11177 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11181 }
else if (m_singleChart &&
11182 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11186 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11189 if (zoom_factor > 8.0) {
11190 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11193 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11197 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11201void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11203 if (g_bopengl && m_glcc) {
11205 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11210 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11211 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11214 float plylat, plylon;
11215 float plylat1, plylon1;
11217 int pixx, pixy, pixx1, pixy1;
11220 ChartData->GetDBBoundingBox(dbIndex, box);
11224 if (box.GetLonRange() == 360)
return;
11226 double lon_bias = 0;
11228 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11230 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11232 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11233 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11235 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11236 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11239 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11242 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11243 if (0 == nAuxPlyEntries)
11247 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11248 plylon += lon_bias;
11254 for (
int i = 0; i < nPly - 1; i++) {
11255 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11256 plylon1 += lon_bias;
11262 int pixxs1 = pixx1;
11263 int pixys1 = pixy1;
11265 bool b_skip =
false;
11269 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11270 pow((
double)(pixy1 - pixy), 2)) /
11276 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11281 if (fabs(dist - distgc) > 10000. * 1852.)
11287 ClipResult res = cohen_sutherland_line_clip_i(
11289 if (res != Invisible && !b_skip)
11290 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11298 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11299 plylon1 += lon_bias;
11305 ClipResult res = cohen_sutherland_line_clip_i(
11307 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11314 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11315 for (
int j = 0; j < nAuxPlyEntries; j++) {
11317 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11322 for (
int i = 0; i < nAuxPly - 1; i++) {
11323 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11329 int pixxs1 = pixx1;
11330 int pixys1 = pixy1;
11332 bool b_skip =
false;
11336 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11337 ((pixy1 - pixy) * (pixy1 - pixy))) /
11342 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11347 if (fabs(dist - distgc) > 10000. * 1852.)
11353 ClipResult res = cohen_sutherland_line_clip_i(
11355 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11363 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11368 ClipResult res = cohen_sutherland_line_clip_i(
11370 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11375static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11376 const wxString &second) {
11377 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11379 int pointsize = dFont->GetPointSize();
11383 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11384 false, dFont->GetFaceName());
11386 dc.SetFont(*psRLI_font);
11394 int hilite_offset = 3;
11397 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11398 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11400 dc.GetTextExtent(first, &w1, &h1);
11401 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11407 w = wxMax(w1, w2) + (h1 / 2);
11412 xp = ref_point.x - w;
11414 yp += hilite_offset;
11416 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11418 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11419 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11421 dc.DrawText(first, xp, yp);
11422 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11425void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11426 if (!g_bAllowShipToActive)
return;
11432 wxPoint2DDouble pa, pb;
11439 if (rt->
m_width != wxPENSTYLE_INVALID)
11441 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11442 g_shipToActiveStyle, 5)];
11443 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11445 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11448 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11451 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11454 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11455 (
int)pb.m_y, GetVP(),
true);
11459#ifdef USE_ANDROID_GLES2
11460 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11462 if (style != wxPENSTYLE_SOLID) {
11463 if (glChartCanvas::dash_map.find(style) !=
11464 glChartCanvas::dash_map.end()) {
11465 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11469 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11472 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11473 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11479void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11481 if (m_routeState >= 2) route = m_pMouseRoute;
11482 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11483 route = m_pMeasureRoute;
11485 if (!route)
return;
11493 int np = route->GetnPoints();
11495 if (g_btouch && (np > 1)) np--;
11497 render_lat = rp.m_lat;
11498 render_lon = rp.m_lon;
11501 double rhumbBearing, rhumbDist;
11503 &rhumbBearing, &rhumbDist);
11504 double brg = rhumbBearing;
11505 double dist = rhumbDist;
11509 double gcBearing, gcBearing2, gcDist;
11510 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11513 double gcDistm = gcDist / 1852.0;
11516 rhumbBearing = 90.;
11518 wxPoint destPoint, lastPoint;
11521 int milesDiff = rhumbDist - gcDistm;
11522 if (milesDiff > 1) {
11533 for (
int i = 1; i <= milesDiff; i++) {
11534 double p = (double)i * (1.0 / (
double)milesDiff);
11536 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11537 &pLon, &pLat, &gcBearing2);
11539 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11541 lastPoint = destPoint;
11544 if (r_rband.x && r_rband.y) {
11545 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11547 if (m_bMeasure_DistCircle) {
11548 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11549 powf((
float)(r_rband.y - lastPoint.y), 2));
11552 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11553 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11559 wxString routeInfo;
11562 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11568 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11570 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11571 (
int)varBrg, 0x00B0);
11578 routeInfo <<
"\nReverse: ";
11580 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11581 (
int)(brg + 180.) % 360, 0x00B0);
11583 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11584 (
int)(varBrg + 180.) % 360, 0x00B0);
11589 s0.Append(_(
"Route") +
": ");
11591 s0.Append(_(
"Layer Route: "));
11594 if (!g_btouch) disp_length += dist;
11597 RouteLegInfo(dc, r_rband, routeInfo, s0);
11599 m_brepaint_piano =
true;
11602void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11603 if (!m_bShowVisibleSectors)
return;
11605 if (g_bDeferredInitDone) {
11607 double rhumbBearing, rhumbDist;
11608 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11609 &rhumbBearing, &rhumbDist);
11611 if (rhumbDist > 0.05)
11613 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11614 m_sectorlegsVisible);
11615 m_sector_glat =
gLat;
11616 m_sector_glon =
gLon;
11618 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11622void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11630void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11631 if (!ps52plib)
return;
11633 if (VPoint.b_quilt) {
11634 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11636 if (m_pQuilt->IsQuiltVector()) {
11637 if (ps52plib->GetStateHash() != m_s52StateHash) {
11639 m_s52StateHash = ps52plib->GetStateHash();
11643 if (ps52plib->GetStateHash() != m_s52StateHash) {
11645 m_s52StateHash = ps52plib->GetStateHash();
11650 bool bSendPlibState =
true;
11651 if (VPoint.b_quilt) {
11652 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11655 if (bSendPlibState) {
11657 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11658 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11659 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11660 v[
"OpenCPN Version Date"] = VERSION_DATE;
11661 v[
"OpenCPN Version Full"] = VERSION_FULL;
11664 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11665 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11666 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11667 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11668 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11669 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11670 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11674 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11675 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11679 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11680 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11681 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11682 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11683 ps52plib->m_bShowS57ImportantTextOnly;
11684 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11685 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11686 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11687 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11688 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11691 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11692 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11693 v[
"OpenCPN Scale Factor Exp"] =
11694 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11701 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11702 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11703 g_lastS52PLIBPluginMessage = out;
11710 wxPaintDC dc(
this);
11720 if (!m_b_paint_enable) {
11728 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11730 if (m_glcc && g_bopengl) {
11731 if (!s_in_update) {
11741 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11743 wxRegion ru = GetUpdateRegion();
11745 int rx, ry, rwidth, rheight;
11746 ru.GetBox(rx, ry, rwidth, rheight);
11748#ifdef ocpnUSE_DIBSECTION
11751 wxMemoryDC temp_dc;
11759 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11760 height += m_Piano->GetHeight();
11762 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11766 int thumbx, thumby, thumbsx, thumbsy;
11767 pthumbwin->GetPosition(&thumbx, &thumby);
11768 pthumbwin->GetSize(&thumbsx, &thumbsy);
11769 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11772 rgn_chart.Subtract(rgn_thumbwin);
11773 ru.Subtract(rgn_thumbwin);
11779 wxRegion rgn_blit = ru;
11780 if (g_bShowChartBar) {
11781 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11782 GetClientSize().x, m_Piano->GetHeight());
11785 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11786 if (style->chartStatusWindowTransparent)
11787 m_brepaint_piano =
true;
11789 ru.Subtract(chart_bar_rect);
11793 if (m_Compass && m_Compass->IsShown()) {
11794 wxRect compassRect = m_Compass->
GetRect();
11795 if (ru.Contains(compassRect) != wxOutRegion) {
11796 ru.Subtract(compassRect);
11800 if (m_notification_button) {
11801 wxRect noteRect = m_notification_button->
GetRect();
11802 if (ru.Contains(noteRect) != wxOutRegion) {
11803 ru.Subtract(noteRect);
11808 bool b_newview =
true;
11813 m_cache_vp.IsValid()) {
11819 bool b_rcache_ok =
false;
11820 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11821 b_rcache_ok = !b_newview;
11824 if (VPoint.b_MercatorProjectionOverride)
11825 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11839 if (b_rcache_ok) chart_get_region.Clear();
11842 if (VPoint.b_quilt)
11844 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11846 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11851 AbstractPlatform::ShowBusySpinner();
11855 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11856 (m_working_bm.GetHeight() != svp.
pix_height))
11860 if (fabs(VPoint.
rotation) < 0.01) {
11861 bool b_save =
true;
11866 m_cache_vp.Invalidate();
11880 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11885 int dy = c_new.y - c_old.y;
11886 int dx = c_new.x - c_old.x;
11891 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11895 temp_dc.SelectObject(m_working_bm);
11897 wxMemoryDC cache_dc;
11898 cache_dc.SelectObject(m_cached_chart_bm);
11902 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11905 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11911 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11914 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11922 update_region.Union(
11925 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11930 update_region.Union(
11933 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11937 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11939 cache_dc.SelectObject(wxNullBitmap);
11943 temp_dc.SelectObject(m_cached_chart_bm);
11946 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11950 temp_dc.SelectObject(m_working_bm);
11951 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11956 temp_dc.SelectObject(m_cached_chart_bm);
11961 temp_dc.SelectObject(m_working_bm);
11962 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11975 wxMemoryDC scratch_dc_0;
11976 scratch_dc_0.SelectObject(m_cached_chart_bm);
11979 scratch_dc_0.SelectObject(wxNullBitmap);
11988 temp_dc.SelectObject(m_working_bm);
11991 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11992 chart_get_all_region);
11995 AbstractPlatform::HideBusySpinner();
12001 if (!m_singleChart) {
12002 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12007 if (!chart_get_region.IsEmpty()) {
12008 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12012 if (temp_dc.IsOk()) {
12017 if (!VPoint.b_quilt) {
12020 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12021 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12028 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12029 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12032 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12034 temp_dc.DestroyClippingRegion();
12039 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12041 if (!backgroundRegion.IsEmpty()) {
12047 wxColour water = pWorldBackgroundChart->water;
12048 if (water.IsOk()) {
12049 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12050 temp_dc.SetBrush(wxBrush(water));
12052 while (upd.HaveRects()) {
12053 wxRect rect = upd.GetRect();
12054 temp_dc.DrawRectangle(rect);
12059 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12060 temp_dc.SetDeviceClippingRegion(*clip_region);
12061 delete clip_region;
12065 SetVPRotation(VPoint.
skew);
12074 wxMemoryDC *pChartDC = &temp_dc;
12075 wxMemoryDC rotd_dc;
12077 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12079 if (!b_rcache_ok) {
12081 wxMemoryDC tbase_dc;
12083 tbase_dc.SelectObject(bm_base);
12085 tbase_dc.SelectObject(wxNullBitmap);
12087 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12090 wxImage base_image;
12091 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12099 bool b_rot_ok =
false;
12100 if (base_image.IsOk()) {
12103 m_b_rot_hidef =
false;
12107 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12108 m_b_rot_hidef, &m_roffset);
12113 rot_vp.IsValid() && (ri.IsOk())) {
12120 m_prot_bm =
new wxBitmap(ri);
12123 m_roffset.x += VPoint.rv_rect.x;
12124 m_roffset.y += VPoint.rv_rect.y;
12127 if (m_prot_bm && m_prot_bm->IsOk()) {
12128 rotd_dc.SelectObject(*m_prot_bm);
12129 pChartDC = &rotd_dc;
12131 pChartDC = &temp_dc;
12132 m_roffset = wxPoint(0, 0);
12135 pChartDC = &temp_dc;
12136 m_roffset = wxPoint(0, 0);
12139 wxPoint offset = m_roffset;
12142 m_cache_vp = VPoint;
12145 wxMemoryDC mscratch_dc;
12146 mscratch_dc.SelectObject(*pscratch_bm);
12148 mscratch_dc.ResetBoundingBox();
12149 mscratch_dc.DestroyClippingRegion();
12150 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12153 wxRegionIterator upd(rgn_blit);
12155 wxRect rect = upd.GetRect();
12157 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12158 rect.x - offset.x, rect.y - offset.y);
12164 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12165 if (
this == wxWindow::FindFocus()) {
12168 wxColour colour = GetGlobalColor(
"BLUE4");
12169 mscratch_dc.SetPen(wxPen(colour));
12170 mscratch_dc.SetBrush(wxBrush(colour));
12172 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12173 mscratch_dc.DrawRectangle(activeRect);
12178 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12179 unsigned int im = stackIndexArray.size();
12180 if (VPoint.b_quilt && im > 0) {
12181 std::vector<int> tiles_to_show;
12182 for (
unsigned int is = 0; is < im; is++) {
12184 ChartData->GetChartTableEntry(stackIndexArray[is]);
12185 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12188 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12189 tiles_to_show.push_back(stackIndexArray[is]);
12193 if (tiles_to_show.size())
12194 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12200 ocpnDC scratch_dc(mscratch_dc);
12201 RenderAlertMessage(mscratch_dc, GetVP());
12207#ifdef ocpnUSE_DIBSECTION
12212 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12213 q_dc.SelectObject(qbm);
12216 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12219 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12220 q_dc.SetBrush(qbr);
12221 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12224 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12227 q_dc.SelectObject(wxNullBitmap);
12236 if( VPoint.b_quilt ) {
12237 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12238 ChartBase *chart = m_pQuilt->GetRefChart();
12239 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12244 ChPI->ClearPLIBTextList();
12247 ps52plib->ClearTextList();
12251 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12253 wxColor maskBackground = wxColour(1,0,0);
12254 t_dc.SelectObject( qbm );
12255 t_dc.SetBackground(wxBrush(maskBackground));
12259 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12262 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12263 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12266 wxRegionIterator upd_final( ru );
12267 while( upd_final ) {
12268 wxRect rect = upd_final.GetRect();
12269 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12273 t_dc.SelectObject( wxNullBitmap );
12279 if (VPoint.b_quilt) {
12280 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12281 ChartBase *chart = m_pQuilt->GetRefChart();
12282 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12286 ChPI->ClearPLIBTextList();
12288 if (ps52plib) ps52plib->ClearTextList();
12293 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12295 if (g_bShowChartBar && m_Piano) {
12296 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12297 GetVP().pix_width, m_Piano->GetHeight());
12300 if (!style->chartStatusWindowTransparent)
12301 chart_all_text_region.Subtract(chart_bar_rect);
12304 if (m_Compass && m_Compass->IsShown()) {
12305 wxRect compassRect = m_Compass->
GetRect();
12306 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12307 chart_all_text_region.Subtract(compassRect);
12311 mscratch_dc.DestroyClippingRegion();
12313 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12314 chart_all_text_region);
12320 ocpnDC scratch_dc(mscratch_dc);
12321 DrawOverlayObjects(scratch_dc, ru);
12324 wxRegionIterator upd_final(rgn_blit);
12325 while (upd_final) {
12326 wxRect rect = upd_final.GetRect();
12327 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12334 temp_dc.SelectObject(wxNullBitmap);
12336 mscratch_dc.SelectObject(wxNullBitmap);
12338 dc.DestroyClippingRegion();
12343void ChartCanvas::PaintCleanup() {
12345 if (m_inPinch)
return;
12356 m_bTCupdate =
false;
12360 WarpPointer(warp_x, warp_y);
12367 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12368 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12372wxColour GetErrorGraphicColor(
double val)
12391 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12392 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12393 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12394 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12395 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12396 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12397 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12398 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12399 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12400 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12401 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12402 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12403 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12404 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12405 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12406 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12407 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12408 else if( val >= 48) c.Set(
"#410000");
12413void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12416 gr_image.InitAlpha();
12418 double maxval = -10000;
12419 double minval = 10000;
12436 maxval = wxMax(maxval, (glat - rlat));
12437 minval = wxMin(minval, (glat - rlat));
12454 double f = ((glat - rlat)-minval)/(maxval - minval);
12456 double dy = (f * 40);
12458 wxColour c = GetErrorGraphicColor(dy);
12459 unsigned char r = c.Red();
12460 unsigned char g = c.Green();
12461 unsigned char b = c.Blue();
12463 gr_image.SetRGB(j, i, r,g,b);
12464 if((glat - rlat )!= 0)
12465 gr_image.SetAlpha(j, i, 128);
12467 gr_image.SetAlpha(j, i, 255);
12474 wxBitmap *pbm =
new wxBitmap(gr_image);
12475 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12476 pbm->SetMask(gr_mask);
12478 pmdc->DrawBitmap(*pbm, 0,0);
12486void ChartCanvas::CancelMouseRoute() {
12488 m_pMouseRoute = NULL;
12489 m_bDrawingRoute =
false;
12492int ChartCanvas::GetNextContextMenuId() {
12493 return CanvasMenuHandler::GetNextContextMenuId();
12496bool ChartCanvas::SetCursor(
const wxCursor &c) {
12498 if (g_bopengl && m_glcc)
12499 return m_glcc->SetCursor(c);
12502 return wxWindow::SetCursor(c);
12505void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12506 if (g_bquiting)
return;
12516 if (!m_RolloverPopupTimer.IsRunning() &&
12517 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12518 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12519 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12520 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12523 if (m_glcc && g_bopengl) {
12526 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12528 m_glcc->Refresh(eraseBackground,
12545 if (m_pCIWin && m_pCIWin->IsShown()) {
12547 m_pCIWin->Refresh(
false);
12555 wxWindow::Refresh(eraseBackground, rect);
12558void ChartCanvas::Update() {
12559 if (m_glcc && g_bopengl) {
12564 wxWindow::Update();
12568 if (!pemboss)
return;
12569 int x = pemboss->x, y = pemboss->y;
12570 const double factor = 200;
12572 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12573 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12574 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12577 wxMemoryDC snip_dc;
12578 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12579 snip_dc.SelectObject(snip_bmp);
12581 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12582 snip_dc.SelectObject(wxNullBitmap);
12584 wxImage snip_img = snip_bmp.ConvertToImage();
12587 unsigned char *pdata = snip_img.GetData();
12589 for (
int y = 0; y < pemboss->height; y++) {
12590 int map_index = (y * pemboss->width);
12591 for (
int x = 0; x < pemboss->width; x++) {
12592 double val = (pemboss->pmap[map_index] * factor) / 256.;
12594 int nred = (int)((*pdata) + val);
12595 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12596 *pdata++ = (
unsigned char)nred;
12598 int ngreen = (int)((*pdata) + val);
12599 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12600 *pdata++ = (
unsigned char)ngreen;
12602 int nblue = (int)((*pdata) + val);
12603 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12604 *pdata++ = (
unsigned char)nblue;
12612 wxBitmap emb_bmp(snip_img);
12615 wxMemoryDC result_dc;
12616 result_dc.SelectObject(emb_bmp);
12619 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12621 result_dc.SelectObject(wxNullBitmap);
12627 if (GetQuiltMode()) {
12629 int refIndex = GetQuiltRefChartdbIndex();
12630 if (refIndex >= 0) {
12632 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12633 if (current_type == CHART_TYPE_MBTILES) {
12634 ChartBase *pChart = m_pQuilt->GetRefChart();
12637 zoom_factor = ptc->GetZoomFactor();
12642 if (zoom_factor <= 3.9)
return NULL;
12644 if (m_singleChart) {
12645 if (zoom_factor <= 3.9)
return NULL;
12650 if (m_pEM_OverZoom) {
12651 m_pEM_OverZoom->x = 4;
12652 m_pEM_OverZoom->y = 0;
12654 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12655 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12658 return m_pEM_OverZoom;
12661void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12674 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12675 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12679 AISDrawAreaNotices(dc, GetVP(),
this);
12681 wxDC *pdc = dc.GetDC();
12683 pdc->DestroyClippingRegion();
12684 wxDCClipper(*pdc, ru);
12687 if (m_bShowNavobjects) {
12688 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12689 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12690 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12691 DrawAnchorWatchPoints(dc);
12693 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12694 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12697 AISDraw(dc, GetVP(),
this);
12701 RenderVisibleSectorLights(dc);
12703 RenderAllChartOutlines(dc, GetVP());
12704 RenderRouteLegs(dc);
12705 RenderShipToActive(dc,
false);
12707 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12709 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12713 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12714 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12717 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12722 RebuildTideSelectList(GetVP().GetBBox());
12723 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12726 if (m_bShowCurrent) {
12727 RebuildCurrentSelectList(GetVP().GetBBox());
12728 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12731 if (!g_PrintingInProgress) {
12732 if (IsPrimaryCanvas()) {
12736 if (IsPrimaryCanvas()) {
12740 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12742 if (m_pTrackRolloverWin) {
12743 m_pTrackRolloverWin->Draw(dc);
12744 m_brepaint_piano =
true;
12747 if (m_pRouteRolloverWin) {
12748 m_pRouteRolloverWin->Draw(dc);
12749 m_brepaint_piano =
true;
12752 if (m_pAISRolloverWin) {
12753 m_pAISRolloverWin->Draw(dc);
12754 m_brepaint_piano =
true;
12756 if (m_brepaint_piano && g_bShowChartBar) {
12757 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12760 if (m_Compass) m_Compass->Paint(dc);
12762 if (!g_CanvasHideNotificationIcon) {
12763 if (IsPrimaryCanvas()) {
12764 auto ¬eman = NotificationManager::GetInstance();
12765 if (noteman.GetNotificationCount()) {
12766 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12767 if (m_notification_button->UpdateStatus()) Refresh();
12768 m_notification_button->Show(
true);
12769 m_notification_button->Paint(dc);
12771 m_notification_button->Show(
false);
12777 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12783 if (!m_bShowDepthUnits)
return NULL;
12785 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12787 if (GetQuiltMode()) {
12788 wxString s = m_pQuilt->GetQuiltDepthUnit();
12791 depth_unit_type = DEPTH_UNIT_FEET;
12792 else if (s.StartsWith(
"FATHOMS"))
12793 depth_unit_type = DEPTH_UNIT_FATHOMS;
12794 else if (s.StartsWith(
"METERS"))
12795 depth_unit_type = DEPTH_UNIT_METERS;
12796 else if (s.StartsWith(
"METRES"))
12797 depth_unit_type = DEPTH_UNIT_METERS;
12798 else if (s.StartsWith(
"METRIC"))
12799 depth_unit_type = DEPTH_UNIT_METERS;
12800 else if (s.StartsWith(
"METER"))
12801 depth_unit_type = DEPTH_UNIT_METERS;
12804 if (m_singleChart) {
12805 depth_unit_type = m_singleChart->GetDepthUnitType();
12806 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12807 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12812 switch (depth_unit_type) {
12813 case DEPTH_UNIT_FEET:
12816 case DEPTH_UNIT_METERS:
12817 ped = m_pEM_Meters;
12819 case DEPTH_UNIT_FATHOMS:
12820 ped = m_pEM_Fathoms;
12826 ped->x = (GetVP().
pix_width - ped->width);
12828 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12829 wxRect r = m_Compass->
GetRect();
12830 ped->y = r.y + r.height;
12837void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12840 if (style->embossFont == wxEmptyString) {
12841 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12843 font.SetPointSize(60);
12844 font.SetWeight(wxFONTWEIGHT_BOLD);
12846 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12847 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12849 int emboss_width = 500;
12850 int emboss_height = 200;
12854 delete m_pEM_Meters;
12855 delete m_pEM_Fathoms;
12859 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12861 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12863 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12866#define OVERZOOM_TEXT _("OverZoom")
12868void ChartCanvas::SetOverzoomFont() {
12873 if (style->embossFont == wxEmptyString) {
12874 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12876 font.SetPointSize(40);
12877 font.SetWeight(wxFONTWEIGHT_BOLD);
12879 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12880 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12882 wxClientDC dc(
this);
12884 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12886 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12887 font.SetPointSize(font.GetPointSize() - 1);
12889 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12891 m_overzoomFont = font;
12892 m_overzoomTextWidth = w;
12893 m_overzoomTextHeight = h;
12896void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12897 delete m_pEM_OverZoom;
12899 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12901 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12902 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12905emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12906 int height,
const wxString &str,
12911 wxBitmap bmp(width, height, -1);
12914 wxMemoryDC temp_dc;
12915 temp_dc.SelectObject(bmp);
12918 temp_dc.SetBackground(*wxWHITE_BRUSH);
12919 temp_dc.SetTextBackground(*wxWHITE);
12920 temp_dc.SetTextForeground(*wxBLACK);
12924 temp_dc.SetFont(font);
12927 temp_dc.GetTextExtent(str, &str_w, &str_h);
12929 temp_dc.DrawText(str, 1, 1);
12932 temp_dc.SelectObject(wxNullBitmap);
12935 wxImage img = bmp.ConvertToImage();
12937 int image_width = str_w * 105 / 100;
12938 int image_height = str_h * 105 / 100;
12939 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12940 wxMin(image_height, img.GetHeight()));
12941 wxImage imgs = img.GetSubImage(r);
12945 case GLOBAL_COLOR_SCHEME_DAY:
12949 case GLOBAL_COLOR_SCHEME_DUSK:
12952 case GLOBAL_COLOR_SCHEME_NIGHT:
12959 const int w = imgs.GetWidth();
12960 const int h = imgs.GetHeight();
12961 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12966 for (
int y = 1; y < h - 1; y++) {
12967 for (
int x = 1; x < w - 1; x++) {
12969 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12970 val = (int)(val * val_factor);
12971 index = (y * w) + x;
12984void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12985 Track *active_track = NULL;
12988 active_track = pTrackDraw;
12992 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12995 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12998void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12999 Track *active_track = NULL;
13002 active_track = pTrackDraw;
13006 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13009void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13010 Route *active_route = NULL;
13012 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13013 active_route = pRouteDraw;
13018 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13023 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13026void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13027 Route *active_route = NULL;
13030 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13031 active_route = pRouteDraw;
13035 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13038void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13039 if (!pWayPointMan)
return;
13041 auto node = pWayPointMan->GetWaypointList()->begin();
13043 while (node != pWayPointMan->GetWaypointList()->end()) {
13052 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13056 if (pWP->GetShowWaypointRangeRings() &&
13057 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13058 double factor = 1.00;
13059 if (pWP->GetWaypointRangeRingsStepUnits() ==
13061 factor = 1 / 1.852;
13063 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13064 pWP->GetWaypointRangeRingsStep() / 60.;
13068 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13069 pWP->m_lat + radius, pWP->m_lon + radius);
13070 if (!BltBBox.IntersectOut(radar_box)) {
13081void ChartCanvas::DrawBlinkObjects() {
13083 wxRect update_rect;
13085 if (!pWayPointMan)
return;
13087 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13094 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13097void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13102 wxPoint lAnchorPoint1, lAnchorPoint2;
13116 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13117 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13119 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13120 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13121 dc.SetBrush(*ppBrush);
13125 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13130 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13135 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13140 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13145double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13148 wxPoint lAnchorPoint;
13151 double tlat1, tlon1;
13153 if (pAnchorWatchPoint) {
13154 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13155 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13156 dabs = fabs(d1 / 1852.);
13157 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13162 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13163 pow((
double)(lAnchorPoint.y - r1.y), 2));
13166 if (d1 < 0) lpp = -lpp;
13174void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13177 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13179 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13185 if ((type ==
't') || (type ==
'T')) {
13186 if (BBox.Contains(lat, lon)) {
13188 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13194void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13197 wxDateTime this_now = gTimeSource;
13198 bool cur_time = !gTimeSource.IsValid();
13199 if (cur_time) this_now = wxDateTime::Now();
13200 time_t t_this_now = this_now.GetTicks();
13202 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13204 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13205 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13206 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13207 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13209 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13210 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13211 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13212 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13213 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13214 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13216 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13217 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13218 int font_size = wxMax(10, dFont->GetPointSize());
13221 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13222 false, dFont->GetFaceName());
13224 dc.SetPen(*pblack_pen);
13225 dc.SetBrush(*pgreen_brush);
13229 case GLOBAL_COLOR_SCHEME_DAY:
13232 case GLOBAL_COLOR_SCHEME_DUSK:
13235 case GLOBAL_COLOR_SCHEME_NIGHT:
13236 bm = m_bmTideNight;
13243 int bmw = bm.GetWidth();
13244 int bmh = bm.GetHeight();
13246 float scale_factor = 1.0;
13250 float icon_pixelRefDim = 45;
13255 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13257 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13259 scale_factor *= pix_factor;
13266 scale_factor *= user_scale_factor;
13267 scale_factor *= GetContentScaleFactor();
13270 double marge = 0.05;
13271 std::vector<LLBBox> drawn_boxes;
13272 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13276 if ((type ==
't') || (type ==
'T'))
13281 if (BBox.ContainsMarge(lat, lon, marge)) {
13283 if (GetVP().chart_scale < 500000) {
13284 bool bdrawn =
false;
13285 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13286 if (drawn_boxes[i].Contains(lat, lon)) {
13291 if (bdrawn)
continue;
13294 this_box.Set(lat, lon, lat, lon);
13295 this_box.EnLarge(.005);
13296 drawn_boxes.push_back(this_box);
13302 if (GetVP().chart_scale > 500000) {
13303 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13307 dc.SetFont(*plabelFont);
13319 if (
ptcmgr->GetTideFlowSens(
13320 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13324 ptcmgr->GetHightOrLowTide(
13325 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13326 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13338 if (tctime > t_this_now)
13339 ptcmgr->GetHightOrLowTide(
13340 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13341 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13345 ptcmgr->GetHightOrLowTide(
13346 t_this_now, FORWARD_TEN_MINUTES_STEP,
13347 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13361 int width = (int)(12 * scale_factor + 0.5);
13362 int height = (int)(45 * scale_factor + 0.5);
13363 int linew = wxMax(1, (
int)(scale_factor));
13364 int xDraw = r.x - (width / 2);
13365 int yDraw = r.y - (height / 2);
13368 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13369 int hs = (httime > lttime) ? -4 : 4;
13370 hs *= (int)(scale_factor + 0.5);
13371 if (ts > 0.995 || ts < 0.005) hs = 0;
13372 int ht_y = (int)(height * ts);
13375 pblack_pen->SetWidth(linew);
13376 dc.SetPen(*pblack_pen);
13377 dc.SetBrush(*pyelo_brush);
13378 dc.DrawRectangle(xDraw, yDraw, width, height);
13382 dc.SetPen(*pblue_pen);
13383 dc.SetBrush(*pblue_brush);
13384 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13385 (width - (4 * linew)), height - ht_y);
13391 arrow[0].x = xDraw + 2 * linew;
13392 arrow[1].x = xDraw + width / 2;
13393 arrow[2].x = xDraw + width - 2 * linew;
13394 pyelo_pen->SetWidth(linew);
13395 pblue_pen->SetWidth(linew);
13396 if (ts > 0.35 || ts < 0.15)
13398 hl = (int)(height * 0.25) + yDraw;
13400 arrow[1].y = hl + hs;
13403 dc.SetPen(*pyelo_pen);
13405 dc.SetPen(*pblue_pen);
13406 dc.DrawLines(3, arrow);
13408 if (ts > 0.60 || ts < 0.40)
13410 hl = (int)(height * 0.5) + yDraw;
13412 arrow[1].y = hl + hs;
13415 dc.SetPen(*pyelo_pen);
13417 dc.SetPen(*pblue_pen);
13418 dc.DrawLines(3, arrow);
13420 if (ts < 0.65 || ts > 0.85)
13422 hl = (int)(height * 0.75) + yDraw;
13424 arrow[1].y = hl + hs;
13427 dc.SetPen(*pyelo_pen);
13429 dc.SetPen(*pblue_pen);
13430 dc.DrawLines(3, arrow);
13434 s.Printf(
"%3.1f", nowlev);
13436 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13438 dc.GetTextExtent(s, &wx1, NULL);
13440 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13455void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13458 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13460 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13466 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13467 if ((BBox.Contains(lat, lon))) {
13469 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13475void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13478 float tcvalue, dir;
13482 double lon_last = 0.;
13483 double lat_last = 0.;
13485 double marge = 0.2;
13486 bool cur_time = !gTimeSource.IsValid();
13488 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13489 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13491 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13493 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13494 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13495 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13496 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13497 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13498 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13499 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13500 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13502 double skew_angle = GetVPRotation();
13504 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13505 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13506 int font_size = wxMax(10, dFont->GetPointSize());
13509 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13510 false, dFont->GetFaceName());
13512 float scale_factor = 1.0;
13518 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13520 float nominal_icon_size_pixels = 15;
13521 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13523 scale_factor *= pix_factor;
13530 scale_factor *= user_scale_factor;
13532 scale_factor *= GetContentScaleFactor();
13535 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13541 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13542 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13547 int dd = (int)(5.0 * scale_factor + 0.5);
13558 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13559 dc.SetPen(*pblack_pen);
13560 dc.SetBrush(*porange_brush);
13561 dc.DrawPolygon(4, d);
13564 dc.SetBrush(*pblack_brush);
13565 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13569 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13583 double a1 = fabs(tcvalue) * 10.;
13585 a1 = wxMax(1.0, a1);
13586 double a2 = log10(a1);
13588 float cscale = scale_factor * a2 * 0.3;
13590 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13591 dc.SetPen(*porange_pen);
13592 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13596 if (bDrawCurrentValues) {
13597 dc.SetFont(*pTCFont);
13598 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13599 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13625 if (!pvIDX)
return;
13630 if (pCwin && pCwin->IsShown()) {
13638 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13653 pCwin =
new TCWin(
this, x, y, pvIDX);
13671#define NUM_CURRENT_ARROW_POINTS 9
13672static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13673 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13674 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13675 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13677void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13679 if (
scale > 1e-2) {
13680 float sin_rot = sin(rot_angle * PI / 180.);
13681 float cos_rot = cos(rot_angle * PI / 180.);
13685 float xt = CurrentArrowArray[0].x;
13686 float yt = CurrentArrowArray[0].y;
13688 float xp = (xt * cos_rot) - (yt * sin_rot);
13689 float yp = (xt * sin_rot) + (yt * cos_rot);
13690 int x1 = (int)(xp *
scale);
13691 int y1 = (int)(yp *
scale);
13694 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13695 xt = CurrentArrowArray[ip].x;
13696 yt = CurrentArrowArray[ip].y;
13698 float xp = (xt * cos_rot) - (yt * sin_rot);
13699 float yp = (xt * sin_rot) + (yt * cos_rot);
13700 int x2 = (int)(xp *
scale);
13701 int y2 = (int)(yp *
scale);
13703 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13711wxString ChartCanvas::FindValidUploadPort() {
13714 if (!g_uploadConnection.IsEmpty() &&
13715 g_uploadConnection.StartsWith(
"Serial")) {
13716 port = g_uploadConnection;
13722 for (
auto *cp : TheConnectionParams()) {
13723 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13724 port <<
"Serial:" << cp->Port;
13730void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13733 if (NULL == g_pais_query_dialog_active) {
13734 int pos_x = g_ais_query_dialog_x;
13735 int pos_y = g_ais_query_dialog_y;
13737 if (g_pais_query_dialog_active) {
13738 g_pais_query_dialog_active->Destroy();
13744 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13745 wxPoint(pos_x, pos_y));
13747 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13748 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13749 g_pais_query_dialog_active->SetMMSI(mmsi);
13750 g_pais_query_dialog_active->UpdateText();
13751 wxSize sz = g_pais_query_dialog_active->GetSize();
13753 bool b_reset_pos =
false;
13758 RECT frame_title_rect;
13759 frame_title_rect.left = pos_x;
13760 frame_title_rect.top = pos_y;
13761 frame_title_rect.right = pos_x + sz.x;
13762 frame_title_rect.bottom = pos_y + 30;
13764 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13765 b_reset_pos =
true;
13770 wxRect window_title_rect;
13771 window_title_rect.x = pos_x;
13772 window_title_rect.y = pos_y;
13773 window_title_rect.width = sz.x;
13774 window_title_rect.height = 30;
13776 wxRect ClientRect = wxGetClientDisplayRect();
13777 ClientRect.Deflate(
13779 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13783 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13786 g_pais_query_dialog_active->SetMMSI(mmsi);
13787 g_pais_query_dialog_active->UpdateText();
13790 g_pais_query_dialog_active->Show();
13793void ChartCanvas::ToggleCanvasQuiltMode() {
13794 bool cur_mode = GetQuiltMode();
13796 if (!GetQuiltMode())
13797 SetQuiltMode(
true);
13798 else if (GetQuiltMode()) {
13799 SetQuiltMode(
false);
13800 g_sticky_chart = GetQuiltReferenceChartIndex();
13803 if (cur_mode != GetQuiltMode()) {
13804 SetupCanvasQuiltMode();
13813 if (ps52plib) ps52plib->GenerateStateHash();
13815 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13816 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13819void ChartCanvas::DoCanvasStackDelta(
int direction) {
13820 if (!GetQuiltMode()) {
13821 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13822 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13823 if ((current_stack_index + direction) < 0)
return;
13825 if (m_bpersistent_quilt ) {
13827 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13829 if (IsChartQuiltableRef(new_dbIndex)) {
13830 ToggleCanvasQuiltMode();
13831 SelectQuiltRefdbChart(new_dbIndex);
13832 m_bpersistent_quilt =
false;
13835 SelectChartFromStack(current_stack_index + direction);
13838 std::vector<int> piano_chart_index_array =
13839 GetQuiltExtendedStackdbIndexArray();
13840 int refdb = GetQuiltRefChartdbIndex();
13843 int current_index = -1;
13844 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13845 if (refdb == piano_chart_index_array[i]) {
13850 if (current_index == -1)
return;
13853 int target_family = ctet.GetChartFamily();
13855 int new_index = -1;
13856 int check_index = current_index + direction;
13857 bool found =
false;
13858 int check_dbIndex = -1;
13859 int new_dbIndex = -1;
13863 (
unsigned int)check_index < piano_chart_index_array.size() &&
13864 (check_index >= 0)) {
13865 check_dbIndex = piano_chart_index_array[check_index];
13867 if (target_family == cte.GetChartFamily()) {
13869 new_index = check_index;
13870 new_dbIndex = check_dbIndex;
13874 check_index += direction;
13877 if (!found)
return;
13879 if (!IsChartQuiltableRef(new_dbIndex)) {
13880 ToggleCanvasQuiltMode();
13881 SelectdbChart(new_dbIndex);
13882 m_bpersistent_quilt =
true;
13884 SelectQuiltRefChart(new_index);
13888 gFrame->UpdateGlobalMenuItems();
13890 SetQuiltChartHiLiteIndex(-1);
13901void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13904 switch (event.GetId()) {
13916 DoCanvasStackDelta(1);
13921 DoCanvasStackDelta(-1);
13931 ShowCurrents(!GetbShowCurrent());
13938 ShowTides(!GetbShowTide());
13945 if (0 == m_routeState) {
13952 androidSetRouteAnnunciator(m_routeState == 1);
13958 SetAISCanvasDisplayStyle(-1);
13970void ChartCanvas::SetShowAIS(
bool show) {
13972 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13973 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13976void ChartCanvas::SetAttenAIS(
bool show) {
13977 m_bShowAISScaled = show;
13978 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13979 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13982void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13985 bool bShowAIS_Array[3] = {
true,
true,
false};
13986 bool bShowScaled_Array[3] = {
false,
true,
true};
13987 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13988 _(
"Attenuate less critical AIS targets"),
13989 _(
"Hide AIS Targets")};
13990 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
13992 int AIS_Toolbar_Switch = 0;
13993 if (StyleIndx == -1) {
13995 for (
int i = 1; i < ArraySize; i++) {
13996 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13997 (bShowScaled_Array[i] == m_bShowAISScaled))
13998 AIS_Toolbar_Switch = i;
14000 AIS_Toolbar_Switch++;
14001 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14002 AIS_Toolbar_Switch++;
14005 AIS_Toolbar_Switch = StyleIndx;
14008 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14010 int AIS_Toolbar_Switch_Next =
14011 AIS_Toolbar_Switch + 1;
14012 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14013 AIS_Toolbar_Switch_Next++;
14014 if (AIS_Toolbar_Switch_Next >= ArraySize)
14015 AIS_Toolbar_Switch_Next = 0;
14018 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14019 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14022void ChartCanvas::TouchAISToolActive() {}
14024void ChartCanvas::UpdateAISTBTool() {}
14032void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14034 bool b_update =
false;
14035 int cc1_edge_comp = 2;
14036 wxRect rect = m_Compass->
GetRect();
14037 wxSize parent_size = GetSize();
14039 parent_size *= m_displayScale;
14043 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14044 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14045 wxRect compass_rect(compass_pt, rect.GetSize());
14047 m_Compass->Move(compass_pt);
14049 if (m_Compass && m_Compass->IsShown())
14050 m_Compass->UpdateStatus(b_force_new | b_update);
14052 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14053 scaler = wxMax(scaler, 1.0);
14054 wxPoint note_point = wxPoint(
14055 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14056 if (m_notification_button) {
14057 m_notification_button->Move(note_point);
14058 m_notification_button->UpdateStatus();
14061 if (b_force_new | b_update) Refresh();
14064void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14065 ChartTypeEnum New_Type,
14066 ChartFamilyEnum New_Family) {
14067 if (!GetpCurrentStack())
return;
14070 if (index < GetpCurrentStack()->nEntry) {
14073 pTentative_Chart =
ChartData->OpenStackChartConditional(
14074 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14076 if (pTentative_Chart) {
14077 if (m_singleChart) m_singleChart->Deactivate();
14079 m_singleChart = pTentative_Chart;
14080 m_singleChart->Activate();
14082 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14083 GetpCurrentStack(), m_singleChart->GetFullPath());
14096 double best_scale_ppm = GetBestVPScale(m_singleChart);
14097 double rotation = GetVPRotation();
14098 double oldskew = GetVPSkew();
14099 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14101 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14102 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14103 if (fabs(newskew) > 0.0001) rotation = newskew;
14106 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14108 UpdateGPSCompassStatusBox(
true);
14112 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14113 if (idx < 0)
return;
14115 std::vector<int> piano_active_chart_index_array;
14116 piano_active_chart_index_array.push_back(
14117 GetpCurrentStack()->GetCurrentEntrydbIndex());
14118 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14121void ChartCanvas::SelectdbChart(
int dbindex) {
14122 if (!GetpCurrentStack())
return;
14125 if (dbindex >= 0) {
14128 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14130 if (pTentative_Chart) {
14131 if (m_singleChart) m_singleChart->Deactivate();
14133 m_singleChart = pTentative_Chart;
14134 m_singleChart->Activate();
14136 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14137 GetpCurrentStack(), m_singleChart->GetFullPath());
14150 double best_scale_ppm = GetBestVPScale(m_singleChart);
14154 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14164void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14167 if (!GetQuiltMode()) {
14168 if (GetpCurrentStack()) {
14169 int stack_index = -1;
14170 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14171 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14172 if (check_dbIndex < 0)
continue;
14174 ChartData->GetChartTableEntry(check_dbIndex);
14175 if (type == cte.GetChartType()) {
14178 }
else if (family == cte.GetChartFamily()) {
14184 if (stack_index >= 0) {
14185 SelectChartFromStack(stack_index);
14189 int sel_dbIndex = -1;
14190 std::vector<int> piano_chart_index_array =
14191 GetQuiltExtendedStackdbIndexArray();
14192 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14193 int check_dbIndex = piano_chart_index_array[i];
14195 if (type == cte.GetChartType()) {
14196 if (IsChartQuiltableRef(check_dbIndex)) {
14197 sel_dbIndex = check_dbIndex;
14200 }
else if (family == cte.GetChartFamily()) {
14201 if (IsChartQuiltableRef(check_dbIndex)) {
14202 sel_dbIndex = check_dbIndex;
14208 if (sel_dbIndex >= 0) {
14209 SelectQuiltRefdbChart(sel_dbIndex,
false);
14211 AdjustQuiltRefChart();
14218 SetQuiltChartHiLiteIndex(-1);
14223bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14224 return std::find(m_tile_yesshow_index_array.begin(),
14225 m_tile_yesshow_index_array.end(),
14226 index) != m_tile_yesshow_index_array.end();
14229bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14230 return std::find(m_tile_noshow_index_array.begin(),
14231 m_tile_noshow_index_array.end(),
14232 index) != m_tile_noshow_index_array.end();
14235void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14236 if (std::find(m_tile_noshow_index_array.begin(),
14237 m_tile_noshow_index_array.end(),
14238 index) == m_tile_noshow_index_array.end()) {
14239 m_tile_noshow_index_array.push_back(index);
14249void ChartCanvas::HandlePianoClick(
14250 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14253 if (!m_pCurrentStack)
return;
14269 double distance = 25000;
14270 int closest_index = -1;
14271 for (
int chart_index : selected_dbIndex_array) {
14273 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14274 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14277 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14278 if (test_distance < distance) {
14279 distance = test_distance;
14280 closest_index = chart_index;
14284 int selected_dbIndex = selected_dbIndex_array[0];
14285 if (closest_index >= 0) selected_dbIndex = closest_index;
14287 if (!GetQuiltMode()) {
14288 if (m_bpersistent_quilt ) {
14289 if (IsChartQuiltableRef(selected_dbIndex)) {
14290 ToggleCanvasQuiltMode();
14291 SelectQuiltRefdbChart(selected_dbIndex);
14292 m_bpersistent_quilt =
false;
14294 SelectChartFromStack(selected_index);
14297 SelectChartFromStack(selected_index);
14298 g_sticky_chart = selected_dbIndex;
14302 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14306 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14307 bool bfound =
false;
14308 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14309 if (m_tile_noshow_index_array[i] ==
14310 selected_dbIndex) {
14311 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14318 m_tile_noshow_index_array.push_back(selected_dbIndex);
14322 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14323 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14327 if (IsChartQuiltableRef(selected_dbIndex)) {
14333 bool set_scale =
false;
14334 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14335 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14341 SelectQuiltRefdbChart(selected_dbIndex,
true);
14343 SelectQuiltRefdbChart(selected_dbIndex,
false);
14348 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14350 double proposed_scale_onscreen =
14353 if (g_bPreserveScaleOnX) {
14354 proposed_scale_onscreen =
14355 wxMin(proposed_scale_onscreen,
14357 GetCanvasWidth()));
14359 proposed_scale_onscreen =
14360 wxMin(proposed_scale_onscreen,
14362 GetCanvasWidth()));
14364 proposed_scale_onscreen =
14365 wxMax(proposed_scale_onscreen,
14374 ToggleCanvasQuiltMode();
14375 SelectdbChart(selected_dbIndex);
14376 m_bpersistent_quilt =
true;
14381 SetQuiltChartHiLiteIndex(-1);
14382 gFrame->UpdateGlobalMenuItems();
14384 HideChartInfoWindow();
14389void ChartCanvas::HandlePianoRClick(
14390 int x,
int y,
int selected_index,
14391 const std::vector<int> &selected_dbIndex_array) {
14394 if (!GetpCurrentStack())
return;
14396 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14397 UpdateCanvasControlBar();
14399 SetQuiltChartHiLiteIndex(-1);
14402void ChartCanvas::HandlePianoRollover(
14403 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14404 int n_charts,
int scale) {
14407 if (!GetpCurrentStack())
return;
14412 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14414 if (!GetQuiltMode()) {
14415 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14418 std::vector<int> piano_chart_index_array;
14419 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14420 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14421 if ((GetpCurrentStack()->nEntry > 1) ||
14422 (piano_chart_index_array.size() >= 1)) {
14423 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14425 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14427 }
else if (GetpCurrentStack()->nEntry == 1) {
14429 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14430 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14431 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14433 }
else if ((-1 == selected_index) &&
14434 (0 == selected_dbIndex_array.size())) {
14435 ShowChartInfoWindow(key_location.x, -1);
14439 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14441 if ((GetpCurrentStack()->nEntry > 1) ||
14442 (piano_chart_index_array.size() >= 1)) {
14444 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14445 selected_dbIndex_array);
14446 else if (n_charts == 1)
14447 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14449 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14456void ChartCanvas::ClearPianoRollover() {
14457 ClearQuiltChartHiLiteIndexArray();
14458 ShowChartInfoWindow(0, -1);
14459 std::vector<int> vec;
14460 ShowCompositeInfoWindow(0, 0, 0, vec);
14464void ChartCanvas::UpdateCanvasControlBar() {
14465 if (m_pianoFrozen)
return;
14467 if (!GetpCurrentStack())
return;
14469 if (!g_bShowChartBar)
return;
14472 int sel_family = -1;
14474 std::vector<int> piano_chart_index_array;
14475 std::vector<int> empty_piano_chart_index_array;
14477 wxString old_hash = m_Piano->GetStoredHash();
14479 if (GetQuiltMode()) {
14480 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14481 GetQuiltFullScreendbIndexArray());
14483 std::vector<int> piano_active_chart_index_array =
14484 GetQuiltCandidatedbIndexArray();
14485 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14487 std::vector<int> piano_eclipsed_chart_index_array =
14488 GetQuiltEclipsedStackdbIndexArray();
14489 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14491 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14492 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14494 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14495 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14497 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14498 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14501 if (m_singleChart) {
14502 sel_type = m_singleChart->GetChartType();
14503 sel_family = m_singleChart->GetChartFamily();
14508 std::vector<int> piano_skew_chart_index_array;
14509 std::vector<int> piano_tmerc_chart_index_array;
14510 std::vector<int> piano_poly_chart_index_array;
14512 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14514 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14515 double skew_norm = ctei.GetChartSkew();
14516 if (skew_norm > 180.) skew_norm -= 360.;
14518 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14519 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14522 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14523 if (fabs(skew_norm) > 1.)
14524 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14526 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14527 }
else if (fabs(skew_norm) > 1.)
14528 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14530 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14531 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14532 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14534 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14535 if (new_hash != old_hash) {
14536 m_Piano->FormatKeys();
14537 HideChartInfoWindow();
14538 m_Piano->ResetRollover();
14539 SetQuiltChartHiLiteIndex(-1);
14540 m_brepaint_piano =
true;
14546 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14548 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14549 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14550 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14551 if (e == CHART_FAMILY_RASTER) mask |= 1;
14552 if (e == CHART_FAMILY_VECTOR) {
14553 if (t == CHART_TYPE_CM93COMP)
14560 wxString s_indicated;
14561 if (sel_type == CHART_TYPE_CM93COMP)
14562 s_indicated =
"cm93";
14564 if (sel_family == CHART_FAMILY_RASTER)
14565 s_indicated =
"raster";
14566 else if (sel_family == CHART_FAMILY_VECTOR)
14567 s_indicated =
"vector";
14570 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14573void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14575void ChartCanvas::PianoPopupMenu(
14576 int x,
int y,
int selected_index,
14577 const std::vector<int> &selected_dbIndex_array) {
14578 if (!GetpCurrentStack())
return;
14581 if (!GetQuiltMode())
return;
14583 m_piano_ctx_menu =
new wxMenu();
14585 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14595 menu_selected_dbIndex = selected_dbIndex_array[0];
14596 menu_selected_index = selected_index;
14599 bool b_is_in_noshow =
false;
14600 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14601 if (m_quilt_noshow_index_array[i] ==
14602 menu_selected_dbIndex)
14604 b_is_in_noshow =
true;
14609 if (b_is_in_noshow) {
14610 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14611 _(
"Show This Chart"));
14612 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14613 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14614 }
else if (GetpCurrentStack()->nEntry > 1) {
14615 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14616 _(
"Hide This Chart"));
14617 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14618 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14622 wxPoint pos = wxPoint(x, y - 30);
14625 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14626 PopupMenu(m_piano_ctx_menu, pos);
14628 delete m_piano_ctx_menu;
14629 m_piano_ctx_menu = NULL;
14631 HideChartInfoWindow();
14632 m_Piano->ResetRollover();
14634 SetQuiltChartHiLiteIndex(-1);
14635 ClearQuiltChartHiLiteIndexArray();
14640void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14641 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14642 if (m_quilt_noshow_index_array[i] ==
14643 menu_selected_dbIndex)
14645 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14651void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14652 if (!GetpCurrentStack())
return;
14655 RemoveChartFromQuilt(menu_selected_dbIndex);
14659 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14660 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14662 int i = menu_selected_index + 1;
14663 bool b_success =
false;
14664 while (i < GetpCurrentStack()->nEntry - 1) {
14665 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14666 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14667 SelectQuiltRefChart(i);
14677 i = menu_selected_index - 1;
14679 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14680 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14681 SelectQuiltRefChart(i);
14691void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14693 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14694 if (m_quilt_noshow_index_array[i] ==
14697 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14702 m_quilt_noshow_index_array.push_back(dbIndex);
14705bool ChartCanvas::UpdateS52State() {
14706 bool retval =
false;
14709 ps52plib->SetShowS57Text(m_encShowText);
14710 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14711 ps52plib->m_bShowSoundg = m_encShowDepth;
14712 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14713 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14716 if (!m_encShowLights)
14717 ps52plib->AddObjNoshow(
"LIGHTS");
14719 ps52plib->RemoveObjNoshow(
"LIGHTS");
14720 ps52plib->SetLightsOff(!m_encShowLights);
14721 ps52plib->m_bExtendLightSectors =
true;
14724 ps52plib->SetAnchorOn(m_encShowAnchor);
14725 ps52plib->SetQualityOfData(m_encShowDataQual);
14731void ChartCanvas::SetShowENCDataQual(
bool show) {
14732 m_encShowDataQual = show;
14733 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14734 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14736 m_s52StateHash = 0;
14739void ChartCanvas::SetShowENCText(
bool show) {
14740 m_encShowText = show;
14741 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14742 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14744 m_s52StateHash = 0;
14747void ChartCanvas::SetENCDisplayCategory(
int category) {
14748 m_encDisplayCategory = category;
14749 m_s52StateHash = 0;
14752void ChartCanvas::SetShowENCDepth(
bool show) {
14753 m_encShowDepth = show;
14754 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14755 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14757 m_s52StateHash = 0;
14760void ChartCanvas::SetShowENCLightDesc(
bool show) {
14761 m_encShowLightDesc = show;
14762 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14763 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14765 m_s52StateHash = 0;
14768void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14769 m_encShowBuoyLabels = show;
14770 m_s52StateHash = 0;
14773void ChartCanvas::SetShowENCLights(
bool show) {
14774 m_encShowLights = show;
14775 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14776 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14778 m_s52StateHash = 0;
14781void ChartCanvas::SetShowENCAnchor(
bool show) {
14782 m_encShowAnchor = show;
14783 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14784 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14786 m_s52StateHash = 0;
14789wxRect ChartCanvas::GetMUIBarRect() {
14792 rv = m_muiBar->GetRect();
14798void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14799 if (!GetAlertString().IsEmpty()) {
14800 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14801 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14803 dc.SetFont(*pfont);
14804 dc.SetPen(*wxTRANSPARENT_PEN);
14806 dc.SetBrush(wxColour(243, 229, 47));
14808 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14812 wxRect sbr = GetScaleBarRect();
14813 int xp = sbr.x + sbr.width + 10;
14814 int yp = (sbr.y + sbr.height) - h;
14816 int wdraw = w + 10;
14817 dc.DrawRectangle(xp, yp, wdraw, h);
14818 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14819 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14829#define BRIGHT_XCALIB
14830#define __OPCPN_USEICC__
14833#ifdef __OPCPN_USEICC__
14834int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14835 double co_green,
double co_blue);
14837wxString temp_file_name;
14841class ocpnCurtain:
public wxDialog
14843 DECLARE_CLASS( ocpnCurtain )
14844 DECLARE_EVENT_TABLE()
14847 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14849 bool ProcessEvent(wxEvent& event);
14853IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14855BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14858ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14860 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14863ocpnCurtain::~ocpnCurtain()
14867bool ocpnCurtain::ProcessEvent(wxEvent& event)
14869 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14870 return GetParent()->GetEventHandler()->ProcessEvent(event);
14875#include <windows.h>
14878typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14879typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14880SetDeviceGammaRamp_ptr_type
14881 g_pSetDeviceGammaRamp;
14882GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14884WORD *g_pSavedGammaMap;
14888int InitScreenBrightness() {
14891 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14895 if (NULL == hGDI32DLL) {
14896 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14898 if (NULL != hGDI32DLL) {
14900 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14901 hGDI32DLL,
"SetDeviceGammaRamp");
14902 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14903 hGDI32DLL,
"GetDeviceGammaRamp");
14906 if ((NULL == g_pSetDeviceGammaRamp) ||
14907 (NULL == g_pGetDeviceGammaRamp)) {
14908 FreeLibrary(hGDI32DLL);
14917 if (!g_pSavedGammaMap) {
14918 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14921 bbr = g_pGetDeviceGammaRamp(
14922 hDC, g_pSavedGammaMap);
14923 ReleaseDC(NULL, hDC);
14928 wxRegKey *pRegKey =
new wxRegKey(
14929 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14930 "NT\\CurrentVersion\\ICM");
14931 if (!pRegKey->Exists()) pRegKey->Create();
14932 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14934 g_brightness_init =
true;
14940 if (NULL == g_pcurtain) {
14941 if (gFrame->CanSetTransparent()) {
14943 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14944 wxPoint(0, 0), ::wxGetDisplaySize(),
14945 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14946 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14953 g_pcurtain->Hide();
14955 HWND hWnd = GetHwndOf(g_pcurtain);
14956 SetWindowLong(hWnd, GWL_EXSTYLE,
14957 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14958 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14959 g_pcurtain->SetTransparent(0);
14961 g_pcurtain->Maximize();
14962 g_pcurtain->Show();
14965 g_pcurtain->Enable();
14966 g_pcurtain->Disable();
14973 g_brightness_init =
true;
14979 wxString cmd(
"xcalib -version");
14981 wxArrayString output;
14982 long r = wxExecute(cmd, output);
14985 " External application \"xcalib\" not found. Screen brightness "
14988 g_brightness_init =
true;
14993int RestoreScreenBrightness() {
14996 if (g_pSavedGammaMap) {
14997 HDC hDC = GetDC(NULL);
14998 g_pSetDeviceGammaRamp(hDC,
15000 ReleaseDC(NULL, hDC);
15002 free(g_pSavedGammaMap);
15003 g_pSavedGammaMap = NULL;
15007 g_pcurtain->Close();
15008 g_pcurtain->Destroy();
15012 g_brightness_init =
false;
15017#ifdef BRIGHT_XCALIB
15018 if (g_brightness_init) {
15020 cmd =
"xcalib -clear";
15021 wxExecute(cmd, wxEXEC_ASYNC);
15022 g_brightness_init =
false;
15032int SetScreenBrightness(
int brightness) {
15039 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15041 g_pcurtain->Close();
15042 g_pcurtain->Destroy();
15046 InitScreenBrightness();
15048 if (NULL == hGDI32DLL) {
15050 wchar_t wdll_name[80];
15051 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15052 LPCWSTR cstr = wdll_name;
15054 hGDI32DLL = LoadLibrary(cstr);
15056 if (NULL != hGDI32DLL) {
15058 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15059 hGDI32DLL,
"SetDeviceGammaRamp");
15060 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15061 hGDI32DLL,
"GetDeviceGammaRamp");
15064 if ((NULL == g_pSetDeviceGammaRamp) ||
15065 (NULL == g_pGetDeviceGammaRamp)) {
15066 FreeLibrary(hGDI32DLL);
15073 HDC hDC = GetDC(NULL);
15084 int increment = brightness * 256 / 100;
15087 WORD GammaTable[3][256];
15090 for (
int i = 0; i < 256; i++) {
15091 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15092 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15093 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15095 table_val += increment;
15097 if (table_val > 65535) table_val = 65535;
15100 g_pSetDeviceGammaRamp(hDC, GammaTable);
15101 ReleaseDC(NULL, hDC);
15108 if (g_pSavedGammaMap) {
15109 HDC hDC = GetDC(NULL);
15110 g_pSetDeviceGammaRamp(hDC,
15112 ReleaseDC(NULL, hDC);
15115 if (brightness < 100) {
15116 if (NULL == g_pcurtain) InitScreenBrightness();
15119 int sbrite = wxMax(1, brightness);
15120 sbrite = wxMin(100, sbrite);
15122 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15126 g_pcurtain->Close();
15127 g_pcurtain->Destroy();
15137#ifdef BRIGHT_XCALIB
15139 if (!g_brightness_init) {
15140 last_brightness = 100;
15141 g_brightness_init =
true;
15142 temp_file_name = wxFileName::CreateTempFileName(
"");
15143 InitScreenBrightness();
15146#ifdef __OPCPN_USEICC__
15149 if (!CreateSimpleICCProfileFile(
15150 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15151 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15152 wxString cmd(
"xcalib ");
15153 cmd += temp_file_name;
15155 wxExecute(cmd, wxEXEC_ASYNC);
15164 if (brightness > last_brightness) {
15166 cmd =
"xcalib -clear";
15167 wxExecute(cmd, wxEXEC_ASYNC);
15169 ::wxMilliSleep(10);
15171 int brite_adj = wxMax(1, brightness);
15172 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15173 wxExecute(cmd, wxEXEC_ASYNC);
15175 int brite_adj = wxMax(1, brightness);
15176 int factor = (brite_adj * 100) / last_brightness;
15177 factor = wxMax(1, factor);
15179 cmd.Printf(
"xcalib -co %2d -a", factor);
15180 wxExecute(cmd, wxEXEC_ASYNC);
15185 last_brightness = brightness;
15192#ifdef __OPCPN_USEICC__
15194#define MLUT_TAG 0x6d4c5554L
15195#define VCGT_TAG 0x76636774L
15197int GetIntEndian(
unsigned char *s) {
15202 p = (
unsigned char *)&ret;
15205 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15207 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15212unsigned short GetShortEndian(
unsigned char *s) {
15213 unsigned short ret;
15217 p = (
unsigned char *)&ret;
15220 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15222 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15228int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15229 double co_green,
double co_blue) {
15233 fp = fopen(file_name,
"wb");
15234 if (!fp)
return -1;
15240 for (
int i = 0; i < 128; i++) header[i] = 0;
15242 fwrite(header, 128, 1, fp);
15246 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15247 fwrite(&numTags, 1, 4, fp);
15249 int tagName0 = VCGT_TAG;
15250 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15251 fwrite(&tagName, 1, 4, fp);
15253 int tagOffset0 = 128 + 4 *
sizeof(int);
15254 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15255 fwrite(&tagOffset, 1, 4, fp);
15258 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15259 fwrite(&tagSize, 1, 4, fp);
15261 fwrite(&tagName, 1, 4, fp);
15263 fwrite(&tagName, 1, 4, fp);
15268 int gammatype0 = 0;
15269 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15270 fwrite(&gammatype, 1, 4, fp);
15272 int numChannels0 = 3;
15273 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15274 fwrite(&numChannels, 1, 2, fp);
15276 int numEntries0 = 256;
15277 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15278 fwrite(&numEntries, 1, 2, fp);
15280 int entrySize0 = 1;
15281 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15282 fwrite(&entrySize, 1, 2, fp);
15284 unsigned char ramp[256];
15287 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15288 fwrite(ramp, 256, 1, fp);
15291 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15292 fwrite(ramp, 256, 1, fp);
15295 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15296 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.
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.
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.
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.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
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.
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".
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.
PluginLoader is a backend module without any direct GUI functionality.
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.
MySQL based storage for routes, tracks, etc.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
User notifications manager.
Notification Manager GUI.
OCPN_AUIManager * g_pauimgr
Global instance.
Optimized wxBitmap Object.
#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.
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.
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.
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.