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<PI_PointContext> ChartCanvas::GetCanvasContextAtPoint(
int x,
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<PI_PointContext>();
7617 rstruct->object_type = OBJECT_CHART;
7618 rstruct->object_ident =
"";
7620 if (seltype == SELTYPE_AISTARGET) {
7621 rstruct->object_type = OBJECT_AISTARGET;
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 = OBJECT_ROUTEPOINT;
7628 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7630 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7631 if (SelectedRoute) {
7632 rstruct->object_type = OBJECT_ROUTESEGMENT;
7633 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7640void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7641 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7642 singleClickEventIsValid =
false;
7643 m_DoubleClickTimer->Stop();
7648bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7649 if (!m_bChartDragging && !m_bDrawingRoute) {
7654 if (m_Compass && m_Compass->IsShown()) {
7656 bool isInCompass = logicalRect.Contains(event.GetPosition());
7657 if (isInCompass || m_mouseWasInCompass) {
7658 if (m_Compass->MouseEvent(event)) {
7659 cursor_region = CENTER;
7660 if (!g_btouch) SetCanvasCursor(event);
7661 m_mouseWasInCompass = isInCompass;
7665 m_mouseWasInCompass = isInCompass;
7668 if (m_notification_button && m_notification_button->IsShown()) {
7670 bool isinButton = logicalRect.Contains(event.GetPosition());
7672 SetCursor(*pCursorArrow);
7673 if (event.LeftDown()) HandleNotificationMouseClick();
7678 if (MouseEventToolbar(event))
return true;
7680 if (MouseEventChartBar(event))
return true;
7682 if (MouseEventMUIBar(event))
return true;
7684 if (MouseEventIENCBar(event))
return true;
7689void ChartCanvas::HandleNotificationMouseClick() {
7690 if (!m_NotificationsList) {
7694 m_NotificationsList->RecalculateSize();
7695 m_NotificationsList->Hide();
7698 if (m_NotificationsList->IsShown()) {
7699 m_NotificationsList->Hide();
7701 m_NotificationsList->RecalculateSize();
7702 m_NotificationsList->ReloadNotificationList();
7703 m_NotificationsList->Show();
7706bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7707 if (!g_bShowChartBar)
return false;
7709 if (!m_Piano->MouseEvent(event))
return false;
7711 cursor_region = CENTER;
7712 if (!g_btouch) SetCanvasCursor(event);
7716bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7717 if (!IsPrimaryCanvas())
return false;
7726 cursor_region = CENTER;
7727 if (!g_btouch) SetCanvasCursor(event);
7731bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7732 if (!IsPrimaryCanvas())
return false;
7745bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7747 if (!m_muiBar->MouseEvent(event))
return false;
7750 cursor_region = CENTER;
7751 if (!g_btouch) SetCanvasCursor(event);
7763 event.GetPosition(&x, &y);
7765 x *= m_displayScale;
7766 y *= m_displayScale;
7768 m_MouseDragging =
event.Dragging();
7774 if (event.Dragging()) {
7775 if ((x == mouse_x) && (y == mouse_y))
return true;
7781 mouse_leftisdown =
event.LeftDown();
7785 cursor_region = CENTER;
7789 if (m_Compass && m_Compass->IsShown() &&
7790 m_Compass->
GetRect().Contains(event.GetPosition())) {
7791 cursor_region = CENTER;
7792 }
else if (x > xr_margin) {
7793 cursor_region = MID_RIGHT;
7794 }
else if (x < xl_margin) {
7795 cursor_region = MID_LEFT;
7796 }
else if (y > yb_margin - chartbar_height &&
7797 y < m_canvas_height - chartbar_height) {
7798 cursor_region = MID_TOP;
7799 }
else if (y < yt_margin) {
7800 cursor_region = MID_BOT;
7802 cursor_region = CENTER;
7805 if (!g_btouch) SetCanvasCursor(event);
7809 leftIsDown =
event.LeftDown();
7812 if (event.LeftDown()) {
7813 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7816 g_bTempShowMenuBar =
false;
7817 parent_frame->ApplyGlobalSettings(
false);
7825 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7826 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7830 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7831 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7834 event.SetEventObject(
this);
7835 if (SendMouseEventToPlugins(event))
7842 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7843 StartChartDragInertia();
7846 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7847 !singleClickEventIsValid) {
7849 if (m_DoubleClickTimer->IsRunning()) {
7850 m_DoubleClickTimer->Stop();
7855 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7856 singleClickEvent = event;
7857 singleClickEventIsValid =
true;
7866 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7867 if (g_click_stop > 0) {
7875 if (GetUpMode() == COURSE_UP_MODE) {
7876 m_b_rot_hidef =
false;
7877 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7879 pRotDefTimer->Stop();
7882 bool bRoll = !g_btouch;
7887 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7888 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7889 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7890 m_RolloverPopupTimer.Start(
7894 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7898 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7907#if !defined(__WXGTK__) && !defined(__WXQT__)
7915 if ((x >= 0) && (y >= 0))
7920 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7921 wxPoint p = ClientToScreen(wxPoint(x, y));
7927 if (m_routeState >= 2) {
7930 m_bDrawingRoute =
true;
7932 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7937 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7940 m_bDrawingRoute =
true;
7942 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7955#if defined(__WXMAC__) || defined(__ANDROID__)
7959 wxClientDC cdc(GetParent());
7971 if (m_pSelectedRoute) {
7973 m_pSelectedRoute->DeSelectRoute();
7975 if (g_bopengl && m_glcc) {
7980 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7983 if (m_pFoundRoutePoint) {
7991 if (g_btouch && m_pRoutePointEditTarget) {
7994 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7998 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7999 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8000 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8001 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8002 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8006 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8009 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8015 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8018 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8019 seltype |= SELTYPE_AISTARGET;
8024 m_pFoundRoutePoint = NULL;
8029 Route *pSelectedActiveRoute = NULL;
8030 Route *pSelectedVizRoute = NULL;
8033 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8034 SelectableItemList SelList =
8035 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8043 bool brp_viz =
false;
8045 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8047 if (pr->IsVisible()) {
8052 if (!brp_viz && prp->IsShared())
8054 brp_viz = prp->IsVisible();
8057 brp_viz = prp->IsVisible();
8059 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8064 m_pSelectedRoute = NULL;
8066 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8069 pSelectedActiveRoute = pr;
8070 pFoundActiveRoutePoint = prp;
8075 if (NULL == pSelectedVizRoute) {
8076 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8078 if (pr->IsVisible()) {
8079 pSelectedVizRoute = pr;
8080 pFoundVizRoutePoint = prp;
8086 delete proute_array;
8091 if (pFoundActiveRoutePoint) {
8092 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8093 m_pSelectedRoute = pSelectedActiveRoute;
8094 }
else if (pFoundVizRoutePoint) {
8095 m_pFoundRoutePoint = pFoundVizRoutePoint;
8096 m_pSelectedRoute = pSelectedVizRoute;
8099 m_pFoundRoutePoint = pFirstVizPoint;
8101 if (m_pSelectedRoute) {
8102 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8103 }
else if (m_pFoundRoutePoint) {
8104 seltype |= SELTYPE_MARKPOINT;
8108 if (m_pFoundRoutePoint) {
8112 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8113 RefreshRect(wp_rect,
true);
8121 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8122 SelectableItemList SelList =
8123 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8125 if (NULL == m_pSelectedRoute)
8130 if (pr->IsVisible()) {
8131 m_pSelectedRoute = pr;
8137 if (m_pSelectedRoute) {
8138 if (NULL == m_pFoundRoutePoint)
8139 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8144 if (g_bopengl && m_glcc) {
8149 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8151 seltype |= SELTYPE_ROUTESEGMENT;
8155 if (pFindTrackSeg) {
8156 m_pSelectedTrack = NULL;
8157 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8158 SelectableItemList SelList =
8159 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8164 if (pt->IsVisible()) {
8165 m_pSelectedTrack = pt;
8169 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8175 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8176 seltype |= SELTYPE_CURRENTPOINT;
8179 else if (pFindTide) {
8180 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8181 seltype |= SELTYPE_TIDEPOINT;
8186 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8191IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8201 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8202 SelectableItemList SelList =
8203 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8206 pFind = *SelList.begin();
8207 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8209 auto node = SelList.begin();
8210 if (SelList.size() > 1) {
8211 for (++node; node != SelList.end(); ++node) {
8214 if (pIDX_candidate->
IDX_type ==
'c') {
8215 pIDX_best_candidate = pIDX_candidate;
8220 pFind = *SelList.begin();
8221 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8224 return pIDX_best_candidate;
8226void ChartCanvas::CallPopupMenu(
int x,
int y) {
8230 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8238 if (SELTYPE_CURRENTPOINT == seltype) {
8244 if (SELTYPE_TIDEPOINT == seltype) {
8250 InvokeCanvasMenu(x, y, seltype);
8253 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8257 m_pSelectedRoute = NULL;
8259 if (m_pFoundRoutePoint) {
8260 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8263 m_pFoundRoutePoint = NULL;
8269bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8277 event.GetPosition(&x, &y);
8283 SelectRadius = g_Platform->GetSelectRadiusPix() /
8284 (m_true_scale_ppm * 1852 * 60);
8291 if (event.LeftDClick() && (cursor_region == CENTER)) {
8292 m_DoubleClickTimer->Start();
8293 singleClickEventIsValid =
false;
8299 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8302 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8305 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8306 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8307 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8313 SelectableItemList rpSelList =
8314 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8315 bool b_onRPtarget =
false;
8318 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8319 b_onRPtarget =
true;
8326 if (m_pRoutePointEditTarget) {
8328 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8334 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8337 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8338 m_pRoutePointEditTarget = NULL;
8339 RefreshRect(wp_rect,
true);
8343 auto node = rpSelList.begin();
8344 if (node != rpSelList.end()) {
8348 wxArrayPtrVoid *proute_array =
8353 bool brp_viz =
false;
8355 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8357 if (pr->IsVisible()) {
8362 delete proute_array;
8366 brp_viz = frp->IsVisible();
8368 brp_viz = frp->IsVisible();
8371 ShowMarkPropertiesDialog(frp);
8379 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8383 if (pr->IsVisible()) {
8384 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8389 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8393 if (pt->IsVisible()) {
8394 ShowTrackPropertiesDialog(pt);
8403 if (m_bShowCurrent) {
8405 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8407 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8415 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8417 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8425 ShowObjectQueryWindow(x, y, zlat, zlon);
8430 if (event.LeftDown()) {
8446 bool appending =
false;
8447 bool inserting =
false;
8450 SetCursor(*pCursorPencil);
8454 m_bRouteEditing =
true;
8456 if (m_routeState == 1) {
8457 m_pMouseRoute =
new Route();
8458 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8468 double nearby_radius_meters =
8469 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8472 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8473 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8474 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8475 wxArrayPtrVoid *proute_array =
8480 bool brp_viz =
false;
8482 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8484 if (pr->IsVisible()) {
8489 delete proute_array;
8491 pNearbyPoint->IsShared())
8494 pNearbyPoint->IsVisible();
8496 brp_viz = pNearbyPoint->IsVisible();
8499 wxString msg = _(
"Use nearby waypoint?");
8501 const bool noname(pNearbyPoint->GetName() ==
"");
8504 _(
"Use nearby nameless waypoint and name it M with"
8505 " a unique number?");
8508 m_FinishRouteOnKillFocus =
false;
8510 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8511 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8512 m_FinishRouteOnKillFocus =
true;
8513 if (dlg_return == wxID_YES) {
8515 if (m_pMouseRoute) {
8516 int last_wp_num = m_pMouseRoute->GetnPoints();
8518 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8519 wxString wp_name = wxString::Format(
8520 "M%002i-%s", last_wp_num + 1, guid_short);
8521 pNearbyPoint->SetName(wp_name);
8523 pNearbyPoint->SetName(
"WPXX");
8525 pMousePoint = pNearbyPoint;
8528 if (m_routeState > 1)
8529 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8530 Undo_HasParent, NULL);
8533 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8534 bool procede =
false;
8538 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8544 m_FinishRouteOnKillFocus =
false;
8550 _(
"Insert first part of this route in the new route?");
8551 if (tail->GetIndexOf(pMousePoint) ==
8554 dmsg = _(
"Insert this route in the new route?");
8556 if (tail->GetIndexOf(pMousePoint) != 1) {
8557 dlg_return = OCPNMessageBox(
8558 this, dmsg, _(
"OpenCPN Route Create"),
8559 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8560 m_FinishRouteOnKillFocus =
true;
8562 if (dlg_return == wxID_YES) {
8569 _(
"Append last part of this route to the new route?");
8570 if (tail->GetIndexOf(pMousePoint) == 1)
8572 "Append this route to the new route?");
8577 if (tail->GetLastPoint() != pMousePoint) {
8578 dlg_return = OCPNMessageBox(
8579 this, dmsg, _(
"OpenCPN Route Create"),
8580 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8581 m_FinishRouteOnKillFocus =
true;
8583 if (dlg_return == wxID_YES) {
8594 if (!FindRouteContainingWaypoint(pMousePoint))
8595 pMousePoint->SetShared(
true);
8600 if (NULL == pMousePoint) {
8601 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8603 pMousePoint->SetNameShown(
false);
8607 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8609 if (m_routeState > 1)
8610 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8611 Undo_IsOrphanded, NULL);
8614 if (m_pMouseRoute) {
8615 if (m_routeState == 1) {
8617 m_pMouseRoute->AddPoint(pMousePoint);
8621 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8622 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8623 &rhumbBearing, &rhumbDist);
8624 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8625 rlat, &gcDist, &gcBearing, NULL);
8626 double gcDistNM = gcDist / 1852.0;
8629 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8630 pow(rhumbDist - gcDistNM - 1, 0.5);
8633 msg << _(
"For this leg the Great Circle route is ")
8635 << _(
" shorter than rhumbline.\n\n")
8636 << _(
"Would you like include the Great Circle routing points "
8639 m_FinishRouteOnKillFocus =
false;
8640 m_disable_edge_pan =
true;
8643 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8644 wxYES_NO | wxNO_DEFAULT);
8646 m_disable_edge_pan =
false;
8647 m_FinishRouteOnKillFocus =
true;
8649 if (answer == wxID_YES) {
8651 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8652 wxRealPoint gcCoord;
8654 for (
int i = 1; i <= segmentCount; i++) {
8655 double fraction = (double)i * (1.0 / (
double)segmentCount);
8656 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8657 gcDist * fraction, gcBearing,
8658 &gcCoord.x, &gcCoord.y, NULL);
8660 if (i < segmentCount) {
8661 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8663 gcPoint->SetNameShown(
false);
8665 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8667 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8670 gcPoint = pMousePoint;
8673 m_pMouseRoute->AddPoint(gcPoint);
8674 pSelect->AddSelectableRouteSegment(
8675 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8676 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8677 prevGcPoint = gcPoint;
8680 undo->CancelUndoableAction(
true);
8683 m_pMouseRoute->AddPoint(pMousePoint);
8684 pSelect->AddSelectableRouteSegment(
8685 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8686 pMousePoint, m_pMouseRoute);
8687 undo->AfterUndoableAction(m_pMouseRoute);
8691 m_pMouseRoute->AddPoint(pMousePoint);
8692 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8693 rlon, m_prev_pMousePoint,
8694 pMousePoint, m_pMouseRoute);
8695 undo->AfterUndoableAction(m_pMouseRoute);
8701 m_prev_pMousePoint = pMousePoint;
8709 int connect = tail->GetIndexOf(pMousePoint);
8714 int length = tail->GetnPoints();
8719 start = connect + 1;
8724 m_pMouseRoute->RemovePoint(
8728 for (i = start; i <= stop; i++) {
8729 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8732 m_pMouseRoute->GetnPoints();
8734 gFrame->RefreshAllCanvas();
8738 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8740 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8741 m_pMouseRoute->FinalizeForRendering();
8743 gFrame->RefreshAllCanvas();
8747 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8749 SetCursor(*pCursorPencil);
8751 if (!m_pMeasureRoute) {
8752 m_pMeasureRoute =
new Route();
8756 if (m_nMeasureState == 1) {
8763 wxEmptyString, wxEmptyString);
8765 pMousePoint->SetShowWaypointRangeRings(
false);
8767 m_pMeasureRoute->AddPoint(pMousePoint);
8771 m_prev_pMousePoint = pMousePoint;
8775 gFrame->RefreshAllCanvas();
8780 FindRoutePointsAtCursor(SelectRadius,
true);
8784 m_last_touch_down_pos =
event.GetPosition();
8786 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8794 if (ret)
return true;
8797 if (event.Dragging()) {
8800 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8802 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8804 SelectableItemList SelList =
pSelect->FindSelectionList(
8808 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8813 if (m_pRoutePointEditTarget &&
8814 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8816 SelectableItemList SelList =
pSelect->FindSelectionList(
8820 if (m_pRoutePointEditTarget == frp) {
8821 m_bIsInRadius =
true;
8826 if (!m_dragoffsetSet) {
8828 .PresetDragOffset(
this, mouse_x, mouse_y);
8829 m_dragoffsetSet =
true;
8834 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8835 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8838 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8840 DraggingAllowed =
false;
8842 if (m_pRoutePointEditTarget &&
8843 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8844 DraggingAllowed =
false;
8846 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8848 if (DraggingAllowed) {
8849 if (!undo->InUndoableAction()) {
8850 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8851 Undo_NeedsCopy, m_pFoundPoint);
8857 if (!g_bopengl && m_pEditRouteArray) {
8858 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8859 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8866 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8867 pre_rect.Union(route_rect);
8875 if (CheckEdgePan(x, y,
true, 5, 2))
8883 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8885 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8886 m_pRoutePointEditTarget,
8887 SELTYPE_DRAGHANDLE);
8888 m_pFoundPoint->m_slat =
8889 m_pRoutePointEditTarget->m_lat;
8890 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8892 m_pRoutePointEditTarget->m_lat =
8894 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8895 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8896 m_pFoundPoint->m_slat =
8898 m_pFoundPoint->m_slon = new_cursor_lon;
8914 if (m_pEditRouteArray) {
8915 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8917 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8920 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8921 post_rect.Union(route_rect);
8927 pre_rect.Union(post_rect);
8928 RefreshRect(pre_rect,
false);
8930 gFrame->RefreshCanvasOther(
this);
8931 m_bRoutePoinDragging =
true;
8936 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8937 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8940 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8942 DraggingAllowed =
false;
8944 if (m_pRoutePointEditTarget &&
8945 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8946 DraggingAllowed =
false;
8948 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8950 if (DraggingAllowed) {
8951 if (!undo->InUndoableAction()) {
8952 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8953 Undo_NeedsCopy, m_pFoundPoint);
8967 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8973 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8974 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8975 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8976 (
int)(lppmax - (pre_rect.height / 2)));
8984 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8987 m_pRoutePointEditTarget,
8988 SELTYPE_DRAGHANDLE);
8989 m_pFoundPoint->m_slat =
8990 m_pRoutePointEditTarget->m_lat;
8991 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8993 m_pRoutePointEditTarget->m_lat =
8996 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9009 if (!g_btouch) InvalidateGL();
9015 .CalculateDCRect(m_dc_route,
this, &post_rect);
9016 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9017 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9018 (
int)(lppmax - (post_rect.height / 2)));
9021 pre_rect.Union(post_rect);
9022 RefreshRect(pre_rect,
false);
9024 gFrame->RefreshCanvasOther(
this);
9025 m_bRoutePoinDragging =
true;
9027 ret = g_btouch ? m_bRoutePoinDragging :
true;
9030 if (ret)
return true;
9033 if (event.LeftUp()) {
9034 bool b_startedit_route =
false;
9035 m_dragoffsetSet =
false;
9038 m_bChartDragging =
false;
9039 m_bIsInRadius =
false;
9044 m_bedge_pan =
false;
9049 bool appending =
false;
9050 bool inserting =
false;
9056 if (m_pRoutePointEditTarget) {
9062 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9063 RefreshRect(wp_rect,
true);
9065 m_pRoutePointEditTarget = NULL;
9067 m_bRouteEditing =
true;
9069 if (m_routeState == 1) {
9070 m_pMouseRoute =
new Route();
9071 m_pMouseRoute->SetHiLite(50);
9075 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9082 double nearby_radius_meters =
9083 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9086 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9087 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9088 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9091 m_FinishRouteOnKillFocus =
9093 dlg_return = OCPNMessageBox(
9094 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9095 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9096 m_FinishRouteOnKillFocus =
true;
9098 dlg_return = wxID_YES;
9100 if (dlg_return == wxID_YES) {
9101 pMousePoint = pNearbyPoint;
9104 if (m_routeState > 1)
9105 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9106 Undo_HasParent, NULL);
9107 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9109 bool procede =
false;
9113 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9119 m_FinishRouteOnKillFocus =
false;
9120 if (m_routeState == 1) {
9124 _(
"Insert first part of this route in the new route?");
9125 if (tail->GetIndexOf(pMousePoint) ==
9128 dmsg = _(
"Insert this route in the new route?");
9130 if (tail->GetIndexOf(pMousePoint) != 1) {
9132 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9133 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9134 m_FinishRouteOnKillFocus =
true;
9136 if (dlg_return == wxID_YES) {
9143 _(
"Append last part of this route to the new route?");
9144 if (tail->GetIndexOf(pMousePoint) == 1)
9146 "Append this route to the new route?");
9150 if (tail->GetLastPoint() != pMousePoint) {
9152 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9153 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9154 m_FinishRouteOnKillFocus =
true;
9156 if (dlg_return == wxID_YES) {
9167 if (!FindRouteContainingWaypoint(pMousePoint))
9168 pMousePoint->SetShared(
true);
9172 if (NULL == pMousePoint) {
9173 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9175 pMousePoint->SetNameShown(
false);
9177 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9179 if (m_routeState > 1)
9180 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9181 Undo_IsOrphanded, NULL);
9184 if (m_routeState == 1) {
9186 m_pMouseRoute->AddPoint(pMousePoint);
9187 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9191 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9192 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9193 &rhumbBearing, &rhumbDist);
9194 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9195 &gcDist, &gcBearing, NULL);
9196 double gcDistNM = gcDist / 1852.0;
9199 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9200 pow(rhumbDist - gcDistNM - 1, 0.5);
9203 msg << _(
"For this leg the Great Circle route is ")
9205 << _(
" shorter than rhumbline.\n\n")
9206 << _(
"Would you like include the Great Circle routing points "
9210 m_FinishRouteOnKillFocus =
false;
9211 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9212 wxYES_NO | wxNO_DEFAULT);
9213 m_FinishRouteOnKillFocus =
true;
9215 int answer = wxID_NO;
9218 if (answer == wxID_YES) {
9220 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9221 wxRealPoint gcCoord;
9223 for (
int i = 1; i <= segmentCount; i++) {
9224 double fraction = (double)i * (1.0 / (
double)segmentCount);
9225 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9226 gcDist * fraction, gcBearing,
9227 &gcCoord.x, &gcCoord.y, NULL);
9229 if (i < segmentCount) {
9230 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9232 gcPoint->SetNameShown(
false);
9233 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9236 gcPoint = pMousePoint;
9239 m_pMouseRoute->AddPoint(gcPoint);
9240 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9242 pSelect->AddSelectableRouteSegment(
9243 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9244 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9245 prevGcPoint = gcPoint;
9248 undo->CancelUndoableAction(
true);
9251 m_pMouseRoute->AddPoint(pMousePoint);
9252 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9253 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9254 rlon, m_prev_pMousePoint,
9255 pMousePoint, m_pMouseRoute);
9256 undo->AfterUndoableAction(m_pMouseRoute);
9260 m_pMouseRoute->AddPoint(pMousePoint);
9261 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9263 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9264 rlon, m_prev_pMousePoint,
9265 pMousePoint, m_pMouseRoute);
9266 undo->AfterUndoableAction(m_pMouseRoute);
9272 m_prev_pMousePoint = pMousePoint;
9279 int connect = tail->GetIndexOf(pMousePoint);
9284 int length = tail->GetnPoints();
9289 start = connect + 1;
9294 m_pMouseRoute->RemovePoint(
9298 for (i = start; i <= stop; i++) {
9299 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9302 m_pMouseRoute->GetnPoints();
9304 gFrame->RefreshAllCanvas();
9308 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9310 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9311 m_pMouseRoute->FinalizeForRendering();
9316 }
else if (m_bMeasure_Active && m_nMeasureState)
9319 m_bedge_pan =
false;
9323 if (m_nMeasureState == 1) {
9324 m_pMeasureRoute =
new Route();
9330 if (m_pMeasureRoute) {
9333 wxEmptyString, wxEmptyString);
9336 m_pMeasureRoute->AddPoint(pMousePoint);
9340 m_prev_pMousePoint = pMousePoint;
9342 m_pMeasureRoute->GetnPoints();
9346 CancelMeasureRoute();
9352 bool bSelectAllowed =
true;
9354 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9356 bSelectAllowed =
false;
9360 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9361 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9362 significant_drag) ||
9363 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9364 significant_drag)) {
9365 bSelectAllowed =
false;
9373 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9375 if (bSelectAllowed) {
9376 bool b_was_editing_mark = m_bMarkEditing;
9377 bool b_was_editing_route = m_bRouteEditing;
9378 FindRoutePointsAtCursor(SelectRadius,
9384 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9385 m_pRoutePointEditTarget = NULL;
9387 if (!b_was_editing_route) {
9388 if (m_pEditRouteArray) {
9389 b_startedit_route =
true;
9393 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9394 m_pTrackRolloverWin->IsActive(
false);
9396 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9397 m_pRouteRolloverWin->IsActive(
false);
9401 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9403 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9411 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9412 pre_rect.Union(route_rect);
9415 RefreshRect(pre_rect,
true);
9418 b_startedit_route =
false;
9422 if (m_pRoutePointEditTarget) {
9423 if (b_was_editing_mark ||
9424 b_was_editing_route) {
9425 if (m_lastRoutePointEditTarget) {
9429 .EnableDragHandle(
false);
9430 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9431 SELTYPE_DRAGHANDLE);
9435 if (m_pRoutePointEditTarget) {
9438 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9439 wxPoint2DDouble dragHandlePoint =
9441 .GetDragHandlePoint(
this);
9443 dragHandlePoint.m_y, dragHandlePoint.m_x,
9444 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9447 if (m_lastRoutePointEditTarget) {
9451 .EnableDragHandle(
false);
9452 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9453 SELTYPE_DRAGHANDLE);
9456 wxArrayPtrVoid *lastEditRouteArray =
9458 m_lastRoutePointEditTarget);
9459 if (lastEditRouteArray) {
9460 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9462 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9467 delete lastEditRouteArray;
9478 if (m_lastRoutePointEditTarget) {
9481 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9482 RefreshRect(wp_rect,
true);
9485 if (m_pRoutePointEditTarget) {
9488 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9489 RefreshRect(wp_rect,
true);
9497 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9498 bool b_start_rollover =
false;
9502 if (pFind) b_start_rollover =
true;
9505 if (!b_start_rollover && !b_startedit_route) {
9506 SelectableItemList SelList =
pSelect->FindSelectionList(
9510 if (pr && pr->IsVisible()) {
9511 b_start_rollover =
true;
9517 if (!b_start_rollover && !b_startedit_route) {
9518 SelectableItemList SelList =
pSelect->FindSelectionList(
9522 if (tr && tr->IsVisible()) {
9523 b_start_rollover =
true;
9529 if (b_start_rollover)
9530 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9534 bool appending =
false;
9535 bool inserting =
false;
9537 if (m_bRouteEditing ) {
9539 if (m_pRoutePointEditTarget) {
9545 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9546 double nearby_radius_meters =
9547 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9548 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9549 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9550 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9552 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9556 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9558 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9562 std::find(list->begin(), list->end(), pNearbyPoint);
9563 if (pos != list->end()) {
9575 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9580 OCPNMessageBox(
this,
9581 _(
"Replace this RoutePoint by the nearby "
9583 _(
"OpenCPN RoutePoint change"),
9584 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9585 if (dlg_return == wxID_YES) {
9590 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9593 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9595 if (tail && current && (tail != current)) {
9597 connect = tail->GetIndexOf(pNearbyPoint);
9598 int index_current_route =
9599 current->GetIndexOf(m_pRoutePointEditTarget);
9600 index_last = current->GetIndexOf(current->GetLastPoint());
9601 dlg_return1 = wxID_NO;
9603 index_current_route) {
9605 if (connect != tail->GetnPoints()) {
9608 _(
"Last part of route to be appended to dragged "
9612 _(
"Full route to be appended to dragged route?");
9614 dlg_return1 = OCPNMessageBox(
9615 this, dmsg, _(
"OpenCPN Route Create"),
9616 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9617 if (dlg_return1 == wxID_YES) {
9621 }
else if (index_current_route ==
9626 _(
"First part of route to be inserted into dragged "
9628 if (connect == tail->GetnPoints())
9630 "Full route to be inserted into dragged route?");
9632 dlg_return1 = OCPNMessageBox(
9633 this, dmsg, _(
"OpenCPN Route Create"),
9634 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9635 if (dlg_return1 == wxID_YES) {
9642 if (m_pRoutePointEditTarget->IsShared()) {
9644 dlg_return = OCPNMessageBox(
9646 _(
"Do you really want to delete and replace this "
9648 "\n" + _(
"which has been created manually?"),
9649 (
"OpenCPN RoutePoint warning"),
9650 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9653 if (dlg_return == wxID_YES) {
9654 pMousePoint = pNearbyPoint;
9656 pMousePoint->SetShared(
true);
9666 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9668 if (m_pEditRouteArray) {
9669 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9671 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9676 auto pos = std::find(list->begin(), list->end(),
9677 m_pRoutePointEditTarget);
9679 pSelect->DeleteAllSelectableRoutePoints(pr);
9680 pSelect->DeleteAllSelectableRouteSegments(pr);
9683 pos = std::find(list->begin(), list->end(),
9684 m_pRoutePointEditTarget);
9687 pSelect->AddAllSelectableRouteSegments(pr);
9688 pSelect->AddAllSelectableRoutePoints(pr);
9690 pr->FinalizeForRendering();
9691 pr->UpdateSegmentDistances();
9692 if (m_bRoutePoinDragging) {
9694 NavObj_dB::GetInstance().UpdateRoute(pr);
9702 if (m_pEditRouteArray) {
9703 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9705 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9724 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9731 delete m_pRoutePointEditTarget;
9732 m_lastRoutePointEditTarget = NULL;
9733 m_pRoutePointEditTarget = NULL;
9734 undo->AfterUndoableAction(pMousePoint);
9735 undo->InvalidateUndo();
9740 else if (m_bMarkEditing) {
9741 if (m_pRoutePointEditTarget)
9742 if (m_bRoutePoinDragging) {
9744 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9748 if (m_pRoutePointEditTarget)
9749 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9751 if (!m_pRoutePointEditTarget) {
9752 delete m_pEditRouteArray;
9753 m_pEditRouteArray = NULL;
9754 m_bRouteEditing =
false;
9756 m_bRoutePoinDragging =
false;
9763 int length = tail->GetnPoints();
9764 for (
int i = connect + 1; i <= length; i++) {
9765 current->AddPointAndSegment(tail->GetPoint(i),
false);
9768 gFrame->RefreshAllCanvas();
9771 current->FinalizeForRendering();
9777 pSelect->DeleteAllSelectableRoutePoints(current);
9778 pSelect->DeleteAllSelectableRouteSegments(current);
9779 for (
int i = 1; i < connect; i++) {
9780 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9782 pSelect->AddAllSelectableRouteSegments(current);
9783 pSelect->AddAllSelectableRoutePoints(current);
9784 current->FinalizeForRendering();
9791 if (m_pEditRouteArray) {
9792 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9793 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9806 if (m_bRouteEditing) {
9809 bool appending =
false;
9810 bool inserting =
false;
9813 if (m_pRoutePointEditTarget) {
9814 m_pRoutePointEditTarget->
m_bBlink =
false;
9818 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9819 double nearby_radius_meters =
9820 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9821 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9822 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9823 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9825 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9826 bool duplicate =
false;
9828 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9830 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9834 std::find(list->begin(), list->end(), pNearbyPoint);
9835 if (pos != list->end()) {
9847 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9852 OCPNMessageBox(
this,
9853 _(
"Replace this RoutePoint by the nearby "
9855 _(
"OpenCPN RoutePoint change"),
9856 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9857 if (dlg_return == wxID_YES) {
9861 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9864 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9866 if (tail && current && (tail != current)) {
9868 connect = tail->GetIndexOf(pNearbyPoint);
9869 int index_current_route =
9870 current->GetIndexOf(m_pRoutePointEditTarget);
9871 index_last = current->GetIndexOf(current->GetLastPoint());
9872 dlg_return1 = wxID_NO;
9874 index_current_route) {
9876 if (connect != tail->GetnPoints()) {
9879 _(
"Last part of route to be appended to dragged "
9883 _(
"Full route to be appended to dragged route?");
9885 dlg_return1 = OCPNMessageBox(
9886 this, dmsg, _(
"OpenCPN Route Create"),
9887 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9888 if (dlg_return1 == wxID_YES) {
9892 }
else if (index_current_route ==
9897 _(
"First part of route to be inserted into dragged "
9899 if (connect == tail->GetnPoints())
9901 "Full route to be inserted into dragged route?");
9903 dlg_return1 = OCPNMessageBox(
9904 this, dmsg, _(
"OpenCPN Route Create"),
9905 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9906 if (dlg_return1 == wxID_YES) {
9913 if (m_pRoutePointEditTarget->IsShared()) {
9914 dlg_return = wxID_NO;
9915 dlg_return = OCPNMessageBox(
9917 _(
"Do you really want to delete and replace this "
9919 "\n" + _(
"which has been created manually?"),
9920 (
"OpenCPN RoutePoint warning"),
9921 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9924 if (dlg_return == wxID_YES) {
9925 pMousePoint = pNearbyPoint;
9927 pMousePoint->SetShared(
true);
9937 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9939 if (m_pEditRouteArray) {
9940 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9942 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9946 auto pos = std::find(list->begin(), list->end(),
9947 m_pRoutePointEditTarget);
9949 pSelect->DeleteAllSelectableRoutePoints(pr);
9950 pSelect->DeleteAllSelectableRouteSegments(pr);
9953 pos = std::find(list->begin(), list->end(),
9954 m_pRoutePointEditTarget);
9955 if (pos != list->end()) list->erase(pos);
9958 pSelect->AddAllSelectableRouteSegments(pr);
9959 pSelect->AddAllSelectableRoutePoints(pr);
9961 pr->FinalizeForRendering();
9962 pr->UpdateSegmentDistances();
9965 if (m_bRoutePoinDragging) {
9970 NavObj_dB::GetInstance().UpdateRoutePoint(
9971 m_pRoutePointEditTarget);
9973 NavObj_dB::GetInstance().UpdateRoute(pr);
9985 int length = tail->GetnPoints();
9986 for (
int i = connect + 1; i <= length; i++) {
9987 current->AddPointAndSegment(tail->GetPoint(i),
false);
9991 gFrame->RefreshAllCanvas();
9994 current->FinalizeForRendering();
10000 pSelect->DeleteAllSelectableRoutePoints(current);
10001 pSelect->DeleteAllSelectableRouteSegments(current);
10002 for (
int i = 1; i < connect; i++) {
10003 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10005 pSelect->AddAllSelectableRouteSegments(current);
10006 pSelect->AddAllSelectableRoutePoints(current);
10007 current->FinalizeForRendering();
10014 if (m_pEditRouteArray) {
10015 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10017 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10029 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10036 delete m_pRoutePointEditTarget;
10037 m_lastRoutePointEditTarget = NULL;
10038 undo->AfterUndoableAction(pMousePoint);
10039 undo->InvalidateUndo();
10044 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10047 delete m_pEditRouteArray;
10048 m_pEditRouteArray = NULL;
10052 m_bRouteEditing =
false;
10053 m_pRoutePointEditTarget = NULL;
10059 else if (m_bMarkEditing) {
10060 if (m_pRoutePointEditTarget) {
10061 if (m_bRoutePoinDragging) {
10063 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10065 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10070 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10072 RefreshRect(wp_rect,
true);
10075 m_pRoutePointEditTarget = NULL;
10076 m_bMarkEditing =
false;
10081 else if (leftIsDown) {
10082 leftIsDown =
false;
10086 if (!m_bChartDragging && !m_bMeasure_Active) {
10088 m_bChartDragging =
false;
10092 m_bRoutePoinDragging =
false;
10095 if (ret)
return true;
10098 if (event.RightDown()) {
10109 m_FinishRouteOnKillFocus =
false;
10110 CallPopupMenu(mx, my);
10111 m_FinishRouteOnKillFocus =
true;
10121 if (event.ShiftDown()) {
10125 event.GetPosition(&x, &y);
10127 x *= m_displayScale;
10128 y *= m_displayScale;
10134 int wheel_dir =
event.GetWheelRotation();
10137 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10138 wheel_dir = wheel_dir > 0 ? 1 : -1;
10140 double factor = g_mouse_zoom_sensitivity;
10141 if (wheel_dir < 0) factor = 1 / factor;
10144 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10145 if (wheel_dir == m_last_wheel_dir) {
10146 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10151 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10152 m_wheelstopwatch.Start(0);
10157 m_last_wheel_dir = wheel_dir;
10162 if (event.LeftDown()) {
10168 last_drag.x = x, last_drag.y = y;
10169 panleftIsDown =
true;
10172 if (event.LeftUp()) {
10173 if (panleftIsDown) {
10175 panleftIsDown =
false;
10178 if (!m_bChartDragging && !m_bMeasure_Active) {
10179 switch (cursor_region) {
10201 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10206 m_bChartDragging =
false;
10212 if (event.Dragging() && event.LeftIsDown()) {
10228 if (g_btouch && !m_inPinch) {
10229 struct timespec now;
10230 clock_gettime(CLOCK_MONOTONIC, &now);
10231 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10233 bool trigger_hold =
false;
10234 if (
false == m_bChartDragging) {
10235 if (m_DragTrigger < 0) {
10238 m_DragTriggerStartTime = tnow;
10239 trigger_hold =
true;
10241 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10242 m_DragTrigger = -1;
10247 if (trigger_hold)
return true;
10249 if (
false == m_bChartDragging) {
10252 last_drag.x = x - 1, last_drag.y = y - 1;
10253 m_bChartDragging =
true;
10254 m_chart_drag_total_time = 0;
10255 m_chart_drag_total_x = 0;
10256 m_chart_drag_total_y = 0;
10257 m_inertia_last_drag_x = x;
10258 m_inertia_last_drag_y = y;
10259 m_drag_vec_x.clear();
10260 m_drag_vec_y.clear();
10261 m_drag_vec_t.clear();
10262 m_last_drag_time = tnow;
10266 uint64_t delta_t = tnow - m_last_drag_time;
10267 double delta_tf = delta_t / 1e9;
10269 m_chart_drag_total_time += delta_tf;
10270 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10271 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10273 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10274 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10275 m_drag_vec_t.push_back(delta_tf);
10277 m_inertia_last_drag_x = x;
10278 m_inertia_last_drag_y = y;
10279 m_last_drag_time = tnow;
10281 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10282 if (!m_routeState) {
10285 m_bChartDragging =
true;
10287 StartTimedMovement();
10288 m_pan_drag.x += last_drag.x - x;
10289 m_pan_drag.y += last_drag.y - y;
10290 last_drag.x = x, last_drag.y = y;
10293 }
else if (!g_btouch) {
10294 if ((last_drag.x != x) || (last_drag.y != y)) {
10295 if (!m_routeState) {
10298 m_bChartDragging =
true;
10299 StartTimedMovement();
10300 m_pan_drag.x += last_drag.x - x;
10301 m_pan_drag.y += last_drag.y - y;
10302 last_drag.x = x, last_drag.y = y;
10309 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10311 m_DoubleClickTimer->Start();
10312 singleClickEventIsValid =
false;
10320void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10321 if (MouseEventOverlayWindows(event))
return;
10325 bool nm = MouseEventProcessObjects(event);
10329void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10332 wxCursor *ptarget_cursor = pCursorArrow;
10333 if (!pPlugIn_Cursor) {
10334 ptarget_cursor = pCursorArrow;
10335 if ((!m_routeState) &&
10336 (!m_bMeasure_Active) ) {
10337 if (cursor_region == MID_RIGHT) {
10338 ptarget_cursor = pCursorRight;
10339 }
else if (cursor_region == MID_LEFT) {
10340 ptarget_cursor = pCursorLeft;
10341 }
else if (cursor_region == MID_TOP) {
10342 ptarget_cursor = pCursorDown;
10343 }
else if (cursor_region == MID_BOT) {
10344 ptarget_cursor = pCursorUp;
10346 ptarget_cursor = pCursorArrow;
10348 }
else if (m_bMeasure_Active ||
10350 ptarget_cursor = pCursorPencil;
10352 ptarget_cursor = pPlugIn_Cursor;
10355 SetCursor(*ptarget_cursor);
10358void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10359 SetCursor(*pCursorArrow);
10362void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10366 wxArrayString files;
10368 ChartBase *target_chart = GetChartAtCursor();
10369 if (target_chart) {
10370 file.Assign(target_chart->GetFullPath());
10371 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10372 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10375 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10377 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10378 unsigned int im = stackIndexArray.size();
10379 int scale = 2147483647;
10380 if (VPoint.b_quilt && im > 0) {
10381 for (
unsigned int is = 0; is < im; is++) {
10382 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10383 CHART_TYPE_MBTILES) {
10384 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10386 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10387 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10389 .Contains(lat, lon)) {
10390 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10393 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10394 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10402 std::vector<Ais8_001_22 *> area_notices;
10404 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10407 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10408 auto target_data = target.second;
10409 if (!target_data->area_notices.empty()) {
10410 for (
auto &ani : target_data->area_notices) {
10415 for (Ais8_001_22_SubAreaList::iterator sa =
10416 area_notice.sub_areas.begin();
10417 sa != area_notice.sub_areas.end(); ++sa) {
10418 switch (sa->shape) {
10419 case AIS8_001_22_SHAPE_CIRCLE: {
10420 wxPoint target_point;
10422 bbox.Expand(target_point);
10423 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10426 case AIS8_001_22_SHAPE_RECT: {
10427 wxPoint target_point;
10429 bbox.Expand(target_point);
10430 if (sa->e_dim_m > sa->n_dim_m)
10431 bbox.EnLarge(sa->e_dim_m * vp_scale);
10433 bbox.EnLarge(sa->n_dim_m * vp_scale);
10436 case AIS8_001_22_SHAPE_POLYGON:
10437 case AIS8_001_22_SHAPE_POLYLINE: {
10438 for (
int i = 0; i < 4; ++i) {
10439 double lat = sa->latitude;
10440 double lon = sa->longitude;
10441 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10443 wxPoint target_point;
10445 bbox.Expand(target_point);
10449 case AIS8_001_22_SHAPE_SECTOR: {
10450 double lat1 = sa->latitude;
10451 double lon1 = sa->longitude;
10453 wxPoint target_point;
10455 bbox.Expand(target_point);
10456 for (
int i = 0; i < 18; ++i) {
10459 sa->left_bound_deg +
10460 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10461 sa->radius_m / 1852.0, &lat, &lon);
10463 bbox.Expand(target_point);
10465 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10468 bbox.Expand(target_point);
10474 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10475 area_notices.push_back(&area_notice);
10482 if (target_chart || !area_notices.empty() || file.HasName()) {
10484 int sel_rad_pix = 5;
10485 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10490 SetCursor(wxCURSOR_WAIT);
10491 bool lightsVis = m_encShowLights;
10492 if (!lightsVis) SetShowENCLights(
true);
10495 ListOfObjRazRules *rule_list = NULL;
10496 ListOfPI_S57Obj *pi_rule_list = NULL;
10499 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10500 else if (target_plugin_chart)
10501 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10502 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10504 ListOfObjRazRules *overlay_rule_list = NULL;
10505 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10508 if (CHs57_Overlay) {
10509 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10510 zlat, zlon, SelectRadius, &GetVP());
10513 if (!lightsVis) SetShowENCLights(
false);
10516 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10517 wxString face = dFont->GetFaceName();
10521 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10522 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10526 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10534 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10535 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10538 int points = dFont->GetPointSize();
10540 int points = dFont->GetPointSize() + 1;
10544 for (
int i = -2; i < 5; i++) {
10545 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10549 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10551 if (overlay_rule_list && CHs57_Overlay) {
10552 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10553 objText <<
"<hr noshade>";
10556 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10557 an != area_notices.end(); ++an) {
10558 objText <<
"<b>AIS Area Notice:</b> ";
10559 objText << ais8_001_22_notice_names[(*an)->notice_type];
10560 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10561 (*an)->sub_areas.begin();
10562 sa != (*an)->sub_areas.end(); ++sa)
10563 if (!sa->text.empty()) objText << sa->text;
10564 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10565 objText <<
"<hr noshade>";
10569 objText << Chs57->CreateObjDescriptions(rule_list);
10570 else if (target_plugin_chart)
10571 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10574 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10577 wxString AddFiles, filenameOK;
10579 if (!target_plugin_chart) {
10582 AddFiles = wxString::Format(
10583 "<hr noshade><br><b>Additional info files attached to: </b> "
10585 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10587 file.GetFullName());
10589 file.Assign(file.GetPath(),
"");
10590 wxDir dir(file.GetFullPath());
10592 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10594 file.Assign(dir.GetNameWithSep().append(filename));
10595 wxString FormatString =
10596 "<td valign=top><font size=-2><a "
10597 "href=\"%s\">%s</a></font></td>";
10598 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10599 filenameOK = file.GetFullPath();
10601 if (3 * ((
int)filecount / 3) == filecount)
10602 FormatString.Prepend(
"<tr>");
10604 FormatString.Prepend(
10605 "<td>  </td>");
10608 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10609 file.GetFullName());
10612 cont = dir.GetNext(&filename);
10614 objText << AddFiles <<
"</table>";
10616 objText <<
"</font>";
10617 objText <<
"</body></html>";
10619 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10623 if ((!Chs57 && filecount == 1)) {
10625 wxHtmlLinkInfo hli(filenameOK);
10626 wxHtmlLinkEvent hle(1, hli);
10630 if (rule_list) rule_list->Clear();
10633 if (overlay_rule_list) overlay_rule_list->Clear();
10634 delete overlay_rule_list;
10636 if (pi_rule_list) pi_rule_list->Clear();
10637 delete pi_rule_list;
10639 SetCursor(wxCURSOR_ARROW);
10643void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10652 wxSize canvas_size = GetSize();
10659 wxPoint canvas_pos = GetPosition();
10662 bool newFit =
false;
10663 if (canvas_size.x < fitted_size.x) {
10664 fitted_size.x = canvas_size.x - 40;
10665 if (canvas_size.y < fitted_size.y)
10666 fitted_size.y -= 40;
10668 if (canvas_size.y < fitted_size.y) {
10669 fitted_size.y = canvas_size.y - 40;
10670 if (canvas_size.x < fitted_size.x)
10671 fitted_size.x -= 40;
10682 wxString title_base = _(
"Mark Properties");
10684 title_base = _(
"Waypoint Properties");
10689 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10701void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10711 if (g_bresponsive) {
10712 wxSize canvas_size = GetSize();
10713 wxPoint canvas_pos = GetPosition();
10717 if (canvas_size.x < fitted_size.x) {
10718 fitted_size.x = canvas_size.x;
10719 if (canvas_size.y < fitted_size.y)
10720 fitted_size.y -= 20;
10722 if (canvas_size.y < fitted_size.y) {
10723 fitted_size.y = canvas_size.y;
10724 if (canvas_size.x < fitted_size.x)
10725 fitted_size.x -= 20;
10734 wxPoint xxp = ClientToScreen(canvas_pos);
10745void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10757void pupHandler_PasteWaypoint() {
10760 int pasteBuffer = kml.ParsePasteBuffer();
10761 RoutePoint *pasted = kml.GetParsedRoutePoint();
10762 if (!pasted)
return;
10764 double nearby_radius_meters =
10765 g_Platform->GetSelectRadiusPix() /
10766 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10768 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10769 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10771 int answer = wxID_NO;
10775 "There is an existing waypoint at the same location as the one you are "
10776 "pasting. Would you like to merge the pasted data with it?\n\n");
10777 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10778 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10779 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10782 if (answer == wxID_YES) {
10783 nearPoint->SetName(pasted->GetName());
10785 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10786 pRouteManagerDialog->UpdateWptListCtrl();
10789 if (answer == wxID_NO) {
10792 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10795 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10798 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10799 pRouteManagerDialog->UpdateWptListCtrl();
10804 gFrame->InvalidateAllGL();
10805 gFrame->RefreshAllCanvas(
false);
10808void pupHandler_PasteRoute() {
10811 int pasteBuffer = kml.ParsePasteBuffer();
10812 Route *pasted = kml.GetParsedRoute();
10813 if (!pasted)
return;
10815 double nearby_radius_meters =
10816 g_Platform->GetSelectRadiusPix() /
10817 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10823 bool mergepoints =
false;
10824 bool createNewRoute =
true;
10825 int existingWaypointCounter = 0;
10827 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10828 curPoint = pasted->GetPoint(i);
10829 nearPoint = pWayPointMan->GetNearbyWaypoint(
10830 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10832 mergepoints =
true;
10833 existingWaypointCounter++;
10841 int answer = wxID_NO;
10845 "There are existing waypoints at the same location as some of the ones "
10846 "you are pasting. Would you like to just merge the pasted data into "
10848 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10849 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10850 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10852 if (answer == wxID_CANCEL) {
10859 if (mergepoints && answer == wxID_YES &&
10860 existingWaypointCounter == pasted->GetnPoints()) {
10863 createNewRoute =
false;
10869 Route *newRoute = 0;
10872 if (createNewRoute) {
10873 newRoute =
new Route();
10877 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10878 curPoint = pasted->GetPoint(i);
10881 newPoint = pWayPointMan->GetNearbyWaypoint(
10882 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10883 newPoint->SetName(curPoint->GetName());
10886 if (createNewRoute) newRoute->AddPoint(newPoint);
10892 newPoint->SetIconName(
"circle");
10895 newPoint->SetShared(
false);
10897 newRoute->AddPoint(newPoint);
10898 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10901 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10904 if (i > 1 && createNewRoute)
10905 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10906 curPoint->m_lat, curPoint->m_lon,
10907 prevPoint, newPoint, newRoute);
10908 prevPoint = newPoint;
10911 if (createNewRoute) {
10914 NavObj_dB::GetInstance().InsertRoute(newRoute);
10920 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10921 pRouteManagerDialog->UpdateRouteListCtrl();
10922 pRouteManagerDialog->UpdateWptListCtrl();
10924 gFrame->InvalidateAllGL();
10925 gFrame->RefreshAllCanvas(
false);
10931void pupHandler_PasteTrack() {
10934 int pasteBuffer = kml.ParsePasteBuffer();
10935 Track *pasted = kml.GetParsedTrack();
10936 if (!pasted)
return;
10944 newTrack->SetName(pasted->GetName());
10946 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10947 curPoint = pasted->GetPoint(i);
10951 wxDateTime now = wxDateTime::Now();
10954 newTrack->AddPoint(newPoint);
10957 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10958 newPoint->m_lat, newPoint->m_lon,
10959 prevPoint, newPoint, newTrack);
10961 prevPoint = newPoint;
10966 NavObj_dB::GetInstance().InsertTrack(newTrack);
10968 gFrame->InvalidateAllGL();
10969 gFrame->RefreshAllCanvas(
false);
10972bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10975 v[
"CursorPosition_x"] = x;
10976 v[
"CursorPosition_y"] = y;
10979 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10980 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10981 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
10986 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
10988 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
10991#define SELTYPE_UNKNOWN 0x0001
10992#define SELTYPE_ROUTEPOINT 0x0002
10993#define SELTYPE_ROUTESEGMENT 0x0004
10994#define SELTYPE_TIDEPOINT 0x0008
10995#define SELTYPE_CURRENTPOINT 0x0010
10996#define SELTYPE_ROUTECREATE 0x0020
10997#define SELTYPE_AISTARGET 0x0040
10998#define SELTYPE_MARKPOINT 0x0080
10999#define SELTYPE_TRACKSEGMENT 0x0100
11000#define SELTYPE_DRAGHANDLE 0x0200
11003 if (g_bhide_context_menus)
return true;
11005 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11006 m_pIDXCandidate, m_nmea_log);
11009 wxEVT_COMMAND_MENU_SELECTED,
11010 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11016 if (m_inLongPress) {
11017 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11018 m_inLongPress =
false;
11022 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11025 wxEVT_COMMAND_MENU_SELECTED,
11026 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11028 delete m_canvasMenu;
11029 m_canvasMenu = NULL;
11039void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11042 if (m_canvasMenu) {
11043 m_canvasMenu->PopupMenuHandler(event);
11048void ChartCanvas::StartRoute() {
11050 if (g_brouteCreating)
return;
11054 g_brouteCreating =
true;
11056 m_bDrawingRoute =
false;
11057 SetCursor(*pCursorPencil);
11059 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11061 HideGlobalToolbar();
11064 androidSetRouteAnnunciator(
true);
11068wxString ChartCanvas::FinishRoute() {
11070 m_prev_pMousePoint = NULL;
11071 m_bDrawingRoute =
false;
11073 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11076 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11078 androidSetRouteAnnunciator(
false);
11081 SetCursor(*pCursorArrow);
11083 if (m_pMouseRoute) {
11084 if (m_bAppendingRoute) {
11086 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11088 if (m_pMouseRoute->GetnPoints() > 1) {
11090 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11093 m_pMouseRoute = NULL;
11096 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11103 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11104 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11105 pRouteManagerDialog->UpdateRouteListCtrl();
11108 m_bAppendingRoute =
false;
11109 m_pMouseRoute = NULL;
11111 m_pSelectedRoute = NULL;
11113 undo->InvalidateUndo();
11114 gFrame->RefreshAllCanvas(
true);
11118 ShowGlobalToolbar();
11120 g_brouteCreating =
false;
11125void ChartCanvas::HideGlobalToolbar() {
11126 if (m_canvasIndex == 0) {
11127 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11131void ChartCanvas::ShowGlobalToolbar() {
11132 if (m_canvasIndex == 0) {
11133 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11137void ChartCanvas::ShowAISTargetList() {
11138 if (NULL == g_pAISTargetList) {
11142 g_pAISTargetList->UpdateAISTargetList();
11145void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11146 if (!m_bShowOutlines)
return;
11150 int nEntry =
ChartData->GetChartTableEntries();
11152 for (
int i = 0; i < nEntry; i++) {
11156 bool b_group_draw =
false;
11157 if (m_groupIndex > 0) {
11158 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11159 int index = pt->GetGroupArray()[ig];
11160 if (m_groupIndex == index) {
11161 b_group_draw =
true;
11166 b_group_draw =
true;
11168 if (b_group_draw) RenderChartOutline(dc, i, vp);
11174 if (VPoint.b_quilt) {
11175 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11176 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11180 }
else if (m_singleChart &&
11181 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11185 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11188 if (zoom_factor > 8.0) {
11189 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11192 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11196 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11200void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11202 if (g_bopengl && m_glcc) {
11204 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11209 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11210 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11213 float plylat, plylon;
11214 float plylat1, plylon1;
11216 int pixx, pixy, pixx1, pixy1;
11219 ChartData->GetDBBoundingBox(dbIndex, box);
11223 if (box.GetLonRange() == 360)
return;
11225 double lon_bias = 0;
11227 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11229 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11231 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11232 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11234 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11235 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11238 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11241 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11242 if (0 == nAuxPlyEntries)
11246 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11247 plylon += lon_bias;
11253 for (
int i = 0; i < nPly - 1; i++) {
11254 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11255 plylon1 += lon_bias;
11261 int pixxs1 = pixx1;
11262 int pixys1 = pixy1;
11264 bool b_skip =
false;
11268 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11269 pow((
double)(pixy1 - pixy), 2)) /
11275 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11280 if (fabs(dist - distgc) > 10000. * 1852.)
11286 ClipResult res = cohen_sutherland_line_clip_i(
11288 if (res != Invisible && !b_skip)
11289 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11297 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11298 plylon1 += lon_bias;
11304 ClipResult res = cohen_sutherland_line_clip_i(
11306 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11313 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11314 for (
int j = 0; j < nAuxPlyEntries; j++) {
11316 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11321 for (
int i = 0; i < nAuxPly - 1; i++) {
11322 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11328 int pixxs1 = pixx1;
11329 int pixys1 = pixy1;
11331 bool b_skip =
false;
11335 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11336 ((pixy1 - pixy) * (pixy1 - pixy))) /
11341 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11346 if (fabs(dist - distgc) > 10000. * 1852.)
11352 ClipResult res = cohen_sutherland_line_clip_i(
11354 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11362 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11367 ClipResult res = cohen_sutherland_line_clip_i(
11369 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11374static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11375 const wxString &second) {
11376 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11378 int pointsize = dFont->GetPointSize();
11382 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11383 false, dFont->GetFaceName());
11385 dc.SetFont(*psRLI_font);
11393 int hilite_offset = 3;
11396 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11397 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11399 dc.GetTextExtent(first, &w1, &h1);
11400 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11406 w = wxMax(w1, w2) + (h1 / 2);
11411 xp = ref_point.x - w;
11413 yp += hilite_offset;
11415 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11417 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11418 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11420 dc.DrawText(first, xp, yp);
11421 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11424void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11425 if (!g_bAllowShipToActive)
return;
11431 wxPoint2DDouble pa, pb;
11438 if (rt->
m_width != wxPENSTYLE_INVALID)
11440 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11441 g_shipToActiveStyle, 5)];
11442 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11444 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11447 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11450 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11453 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11454 (
int)pb.m_y, GetVP(),
true);
11458#ifdef USE_ANDROID_GLES2
11459 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11461 if (style != wxPENSTYLE_SOLID) {
11462 if (glChartCanvas::dash_map.find(style) !=
11463 glChartCanvas::dash_map.end()) {
11464 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11468 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11471 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11472 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11478void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11480 if (m_routeState >= 2) route = m_pMouseRoute;
11481 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11482 route = m_pMeasureRoute;
11484 if (!route)
return;
11492 int np = route->GetnPoints();
11494 if (g_btouch && (np > 1)) np--;
11496 render_lat = rp.m_lat;
11497 render_lon = rp.m_lon;
11500 double rhumbBearing, rhumbDist;
11502 &rhumbBearing, &rhumbDist);
11503 double brg = rhumbBearing;
11504 double dist = rhumbDist;
11508 double gcBearing, gcBearing2, gcDist;
11509 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11512 double gcDistm = gcDist / 1852.0;
11515 rhumbBearing = 90.;
11517 wxPoint destPoint, lastPoint;
11520 int milesDiff = rhumbDist - gcDistm;
11521 if (milesDiff > 1) {
11532 for (
int i = 1; i <= milesDiff; i++) {
11533 double p = (double)i * (1.0 / (
double)milesDiff);
11535 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11536 &pLon, &pLat, &gcBearing2);
11538 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11540 lastPoint = destPoint;
11543 if (r_rband.x && r_rband.y) {
11544 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11546 if (m_bMeasure_DistCircle) {
11547 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11548 powf((
float)(r_rband.y - lastPoint.y), 2));
11551 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11552 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11558 wxString routeInfo;
11561 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11567 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11569 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11570 (
int)varBrg, 0x00B0);
11577 routeInfo <<
"\nReverse: ";
11579 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11580 (
int)(brg + 180.) % 360, 0x00B0);
11582 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11583 (
int)(varBrg + 180.) % 360, 0x00B0);
11588 s0.Append(_(
"Route") +
": ");
11590 s0.Append(_(
"Layer Route: "));
11593 if (!g_btouch) disp_length += dist;
11596 RouteLegInfo(dc, r_rband, routeInfo, s0);
11598 m_brepaint_piano =
true;
11601void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11602 if (!m_bShowVisibleSectors)
return;
11604 if (g_bDeferredInitDone) {
11606 double rhumbBearing, rhumbDist;
11607 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11608 &rhumbBearing, &rhumbDist);
11610 if (rhumbDist > 0.05)
11612 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11613 m_sectorlegsVisible);
11614 m_sector_glat =
gLat;
11615 m_sector_glon =
gLon;
11617 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11621void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11629void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11630 if (!ps52plib)
return;
11632 if (VPoint.b_quilt) {
11633 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11635 if (m_pQuilt->IsQuiltVector()) {
11636 if (ps52plib->GetStateHash() != m_s52StateHash) {
11638 m_s52StateHash = ps52plib->GetStateHash();
11642 if (ps52plib->GetStateHash() != m_s52StateHash) {
11644 m_s52StateHash = ps52plib->GetStateHash();
11649 bool bSendPlibState =
true;
11650 if (VPoint.b_quilt) {
11651 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11654 if (bSendPlibState) {
11656 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11657 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11658 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11659 v[
"OpenCPN Version Date"] = VERSION_DATE;
11660 v[
"OpenCPN Version Full"] = VERSION_FULL;
11663 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11664 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11665 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11666 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11667 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11668 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11669 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11673 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11674 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11678 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11679 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11680 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11681 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11682 ps52plib->m_bShowS57ImportantTextOnly;
11683 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11684 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11685 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11686 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11687 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11690 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11691 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11692 v[
"OpenCPN Scale Factor Exp"] =
11693 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11700 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11701 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11702 g_lastS52PLIBPluginMessage = out;
11709 wxPaintDC dc(
this);
11719 if (!m_b_paint_enable) {
11727 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11729 if (m_glcc && g_bopengl) {
11730 if (!s_in_update) {
11740 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11742 wxRegion ru = GetUpdateRegion();
11744 int rx, ry, rwidth, rheight;
11745 ru.GetBox(rx, ry, rwidth, rheight);
11747#ifdef ocpnUSE_DIBSECTION
11750 wxMemoryDC temp_dc;
11758 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11759 height += m_Piano->GetHeight();
11761 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11765 int thumbx, thumby, thumbsx, thumbsy;
11766 pthumbwin->GetPosition(&thumbx, &thumby);
11767 pthumbwin->GetSize(&thumbsx, &thumbsy);
11768 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11771 rgn_chart.Subtract(rgn_thumbwin);
11772 ru.Subtract(rgn_thumbwin);
11778 wxRegion rgn_blit = ru;
11779 if (g_bShowChartBar) {
11780 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11781 GetClientSize().x, m_Piano->GetHeight());
11784 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11785 if (style->chartStatusWindowTransparent)
11786 m_brepaint_piano =
true;
11788 ru.Subtract(chart_bar_rect);
11792 if (m_Compass && m_Compass->IsShown()) {
11793 wxRect compassRect = m_Compass->
GetRect();
11794 if (ru.Contains(compassRect) != wxOutRegion) {
11795 ru.Subtract(compassRect);
11799 if (m_notification_button) {
11800 wxRect noteRect = m_notification_button->
GetRect();
11801 if (ru.Contains(noteRect) != wxOutRegion) {
11802 ru.Subtract(noteRect);
11807 bool b_newview =
true;
11812 m_cache_vp.IsValid()) {
11818 bool b_rcache_ok =
false;
11819 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11820 b_rcache_ok = !b_newview;
11823 if (VPoint.b_MercatorProjectionOverride)
11824 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11838 if (b_rcache_ok) chart_get_region.Clear();
11841 if (VPoint.b_quilt)
11843 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11845 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11850 AbstractPlatform::ShowBusySpinner();
11854 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11855 (m_working_bm.GetHeight() != svp.
pix_height))
11859 if (fabs(VPoint.
rotation) < 0.01) {
11860 bool b_save =
true;
11865 m_cache_vp.Invalidate();
11879 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11884 int dy = c_new.y - c_old.y;
11885 int dx = c_new.x - c_old.x;
11890 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11894 temp_dc.SelectObject(m_working_bm);
11896 wxMemoryDC cache_dc;
11897 cache_dc.SelectObject(m_cached_chart_bm);
11901 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11904 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11910 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11913 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11921 update_region.Union(
11924 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11929 update_region.Union(
11932 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11936 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11938 cache_dc.SelectObject(wxNullBitmap);
11942 temp_dc.SelectObject(m_cached_chart_bm);
11945 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11949 temp_dc.SelectObject(m_working_bm);
11950 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11955 temp_dc.SelectObject(m_cached_chart_bm);
11960 temp_dc.SelectObject(m_working_bm);
11961 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11974 wxMemoryDC scratch_dc_0;
11975 scratch_dc_0.SelectObject(m_cached_chart_bm);
11978 scratch_dc_0.SelectObject(wxNullBitmap);
11987 temp_dc.SelectObject(m_working_bm);
11990 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11991 chart_get_all_region);
11994 AbstractPlatform::HideBusySpinner();
12000 if (!m_singleChart) {
12001 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12006 if (!chart_get_region.IsEmpty()) {
12007 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12011 if (temp_dc.IsOk()) {
12016 if (!VPoint.b_quilt) {
12019 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12020 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12027 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12028 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12031 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12033 temp_dc.DestroyClippingRegion();
12038 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12040 if (!backgroundRegion.IsEmpty()) {
12046 wxColour water = pWorldBackgroundChart->water;
12047 if (water.IsOk()) {
12048 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12049 temp_dc.SetBrush(wxBrush(water));
12051 while (upd.HaveRects()) {
12052 wxRect rect = upd.GetRect();
12053 temp_dc.DrawRectangle(rect);
12058 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12059 temp_dc.SetDeviceClippingRegion(*clip_region);
12060 delete clip_region;
12064 SetVPRotation(VPoint.
skew);
12073 wxMemoryDC *pChartDC = &temp_dc;
12074 wxMemoryDC rotd_dc;
12076 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12078 if (!b_rcache_ok) {
12080 wxMemoryDC tbase_dc;
12082 tbase_dc.SelectObject(bm_base);
12084 tbase_dc.SelectObject(wxNullBitmap);
12086 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12089 wxImage base_image;
12090 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12098 bool b_rot_ok =
false;
12099 if (base_image.IsOk()) {
12102 m_b_rot_hidef =
false;
12106 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12107 m_b_rot_hidef, &m_roffset);
12112 rot_vp.IsValid() && (ri.IsOk())) {
12119 m_prot_bm =
new wxBitmap(ri);
12122 m_roffset.x += VPoint.rv_rect.x;
12123 m_roffset.y += VPoint.rv_rect.y;
12126 if (m_prot_bm && m_prot_bm->IsOk()) {
12127 rotd_dc.SelectObject(*m_prot_bm);
12128 pChartDC = &rotd_dc;
12130 pChartDC = &temp_dc;
12131 m_roffset = wxPoint(0, 0);
12134 pChartDC = &temp_dc;
12135 m_roffset = wxPoint(0, 0);
12138 wxPoint offset = m_roffset;
12141 m_cache_vp = VPoint;
12144 wxMemoryDC mscratch_dc;
12145 mscratch_dc.SelectObject(*pscratch_bm);
12147 mscratch_dc.ResetBoundingBox();
12148 mscratch_dc.DestroyClippingRegion();
12149 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12152 wxRegionIterator upd(rgn_blit);
12154 wxRect rect = upd.GetRect();
12156 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12157 rect.x - offset.x, rect.y - offset.y);
12163 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12164 if (
this == wxWindow::FindFocus()) {
12167 wxColour colour = GetGlobalColor(
"BLUE4");
12168 mscratch_dc.SetPen(wxPen(colour));
12169 mscratch_dc.SetBrush(wxBrush(colour));
12171 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12172 mscratch_dc.DrawRectangle(activeRect);
12177 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12178 unsigned int im = stackIndexArray.size();
12179 if (VPoint.b_quilt && im > 0) {
12180 std::vector<int> tiles_to_show;
12181 for (
unsigned int is = 0; is < im; is++) {
12183 ChartData->GetChartTableEntry(stackIndexArray[is]);
12184 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12187 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12188 tiles_to_show.push_back(stackIndexArray[is]);
12192 if (tiles_to_show.size())
12193 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12199 ocpnDC scratch_dc(mscratch_dc);
12200 RenderAlertMessage(mscratch_dc, GetVP());
12206#ifdef ocpnUSE_DIBSECTION
12211 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12212 q_dc.SelectObject(qbm);
12215 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12218 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12219 q_dc.SetBrush(qbr);
12220 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12223 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12226 q_dc.SelectObject(wxNullBitmap);
12235 if( VPoint.b_quilt ) {
12236 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12237 ChartBase *chart = m_pQuilt->GetRefChart();
12238 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12243 ChPI->ClearPLIBTextList();
12246 ps52plib->ClearTextList();
12250 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12252 wxColor maskBackground = wxColour(1,0,0);
12253 t_dc.SelectObject( qbm );
12254 t_dc.SetBackground(wxBrush(maskBackground));
12258 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12261 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12262 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12265 wxRegionIterator upd_final( ru );
12266 while( upd_final ) {
12267 wxRect rect = upd_final.GetRect();
12268 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12272 t_dc.SelectObject( wxNullBitmap );
12278 if (VPoint.b_quilt) {
12279 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12280 ChartBase *chart = m_pQuilt->GetRefChart();
12281 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12285 ChPI->ClearPLIBTextList();
12287 if (ps52plib) ps52plib->ClearTextList();
12292 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12294 if (g_bShowChartBar && m_Piano) {
12295 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12296 GetVP().pix_width, m_Piano->GetHeight());
12299 if (!style->chartStatusWindowTransparent)
12300 chart_all_text_region.Subtract(chart_bar_rect);
12303 if (m_Compass && m_Compass->IsShown()) {
12304 wxRect compassRect = m_Compass->
GetRect();
12305 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12306 chart_all_text_region.Subtract(compassRect);
12310 mscratch_dc.DestroyClippingRegion();
12312 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12313 chart_all_text_region);
12319 ocpnDC scratch_dc(mscratch_dc);
12320 DrawOverlayObjects(scratch_dc, ru);
12323 wxRegionIterator upd_final(rgn_blit);
12324 while (upd_final) {
12325 wxRect rect = upd_final.GetRect();
12326 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12333 temp_dc.SelectObject(wxNullBitmap);
12335 mscratch_dc.SelectObject(wxNullBitmap);
12337 dc.DestroyClippingRegion();
12342void ChartCanvas::PaintCleanup() {
12344 if (m_inPinch)
return;
12355 m_bTCupdate =
false;
12359 WarpPointer(warp_x, warp_y);
12366 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12367 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12371wxColour GetErrorGraphicColor(
double val)
12390 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12391 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12392 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12393 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12394 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12395 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12396 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12397 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12398 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12399 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12400 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12401 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12402 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12403 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12404 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12405 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12406 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12407 else if( val >= 48) c.Set(
"#410000");
12412void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12415 gr_image.InitAlpha();
12417 double maxval = -10000;
12418 double minval = 10000;
12435 maxval = wxMax(maxval, (glat - rlat));
12436 minval = wxMin(minval, (glat - rlat));
12453 double f = ((glat - rlat)-minval)/(maxval - minval);
12455 double dy = (f * 40);
12457 wxColour c = GetErrorGraphicColor(dy);
12458 unsigned char r = c.Red();
12459 unsigned char g = c.Green();
12460 unsigned char b = c.Blue();
12462 gr_image.SetRGB(j, i, r,g,b);
12463 if((glat - rlat )!= 0)
12464 gr_image.SetAlpha(j, i, 128);
12466 gr_image.SetAlpha(j, i, 255);
12473 wxBitmap *pbm =
new wxBitmap(gr_image);
12474 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12475 pbm->SetMask(gr_mask);
12477 pmdc->DrawBitmap(*pbm, 0,0);
12485void ChartCanvas::CancelMouseRoute() {
12487 m_pMouseRoute = NULL;
12488 m_bDrawingRoute =
false;
12491int ChartCanvas::GetNextContextMenuId() {
12492 return CanvasMenuHandler::GetNextContextMenuId();
12495bool ChartCanvas::SetCursor(
const wxCursor &c) {
12497 if (g_bopengl && m_glcc)
12498 return m_glcc->SetCursor(c);
12501 return wxWindow::SetCursor(c);
12504void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12505 if (g_bquiting)
return;
12515 if (!m_RolloverPopupTimer.IsRunning() &&
12516 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12517 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12518 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12519 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12522 if (m_glcc && g_bopengl) {
12525 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12527 m_glcc->Refresh(eraseBackground,
12544 if (m_pCIWin && m_pCIWin->IsShown()) {
12546 m_pCIWin->Refresh(
false);
12554 wxWindow::Refresh(eraseBackground, rect);
12557void ChartCanvas::Update() {
12558 if (m_glcc && g_bopengl) {
12563 wxWindow::Update();
12567 if (!pemboss)
return;
12568 int x = pemboss->x, y = pemboss->y;
12569 const double factor = 200;
12571 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12572 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12573 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12576 wxMemoryDC snip_dc;
12577 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12578 snip_dc.SelectObject(snip_bmp);
12580 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12581 snip_dc.SelectObject(wxNullBitmap);
12583 wxImage snip_img = snip_bmp.ConvertToImage();
12586 unsigned char *pdata = snip_img.GetData();
12588 for (
int y = 0; y < pemboss->height; y++) {
12589 int map_index = (y * pemboss->width);
12590 for (
int x = 0; x < pemboss->width; x++) {
12591 double val = (pemboss->pmap[map_index] * factor) / 256.;
12593 int nred = (int)((*pdata) + val);
12594 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12595 *pdata++ = (
unsigned char)nred;
12597 int ngreen = (int)((*pdata) + val);
12598 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12599 *pdata++ = (
unsigned char)ngreen;
12601 int nblue = (int)((*pdata) + val);
12602 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12603 *pdata++ = (
unsigned char)nblue;
12611 wxBitmap emb_bmp(snip_img);
12614 wxMemoryDC result_dc;
12615 result_dc.SelectObject(emb_bmp);
12618 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12620 result_dc.SelectObject(wxNullBitmap);
12626 if (GetQuiltMode()) {
12628 int refIndex = GetQuiltRefChartdbIndex();
12629 if (refIndex >= 0) {
12631 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12632 if (current_type == CHART_TYPE_MBTILES) {
12633 ChartBase *pChart = m_pQuilt->GetRefChart();
12636 zoom_factor = ptc->GetZoomFactor();
12641 if (zoom_factor <= 3.9)
return NULL;
12643 if (m_singleChart) {
12644 if (zoom_factor <= 3.9)
return NULL;
12649 if (m_pEM_OverZoom) {
12650 m_pEM_OverZoom->x = 4;
12651 m_pEM_OverZoom->y = 0;
12653 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12654 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12657 return m_pEM_OverZoom;
12660void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12673 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12674 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12678 AISDrawAreaNotices(dc, GetVP(),
this);
12680 wxDC *pdc = dc.GetDC();
12682 pdc->DestroyClippingRegion();
12683 wxDCClipper(*pdc, ru);
12686 if (m_bShowNavobjects) {
12687 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12688 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12689 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12690 DrawAnchorWatchPoints(dc);
12692 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12693 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12696 AISDraw(dc, GetVP(),
this);
12700 RenderVisibleSectorLights(dc);
12702 RenderAllChartOutlines(dc, GetVP());
12703 RenderRouteLegs(dc);
12704 RenderShipToActive(dc,
false);
12706 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12708 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12712 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12713 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12716 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12721 RebuildTideSelectList(GetVP().GetBBox());
12722 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12725 if (m_bShowCurrent) {
12726 RebuildCurrentSelectList(GetVP().GetBBox());
12727 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12730 if (!g_PrintingInProgress) {
12731 if (IsPrimaryCanvas()) {
12735 if (IsPrimaryCanvas()) {
12739 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12741 if (m_pTrackRolloverWin) {
12742 m_pTrackRolloverWin->Draw(dc);
12743 m_brepaint_piano =
true;
12746 if (m_pRouteRolloverWin) {
12747 m_pRouteRolloverWin->Draw(dc);
12748 m_brepaint_piano =
true;
12751 if (m_pAISRolloverWin) {
12752 m_pAISRolloverWin->Draw(dc);
12753 m_brepaint_piano =
true;
12755 if (m_brepaint_piano && g_bShowChartBar) {
12756 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12759 if (m_Compass) m_Compass->Paint(dc);
12761 if (!g_CanvasHideNotificationIcon) {
12762 if (IsPrimaryCanvas()) {
12763 auto ¬eman = NotificationManager::GetInstance();
12764 if (noteman.GetNotificationCount()) {
12765 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12766 if (m_notification_button->UpdateStatus()) Refresh();
12767 m_notification_button->Show(
true);
12768 m_notification_button->Paint(dc);
12770 m_notification_button->Show(
false);
12776 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12782 if (!m_bShowDepthUnits)
return NULL;
12784 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12786 if (GetQuiltMode()) {
12787 wxString s = m_pQuilt->GetQuiltDepthUnit();
12790 depth_unit_type = DEPTH_UNIT_FEET;
12791 else if (s.StartsWith(
"FATHOMS"))
12792 depth_unit_type = DEPTH_UNIT_FATHOMS;
12793 else if (s.StartsWith(
"METERS"))
12794 depth_unit_type = DEPTH_UNIT_METERS;
12795 else if (s.StartsWith(
"METRES"))
12796 depth_unit_type = DEPTH_UNIT_METERS;
12797 else if (s.StartsWith(
"METRIC"))
12798 depth_unit_type = DEPTH_UNIT_METERS;
12799 else if (s.StartsWith(
"METER"))
12800 depth_unit_type = DEPTH_UNIT_METERS;
12803 if (m_singleChart) {
12804 depth_unit_type = m_singleChart->GetDepthUnitType();
12805 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12806 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12811 switch (depth_unit_type) {
12812 case DEPTH_UNIT_FEET:
12815 case DEPTH_UNIT_METERS:
12816 ped = m_pEM_Meters;
12818 case DEPTH_UNIT_FATHOMS:
12819 ped = m_pEM_Fathoms;
12825 ped->x = (GetVP().
pix_width - ped->width);
12827 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12828 wxRect r = m_Compass->
GetRect();
12829 ped->y = r.y + r.height;
12836void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12839 if (style->embossFont == wxEmptyString) {
12840 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12842 font.SetPointSize(60);
12843 font.SetWeight(wxFONTWEIGHT_BOLD);
12845 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12846 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12848 int emboss_width = 500;
12849 int emboss_height = 200;
12853 delete m_pEM_Meters;
12854 delete m_pEM_Fathoms;
12858 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12860 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12862 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12865#define OVERZOOM_TEXT _("OverZoom")
12867void ChartCanvas::SetOverzoomFont() {
12872 if (style->embossFont == wxEmptyString) {
12873 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12875 font.SetPointSize(40);
12876 font.SetWeight(wxFONTWEIGHT_BOLD);
12878 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12879 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12881 wxClientDC dc(
this);
12883 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12885 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12886 font.SetPointSize(font.GetPointSize() - 1);
12888 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12890 m_overzoomFont = font;
12891 m_overzoomTextWidth = w;
12892 m_overzoomTextHeight = h;
12895void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12896 delete m_pEM_OverZoom;
12898 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12900 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12901 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12904emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12905 int height,
const wxString &str,
12910 wxBitmap bmp(width, height, -1);
12913 wxMemoryDC temp_dc;
12914 temp_dc.SelectObject(bmp);
12917 temp_dc.SetBackground(*wxWHITE_BRUSH);
12918 temp_dc.SetTextBackground(*wxWHITE);
12919 temp_dc.SetTextForeground(*wxBLACK);
12923 temp_dc.SetFont(font);
12926 temp_dc.GetTextExtent(str, &str_w, &str_h);
12928 temp_dc.DrawText(str, 1, 1);
12931 temp_dc.SelectObject(wxNullBitmap);
12934 wxImage img = bmp.ConvertToImage();
12936 int image_width = str_w * 105 / 100;
12937 int image_height = str_h * 105 / 100;
12938 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12939 wxMin(image_height, img.GetHeight()));
12940 wxImage imgs = img.GetSubImage(r);
12944 case GLOBAL_COLOR_SCHEME_DAY:
12948 case GLOBAL_COLOR_SCHEME_DUSK:
12951 case GLOBAL_COLOR_SCHEME_NIGHT:
12958 const int w = imgs.GetWidth();
12959 const int h = imgs.GetHeight();
12960 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12965 for (
int y = 1; y < h - 1; y++) {
12966 for (
int x = 1; x < w - 1; x++) {
12968 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12969 val = (int)(val * val_factor);
12970 index = (y * w) + x;
12983void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12984 Track *active_track = NULL;
12987 active_track = pTrackDraw;
12991 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12994 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12997void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12998 Track *active_track = NULL;
13001 active_track = pTrackDraw;
13005 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13008void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13009 Route *active_route = NULL;
13011 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13012 active_route = pRouteDraw;
13017 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13022 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13025void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13026 Route *active_route = NULL;
13029 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13030 active_route = pRouteDraw;
13034 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13037void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13038 if (!pWayPointMan)
return;
13040 auto node = pWayPointMan->GetWaypointList()->begin();
13042 while (node != pWayPointMan->GetWaypointList()->end()) {
13051 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13055 if (pWP->GetShowWaypointRangeRings() &&
13056 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13057 double factor = 1.00;
13058 if (pWP->GetWaypointRangeRingsStepUnits() ==
13060 factor = 1 / 1.852;
13062 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13063 pWP->GetWaypointRangeRingsStep() / 60.;
13067 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13068 pWP->m_lat + radius, pWP->m_lon + radius);
13069 if (!BltBBox.IntersectOut(radar_box)) {
13080void ChartCanvas::DrawBlinkObjects() {
13082 wxRect update_rect;
13084 if (!pWayPointMan)
return;
13086 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13093 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13096void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13101 wxPoint lAnchorPoint1, lAnchorPoint2;
13115 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13116 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13118 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13119 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13120 dc.SetBrush(*ppBrush);
13124 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13129 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13134 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13139 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13144double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13147 wxPoint lAnchorPoint;
13150 double tlat1, tlon1;
13152 if (pAnchorWatchPoint) {
13153 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13154 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13155 dabs = fabs(d1 / 1852.);
13156 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13161 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13162 pow((
double)(lAnchorPoint.y - r1.y), 2));
13165 if (d1 < 0) lpp = -lpp;
13173void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13176 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13178 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13184 if ((type ==
't') || (type ==
'T')) {
13185 if (BBox.Contains(lat, lon)) {
13187 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13193void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13196 wxDateTime this_now = gTimeSource;
13197 bool cur_time = !gTimeSource.IsValid();
13198 if (cur_time) this_now = wxDateTime::Now();
13199 time_t t_this_now = this_now.GetTicks();
13201 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13203 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13204 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13205 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13206 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13208 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13209 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13210 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13211 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13212 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13213 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13215 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13216 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13217 int font_size = wxMax(10, dFont->GetPointSize());
13220 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13221 false, dFont->GetFaceName());
13223 dc.SetPen(*pblack_pen);
13224 dc.SetBrush(*pgreen_brush);
13228 case GLOBAL_COLOR_SCHEME_DAY:
13231 case GLOBAL_COLOR_SCHEME_DUSK:
13234 case GLOBAL_COLOR_SCHEME_NIGHT:
13235 bm = m_bmTideNight;
13242 int bmw = bm.GetWidth();
13243 int bmh = bm.GetHeight();
13245 float scale_factor = 1.0;
13249 float icon_pixelRefDim = 45;
13254 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13256 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13258 scale_factor *= pix_factor;
13265 scale_factor *= user_scale_factor;
13266 scale_factor *= GetContentScaleFactor();
13269 double marge = 0.05;
13270 std::vector<LLBBox> drawn_boxes;
13271 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13275 if ((type ==
't') || (type ==
'T'))
13280 if (BBox.ContainsMarge(lat, lon, marge)) {
13282 if (GetVP().chart_scale < 500000) {
13283 bool bdrawn =
false;
13284 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13285 if (drawn_boxes[i].Contains(lat, lon)) {
13290 if (bdrawn)
continue;
13293 this_box.Set(lat, lon, lat, lon);
13294 this_box.EnLarge(.005);
13295 drawn_boxes.push_back(this_box);
13301 if (GetVP().chart_scale > 500000) {
13302 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13306 dc.SetFont(*plabelFont);
13318 if (
ptcmgr->GetTideFlowSens(
13319 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13323 ptcmgr->GetHightOrLowTide(
13324 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13325 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13337 if (tctime > t_this_now)
13338 ptcmgr->GetHightOrLowTide(
13339 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13340 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13344 ptcmgr->GetHightOrLowTide(
13345 t_this_now, FORWARD_TEN_MINUTES_STEP,
13346 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13360 int width = (int)(12 * scale_factor + 0.5);
13361 int height = (int)(45 * scale_factor + 0.5);
13362 int linew = wxMax(1, (
int)(scale_factor));
13363 int xDraw = r.x - (width / 2);
13364 int yDraw = r.y - (height / 2);
13367 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13368 int hs = (httime > lttime) ? -4 : 4;
13369 hs *= (int)(scale_factor + 0.5);
13370 if (ts > 0.995 || ts < 0.005) hs = 0;
13371 int ht_y = (int)(height * ts);
13374 pblack_pen->SetWidth(linew);
13375 dc.SetPen(*pblack_pen);
13376 dc.SetBrush(*pyelo_brush);
13377 dc.DrawRectangle(xDraw, yDraw, width, height);
13381 dc.SetPen(*pblue_pen);
13382 dc.SetBrush(*pblue_brush);
13383 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13384 (width - (4 * linew)), height - ht_y);
13390 arrow[0].x = xDraw + 2 * linew;
13391 arrow[1].x = xDraw + width / 2;
13392 arrow[2].x = xDraw + width - 2 * linew;
13393 pyelo_pen->SetWidth(linew);
13394 pblue_pen->SetWidth(linew);
13395 if (ts > 0.35 || ts < 0.15)
13397 hl = (int)(height * 0.25) + yDraw;
13399 arrow[1].y = hl + hs;
13402 dc.SetPen(*pyelo_pen);
13404 dc.SetPen(*pblue_pen);
13405 dc.DrawLines(3, arrow);
13407 if (ts > 0.60 || ts < 0.40)
13409 hl = (int)(height * 0.5) + yDraw;
13411 arrow[1].y = hl + hs;
13414 dc.SetPen(*pyelo_pen);
13416 dc.SetPen(*pblue_pen);
13417 dc.DrawLines(3, arrow);
13419 if (ts < 0.65 || ts > 0.85)
13421 hl = (int)(height * 0.75) + yDraw;
13423 arrow[1].y = hl + hs;
13426 dc.SetPen(*pyelo_pen);
13428 dc.SetPen(*pblue_pen);
13429 dc.DrawLines(3, arrow);
13433 s.Printf(
"%3.1f", nowlev);
13435 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13437 dc.GetTextExtent(s, &wx1, NULL);
13439 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13454void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13457 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13459 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13465 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13466 if ((BBox.Contains(lat, lon))) {
13468 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13474void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13477 float tcvalue, dir;
13481 double lon_last = 0.;
13482 double lat_last = 0.;
13484 double marge = 0.2;
13485 bool cur_time = !gTimeSource.IsValid();
13487 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13488 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13490 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13492 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13493 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13494 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13495 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13496 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13497 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13498 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13499 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13501 double skew_angle = GetVPRotation();
13503 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13504 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13505 int font_size = wxMax(10, dFont->GetPointSize());
13508 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13509 false, dFont->GetFaceName());
13511 float scale_factor = 1.0;
13517 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13519 float nominal_icon_size_pixels = 15;
13520 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13522 scale_factor *= pix_factor;
13529 scale_factor *= user_scale_factor;
13531 scale_factor *= GetContentScaleFactor();
13534 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13540 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13541 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13546 int dd = (int)(5.0 * scale_factor + 0.5);
13557 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13558 dc.SetPen(*pblack_pen);
13559 dc.SetBrush(*porange_brush);
13560 dc.DrawPolygon(4, d);
13563 dc.SetBrush(*pblack_brush);
13564 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13568 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13582 double a1 = fabs(tcvalue) * 10.;
13584 a1 = wxMax(1.0, a1);
13585 double a2 = log10(a1);
13587 float cscale = scale_factor * a2 * 0.3;
13589 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13590 dc.SetPen(*porange_pen);
13591 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13595 if (bDrawCurrentValues) {
13596 dc.SetFont(*pTCFont);
13597 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13598 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13624 if (!pvIDX)
return;
13629 if (pCwin && pCwin->IsShown()) {
13637 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13652 pCwin =
new TCWin(
this, x, y, pvIDX);
13670#define NUM_CURRENT_ARROW_POINTS 9
13671static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13672 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13673 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13674 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13676void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13678 if (
scale > 1e-2) {
13679 float sin_rot = sin(rot_angle * PI / 180.);
13680 float cos_rot = cos(rot_angle * PI / 180.);
13684 float xt = CurrentArrowArray[0].x;
13685 float yt = CurrentArrowArray[0].y;
13687 float xp = (xt * cos_rot) - (yt * sin_rot);
13688 float yp = (xt * sin_rot) + (yt * cos_rot);
13689 int x1 = (int)(xp *
scale);
13690 int y1 = (int)(yp *
scale);
13693 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13694 xt = CurrentArrowArray[ip].x;
13695 yt = CurrentArrowArray[ip].y;
13697 float xp = (xt * cos_rot) - (yt * sin_rot);
13698 float yp = (xt * sin_rot) + (yt * cos_rot);
13699 int x2 = (int)(xp *
scale);
13700 int y2 = (int)(yp *
scale);
13702 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13710wxString ChartCanvas::FindValidUploadPort() {
13713 if (!g_uploadConnection.IsEmpty() &&
13714 g_uploadConnection.StartsWith(
"Serial")) {
13715 port = g_uploadConnection;
13721 for (
auto *cp : TheConnectionParams()) {
13722 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13723 port <<
"Serial:" << cp->Port;
13729void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13732 if (NULL == g_pais_query_dialog_active) {
13733 int pos_x = g_ais_query_dialog_x;
13734 int pos_y = g_ais_query_dialog_y;
13736 if (g_pais_query_dialog_active) {
13737 g_pais_query_dialog_active->Destroy();
13743 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13744 wxPoint(pos_x, pos_y));
13746 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13747 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13748 g_pais_query_dialog_active->SetMMSI(mmsi);
13749 g_pais_query_dialog_active->UpdateText();
13750 wxSize sz = g_pais_query_dialog_active->GetSize();
13752 bool b_reset_pos =
false;
13757 RECT frame_title_rect;
13758 frame_title_rect.left = pos_x;
13759 frame_title_rect.top = pos_y;
13760 frame_title_rect.right = pos_x + sz.x;
13761 frame_title_rect.bottom = pos_y + 30;
13763 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13764 b_reset_pos =
true;
13769 wxRect window_title_rect;
13770 window_title_rect.x = pos_x;
13771 window_title_rect.y = pos_y;
13772 window_title_rect.width = sz.x;
13773 window_title_rect.height = 30;
13775 wxRect ClientRect = wxGetClientDisplayRect();
13776 ClientRect.Deflate(
13778 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13782 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13785 g_pais_query_dialog_active->SetMMSI(mmsi);
13786 g_pais_query_dialog_active->UpdateText();
13789 g_pais_query_dialog_active->Show();
13792void ChartCanvas::ToggleCanvasQuiltMode() {
13793 bool cur_mode = GetQuiltMode();
13795 if (!GetQuiltMode())
13796 SetQuiltMode(
true);
13797 else if (GetQuiltMode()) {
13798 SetQuiltMode(
false);
13799 g_sticky_chart = GetQuiltReferenceChartIndex();
13802 if (cur_mode != GetQuiltMode()) {
13803 SetupCanvasQuiltMode();
13812 if (ps52plib) ps52plib->GenerateStateHash();
13814 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13815 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13818void ChartCanvas::DoCanvasStackDelta(
int direction) {
13819 if (!GetQuiltMode()) {
13820 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13821 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13822 if ((current_stack_index + direction) < 0)
return;
13824 if (m_bpersistent_quilt ) {
13826 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13828 if (IsChartQuiltableRef(new_dbIndex)) {
13829 ToggleCanvasQuiltMode();
13830 SelectQuiltRefdbChart(new_dbIndex);
13831 m_bpersistent_quilt =
false;
13834 SelectChartFromStack(current_stack_index + direction);
13837 std::vector<int> piano_chart_index_array =
13838 GetQuiltExtendedStackdbIndexArray();
13839 int refdb = GetQuiltRefChartdbIndex();
13842 int current_index = -1;
13843 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13844 if (refdb == piano_chart_index_array[i]) {
13849 if (current_index == -1)
return;
13852 int target_family = ctet.GetChartFamily();
13854 int new_index = -1;
13855 int check_index = current_index + direction;
13856 bool found =
false;
13857 int check_dbIndex = -1;
13858 int new_dbIndex = -1;
13862 (
unsigned int)check_index < piano_chart_index_array.size() &&
13863 (check_index >= 0)) {
13864 check_dbIndex = piano_chart_index_array[check_index];
13866 if (target_family == cte.GetChartFamily()) {
13868 new_index = check_index;
13869 new_dbIndex = check_dbIndex;
13873 check_index += direction;
13876 if (!found)
return;
13878 if (!IsChartQuiltableRef(new_dbIndex)) {
13879 ToggleCanvasQuiltMode();
13880 SelectdbChart(new_dbIndex);
13881 m_bpersistent_quilt =
true;
13883 SelectQuiltRefChart(new_index);
13887 gFrame->UpdateGlobalMenuItems();
13889 SetQuiltChartHiLiteIndex(-1);
13900void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13903 switch (event.GetId()) {
13915 DoCanvasStackDelta(1);
13920 DoCanvasStackDelta(-1);
13930 ShowCurrents(!GetbShowCurrent());
13937 ShowTides(!GetbShowTide());
13944 if (0 == m_routeState) {
13951 androidSetRouteAnnunciator(m_routeState == 1);
13957 SetAISCanvasDisplayStyle(-1);
13969void ChartCanvas::SetShowAIS(
bool show) {
13971 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13972 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13975void ChartCanvas::SetAttenAIS(
bool show) {
13976 m_bShowAISScaled = show;
13977 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13978 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13981void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13984 bool bShowAIS_Array[3] = {
true,
true,
false};
13985 bool bShowScaled_Array[3] = {
false,
true,
true};
13986 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13987 _(
"Attenuate less critical AIS targets"),
13988 _(
"Hide AIS Targets")};
13989 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
13991 int AIS_Toolbar_Switch = 0;
13992 if (StyleIndx == -1) {
13994 for (
int i = 1; i < ArraySize; i++) {
13995 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13996 (bShowScaled_Array[i] == m_bShowAISScaled))
13997 AIS_Toolbar_Switch = i;
13999 AIS_Toolbar_Switch++;
14000 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14001 AIS_Toolbar_Switch++;
14004 AIS_Toolbar_Switch = StyleIndx;
14007 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14009 int AIS_Toolbar_Switch_Next =
14010 AIS_Toolbar_Switch + 1;
14011 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14012 AIS_Toolbar_Switch_Next++;
14013 if (AIS_Toolbar_Switch_Next >= ArraySize)
14014 AIS_Toolbar_Switch_Next = 0;
14017 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14018 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14021void ChartCanvas::TouchAISToolActive() {}
14023void ChartCanvas::UpdateAISTBTool() {}
14031void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14033 bool b_update =
false;
14034 int cc1_edge_comp = 2;
14035 wxRect rect = m_Compass->
GetRect();
14036 wxSize parent_size = GetSize();
14038 parent_size *= m_displayScale;
14042 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14043 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14044 wxRect compass_rect(compass_pt, rect.GetSize());
14046 m_Compass->Move(compass_pt);
14048 if (m_Compass && m_Compass->IsShown())
14049 m_Compass->UpdateStatus(b_force_new | b_update);
14051 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14052 scaler = wxMax(scaler, 1.0);
14053 wxPoint note_point = wxPoint(
14054 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14055 if (m_notification_button) {
14056 m_notification_button->Move(note_point);
14057 m_notification_button->UpdateStatus();
14060 if (b_force_new | b_update) Refresh();
14063void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14064 ChartTypeEnum New_Type,
14065 ChartFamilyEnum New_Family) {
14066 if (!GetpCurrentStack())
return;
14069 if (index < GetpCurrentStack()->nEntry) {
14072 pTentative_Chart =
ChartData->OpenStackChartConditional(
14073 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14075 if (pTentative_Chart) {
14076 if (m_singleChart) m_singleChart->Deactivate();
14078 m_singleChart = pTentative_Chart;
14079 m_singleChart->Activate();
14081 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14082 GetpCurrentStack(), m_singleChart->GetFullPath());
14095 double best_scale_ppm = GetBestVPScale(m_singleChart);
14096 double rotation = GetVPRotation();
14097 double oldskew = GetVPSkew();
14098 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14100 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14101 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14102 if (fabs(newskew) > 0.0001) rotation = newskew;
14105 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14107 UpdateGPSCompassStatusBox(
true);
14111 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14112 if (idx < 0)
return;
14114 std::vector<int> piano_active_chart_index_array;
14115 piano_active_chart_index_array.push_back(
14116 GetpCurrentStack()->GetCurrentEntrydbIndex());
14117 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14120void ChartCanvas::SelectdbChart(
int dbindex) {
14121 if (!GetpCurrentStack())
return;
14124 if (dbindex >= 0) {
14127 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14129 if (pTentative_Chart) {
14130 if (m_singleChart) m_singleChart->Deactivate();
14132 m_singleChart = pTentative_Chart;
14133 m_singleChart->Activate();
14135 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14136 GetpCurrentStack(), m_singleChart->GetFullPath());
14149 double best_scale_ppm = GetBestVPScale(m_singleChart);
14153 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14163void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14166 if (!GetQuiltMode()) {
14167 if (GetpCurrentStack()) {
14168 int stack_index = -1;
14169 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14170 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14171 if (check_dbIndex < 0)
continue;
14173 ChartData->GetChartTableEntry(check_dbIndex);
14174 if (type == cte.GetChartType()) {
14177 }
else if (family == cte.GetChartFamily()) {
14183 if (stack_index >= 0) {
14184 SelectChartFromStack(stack_index);
14188 int sel_dbIndex = -1;
14189 std::vector<int> piano_chart_index_array =
14190 GetQuiltExtendedStackdbIndexArray();
14191 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14192 int check_dbIndex = piano_chart_index_array[i];
14194 if (type == cte.GetChartType()) {
14195 if (IsChartQuiltableRef(check_dbIndex)) {
14196 sel_dbIndex = check_dbIndex;
14199 }
else if (family == cte.GetChartFamily()) {
14200 if (IsChartQuiltableRef(check_dbIndex)) {
14201 sel_dbIndex = check_dbIndex;
14207 if (sel_dbIndex >= 0) {
14208 SelectQuiltRefdbChart(sel_dbIndex,
false);
14210 AdjustQuiltRefChart();
14217 SetQuiltChartHiLiteIndex(-1);
14222bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14223 return std::find(m_tile_yesshow_index_array.begin(),
14224 m_tile_yesshow_index_array.end(),
14225 index) != m_tile_yesshow_index_array.end();
14228bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14229 return std::find(m_tile_noshow_index_array.begin(),
14230 m_tile_noshow_index_array.end(),
14231 index) != m_tile_noshow_index_array.end();
14234void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14235 if (std::find(m_tile_noshow_index_array.begin(),
14236 m_tile_noshow_index_array.end(),
14237 index) == m_tile_noshow_index_array.end()) {
14238 m_tile_noshow_index_array.push_back(index);
14248void ChartCanvas::HandlePianoClick(
14249 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14252 if (!m_pCurrentStack)
return;
14268 double distance = 25000;
14269 int closest_index = -1;
14270 for (
int chart_index : selected_dbIndex_array) {
14272 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14273 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14276 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14277 if (test_distance < distance) {
14278 distance = test_distance;
14279 closest_index = chart_index;
14283 int selected_dbIndex = selected_dbIndex_array[0];
14284 if (closest_index >= 0) selected_dbIndex = closest_index;
14286 if (!GetQuiltMode()) {
14287 if (m_bpersistent_quilt ) {
14288 if (IsChartQuiltableRef(selected_dbIndex)) {
14289 ToggleCanvasQuiltMode();
14290 SelectQuiltRefdbChart(selected_dbIndex);
14291 m_bpersistent_quilt =
false;
14293 SelectChartFromStack(selected_index);
14296 SelectChartFromStack(selected_index);
14297 g_sticky_chart = selected_dbIndex;
14301 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14305 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14306 bool bfound =
false;
14307 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14308 if (m_tile_noshow_index_array[i] ==
14309 selected_dbIndex) {
14310 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14317 m_tile_noshow_index_array.push_back(selected_dbIndex);
14321 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14322 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14326 if (IsChartQuiltableRef(selected_dbIndex)) {
14332 bool set_scale =
false;
14333 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14334 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14340 SelectQuiltRefdbChart(selected_dbIndex,
true);
14342 SelectQuiltRefdbChart(selected_dbIndex,
false);
14347 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14349 double proposed_scale_onscreen =
14352 if (g_bPreserveScaleOnX) {
14353 proposed_scale_onscreen =
14354 wxMin(proposed_scale_onscreen,
14356 GetCanvasWidth()));
14358 proposed_scale_onscreen =
14359 wxMin(proposed_scale_onscreen,
14361 GetCanvasWidth()));
14363 proposed_scale_onscreen =
14364 wxMax(proposed_scale_onscreen,
14373 ToggleCanvasQuiltMode();
14374 SelectdbChart(selected_dbIndex);
14375 m_bpersistent_quilt =
true;
14380 SetQuiltChartHiLiteIndex(-1);
14381 gFrame->UpdateGlobalMenuItems();
14383 HideChartInfoWindow();
14388void ChartCanvas::HandlePianoRClick(
14389 int x,
int y,
int selected_index,
14390 const std::vector<int> &selected_dbIndex_array) {
14393 if (!GetpCurrentStack())
return;
14395 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14396 UpdateCanvasControlBar();
14398 SetQuiltChartHiLiteIndex(-1);
14401void ChartCanvas::HandlePianoRollover(
14402 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14403 int n_charts,
int scale) {
14406 if (!GetpCurrentStack())
return;
14411 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14413 if (!GetQuiltMode()) {
14414 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14417 std::vector<int> piano_chart_index_array;
14418 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14419 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14420 if ((GetpCurrentStack()->nEntry > 1) ||
14421 (piano_chart_index_array.size() >= 1)) {
14422 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14424 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14426 }
else if (GetpCurrentStack()->nEntry == 1) {
14428 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14429 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14430 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14432 }
else if ((-1 == selected_index) &&
14433 (0 == selected_dbIndex_array.size())) {
14434 ShowChartInfoWindow(key_location.x, -1);
14438 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14440 if ((GetpCurrentStack()->nEntry > 1) ||
14441 (piano_chart_index_array.size() >= 1)) {
14443 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14444 selected_dbIndex_array);
14445 else if (n_charts == 1)
14446 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14448 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14455void ChartCanvas::ClearPianoRollover() {
14456 ClearQuiltChartHiLiteIndexArray();
14457 ShowChartInfoWindow(0, -1);
14458 std::vector<int> vec;
14459 ShowCompositeInfoWindow(0, 0, 0, vec);
14463void ChartCanvas::UpdateCanvasControlBar() {
14464 if (m_pianoFrozen)
return;
14466 if (!GetpCurrentStack())
return;
14468 if (!g_bShowChartBar)
return;
14471 int sel_family = -1;
14473 std::vector<int> piano_chart_index_array;
14474 std::vector<int> empty_piano_chart_index_array;
14476 wxString old_hash = m_Piano->GetStoredHash();
14478 if (GetQuiltMode()) {
14479 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14480 GetQuiltFullScreendbIndexArray());
14482 std::vector<int> piano_active_chart_index_array =
14483 GetQuiltCandidatedbIndexArray();
14484 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14486 std::vector<int> piano_eclipsed_chart_index_array =
14487 GetQuiltEclipsedStackdbIndexArray();
14488 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14490 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14491 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14493 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14494 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14496 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14497 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14500 if (m_singleChart) {
14501 sel_type = m_singleChart->GetChartType();
14502 sel_family = m_singleChart->GetChartFamily();
14507 std::vector<int> piano_skew_chart_index_array;
14508 std::vector<int> piano_tmerc_chart_index_array;
14509 std::vector<int> piano_poly_chart_index_array;
14511 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14513 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14514 double skew_norm = ctei.GetChartSkew();
14515 if (skew_norm > 180.) skew_norm -= 360.;
14517 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14518 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14521 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14522 if (fabs(skew_norm) > 1.)
14523 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14525 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14526 }
else if (fabs(skew_norm) > 1.)
14527 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14529 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14530 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14531 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14533 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14534 if (new_hash != old_hash) {
14535 m_Piano->FormatKeys();
14536 HideChartInfoWindow();
14537 m_Piano->ResetRollover();
14538 SetQuiltChartHiLiteIndex(-1);
14539 m_brepaint_piano =
true;
14545 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14547 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14548 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14549 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14550 if (e == CHART_FAMILY_RASTER) mask |= 1;
14551 if (e == CHART_FAMILY_VECTOR) {
14552 if (t == CHART_TYPE_CM93COMP)
14559 wxString s_indicated;
14560 if (sel_type == CHART_TYPE_CM93COMP)
14561 s_indicated =
"cm93";
14563 if (sel_family == CHART_FAMILY_RASTER)
14564 s_indicated =
"raster";
14565 else if (sel_family == CHART_FAMILY_VECTOR)
14566 s_indicated =
"vector";
14569 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14572void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14574void ChartCanvas::PianoPopupMenu(
14575 int x,
int y,
int selected_index,
14576 const std::vector<int> &selected_dbIndex_array) {
14577 if (!GetpCurrentStack())
return;
14580 if (!GetQuiltMode())
return;
14582 m_piano_ctx_menu =
new wxMenu();
14584 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14594 menu_selected_dbIndex = selected_dbIndex_array[0];
14595 menu_selected_index = selected_index;
14598 bool b_is_in_noshow =
false;
14599 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14600 if (m_quilt_noshow_index_array[i] ==
14601 menu_selected_dbIndex)
14603 b_is_in_noshow =
true;
14608 if (b_is_in_noshow) {
14609 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14610 _(
"Show This Chart"));
14611 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14612 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14613 }
else if (GetpCurrentStack()->nEntry > 1) {
14614 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14615 _(
"Hide This Chart"));
14616 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14617 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14621 wxPoint pos = wxPoint(x, y - 30);
14624 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14625 PopupMenu(m_piano_ctx_menu, pos);
14627 delete m_piano_ctx_menu;
14628 m_piano_ctx_menu = NULL;
14630 HideChartInfoWindow();
14631 m_Piano->ResetRollover();
14633 SetQuiltChartHiLiteIndex(-1);
14634 ClearQuiltChartHiLiteIndexArray();
14639void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14640 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14641 if (m_quilt_noshow_index_array[i] ==
14642 menu_selected_dbIndex)
14644 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14650void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14651 if (!GetpCurrentStack())
return;
14654 RemoveChartFromQuilt(menu_selected_dbIndex);
14658 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14659 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14661 int i = menu_selected_index + 1;
14662 bool b_success =
false;
14663 while (i < GetpCurrentStack()->nEntry - 1) {
14664 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14665 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14666 SelectQuiltRefChart(i);
14676 i = menu_selected_index - 1;
14678 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14679 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14680 SelectQuiltRefChart(i);
14690void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14692 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14693 if (m_quilt_noshow_index_array[i] ==
14696 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14701 m_quilt_noshow_index_array.push_back(dbIndex);
14704bool ChartCanvas::UpdateS52State() {
14705 bool retval =
false;
14708 ps52plib->SetShowS57Text(m_encShowText);
14709 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14710 ps52plib->m_bShowSoundg = m_encShowDepth;
14711 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14712 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14715 if (!m_encShowLights)
14716 ps52plib->AddObjNoshow(
"LIGHTS");
14718 ps52plib->RemoveObjNoshow(
"LIGHTS");
14719 ps52plib->SetLightsOff(!m_encShowLights);
14720 ps52plib->m_bExtendLightSectors =
true;
14723 ps52plib->SetAnchorOn(m_encShowAnchor);
14724 ps52plib->SetQualityOfData(m_encShowDataQual);
14730void ChartCanvas::SetShowENCDataQual(
bool show) {
14731 m_encShowDataQual = show;
14732 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14733 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14735 m_s52StateHash = 0;
14738void ChartCanvas::SetShowENCText(
bool show) {
14739 m_encShowText = show;
14740 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14741 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14743 m_s52StateHash = 0;
14746void ChartCanvas::SetENCDisplayCategory(
int category) {
14747 m_encDisplayCategory = category;
14748 m_s52StateHash = 0;
14751void ChartCanvas::SetShowENCDepth(
bool show) {
14752 m_encShowDepth = show;
14753 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14754 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14756 m_s52StateHash = 0;
14759void ChartCanvas::SetShowENCLightDesc(
bool show) {
14760 m_encShowLightDesc = show;
14761 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14762 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14764 m_s52StateHash = 0;
14767void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14768 m_encShowBuoyLabels = show;
14769 m_s52StateHash = 0;
14772void ChartCanvas::SetShowENCLights(
bool show) {
14773 m_encShowLights = show;
14774 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14775 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14777 m_s52StateHash = 0;
14780void ChartCanvas::SetShowENCAnchor(
bool show) {
14781 m_encShowAnchor = show;
14782 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14783 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14785 m_s52StateHash = 0;
14788wxRect ChartCanvas::GetMUIBarRect() {
14791 rv = m_muiBar->GetRect();
14797void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14798 if (!GetAlertString().IsEmpty()) {
14799 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14800 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14802 dc.SetFont(*pfont);
14803 dc.SetPen(*wxTRANSPARENT_PEN);
14805 dc.SetBrush(wxColour(243, 229, 47));
14807 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14811 wxRect sbr = GetScaleBarRect();
14812 int xp = sbr.x + sbr.width + 10;
14813 int yp = (sbr.y + sbr.height) - h;
14815 int wdraw = w + 10;
14816 dc.DrawRectangle(xp, yp, wdraw, h);
14817 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14818 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14828#define BRIGHT_XCALIB
14829#define __OPCPN_USEICC__
14832#ifdef __OPCPN_USEICC__
14833int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14834 double co_green,
double co_blue);
14836wxString temp_file_name;
14840class ocpnCurtain:
public wxDialog
14842 DECLARE_CLASS( ocpnCurtain )
14843 DECLARE_EVENT_TABLE()
14846 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14848 bool ProcessEvent(wxEvent& event);
14852IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14854BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14857ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14859 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14862ocpnCurtain::~ocpnCurtain()
14866bool ocpnCurtain::ProcessEvent(wxEvent& event)
14868 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14869 return GetParent()->GetEventHandler()->ProcessEvent(event);
14874#include <windows.h>
14877typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14878typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14879SetDeviceGammaRamp_ptr_type
14880 g_pSetDeviceGammaRamp;
14881GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14883WORD *g_pSavedGammaMap;
14887int InitScreenBrightness() {
14890 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14894 if (NULL == hGDI32DLL) {
14895 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14897 if (NULL != hGDI32DLL) {
14899 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14900 hGDI32DLL,
"SetDeviceGammaRamp");
14901 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14902 hGDI32DLL,
"GetDeviceGammaRamp");
14905 if ((NULL == g_pSetDeviceGammaRamp) ||
14906 (NULL == g_pGetDeviceGammaRamp)) {
14907 FreeLibrary(hGDI32DLL);
14916 if (!g_pSavedGammaMap) {
14917 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14920 bbr = g_pGetDeviceGammaRamp(
14921 hDC, g_pSavedGammaMap);
14922 ReleaseDC(NULL, hDC);
14927 wxRegKey *pRegKey =
new wxRegKey(
14928 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14929 "NT\\CurrentVersion\\ICM");
14930 if (!pRegKey->Exists()) pRegKey->Create();
14931 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14933 g_brightness_init =
true;
14939 if (NULL == g_pcurtain) {
14940 if (gFrame->CanSetTransparent()) {
14942 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14943 wxPoint(0, 0), ::wxGetDisplaySize(),
14944 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14945 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14952 g_pcurtain->Hide();
14954 HWND hWnd = GetHwndOf(g_pcurtain);
14955 SetWindowLong(hWnd, GWL_EXSTYLE,
14956 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14957 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14958 g_pcurtain->SetTransparent(0);
14960 g_pcurtain->Maximize();
14961 g_pcurtain->Show();
14964 g_pcurtain->Enable();
14965 g_pcurtain->Disable();
14972 g_brightness_init =
true;
14978 wxString cmd(
"xcalib -version");
14980 wxArrayString output;
14981 long r = wxExecute(cmd, output);
14984 " External application \"xcalib\" not found. Screen brightness "
14987 g_brightness_init =
true;
14992int RestoreScreenBrightness() {
14995 if (g_pSavedGammaMap) {
14996 HDC hDC = GetDC(NULL);
14997 g_pSetDeviceGammaRamp(hDC,
14999 ReleaseDC(NULL, hDC);
15001 free(g_pSavedGammaMap);
15002 g_pSavedGammaMap = NULL;
15006 g_pcurtain->Close();
15007 g_pcurtain->Destroy();
15011 g_brightness_init =
false;
15016#ifdef BRIGHT_XCALIB
15017 if (g_brightness_init) {
15019 cmd =
"xcalib -clear";
15020 wxExecute(cmd, wxEXEC_ASYNC);
15021 g_brightness_init =
false;
15031int SetScreenBrightness(
int brightness) {
15038 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15040 g_pcurtain->Close();
15041 g_pcurtain->Destroy();
15045 InitScreenBrightness();
15047 if (NULL == hGDI32DLL) {
15049 wchar_t wdll_name[80];
15050 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15051 LPCWSTR cstr = wdll_name;
15053 hGDI32DLL = LoadLibrary(cstr);
15055 if (NULL != hGDI32DLL) {
15057 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15058 hGDI32DLL,
"SetDeviceGammaRamp");
15059 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15060 hGDI32DLL,
"GetDeviceGammaRamp");
15063 if ((NULL == g_pSetDeviceGammaRamp) ||
15064 (NULL == g_pGetDeviceGammaRamp)) {
15065 FreeLibrary(hGDI32DLL);
15072 HDC hDC = GetDC(NULL);
15083 int increment = brightness * 256 / 100;
15086 WORD GammaTable[3][256];
15089 for (
int i = 0; i < 256; i++) {
15090 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15091 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15092 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15094 table_val += increment;
15096 if (table_val > 65535) table_val = 65535;
15099 g_pSetDeviceGammaRamp(hDC, GammaTable);
15100 ReleaseDC(NULL, hDC);
15107 if (g_pSavedGammaMap) {
15108 HDC hDC = GetDC(NULL);
15109 g_pSetDeviceGammaRamp(hDC,
15111 ReleaseDC(NULL, hDC);
15114 if (brightness < 100) {
15115 if (NULL == g_pcurtain) InitScreenBrightness();
15118 int sbrite = wxMax(1, brightness);
15119 sbrite = wxMin(100, sbrite);
15121 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15125 g_pcurtain->Close();
15126 g_pcurtain->Destroy();
15136#ifdef BRIGHT_XCALIB
15138 if (!g_brightness_init) {
15139 last_brightness = 100;
15140 g_brightness_init =
true;
15141 temp_file_name = wxFileName::CreateTempFileName(
"");
15142 InitScreenBrightness();
15145#ifdef __OPCPN_USEICC__
15148 if (!CreateSimpleICCProfileFile(
15149 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15150 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15151 wxString cmd(
"xcalib ");
15152 cmd += temp_file_name;
15154 wxExecute(cmd, wxEXEC_ASYNC);
15163 if (brightness > last_brightness) {
15165 cmd =
"xcalib -clear";
15166 wxExecute(cmd, wxEXEC_ASYNC);
15168 ::wxMilliSleep(10);
15170 int brite_adj = wxMax(1, brightness);
15171 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15172 wxExecute(cmd, wxEXEC_ASYNC);
15174 int brite_adj = wxMax(1, brightness);
15175 int factor = (brite_adj * 100) / last_brightness;
15176 factor = wxMax(1, factor);
15178 cmd.Printf(
"xcalib -co %2d -a", factor);
15179 wxExecute(cmd, wxEXEC_ASYNC);
15184 last_brightness = brightness;
15191#ifdef __OPCPN_USEICC__
15193#define MLUT_TAG 0x6d4c5554L
15194#define VCGT_TAG 0x76636774L
15196int GetIntEndian(
unsigned char *s) {
15201 p = (
unsigned char *)&ret;
15204 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15206 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15211unsigned short GetShortEndian(
unsigned char *s) {
15212 unsigned short ret;
15216 p = (
unsigned char *)&ret;
15219 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15221 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15227int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15228 double co_green,
double co_blue) {
15232 fp = fopen(file_name,
"wb");
15233 if (!fp)
return -1;
15239 for (
int i = 0; i < 128; i++) header[i] = 0;
15241 fwrite(header, 128, 1, fp);
15245 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15246 fwrite(&numTags, 1, 4, fp);
15248 int tagName0 = VCGT_TAG;
15249 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15250 fwrite(&tagName, 1, 4, fp);
15252 int tagOffset0 = 128 + 4 *
sizeof(int);
15253 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15254 fwrite(&tagOffset, 1, 4, fp);
15257 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15258 fwrite(&tagSize, 1, 4, fp);
15260 fwrite(&tagName, 1, 4, fp);
15262 fwrite(&tagName, 1, 4, fp);
15267 int gammatype0 = 0;
15268 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15269 fwrite(&gammatype, 1, 4, fp);
15271 int numChannels0 = 3;
15272 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15273 fwrite(&numChannels, 1, 2, fp);
15275 int numEntries0 = 256;
15276 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15277 fwrite(&numEntries, 1, 2, fp);
15279 int entrySize0 = 1;
15280 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15281 fwrite(&entrySize, 1, 2, fp);
15283 unsigned char ramp[256];
15286 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15287 fwrite(ramp, 256, 1, fp);
15290 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15291 fwrite(ramp, 256, 1, fp);
15294 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15295 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.