33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
39#include "o_sound/o_sound.h"
46#include "model/geodesic.h"
52#include "model/nav_object_database.h"
111#include "tide_time.h"
118#include "s57_ocpn_utils.h"
121#include "androidUTIL.h"
131#include <wx/msw/msvcrt.h>
140#define printf printf2
142int __cdecl printf2(
const char *format, ...) {
146 va_start(argptr, format);
147 int ret = vsnprintf(str,
sizeof(str), format, argptr);
149 OutputDebugStringA(str);
154#if defined(__MSVC__) && (_MSC_VER < 1700)
155#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
161#define OCPN_ALT_MENUBAR 1
169extern ColorScheme global_color_scheme;
170extern wxColor GetDimColor(wxColor c);
172static bool g_bSmoothRecenter =
true;
173static bool bDrawCurrentValues;
194static bool mouse_leftisdown;
195static bool g_brouteCreating;
196static int r_gamma_mult;
197static int g_gamma_mult;
198static int b_gamma_mult;
199static int gamma_state;
200static bool g_brightness_init;
201static int last_brightness;
202static wxGLContext *g_pGLcontext;
205static wxDialog *g_pcurtain;
207static wxString g_lastS52PLIBPluginMessage;
210#define MAX_BRIGHT 100
216EVT_PAINT(ChartCanvas::OnPaint)
217EVT_ACTIVATE(ChartCanvas::OnActivate)
218EVT_SIZE(ChartCanvas::OnSize)
219#ifndef HAVE_WX_GESTURE_EVENTS
220EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
222EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
223EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
224EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
225EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
226EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
227EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
228EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
229EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
230EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
231EVT_KEY_UP(ChartCanvas::OnKeyUp)
232EVT_CHAR(ChartCanvas::OnKeyChar)
233EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
234EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
235EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
236EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
237EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
238EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
239EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
240EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
241EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
242EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
248 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
249 m_nmea_log(nmea_log) {
250 parent_frame = (
MyFrame *)frame;
251 m_canvasIndex = canvasIndex;
255 SetBackgroundColour(wxColour(0, 0, 0));
256 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
260 m_bDrawingRoute =
false;
261 m_bRouteEditing =
false;
262 m_bMarkEditing =
false;
263 m_bRoutePoinDragging =
false;
264 m_bIsInRadius =
false;
265 m_bMayToggleMenuBar =
true;
268 m_bShowNavobjects =
true;
270 m_bAppendingRoute =
false;
271 pThumbDIBShow = NULL;
272 m_bShowCurrent =
false;
274 bShowingCurrent =
false;
278 m_b_paint_enable =
true;
281 pss_overlay_bmp = NULL;
282 pss_overlay_mask = NULL;
283 m_bChartDragging =
false;
284 m_bMeasure_Active =
false;
285 m_bMeasure_DistCircle =
false;
286 m_pMeasureRoute = NULL;
287 m_pTrackRolloverWin = NULL;
288 m_pRouteRolloverWin = NULL;
289 m_pAISRolloverWin = NULL;
291 m_disable_edge_pan =
false;
292 m_dragoffsetSet =
false;
296 m_singleChart = NULL;
297 m_upMode = NORTH_UP_MODE;
299 m_bShowAISScaled =
false;
300 m_timed_move_vp_active =
false;
302 m_disable_adjust_on_zoom =
false;
309 m_pSelectedRoute = NULL;
310 m_pSelectedTrack = NULL;
311 m_pRoutePointEditTarget = NULL;
312 m_pFoundPoint = NULL;
313 m_pMouseRoute = NULL;
314 m_prev_pMousePoint = NULL;
315 m_pEditRouteArray = NULL;
316 m_pFoundRoutePoint = NULL;
317 m_FinishRouteOnKillFocus =
true;
319 m_pRolloverRouteSeg = NULL;
320 m_pRolloverTrackSeg = NULL;
321 m_bsectors_shown =
false;
323 m_bbrightdir =
false;
328 m_pos_image_user_day = NULL;
329 m_pos_image_user_dusk = NULL;
330 m_pos_image_user_night = NULL;
331 m_pos_image_user_grey_day = NULL;
332 m_pos_image_user_grey_dusk = NULL;
333 m_pos_image_user_grey_night = NULL;
336 m_rotation_speed = 0;
342 m_pos_image_user_yellow_day = NULL;
343 m_pos_image_user_yellow_dusk = NULL;
344 m_pos_image_user_yellow_night = NULL;
346 SetOwnShipState(SHIP_INVALID);
348 undo =
new Undo(
this);
354 m_focus_indicator_pix = 1;
356 m_pCurrentStack = NULL;
357 m_bpersistent_quilt =
false;
358 m_piano_ctx_menu = NULL;
360 m_NotificationsList = NULL;
361 m_notification_button = NULL;
363 g_ChartNotRenderScaleFactor = 2.0;
364 m_bShowScaleInStatusBar =
true;
367 m_bShowScaleInStatusBar =
false;
368 m_show_focus_bar =
true;
370 m_bShowOutlines =
false;
371 m_bDisplayGrid =
false;
372 m_bShowDepthUnits =
true;
373 m_encDisplayCategory = (int)STANDARD;
375 m_encShowLights =
true;
376 m_encShowAnchor =
true;
377 m_encShowDataQual =
false;
379 m_pQuilt =
new Quilt(
this);
384 g_PrintingInProgress =
false;
386#ifdef HAVE_WX_GESTURE_EVENTS
387 m_oldVPSScale = -1.0;
388 m_popupWanted =
false;
391 m_inLongPress =
false;
394 m_sw_left_down.Start();
395 m_sw_left_up.Start();
399 singleClickEventIsValid =
false;
408 pCursorPencil = NULL;
413 SetCursor(*pCursorArrow);
415 pPanTimer =
new wxTimer(
this, m_MouseDragging);
418 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
419 pMovementTimer->Stop();
421 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
422 pMovementStopTimer->Stop();
424 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
425 pRotDefTimer->Stop();
427 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
428 m_DoubleClickTimer->Stop();
430 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
431 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
432 m_chart_drag_inertia_active =
false;
434 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
435 m_animationActive =
false;
436 m_menuTimer.SetOwner(
this, MENU_TIMER);
437 m_tap_timer.SetOwner(
this, TAP_TIMER);
441 m_panx_target_final = m_pany_target_final = 0;
442 m_panx_target_now = m_pany_target_now = 0;
444 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
445 pCurTrackTimer->Stop();
446 m_curtrack_timer_msec = 10;
448 m_wheelzoom_stop_oneshot = 0;
449 m_last_wheel_dir = 0;
451 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
453 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
455 m_rollover_popup_timer_msec = 20;
457 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
459 m_b_rot_hidef =
true;
464 m_upMode = NORTH_UP_MODE;
465 m_bLookAhead =
false;
469 m_cs = GLOBAL_COLOR_SCHEME_DAY;
472 VPoint.view_scale_ppm = 1;
476 m_canvas_scale_factor = 1.;
478 m_canvas_width = 1000;
480 m_overzoomTextWidth = 0;
481 m_overzoomTextHeight = 0;
490 m_pEM_Fathoms = NULL;
492 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
494 m_pEM_OverZoom = NULL;
496 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
504 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
507 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
510 double factor_dusk = 0.5;
511 double factor_night = 0.25;
514 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
516 int rimg_width = m_os_image_red_day.GetWidth();
517 int rimg_height = m_os_image_red_day.GetHeight();
519 m_os_image_red_dusk = m_os_image_red_day.Copy();
520 m_os_image_red_night = m_os_image_red_day.Copy();
522 for (
int iy = 0; iy < rimg_height; iy++) {
523 for (
int ix = 0; ix < rimg_width; ix++) {
524 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
525 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
526 m_os_image_red_day.GetGreen(ix, iy),
527 m_os_image_red_day.GetBlue(ix, iy));
528 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
529 hsv.value = hsv.value * factor_dusk;
530 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
531 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
533 hsv = wxImage::RGBtoHSV(rgb);
534 hsv.value = hsv.value * factor_night;
535 nrgb = wxImage::HSVtoRGB(hsv);
536 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
542 m_os_image_grey_day =
543 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
545 int gimg_width = m_os_image_grey_day.GetWidth();
546 int gimg_height = m_os_image_grey_day.GetHeight();
548 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
549 m_os_image_grey_night = m_os_image_grey_day.Copy();
551 for (
int iy = 0; iy < gimg_height; iy++) {
552 for (
int ix = 0; ix < gimg_width; ix++) {
553 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
554 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
555 m_os_image_grey_day.GetGreen(ix, iy),
556 m_os_image_grey_day.GetBlue(ix, iy));
557 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
558 hsv.value = hsv.value * factor_dusk;
559 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
560 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
562 hsv = wxImage::RGBtoHSV(rgb);
563 hsv.value = hsv.value * factor_night;
564 nrgb = wxImage::HSVtoRGB(hsv);
565 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
571 m_os_image_yellow_day = m_os_image_red_day.Copy();
573 gimg_width = m_os_image_yellow_day.GetWidth();
574 gimg_height = m_os_image_yellow_day.GetHeight();
576 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
577 m_os_image_yellow_night = m_os_image_red_day.Copy();
579 for (
int iy = 0; iy < gimg_height; iy++) {
580 for (
int ix = 0; ix < gimg_width; ix++) {
581 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
582 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
583 m_os_image_yellow_day.GetGreen(ix, iy),
584 m_os_image_yellow_day.GetBlue(ix, iy));
585 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
586 hsv.hue += 60. / 360.;
587 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
588 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
590 hsv = wxImage::RGBtoHSV(rgb);
591 hsv.value = hsv.value * factor_dusk;
592 hsv.hue += 60. / 360.;
593 nrgb = wxImage::HSVtoRGB(hsv);
594 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
596 hsv = wxImage::RGBtoHSV(rgb);
597 hsv.hue += 60. / 360.;
598 hsv.value = hsv.value * factor_night;
599 nrgb = wxImage::HSVtoRGB(hsv);
600 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
606 m_pos_image_red = &m_os_image_red_day;
607 m_pos_image_yellow = &m_os_image_yellow_day;
608 m_pos_image_grey = &m_os_image_grey_day;
612 m_pBrightPopup = NULL;
615 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
620 m_Piano =
new Piano(
this);
622 m_bShowCompassWin =
true;
624 m_Compass->SetScaleFactor(g_compass_scalefactor);
625 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
628 m_notification_button->SetScaleFactor(g_compass_scalefactor);
629 m_notification_button->Show(
true);
631 m_pianoFrozen =
false;
633 SetMinSize(wxSize(200, 200));
635 m_displayScale = 1.0;
636#if defined(__WXOSX__) || defined(__WXGTK3__)
638 m_displayScale = GetContentScaleFactor();
640 VPoint.SetPixelScale(m_displayScale);
642#ifdef HAVE_WX_GESTURE_EVENTS
645 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
646 wxLogError(
"Failed to enable touch events");
651 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
652 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
654 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
655 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
657 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
658 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
660 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
661 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
666 auto ¬eman = NotificationManager::GetInstance();
668 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
669 evt_notificationlist_change_listener.Listen(
670 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
671 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
672 if (m_NotificationsList && m_NotificationsList->IsShown()) {
673 m_NotificationsList->ReloadNotificationList();
679ChartCanvas::~ChartCanvas() {
680 delete pThumbDIBShow;
688 delete pCursorPencil;
692 delete pMovementTimer;
693 delete pMovementStopTimer;
694 delete pCurTrackTimer;
696 delete m_DoubleClickTimer;
698 delete m_pTrackRolloverWin;
699 delete m_pRouteRolloverWin;
700 delete m_pAISRolloverWin;
701 delete m_pBrightPopup;
707 m_dc_route.SelectObject(wxNullBitmap);
710 delete pWorldBackgroundChart;
711 delete pss_overlay_bmp;
715 delete m_pEM_Fathoms;
717 delete m_pEM_OverZoom;
722 delete m_pos_image_user_day;
723 delete m_pos_image_user_dusk;
724 delete m_pos_image_user_night;
725 delete m_pos_image_user_grey_day;
726 delete m_pos_image_user_grey_dusk;
727 delete m_pos_image_user_grey_night;
728 delete m_pos_image_user_yellow_day;
729 delete m_pos_image_user_yellow_dusk;
730 delete m_pos_image_user_yellow_night;
734 if (!g_bdisable_opengl) {
737#if wxCHECK_VERSION(2, 9, 0)
738 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
745 MUIBar *muiBar = m_muiBar;
749 delete m_pCurrentStack;
754void ChartCanvas::SetupGridFont() {
755 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
757 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
759 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
760 FALSE, wxString(
"Arial"));
763void ChartCanvas::RebuildCursors() {
769 delete pCursorPencil;
773 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
777 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
778 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
779 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
780 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
781 wxImage ICursorPencil =
782 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
783 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
785#if !defined(__WXMSW__) && !defined(__WXQT__)
786 ICursorLeft.ConvertAlphaToMask(128);
787 ICursorRight.ConvertAlphaToMask(128);
788 ICursorUp.ConvertAlphaToMask(128);
789 ICursorDown.ConvertAlphaToMask(128);
790 ICursorPencil.ConvertAlphaToMask(10);
791 ICursorCross.ConvertAlphaToMask(10);
794 if (ICursorLeft.Ok()) {
795 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
796 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
797 pCursorLeft =
new wxCursor(ICursorLeft);
799 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
801 if (ICursorRight.Ok()) {
802 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
803 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
804 pCursorRight =
new wxCursor(ICursorRight);
806 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
808 if (ICursorUp.Ok()) {
809 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
810 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
811 pCursorUp =
new wxCursor(ICursorUp);
813 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
815 if (ICursorDown.Ok()) {
816 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
817 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
818 pCursorDown =
new wxCursor(ICursorDown);
820 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
822 if (ICursorPencil.Ok()) {
823 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
824 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
825 pCursorPencil =
new wxCursor(ICursorPencil);
827 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
829 if (ICursorCross.Ok()) {
830 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
831 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
832 pCursorCross =
new wxCursor(ICursorCross);
834 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
836 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
837 pPlugIn_Cursor = NULL;
840void ChartCanvas::CanvasApplyLocale() {
841 CreateDepthUnitEmbossMaps(m_cs);
842 CreateOZEmbossMapData(m_cs);
845void ChartCanvas::SetupGlCanvas() {
848 if (!g_bdisable_opengl) {
850 wxLogMessage(
"Creating glChartCanvas");
855 if (IsPrimaryCanvas()) {
862 wxGLContext *pctx =
new wxGLContext(m_glcc);
863 m_glcc->SetContext(pctx);
867 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
869 m_glcc->SetContext(g_pGLcontext);
879 if (!g_bdisable_opengl) {
882 wxLogMessage(
"Creating glChartCanvas");
886 if (IsPrimaryCanvas()) {
887 qDebug() <<
"Creating Primary glChartCanvas";
895 wxGLContext *pctx =
new wxGLContext(m_glcc);
896 m_glcc->SetContext(pctx);
898 m_glcc->m_pParentCanvas =
this;
901 qDebug() <<
"Creating Secondary glChartCanvas";
907 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
910 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
911 m_glcc->SetContext(pwxctx);
912 m_glcc->m_pParentCanvas =
this;
920void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
921 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
936 if (m_routeState && m_FinishRouteOnKillFocus)
937 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
939 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
943void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
944 m_routeFinishTimer.Stop();
948 gFrame->UpdateGlobalMenuItems(
this);
950 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
953void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
954 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
957#ifdef HAVE_WX_GESTURE_EVENTS
958void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
965 m_popupWanted =
true;
967 m_inLongPress = !g_bhide_context_menus;
970 m_menuPos =
event.GetPosition();
971 wxMouseEvent ev(wxEVT_LEFT_UP);
972 ev.m_x = m_menuPos.x;
973 ev.m_y = m_menuPos.y;
974 wxPostEvent(
this, ev);
977 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
978 ev_right_click.m_x = m_menuPos.x;
979 ev_right_click.m_y = m_menuPos.y;
980 MouseEvent(ev_right_click);
986void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
990void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
992void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
994void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
996 long dt = m_sw_left_up.Time() - m_sw_up_time;
997 m_sw_up_time = m_sw_left_up.Time();
1008 wxPoint pos =
event.GetPosition();
1012 if (!m_popupWanted) {
1013 wxMouseEvent ev(wxEVT_LEFT_UP);
1020 m_popupWanted =
false;
1022 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1029void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1034 long dt = m_sw_left_down.Time() - m_sw_down_time;
1035 m_sw_down_time = m_sw_left_down.Time();
1050 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1052 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1053 m_lastTapPos.y - max_double_click_distance,
1054 max_double_click_distance * 2, max_double_click_distance * 2);
1057 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1063 m_lastTapPos =
event.GetPosition();
1064 m_tap_timer.StartOnce(
1068 if (m_tap_count == 2) {
1072 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1085void ChartCanvas::OnMotion(wxMouseEvent &event) {
1090 event.m_leftDown = m_leftdown;
1094void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1096 if (event.IsGestureEnd())
return;
1098 double factor =
event.GetZoomFactor();
1100 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1105 double wanted_factor = m_oldVPSScale / current_vps * factor;
1110 if (event.IsGestureStart()) {
1111 m_zoomStartPoint =
event.GetPosition();
1113 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1115 m_zoomStartPoint =
event.GetPosition();
1119void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1121void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1122 DoRotateCanvas(0.0);
1126void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1131void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1132 m_FinishRouteOnKillFocus =
false;
1133 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1134 m_FinishRouteOnKillFocus =
true;
1137void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1142 m_restore_dbindex = pcc->DBindex;
1144 if (pcc->GroupID < 0) pcc->GroupID = 0;
1149 m_groupIndex = pcc->GroupID;
1151 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1165 m_encDisplayCategory = pcc->nENCDisplayCategory;
1166 m_encShowDepth = pcc->bShowENCDepths;
1167 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1168 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1169 m_encShowLights = pcc->bShowENCLights;
1170 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1171 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1172 m_encShowDataQual = pcc->bShowENCDataQuality;
1176 m_upMode = NORTH_UP_MODE;
1178 m_upMode = COURSE_UP_MODE;
1180 m_upMode = HEAD_UP_MODE;
1184 m_singleChart = NULL;
1187void ChartCanvas::ApplyGlobalSettings() {
1190 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1191 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1193 m_notification_button->UpdateStatus();
1196void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1197 bool groupOK = CheckGroup(m_groupIndex);
1200 SetGroupIndex(m_groupIndex,
true);
1204void ChartCanvas::SetShowGPS(
bool bshow) {
1205 if (m_bShowGPS != bshow) {
1208 m_Compass->SetScaleFactor(g_compass_scalefactor);
1209 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1214void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1215 m_bShowCompassWin = bshow;
1217 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1218 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1222int ChartCanvas::GetPianoHeight() {
1224 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1229void ChartCanvas::ConfigureChartBar() {
1232 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1233 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1235 if (GetQuiltMode()) {
1236 m_Piano->SetRoundedRectangles(
true);
1238 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1239 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1240 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1243void ChartCanvas::ShowTides(
bool bShow) {
1244 gFrame->LoadHarmonics();
1247 SetbShowTide(bShow);
1249 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1251 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1252 SetbShowTide(
false);
1253 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1256 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1257 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1268void ChartCanvas::ShowCurrents(
bool bShow) {
1269 gFrame->LoadHarmonics();
1272 SetbShowCurrent(bShow);
1273 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1275 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1276 SetbShowCurrent(
false);
1277 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1280 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1281 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1298void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1300void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1303 int new_index = index;
1306 bool bgroup_override =
false;
1307 int old_group_index = new_index;
1309 if (!CheckGroup(new_index)) {
1311 bgroup_override =
true;
1314 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1318 int current_chart_native_scale = GetCanvasChartNativeScale();
1321 m_groupIndex = new_index;
1327 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1331 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1335 g_sticky_chart = -1;
1339 UpdateCanvasOnGroupChange();
1342 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1344 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1347 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1348 double best_scale = GetBestStartScale(dbi_hint, vp);
1352 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1356 canvasChartsRefresh(dbi_hint);
1358 UpdateCanvasControlBar();
1360 if (!autoSwitch && bgroup_override) {
1362 wxString msg(_(
"Group \""));
1365 msg += pGroup->m_group_name;
1367 msg += _(
"\" is empty.");
1369 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1376 if (bgroup_override) {
1377 wxString msg(_(
"Group \""));
1380 msg += pGroup->m_group_name;
1382 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1384 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1388bool ChartCanvas::CheckGroup(
int igroup) {
1391 if (igroup == 0)
return true;
1398 if (pGroup->m_element_array.empty())
1402 for (
const auto &elem : pGroup->m_element_array) {
1403 for (
unsigned int ic = 0;
1404 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1406 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1408 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1413 for (
const auto &elem : pGroup->m_element_array) {
1414 const wxString &element_root = elem.m_element_name;
1415 wxString test_string =
"GSHH";
1416 if (element_root.Upper().Contains(test_string))
return true;
1422void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1425 AbstractPlatform::ShowBusySpinner();
1429 SetQuiltRefChart(-1);
1431 m_singleChart = NULL;
1437 if (!m_pCurrentStack) {
1439 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1442 if (-1 != dbi_hint) {
1443 if (GetQuiltMode()) {
1444 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1445 SetQuiltRefChart(dbi_hint);
1449 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1451 if (pTentative_Chart) {
1454 if (m_singleChart) m_singleChart->Deactivate();
1456 m_singleChart = pTentative_Chart;
1457 m_singleChart->Activate();
1459 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1460 GetpCurrentStack(), m_singleChart->GetFullPath());
1468 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1469 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1470 SetQuiltRefChart(selected_index);
1474 SetupCanvasQuiltMode();
1475 if (!GetQuiltMode() && m_singleChart == 0) {
1477 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1478 m_singleChart = pDummyChart;
1484 UpdateCanvasControlBar();
1485 UpdateGPSCompassStatusBox(
true);
1487 SetCursor(wxCURSOR_ARROW);
1489 AbstractPlatform::HideBusySpinner();
1492bool ChartCanvas::DoCanvasUpdate() {
1494 double vpLat, vpLon;
1495 bool blong_jump =
false;
1496 meters_to_shift = 0;
1499 bool bNewChart =
false;
1500 bool bNewView =
false;
1501 bool bCanvasChartAutoOpen =
true;
1503 bool bNewPiano =
false;
1504 bool bOpenSpecified;
1510 if (bDBUpdateInProgress)
return false;
1514 if (m_chart_drag_inertia_active)
return false;
1540 double dx = m_OSoffsetx;
1541 double dy = m_OSoffsety;
1545 if (GetUpMode() == NORTH_UP_MODE) {
1546 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1548 double offset_angle = atan2(d_north, d_east);
1549 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1550 double chart_angle = GetVPRotation();
1551 double target_angle = chart_angle + offset_angle;
1552 double d_east_mod = offset_distance * cos(target_angle);
1553 double d_north_mod = offset_distance * sin(target_angle);
1554 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1558 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1559 double cog_to_use =
gCog;
1561 (fabs(
gCog - gCog_gt) > 20)) {
1562 cog_to_use = gCog_gt;
1565 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1567 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1569 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1570 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1572 double pixel_delta_tent =
1573 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1575 double pixel_delta = 0;
1580 if (!std::isnan(
gSog)) {
1584 pixel_delta = pixel_delta_tent;
1587 meters_to_shift = 0;
1589 if (!std::isnan(
gCog)) {
1590 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1591 dir_to_shift = cog_to_use;
1592 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1598 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1612 if (GetQuiltMode()) {
1613 int current_db_index = -1;
1614 if (m_pCurrentStack)
1617 ->GetCurrentEntrydbIndex();
1625 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1627 if (m_pCurrentStack->nEntry) {
1628 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1630 SelectQuiltRefdbChart(new_dbIndex,
true);
1631 m_bautofind =
false;
1635 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1636 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1641 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1647 double proposed_scale_onscreen =
1650 int initial_db_index = m_restore_dbindex;
1651 if (initial_db_index < 0) {
1652 if (m_pCurrentStack->nEntry) {
1654 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1659 if (m_pCurrentStack->nEntry) {
1660 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1665 if (!IsChartQuiltableRef(initial_db_index)) {
1669 int stack_index = 0;
1671 if (stack_index >= 0) {
1672 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1673 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1674 if (IsChartQuiltableRef(test_db_index) &&
1676 ChartData->GetDBChartType(initial_db_index))) {
1677 initial_db_index = test_db_index;
1687 SetQuiltRefChart(initial_db_index);
1688 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1696 0, GetVPRotation());
1701 bool super_jump =
false;
1703 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1704 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1705 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1708 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1710 if (blong_jump) nstep = 20;
1711 StartTimedMovementVP(vpLat, vpLon, nstep);
1722 pLast_Ch = m_singleChart;
1723 ChartTypeEnum new_open_type;
1724 ChartFamilyEnum new_open_family;
1726 new_open_type = pLast_Ch->GetChartType();
1727 new_open_family = pLast_Ch->GetChartFamily();
1729 new_open_type = CHART_TYPE_KAP;
1730 new_open_family = CHART_FAMILY_RASTER;
1733 bOpenSpecified = m_bFirstAuto;
1736 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1739 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1741 if (NULL == pDummyChart) {
1747 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1749 m_singleChart = pDummyChart;
1754 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1756 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1759 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1760 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1767 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1773 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1778 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1781 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1786 if (NULL != m_singleChart)
1787 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1788 m_singleChart->GetFullPath());
1791 m_pCurrentStack->CurrentStackEntry = tEntry;
1801 if (bCanvasChartAutoOpen) {
1802 bool search_direction =
1804 int start_index = 0;
1808 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1809 (LastStack.nEntry == 0)) {
1810 search_direction =
true;
1811 start_index = m_pCurrentStack->nEntry - 1;
1815 if (bOpenSpecified) {
1816 search_direction =
false;
1818 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1821 new_open_type = CHART_TYPE_DONTCARE;
1824 pProposed =
ChartData->OpenStackChartConditional(
1825 m_pCurrentStack, start_index, search_direction, new_open_type,
1829 if (NULL == pProposed)
1830 pProposed =
ChartData->OpenStackChartConditional(
1831 m_pCurrentStack, start_index, search_direction,
1832 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1834 if (NULL == pProposed)
1835 pProposed =
ChartData->OpenStackChartConditional(
1836 m_pCurrentStack, start_index, search_direction,
1837 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1848 if (NULL == pProposed) {
1849 if (NULL == pDummyChart) {
1855 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1857 pProposed = pDummyChart;
1861 if (m_singleChart) m_singleChart->Deactivate();
1862 m_singleChart = pProposed;
1864 if (m_singleChart) {
1865 m_singleChart->Activate();
1866 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1867 m_pCurrentStack, m_singleChart->GetFullPath());
1872 if (NULL != m_singleChart) {
1878 if (!GetVP().IsValid())
1879 set_scale = 1. / 20000.;
1881 double proposed_scale_onscreen;
1884 double new_scale_ppm =
1885 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1893 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1894 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1895 double equivalent_vp_scale =
1897 double new_scale_ppm =
1898 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1903 proposed_scale_onscreen =
1904 wxMin(proposed_scale_onscreen,
1907 proposed_scale_onscreen =
1908 wxMax(proposed_scale_onscreen,
1917 m_singleChart->GetChartSkew() * PI / 180.,
1924 if ((m_bFollow) && m_singleChart)
1926 m_singleChart->GetChartSkew() * PI / 180.,
1935 m_bFirstAuto =
false;
1939 if (bNewChart && !bNewView) Refresh(
false);
1944 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1947 return bNewChart | bNewView;
1950void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1951 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1953 SetQuiltRefChart(db_index);
1958 double best_scale_ppm = GetBestVPScale(pc);
1962 SetQuiltRefChart(-1);
1964 SetQuiltRefChart(-1);
1967void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1968 std::vector<int> piano_chart_index_array =
1969 GetQuiltExtendedStackdbIndexArray();
1970 int current_db_index = piano_chart_index_array[selected_index];
1972 SelectQuiltRefdbChart(current_db_index);
1975double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1979 if ((g_bPreserveScaleOnX) ||
1980 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
1986 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
1987 double equivalent_vp_scale =
1989 double new_scale_ppm =
1990 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1997 double max_underzoom_multiplier = 2.0;
1998 if (GetVP().b_quilt) {
1999 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2000 pchart->GetChartType(),
2001 pchart->GetChartFamily());
2002 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2005 proposed_scale_onscreen = wxMin(
2006 proposed_scale_onscreen,
2008 max_underzoom_multiplier);
2011 proposed_scale_onscreen =
2012 wxMax(proposed_scale_onscreen,
2020void ChartCanvas::SetupCanvasQuiltMode() {
2025 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2029 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2030 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2031 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2032 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2034 m_Piano->SetRoundedRectangles(
true);
2037 int target_new_dbindex = -1;
2038 if (m_pCurrentStack) {
2039 target_new_dbindex =
2040 GetQuiltReferenceChartIndex();
2042 if (-1 != target_new_dbindex) {
2043 if (!IsChartQuiltableRef(target_new_dbindex)) {
2044 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2045 int type =
ChartData->GetDBChartType(target_new_dbindex);
2048 int stack_index = m_pCurrentStack->CurrentStackEntry;
2050 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2051 (stack_index >= 0)) {
2052 int proj_tent =
ChartData->GetDBChartProj(
2053 m_pCurrentStack->GetDBIndex(stack_index));
2054 int type_tent =
ChartData->GetDBChartType(
2055 m_pCurrentStack->GetDBIndex(stack_index));
2057 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2058 if ((proj == proj_tent) && (type_tent == type)) {
2059 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2069 if (IsChartQuiltableRef(target_new_dbindex))
2070 SelectQuiltRefdbChart(target_new_dbindex,
2073 SelectQuiltRefdbChart(-1,
false);
2075 m_singleChart = NULL;
2078 AdjustQuiltRefChart();
2086 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2090 std::vector<int> empty_array;
2091 m_Piano->SetActiveKeyArray(empty_array);
2092 m_Piano->SetNoshowIndexArray(empty_array);
2093 m_Piano->SetEclipsedIndexArray(empty_array);
2096 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2097 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2098 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2099 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2101 m_Piano->SetRoundedRectangles(
false);
2107 if (!GetQuiltMode()) {
2112 if (m_bFollow ==
true) {
2120 if (!m_singleChart) {
2123 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2131 int cur_max_scale = (int)1e8;
2133 ChartBase *pChart = GetFirstQuiltChart();
2137 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2139 if (pChart->GetNativeScale() < cur_max_scale) {
2140 Candidate_Chart = pChart;
2141 cur_max_scale = pChart->GetNativeScale();
2144 pChart = GetNextQuiltChart();
2147 m_singleChart = Candidate_Chart;
2151 if (NULL == m_singleChart) {
2152 m_singleChart =
ChartData->OpenStackChartConditional(
2153 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2154 CHART_FAMILY_DONTCARE);
2160 InvalidateAllQuiltPatchs();
2162 if (m_singleChart) {
2163 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2164 std::vector<int> one_array;
2165 one_array.push_back(dbi);
2166 m_Piano->SetActiveKeyArray(one_array);
2169 if (m_singleChart) {
2170 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2174 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2178bool ChartCanvas::IsTempMenuBarEnabled() {
2181 wxGetOsVersion(&major);
2189double ChartCanvas::GetCanvasRangeMeters() {
2191 GetSize(&width, &height);
2192 int minDimension = wxMin(width, height);
2195 range *= cos(GetVP().clat * PI / 180.);
2199void ChartCanvas::SetCanvasRangeMeters(
double range) {
2201 GetSize(&width, &height);
2202 int minDimension = wxMin(width, height);
2204 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2208bool ChartCanvas::SetUserOwnship() {
2212 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2213 double factor_dusk = 0.5;
2214 double factor_night = 0.25;
2216 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2217 m_pos_image_user_day =
new wxImage;
2218 *m_pos_image_user_day = pbmp->ConvertToImage();
2219 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2221 int gimg_width = m_pos_image_user_day->GetWidth();
2222 int gimg_height = m_pos_image_user_day->GetHeight();
2225 m_pos_image_user_dusk =
new wxImage;
2226 m_pos_image_user_night =
new wxImage;
2228 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2229 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2231 for (
int iy = 0; iy < gimg_height; iy++) {
2232 for (
int ix = 0; ix < gimg_width; ix++) {
2233 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2234 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2235 m_pos_image_user_day->GetGreen(ix, iy),
2236 m_pos_image_user_day->GetBlue(ix, iy));
2237 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2238 hsv.value = hsv.value * factor_dusk;
2239 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2240 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2243 hsv = wxImage::RGBtoHSV(rgb);
2244 hsv.value = hsv.value * factor_night;
2245 nrgb = wxImage::HSVtoRGB(hsv);
2246 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2253 m_pos_image_user_grey_day =
new wxImage;
2254 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2256 m_pos_image_user_grey_dusk =
new wxImage;
2257 m_pos_image_user_grey_night =
new wxImage;
2259 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2260 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2262 for (
int iy = 0; iy < gimg_height; iy++) {
2263 for (
int ix = 0; ix < gimg_width; ix++) {
2264 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2265 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2266 m_pos_image_user_grey_day->GetGreen(ix, iy),
2267 m_pos_image_user_grey_day->GetBlue(ix, iy));
2268 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2269 hsv.value = hsv.value * factor_dusk;
2270 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2271 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2274 hsv = wxImage::RGBtoHSV(rgb);
2275 hsv.value = hsv.value * factor_night;
2276 nrgb = wxImage::HSVtoRGB(hsv);
2277 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2284 m_pos_image_user_yellow_day =
new wxImage;
2285 m_pos_image_user_yellow_dusk =
new wxImage;
2286 m_pos_image_user_yellow_night =
new wxImage;
2288 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2289 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2290 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2292 for (
int iy = 0; iy < gimg_height; iy++) {
2293 for (
int ix = 0; ix < gimg_width; ix++) {
2294 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2295 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2296 m_pos_image_user_grey_day->GetGreen(ix, iy),
2297 m_pos_image_user_grey_day->GetBlue(ix, iy));
2301 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2302 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2303 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2305 hsv = wxImage::RGBtoHSV(rgb);
2306 hsv.value = hsv.value * factor_dusk;
2307 nrgb = wxImage::HSVtoRGB(hsv);
2308 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2310 hsv = wxImage::RGBtoHSV(rgb);
2311 hsv.value = hsv.value * factor_night;
2312 nrgb = wxImage::HSVtoRGB(hsv);
2313 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2325 m_display_size_mm = size;
2332 double horizontal = sd.x;
2336 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2337 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2341 ps52plib->SetPPMM(m_pix_per_mm);
2346 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2348 m_display_size_mm, sd.x, sd.y);
2354 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2357 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2360void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2362 wxString msg(event.m_string.c_str(), wxConvUTF8);
2364 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2365 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2368 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2370 compress_msg_array.RemoveAt(event.thread);
2371 compress_msg_array.Insert( msg, event.thread);
2374 compress_msg_array.Add(msg);
2377 wxString combined_msg;
2378 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2379 combined_msg += compress_msg_array[i];
2380 combined_msg +=
"\n";
2384 pprog->Update(pprog_count, combined_msg, &skip );
2385 pprog->SetSize(pprog_size);
2390void ChartCanvas::InvalidateGL() {
2391 if (!m_glcc)
return;
2393 if (g_bopengl) m_glcc->Invalidate();
2395 if (m_Compass) m_Compass->UpdateStatus(
true);
2398int ChartCanvas::GetCanvasChartNativeScale() {
2400 if (!VPoint.b_quilt) {
2401 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2403 ret = (int)m_pQuilt->GetRefNativeScale();
2408ChartBase *ChartCanvas::GetChartAtCursor() {
2410 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2411 target_chart = m_singleChart;
2412 else if (VPoint.b_quilt)
2413 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2415 target_chart = NULL;
2416 return target_chart;
2419ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2423 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2425 target_chart = NULL;
2426 return target_chart;
2429int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2430 int new_dbIndex = -1;
2431 if (!VPoint.b_quilt) {
2432 if (m_pCurrentStack) {
2433 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2434 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2436 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2446 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2448 for (
unsigned int is = 0; is < im; is++) {
2450 m_pQuilt->GetExtendedStackIndexArray()[is]);
2453 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2463void ChartCanvas::EnablePaint(
bool b_enable) {
2464 m_b_paint_enable = b_enable;
2466 if (m_glcc) m_glcc->EnablePaint(b_enable);
2470bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2472void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2474std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2475 return m_pQuilt->GetQuiltIndexArray();
2479void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2480 VPoint.b_quilt = b_quilt;
2481 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2484bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2486int ChartCanvas::GetQuiltReferenceChartIndex() {
2487 return m_pQuilt->GetRefChartdbIndex();
2490void ChartCanvas::InvalidateAllQuiltPatchs() {
2491 m_pQuilt->InvalidateAllQuiltPatchs();
2494ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2495 return m_pQuilt->GetLargestScaleChart();
2498ChartBase *ChartCanvas::GetFirstQuiltChart() {
2499 return m_pQuilt->GetFirstChart();
2502ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2504int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2506void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2507 m_pQuilt->SetHiliteIndex(dbIndex);
2510void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2511 m_pQuilt->SetHiliteIndexArray(hilite_array);
2514void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2515 m_pQuilt->ClearHiliteIndexArray();
2518std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2520 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2523int ChartCanvas::GetQuiltRefChartdbIndex() {
2524 return m_pQuilt->GetRefChartdbIndex();
2527std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2528 return m_pQuilt->GetExtendedStackIndexArray();
2531std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2532 return m_pQuilt->GetFullscreenIndexArray();
2535std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2536 return m_pQuilt->GetEclipsedStackIndexArray();
2539void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2541double ChartCanvas::GetQuiltMaxErrorFactor() {
2542 return m_pQuilt->GetMaxErrorFactor();
2545bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2546 return m_pQuilt->IsChartQuiltableRef(db_index);
2550 double chartMaxScale =
2552 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2555void ChartCanvas::StartMeasureRoute() {
2556 if (!m_routeState) {
2557 if (m_bMeasure_Active) {
2559 m_pMeasureRoute = NULL;
2562 m_bMeasure_Active =
true;
2563 m_nMeasureState = 1;
2564 m_bDrawingRoute =
false;
2566 SetCursor(*pCursorPencil);
2571void ChartCanvas::CancelMeasureRoute() {
2572 m_bMeasure_Active =
false;
2573 m_nMeasureState = 0;
2574 m_bDrawingRoute =
false;
2577 m_pMeasureRoute = NULL;
2579 SetCursor(*pCursorArrow);
2582ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2584void ChartCanvas::SetVP(
ViewPort &vp) {
2595void ChartCanvas::TriggerDeferredFocus() {
2598 m_deferredFocusTimer.Start(20,
true);
2600#if defined(__WXGTK__) || defined(__WXOSX__)
2611void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2616void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2617 if (SendKeyEventToPlugins(event))
2621 int key_char =
event.GetKeyCode();
2624 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2630 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2635 if (g_benable_rotate) {
2656void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2657 if (SendKeyEventToPlugins(event))
2661 bool b_handled =
false;
2663 m_modkeys =
event.GetModifiers();
2665 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2667#ifdef OCPN_ALT_MENUBAR
2673 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2675 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2676 if (!g_bTempShowMenuBar) {
2677 g_bTempShowMenuBar =
true;
2678 parent_frame->ApplyGlobalSettings(
false);
2680 m_bMayToggleMenuBar =
false;
2686 if (event.GetKeyCode() != WXK_ALT) {
2687 m_bMayToggleMenuBar =
false;
2694 switch (event.GetKeyCode()) {
2701 event.GetPosition(&x, &y);
2702 m_FinishRouteOnKillFocus =
false;
2703 CallPopupMenu(x, y);
2704 m_FinishRouteOnKillFocus =
true;
2708 m_modkeys |= wxMOD_ALT;
2712 m_modkeys |= wxMOD_CONTROL;
2717 case WXK_RAW_CONTROL:
2718 m_modkeys |= wxMOD_RAW_CONTROL;
2723 if (m_modkeys == wxMOD_CONTROL)
2724 parent_frame->DoStackDown(
this);
2726 StartTimedMovement();
2736 StartTimedMovement();
2744 if (m_modkeys == wxMOD_CONTROL)
2745 parent_frame->DoStackUp(
this);
2747 StartTimedMovement();
2757 StartTimedMovement();
2769 SetShowENCText(!GetShowENCText());
2775 if (!m_bMeasure_Active) {
2776 if (event.ShiftDown())
2777 m_bMeasure_DistCircle =
true;
2779 m_bMeasure_DistCircle =
false;
2781 StartMeasureRoute();
2783 CancelMeasureRoute();
2785 SetCursor(*pCursorArrow);
2795 parent_frame->ToggleColorScheme();
2797 TriggerDeferredFocus();
2801 int mod = m_modkeys & wxMOD_SHIFT;
2802 if (mod != m_brightmod) {
2804 m_bbrightdir = !m_bbrightdir;
2807 if (!m_bbrightdir) {
2808 g_nbrightness -= 10;
2809 if (g_nbrightness <= MIN_BRIGHT) {
2810 g_nbrightness = MIN_BRIGHT;
2811 m_bbrightdir =
true;
2814 g_nbrightness += 10;
2815 if (g_nbrightness >= MAX_BRIGHT) {
2816 g_nbrightness = MAX_BRIGHT;
2817 m_bbrightdir =
false;
2821 SetScreenBrightness(g_nbrightness);
2822 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2831 parent_frame->DoStackDown(
this);
2835 parent_frame->DoStackUp(
this);
2840 ToggleCanvasQuiltMode();
2846 parent_frame->ToggleFullScreen();
2851 if (m_modkeys == wxMOD_ALT) {
2854 ToggleChartOutlines();
2860 parent_frame->ActivateMOB();
2864 case WXK_NUMPAD_ADD:
2869 case WXK_NUMPAD_SUBTRACT:
2870 case WXK_PAGEDOWN: {
2871 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2876 if (m_bMeasure_Active) {
2877 if (m_nMeasureState > 2) {
2878 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2880 m_pMeasureRoute->GetnPoints();
2882 gFrame->RefreshAllCanvas();
2884 CancelMeasureRoute();
2885 StartMeasureRoute();
2893 if (event.GetKeyCode() < 128)
2895 int key_char =
event.GetKeyCode();
2899 if (!g_b_assume_azerty) {
2901 if (g_benable_rotate) {
2933 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2940 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2941 m_modkeys & wxMOD_RAW_CONTROL) {
2942 parent_frame->ToggleFullScreen();
2947 if (event.ControlDown()) key_char -= 64;
2949 if (key_char >=
'0' && key_char <=
'9')
2950 SetGroupIndex(key_char -
'0');
2955 SetShowENCAnchor(!GetShowENCAnchor());
2961 parent_frame->ToggleColorScheme();
2966 event.GetPosition(&x, &y);
2967 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2968 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2971 if (VPoint.b_quilt) {
2973 if (m_pQuilt->GetChartAtPix(
2978 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2980 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2985 if (m_singleChart) {
2986 ChartType = m_singleChart->GetChartType();
2987 ChartFam = m_singleChart->GetChartFamily();
2991 if ((ChartType != CHART_TYPE_UNKNOWN) ||
2992 (ChartFam != CHART_FAMILY_UNKNOWN)) {
2994 this, -1, ChartType, ChartFam,
2995 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
2996 wxDefaultSize, wxSIMPLE_BORDER,
"");
3009 m_nmea_log->Raise();
3013 SetShowENCLights(!GetShowENCLights());
3019 if (event.ShiftDown())
3020 m_bMeasure_DistCircle =
true;
3022 m_bMeasure_DistCircle =
false;
3024 StartMeasureRoute();
3028 if (g_bInlandEcdis && ps52plib) {
3029 SetENCDisplayCategory((_DisCat)STANDARD);
3034 ToggleChartOutlines();
3038 ToggleCanvasQuiltMode();
3042 parent_frame->ToggleTestPause();
3045 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3046 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3047 g_iNavAidRadarRingsNumberVisible = 1;
3048 else if (!g_bNavAidRadarRingsShown &&
3049 g_iNavAidRadarRingsNumberVisible == 1)
3050 g_iNavAidRadarRingsNumberVisible = 0;
3053 SetShowENCDepth(!m_encShowDepth);
3058 SetShowENCText(!GetShowENCText());
3063 SetShowENCDataQual(!GetShowENCDataQual());
3068 m_bShowNavobjects = !m_bShowNavobjects;
3083 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3088 if (event.ControlDown()) gFrame->DropMarker(
false);
3095 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3096 if ((indexActive + 1) <= r->GetnPoints()) {
3107 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3113 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3119 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3126 parent_frame->DoSettings();
3130 parent_frame->Close();
3146 if (undo->AnythingToRedo()) {
3147 undo->RedoNextAction();
3154 if (event.ShiftDown()) {
3155 if (undo->AnythingToRedo()) {
3156 undo->RedoNextAction();
3161 if (undo->AnythingToUndo()) {
3162 undo->UndoLastAction();
3171 if (m_bMeasure_Active) {
3172 CancelMeasureRoute();
3174 SetCursor(*pCursorArrow);
3177 gFrame->RefreshAllCanvas();
3191 switch (gamma_state) {
3211 SetScreenBrightness(g_nbrightness);
3216 if (event.ControlDown()) {
3217 m_bShowCompassWin = !m_bShowCompassWin;
3218 SetShowGPSCompassWindow(m_bShowCompassWin);
3235void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3236 if (SendKeyEventToPlugins(event))
3240 switch (event.GetKeyCode()) {
3242 parent_frame->SwitchKBFocus(
this);
3248 if (!m_pany) m_panspeed = 0;
3254 if (!m_panx) m_panspeed = 0;
3257 case WXK_NUMPAD_ADD:
3258 case WXK_NUMPAD_SUBTRACT:
3267 m_modkeys &= ~wxMOD_ALT;
3268#ifdef OCPN_ALT_MENUBAR
3273 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3274 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3275 parent_frame->ApplyGlobalSettings(
false);
3277 m_bMayToggleMenuBar =
true;
3283 m_modkeys &= ~wxMOD_CONTROL;
3287 if (event.GetKeyCode() < 128)
3289 int key_char =
event.GetKeyCode();
3293 if (!g_b_assume_azerty) {
3308 m_rotation_speed = 0;
3326void ChartCanvas::ToggleChartOutlines() {
3327 m_bShowOutlines = !m_bShowOutlines;
3333 if (g_bopengl) InvalidateGL();
3337void ChartCanvas::ToggleLookahead() {
3338 m_bLookAhead = !m_bLookAhead;
3343void ChartCanvas::SetUpMode(
int mode) {
3346 if (mode != NORTH_UP_MODE) {
3349 if (!std::isnan(
gCog)) stuff =
gCog;
3352 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3355 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3357 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3358 SetVPRotation(GetVPSkew());
3363 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3364 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3366 UpdateGPSCompassStatusBox(
true);
3367 gFrame->DoChartUpdate();
3370bool ChartCanvas::DoCanvasCOGSet() {
3371 if (GetUpMode() == NORTH_UP_MODE)
return false;
3373 if (g_btenhertz) cog_use =
gCog;
3375 double rotation = 0;
3376 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3377 rotation = -
gHdt * PI / 180.;
3378 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3379 rotation = -cog_use * PI / 180.;
3381 SetVPRotation(rotation);
3385double easeOutCubic(
double t) {
3387 return 1.0 - pow(1.0 - t, 3.0);
3390void ChartCanvas::StartChartDragInertia() {
3391 m_bChartDragging =
false;
3394 m_chart_drag_inertia_time = 750;
3395 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3400 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3404 size_t length = m_drag_vec_t.size();
3405 for (
size_t i = 0; i < n_vel; i++) {
3406 xacc += m_drag_vec_x.at(length - 1 - i);
3407 yacc += m_drag_vec_y.at(length - 1 - i);
3408 tacc += m_drag_vec_t.at(length - 1 - i);
3411 if (tacc == 0)
return;
3413 m_chart_drag_velocity_x = xacc / tacc;
3414 m_chart_drag_velocity_y = yacc / tacc;
3416 m_chart_drag_inertia_active =
true;
3418 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3421void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3422 if (!m_chart_drag_inertia_active)
return;
3424 wxLongLong now = wxGetLocalTimeMillis();
3425 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3426 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3427 if (t > 1.0) t = 1.0;
3428 double e = 1.0 - easeOutCubic(t);
3431 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3433 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3435 m_last_elapsed = elapsed;
3439 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3440 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3441 double inertia_lat, inertia_lon;
3445 if (!IsOwnshipOnScreen()) {
3447 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3448 UpdateFollowButtonState();
3459 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3460 m_chart_drag_inertia_timer.Stop();
3463 m_target_lat = GetVP().
clat;
3464 m_target_lon = GetVP().
clon;
3465 m_pan_drag.x = m_pan_drag.y = 0;
3466 m_panx = m_pany = 0;
3467 m_chart_drag_inertia_active =
false;
3471 int target_redraw_interval = 40;
3472 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3476void ChartCanvas::StopMovement() {
3477 m_panx = m_pany = 0;
3480 m_rotation_speed = 0;
3483#if !defined(__WXGTK__) && !defined(__WXQT__)
3494bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3496 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3498 if (!pMovementTimer->IsRunning()) {
3499 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3502 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3507 m_last_movement_time = wxDateTime::UNow();
3511void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3514 m_target_lat = target_lat;
3515 m_target_lon = target_lon;
3518 m_start_lat = GetVP().
clat;
3519 m_start_lon = GetVP().
clon;
3521 m_VPMovementTimer.Start(1,
true);
3522 m_timed_move_vp_active =
true;
3524 m_timedVP_step = nstep;
3527void ChartCanvas::DoTimedMovementVP() {
3528 if (!m_timed_move_vp_active)
return;
3529 if (m_stvpc++ > m_timedVP_step * 2) {
3536 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3551 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3552 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3554 m_run_lat = new_lat;
3555 m_run_lon = new_lon;
3560void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3562void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3564void ChartCanvas::StartTimedMovementTarget() {}
3566void ChartCanvas::DoTimedMovementTarget() {}
3568void ChartCanvas::StopMovementTarget() {}
3571void ChartCanvas::DoTimedMovement() {
3572 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3576 wxDateTime now = wxDateTime::UNow();
3578 if (m_last_movement_time.IsValid())
3579 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3581 m_last_movement_time = now;
3591 if (dt == 0) dt = 1;
3594 if (m_mustmove < 0) m_mustmove = 0;
3597 if (m_pan_drag.x || m_pan_drag.y) {
3599 m_pan_drag.x = m_pan_drag.y = 0;
3602 if (m_panx || m_pany) {
3603 const double slowpan = .1, maxpan = 2;
3604 if (m_modkeys == wxMOD_ALT)
3605 m_panspeed = slowpan;
3607 m_panspeed += (double)dt / 500;
3608 m_panspeed = wxMin(maxpan, m_panspeed);
3610 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3613 if (m_zoom_factor != 1) {
3614 double alpha = 400, beta = 1.5;
3615 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3617 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3619 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3624 if (zoom_factor > 1) {
3625 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3629 else if (zoom_factor < 1) {
3630 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3635 if (fabs(zoom_factor - 1) > 1e-4) {
3636 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3641 if (m_wheelzoom_stop_oneshot > 0) {
3642 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3643 m_wheelzoom_stop_oneshot = 0;
3648 if (zoom_factor > 1) {
3650 m_wheelzoom_stop_oneshot = 0;
3653 }
else if (zoom_factor < 1) {
3655 m_wheelzoom_stop_oneshot = 0;
3662 if (m_rotation_speed) {
3663 double speed = m_rotation_speed;
3664 if (m_modkeys == wxMOD_ALT) speed /= 10;
3665 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3669void ChartCanvas::SetColorScheme(ColorScheme cs) {
3674 case GLOBAL_COLOR_SCHEME_DAY:
3675 m_pos_image_red = &m_os_image_red_day;
3676 m_pos_image_grey = &m_os_image_grey_day;
3677 m_pos_image_yellow = &m_os_image_yellow_day;
3678 m_pos_image_user = m_pos_image_user_day;
3679 m_pos_image_user_grey = m_pos_image_user_grey_day;
3680 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3681 m_cTideBitmap = m_bmTideDay;
3682 m_cCurrentBitmap = m_bmCurrentDay;
3685 case GLOBAL_COLOR_SCHEME_DUSK:
3686 m_pos_image_red = &m_os_image_red_dusk;
3687 m_pos_image_grey = &m_os_image_grey_dusk;
3688 m_pos_image_yellow = &m_os_image_yellow_dusk;
3689 m_pos_image_user = m_pos_image_user_dusk;
3690 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3691 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3692 m_cTideBitmap = m_bmTideDusk;
3693 m_cCurrentBitmap = m_bmCurrentDusk;
3695 case GLOBAL_COLOR_SCHEME_NIGHT:
3696 m_pos_image_red = &m_os_image_red_night;
3697 m_pos_image_grey = &m_os_image_grey_night;
3698 m_pos_image_yellow = &m_os_image_yellow_night;
3699 m_pos_image_user = m_pos_image_user_night;
3700 m_pos_image_user_grey = m_pos_image_user_grey_night;
3701 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3702 m_cTideBitmap = m_bmTideNight;
3703 m_cCurrentBitmap = m_bmCurrentNight;
3706 m_pos_image_red = &m_os_image_red_day;
3707 m_pos_image_grey = &m_os_image_grey_day;
3708 m_pos_image_yellow = &m_os_image_yellow_day;
3709 m_pos_image_user = m_pos_image_user_day;
3710 m_pos_image_user_grey = m_pos_image_user_grey_day;
3711 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3712 m_cTideBitmap = m_bmTideDay;
3713 m_cCurrentBitmap = m_bmCurrentDay;
3717 CreateDepthUnitEmbossMaps(cs);
3718 CreateOZEmbossMapData(cs);
3721 m_fog_color = wxColor(
3725 case GLOBAL_COLOR_SCHEME_DUSK:
3728 case GLOBAL_COLOR_SCHEME_NIGHT:
3734 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3735 m_fog_color.Blue() * dim);
3739 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3740 SetBackgroundColour( wxColour(0,0,0) );
3742 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3745 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3747 SetBackgroundColour( wxNullColour );
3754 m_Piano->SetColorScheme(cs);
3756 m_Compass->SetColorScheme(cs);
3758 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3760 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3762 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3763 if (m_notification_button) {
3764 m_notification_button->SetColorScheme(cs);
3768 if (g_bopengl && m_glcc) {
3769 m_glcc->SetColorScheme(cs);
3775 m_brepaint_piano =
true;
3782wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3783 wxImage img = Bitmap.ConvertToImage();
3784 int sx = img.GetWidth();
3785 int sy = img.GetHeight();
3787 wxImage new_img(img);
3789 for (
int i = 0; i < sx; i++) {
3790 for (
int j = 0; j < sy; j++) {
3791 if (!img.IsTransparent(i, j)) {
3792 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3793 (
unsigned char)(img.GetGreen(i, j) * factor),
3794 (
unsigned char)(img.GetBlue(i, j) * factor));
3799 wxBitmap ret = wxBitmap(new_img);
3804void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3807 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3809 if (!m_pBrightPopup) {
3812 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3816 m_pBrightPopup->SetSize(x, y);
3817 m_pBrightPopup->Move(120, 120);
3820 int bmpsx = m_pBrightPopup->GetSize().x;
3821 int bmpsy = m_pBrightPopup->GetSize().y;
3823 wxBitmap bmp(bmpsx, bmpsx);
3824 wxMemoryDC mdc(bmp);
3826 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3827 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3828 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3829 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3832 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3834 mdc.SetFont(*pfont);
3837 if (brightness == max)
3839 else if (brightness == min)
3842 val.Printf(
"%3d", brightness);
3844 mdc.DrawText(val, 0, 0);
3846 mdc.SelectObject(wxNullBitmap);
3848 m_pBrightPopup->SetBitmap(bmp);
3849 m_pBrightPopup->Show();
3850 m_pBrightPopup->Refresh();
3853void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3854 m_b_rot_hidef =
true;
3858void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3861 bool b_need_refresh =
false;
3863 wxSize win_size = GetSize() * m_displayScale;
3867 bool showAISRollover =
false;
3869 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3873 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3874 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3877 showAISRollover =
true;
3879 if (NULL == m_pAISRolloverWin) {
3881 m_pAISRolloverWin->IsActive(
false);
3882 b_need_refresh =
true;
3883 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3884 m_AISRollover_MMSI != FoundAIS_MMSI) {
3890 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3891 m_pAISRolloverWin->IsActive(
false);
3892 m_AISRollover_MMSI = 0;
3897 m_AISRollover_MMSI = FoundAIS_MMSI;
3899 if (!m_pAISRolloverWin->IsActive()) {
3900 wxString s = ptarget->GetRolloverString();
3901 m_pAISRolloverWin->SetString(s);
3903 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3904 AIS_ROLLOVER, win_size);
3905 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3906 m_pAISRolloverWin->IsActive(
true);
3907 b_need_refresh =
true;
3911 m_AISRollover_MMSI = 0;
3912 showAISRollover =
false;
3917 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3918 m_pAISRolloverWin->IsActive(
false);
3919 m_AISRollover_MMSI = 0;
3920 b_need_refresh =
true;
3925 bool showRouteRollover =
false;
3927 if (NULL == m_pRolloverRouteSeg) {
3931 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3932 SelectableItemList SelList =
pSelect->FindSelectionList(
3934 auto node = SelList.begin();
3935 while (node != SelList.end()) {
3940 if (pr && pr->IsVisible()) {
3941 m_pRolloverRouteSeg = pFindSel;
3942 showRouteRollover =
true;
3944 if (NULL == m_pRouteRolloverWin) {
3946 m_pRouteRolloverWin->IsActive(
false);
3949 if (!m_pRouteRolloverWin->IsActive()) {
3957 DistanceBearingMercator(
3958 segShow_point_b->m_lat, segShow_point_b->m_lon,
3959 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3961 if (!pr->m_bIsInLayer)
3962 s.Append(_(
"Route") +
": ");
3964 s.Append(_(
"Layer Route: "));
3966 if (pr->m_RouteNameString.IsEmpty())
3967 s.Append(_(
"(unnamed)"));
3969 s.Append(pr->m_RouteNameString);
3974 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3975 << segShow_point_b->GetName() <<
"\n";
3978 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
3979 (
int)floor(brg + 0.5), 0x00B0);
3982 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3984 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3985 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3987 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
3988 (
int)floor(varBrg + 0.5), 0x00B0);
3996 double shiptoEndLeg = 0.;
3997 bool validActive =
false;
3998 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4001 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4002 auto node = pr->pRoutePointList->begin();
4004 float dist_to_endleg = 0;
4007 for (++node; node != pr->pRoutePointList->end(); ++node) {
4014 if (prp->IsSame(segShow_point_a))
break;
4022 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4025 ->GetCurrentRngToActivePoint();
4034 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4039 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4040 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4042 << wxString(ttg_sec > SECONDS_PER_DAY
4043 ? ttg_span.Format(_(
"%Dd %H:%M"))
4044 : ttg_span.Format(_(
"%H:%M")));
4045 wxDateTime dtnow, eta;
4046 eta = dtnow.SetToCurrent().Add(ttg_span);
4047 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4048 << eta.Format(
" %d %H:%M");
4052 m_pRouteRolloverWin->SetString(s);
4054 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4055 LEG_ROLLOVER, win_size);
4056 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4057 m_pRouteRolloverWin->IsActive(
true);
4058 b_need_refresh =
true;
4059 showRouteRollover =
true;
4068 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4070 m_pRolloverRouteSeg))
4071 showRouteRollover =
false;
4072 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4073 showRouteRollover =
false;
4075 showRouteRollover =
true;
4079 if (m_routeState) showRouteRollover =
false;
4082 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4083 showRouteRollover =
false;
4085 if (m_pRouteRolloverWin &&
4086 !showRouteRollover) {
4087 m_pRouteRolloverWin->IsActive(
false);
4088 m_pRolloverRouteSeg = NULL;
4089 m_pRouteRolloverWin->Destroy();
4090 m_pRouteRolloverWin = NULL;
4091 b_need_refresh =
true;
4092 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4093 m_pRouteRolloverWin->IsActive(
true);
4094 b_need_refresh =
true;
4099 bool showTrackRollover =
false;
4101 if (NULL == m_pRolloverTrackSeg) {
4105 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4106 SelectableItemList SelList =
pSelect->FindSelectionList(
4109 auto node = SelList.begin();
4110 while (node != SelList.end()) {
4115 if (pt && pt->IsVisible()) {
4116 m_pRolloverTrackSeg = pFindSel;
4117 showTrackRollover =
true;
4119 if (NULL == m_pTrackRolloverWin) {
4121 m_pTrackRolloverWin->IsActive(
false);
4124 if (!m_pTrackRolloverWin->IsActive()) {
4132 DistanceBearingMercator(
4133 segShow_point_b->m_lat, segShow_point_b->m_lon,
4134 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4136 if (!pt->m_bIsInLayer)
4137 s.Append(_(
"Track") +
": ");
4139 s.Append(_(
"Layer Track: "));
4141 if (pt->GetName().IsEmpty())
4142 s.Append(_(
"(unnamed)"));
4144 s.Append(pt->GetName());
4145 double tlenght = pt->Length();
4147 if (pt->GetLastPoint()->GetTimeString() &&
4148 pt->GetPoint(0)->GetTimeString()) {
4149 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4150 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4151 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4152 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4153 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4154 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4155 << getUsrSpeedUnit();
4156 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4157 : ttime.Format(
" %H:%M"));
4161 if (g_bShowTrackPointTime &&
4162 strlen(segShow_point_b->GetTimeString())) {
4163 wxString stamp = segShow_point_b->GetTimeString();
4164 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4165 if (timestamp.IsValid()) {
4169 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4171 s <<
"\n" << _(
"Segment Created: ") << stamp;
4176 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4181 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4183 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4184 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4186 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4192 if (segShow_point_a->GetTimeString() &&
4193 segShow_point_b->GetTimeString()) {
4194 wxDateTime apoint = segShow_point_a->GetCreateTime();
4195 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4196 if (apoint.IsValid() && bpoint.IsValid()) {
4197 double segmentSpeed = toUsrSpeed(
4198 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4199 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4200 << getUsrSpeedUnit();
4204 m_pTrackRolloverWin->SetString(s);
4206 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4207 LEG_ROLLOVER, win_size);
4208 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4209 m_pTrackRolloverWin->IsActive(
true);
4210 b_need_refresh =
true;
4211 showTrackRollover =
true;
4220 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4222 m_pRolloverTrackSeg))
4223 showTrackRollover =
false;
4224 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4225 showTrackRollover =
false;
4227 showTrackRollover =
true;
4231 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4232 showTrackRollover =
false;
4235 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4236 showTrackRollover =
false;
4242 if (m_pTrackRolloverWin &&
4243 !showTrackRollover) {
4244 m_pTrackRolloverWin->IsActive(
false);
4245 m_pRolloverTrackSeg = NULL;
4246 m_pTrackRolloverWin->Destroy();
4247 m_pTrackRolloverWin = NULL;
4248 b_need_refresh =
true;
4249 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4250 m_pTrackRolloverWin->IsActive(
true);
4251 b_need_refresh =
true;
4254 if (b_need_refresh) Refresh();
4257void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4258 if ((GetShowENCLights() || m_bsectors_shown) &&
4259 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4260 extendedSectorLegs)) {
4261 if (!m_bsectors_shown) {
4263 m_bsectors_shown =
true;
4266 if (m_bsectors_shown) {
4268 m_bsectors_shown =
false;
4276#if defined(__WXGTK__) || defined(__WXQT__)
4281 double cursor_lat, cursor_lon;
4284 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4285 while (cursor_lon < -180.) cursor_lon += 360.;
4287 while (cursor_lon > 180.) cursor_lon -= 360.;
4289 SetCursorStatus(cursor_lat, cursor_lon);
4295void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4296 if (!parent_frame->m_pStatusBar)
return;
4300 s1 += toSDMM(1, cursor_lat);
4302 s1 += toSDMM(2, cursor_lon);
4304 if (STAT_FIELD_CURSOR_LL >= 0)
4305 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4307 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4312 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4313 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4314 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4316 wxString s = st + sm;
4329 if (g_bShowLiveETA) {
4332 float boatSpeedDefault = g_defaultBoatSpeed;
4337 if (!std::isnan(
gSog)) {
4339 if (boatSpeed < 0.5) {
4342 realTimeETA = dist / boatSpeed * 60;
4351 s << minutesToHoursDays(realTimeETA);
4356 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4357 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4359 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4364 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4372wxString minutesToHoursDays(
float timeInMinutes) {
4375 if (timeInMinutes == 0) {
4380 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4381 s << wxString::Format(
"%d", (
int)timeInMinutes);
4386 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4389 hours = (int)timeInMinutes / 60;
4390 min = (int)timeInMinutes % 60;
4393 s << wxString::Format(
"%d", hours);
4396 s << wxString::Format(
"%d", hours);
4398 s << wxString::Format(
"%d", min);
4405 else if (timeInMinutes > 24 * 60) {
4408 days = (int)(timeInMinutes / 60) / 24;
4409 hours = (int)(timeInMinutes / 60) % 24;
4412 s << wxString::Format(
"%d", days);
4415 s << wxString::Format(
"%d", days);
4417 s << wxString::Format(
"%d", hours);
4429void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4437 wxPoint2DDouble *r) {
4442 double rlon, wxPoint2DDouble *r) {
4453 if (!g_bopengl && m_singleChart &&
4454 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4455 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4456 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4457 (m_singleChart->GetChartProjectionType() !=
4458 PROJECTION_TRANSVERSE_MERCATOR) &&
4459 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4460 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4461 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4475 Cur_BSB_Ch->SetVPRasterParms(vp);
4476 double rpixxd, rpixyd;
4477 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4503 if (std::isnan(p.m_x)) {
4504 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4508 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4509 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4511 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4530 if (!g_bopengl && m_singleChart &&
4531 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4532 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4533 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4534 (m_singleChart->GetChartProjectionType() !=
4535 PROJECTION_TRANSVERSE_MERCATOR) &&
4536 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4537 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4538 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4549 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4552 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4557 else if (slon > 180.)
4568 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4574 DoZoomCanvas(factor,
false);
4575 extendedSectorLegs.clear();
4580 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4583 if (StartTimedMovement(stoptimer)) {
4585 m_zoom_factor = factor;
4590 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4592 DoZoomCanvas(factor, can_zoom_to_cursor);
4595 extendedSectorLegs.clear();
4598void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4601 if (!m_pCurrentStack)
return;
4607 if (m_bzooming)
return;
4616 double proposed_scale_onscreen =
4619 bool b_do_zoom =
false;
4628 if (!VPoint.b_quilt) {
4631 if (!m_disable_adjust_on_zoom) {
4632 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4633 if (new_db_index >= 0)
4634 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4638 int current_ref_stack_index = -1;
4639 if (m_pCurrentStack->nEntry) {
4641 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4642 m_pQuilt->SetReferenceChart(trial_index);
4643 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4644 if (new_db_index >= 0)
4645 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4649 if (m_pCurrentStack)
4650 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4661 double min_allowed_scale =
4664 if (proposed_scale_onscreen < min_allowed_scale) {
4669 proposed_scale_onscreen = min_allowed_scale;
4673 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4676 }
else if (factor < 1) {
4681 bool b_smallest =
false;
4683 if (!VPoint.b_quilt) {
4688 LLBBox viewbox = VPoint.GetBBox();
4690 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4691 double max_allowed_scale;
4705 if (proposed_scale_onscreen > max_allowed_scale) {
4707 proposed_scale_onscreen = max_allowed_scale;
4712 if (!m_disable_adjust_on_zoom) {
4714 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4715 if (new_db_index >= 0)
4716 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4718 if (m_pCurrentStack)
4719 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4722 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4724 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4725 proposed_scale_onscreen =
4726 wxMin(proposed_scale_onscreen,
4732 m_absolute_min_scale_ppm)
4733 proposed_scale_onscreen =
4742 bool b_allow_ztc =
true;
4743 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4744 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4746 double brg, distance;
4747 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4750 meters_to_shift = distance * 1852;
4758 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4761 if (m_bFollow) DoCanvasUpdate();
4768void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4770 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4774void ChartCanvas::RotateCanvas(
double dir) {
4778 if (StartTimedMovement()) {
4780 m_rotation_speed = dir * 60;
4783 double speed = dir * 10;
4784 if (m_modkeys == wxMOD_ALT) speed /= 20;
4785 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4789void ChartCanvas::DoRotateCanvas(
double rotation) {
4790 while (rotation < 0) rotation += 2 * PI;
4791 while (rotation > 2 * PI) rotation -= 2 * PI;
4793 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4795 SetVPRotation(rotation);
4796 parent_frame->UpdateRotationState(VPoint.
rotation);
4799void ChartCanvas::DoTiltCanvas(
double tilt) {
4800 while (tilt < 0) tilt = 0;
4801 while (tilt > .95) tilt = .95;
4803 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4809void ChartCanvas::TogglebFollow() {
4816void ChartCanvas::ClearbFollow() {
4819 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4821 UpdateFollowButtonState();
4825 parent_frame->SetChartUpdatePeriod();
4828void ChartCanvas::SetbFollow() {
4831 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4832 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4840 p.m_x += m_OSoffsetx;
4841 p.m_y -= m_OSoffsety;
4850 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4851 UpdateFollowButtonState();
4853 if (!g_bSmoothRecenter) {
4857 parent_frame->SetChartUpdatePeriod();
4860void ChartCanvas::UpdateFollowButtonState() {
4863 m_muiBar->SetFollowButtonState(0);
4866 m_muiBar->SetFollowButtonState(2);
4868 m_muiBar->SetFollowButtonState(1);
4874 androidSetFollowTool(0);
4877 androidSetFollowTool(2);
4879 androidSetFollowTool(1);
4886 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4887 if (pic->m_enabled && pic->m_init_state) {
4888 switch (pic->m_api_version) {
4891 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4902void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4903 if (g_bSmoothRecenter && !m_routeState) {
4904 if (StartSmoothJump(lat, lon, scale_ppm))
4908 double gcDist, gcBearingEnd;
4909 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4911 gcBearingEnd += 180;
4912 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4915 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4916 double new_lat = lat + (lat_offset / (1852 * 60));
4917 double new_lon = lon + (lon_offset / (1852 * 60));
4920 StartSmoothJump(lat, lon, scale_ppm);
4925 if (lon > 180.0) lon -= 360.0;
4931 if (!GetQuiltMode()) {
4933 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4934 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4938 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4939 AdjustQuiltRefChart();
4946 UpdateFollowButtonState();
4954bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4959 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4960 double distance_pixels = gcDist *
GetVPScale();
4961 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4967 m_startLat = m_vLat;
4968 m_startLon = m_vLon;
4973 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4974 m_endScale = scale_ppm;
4977 m_animationDuration = 600;
4978 m_animationStart = wxGetLocalTimeMillis();
4985 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
4986 m_animationActive =
true;
4991void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
4993 wxLongLong now = wxGetLocalTimeMillis();
4994 double elapsed = (now - m_animationStart).ToDouble();
4995 double t = elapsed / m_animationDuration.ToDouble();
4996 if (t > 1.0) t = 1.0;
4999 double e = easeOutCubic(t);
5002 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5003 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5004 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5009 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5015 m_animationActive =
false;
5016 UpdateFollowButtonState();
5025 extendedSectorLegs.clear();
5034 if (iters++ > 5)
return false;
5035 if (!std::isnan(dlat))
break;
5038 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5044 else if (dlat < -90)
5047 if (dlon > 360.) dlon -= 360.;
5048 if (dlon < -360.) dlon += 360.;
5063 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5067 if (VPoint.b_quilt) {
5068 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5069 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5073 double tweak_scale_ppm =
5079 if (new_ref_dbIndex == -1) {
5080#pragma GCC diagnostic push
5081#pragma GCC diagnostic ignored "-Warray-bounds"
5088 int trial_index = -1;
5089 if (m_pCurrentStack->nEntry) {
5091 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5094 if (trial_index < 0) {
5095 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5096 if (full_screen_array.size())
5097 trial_index = full_screen_array[full_screen_array.size() - 1];
5100 if (trial_index >= 0) {
5101 m_pQuilt->SetReferenceChart(trial_index);
5106#pragma GCC diagnostic pop
5113 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5115 double offset_angle = atan2(offy, offx);
5116 double offset_distance = sqrt((offy * offy) + (offx * offx));
5117 double chart_angle = GetVPRotation();
5118 double target_angle = chart_angle - offset_angle;
5119 double d_east_mod = offset_distance * cos(target_angle);
5120 double d_north_mod = offset_distance * sin(target_angle);
5125 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5126 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5128 UpdateFollowButtonState();
5134 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5139bool ChartCanvas::IsOwnshipOnScreen() {
5142 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5143 ((r.y > 0) && r.y < GetCanvasHeight()))
5149void ChartCanvas::ReloadVP(
bool b_adjust) {
5150 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5152 LoadVP(VPoint, b_adjust);
5155void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5157 if (g_bopengl && m_glcc) {
5158 m_glcc->Invalidate();
5159 if (m_glcc->GetSize() != GetSize()) {
5160 m_glcc->SetSize(GetSize());
5165 m_cache_vp.Invalidate();
5166 m_bm_cache_vp.Invalidate();
5169 VPoint.Invalidate();
5171 if (m_pQuilt) m_pQuilt->Invalidate();
5180 vp.m_projection_type, b_adjust);
5183void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5184 m_pQuilt->SetReferenceChart(dbIndex);
5185 VPoint.Invalidate();
5186 m_pQuilt->Invalidate();
5189double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5191 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5198int ChartCanvas::AdjustQuiltRefChart() {
5203 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5205 double min_ref_scale =
5206 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5207 double max_ref_scale =
5208 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5211 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5212 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5213 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5215 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5218 int target_stack_index = wxNOT_FOUND;
5220 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5221 if (index == m_pQuilt->GetRefChartdbIndex()) {
5222 target_stack_index = il;
5227 if (wxNOT_FOUND == target_stack_index)
5228 target_stack_index = 0;
5230 int ref_family = pc->GetChartFamily();
5231 int extended_array_count =
5232 m_pQuilt->GetExtendedStackIndexArray().size();
5233 while ((!brender_ok) &&
5234 ((
int)target_stack_index < (extended_array_count - 1))) {
5235 target_stack_index++;
5237 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5239 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5240 IsChartQuiltableRef(test_db_index)) {
5243 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5245 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5252 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5253 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5254 IsChartQuiltableRef(new_db_index)) {
5255 m_pQuilt->SetReferenceChart(new_db_index);
5258 ret = m_pQuilt->GetRefChartdbIndex();
5260 ret = m_pQuilt->GetRefChartdbIndex();
5263 ret = m_pQuilt->GetRefChartdbIndex();
5272void ChartCanvas::UpdateCanvasOnGroupChange() {
5273 delete m_pCurrentStack;
5285bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5286 double latNE,
double lonNE) {
5288 double latc = (latSW + latNE) / 2.0;
5289 double lonc = (lonSW + lonNE) / 2.0;
5292 double ne_easting, ne_northing;
5293 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5295 double sw_easting, sw_northing;
5296 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5298 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5305 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5308bool ChartCanvas::SetVPProjection(
int projection) {
5314 double prev_true_scale_ppm = m_true_scale_ppm;
5319 m_absolute_min_scale_ppm));
5327bool ChartCanvas::SetVPRotation(
double angle) {
5329 VPoint.
skew, angle);
5332 double skew,
double rotation,
int projection,
5333 bool b_adjust,
bool b_refresh) {
5338 if (VPoint.IsValid()) {
5339 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5340 (fabs(VPoint.
skew - skew) < 1e-9) &&
5341 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5342 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5343 (VPoint.m_projection_type == projection ||
5344 projection == PROJECTION_UNKNOWN))
5347 if (VPoint.m_projection_type != projection)
5348 VPoint.InvalidateTransformCache();
5358 if (projection != PROJECTION_UNKNOWN)
5359 VPoint.SetProjectionType(projection);
5360 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5361 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5364 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5365 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5366 if (VPoint.
clat > 89.5)
5368 else if (VPoint.
clat < -89.5)
5369 VPoint.
clat = -89.5;
5374 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5375 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5387 bool bwasValid = VPoint.IsValid();
5392 m_cache_vp.Invalidate();
5397 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5401 int mouseX = mouse_x;
5402 int mouseY = mouse_y;
5403 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5409 SendCursorLatLonToAllPlugIns(lat, lon);
5412 if (!VPoint.b_quilt && m_singleChart) {
5417 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5421 if ((!m_cache_vp.IsValid()) ||
5426 wxPoint cp_last, cp_this;
5430 if (cp_last != cp_this) {
5436 if (m_pCurrentStack) {
5438 int current_db_index;
5440 m_pCurrentStack->GetCurrentEntrydbIndex();
5442 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5444 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5447 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5451 if (VPoint.b_quilt) {
5453 m_pQuilt->InvalidateAllQuiltPatchs();
5457 if (!m_pCurrentStack)
return false;
5459 int current_db_index;
5461 m_pCurrentStack->GetCurrentEntrydbIndex();
5463 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5464 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5467 int current_ref_stack_index = -1;
5468 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5469 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5470 current_ref_stack_index = i;
5473 if (g_bFullScreenQuilt) {
5474 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5478 bool b_needNewRef =
false;
5481 if ((-1 == current_ref_stack_index) &&
5482 (m_pQuilt->GetRefChartdbIndex() >= 0))
5483 b_needNewRef =
true;
5490 bool renderable =
true;
5492 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5493 if (referenceChart) {
5494 double chartMaxScale = referenceChart->GetNormalScaleMax(
5496 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5498 if (!renderable) b_needNewRef =
true;
5501 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5503 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5504 int target_scale = cte_ref.GetScale();
5505 int target_type = cte_ref.GetChartType();
5506 int candidate_stack_index;
5513 candidate_stack_index = 0;
5514 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5516 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5517 int candidate_scale = cte_candidate.GetScale();
5518 int candidate_type = cte_candidate.GetChartType();
5520 if ((candidate_scale >= target_scale) &&
5521 (candidate_type == target_type)) {
5522 bool renderable =
true;
5524 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5525 if (tentative_referenceChart) {
5526 double chartMaxScale =
5527 tentative_referenceChart->GetNormalScaleMax(
5529 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5532 if (renderable)
break;
5535 candidate_stack_index++;
5540 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5541 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5542 while (candidate_stack_index >= 0) {
5543 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5547 int candidate_scale = cte_candidate.GetScale();
5548 int candidate_type = cte_candidate.GetChartType();
5550 if ((candidate_scale <= target_scale) &&
5551 (candidate_type == target_type))
5554 candidate_stack_index--;
5559 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5560 (candidate_stack_index < 0))
5561 candidate_stack_index = 0;
5563 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5565 m_pQuilt->SetReferenceChart(new_ref_index);
5571 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5576 bool renderable =
true;
5578 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5579 if (referenceChart) {
5580 double chartMaxScale = referenceChart->GetNormalScaleMax(
5582 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5583 proj =
ChartData->GetDBChartProj(ref_db_index);
5585 proj = PROJECTION_MERCATOR;
5587 VPoint.b_MercatorProjectionOverride =
5588 (m_pQuilt->GetnCharts() == 0 || !renderable);
5590 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5592 VPoint.SetProjectionType(proj);
5599 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5604 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5624 m_pQuilt->Invalidate();
5641 if (b_refresh) Refresh(
false);
5648 }
else if (!g_bopengl) {
5649 OcpnProjType projection = PROJECTION_UNKNOWN;
5652 projection = m_singleChart->GetChartProjectionType();
5653 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5654 VPoint.SetProjectionType(projection);
5658 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5659 m_cache_vp.Invalidate();
5663 UpdateCanvasControlBar();
5669 if (VPoint.GetBBox().GetValid()) {
5672 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5681 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5684 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5691 wxPoint2DDouble r, r1;
5693 double delta_check =
5697 double check_point = wxMin(89., VPoint.
clat);
5699 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5702 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5703 VPoint.
clon, 0, &rhumbDist);
5708 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5709 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5711 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5715 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5721 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5723 if (m_true_scale_ppm)
5724 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5729 double round_factor = 1000.;
5733 round_factor = 100.;
5735 round_factor = 1000.;
5738 double retina_coef = 1;
5742 retina_coef = GetContentScaleFactor();
5753 double true_scale_display =
5754 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5759 if (m_displayed_scale_factor > 10.0)
5760 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5761 m_displayed_scale_factor);
5762 else if (m_displayed_scale_factor > 1.0)
5763 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5764 m_displayed_scale_factor);
5765 else if (m_displayed_scale_factor > 0.1) {
5766 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5767 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5768 }
else if (m_displayed_scale_factor > 0.01) {
5769 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5770 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5773 "%s %4.0f (---)", _(
"Scale"),
5774 true_scale_display);
5777 m_scaleValue = true_scale_display;
5779 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5781 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5782 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5784 bool b_noshow =
false;
5788 wxClientDC dc(parent_frame->GetStatusBar());
5790 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5791 dc.SetFont(*templateFont);
5792 dc.GetTextExtent(text, &w, &h);
5797 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5798 if (w && w > rect.width) {
5799 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5803 dc.GetTextExtent(text, &w, &h);
5805 if (w && w > rect.width) {
5811 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5816 m_vLat = VPoint.
clat;
5817 m_vLon = VPoint.
clon;
5831static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5835static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5836 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5838wxColour ChartCanvas::PredColor() {
5841 if (SHIP_NORMAL == m_ownship_state)
5842 return GetGlobalColor(
"URED");
5844 else if (SHIP_LOWACCURACY == m_ownship_state)
5845 return GetGlobalColor(
"YELO1");
5847 return GetGlobalColor(
"NODTA");
5850wxColour ChartCanvas::ShipColor() {
5854 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5856 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5858 return GetGlobalColor(
"URED");
5861void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5862 wxPoint2DDouble lShipMidPoint) {
5863 dc.SetPen(wxPen(PredColor(), 2));
5865 if (SHIP_NORMAL == m_ownship_state)
5866 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5868 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5870 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5871 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5873 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5875 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5876 lShipMidPoint.m_y + 12);
5879void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5880 wxPoint GPSOffsetPixels,
5881 wxPoint2DDouble lGPSPoint) {
5886 float ref_dim = m_display_size_mm / 24;
5887 ref_dim = wxMin(ref_dim, 12);
5888 ref_dim = wxMax(ref_dim, 6);
5891 cPred.Set(g_cog_predictor_color);
5892 if (cPred == wxNullColour) cPred = PredColor();
5899 double nominal_line_width_pix = wxMax(
5901 floor(m_pix_per_mm / 2));
5905 if (nominal_line_width_pix > g_cog_predictor_width)
5906 g_cog_predictor_width = nominal_line_width_pix;
5909 wxPoint lPredPoint, lHeadPoint;
5911 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5912 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5914 double pred_lat, pred_lon;
5915 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5916 &pred_lat, &pred_lon);
5927 float ndelta_pix = 10.;
5928 double hdg_pred_lat, hdg_pred_lon;
5929 bool b_render_hdt =
false;
5930 if (!std::isnan(
gHdt)) {
5932 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5935 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5936 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5937 if (dist > ndelta_pix ) {
5938 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5939 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5944 wxPoint lShipMidPoint;
5945 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5946 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5947 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5948 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5950 if (lpp >= img_height / 2) {
5951 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5952 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5953 !std::isnan(
gSog)) {
5955 float dash_length = ref_dim;
5956 wxDash dash_long[2];
5958 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5959 g_cog_predictor_width);
5960 dash_long[1] = dash_long[0] / 2.0;
5964 if (dash_length > 250.) {
5965 dash_long[0] = 250. / g_cog_predictor_width;
5966 dash_long[1] = dash_long[0] / 2;
5969 wxPen ppPen2(cPred, g_cog_predictor_width,
5970 (wxPenStyle)g_cog_predictor_style);
5971 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5972 ppPen2.SetDashes(2, dash_long);
5975 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5976 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5978 if (g_cog_predictor_width > 1) {
5979 float line_width = g_cog_predictor_width / 3.;
5981 wxDash dash_long3[2];
5982 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5983 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5985 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
5986 (wxPenStyle)g_cog_predictor_style);
5987 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5988 ppPen3.SetDashes(2, dash_long3);
5990 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
5991 lGPSPoint.m_y + GPSOffsetPixels.y,
5992 lPredPoint.x + GPSOffsetPixels.x,
5993 lPredPoint.y + GPSOffsetPixels.y);
5996 if (g_cog_predictor_endmarker) {
5998 double png_pred_icon_scale_factor = .4;
5999 if (g_ShipScaleFactorExp > 1.0)
6000 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6001 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6005 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6006 (
float)(lPredPoint.x - lShipMidPoint.x));
6007 cog_rad += (float)PI;
6009 for (
int i = 0; i < 4; i++) {
6011 double pxa = (double)(s_png_pred_icon[j]);
6012 double pya = (double)(s_png_pred_icon[j + 1]);
6014 pya *= png_pred_icon_scale_factor;
6015 pxa *= png_pred_icon_scale_factor;
6017 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6018 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6020 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6021 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6025 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6028 dc.SetBrush(wxBrush(cPred));
6030 dc.StrokePolygon(4, icon);
6037 float hdt_dash_length = ref_dim * 0.4;
6039 cPred.Set(g_ownship_HDTpredictor_color);
6040 if (cPred == wxNullColour) cPred = PredColor();
6042 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6043 : g_cog_predictor_width * 0.8);
6044 wxDash dash_short[2];
6046 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6049 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6052 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6053 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6054 ppPen2.SetDashes(2, dash_short);
6058 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6059 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6061 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6063 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6065 if (g_ownship_HDTpredictor_endmarker) {
6066 double nominal_circle_size_pixels = wxMax(
6067 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6070 if (g_ShipScaleFactorExp > 1.0)
6071 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6073 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6074 lHeadPoint.y + GPSOffsetPixels.y,
6075 nominal_circle_size_pixels / 2);
6080 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6081 double factor = 1.00;
6082 if (g_pNavAidRadarRingsStepUnits == 1)
6084 else if (g_pNavAidRadarRingsStepUnits == 2) {
6085 if (std::isnan(
gSog))
6090 factor *= g_fNavAidRadarRingsStep;
6094 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6097 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6098 pow((
double)(lGPSPoint.m_y - r.y), 2));
6099 int pix_radius = (int)lpp;
6101 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6103 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6106 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6108 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6109 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6113void ChartCanvas::ComputeShipScaleFactor(
6114 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6115 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6116 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6117 float screenResolution = m_pix_per_mm;
6120 double ship_bow_lat, ship_bow_lon;
6121 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6122 &ship_bow_lat, &ship_bow_lon);
6123 wxPoint lShipBowPoint;
6124 wxPoint2DDouble b_point =
6128 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6129 powf((
float)(b_point.m_y - a_point.m_y), 2));
6132 float shipLength_mm = shipLength_px / screenResolution;
6135 float ownship_min_mm = g_n_ownship_min_mm;
6136 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6139 float hdt_ant = icon_hdt + 180.;
6140 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6141 float dx = g_n_gps_antenna_offset_x / 1852.;
6142 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6150 if (shipLength_mm < ownship_min_mm) {
6151 dy /= shipLength_mm / ownship_min_mm;
6152 dx /= shipLength_mm / ownship_min_mm;
6155 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6157 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6158 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6164 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6165 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6167 float scale_factor = shipLength_px / ownShipLength;
6170 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6173 scale_factor = wxMax(scale_factor, scale_factor_min);
6175 scale_factor_y = scale_factor;
6176 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6177 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6180void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6181 if (!GetVP().IsValid())
return;
6183 wxPoint GPSOffsetPixels(0, 0);
6184 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6187 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6188 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6192 lShipMidPoint = lGPSPoint;
6196 float icon_hdt = pCog;
6197 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6200 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6204 double osd_head_lat, osd_head_lon;
6205 wxPoint osd_head_point;
6207 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6212 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6213 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6214 icon_rad += (float)PI;
6216 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6220 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6224 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6225 if (GetVP().chart_scale >
6228 ShipDrawLargeScale(dc, lShipMidPoint);
6234 if (m_pos_image_user)
6235 pos_image = m_pos_image_user->Copy();
6236 else if (SHIP_NORMAL == m_ownship_state)
6237 pos_image = m_pos_image_red->Copy();
6238 if (SHIP_LOWACCURACY == m_ownship_state)
6239 pos_image = m_pos_image_yellow->Copy();
6240 else if (SHIP_NORMAL != m_ownship_state)
6241 pos_image = m_pos_image_grey->Copy();
6244 if (m_pos_image_user) {
6245 pos_image = m_pos_image_user->Copy();
6247 if (SHIP_LOWACCURACY == m_ownship_state)
6248 pos_image = m_pos_image_user_yellow->Copy();
6249 else if (SHIP_NORMAL != m_ownship_state)
6250 pos_image = m_pos_image_user_grey->Copy();
6253 img_height = pos_image.GetHeight();
6255 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6256 g_OwnShipIconType > 0)
6258 int ownShipWidth = 22;
6259 int ownShipLength = 84;
6260 if (g_OwnShipIconType == 1) {
6261 ownShipWidth = pos_image.GetWidth();
6262 ownShipLength = pos_image.GetHeight();
6265 float scale_factor_x, scale_factor_y;
6266 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6267 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6268 scale_factor_x, scale_factor_y);
6270 if (g_OwnShipIconType == 1) {
6271 pos_image.Rescale(ownShipWidth * scale_factor_x,
6272 ownShipLength * scale_factor_y,
6273 wxIMAGE_QUALITY_HIGH);
6274 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6276 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6279 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6280 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6281 if (rot_image.GetAlpha(ip, jp) > 64)
6282 rot_image.SetAlpha(ip, jp, 255);
6284 wxBitmap os_bm(rot_image);
6286 int w = os_bm.GetWidth();
6287 int h = os_bm.GetHeight();
6290 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6291 lShipMidPoint.m_y - h / 2,
true);
6294 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6295 lShipMidPoint.m_y - h / 2);
6296 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6297 lShipMidPoint.m_y - h / 2 + h);
6300 else if (g_OwnShipIconType == 2) {
6301 wxPoint ownship_icon[10];
6303 for (
int i = 0; i < 10; i++) {
6305 float pxa = (float)(s_ownship_icon[j]);
6306 float pya = (float)(s_ownship_icon[j + 1]);
6307 pya *= scale_factor_y;
6308 pxa *= scale_factor_x;
6310 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6311 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6313 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6314 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6317 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6319 dc.SetBrush(wxBrush(ShipColor()));
6321 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6324 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6326 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6330 img_height = ownShipLength * scale_factor_y;
6334 if (m_pos_image_user) circle_rad = 1;
6336 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6337 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6338 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6341 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6343 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6346 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6347 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6348 if (rot_image.GetAlpha(ip, jp) > 64)
6349 rot_image.SetAlpha(ip, jp, 255);
6351 wxBitmap os_bm(rot_image);
6353 if (g_ShipScaleFactorExp > 1) {
6354 wxImage scaled_image = os_bm.ConvertToImage();
6355 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6357 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6358 scaled_image.GetHeight() * factor,
6359 wxIMAGE_QUALITY_HIGH));
6361 int w = os_bm.GetWidth();
6362 int h = os_bm.GetHeight();
6365 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6366 lShipMidPoint.m_y - h / 2,
true);
6370 if (m_pos_image_user) circle_rad = 1;
6372 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6373 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6374 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6377 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6378 lShipMidPoint.m_y - h / 2);
6379 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6380 lShipMidPoint.m_y - h / 2 + h);
6385 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6398void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6399 float &MinorSpacing) {
6404 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6405 {.000001f, 45.0f, 15.0f},
6406 {.0002f, 30.0f, 10.0f},
6407 {.0003f, 10.0f, 2.0f},
6408 {.0008f, 5.0f, 1.0f},
6409 {.001f, 2.0f, 30.0f / 60.0f},
6410 {.003f, 1.0f, 20.0f / 60.0f},
6411 {.006f, 0.5f, 10.0f / 60.0f},
6412 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6413 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6414 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6415 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6416 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6417 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6418 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6419 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6422 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6423 if (view_scale_ppm < lltab[tabi][0])
break;
6424 MajorSpacing = lltab[tabi][1];
6425 MinorSpacing = lltab[tabi][2];
6439wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6440 int deg = (int)fabs(latlon);
6441 float min = fabs((fabs(latlon) - deg) * 60.0);
6451 }
else if (latlon < 0.0) {
6463 if (spacing >= 1.0) {
6464 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6465 }
else if (spacing >= (1.0 / 60.0)) {
6466 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6468 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6485void ChartCanvas::GridDraw(
ocpnDC &dc) {
6486 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6488 double nlat, elon, slat, wlon;
6491 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6493 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6495 if (!m_pgridFont) SetupGridFont();
6496 dc.SetFont(*m_pgridFont);
6497 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6500 h = m_canvas_height;
6511 dlon = dlon + 360.0;
6514 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6517 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6520 while (lat < nlat) {
6523 CalcGridText(lat, gridlatMajor,
true);
6525 dc.
DrawLine(0, r.y, w, r.y,
false);
6526 dc.DrawText(st, 0, r.y);
6527 lat = lat + gridlatMajor;
6529 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6533 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6536 while (lat < nlat) {
6539 dc.
DrawLine(0, r.y, 10, r.y,
false);
6540 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6541 lat = lat + gridlatMinor;
6545 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6548 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6551 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6553 wxString st = CalcGridText(lon, gridlonMajor,
false);
6555 dc.
DrawLine(r.x, 0, r.x, h,
false);
6556 dc.DrawText(st, r.x, 0);
6557 lon = lon + gridlonMajor;
6562 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6566 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6568 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6571 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6572 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6573 lon = lon + gridlonMinor;
6580void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6582 double blat, blon, tlat, tlon;
6585 int x_origin = m_bDisplayGrid ? 60 : 20;
6586 int y_origin = m_canvas_height - 50;
6592 if (GetVP().chart_scale > 80000)
6596 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6597 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6602 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6603 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6607 double rotation = -VPoint.
rotation;
6609 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6611 int l1 = (y_origin - r.y) / count;
6613 for (
int i = 0; i < count; i++) {
6620 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6623 double blat, blon, tlat, tlon;
6630 int y_origin = m_canvas_height - chartbar_height - 5;
6634 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6641 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6646 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6647 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6651 float places = floor(logdist), rem = logdist - places;
6652 dist = pow(10, places);
6659 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6660 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6661 double rotation = -VPoint.
rotation;
6667 int l1 = r.x - x_origin;
6669 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6674 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6675 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6676 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6678 if (!m_pgridFont) SetupGridFont();
6679 dc.SetFont(*m_pgridFont);
6680 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6682 dc.GetTextExtent(s, &w, &h);
6688 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6692void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6697 double ra_max = 40.;
6699 wxPen pen_save = dc.GetPen();
6701 wxDateTime now = wxDateTime::Now();
6707 x0 = x1 = x + radius;
6712 while (angle < 360.) {
6713 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6716 if (angle > 360.) angle = 360.;
6718 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6726 x1 = (int)(x + cos(angle * PI / 180.) * r);
6727 y1 = (int)(y + sin(angle * PI / 180.) * r);
6737 dc.
DrawLine(x + radius, y, x1, y1);
6739 dc.SetPen(pen_save);
6742static bool bAnchorSoundPlaying =
false;
6744static void onAnchorSoundFinished(
void *ptr) {
6745 o_sound::g_anchorwatch_sound->UnLoad();
6746 bAnchorSoundPlaying =
false;
6749void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6750 using namespace o_sound;
6752 bool play_sound =
false;
6754 if (AnchorAlertOn1) {
6755 wxPoint TargetPoint;
6758 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6759 TargetPoint.y, 100);
6763 AnchorAlertOn1 =
false;
6766 if (AnchorAlertOn2) {
6767 wxPoint TargetPoint;
6770 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6771 TargetPoint.y, 100);
6775 AnchorAlertOn2 =
false;
6778 if (!bAnchorSoundPlaying) {
6779 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6780 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6781 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6782 if (g_anchorwatch_sound->IsOk()) {
6783 bAnchorSoundPlaying =
true;
6784 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6785 g_anchorwatch_sound->Play();
6791void ChartCanvas::UpdateShips() {
6794 wxClientDC dc(
this);
6795 if (!dc.IsOk())
return;
6797 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6798 if (!test_bitmap.IsOk())
return;
6800 wxMemoryDC temp_dc(test_bitmap);
6802 temp_dc.ResetBoundingBox();
6803 temp_dc.DestroyClippingRegion();
6804 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6815 ocpndc.CalcBoundingBox(px.x, px.y);
6820 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6821 temp_dc.MaxY() - temp_dc.MinY());
6823 wxRect own_ship_update_rect = ship_draw_rect;
6825 if (!own_ship_update_rect.IsEmpty()) {
6828 own_ship_update_rect.Union(ship_draw_last_rect);
6829 own_ship_update_rect.Inflate(2);
6832 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6834 ship_draw_last_rect = ship_draw_rect;
6836 temp_dc.SelectObject(wxNullBitmap);
6839void ChartCanvas::UpdateAlerts() {
6844 wxClientDC dc(
this);
6848 dc.GetSize(&sx, &sy);
6851 wxBitmap test_bitmap(sx, sy, -1);
6855 temp_dc.SelectObject(test_bitmap);
6857 temp_dc.ResetBoundingBox();
6858 temp_dc.DestroyClippingRegion();
6859 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6866 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6867 temp_dc.MaxX() - temp_dc.MinX(),
6868 temp_dc.MaxY() - temp_dc.MinY());
6870 if (!alert_rect.IsEmpty())
6871 alert_rect.Inflate(2);
6873 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6876 wxRect alert_update_rect = alert_draw_rect;
6877 alert_update_rect.Union(alert_rect);
6880 RefreshRect(alert_update_rect,
false);
6884 alert_draw_rect = alert_rect;
6886 temp_dc.SelectObject(wxNullBitmap);
6889void ChartCanvas::UpdateAIS() {
6895 wxClientDC dc(
this);
6899 dc.GetSize(&sx, &sy);
6907 if (
g_pAIS->GetTargetList().size() > 10) {
6908 ais_rect = wxRect(0, 0, sx, sy);
6911 wxBitmap test_bitmap(sx, sy, -1);
6915 temp_dc.SelectObject(test_bitmap);
6917 temp_dc.ResetBoundingBox();
6918 temp_dc.DestroyClippingRegion();
6919 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6923 AISDraw(ocpndc, GetVP(),
this);
6924 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6928 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6929 temp_dc.MaxY() - temp_dc.MinY());
6931 if (!ais_rect.IsEmpty())
6932 ais_rect.Inflate(2);
6934 temp_dc.SelectObject(wxNullBitmap);
6937 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6940 wxRect ais_update_rect = ais_draw_rect;
6941 ais_update_rect.Union(ais_rect);
6944 RefreshRect(ais_update_rect,
false);
6948 ais_draw_rect = ais_rect;
6951void ChartCanvas::ToggleCPAWarn() {
6952 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6958 g_bTCPA_Max =
false;
6962 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6963 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6965 if (!g_AisFirstTimeUse) {
6966 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
6967 _(
"CPA") +
" " + mess, 4, 4);
6972void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6974void ChartCanvas::OnSize(wxSizeEvent &event) {
6975 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6977 GetClientSize(&m_canvas_width, &m_canvas_height);
6981 m_displayScale = GetContentScaleFactor();
6985 m_canvas_width *= m_displayScale;
6986 m_canvas_height *= m_displayScale;
6999 m_absolute_min_scale_ppm =
7001 (1.2 * WGS84_semimajor_axis_meters * PI);
7004 gFrame->ProcessCanvasResize();
7014 SetMUIBarPosition();
7015 UpdateFollowButtonState();
7016 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7020 xr_margin = m_canvas_width * 95 / 100;
7021 xl_margin = m_canvas_width * 5 / 100;
7022 yt_margin = m_canvas_height * 5 / 100;
7023 yb_margin = m_canvas_height * 95 / 100;
7026 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7031 m_brepaint_piano =
true;
7034 m_dc_route.SelectObject(wxNullBitmap);
7037 m_dc_route.SelectObject(*proute_bm);
7051 m_glcc->OnSize(event);
7060void ChartCanvas::ProcessNewGUIScale() {
7068void ChartCanvas::CreateMUIBar() {
7069 if (g_useMUI && !m_muiBar) {
7070 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7071 m_muiBar->SetColorScheme(m_cs);
7072 m_muiBarHOSize = m_muiBar->m_size;
7080 SetMUIBarPosition();
7081 UpdateFollowButtonState();
7082 m_muiBar->UpdateDynamicValues();
7083 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7087void ChartCanvas::SetMUIBarPosition() {
7091 int pianoWidth = GetClientSize().x * 0.6f;
7096 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7097 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7099 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7100 m_muiBar->SetColorScheme(m_cs);
7104 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7105 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7107 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7108 m_muiBar->SetColorScheme(m_cs);
7112 m_muiBar->SetBestPosition();
7116void ChartCanvas::DestroyMuiBar() {
7123void ChartCanvas::ShowCompositeInfoWindow(
7124 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7126 if (NULL == m_pCIWin) {
7131 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7134 s = _(
"Composite of ");
7137 s1.Printf(
"%d ", n_charts);
7145 s1.Printf(_(
"Chart scale"));
7148 s2.Printf(
"1:%d\n",
scale);
7152 s1 = _(
"Zoom in for more information");
7156 int char_width = s1.Length();
7157 int char_height = 3;
7159 if (g_bChartBarEx) {
7162 for (
int i : index_vector) {
7164 wxString path = cte.GetFullSystemPath();
7168 char_width = wxMax(char_width, path.Length());
7169 if (j++ >= 9)
break;
7172 s +=
" .\n .\n .\n";
7181 m_pCIWin->SetString(s);
7183 m_pCIWin->FitToChars(char_width, char_height);
7186 p.x = x / GetContentScaleFactor();
7187 if ((p.x + m_pCIWin->GetWinSize().x) >
7188 (m_canvas_width / GetContentScaleFactor()))
7189 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7190 m_pCIWin->GetWinSize().x) /
7193 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7194 4 - m_pCIWin->GetWinSize().y;
7196 m_pCIWin->dbIndex = 0;
7197 m_pCIWin->chart_scale = 0;
7198 m_pCIWin->SetPosition(p);
7199 m_pCIWin->SetBitmap();
7200 m_pCIWin->Refresh();
7204 HideChartInfoWindow();
7208void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7210 if (NULL == m_pCIWin) {
7215 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7224 dbIndex, FULL_INIT);
7226 int char_width, char_height;
7227 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7228 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7230 m_pCIWin->SetString(s);
7231 m_pCIWin->FitToChars(char_width, char_height);
7234 p.x = x / GetContentScaleFactor();
7235 if ((p.x + m_pCIWin->GetWinSize().x) >
7236 (m_canvas_width / GetContentScaleFactor()))
7237 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7238 m_pCIWin->GetWinSize().x) /
7241 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7242 4 - m_pCIWin->GetWinSize().y;
7244 m_pCIWin->dbIndex = dbIndex;
7245 m_pCIWin->SetPosition(p);
7246 m_pCIWin->SetBitmap();
7247 m_pCIWin->Refresh();
7251 HideChartInfoWindow();
7255void ChartCanvas::HideChartInfoWindow() {
7258 m_pCIWin->Destroy();
7262 androidForceFullRepaint();
7267void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7268 wxMouseEvent ev(wxEVT_MOTION);
7271 ev.m_leftDown = mouse_leftisdown;
7273 wxEvtHandler *evthp = GetEventHandler();
7275 ::wxPostEvent(evthp, ev);
7278void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7279 if ((m_panx_target_final - m_panx_target_now) ||
7280 (m_pany_target_final - m_pany_target_now)) {
7281 DoTimedMovementTarget();
7286void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7288bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7290 if (m_disable_edge_pan)
return false;
7293 int pan_margin = m_canvas_width * margin / 100;
7294 int pan_timer_set = 200;
7295 double pan_delta = GetVP().
pix_width * delta / 100;
7299 if (x > m_canvas_width - pan_margin) {
7304 else if (x < pan_margin) {
7309 if (y < pan_margin) {
7314 else if (y > m_canvas_height - pan_margin) {
7323 wxMouseState state = ::wxGetMouseState();
7324#if wxCHECK_VERSION(3, 0, 0)
7325 if (!state.LeftIsDown())
7327 if (!state.LeftDown())
7332 if ((bft) && !pPanTimer->IsRunning()) {
7334 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7340 if ((!bft) && pPanTimer->IsRunning()) {
7350void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7351 bool setBeingEdited) {
7352 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7353 m_pRoutePointEditTarget = NULL;
7354 m_pFoundPoint = NULL;
7357 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7358 SelectableItemList SelList =
pSelect->FindSelectionList(
7368 bool brp_viz =
false;
7369 if (m_pEditRouteArray) {
7370 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7371 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7372 if (pr->IsVisible()) {
7378 brp_viz = frp->IsVisible();
7382 if (m_pEditRouteArray)
7384 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7385 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7388 m_bRouteEditing = setBeingEdited;
7391 frp->m_bRPIsBeingEdited = setBeingEdited;
7392 m_bMarkEditing = setBeingEdited;
7395 m_pRoutePointEditTarget = frp;
7396 m_pFoundPoint = pFind;
7401std::shared_ptr<PI_PointContext> ChartCanvas::GetCanvasContextAtPoint(
int x,
7416 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7417 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7418 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7419 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7420 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7424 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7427 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7432 int FoundAIS_MMSI = 0;
7434 FoundAIS_MMSI = pFindAIS->GetUserData();
7437 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7438 seltype |= SELTYPE_AISTARGET;
7444 Route *SelectedRoute = NULL;
7450 Route *pSelectedActiveRoute = NULL;
7451 Route *pSelectedVizRoute = NULL;
7454 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7455 SelectableItemList SelList =
7456 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7464 bool brp_viz =
false;
7466 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7468 if (pr->IsVisible()) {
7473 if (!brp_viz && prp->IsShared())
7475 brp_viz = prp->IsVisible();
7478 brp_viz = prp->IsVisible();
7480 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7486 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7489 pSelectedActiveRoute = pr;
7490 pFoundActiveRoutePoint = prp;
7495 if (NULL == pSelectedVizRoute) {
7496 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7498 if (pr->IsVisible()) {
7499 pSelectedVizRoute = pr;
7500 pFoundVizRoutePoint = prp;
7506 delete proute_array;
7511 if (pFoundActiveRoutePoint) {
7512 FoundRoutePoint = pFoundActiveRoutePoint;
7513 SelectedRoute = pSelectedActiveRoute;
7514 }
else if (pFoundVizRoutePoint) {
7515 FoundRoutePoint = pFoundVizRoutePoint;
7516 SelectedRoute = pSelectedVizRoute;
7519 FoundRoutePoint = pFirstVizPoint;
7521 if (SelectedRoute) {
7522 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7523 }
else if (FoundRoutePoint) {
7524 seltype |= SELTYPE_MARKPOINT;
7529 if (m_pFoundRoutePoint) {
7533 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7534 RefreshRect(wp_rect,
true);
7543 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7544 SelectableItemList SelList =
7545 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7547 if (NULL == SelectedRoute)
7552 if (pr->IsVisible()) {
7559 if (SelectedRoute) {
7560 if (NULL == FoundRoutePoint)
7561 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7564 seltype |= SELTYPE_ROUTESEGMENT;
7569 if (pFindTrackSeg) {
7570 m_pSelectedTrack = NULL;
7571 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7572 SelectableItemList SelList =
7573 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7576 wxSelectableItemListNode *node = SelList.GetFirst();
7581 if (pt->IsVisible()) {
7582 m_pSelectedTrack = pt;
7585 node = node->GetNext();
7588 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7593 bool bseltc =
false;
7606 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7607 SelectableItemList SelList =
pSelectTC->FindSelectionList(
7611 wxSelectableItemListNode *node = SelList.GetFirst();
7612 pFind = node->GetData();
7613 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7615 if (SelList.GetCount() > 1) {
7616 node = node->GetNext();
7618 pFind = node->GetData();
7620 if (pIDX_candidate->
IDX_type ==
'c') {
7621 pIDX_best_candidate = pIDX_candidate;
7625 node = node->GetNext();
7628 wxSelectableItemListNode *node = SelList.GetFirst();
7629 pFind = node->GetData();
7630 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7633 m_pIDXCandidate = pIDX_best_candidate;
7640 seltype |= SELTYPE_CURRENTPOINT;
7643 else if (pFindTide) {
7644 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7651 seltype |= SELTYPE_TIDEPOINT;
7656 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7659 auto rstruct = std::make_shared<PI_PointContext>();
7660 rstruct->object_type = OBJECT_CHART;
7661 rstruct->object_ident =
"";
7663 if (seltype == SELTYPE_AISTARGET) {
7664 rstruct->object_type = OBJECT_AISTARGET;
7666 val.Printf(
"%d", FoundAIS_MMSI);
7667 rstruct->object_ident = val.ToStdString();
7668 }
else if (seltype & SELTYPE_MARKPOINT) {
7669 if (FoundRoutePoint) {
7670 rstruct->object_type = OBJECT_ROUTEPOINT;
7671 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7673 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7674 if (SelectedRoute) {
7675 rstruct->object_type = OBJECT_ROUTESEGMENT;
7676 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7683void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7684 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7685 singleClickEventIsValid =
false;
7686 m_DoubleClickTimer->Stop();
7691bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7692 if (!m_bChartDragging && !m_bDrawingRoute) {
7697 if (m_Compass && m_Compass->IsShown()) {
7699 bool isInCompass = logicalRect.Contains(event.GetPosition());
7700 if (isInCompass || m_mouseWasInCompass) {
7701 if (m_Compass->MouseEvent(event)) {
7702 cursor_region = CENTER;
7703 if (!g_btouch) SetCanvasCursor(event);
7704 m_mouseWasInCompass = isInCompass;
7708 m_mouseWasInCompass = isInCompass;
7711 if (m_notification_button && m_notification_button->IsShown()) {
7713 bool isinButton = logicalRect.Contains(event.GetPosition());
7715 SetCursor(*pCursorArrow);
7716 if (event.LeftDown()) HandleNotificationMouseClick();
7721 if (MouseEventToolbar(event))
return true;
7723 if (MouseEventChartBar(event))
return true;
7725 if (MouseEventMUIBar(event))
return true;
7727 if (MouseEventIENCBar(event))
return true;
7732void ChartCanvas::HandleNotificationMouseClick() {
7733 if (!m_NotificationsList) {
7737 m_NotificationsList->RecalculateSize();
7738 m_NotificationsList->Hide();
7741 if (m_NotificationsList->IsShown()) {
7742 m_NotificationsList->Hide();
7744 m_NotificationsList->RecalculateSize();
7745 m_NotificationsList->ReloadNotificationList();
7746 m_NotificationsList->Show();
7749bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7750 if (!g_bShowChartBar)
return false;
7752 if (!m_Piano->MouseEvent(event))
return false;
7754 cursor_region = CENTER;
7755 if (!g_btouch) SetCanvasCursor(event);
7759bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7760 if (!IsPrimaryCanvas())
return false;
7769 cursor_region = CENTER;
7770 if (!g_btouch) SetCanvasCursor(event);
7774bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7775 if (!IsPrimaryCanvas())
return false;
7788bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7790 if (!m_muiBar->MouseEvent(event))
return false;
7793 cursor_region = CENTER;
7794 if (!g_btouch) SetCanvasCursor(event);
7806 event.GetPosition(&x, &y);
7808 x *= m_displayScale;
7809 y *= m_displayScale;
7811 m_MouseDragging =
event.Dragging();
7817 if (event.Dragging()) {
7818 if ((x == mouse_x) && (y == mouse_y))
return true;
7824 mouse_leftisdown =
event.LeftDown();
7828 cursor_region = CENTER;
7832 if (m_Compass && m_Compass->IsShown() &&
7833 m_Compass->
GetRect().Contains(event.GetPosition())) {
7834 cursor_region = CENTER;
7835 }
else if (x > xr_margin) {
7836 cursor_region = MID_RIGHT;
7837 }
else if (x < xl_margin) {
7838 cursor_region = MID_LEFT;
7839 }
else if (y > yb_margin - chartbar_height &&
7840 y < m_canvas_height - chartbar_height) {
7841 cursor_region = MID_TOP;
7842 }
else if (y < yt_margin) {
7843 cursor_region = MID_BOT;
7845 cursor_region = CENTER;
7848 if (!g_btouch) SetCanvasCursor(event);
7852 leftIsDown =
event.LeftDown();
7855 if (event.LeftDown()) {
7856 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7859 g_bTempShowMenuBar =
false;
7860 parent_frame->ApplyGlobalSettings(
false);
7868 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7869 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7873 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7874 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7877 event.SetEventObject(
this);
7878 if (SendMouseEventToPlugins(event))
7885 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7886 StartChartDragInertia();
7889 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7891 if (m_DoubleClickTimer->IsRunning()) {
7892 m_DoubleClickTimer->Stop();
7897 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7898 singleClickEvent = event;
7899 singleClickEventIsValid =
true;
7908 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7909 if (g_click_stop > 0) {
7917 if (GetUpMode() == COURSE_UP_MODE) {
7918 m_b_rot_hidef =
false;
7919 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7921 pRotDefTimer->Stop();
7924 bool bRoll = !g_btouch;
7929 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7930 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7931 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7932 m_RolloverPopupTimer.Start(
7936 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7940 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7949#if !defined(__WXGTK__) && !defined(__WXQT__)
7957 if ((x >= 0) && (y >= 0))
7962 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7963 wxPoint p = ClientToScreen(wxPoint(x, y));
7969 if (m_routeState >= 2) {
7972 m_bDrawingRoute =
true;
7974 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7979 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7982 m_bDrawingRoute =
true;
7984 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7997#if defined(__WXMAC__) || defined(__ANDROID__)
8001 wxClientDC cdc(GetParent());
8013 if (m_pSelectedRoute) {
8015 m_pSelectedRoute->DeSelectRoute();
8017 if (g_bopengl && m_glcc) {
8022 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8025 if (m_pFoundRoutePoint) {
8033 if (g_btouch && m_pRoutePointEditTarget) {
8036 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8040 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8041 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8042 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8043 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8044 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8048 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8051 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8057 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8060 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8061 seltype |= SELTYPE_AISTARGET;
8066 m_pFoundRoutePoint = NULL;
8071 Route *pSelectedActiveRoute = NULL;
8072 Route *pSelectedVizRoute = NULL;
8075 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8076 SelectableItemList SelList =
8077 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8085 bool brp_viz =
false;
8087 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8089 if (pr->IsVisible()) {
8094 if (!brp_viz && prp->IsShared())
8096 brp_viz = prp->IsVisible();
8099 brp_viz = prp->IsVisible();
8101 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8106 m_pSelectedRoute = NULL;
8108 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8111 pSelectedActiveRoute = pr;
8112 pFoundActiveRoutePoint = prp;
8117 if (NULL == pSelectedVizRoute) {
8118 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8120 if (pr->IsVisible()) {
8121 pSelectedVizRoute = pr;
8122 pFoundVizRoutePoint = prp;
8128 delete proute_array;
8133 if (pFoundActiveRoutePoint) {
8134 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8135 m_pSelectedRoute = pSelectedActiveRoute;
8136 }
else if (pFoundVizRoutePoint) {
8137 m_pFoundRoutePoint = pFoundVizRoutePoint;
8138 m_pSelectedRoute = pSelectedVizRoute;
8141 m_pFoundRoutePoint = pFirstVizPoint;
8143 if (m_pSelectedRoute) {
8144 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8145 }
else if (m_pFoundRoutePoint) {
8146 seltype |= SELTYPE_MARKPOINT;
8150 if (m_pFoundRoutePoint) {
8154 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8155 RefreshRect(wp_rect,
true);
8163 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8164 SelectableItemList SelList =
8165 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8167 if (NULL == m_pSelectedRoute)
8172 if (pr->IsVisible()) {
8173 m_pSelectedRoute = pr;
8179 if (m_pSelectedRoute) {
8180 if (NULL == m_pFoundRoutePoint)
8181 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8186 if (g_bopengl && m_glcc) {
8191 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8193 seltype |= SELTYPE_ROUTESEGMENT;
8197 if (pFindTrackSeg) {
8198 m_pSelectedTrack = NULL;
8199 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8200 SelectableItemList SelList =
8201 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8206 if (pt->IsVisible()) {
8207 m_pSelectedTrack = pt;
8211 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8225 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8226 SelectableItemList SelList =
8227 pSelectTC->FindSelectionList(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8230 pFind = *SelList.begin();
8231 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8233 auto node = SelList.begin();
8234 if (SelList.size() > 1) {
8235 for (++node; node != SelList.end(); ++node) {
8238 if (pIDX_candidate->
IDX_type ==
'c') {
8239 pIDX_best_candidate = pIDX_candidate;
8244 pFind = *SelList.begin();
8245 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8248 m_pIDXCandidate = pIDX_best_candidate;
8249 seltype |= SELTYPE_CURRENTPOINT;
8252 else if (pFindTide) {
8253 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8254 seltype |= SELTYPE_TIDEPOINT;
8258 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8263void ChartCanvas::CallPopupMenu(
int x,
int y) {
8267 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8275 if (SELTYPE_CURRENTPOINT == seltype) {
8281 if (SELTYPE_TIDEPOINT == seltype) {
8287 InvokeCanvasMenu(x, y, seltype);
8290 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8294 m_pSelectedRoute = NULL;
8296 if (m_pFoundRoutePoint) {
8297 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8300 m_pFoundRoutePoint = NULL;
8306bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8314 event.GetPosition(&x, &y);
8320 SelectRadius = g_Platform->GetSelectRadiusPix() /
8321 (m_true_scale_ppm * 1852 * 60);
8328 if (event.LeftDClick() && (cursor_region == CENTER)) {
8329 m_DoubleClickTimer->Start();
8330 singleClickEventIsValid =
false;
8336 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8339 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8342 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8343 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8344 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8350 SelectableItemList rpSelList =
8351 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8352 bool b_onRPtarget =
false;
8355 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8356 b_onRPtarget =
true;
8363 if (m_pRoutePointEditTarget) {
8365 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8371 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8374 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8375 m_pRoutePointEditTarget = NULL;
8376 RefreshRect(wp_rect,
true);
8380 auto node = rpSelList.begin();
8381 if (node != rpSelList.end()) {
8385 wxArrayPtrVoid *proute_array =
8390 bool brp_viz =
false;
8392 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8394 if (pr->IsVisible()) {
8399 delete proute_array;
8403 brp_viz = frp->IsVisible();
8405 brp_viz = frp->IsVisible();
8408 ShowMarkPropertiesDialog(frp);
8416 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8420 if (pr->IsVisible()) {
8421 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8426 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8430 if (pt->IsVisible()) {
8431 ShowTrackPropertiesDialog(pt);
8438 ShowObjectQueryWindow(x, y, zlat, zlon);
8443 if (event.LeftDown()) {
8459 bool appending =
false;
8460 bool inserting =
false;
8463 SetCursor(*pCursorPencil);
8467 m_bRouteEditing =
true;
8469 if (m_routeState == 1) {
8470 m_pMouseRoute =
new Route();
8471 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8481 double nearby_radius_meters =
8482 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8485 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8486 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8487 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8488 wxArrayPtrVoid *proute_array =
8493 bool brp_viz =
false;
8495 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8497 if (pr->IsVisible()) {
8502 delete proute_array;
8504 pNearbyPoint->IsShared())
8507 pNearbyPoint->IsVisible();
8509 brp_viz = pNearbyPoint->IsVisible();
8512 wxString msg = _(
"Use nearby waypoint?");
8514 const bool noname(pNearbyPoint->GetName() ==
"");
8517 _(
"Use nearby nameless waypoint and name it M with"
8518 " a unique number?");
8521 m_FinishRouteOnKillFocus =
false;
8523 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8524 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8525 m_FinishRouteOnKillFocus =
true;
8526 if (dlg_return == wxID_YES) {
8528 if (m_pMouseRoute) {
8529 int last_wp_num = m_pMouseRoute->GetnPoints();
8531 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8532 wxString wp_name = wxString::Format(
8533 "M%002i-%s", last_wp_num + 1, guid_short);
8534 pNearbyPoint->SetName(wp_name);
8536 pNearbyPoint->SetName(
"WPXX");
8538 pMousePoint = pNearbyPoint;
8541 if (m_routeState > 1)
8542 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8543 Undo_HasParent, NULL);
8546 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8547 bool procede =
false;
8551 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8557 m_FinishRouteOnKillFocus =
false;
8563 _(
"Insert first part of this route in the new route?");
8564 if (tail->GetIndexOf(pMousePoint) ==
8567 dmsg = _(
"Insert this route in the new route?");
8569 if (tail->GetIndexOf(pMousePoint) != 1) {
8570 dlg_return = OCPNMessageBox(
8571 this, dmsg, _(
"OpenCPN Route Create"),
8572 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8573 m_FinishRouteOnKillFocus =
true;
8575 if (dlg_return == wxID_YES) {
8582 _(
"Append last part of this route to the new route?");
8583 if (tail->GetIndexOf(pMousePoint) == 1)
8585 "Append this route to the new route?");
8590 if (tail->GetLastPoint() != pMousePoint) {
8591 dlg_return = OCPNMessageBox(
8592 this, dmsg, _(
"OpenCPN Route Create"),
8593 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8594 m_FinishRouteOnKillFocus =
true;
8596 if (dlg_return == wxID_YES) {
8607 if (!FindRouteContainingWaypoint(pMousePoint))
8608 pMousePoint->SetShared(
true);
8613 if (NULL == pMousePoint) {
8614 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8616 pMousePoint->SetNameShown(
false);
8620 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8622 if (m_routeState > 1)
8623 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8624 Undo_IsOrphanded, NULL);
8627 if (m_pMouseRoute) {
8628 if (m_routeState == 1) {
8630 m_pMouseRoute->AddPoint(pMousePoint);
8634 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8635 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8636 &rhumbBearing, &rhumbDist);
8637 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8638 rlat, &gcDist, &gcBearing, NULL);
8639 double gcDistNM = gcDist / 1852.0;
8642 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8643 pow(rhumbDist - gcDistNM - 1, 0.5);
8646 msg << _(
"For this leg the Great Circle route is ")
8648 << _(
" shorter than rhumbline.\n\n")
8649 << _(
"Would you like include the Great Circle routing points "
8652 m_FinishRouteOnKillFocus =
false;
8653 m_disable_edge_pan =
true;
8656 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8657 wxYES_NO | wxNO_DEFAULT);
8659 m_disable_edge_pan =
false;
8660 m_FinishRouteOnKillFocus =
true;
8662 if (answer == wxID_YES) {
8664 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8665 wxRealPoint gcCoord;
8667 for (
int i = 1; i <= segmentCount; i++) {
8668 double fraction = (double)i * (1.0 / (
double)segmentCount);
8669 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8670 gcDist * fraction, gcBearing,
8671 &gcCoord.x, &gcCoord.y, NULL);
8673 if (i < segmentCount) {
8674 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8676 gcPoint->SetNameShown(
false);
8678 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8680 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8683 gcPoint = pMousePoint;
8686 m_pMouseRoute->AddPoint(gcPoint);
8687 pSelect->AddSelectableRouteSegment(
8688 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8689 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8690 prevGcPoint = gcPoint;
8693 undo->CancelUndoableAction(
true);
8696 m_pMouseRoute->AddPoint(pMousePoint);
8697 pSelect->AddSelectableRouteSegment(
8698 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8699 pMousePoint, m_pMouseRoute);
8700 undo->AfterUndoableAction(m_pMouseRoute);
8704 m_pMouseRoute->AddPoint(pMousePoint);
8705 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8706 rlon, m_prev_pMousePoint,
8707 pMousePoint, m_pMouseRoute);
8708 undo->AfterUndoableAction(m_pMouseRoute);
8714 m_prev_pMousePoint = pMousePoint;
8722 int connect = tail->GetIndexOf(pMousePoint);
8727 int length = tail->GetnPoints();
8732 start = connect + 1;
8737 m_pMouseRoute->RemovePoint(
8741 for (i = start; i <= stop; i++) {
8742 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8745 m_pMouseRoute->GetnPoints();
8747 gFrame->RefreshAllCanvas();
8751 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8753 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8754 m_pMouseRoute->FinalizeForRendering();
8756 gFrame->RefreshAllCanvas();
8760 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8762 SetCursor(*pCursorPencil);
8764 if (!m_pMeasureRoute) {
8765 m_pMeasureRoute =
new Route();
8769 if (m_nMeasureState == 1) {
8776 wxEmptyString, wxEmptyString);
8778 pMousePoint->SetShowWaypointRangeRings(
false);
8780 m_pMeasureRoute->AddPoint(pMousePoint);
8784 m_prev_pMousePoint = pMousePoint;
8788 gFrame->RefreshAllCanvas();
8793 FindRoutePointsAtCursor(SelectRadius,
true);
8798 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8806 if (ret)
return true;
8809 if (event.Dragging()) {
8812 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8814 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8816 SelectableItemList SelList =
pSelect->FindSelectionList(
8820 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8825 if (m_pRoutePointEditTarget &&
8826 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8828 SelectableItemList SelList =
pSelect->FindSelectionList(
8832 if (m_pRoutePointEditTarget == frp) {
8833 m_bIsInRadius =
true;
8838 if (!m_dragoffsetSet) {
8840 .PresetDragOffset(
this, mouse_x, mouse_y);
8841 m_dragoffsetSet =
true;
8846 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8847 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8850 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8852 DraggingAllowed =
false;
8854 if (m_pRoutePointEditTarget &&
8855 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8856 DraggingAllowed =
false;
8858 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8860 if (DraggingAllowed) {
8861 if (!undo->InUndoableAction()) {
8862 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8863 Undo_NeedsCopy, m_pFoundPoint);
8869 if (!g_bopengl && m_pEditRouteArray) {
8870 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8871 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8878 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8879 pre_rect.Union(route_rect);
8887 if (CheckEdgePan(x, y,
true, 5, 2))
8895 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8897 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8898 m_pRoutePointEditTarget,
8899 SELTYPE_DRAGHANDLE);
8900 m_pFoundPoint->m_slat =
8901 m_pRoutePointEditTarget->m_lat;
8902 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8904 m_pRoutePointEditTarget->m_lat =
8906 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8907 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8908 m_pFoundPoint->m_slat =
8910 m_pFoundPoint->m_slon = new_cursor_lon;
8926 if (m_pEditRouteArray) {
8927 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8929 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8932 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8933 post_rect.Union(route_rect);
8939 pre_rect.Union(post_rect);
8940 RefreshRect(pre_rect,
false);
8942 gFrame->RefreshCanvasOther(
this);
8943 m_bRoutePoinDragging =
true;
8948 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8949 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8952 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8954 DraggingAllowed =
false;
8956 if (m_pRoutePointEditTarget &&
8957 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8958 DraggingAllowed =
false;
8960 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8962 if (DraggingAllowed) {
8963 if (!undo->InUndoableAction()) {
8964 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8965 Undo_NeedsCopy, m_pFoundPoint);
8979 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8985 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8986 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8987 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8988 (
int)(lppmax - (pre_rect.height / 2)));
8996 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8999 m_pRoutePointEditTarget,
9000 SELTYPE_DRAGHANDLE);
9001 m_pFoundPoint->m_slat =
9002 m_pRoutePointEditTarget->m_lat;
9003 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9005 m_pRoutePointEditTarget->m_lat =
9008 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9021 if (!g_btouch) InvalidateGL();
9027 .CalculateDCRect(m_dc_route,
this, &post_rect);
9028 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9029 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9030 (
int)(lppmax - (post_rect.height / 2)));
9033 pre_rect.Union(post_rect);
9034 RefreshRect(pre_rect,
false);
9036 gFrame->RefreshCanvasOther(
this);
9037 m_bRoutePoinDragging =
true;
9042 if (ret)
return true;
9045 if (event.LeftUp()) {
9046 bool b_startedit_route =
false;
9047 m_dragoffsetSet =
false;
9050 m_bChartDragging =
false;
9051 m_bIsInRadius =
false;
9056 m_bedge_pan =
false;
9061 bool appending =
false;
9062 bool inserting =
false;
9068 if (m_pRoutePointEditTarget) {
9074 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9075 RefreshRect(wp_rect,
true);
9077 m_pRoutePointEditTarget = NULL;
9079 m_bRouteEditing =
true;
9081 if (m_routeState == 1) {
9082 m_pMouseRoute =
new Route();
9083 m_pMouseRoute->SetHiLite(50);
9087 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9094 double nearby_radius_meters =
9095 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9098 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9099 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9100 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9103 m_FinishRouteOnKillFocus =
9105 dlg_return = OCPNMessageBox(
9106 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9107 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9108 m_FinishRouteOnKillFocus =
true;
9110 dlg_return = wxID_YES;
9112 if (dlg_return == wxID_YES) {
9113 pMousePoint = pNearbyPoint;
9116 if (m_routeState > 1)
9117 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9118 Undo_HasParent, NULL);
9119 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9121 bool procede =
false;
9125 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9131 m_FinishRouteOnKillFocus =
false;
9132 if (m_routeState == 1) {
9136 _(
"Insert first part of this route in the new route?");
9137 if (tail->GetIndexOf(pMousePoint) ==
9140 dmsg = _(
"Insert this route in the new route?");
9142 if (tail->GetIndexOf(pMousePoint) != 1) {
9144 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9145 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9146 m_FinishRouteOnKillFocus =
true;
9148 if (dlg_return == wxID_YES) {
9155 _(
"Append last part of this route to the new route?");
9156 if (tail->GetIndexOf(pMousePoint) == 1)
9158 "Append this route to the new route?");
9162 if (tail->GetLastPoint() != pMousePoint) {
9164 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9165 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9166 m_FinishRouteOnKillFocus =
true;
9168 if (dlg_return == wxID_YES) {
9179 if (!FindRouteContainingWaypoint(pMousePoint))
9180 pMousePoint->SetShared(
true);
9184 if (NULL == pMousePoint) {
9185 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9187 pMousePoint->SetNameShown(
false);
9189 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9191 if (m_routeState > 1)
9192 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9193 Undo_IsOrphanded, NULL);
9196 if (m_routeState == 1) {
9198 m_pMouseRoute->AddPoint(pMousePoint);
9199 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9203 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9204 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9205 &rhumbBearing, &rhumbDist);
9206 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9207 &gcDist, &gcBearing, NULL);
9208 double gcDistNM = gcDist / 1852.0;
9211 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9212 pow(rhumbDist - gcDistNM - 1, 0.5);
9215 msg << _(
"For this leg the Great Circle route is ")
9217 << _(
" shorter than rhumbline.\n\n")
9218 << _(
"Would you like include the Great Circle routing points "
9222 m_FinishRouteOnKillFocus =
false;
9223 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9224 wxYES_NO | wxNO_DEFAULT);
9225 m_FinishRouteOnKillFocus =
true;
9227 int answer = wxID_NO;
9230 if (answer == wxID_YES) {
9232 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9233 wxRealPoint gcCoord;
9235 for (
int i = 1; i <= segmentCount; i++) {
9236 double fraction = (double)i * (1.0 / (
double)segmentCount);
9237 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9238 gcDist * fraction, gcBearing,
9239 &gcCoord.x, &gcCoord.y, NULL);
9241 if (i < segmentCount) {
9242 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9244 gcPoint->SetNameShown(
false);
9245 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9248 gcPoint = pMousePoint;
9251 m_pMouseRoute->AddPoint(gcPoint);
9252 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9254 pSelect->AddSelectableRouteSegment(
9255 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9256 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9257 prevGcPoint = gcPoint;
9260 undo->CancelUndoableAction(
true);
9263 m_pMouseRoute->AddPoint(pMousePoint);
9264 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9265 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9266 rlon, m_prev_pMousePoint,
9267 pMousePoint, m_pMouseRoute);
9268 undo->AfterUndoableAction(m_pMouseRoute);
9272 m_pMouseRoute->AddPoint(pMousePoint);
9273 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9275 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9276 rlon, m_prev_pMousePoint,
9277 pMousePoint, m_pMouseRoute);
9278 undo->AfterUndoableAction(m_pMouseRoute);
9284 m_prev_pMousePoint = pMousePoint;
9291 int connect = tail->GetIndexOf(pMousePoint);
9296 int length = tail->GetnPoints();
9301 start = connect + 1;
9306 m_pMouseRoute->RemovePoint(
9310 for (i = start; i <= stop; i++) {
9311 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9314 m_pMouseRoute->GetnPoints();
9316 gFrame->RefreshAllCanvas();
9320 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9322 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9323 m_pMouseRoute->FinalizeForRendering();
9328 }
else if (m_bMeasure_Active && m_nMeasureState)
9331 m_bedge_pan =
false;
9335 if (m_nMeasureState == 1) {
9336 m_pMeasureRoute =
new Route();
9342 if (m_pMeasureRoute) {
9345 wxEmptyString, wxEmptyString);
9348 m_pMeasureRoute->AddPoint(pMousePoint);
9352 m_prev_pMousePoint = pMousePoint;
9354 m_pMeasureRoute->GetnPoints();
9358 CancelMeasureRoute();
9364 bool bSelectAllowed =
true;
9366 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9368 bSelectAllowed =
false;
9375 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9377 if (bSelectAllowed) {
9378 bool b_was_editing_mark = m_bMarkEditing;
9379 bool b_was_editing_route = m_bRouteEditing;
9380 FindRoutePointsAtCursor(SelectRadius,
9386 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9387 m_pRoutePointEditTarget = NULL;
9389 if (!b_was_editing_route) {
9390 if (m_pEditRouteArray) {
9391 b_startedit_route =
true;
9395 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9396 m_pTrackRolloverWin->IsActive(
false);
9398 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9399 m_pRouteRolloverWin->IsActive(
false);
9403 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9405 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9413 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9414 pre_rect.Union(route_rect);
9417 RefreshRect(pre_rect,
true);
9420 b_startedit_route =
false;
9424 if (m_pRoutePointEditTarget) {
9425 if (b_was_editing_mark ||
9426 b_was_editing_route) {
9427 if (m_lastRoutePointEditTarget) {
9431 .EnableDragHandle(
false);
9432 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9433 SELTYPE_DRAGHANDLE);
9437 if (m_pRoutePointEditTarget) {
9440 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9441 wxPoint2DDouble dragHandlePoint =
9443 .GetDragHandlePoint(
this);
9445 dragHandlePoint.m_y, dragHandlePoint.m_x,
9446 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9449 if (m_lastRoutePointEditTarget) {
9453 .EnableDragHandle(
false);
9454 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9455 SELTYPE_DRAGHANDLE);
9458 wxArrayPtrVoid *lastEditRouteArray =
9460 m_lastRoutePointEditTarget);
9461 if (lastEditRouteArray) {
9462 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9464 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9469 delete lastEditRouteArray;
9480 if (m_lastRoutePointEditTarget) {
9483 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9484 RefreshRect(wp_rect,
true);
9487 if (m_pRoutePointEditTarget) {
9490 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9491 RefreshRect(wp_rect,
true);
9499 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9500 bool b_start_rollover =
false;
9504 if (pFind) b_start_rollover =
true;
9507 if (!b_start_rollover && !b_startedit_route) {
9508 SelectableItemList SelList =
pSelect->FindSelectionList(
9512 if (pr && pr->IsVisible()) {
9513 b_start_rollover =
true;
9519 if (!b_start_rollover && !b_startedit_route) {
9520 SelectableItemList SelList =
pSelect->FindSelectionList(
9524 if (tr && tr->IsVisible()) {
9525 b_start_rollover =
true;
9531 if (b_start_rollover)
9532 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9536 bool appending =
false;
9537 bool inserting =
false;
9539 if (m_bRouteEditing ) {
9541 if (m_pRoutePointEditTarget) {
9547 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9548 double nearby_radius_meters =
9549 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9550 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9551 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9552 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9554 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9558 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9560 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9564 std::find(list->begin(), list->end(), pNearbyPoint);
9565 if (pos != list->end()) {
9577 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9582 OCPNMessageBox(
this,
9583 _(
"Replace this RoutePoint by the nearby "
9585 _(
"OpenCPN RoutePoint change"),
9586 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9587 if (dlg_return == wxID_YES) {
9592 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9595 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9597 if (tail && current && (tail != current)) {
9599 connect = tail->GetIndexOf(pNearbyPoint);
9600 int index_current_route =
9601 current->GetIndexOf(m_pRoutePointEditTarget);
9602 index_last = current->GetIndexOf(current->GetLastPoint());
9603 dlg_return1 = wxID_NO;
9605 index_current_route) {
9607 if (connect != tail->GetnPoints()) {
9610 _(
"Last part of route to be appended to dragged "
9614 _(
"Full route to be appended to dragged route?");
9616 dlg_return1 = OCPNMessageBox(
9617 this, dmsg, _(
"OpenCPN Route Create"),
9618 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9619 if (dlg_return1 == wxID_YES) {
9623 }
else if (index_current_route ==
9628 _(
"First part of route to be inserted into dragged "
9630 if (connect == tail->GetnPoints())
9632 "Full route to be inserted into dragged route?");
9634 dlg_return1 = OCPNMessageBox(
9635 this, dmsg, _(
"OpenCPN Route Create"),
9636 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9637 if (dlg_return1 == wxID_YES) {
9644 if (m_pRoutePointEditTarget->IsShared()) {
9646 dlg_return = OCPNMessageBox(
9648 _(
"Do you really want to delete and replace this "
9650 "\n" + _(
"which has been created manually?"),
9651 (
"OpenCPN RoutePoint warning"),
9652 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9655 if (dlg_return == wxID_YES) {
9656 pMousePoint = pNearbyPoint;
9658 pMousePoint->SetShared(
true);
9668 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9670 if (m_pEditRouteArray) {
9671 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9673 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9678 auto pos = std::find(list->begin(), list->end(),
9679 m_pRoutePointEditTarget);
9681 pSelect->DeleteAllSelectableRoutePoints(pr);
9682 pSelect->DeleteAllSelectableRouteSegments(pr);
9685 pos = std::find(list->begin(), list->end(),
9686 m_pRoutePointEditTarget);
9689 pSelect->AddAllSelectableRouteSegments(pr);
9690 pSelect->AddAllSelectableRoutePoints(pr);
9692 pr->FinalizeForRendering();
9693 pr->UpdateSegmentDistances();
9694 if (m_bRoutePoinDragging) {
9696 NavObj_dB::GetInstance().UpdateRoute(pr);
9704 if (m_pEditRouteArray) {
9705 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9707 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9726 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9733 delete m_pRoutePointEditTarget;
9734 m_lastRoutePointEditTarget = NULL;
9735 m_pRoutePointEditTarget = NULL;
9736 undo->AfterUndoableAction(pMousePoint);
9737 undo->InvalidateUndo();
9742 else if (m_bMarkEditing) {
9743 if (m_pRoutePointEditTarget)
9744 if (m_bRoutePoinDragging) {
9746 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9750 if (m_pRoutePointEditTarget)
9751 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9753 if (!m_pRoutePointEditTarget) {
9754 delete m_pEditRouteArray;
9755 m_pEditRouteArray = NULL;
9756 m_bRouteEditing =
false;
9758 m_bRoutePoinDragging =
false;
9765 int length = tail->GetnPoints();
9766 for (
int i = connect + 1; i <= length; i++) {
9767 current->AddPointAndSegment(tail->GetPoint(i),
false);
9770 gFrame->RefreshAllCanvas();
9773 current->FinalizeForRendering();
9779 pSelect->DeleteAllSelectableRoutePoints(current);
9780 pSelect->DeleteAllSelectableRouteSegments(current);
9781 for (
int i = 1; i < connect; i++) {
9782 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9784 pSelect->AddAllSelectableRouteSegments(current);
9785 pSelect->AddAllSelectableRoutePoints(current);
9786 current->FinalizeForRendering();
9793 if (m_pEditRouteArray) {
9794 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9795 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9808 if (m_bRouteEditing) {
9811 bool appending =
false;
9812 bool inserting =
false;
9815 if (m_pRoutePointEditTarget) {
9816 m_pRoutePointEditTarget->
m_bBlink =
false;
9820 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9821 double nearby_radius_meters =
9822 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9823 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9824 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9825 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9827 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9828 bool duplicate =
false;
9830 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9832 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9836 std::find(list->begin(), list->end(), pNearbyPoint);
9837 if (pos != list->end()) {
9849 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9854 OCPNMessageBox(
this,
9855 _(
"Replace this RoutePoint by the nearby "
9857 _(
"OpenCPN RoutePoint change"),
9858 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9859 if (dlg_return == wxID_YES) {
9863 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9866 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9868 if (tail && current && (tail != current)) {
9870 connect = tail->GetIndexOf(pNearbyPoint);
9871 int index_current_route =
9872 current->GetIndexOf(m_pRoutePointEditTarget);
9873 index_last = current->GetIndexOf(current->GetLastPoint());
9874 dlg_return1 = wxID_NO;
9876 index_current_route) {
9878 if (connect != tail->GetnPoints()) {
9881 _(
"Last part of route to be appended to dragged "
9885 _(
"Full route to be appended to dragged route?");
9887 dlg_return1 = OCPNMessageBox(
9888 this, dmsg, _(
"OpenCPN Route Create"),
9889 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9890 if (dlg_return1 == wxID_YES) {
9894 }
else if (index_current_route ==
9899 _(
"First part of route to be inserted into dragged "
9901 if (connect == tail->GetnPoints())
9903 "Full route to be inserted into dragged route?");
9905 dlg_return1 = OCPNMessageBox(
9906 this, dmsg, _(
"OpenCPN Route Create"),
9907 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9908 if (dlg_return1 == wxID_YES) {
9915 if (m_pRoutePointEditTarget->IsShared()) {
9916 dlg_return = wxID_NO;
9917 dlg_return = OCPNMessageBox(
9919 _(
"Do you really want to delete and replace this "
9921 "\n" + _(
"which has been created manually?"),
9922 (
"OpenCPN RoutePoint warning"),
9923 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9926 if (dlg_return == wxID_YES) {
9927 pMousePoint = pNearbyPoint;
9929 pMousePoint->SetShared(
true);
9939 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9941 if (m_pEditRouteArray) {
9942 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9944 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9948 auto pos = std::find(list->begin(), list->end(),
9949 m_pRoutePointEditTarget);
9951 pSelect->DeleteAllSelectableRoutePoints(pr);
9952 pSelect->DeleteAllSelectableRouteSegments(pr);
9955 pos = std::find(list->begin(), list->end(),
9956 m_pRoutePointEditTarget);
9957 if (pos != list->end()) list->erase(pos);
9960 pSelect->AddAllSelectableRouteSegments(pr);
9961 pSelect->AddAllSelectableRoutePoints(pr);
9963 pr->FinalizeForRendering();
9964 pr->UpdateSegmentDistances();
9967 if (m_bRoutePoinDragging) {
9972 NavObj_dB::GetInstance().UpdateRoutePoint(
9973 m_pRoutePointEditTarget);
9975 NavObj_dB::GetInstance().UpdateRoute(pr);
9987 int length = tail->GetnPoints();
9988 for (
int i = connect + 1; i <= length; i++) {
9989 current->AddPointAndSegment(tail->GetPoint(i),
false);
9993 gFrame->RefreshAllCanvas();
9996 current->FinalizeForRendering();
10002 pSelect->DeleteAllSelectableRoutePoints(current);
10003 pSelect->DeleteAllSelectableRouteSegments(current);
10004 for (
int i = 1; i < connect; i++) {
10005 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10007 pSelect->AddAllSelectableRouteSegments(current);
10008 pSelect->AddAllSelectableRoutePoints(current);
10009 current->FinalizeForRendering();
10016 if (m_pEditRouteArray) {
10017 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10019 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10031 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10038 delete m_pRoutePointEditTarget;
10039 m_lastRoutePointEditTarget = NULL;
10040 undo->AfterUndoableAction(pMousePoint);
10041 undo->InvalidateUndo();
10046 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10049 delete m_pEditRouteArray;
10050 m_pEditRouteArray = NULL;
10054 m_bRouteEditing =
false;
10055 m_pRoutePointEditTarget = NULL;
10061 else if (m_bMarkEditing) {
10062 if (m_pRoutePointEditTarget) {
10063 if (m_bRoutePoinDragging) {
10065 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10067 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10072 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10074 RefreshRect(wp_rect,
true);
10077 m_pRoutePointEditTarget = NULL;
10078 m_bMarkEditing =
false;
10083 else if (leftIsDown) {
10084 leftIsDown =
false;
10088 if (!m_bChartDragging && !m_bMeasure_Active) {
10090 m_bChartDragging =
false;
10094 m_bRoutePoinDragging =
false;
10097 if (ret)
return true;
10100 if (event.RightDown()) {
10111 m_FinishRouteOnKillFocus =
false;
10112 CallPopupMenu(mx, my);
10113 m_FinishRouteOnKillFocus =
true;
10124 if (event.ShiftDown()) {
10128 event.GetPosition(&x, &y);
10130 x *= m_displayScale;
10131 y *= m_displayScale;
10137 int wheel_dir =
event.GetWheelRotation();
10140 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10141 wheel_dir = wheel_dir > 0 ? 1 : -1;
10143 double factor = g_mouse_zoom_sensitivity;
10144 if (wheel_dir < 0) factor = 1 / factor;
10147 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10148 if (wheel_dir == m_last_wheel_dir) {
10149 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10154 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10155 m_wheelstopwatch.Start(0);
10160 m_last_wheel_dir = wheel_dir;
10165 if (event.LeftDown()) {
10171 last_drag.x = x, last_drag.y = y;
10172 panleftIsDown =
true;
10175 if (event.LeftUp()) {
10176 if (panleftIsDown) {
10178 panleftIsDown =
false;
10181 if (!m_bChartDragging && !m_bMeasure_Active) {
10182 switch (cursor_region) {
10204 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10209 m_bChartDragging =
false;
10215 if (event.Dragging() && event.LeftIsDown()) {
10232 if (g_btouch && !m_inPinch) {
10233 struct timespec now;
10234 clock_gettime(CLOCK_MONOTONIC, &now);
10235 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10237 if (
false == m_bChartDragging) {
10239 last_drag.x = x, last_drag.y = y;
10240 m_bChartDragging =
true;
10241 m_chart_drag_total_time = 0;
10242 m_chart_drag_total_x = 0;
10243 m_chart_drag_total_y = 0;
10244 m_inertia_last_drag_x = x;
10245 m_inertia_last_drag_y = y;
10246 m_drag_vec_x.clear();
10247 m_drag_vec_y.clear();
10248 m_drag_vec_t.clear();
10249 m_last_drag_time = tnow;
10253 uint64_t delta_t = tnow - m_last_drag_time;
10254 double delta_tf = delta_t / 1e9;
10256 m_chart_drag_total_time += delta_tf;
10257 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10258 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10260 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10261 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10262 m_drag_vec_t.push_back(delta_tf);
10264 m_inertia_last_drag_x = x;
10265 m_inertia_last_drag_y = y;
10266 m_last_drag_time = tnow;
10268 if ((last_drag.x != x) || (last_drag.y != y)) {
10269 if (!m_routeState) {
10272 m_bChartDragging =
true;
10273 StartTimedMovement();
10274 m_pan_drag.x += last_drag.x - x;
10275 m_pan_drag.y += last_drag.y - y;
10276 last_drag.x = x, last_drag.y = y;
10279 }
else if (!g_btouch) {
10280 if ((last_drag.x != x) || (last_drag.y != y)) {
10281 if (!m_routeState) {
10284 m_bChartDragging =
true;
10285 StartTimedMovement();
10286 m_pan_drag.x += last_drag.x - x;
10287 m_pan_drag.y += last_drag.y - y;
10288 last_drag.x = x, last_drag.y = y;
10295 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10297 m_DoubleClickTimer->Start();
10298 singleClickEventIsValid =
false;
10306void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10307 if (MouseEventOverlayWindows(event))
return;
10314void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10317 wxCursor *ptarget_cursor = pCursorArrow;
10318 if (!pPlugIn_Cursor) {
10319 ptarget_cursor = pCursorArrow;
10320 if ((!m_routeState) &&
10321 (!m_bMeasure_Active) ) {
10322 if (cursor_region == MID_RIGHT) {
10323 ptarget_cursor = pCursorRight;
10324 }
else if (cursor_region == MID_LEFT) {
10325 ptarget_cursor = pCursorLeft;
10326 }
else if (cursor_region == MID_TOP) {
10327 ptarget_cursor = pCursorDown;
10328 }
else if (cursor_region == MID_BOT) {
10329 ptarget_cursor = pCursorUp;
10331 ptarget_cursor = pCursorArrow;
10333 }
else if (m_bMeasure_Active ||
10335 ptarget_cursor = pCursorPencil;
10337 ptarget_cursor = pPlugIn_Cursor;
10340 SetCursor(*ptarget_cursor);
10343void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10344 SetCursor(*pCursorArrow);
10347void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10351 wxArrayString files;
10353 ChartBase *target_chart = GetChartAtCursor();
10354 if (target_chart) {
10355 file.Assign(target_chart->GetFullPath());
10356 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10357 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10360 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10362 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10363 unsigned int im = stackIndexArray.size();
10364 int scale = 2147483647;
10365 if (VPoint.b_quilt && im > 0) {
10366 for (
unsigned int is = 0; is < im; is++) {
10367 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10368 CHART_TYPE_MBTILES) {
10369 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10371 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10372 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10374 .Contains(lat, lon)) {
10375 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10378 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10379 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10387 std::vector<Ais8_001_22 *> area_notices;
10389 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10392 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10393 auto target_data = target.second;
10394 if (!target_data->area_notices.empty()) {
10395 for (
auto &ani : target_data->area_notices) {
10400 for (Ais8_001_22_SubAreaList::iterator sa =
10401 area_notice.sub_areas.begin();
10402 sa != area_notice.sub_areas.end(); ++sa) {
10403 switch (sa->shape) {
10404 case AIS8_001_22_SHAPE_CIRCLE: {
10405 wxPoint target_point;
10407 bbox.Expand(target_point);
10408 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10411 case AIS8_001_22_SHAPE_RECT: {
10412 wxPoint target_point;
10414 bbox.Expand(target_point);
10415 if (sa->e_dim_m > sa->n_dim_m)
10416 bbox.EnLarge(sa->e_dim_m * vp_scale);
10418 bbox.EnLarge(sa->n_dim_m * vp_scale);
10421 case AIS8_001_22_SHAPE_POLYGON:
10422 case AIS8_001_22_SHAPE_POLYLINE: {
10423 for (
int i = 0; i < 4; ++i) {
10424 double lat = sa->latitude;
10425 double lon = sa->longitude;
10426 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10428 wxPoint target_point;
10430 bbox.Expand(target_point);
10434 case AIS8_001_22_SHAPE_SECTOR: {
10435 double lat1 = sa->latitude;
10436 double lon1 = sa->longitude;
10438 wxPoint target_point;
10440 bbox.Expand(target_point);
10441 for (
int i = 0; i < 18; ++i) {
10444 sa->left_bound_deg +
10445 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10446 sa->radius_m / 1852.0, &lat, &lon);
10448 bbox.Expand(target_point);
10450 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10453 bbox.Expand(target_point);
10459 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10460 area_notices.push_back(&area_notice);
10467 if (target_chart || !area_notices.empty() || file.HasName()) {
10469 int sel_rad_pix = 5;
10470 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10475 SetCursor(wxCURSOR_WAIT);
10476 bool lightsVis = m_encShowLights;
10477 if (!lightsVis) SetShowENCLights(
true);
10480 ListOfObjRazRules *rule_list = NULL;
10481 ListOfPI_S57Obj *pi_rule_list = NULL;
10484 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10485 else if (target_plugin_chart)
10486 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10487 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10489 ListOfObjRazRules *overlay_rule_list = NULL;
10490 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10493 if (CHs57_Overlay) {
10494 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10495 zlat, zlon, SelectRadius, &GetVP());
10498 if (!lightsVis) SetShowENCLights(
false);
10501 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10502 wxString face = dFont->GetFaceName();
10506 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10507 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10511 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10519 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10520 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10523 int points = dFont->GetPointSize();
10525 int points = dFont->GetPointSize() + 1;
10529 for (
int i = -2; i < 5; i++) {
10530 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10534 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10536 if (overlay_rule_list && CHs57_Overlay) {
10537 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10538 objText <<
"<hr noshade>";
10541 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10542 an != area_notices.end(); ++an) {
10543 objText <<
"<b>AIS Area Notice:</b> ";
10544 objText << ais8_001_22_notice_names[(*an)->notice_type];
10545 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10546 (*an)->sub_areas.begin();
10547 sa != (*an)->sub_areas.end(); ++sa)
10548 if (!sa->text.empty()) objText << sa->text;
10549 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10550 objText <<
"<hr noshade>";
10554 objText << Chs57->CreateObjDescriptions(rule_list);
10555 else if (target_plugin_chart)
10556 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10559 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10562 wxString AddFiles, filenameOK;
10564 if (!target_plugin_chart) {
10567 AddFiles = wxString::Format(
10568 "<hr noshade><br><b>Additional info files attached to: </b> "
10570 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10572 file.GetFullName());
10574 file.Assign(file.GetPath(),
"");
10575 wxDir dir(file.GetFullPath());
10577 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10579 file.Assign(dir.GetNameWithSep().append(filename));
10580 wxString FormatString =
10581 "<td valign=top><font size=-2><a "
10582 "href=\"%s\">%s</a></font></td>";
10583 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10584 filenameOK = file.GetFullPath();
10586 if (3 * ((
int)filecount / 3) == filecount)
10587 FormatString.Prepend(
"<tr>");
10589 FormatString.Prepend(
10590 "<td>  </td>");
10593 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10594 file.GetFullName());
10597 cont = dir.GetNext(&filename);
10599 objText << AddFiles <<
"</table>";
10601 objText <<
"</font>";
10602 objText <<
"</body></html>";
10604 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10608 if ((!Chs57 && filecount == 1)) {
10610 wxHtmlLinkInfo hli(filenameOK);
10611 wxHtmlLinkEvent hle(1, hli);
10615 if (rule_list) rule_list->Clear();
10618 if (overlay_rule_list) overlay_rule_list->Clear();
10619 delete overlay_rule_list;
10621 if (pi_rule_list) pi_rule_list->Clear();
10622 delete pi_rule_list;
10624 SetCursor(wxCURSOR_ARROW);
10628void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10637 wxSize canvas_size = GetSize();
10644 wxPoint canvas_pos = GetPosition();
10647 bool newFit =
false;
10648 if (canvas_size.x < fitted_size.x) {
10649 fitted_size.x = canvas_size.x - 40;
10650 if (canvas_size.y < fitted_size.y)
10651 fitted_size.y -= 40;
10653 if (canvas_size.y < fitted_size.y) {
10654 fitted_size.y = canvas_size.y - 40;
10655 if (canvas_size.x < fitted_size.x)
10656 fitted_size.x -= 40;
10667 wxString title_base = _(
"Mark Properties");
10669 title_base = _(
"Waypoint Properties");
10674 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10686void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10696 if (g_bresponsive) {
10697 wxSize canvas_size = GetSize();
10698 wxPoint canvas_pos = GetPosition();
10702 if (canvas_size.x < fitted_size.x) {
10703 fitted_size.x = canvas_size.x;
10704 if (canvas_size.y < fitted_size.y)
10705 fitted_size.y -= 20;
10707 if (canvas_size.y < fitted_size.y) {
10708 fitted_size.y = canvas_size.y;
10709 if (canvas_size.x < fitted_size.x)
10710 fitted_size.x -= 20;
10719 wxPoint xxp = ClientToScreen(canvas_pos);
10730void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10742void pupHandler_PasteWaypoint() {
10745 int pasteBuffer = kml.ParsePasteBuffer();
10746 RoutePoint *pasted = kml.GetParsedRoutePoint();
10747 if (!pasted)
return;
10749 double nearby_radius_meters =
10750 g_Platform->GetSelectRadiusPix() /
10751 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10753 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10754 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10756 int answer = wxID_NO;
10760 "There is an existing waypoint at the same location as the one you are "
10761 "pasting. Would you like to merge the pasted data with it?\n\n");
10762 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10763 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10764 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10767 if (answer == wxID_YES) {
10768 nearPoint->SetName(pasted->GetName());
10770 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10771 pRouteManagerDialog->UpdateWptListCtrl();
10774 if (answer == wxID_NO) {
10777 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10780 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10783 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10784 pRouteManagerDialog->UpdateWptListCtrl();
10789 gFrame->InvalidateAllGL();
10790 gFrame->RefreshAllCanvas(
false);
10793void pupHandler_PasteRoute() {
10796 int pasteBuffer = kml.ParsePasteBuffer();
10797 Route *pasted = kml.GetParsedRoute();
10798 if (!pasted)
return;
10800 double nearby_radius_meters =
10801 g_Platform->GetSelectRadiusPix() /
10802 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10808 bool mergepoints =
false;
10809 bool createNewRoute =
true;
10810 int existingWaypointCounter = 0;
10812 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10813 curPoint = pasted->GetPoint(i);
10814 nearPoint = pWayPointMan->GetNearbyWaypoint(
10815 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10817 mergepoints =
true;
10818 existingWaypointCounter++;
10826 int answer = wxID_NO;
10830 "There are existing waypoints at the same location as some of the ones "
10831 "you are pasting. Would you like to just merge the pasted data into "
10833 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10834 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10835 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10837 if (answer == wxID_CANCEL) {
10844 if (mergepoints && answer == wxID_YES &&
10845 existingWaypointCounter == pasted->GetnPoints()) {
10848 createNewRoute =
false;
10854 Route *newRoute = 0;
10857 if (createNewRoute) {
10858 newRoute =
new Route();
10862 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10863 curPoint = pasted->GetPoint(i);
10866 newPoint = pWayPointMan->GetNearbyWaypoint(
10867 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10868 newPoint->SetName(curPoint->GetName());
10871 if (createNewRoute) newRoute->AddPoint(newPoint);
10877 newPoint->SetIconName(
"circle");
10880 newPoint->SetShared(
false);
10882 newRoute->AddPoint(newPoint);
10883 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10886 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10889 if (i > 1 && createNewRoute)
10890 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10891 curPoint->m_lat, curPoint->m_lon,
10892 prevPoint, newPoint, newRoute);
10893 prevPoint = newPoint;
10896 if (createNewRoute) {
10899 NavObj_dB::GetInstance().InsertRoute(newRoute);
10905 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10906 pRouteManagerDialog->UpdateRouteListCtrl();
10907 pRouteManagerDialog->UpdateWptListCtrl();
10909 gFrame->InvalidateAllGL();
10910 gFrame->RefreshAllCanvas(
false);
10916void pupHandler_PasteTrack() {
10919 int pasteBuffer = kml.ParsePasteBuffer();
10920 Track *pasted = kml.GetParsedTrack();
10921 if (!pasted)
return;
10929 newTrack->SetName(pasted->GetName());
10931 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10932 curPoint = pasted->GetPoint(i);
10936 wxDateTime now = wxDateTime::Now();
10939 newTrack->AddPoint(newPoint);
10942 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10943 newPoint->m_lat, newPoint->m_lon,
10944 prevPoint, newPoint, newTrack);
10946 prevPoint = newPoint;
10951 NavObj_dB::GetInstance().InsertTrack(newTrack);
10953 gFrame->InvalidateAllGL();
10954 gFrame->RefreshAllCanvas(
false);
10957bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10960 v[
"CursorPosition_x"] = x;
10961 v[
"CursorPosition_y"] = y;
10964 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10965 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10966 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
10971 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
10973 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
10976#define SELTYPE_UNKNOWN 0x0001
10977#define SELTYPE_ROUTEPOINT 0x0002
10978#define SELTYPE_ROUTESEGMENT 0x0004
10979#define SELTYPE_TIDEPOINT 0x0008
10980#define SELTYPE_CURRENTPOINT 0x0010
10981#define SELTYPE_ROUTECREATE 0x0020
10982#define SELTYPE_AISTARGET 0x0040
10983#define SELTYPE_MARKPOINT 0x0080
10984#define SELTYPE_TRACKSEGMENT 0x0100
10985#define SELTYPE_DRAGHANDLE 0x0200
10988 if (g_bhide_context_menus)
return true;
10990 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10991 m_pIDXCandidate, m_nmea_log);
10994 wxEVT_COMMAND_MENU_SELECTED,
10995 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11001 if (m_inLongPress) {
11002 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11003 m_inLongPress =
false;
11007 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11010 wxEVT_COMMAND_MENU_SELECTED,
11011 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11013 delete m_canvasMenu;
11014 m_canvasMenu = NULL;
11024void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11027 if (m_canvasMenu) {
11028 m_canvasMenu->PopupMenuHandler(event);
11033void ChartCanvas::StartRoute() {
11035 if (g_brouteCreating)
return;
11039 g_brouteCreating =
true;
11041 m_bDrawingRoute =
false;
11042 SetCursor(*pCursorPencil);
11044 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11046 HideGlobalToolbar();
11049 androidSetRouteAnnunciator(
true);
11053wxString ChartCanvas::FinishRoute() {
11055 m_prev_pMousePoint = NULL;
11056 m_bDrawingRoute =
false;
11058 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11061 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11063 androidSetRouteAnnunciator(
false);
11066 SetCursor(*pCursorArrow);
11068 if (m_pMouseRoute) {
11069 if (m_bAppendingRoute) {
11071 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11073 if (m_pMouseRoute->GetnPoints() > 1) {
11075 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11078 m_pMouseRoute = NULL;
11081 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11088 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11089 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11090 pRouteManagerDialog->UpdateRouteListCtrl();
11093 m_bAppendingRoute =
false;
11094 m_pMouseRoute = NULL;
11096 m_pSelectedRoute = NULL;
11098 undo->InvalidateUndo();
11099 gFrame->RefreshAllCanvas(
true);
11103 ShowGlobalToolbar();
11105 g_brouteCreating =
false;
11110void ChartCanvas::HideGlobalToolbar() {
11111 if (m_canvasIndex == 0) {
11112 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11116void ChartCanvas::ShowGlobalToolbar() {
11117 if (m_canvasIndex == 0) {
11118 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11122void ChartCanvas::ShowAISTargetList() {
11123 if (NULL == g_pAISTargetList) {
11127 g_pAISTargetList->UpdateAISTargetList();
11130void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11131 if (!m_bShowOutlines)
return;
11135 int nEntry =
ChartData->GetChartTableEntries();
11137 for (
int i = 0; i < nEntry; i++) {
11141 bool b_group_draw =
false;
11142 if (m_groupIndex > 0) {
11143 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11144 int index = pt->GetGroupArray()[ig];
11145 if (m_groupIndex == index) {
11146 b_group_draw =
true;
11151 b_group_draw =
true;
11153 if (b_group_draw) RenderChartOutline(dc, i, vp);
11159 if (VPoint.b_quilt) {
11160 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11161 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11165 }
else if (m_singleChart &&
11166 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11170 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11173 if (zoom_factor > 8.0) {
11174 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11177 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11181 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11185void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11187 if (g_bopengl && m_glcc) {
11189 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11194 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11195 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11198 float plylat, plylon;
11199 float plylat1, plylon1;
11201 int pixx, pixy, pixx1, pixy1;
11204 ChartData->GetDBBoundingBox(dbIndex, box);
11208 if (box.GetLonRange() == 360)
return;
11210 double lon_bias = 0;
11212 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11214 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11216 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11217 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11219 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11220 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11223 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11226 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11227 if (0 == nAuxPlyEntries)
11231 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11232 plylon += lon_bias;
11238 for (
int i = 0; i < nPly - 1; i++) {
11239 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11240 plylon1 += lon_bias;
11246 int pixxs1 = pixx1;
11247 int pixys1 = pixy1;
11249 bool b_skip =
false;
11253 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11254 pow((
double)(pixy1 - pixy), 2)) /
11260 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11265 if (fabs(dist - distgc) > 10000. * 1852.)
11271 ClipResult res = cohen_sutherland_line_clip_i(
11273 if (res != Invisible && !b_skip)
11274 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11282 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11283 plylon1 += lon_bias;
11289 ClipResult res = cohen_sutherland_line_clip_i(
11291 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11298 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11299 for (
int j = 0; j < nAuxPlyEntries; j++) {
11301 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11306 for (
int i = 0; i < nAuxPly - 1; i++) {
11307 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11313 int pixxs1 = pixx1;
11314 int pixys1 = pixy1;
11316 bool b_skip =
false;
11320 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11321 ((pixy1 - pixy) * (pixy1 - pixy))) /
11326 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11331 if (fabs(dist - distgc) > 10000. * 1852.)
11337 ClipResult res = cohen_sutherland_line_clip_i(
11339 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11347 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11352 ClipResult res = cohen_sutherland_line_clip_i(
11354 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11359static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11360 const wxString &second) {
11361 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11363 int pointsize = dFont->GetPointSize();
11367 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11368 false, dFont->GetFaceName());
11370 dc.SetFont(*psRLI_font);
11378 int hilite_offset = 3;
11381 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11382 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11384 dc.GetTextExtent(first, &w1, &h1);
11385 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11391 w = wxMax(w1, w2) + (h1 / 2);
11396 xp = ref_point.x - w;
11398 yp += hilite_offset;
11400 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11402 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11403 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11405 dc.DrawText(first, xp, yp);
11406 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11409void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11410 if (!g_bAllowShipToActive)
return;
11416 wxPoint2DDouble pa, pb;
11423 if (rt->
m_width != wxPENSTYLE_INVALID)
11425 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11426 g_shipToActiveStyle, 5)];
11427 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11429 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11432 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11435 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11438 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11439 (
int)pb.m_y, GetVP(),
true);
11443#ifdef USE_ANDROID_GLES2
11444 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11446 if (style != wxPENSTYLE_SOLID) {
11447 if (glChartCanvas::dash_map.find(style) !=
11448 glChartCanvas::dash_map.end()) {
11449 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11453 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11456 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11457 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11463void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11465 if (m_routeState >= 2) route = m_pMouseRoute;
11466 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11467 route = m_pMeasureRoute;
11469 if (!route)
return;
11477 int np = route->GetnPoints();
11479 if (g_btouch && (np > 1)) np--;
11481 render_lat = rp.m_lat;
11482 render_lon = rp.m_lon;
11485 double rhumbBearing, rhumbDist;
11487 &rhumbBearing, &rhumbDist);
11488 double brg = rhumbBearing;
11489 double dist = rhumbDist;
11493 double gcBearing, gcBearing2, gcDist;
11494 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11497 double gcDistm = gcDist / 1852.0;
11500 rhumbBearing = 90.;
11502 wxPoint destPoint, lastPoint;
11505 int milesDiff = rhumbDist - gcDistm;
11506 if (milesDiff > 1) {
11517 for (
int i = 1; i <= milesDiff; i++) {
11518 double p = (double)i * (1.0 / (
double)milesDiff);
11520 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11521 &pLon, &pLat, &gcBearing2);
11523 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11525 lastPoint = destPoint;
11528 if (r_rband.x && r_rband.y) {
11529 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11531 if (m_bMeasure_DistCircle) {
11532 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11533 powf((
float)(r_rband.y - lastPoint.y), 2));
11536 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11537 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11543 wxString routeInfo;
11546 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11552 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11554 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11555 (
int)varBrg, 0x00B0);
11562 routeInfo <<
"\nReverse: ";
11564 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11565 (
int)(brg + 180.) % 360, 0x00B0);
11567 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11568 (
int)(varBrg + 180.) % 360, 0x00B0);
11573 s0.Append(_(
"Route") +
": ");
11575 s0.Append(_(
"Layer Route: "));
11578 if (!g_btouch) disp_length += dist;
11581 RouteLegInfo(dc, r_rband, routeInfo, s0);
11583 m_brepaint_piano =
true;
11586void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11587 if (!m_bShowVisibleSectors)
return;
11589 if (g_bDeferredInitDone) {
11591 double rhumbBearing, rhumbDist;
11592 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11593 &rhumbBearing, &rhumbDist);
11595 if (rhumbDist > 0.05)
11597 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11598 m_sectorlegsVisible);
11599 m_sector_glat =
gLat;
11600 m_sector_glon =
gLon;
11602 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11606void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11614void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11615 if (!ps52plib)
return;
11617 if (VPoint.b_quilt) {
11618 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11620 if (m_pQuilt->IsQuiltVector()) {
11621 if (ps52plib->GetStateHash() != m_s52StateHash) {
11623 m_s52StateHash = ps52plib->GetStateHash();
11627 if (ps52plib->GetStateHash() != m_s52StateHash) {
11629 m_s52StateHash = ps52plib->GetStateHash();
11634 bool bSendPlibState =
true;
11635 if (VPoint.b_quilt) {
11636 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11639 if (bSendPlibState) {
11641 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11642 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11643 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11644 v[
"OpenCPN Version Date"] = VERSION_DATE;
11645 v[
"OpenCPN Version Full"] = VERSION_FULL;
11648 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11649 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11650 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11651 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11652 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11653 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11654 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11658 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11659 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11663 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11664 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11665 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11666 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11667 ps52plib->m_bShowS57ImportantTextOnly;
11668 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11669 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11670 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11671 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11672 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11675 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11676 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11677 v[
"OpenCPN Scale Factor Exp"] =
11678 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11685 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11686 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11687 g_lastS52PLIBPluginMessage = out;
11693void ChartCanvas::OnPaint(wxPaintEvent &event) {
11694 wxPaintDC dc(
this);
11704 if (!m_b_paint_enable) {
11709 UpdateCanvasS52PLIBConfig();
11712 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11714 if (m_glcc && g_bopengl) {
11715 if (!s_in_update) {
11725 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11727 wxRegion ru = GetUpdateRegion();
11729 int rx, ry, rwidth, rheight;
11730 ru.GetBox(rx, ry, rwidth, rheight);
11732#ifdef ocpnUSE_DIBSECTION
11735 wxMemoryDC temp_dc;
11743 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11744 height += m_Piano->GetHeight();
11746 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11750 int thumbx, thumby, thumbsx, thumbsy;
11751 pthumbwin->GetPosition(&thumbx, &thumby);
11752 pthumbwin->GetSize(&thumbsx, &thumbsy);
11753 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11756 rgn_chart.Subtract(rgn_thumbwin);
11757 ru.Subtract(rgn_thumbwin);
11763 wxRegion rgn_blit = ru;
11764 if (g_bShowChartBar) {
11765 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11766 GetClientSize().x, m_Piano->GetHeight());
11769 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11770 if (style->chartStatusWindowTransparent)
11771 m_brepaint_piano =
true;
11773 ru.Subtract(chart_bar_rect);
11777 if (m_Compass && m_Compass->IsShown()) {
11778 wxRect compassRect = m_Compass->
GetRect();
11779 if (ru.Contains(compassRect) != wxOutRegion) {
11780 ru.Subtract(compassRect);
11784 wxRect noteRect = m_notification_button->
GetRect();
11785 if (ru.Contains(noteRect) != wxOutRegion) {
11786 ru.Subtract(noteRect);
11790 bool b_newview =
true;
11795 m_cache_vp.IsValid()) {
11801 bool b_rcache_ok =
false;
11802 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11803 b_rcache_ok = !b_newview;
11806 if (VPoint.b_MercatorProjectionOverride)
11807 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11821 if (b_rcache_ok) chart_get_region.Clear();
11824 if (VPoint.b_quilt)
11826 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11828 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11833 AbstractPlatform::ShowBusySpinner();
11837 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11838 (m_working_bm.GetHeight() != svp.
pix_height))
11842 if (fabs(VPoint.
rotation) < 0.01) {
11843 bool b_save =
true;
11848 m_cache_vp.Invalidate();
11862 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11867 int dy = c_new.y - c_old.y;
11868 int dx = c_new.x - c_old.x;
11873 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11877 temp_dc.SelectObject(m_working_bm);
11879 wxMemoryDC cache_dc;
11880 cache_dc.SelectObject(m_cached_chart_bm);
11884 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11887 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11893 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11896 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11904 update_region.Union(
11907 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11912 update_region.Union(
11915 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11919 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11921 cache_dc.SelectObject(wxNullBitmap);
11925 temp_dc.SelectObject(m_cached_chart_bm);
11928 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11932 temp_dc.SelectObject(m_working_bm);
11933 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11938 temp_dc.SelectObject(m_cached_chart_bm);
11943 temp_dc.SelectObject(m_working_bm);
11944 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11957 wxMemoryDC scratch_dc_0;
11958 scratch_dc_0.SelectObject(m_cached_chart_bm);
11961 scratch_dc_0.SelectObject(wxNullBitmap);
11970 temp_dc.SelectObject(m_working_bm);
11973 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11974 chart_get_all_region);
11977 AbstractPlatform::HideBusySpinner();
11983 if (!m_singleChart) {
11984 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11989 if (!chart_get_region.IsEmpty()) {
11990 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11994 if (temp_dc.IsOk()) {
11999 if (!VPoint.b_quilt) {
12002 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12003 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12010 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12011 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12014 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12016 temp_dc.DestroyClippingRegion();
12021 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12023 if (!backgroundRegion.IsEmpty()) {
12029 wxColour water = pWorldBackgroundChart->water;
12030 if (water.IsOk()) {
12031 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12032 temp_dc.SetBrush(wxBrush(water));
12034 while (upd.HaveRects()) {
12035 wxRect rect = upd.GetRect();
12036 temp_dc.DrawRectangle(rect);
12041 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12042 temp_dc.SetDeviceClippingRegion(*clip_region);
12043 delete clip_region;
12047 SetVPRotation(VPoint.
skew);
12056 wxMemoryDC *pChartDC = &temp_dc;
12057 wxMemoryDC rotd_dc;
12059 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12061 if (!b_rcache_ok) {
12063 wxMemoryDC tbase_dc;
12065 tbase_dc.SelectObject(bm_base);
12067 tbase_dc.SelectObject(wxNullBitmap);
12069 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12072 wxImage base_image;
12073 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12081 bool b_rot_ok =
false;
12082 if (base_image.IsOk()) {
12085 m_b_rot_hidef =
false;
12089 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12090 m_b_rot_hidef, &m_roffset);
12095 rot_vp.IsValid() && (ri.IsOk())) {
12102 m_prot_bm =
new wxBitmap(ri);
12105 m_roffset.x += VPoint.rv_rect.x;
12106 m_roffset.y += VPoint.rv_rect.y;
12109 if (m_prot_bm && m_prot_bm->IsOk()) {
12110 rotd_dc.SelectObject(*m_prot_bm);
12111 pChartDC = &rotd_dc;
12113 pChartDC = &temp_dc;
12114 m_roffset = wxPoint(0, 0);
12117 pChartDC = &temp_dc;
12118 m_roffset = wxPoint(0, 0);
12121 wxPoint offset = m_roffset;
12124 m_cache_vp = VPoint;
12127 wxMemoryDC mscratch_dc;
12128 mscratch_dc.SelectObject(*pscratch_bm);
12130 mscratch_dc.ResetBoundingBox();
12131 mscratch_dc.DestroyClippingRegion();
12132 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12135 wxRegionIterator upd(rgn_blit);
12137 wxRect rect = upd.GetRect();
12139 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12140 rect.x - offset.x, rect.y - offset.y);
12146 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12147 if (
this == wxWindow::FindFocus()) {
12150 wxColour colour = GetGlobalColor(
"BLUE4");
12151 mscratch_dc.SetPen(wxPen(colour));
12152 mscratch_dc.SetBrush(wxBrush(colour));
12154 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12155 mscratch_dc.DrawRectangle(activeRect);
12160 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12161 unsigned int im = stackIndexArray.size();
12162 if (VPoint.b_quilt && im > 0) {
12163 std::vector<int> tiles_to_show;
12164 for (
unsigned int is = 0; is < im; is++) {
12166 ChartData->GetChartTableEntry(stackIndexArray[is]);
12167 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12170 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12171 tiles_to_show.push_back(stackIndexArray[is]);
12175 if (tiles_to_show.size())
12176 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12182 ocpnDC scratch_dc(mscratch_dc);
12183 RenderAlertMessage(mscratch_dc, GetVP());
12189#ifdef ocpnUSE_DIBSECTION
12194 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12195 q_dc.SelectObject(qbm);
12198 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12201 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12202 q_dc.SetBrush(qbr);
12203 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12206 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12209 q_dc.SelectObject(wxNullBitmap);
12218 if( VPoint.b_quilt ) {
12219 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12220 ChartBase *chart = m_pQuilt->GetRefChart();
12221 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12226 ChPI->ClearPLIBTextList();
12229 ps52plib->ClearTextList();
12233 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12235 wxColor maskBackground = wxColour(1,0,0);
12236 t_dc.SelectObject( qbm );
12237 t_dc.SetBackground(wxBrush(maskBackground));
12241 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12244 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12245 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12248 wxRegionIterator upd_final( ru );
12249 while( upd_final ) {
12250 wxRect rect = upd_final.GetRect();
12251 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12255 t_dc.SelectObject( wxNullBitmap );
12261 if (VPoint.b_quilt) {
12262 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12263 ChartBase *chart = m_pQuilt->GetRefChart();
12264 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12268 ChPI->ClearPLIBTextList();
12270 if (ps52plib) ps52plib->ClearTextList();
12275 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12277 if (g_bShowChartBar && m_Piano) {
12278 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12279 GetVP().pix_width, m_Piano->GetHeight());
12282 if (!style->chartStatusWindowTransparent)
12283 chart_all_text_region.Subtract(chart_bar_rect);
12286 if (m_Compass && m_Compass->IsShown()) {
12287 wxRect compassRect = m_Compass->
GetRect();
12288 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12289 chart_all_text_region.Subtract(compassRect);
12293 mscratch_dc.DestroyClippingRegion();
12295 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12296 chart_all_text_region);
12302 ocpnDC scratch_dc(mscratch_dc);
12303 DrawOverlayObjects(scratch_dc, ru);
12306 wxRegionIterator upd_final(rgn_blit);
12307 while (upd_final) {
12308 wxRect rect = upd_final.GetRect();
12309 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12316 temp_dc.SelectObject(wxNullBitmap);
12318 mscratch_dc.SelectObject(wxNullBitmap);
12320 dc.DestroyClippingRegion();
12325void ChartCanvas::PaintCleanup() {
12327 if (m_inPinch)
return;
12338 m_bTCupdate =
false;
12342 WarpPointer(warp_x, warp_y);
12349 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12350 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12354wxColour GetErrorGraphicColor(
double val)
12373 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12374 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12375 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12376 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12377 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12378 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12379 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12380 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12381 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12382 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12383 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12384 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12385 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12386 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12387 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12388 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12389 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12390 else if( val >= 48) c.Set(
"#410000");
12395void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12398 gr_image.InitAlpha();
12400 double maxval = -10000;
12401 double minval = 10000;
12418 maxval = wxMax(maxval, (glat - rlat));
12419 minval = wxMin(minval, (glat - rlat));
12436 double f = ((glat - rlat)-minval)/(maxval - minval);
12438 double dy = (f * 40);
12440 wxColour c = GetErrorGraphicColor(dy);
12441 unsigned char r = c.Red();
12442 unsigned char g = c.Green();
12443 unsigned char b = c.Blue();
12445 gr_image.SetRGB(j, i, r,g,b);
12446 if((glat - rlat )!= 0)
12447 gr_image.SetAlpha(j, i, 128);
12449 gr_image.SetAlpha(j, i, 255);
12456 wxBitmap *pbm =
new wxBitmap(gr_image);
12457 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12458 pbm->SetMask(gr_mask);
12460 pmdc->DrawBitmap(*pbm, 0,0);
12468void ChartCanvas::CancelMouseRoute() {
12470 m_pMouseRoute = NULL;
12471 m_bDrawingRoute =
false;
12474int ChartCanvas::GetNextContextMenuId() {
12475 return CanvasMenuHandler::GetNextContextMenuId();
12478bool ChartCanvas::SetCursor(
const wxCursor &c) {
12480 if (g_bopengl && m_glcc)
12481 return m_glcc->SetCursor(c);
12484 return wxWindow::SetCursor(c);
12487void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12488 if (g_bquiting)
return;
12498 if (!m_RolloverPopupTimer.IsRunning() &&
12499 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12500 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12501 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12502 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12505 if (m_glcc && g_bopengl) {
12508 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12510 m_glcc->Refresh(eraseBackground,
12527 if (m_pCIWin && m_pCIWin->IsShown()) {
12529 m_pCIWin->Refresh(
false);
12537 wxWindow::Refresh(eraseBackground, rect);
12540void ChartCanvas::Update() {
12541 if (m_glcc && g_bopengl) {
12546 wxWindow::Update();
12550 if (!pemboss)
return;
12551 int x = pemboss->x, y = pemboss->y;
12552 const double factor = 200;
12554 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12555 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12556 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12559 wxMemoryDC snip_dc;
12560 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12561 snip_dc.SelectObject(snip_bmp);
12563 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12564 snip_dc.SelectObject(wxNullBitmap);
12566 wxImage snip_img = snip_bmp.ConvertToImage();
12569 unsigned char *pdata = snip_img.GetData();
12571 for (
int y = 0; y < pemboss->height; y++) {
12572 int map_index = (y * pemboss->width);
12573 for (
int x = 0; x < pemboss->width; x++) {
12574 double val = (pemboss->pmap[map_index] * factor) / 256.;
12576 int nred = (int)((*pdata) + val);
12577 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12578 *pdata++ = (
unsigned char)nred;
12580 int ngreen = (int)((*pdata) + val);
12581 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12582 *pdata++ = (
unsigned char)ngreen;
12584 int nblue = (int)((*pdata) + val);
12585 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12586 *pdata++ = (
unsigned char)nblue;
12594 wxBitmap emb_bmp(snip_img);
12597 wxMemoryDC result_dc;
12598 result_dc.SelectObject(emb_bmp);
12601 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12603 result_dc.SelectObject(wxNullBitmap);
12609 if (GetQuiltMode()) {
12611 int refIndex = GetQuiltRefChartdbIndex();
12612 if (refIndex >= 0) {
12614 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12615 if (current_type == CHART_TYPE_MBTILES) {
12616 ChartBase *pChart = m_pQuilt->GetRefChart();
12619 zoom_factor = ptc->GetZoomFactor();
12624 if (zoom_factor <= 3.9)
return NULL;
12626 if (m_singleChart) {
12627 if (zoom_factor <= 3.9)
return NULL;
12632 if (m_pEM_OverZoom) {
12633 m_pEM_OverZoom->x = 4;
12634 m_pEM_OverZoom->y = 0;
12636 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12637 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12640 return m_pEM_OverZoom;
12643void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12656 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12657 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12661 AISDrawAreaNotices(dc, GetVP(),
this);
12663 wxDC *pdc = dc.GetDC();
12665 pdc->DestroyClippingRegion();
12666 wxDCClipper(*pdc, ru);
12669 if (m_bShowNavobjects) {
12670 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12671 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12672 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12673 DrawAnchorWatchPoints(dc);
12675 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12676 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12679 AISDraw(dc, GetVP(),
this);
12683 RenderVisibleSectorLights(dc);
12685 RenderAllChartOutlines(dc, GetVP());
12686 RenderRouteLegs(dc);
12687 RenderShipToActive(dc,
false);
12689 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12691 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12695 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12696 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12699 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12704 RebuildTideSelectList(GetVP().GetBBox());
12705 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12708 if (m_bShowCurrent) {
12709 RebuildCurrentSelectList(GetVP().GetBBox());
12710 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12713 if (!g_PrintingInProgress) {
12714 if (IsPrimaryCanvas()) {
12718 if (IsPrimaryCanvas()) {
12722 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12724 if (m_pTrackRolloverWin) {
12725 m_pTrackRolloverWin->Draw(dc);
12726 m_brepaint_piano =
true;
12729 if (m_pRouteRolloverWin) {
12730 m_pRouteRolloverWin->Draw(dc);
12731 m_brepaint_piano =
true;
12734 if (m_pAISRolloverWin) {
12735 m_pAISRolloverWin->Draw(dc);
12736 m_brepaint_piano =
true;
12738 if (m_brepaint_piano && g_bShowChartBar) {
12739 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12742 if (m_Compass) m_Compass->Paint(dc);
12744 if (!g_CanvasHideNotificationIcon) {
12745 auto ¬eman = NotificationManager::GetInstance();
12746 if (noteman.GetNotificationCount()) {
12747 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12748 if (m_notification_button->UpdateStatus()) Refresh();
12749 m_notification_button->Show(
true);
12750 m_notification_button->Paint(dc);
12752 m_notification_button->Show(
false);
12757 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12763 if (!m_bShowDepthUnits)
return NULL;
12765 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12767 if (GetQuiltMode()) {
12768 wxString s = m_pQuilt->GetQuiltDepthUnit();
12771 depth_unit_type = DEPTH_UNIT_FEET;
12772 else if (s.StartsWith(
"FATHOMS"))
12773 depth_unit_type = DEPTH_UNIT_FATHOMS;
12774 else if (s.StartsWith(
"METERS"))
12775 depth_unit_type = DEPTH_UNIT_METERS;
12776 else if (s.StartsWith(
"METRES"))
12777 depth_unit_type = DEPTH_UNIT_METERS;
12778 else if (s.StartsWith(
"METRIC"))
12779 depth_unit_type = DEPTH_UNIT_METERS;
12780 else if (s.StartsWith(
"METER"))
12781 depth_unit_type = DEPTH_UNIT_METERS;
12784 if (m_singleChart) {
12785 depth_unit_type = m_singleChart->GetDepthUnitType();
12786 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12787 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12792 switch (depth_unit_type) {
12793 case DEPTH_UNIT_FEET:
12796 case DEPTH_UNIT_METERS:
12797 ped = m_pEM_Meters;
12799 case DEPTH_UNIT_FATHOMS:
12800 ped = m_pEM_Fathoms;
12806 ped->x = (GetVP().
pix_width - ped->width);
12808 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12809 wxRect r = m_Compass->
GetRect();
12810 ped->y = r.y + r.height;
12817void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12820 if (style->embossFont == wxEmptyString) {
12821 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12823 font.SetPointSize(60);
12824 font.SetWeight(wxFONTWEIGHT_BOLD);
12826 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12827 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12829 int emboss_width = 500;
12830 int emboss_height = 200;
12834 delete m_pEM_Meters;
12835 delete m_pEM_Fathoms;
12839 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12841 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12843 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12846#define OVERZOOM_TEXT _("OverZoom")
12848void ChartCanvas::SetOverzoomFont() {
12853 if (style->embossFont == wxEmptyString) {
12854 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12856 font.SetPointSize(40);
12857 font.SetWeight(wxFONTWEIGHT_BOLD);
12859 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12860 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12862 wxClientDC dc(
this);
12864 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12866 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12867 font.SetPointSize(font.GetPointSize() - 1);
12869 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12871 m_overzoomFont = font;
12872 m_overzoomTextWidth = w;
12873 m_overzoomTextHeight = h;
12876void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12877 delete m_pEM_OverZoom;
12879 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12881 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12882 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12885emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12886 int height,
const wxString &str,
12891 wxBitmap bmp(width, height, -1);
12894 wxMemoryDC temp_dc;
12895 temp_dc.SelectObject(bmp);
12898 temp_dc.SetBackground(*wxWHITE_BRUSH);
12899 temp_dc.SetTextBackground(*wxWHITE);
12900 temp_dc.SetTextForeground(*wxBLACK);
12904 temp_dc.SetFont(font);
12907 temp_dc.GetTextExtent(str, &str_w, &str_h);
12909 temp_dc.DrawText(str, 1, 1);
12912 temp_dc.SelectObject(wxNullBitmap);
12915 wxImage img = bmp.ConvertToImage();
12917 int image_width = str_w * 105 / 100;
12918 int image_height = str_h * 105 / 100;
12919 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12920 wxMin(image_height, img.GetHeight()));
12921 wxImage imgs = img.GetSubImage(r);
12925 case GLOBAL_COLOR_SCHEME_DAY:
12929 case GLOBAL_COLOR_SCHEME_DUSK:
12932 case GLOBAL_COLOR_SCHEME_NIGHT:
12939 const int w = imgs.GetWidth();
12940 const int h = imgs.GetHeight();
12941 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12946 for (
int y = 1; y < h - 1; y++) {
12947 for (
int x = 1; x < w - 1; x++) {
12949 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12950 val = (int)(val * val_factor);
12951 index = (y * w) + x;
12964void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12965 Track *active_track = NULL;
12968 active_track = pTrackDraw;
12972 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12975 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12978void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12979 Track *active_track = NULL;
12982 active_track = pTrackDraw;
12986 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12989void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12990 Route *active_route = NULL;
12992 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12993 active_route = pRouteDraw;
12998 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13003 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13006void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13007 Route *active_route = NULL;
13010 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13011 active_route = pRouteDraw;
13015 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13018void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13019 if (!pWayPointMan)
return;
13021 auto node = pWayPointMan->GetWaypointList()->begin();
13023 while (node != pWayPointMan->GetWaypointList()->end()) {
13032 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13036 if (pWP->GetShowWaypointRangeRings() &&
13037 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13038 double factor = 1.00;
13039 if (pWP->GetWaypointRangeRingsStepUnits() ==
13041 factor = 1 / 1.852;
13043 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13044 pWP->GetWaypointRangeRingsStep() / 60.;
13048 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13049 pWP->m_lat + radius, pWP->m_lon + radius);
13050 if (!BltBBox.IntersectOut(radar_box)) {
13061void ChartCanvas::DrawBlinkObjects() {
13063 wxRect update_rect;
13065 if (!pWayPointMan)
return;
13067 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13074 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13077void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13082 wxPoint lAnchorPoint1, lAnchorPoint2;
13096 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13097 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13099 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13100 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13101 dc.SetBrush(*ppBrush);
13105 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13110 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13115 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13120 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13125double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13128 wxPoint lAnchorPoint;
13131 double tlat1, tlon1;
13133 if (pAnchorWatchPoint) {
13134 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13135 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13136 dabs = fabs(d1 / 1852.);
13137 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13142 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13143 pow((
double)(lAnchorPoint.y - r1.y), 2));
13146 if (d1 < 0) lpp = -lpp;
13154void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13157 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13159 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13165 if ((type ==
't') || (type ==
'T')) {
13166 if (BBox.Contains(lat, lon)) {
13168 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13174void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13177 wxDateTime this_now = gTimeSource;
13178 bool cur_time = !gTimeSource.IsValid();
13179 if (cur_time) this_now = wxDateTime::Now();
13180 time_t t_this_now = this_now.GetTicks();
13182 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13184 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13185 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13186 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13187 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13189 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13190 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13191 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13192 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13193 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13194 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13196 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13197 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13198 int font_size = wxMax(10, dFont->GetPointSize());
13201 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13202 false, dFont->GetFaceName());
13204 dc.SetPen(*pblack_pen);
13205 dc.SetBrush(*pgreen_brush);
13209 case GLOBAL_COLOR_SCHEME_DAY:
13212 case GLOBAL_COLOR_SCHEME_DUSK:
13215 case GLOBAL_COLOR_SCHEME_NIGHT:
13216 bm = m_bmTideNight;
13223 int bmw = bm.GetWidth();
13224 int bmh = bm.GetHeight();
13226 float scale_factor = 1.0;
13230 float icon_pixelRefDim = 45;
13235 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13237 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13239 scale_factor *= pix_factor;
13246 scale_factor *= user_scale_factor;
13247 scale_factor *= GetContentScaleFactor();
13250 double marge = 0.05;
13251 std::vector<LLBBox> drawn_boxes;
13252 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13256 if ((type ==
't') || (type ==
'T'))
13261 if (BBox.ContainsMarge(lat, lon, marge)) {
13263 if (GetVP().chart_scale < 500000) {
13264 bool bdrawn =
false;
13265 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13266 if (drawn_boxes[i].Contains(lat, lon)) {
13271 if (bdrawn)
continue;
13274 this_box.Set(lat, lon, lat, lon);
13275 this_box.EnLarge(.005);
13276 drawn_boxes.push_back(this_box);
13282 if (GetVP().chart_scale > 500000) {
13283 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13287 dc.SetFont(*plabelFont);
13299 if (
ptcmgr->GetTideFlowSens(
13300 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13304 ptcmgr->GetHightOrLowTide(
13305 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13306 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13318 if (tctime > t_this_now)
13319 ptcmgr->GetHightOrLowTide(
13320 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13321 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13325 ptcmgr->GetHightOrLowTide(
13326 t_this_now, FORWARD_TEN_MINUTES_STEP,
13327 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13341 int width = (int)(12 * scale_factor + 0.5);
13342 int height = (int)(45 * scale_factor + 0.5);
13343 int linew = wxMax(1, (
int)(scale_factor));
13344 int xDraw = r.x - (width / 2);
13345 int yDraw = r.y - (height / 2);
13348 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13349 int hs = (httime > lttime) ? -4 : 4;
13350 hs *= (int)(scale_factor + 0.5);
13351 if (ts > 0.995 || ts < 0.005) hs = 0;
13352 int ht_y = (int)(height * ts);
13355 pblack_pen->SetWidth(linew);
13356 dc.SetPen(*pblack_pen);
13357 dc.SetBrush(*pyelo_brush);
13358 dc.DrawRectangle(xDraw, yDraw, width, height);
13362 dc.SetPen(*pblue_pen);
13363 dc.SetBrush(*pblue_brush);
13364 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13365 (width - (4 * linew)), height - ht_y);
13371 arrow[0].x = xDraw + 2 * linew;
13372 arrow[1].x = xDraw + width / 2;
13373 arrow[2].x = xDraw + width - 2 * linew;
13374 pyelo_pen->SetWidth(linew);
13375 pblue_pen->SetWidth(linew);
13376 if (ts > 0.35 || ts < 0.15)
13378 hl = (int)(height * 0.25) + yDraw;
13380 arrow[1].y = hl + hs;
13383 dc.SetPen(*pyelo_pen);
13385 dc.SetPen(*pblue_pen);
13386 dc.DrawLines(3, arrow);
13388 if (ts > 0.60 || ts < 0.40)
13390 hl = (int)(height * 0.5) + yDraw;
13392 arrow[1].y = hl + hs;
13395 dc.SetPen(*pyelo_pen);
13397 dc.SetPen(*pblue_pen);
13398 dc.DrawLines(3, arrow);
13400 if (ts < 0.65 || ts > 0.85)
13402 hl = (int)(height * 0.75) + yDraw;
13404 arrow[1].y = hl + hs;
13407 dc.SetPen(*pyelo_pen);
13409 dc.SetPen(*pblue_pen);
13410 dc.DrawLines(3, arrow);
13414 s.Printf(
"%3.1f", nowlev);
13416 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13418 dc.GetTextExtent(s, &wx1, NULL);
13420 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13435void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13438 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13440 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13446 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13447 if ((BBox.Contains(lat, lon))) {
13449 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13455void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13458 float tcvalue, dir;
13462 double lon_last = 0.;
13463 double lat_last = 0.;
13465 double marge = 0.2;
13466 bool cur_time = !gTimeSource.IsValid();
13468 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13469 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13471 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13473 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13474 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13475 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13476 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13477 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13478 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13479 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13480 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13482 double skew_angle = GetVPRotation();
13484 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13485 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13486 int font_size = wxMax(10, dFont->GetPointSize());
13489 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13490 false, dFont->GetFaceName());
13492 float scale_factor = 1.0;
13498 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13500 float nominal_icon_size_pixels = 15;
13501 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13503 scale_factor *= pix_factor;
13510 scale_factor *= user_scale_factor;
13512 scale_factor *= GetContentScaleFactor();
13515 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13521 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13522 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13527 int dd = (int)(5.0 * scale_factor + 0.5);
13538 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13539 dc.SetPen(*pblack_pen);
13540 dc.SetBrush(*porange_brush);
13541 dc.DrawPolygon(4, d);
13544 dc.SetBrush(*pblack_brush);
13545 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13549 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13563 double a1 = fabs(tcvalue) * 10.;
13565 a1 = wxMax(1.0, a1);
13566 double a2 = log10(a1);
13568 float cscale = scale_factor * a2 * 0.3;
13570 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13571 dc.SetPen(*porange_pen);
13572 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13576 if (bDrawCurrentValues) {
13577 dc.SetFont(*pTCFont);
13578 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13579 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13605 if (!pvIDX)
return;
13610 if (pCwin && pCwin->IsShown()) {
13618 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13633 pCwin =
new TCWin(
this, x, y, pvIDX);
13651#define NUM_CURRENT_ARROW_POINTS 9
13652static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13653 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13654 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13655 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13657void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13659 if (
scale > 1e-2) {
13660 float sin_rot = sin(rot_angle * PI / 180.);
13661 float cos_rot = cos(rot_angle * PI / 180.);
13665 float xt = CurrentArrowArray[0].x;
13666 float yt = CurrentArrowArray[0].y;
13668 float xp = (xt * cos_rot) - (yt * sin_rot);
13669 float yp = (xt * sin_rot) + (yt * cos_rot);
13670 int x1 = (int)(xp *
scale);
13671 int y1 = (int)(yp *
scale);
13674 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13675 xt = CurrentArrowArray[ip].x;
13676 yt = CurrentArrowArray[ip].y;
13678 float xp = (xt * cos_rot) - (yt * sin_rot);
13679 float yp = (xt * sin_rot) + (yt * cos_rot);
13680 int x2 = (int)(xp *
scale);
13681 int y2 = (int)(yp *
scale);
13683 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13691wxString ChartCanvas::FindValidUploadPort() {
13694 if (!g_uploadConnection.IsEmpty() &&
13695 g_uploadConnection.StartsWith(
"Serial")) {
13696 port = g_uploadConnection;
13702 for (
auto *cp : TheConnectionParams()) {
13703 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13704 port <<
"Serial:" << cp->Port;
13710void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13713 if (NULL == g_pais_query_dialog_active) {
13714 int pos_x = g_ais_query_dialog_x;
13715 int pos_y = g_ais_query_dialog_y;
13717 if (g_pais_query_dialog_active) {
13718 g_pais_query_dialog_active->Destroy();
13724 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13725 wxPoint(pos_x, pos_y));
13727 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13728 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13729 g_pais_query_dialog_active->SetMMSI(mmsi);
13730 g_pais_query_dialog_active->UpdateText();
13731 wxSize sz = g_pais_query_dialog_active->GetSize();
13733 bool b_reset_pos =
false;
13738 RECT frame_title_rect;
13739 frame_title_rect.left = pos_x;
13740 frame_title_rect.top = pos_y;
13741 frame_title_rect.right = pos_x + sz.x;
13742 frame_title_rect.bottom = pos_y + 30;
13744 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13745 b_reset_pos =
true;
13750 wxRect window_title_rect;
13751 window_title_rect.x = pos_x;
13752 window_title_rect.y = pos_y;
13753 window_title_rect.width = sz.x;
13754 window_title_rect.height = 30;
13756 wxRect ClientRect = wxGetClientDisplayRect();
13757 ClientRect.Deflate(
13759 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13763 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13766 g_pais_query_dialog_active->SetMMSI(mmsi);
13767 g_pais_query_dialog_active->UpdateText();
13770 g_pais_query_dialog_active->Show();
13773void ChartCanvas::ToggleCanvasQuiltMode() {
13774 bool cur_mode = GetQuiltMode();
13776 if (!GetQuiltMode())
13777 SetQuiltMode(
true);
13778 else if (GetQuiltMode()) {
13779 SetQuiltMode(
false);
13780 g_sticky_chart = GetQuiltReferenceChartIndex();
13783 if (cur_mode != GetQuiltMode()) {
13784 SetupCanvasQuiltMode();
13793 if (ps52plib) ps52plib->GenerateStateHash();
13795 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13796 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13799void ChartCanvas::DoCanvasStackDelta(
int direction) {
13800 if (!GetQuiltMode()) {
13801 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13802 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13803 if ((current_stack_index + direction) < 0)
return;
13805 if (m_bpersistent_quilt ) {
13807 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13809 if (IsChartQuiltableRef(new_dbIndex)) {
13810 ToggleCanvasQuiltMode();
13811 SelectQuiltRefdbChart(new_dbIndex);
13812 m_bpersistent_quilt =
false;
13815 SelectChartFromStack(current_stack_index + direction);
13818 std::vector<int> piano_chart_index_array =
13819 GetQuiltExtendedStackdbIndexArray();
13820 int refdb = GetQuiltRefChartdbIndex();
13823 int current_index = -1;
13824 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13825 if (refdb == piano_chart_index_array[i]) {
13830 if (current_index == -1)
return;
13833 int target_family = ctet.GetChartFamily();
13835 int new_index = -1;
13836 int check_index = current_index + direction;
13837 bool found =
false;
13838 int check_dbIndex = -1;
13839 int new_dbIndex = -1;
13843 (
unsigned int)check_index < piano_chart_index_array.size() &&
13844 (check_index >= 0)) {
13845 check_dbIndex = piano_chart_index_array[check_index];
13847 if (target_family == cte.GetChartFamily()) {
13849 new_index = check_index;
13850 new_dbIndex = check_dbIndex;
13854 check_index += direction;
13857 if (!found)
return;
13859 if (!IsChartQuiltableRef(new_dbIndex)) {
13860 ToggleCanvasQuiltMode();
13861 SelectdbChart(new_dbIndex);
13862 m_bpersistent_quilt =
true;
13864 SelectQuiltRefChart(new_index);
13868 gFrame->UpdateGlobalMenuItems();
13870 SetQuiltChartHiLiteIndex(-1);
13881void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13884 switch (event.GetId()) {
13896 DoCanvasStackDelta(1);
13901 DoCanvasStackDelta(-1);
13911 ShowCurrents(!GetbShowCurrent());
13918 ShowTides(!GetbShowTide());
13925 if (0 == m_routeState) {
13932 androidSetRouteAnnunciator(m_routeState == 1);
13938 SetAISCanvasDisplayStyle(-1);
13950void ChartCanvas::SetShowAIS(
bool show) {
13952 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13953 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13956void ChartCanvas::SetAttenAIS(
bool show) {
13957 m_bShowAISScaled = show;
13958 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13959 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13962void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13965 bool bShowAIS_Array[3] = {
true,
true,
false};
13966 bool bShowScaled_Array[3] = {
false,
true,
true};
13967 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13968 _(
"Attenuate less critical AIS targets"),
13969 _(
"Hide AIS Targets")};
13970 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
13972 int AIS_Toolbar_Switch = 0;
13973 if (StyleIndx == -1) {
13975 for (
int i = 1; i < ArraySize; i++) {
13976 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13977 (bShowScaled_Array[i] == m_bShowAISScaled))
13978 AIS_Toolbar_Switch = i;
13980 AIS_Toolbar_Switch++;
13981 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13982 AIS_Toolbar_Switch++;
13985 AIS_Toolbar_Switch = StyleIndx;
13988 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13990 int AIS_Toolbar_Switch_Next =
13991 AIS_Toolbar_Switch + 1;
13992 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13993 AIS_Toolbar_Switch_Next++;
13994 if (AIS_Toolbar_Switch_Next >= ArraySize)
13995 AIS_Toolbar_Switch_Next = 0;
13998 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13999 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14002void ChartCanvas::TouchAISToolActive() {}
14004void ChartCanvas::UpdateAISTBTool() {}
14012void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14014 bool b_update =
false;
14015 int cc1_edge_comp = 2;
14016 wxRect rect = m_Compass->
GetRect();
14017 wxSize parent_size = GetSize();
14019 parent_size *= m_displayScale;
14023 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14024 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14025 wxRect compass_rect(compass_pt, rect.GetSize());
14027 m_Compass->Move(compass_pt);
14029 if (m_Compass && m_Compass->IsShown())
14030 m_Compass->UpdateStatus(b_force_new | b_update);
14032 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14033 scaler = wxMax(scaler, 1.0);
14034 wxPoint note_point = wxPoint(
14035 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14036 m_notification_button->Move(note_point);
14037 m_notification_button->UpdateStatus();
14039 if (b_force_new | b_update) Refresh();
14042void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14043 ChartTypeEnum New_Type,
14044 ChartFamilyEnum New_Family) {
14045 if (!GetpCurrentStack())
return;
14048 if (index < GetpCurrentStack()->nEntry) {
14051 pTentative_Chart =
ChartData->OpenStackChartConditional(
14052 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14054 if (pTentative_Chart) {
14055 if (m_singleChart) m_singleChart->Deactivate();
14057 m_singleChart = pTentative_Chart;
14058 m_singleChart->Activate();
14060 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14061 GetpCurrentStack(), m_singleChart->GetFullPath());
14074 double best_scale_ppm = GetBestVPScale(m_singleChart);
14075 double rotation = GetVPRotation();
14076 double oldskew = GetVPSkew();
14077 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14079 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14080 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14081 if (fabs(newskew) > 0.0001) rotation = newskew;
14084 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14086 UpdateGPSCompassStatusBox(
true);
14090 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14091 if (idx < 0)
return;
14093 std::vector<int> piano_active_chart_index_array;
14094 piano_active_chart_index_array.push_back(
14095 GetpCurrentStack()->GetCurrentEntrydbIndex());
14096 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14099void ChartCanvas::SelectdbChart(
int dbindex) {
14100 if (!GetpCurrentStack())
return;
14103 if (dbindex >= 0) {
14106 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14108 if (pTentative_Chart) {
14109 if (m_singleChart) m_singleChart->Deactivate();
14111 m_singleChart = pTentative_Chart;
14112 m_singleChart->Activate();
14114 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14115 GetpCurrentStack(), m_singleChart->GetFullPath());
14128 double best_scale_ppm = GetBestVPScale(m_singleChart);
14132 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14142void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14145 if (!GetQuiltMode()) {
14146 if (GetpCurrentStack()) {
14147 int stack_index = -1;
14148 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14149 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14150 if (check_dbIndex < 0)
continue;
14152 ChartData->GetChartTableEntry(check_dbIndex);
14153 if (type == cte.GetChartType()) {
14156 }
else if (family == cte.GetChartFamily()) {
14162 if (stack_index >= 0) {
14163 SelectChartFromStack(stack_index);
14167 int sel_dbIndex = -1;
14168 std::vector<int> piano_chart_index_array =
14169 GetQuiltExtendedStackdbIndexArray();
14170 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14171 int check_dbIndex = piano_chart_index_array[i];
14173 if (type == cte.GetChartType()) {
14174 if (IsChartQuiltableRef(check_dbIndex)) {
14175 sel_dbIndex = check_dbIndex;
14178 }
else if (family == cte.GetChartFamily()) {
14179 if (IsChartQuiltableRef(check_dbIndex)) {
14180 sel_dbIndex = check_dbIndex;
14186 if (sel_dbIndex >= 0) {
14187 SelectQuiltRefdbChart(sel_dbIndex,
false);
14189 AdjustQuiltRefChart();
14196 SetQuiltChartHiLiteIndex(-1);
14201bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14202 return std::find(m_tile_yesshow_index_array.begin(),
14203 m_tile_yesshow_index_array.end(),
14204 index) != m_tile_yesshow_index_array.end();
14207bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14208 return std::find(m_tile_noshow_index_array.begin(),
14209 m_tile_noshow_index_array.end(),
14210 index) != m_tile_noshow_index_array.end();
14213void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14214 if (std::find(m_tile_noshow_index_array.begin(),
14215 m_tile_noshow_index_array.end(),
14216 index) == m_tile_noshow_index_array.end()) {
14217 m_tile_noshow_index_array.push_back(index);
14227void ChartCanvas::HandlePianoClick(
14228 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14231 if (!m_pCurrentStack)
return;
14247 double distance = 25000;
14248 int closest_index = -1;
14249 for (
int chart_index : selected_dbIndex_array) {
14251 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14252 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14255 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14256 if (test_distance < distance) {
14257 distance = test_distance;
14258 closest_index = chart_index;
14262 int selected_dbIndex = selected_dbIndex_array[0];
14263 if (closest_index >= 0) selected_dbIndex = closest_index;
14265 if (!GetQuiltMode()) {
14266 if (m_bpersistent_quilt ) {
14267 if (IsChartQuiltableRef(selected_dbIndex)) {
14268 ToggleCanvasQuiltMode();
14269 SelectQuiltRefdbChart(selected_dbIndex);
14270 m_bpersistent_quilt =
false;
14272 SelectChartFromStack(selected_index);
14275 SelectChartFromStack(selected_index);
14276 g_sticky_chart = selected_dbIndex;
14280 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14284 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14285 bool bfound =
false;
14286 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14287 if (m_tile_noshow_index_array[i] ==
14288 selected_dbIndex) {
14289 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14296 m_tile_noshow_index_array.push_back(selected_dbIndex);
14300 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14301 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14305 if (IsChartQuiltableRef(selected_dbIndex)) {
14311 bool set_scale =
false;
14312 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14313 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14319 SelectQuiltRefdbChart(selected_dbIndex,
true);
14321 SelectQuiltRefdbChart(selected_dbIndex,
false);
14326 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14328 double proposed_scale_onscreen =
14331 if (g_bPreserveScaleOnX) {
14332 proposed_scale_onscreen =
14333 wxMin(proposed_scale_onscreen,
14335 GetCanvasWidth()));
14337 proposed_scale_onscreen =
14338 wxMin(proposed_scale_onscreen,
14340 GetCanvasWidth()));
14342 proposed_scale_onscreen =
14343 wxMax(proposed_scale_onscreen,
14352 ToggleCanvasQuiltMode();
14353 SelectdbChart(selected_dbIndex);
14354 m_bpersistent_quilt =
true;
14359 SetQuiltChartHiLiteIndex(-1);
14360 gFrame->UpdateGlobalMenuItems();
14362 HideChartInfoWindow();
14367void ChartCanvas::HandlePianoRClick(
14368 int x,
int y,
int selected_index,
14369 const std::vector<int> &selected_dbIndex_array) {
14372 if (!GetpCurrentStack())
return;
14374 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14375 UpdateCanvasControlBar();
14377 SetQuiltChartHiLiteIndex(-1);
14380void ChartCanvas::HandlePianoRollover(
14381 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14382 int n_charts,
int scale) {
14385 if (!GetpCurrentStack())
return;
14390 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14392 if (!GetQuiltMode()) {
14393 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14396 std::vector<int> piano_chart_index_array;
14397 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14398 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14399 if ((GetpCurrentStack()->nEntry > 1) ||
14400 (piano_chart_index_array.size() >= 1)) {
14401 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14403 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14405 }
else if (GetpCurrentStack()->nEntry == 1) {
14407 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14408 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14409 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14411 }
else if ((-1 == selected_index) &&
14412 (0 == selected_dbIndex_array.size())) {
14413 ShowChartInfoWindow(key_location.x, -1);
14417 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14419 if ((GetpCurrentStack()->nEntry > 1) ||
14420 (piano_chart_index_array.size() >= 1)) {
14422 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14423 selected_dbIndex_array);
14424 else if (n_charts == 1)
14425 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14427 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14434void ChartCanvas::ClearPianoRollover() {
14435 ClearQuiltChartHiLiteIndexArray();
14436 ShowChartInfoWindow(0, -1);
14437 std::vector<int> vec;
14438 ShowCompositeInfoWindow(0, 0, 0, vec);
14442void ChartCanvas::UpdateCanvasControlBar() {
14443 if (m_pianoFrozen)
return;
14445 if (!GetpCurrentStack())
return;
14447 if (!g_bShowChartBar)
return;
14450 int sel_family = -1;
14452 std::vector<int> piano_chart_index_array;
14453 std::vector<int> empty_piano_chart_index_array;
14455 wxString old_hash = m_Piano->GetStoredHash();
14457 if (GetQuiltMode()) {
14458 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14459 GetQuiltFullScreendbIndexArray());
14461 std::vector<int> piano_active_chart_index_array =
14462 GetQuiltCandidatedbIndexArray();
14463 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14465 std::vector<int> piano_eclipsed_chart_index_array =
14466 GetQuiltEclipsedStackdbIndexArray();
14467 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14469 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14470 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14472 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14473 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14475 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14476 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14479 if (m_singleChart) {
14480 sel_type = m_singleChart->GetChartType();
14481 sel_family = m_singleChart->GetChartFamily();
14486 std::vector<int> piano_skew_chart_index_array;
14487 std::vector<int> piano_tmerc_chart_index_array;
14488 std::vector<int> piano_poly_chart_index_array;
14490 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14492 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14493 double skew_norm = ctei.GetChartSkew();
14494 if (skew_norm > 180.) skew_norm -= 360.;
14496 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14497 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14500 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14501 if (fabs(skew_norm) > 1.)
14502 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14504 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14505 }
else if (fabs(skew_norm) > 1.)
14506 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14508 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14509 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14510 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14512 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14513 if (new_hash != old_hash) {
14514 m_Piano->FormatKeys();
14515 HideChartInfoWindow();
14516 m_Piano->ResetRollover();
14517 SetQuiltChartHiLiteIndex(-1);
14518 m_brepaint_piano =
true;
14524 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14526 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14527 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14528 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14529 if (e == CHART_FAMILY_RASTER) mask |= 1;
14530 if (e == CHART_FAMILY_VECTOR) {
14531 if (t == CHART_TYPE_CM93COMP)
14538 wxString s_indicated;
14539 if (sel_type == CHART_TYPE_CM93COMP)
14540 s_indicated =
"cm93";
14542 if (sel_family == CHART_FAMILY_RASTER)
14543 s_indicated =
"raster";
14544 else if (sel_family == CHART_FAMILY_VECTOR)
14545 s_indicated =
"vector";
14548 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14551void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14553void ChartCanvas::PianoPopupMenu(
14554 int x,
int y,
int selected_index,
14555 const std::vector<int> &selected_dbIndex_array) {
14556 if (!GetpCurrentStack())
return;
14559 if (!GetQuiltMode())
return;
14561 m_piano_ctx_menu =
new wxMenu();
14563 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14573 menu_selected_dbIndex = selected_dbIndex_array[0];
14574 menu_selected_index = selected_index;
14577 bool b_is_in_noshow =
false;
14578 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14579 if (m_quilt_noshow_index_array[i] ==
14580 menu_selected_dbIndex)
14582 b_is_in_noshow =
true;
14587 if (b_is_in_noshow) {
14588 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14589 _(
"Show This Chart"));
14590 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14591 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14592 }
else if (GetpCurrentStack()->nEntry > 1) {
14593 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14594 _(
"Hide This Chart"));
14595 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14596 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14600 wxPoint pos = wxPoint(x, y - 30);
14603 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14604 PopupMenu(m_piano_ctx_menu, pos);
14606 delete m_piano_ctx_menu;
14607 m_piano_ctx_menu = NULL;
14609 HideChartInfoWindow();
14610 m_Piano->ResetRollover();
14612 SetQuiltChartHiLiteIndex(-1);
14613 ClearQuiltChartHiLiteIndexArray();
14618void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14619 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14620 if (m_quilt_noshow_index_array[i] ==
14621 menu_selected_dbIndex)
14623 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14629void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14630 if (!GetpCurrentStack())
return;
14633 RemoveChartFromQuilt(menu_selected_dbIndex);
14637 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14638 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14640 int i = menu_selected_index + 1;
14641 bool b_success =
false;
14642 while (i < GetpCurrentStack()->nEntry - 1) {
14643 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14644 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14645 SelectQuiltRefChart(i);
14655 i = menu_selected_index - 1;
14657 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14658 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14659 SelectQuiltRefChart(i);
14669void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14671 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14672 if (m_quilt_noshow_index_array[i] ==
14675 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14680 m_quilt_noshow_index_array.push_back(dbIndex);
14683bool ChartCanvas::UpdateS52State() {
14684 bool retval =
false;
14687 ps52plib->SetShowS57Text(m_encShowText);
14688 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14689 ps52plib->m_bShowSoundg = m_encShowDepth;
14690 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14691 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14694 if (!m_encShowLights)
14695 ps52plib->AddObjNoshow(
"LIGHTS");
14697 ps52plib->RemoveObjNoshow(
"LIGHTS");
14698 ps52plib->SetLightsOff(!m_encShowLights);
14699 ps52plib->m_bExtendLightSectors =
true;
14702 ps52plib->SetAnchorOn(m_encShowAnchor);
14703 ps52plib->SetQualityOfData(m_encShowDataQual);
14709void ChartCanvas::SetShowENCDataQual(
bool show) {
14710 m_encShowDataQual = show;
14711 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14712 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14714 m_s52StateHash = 0;
14717void ChartCanvas::SetShowENCText(
bool show) {
14718 m_encShowText = show;
14719 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14720 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14722 m_s52StateHash = 0;
14725void ChartCanvas::SetENCDisplayCategory(
int category) {
14726 m_encDisplayCategory = category;
14727 m_s52StateHash = 0;
14730void ChartCanvas::SetShowENCDepth(
bool show) {
14731 m_encShowDepth = show;
14732 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14733 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14735 m_s52StateHash = 0;
14738void ChartCanvas::SetShowENCLightDesc(
bool show) {
14739 m_encShowLightDesc = show;
14740 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14741 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14743 m_s52StateHash = 0;
14746void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14747 m_encShowBuoyLabels = show;
14748 m_s52StateHash = 0;
14751void ChartCanvas::SetShowENCLights(
bool show) {
14752 m_encShowLights = show;
14753 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14754 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14756 m_s52StateHash = 0;
14759void ChartCanvas::SetShowENCAnchor(
bool show) {
14760 m_encShowAnchor = show;
14761 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14762 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14764 m_s52StateHash = 0;
14767wxRect ChartCanvas::GetMUIBarRect() {
14770 rv = m_muiBar->GetRect();
14776void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14777 if (!GetAlertString().IsEmpty()) {
14778 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14779 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14781 dc.SetFont(*pfont);
14782 dc.SetPen(*wxTRANSPARENT_PEN);
14784 dc.SetBrush(wxColour(243, 229, 47));
14786 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14790 wxRect sbr = GetScaleBarRect();
14791 int xp = sbr.x + sbr.width + 10;
14792 int yp = (sbr.y + sbr.height) - h;
14794 int wdraw = w + 10;
14795 dc.DrawRectangle(xp, yp, wdraw, h);
14796 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14797 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14807#define BRIGHT_XCALIB
14808#define __OPCPN_USEICC__
14811#ifdef __OPCPN_USEICC__
14812int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14813 double co_green,
double co_blue);
14815wxString temp_file_name;
14819class ocpnCurtain:
public wxDialog
14821 DECLARE_CLASS( ocpnCurtain )
14822 DECLARE_EVENT_TABLE()
14825 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14827 bool ProcessEvent(wxEvent& event);
14831IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14833BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14836ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14838 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14841ocpnCurtain::~ocpnCurtain()
14845bool ocpnCurtain::ProcessEvent(wxEvent& event)
14847 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14848 return GetParent()->GetEventHandler()->ProcessEvent(event);
14853#include <windows.h>
14856typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14857typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14858SetDeviceGammaRamp_ptr_type
14859 g_pSetDeviceGammaRamp;
14860GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14862WORD *g_pSavedGammaMap;
14866int InitScreenBrightness() {
14869 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14873 if (NULL == hGDI32DLL) {
14874 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14876 if (NULL != hGDI32DLL) {
14878 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14879 hGDI32DLL,
"SetDeviceGammaRamp");
14880 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14881 hGDI32DLL,
"GetDeviceGammaRamp");
14884 if ((NULL == g_pSetDeviceGammaRamp) ||
14885 (NULL == g_pGetDeviceGammaRamp)) {
14886 FreeLibrary(hGDI32DLL);
14895 if (!g_pSavedGammaMap) {
14896 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14899 bbr = g_pGetDeviceGammaRamp(
14900 hDC, g_pSavedGammaMap);
14901 ReleaseDC(NULL, hDC);
14906 wxRegKey *pRegKey =
new wxRegKey(
14907 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14908 "NT\\CurrentVersion\\ICM");
14909 if (!pRegKey->Exists()) pRegKey->Create();
14910 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14912 g_brightness_init =
true;
14918 if (NULL == g_pcurtain) {
14919 if (gFrame->CanSetTransparent()) {
14921 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14922 wxPoint(0, 0), ::wxGetDisplaySize(),
14923 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14924 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14931 g_pcurtain->Hide();
14933 HWND hWnd = GetHwndOf(g_pcurtain);
14934 SetWindowLong(hWnd, GWL_EXSTYLE,
14935 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14936 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14937 g_pcurtain->SetTransparent(0);
14939 g_pcurtain->Maximize();
14940 g_pcurtain->Show();
14943 g_pcurtain->Enable();
14944 g_pcurtain->Disable();
14951 g_brightness_init =
true;
14957 wxString cmd(
"xcalib -version");
14959 wxArrayString output;
14960 long r = wxExecute(cmd, output);
14963 " External application \"xcalib\" not found. Screen brightness "
14966 g_brightness_init =
true;
14971int RestoreScreenBrightness() {
14974 if (g_pSavedGammaMap) {
14975 HDC hDC = GetDC(NULL);
14976 g_pSetDeviceGammaRamp(hDC,
14978 ReleaseDC(NULL, hDC);
14980 free(g_pSavedGammaMap);
14981 g_pSavedGammaMap = NULL;
14985 g_pcurtain->Close();
14986 g_pcurtain->Destroy();
14990 g_brightness_init =
false;
14995#ifdef BRIGHT_XCALIB
14996 if (g_brightness_init) {
14998 cmd =
"xcalib -clear";
14999 wxExecute(cmd, wxEXEC_ASYNC);
15000 g_brightness_init =
false;
15010int SetScreenBrightness(
int brightness) {
15017 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15019 g_pcurtain->Close();
15020 g_pcurtain->Destroy();
15024 InitScreenBrightness();
15026 if (NULL == hGDI32DLL) {
15028 wchar_t wdll_name[80];
15029 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15030 LPCWSTR cstr = wdll_name;
15032 hGDI32DLL = LoadLibrary(cstr);
15034 if (NULL != hGDI32DLL) {
15036 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15037 hGDI32DLL,
"SetDeviceGammaRamp");
15038 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15039 hGDI32DLL,
"GetDeviceGammaRamp");
15042 if ((NULL == g_pSetDeviceGammaRamp) ||
15043 (NULL == g_pGetDeviceGammaRamp)) {
15044 FreeLibrary(hGDI32DLL);
15051 HDC hDC = GetDC(NULL);
15062 int increment = brightness * 256 / 100;
15065 WORD GammaTable[3][256];
15068 for (
int i = 0; i < 256; i++) {
15069 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15070 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15071 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15073 table_val += increment;
15075 if (table_val > 65535) table_val = 65535;
15078 g_pSetDeviceGammaRamp(hDC, GammaTable);
15079 ReleaseDC(NULL, hDC);
15086 if (g_pSavedGammaMap) {
15087 HDC hDC = GetDC(NULL);
15088 g_pSetDeviceGammaRamp(hDC,
15090 ReleaseDC(NULL, hDC);
15093 if (brightness < 100) {
15094 if (NULL == g_pcurtain) InitScreenBrightness();
15097 int sbrite = wxMax(1, brightness);
15098 sbrite = wxMin(100, sbrite);
15100 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15104 g_pcurtain->Close();
15105 g_pcurtain->Destroy();
15115#ifdef BRIGHT_XCALIB
15117 if (!g_brightness_init) {
15118 last_brightness = 100;
15119 g_brightness_init =
true;
15120 temp_file_name = wxFileName::CreateTempFileName(
"");
15121 InitScreenBrightness();
15124#ifdef __OPCPN_USEICC__
15127 if (!CreateSimpleICCProfileFile(
15128 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15129 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15130 wxString cmd(
"xcalib ");
15131 cmd += temp_file_name;
15133 wxExecute(cmd, wxEXEC_ASYNC);
15142 if (brightness > last_brightness) {
15144 cmd =
"xcalib -clear";
15145 wxExecute(cmd, wxEXEC_ASYNC);
15147 ::wxMilliSleep(10);
15149 int brite_adj = wxMax(1, brightness);
15150 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15151 wxExecute(cmd, wxEXEC_ASYNC);
15153 int brite_adj = wxMax(1, brightness);
15154 int factor = (brite_adj * 100) / last_brightness;
15155 factor = wxMax(1, factor);
15157 cmd.Printf(
"xcalib -co %2d -a", factor);
15158 wxExecute(cmd, wxEXEC_ASYNC);
15163 last_brightness = brightness;
15170#ifdef __OPCPN_USEICC__
15172#define MLUT_TAG 0x6d4c5554L
15173#define VCGT_TAG 0x76636774L
15175int GetIntEndian(
unsigned char *s) {
15180 p = (
unsigned char *)&ret;
15183 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15185 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15190unsigned short GetShortEndian(
unsigned char *s) {
15191 unsigned short ret;
15195 p = (
unsigned char *)&ret;
15198 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15200 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15206int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15207 double co_green,
double co_blue) {
15211 fp = fopen(file_name,
"wb");
15212 if (!fp)
return -1;
15218 for (
int i = 0; i < 128; i++) header[i] = 0;
15220 fwrite(header, 128, 1, fp);
15224 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15225 fwrite(&numTags, 1, 4, fp);
15227 int tagName0 = VCGT_TAG;
15228 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15229 fwrite(&tagName, 1, 4, fp);
15231 int tagOffset0 = 128 + 4 *
sizeof(int);
15232 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15233 fwrite(&tagOffset, 1, 4, fp);
15236 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15237 fwrite(&tagSize, 1, 4, fp);
15239 fwrite(&tagName, 1, 4, fp);
15241 fwrite(&tagName, 1, 4, fp);
15246 int gammatype0 = 0;
15247 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15248 fwrite(&gammatype, 1, 4, fp);
15250 int numChannels0 = 3;
15251 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15252 fwrite(&numChannels, 1, 2, fp);
15254 int numEntries0 = 256;
15255 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15256 fwrite(&numEntries, 1, 2, fp);
15258 int entrySize0 = 1;
15259 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15260 fwrite(&entrySize, 1, 2, fp);
15262 unsigned char ramp[256];
15265 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15266 fwrite(ramp, 256, 1, fp);
15269 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15270 fwrite(ramp, 256, 1, fp);
15273 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15274 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...
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.