35#include <wx/graphics.h>
36#include <wx/clipbrd.h>
37#include <wx/aui/aui.h>
41#include "o_sound/o_sound.h"
48#include "model/geodesic.h"
54#include "model/nav_object_database.h"
113#include "tide_time.h"
120#include "s57_ocpn_utils.h"
123#include "androidUTIL.h"
133#include <wx/msw/msvcrt.h>
142#define printf printf2
144int __cdecl printf2(
const char *format, ...) {
148 va_start(argptr, format);
149 int ret = vsnprintf(str,
sizeof(str), format, argptr);
151 OutputDebugStringA(str);
156#if defined(__MSVC__) && (_MSC_VER < 1700)
157#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
163#define OCPN_ALT_MENUBAR 1
171extern ColorScheme global_color_scheme;
172extern wxColor GetDimColor(wxColor c);
176static bool g_bSmoothRecenter =
true;
177static bool bDrawCurrentValues;
198static bool mouse_leftisdown;
199static bool g_brouteCreating;
200static int r_gamma_mult;
201static int g_gamma_mult;
202static int b_gamma_mult;
203static int gamma_state;
204static bool g_brightness_init;
205static int last_brightness;
206static wxGLContext *g_pGLcontext;
209static wxDialog *g_pcurtain;
211static wxString g_lastS52PLIBPluginMessage;
214#define MAX_BRIGHT 100
221EVT_ACTIVATE(ChartCanvas::OnActivate)
222EVT_SIZE(ChartCanvas::OnSize)
223#ifndef HAVE_WX_GESTURE_EVENTS
224EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
226EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
227EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
228EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
229EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
230EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
231EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
232EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
233EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
234EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
235EVT_KEY_UP(ChartCanvas::OnKeyUp)
236EVT_CHAR(ChartCanvas::OnKeyChar)
237EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
238EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
239EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
240EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
241EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
242EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
243EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
244EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
245EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
246EVT_TIMER(TAP_TIMER, ChartCanvas::OnTapTimer)
252 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
253 m_nmea_log(nmea_log) {
254 parent_frame = (
MyFrame *)frame;
255 m_canvasIndex = canvasIndex;
259 SetBackgroundColour(wxColour(0, 0, 0));
260 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
264 m_bDrawingRoute =
false;
265 m_bRouteEditing =
false;
266 m_bMarkEditing =
false;
267 m_bRoutePoinDragging =
false;
268 m_bIsInRadius =
false;
269 m_bMayToggleMenuBar =
true;
272 m_bShowNavobjects =
true;
274 m_bAppendingRoute =
false;
275 pThumbDIBShow = NULL;
276 m_bShowCurrent =
false;
278 bShowingCurrent =
false;
282 m_b_paint_enable =
true;
285 pss_overlay_bmp = NULL;
286 pss_overlay_mask = NULL;
287 m_bChartDragging =
false;
288 m_bMeasure_Active =
false;
289 m_bMeasure_DistCircle =
false;
290 m_pMeasureRoute = NULL;
291 m_pTrackRolloverWin = NULL;
292 m_pRouteRolloverWin = NULL;
293 m_pAISRolloverWin = NULL;
295 m_disable_edge_pan =
false;
296 m_dragoffsetSet =
false;
300 m_singleChart = NULL;
301 m_upMode = NORTH_UP_MODE;
303 m_bShowAISScaled =
false;
304 m_timed_move_vp_active =
false;
306 m_disable_adjust_on_zoom =
false;
313 m_pSelectedRoute = NULL;
314 m_pSelectedTrack = NULL;
315 m_pRoutePointEditTarget = NULL;
316 m_pFoundPoint = NULL;
317 m_pMouseRoute = NULL;
318 m_prev_pMousePoint = NULL;
319 m_pEditRouteArray = NULL;
320 m_pFoundRoutePoint = NULL;
321 m_FinishRouteOnKillFocus =
true;
323 m_pRolloverRouteSeg = NULL;
324 m_pRolloverTrackSeg = NULL;
325 m_bsectors_shown =
false;
327 m_bbrightdir =
false;
332 m_pos_image_user_day = NULL;
333 m_pos_image_user_dusk = NULL;
334 m_pos_image_user_night = NULL;
335 m_pos_image_user_grey_day = NULL;
336 m_pos_image_user_grey_dusk = NULL;
337 m_pos_image_user_grey_night = NULL;
340 m_rotation_speed = 0;
346 m_pos_image_user_yellow_day = NULL;
347 m_pos_image_user_yellow_dusk = NULL;
348 m_pos_image_user_yellow_night = NULL;
350 SetOwnShipState(SHIP_INVALID);
352 undo =
new Undo(
this);
358 m_focus_indicator_pix = 1;
360 m_pCurrentStack = NULL;
361 m_bpersistent_quilt =
false;
362 m_piano_ctx_menu = NULL;
364 m_NotificationsList = NULL;
365 m_notification_button = NULL;
367 g_ChartNotRenderScaleFactor = 2.0;
368 m_bShowScaleInStatusBar =
true;
371 m_bShowScaleInStatusBar =
false;
372 m_show_focus_bar =
true;
374 m_bShowOutlines =
false;
375 m_bDisplayGrid =
false;
376 m_bShowDepthUnits =
true;
377 m_encDisplayCategory = (int)STANDARD;
379 m_encShowLights =
true;
380 m_encShowAnchor =
true;
381 m_encShowDataQual =
false;
383 m_pQuilt =
new Quilt(
this);
388 g_PrintingInProgress =
false;
390#ifdef HAVE_WX_GESTURE_EVENTS
391 m_oldVPSScale = -1.0;
392 m_popupWanted =
false;
395 m_inLongPress =
false;
398 m_sw_left_down.Start();
399 m_sw_left_up.Start();
403 singleClickEventIsValid =
false;
412 pCursorPencil = NULL;
417 SetCursor(*pCursorArrow);
419 pPanTimer =
new wxTimer(
this, m_MouseDragging);
422 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
423 pMovementTimer->Stop();
425 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
426 pMovementStopTimer->Stop();
428 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
429 pRotDefTimer->Stop();
431 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
432 m_DoubleClickTimer->Stop();
434 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
435 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
436 m_chart_drag_inertia_active =
false;
438 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
439 m_animationActive =
false;
440 m_menuTimer.SetOwner(
this, MENU_TIMER);
441 m_tap_timer.SetOwner(
this, TAP_TIMER);
445 m_panx_target_final = m_pany_target_final = 0;
446 m_panx_target_now = m_pany_target_now = 0;
449 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
450 pCurTrackTimer->Stop();
451 m_curtrack_timer_msec = 10;
453 m_wheelzoom_stop_oneshot = 0;
454 m_last_wheel_dir = 0;
456 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
458 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
460 m_rollover_popup_timer_msec = 20;
462 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
464 m_b_rot_hidef =
true;
469 m_upMode = NORTH_UP_MODE;
470 m_bLookAhead =
false;
474 m_cs = GLOBAL_COLOR_SCHEME_DAY;
477 VPoint.view_scale_ppm = 1;
480 m_ignore_next_leftup =
false;
482 m_canvas_scale_factor = 1.;
484 m_canvas_width = 1000;
486 m_overzoomTextWidth = 0;
487 m_overzoomTextHeight = 0;
496 m_pEM_Fathoms = NULL;
498 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
500 m_pEM_OverZoom = NULL;
502 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
510 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
513 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
516 double factor_dusk = 0.5;
517 double factor_night = 0.25;
520 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
522 int rimg_width = m_os_image_red_day.GetWidth();
523 int rimg_height = m_os_image_red_day.GetHeight();
525 m_os_image_red_dusk = m_os_image_red_day.Copy();
526 m_os_image_red_night = m_os_image_red_day.Copy();
528 for (
int iy = 0; iy < rimg_height; iy++) {
529 for (
int ix = 0; ix < rimg_width; ix++) {
530 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
531 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
532 m_os_image_red_day.GetGreen(ix, iy),
533 m_os_image_red_day.GetBlue(ix, iy));
534 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
535 hsv.value = hsv.value * factor_dusk;
536 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
537 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
539 hsv = wxImage::RGBtoHSV(rgb);
540 hsv.value = hsv.value * factor_night;
541 nrgb = wxImage::HSVtoRGB(hsv);
542 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
548 m_os_image_grey_day =
549 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
551 int gimg_width = m_os_image_grey_day.GetWidth();
552 int gimg_height = m_os_image_grey_day.GetHeight();
554 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
555 m_os_image_grey_night = m_os_image_grey_day.Copy();
557 for (
int iy = 0; iy < gimg_height; iy++) {
558 for (
int ix = 0; ix < gimg_width; ix++) {
559 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
560 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
561 m_os_image_grey_day.GetGreen(ix, iy),
562 m_os_image_grey_day.GetBlue(ix, iy));
563 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
564 hsv.value = hsv.value * factor_dusk;
565 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
566 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
568 hsv = wxImage::RGBtoHSV(rgb);
569 hsv.value = hsv.value * factor_night;
570 nrgb = wxImage::HSVtoRGB(hsv);
571 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
577 m_os_image_yellow_day = m_os_image_red_day.Copy();
579 gimg_width = m_os_image_yellow_day.GetWidth();
580 gimg_height = m_os_image_yellow_day.GetHeight();
582 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
583 m_os_image_yellow_night = m_os_image_red_day.Copy();
585 for (
int iy = 0; iy < gimg_height; iy++) {
586 for (
int ix = 0; ix < gimg_width; ix++) {
587 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
588 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
589 m_os_image_yellow_day.GetGreen(ix, iy),
590 m_os_image_yellow_day.GetBlue(ix, iy));
591 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
592 hsv.hue += 60. / 360.;
593 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
594 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
596 hsv = wxImage::RGBtoHSV(rgb);
597 hsv.value = hsv.value * factor_dusk;
598 hsv.hue += 60. / 360.;
599 nrgb = wxImage::HSVtoRGB(hsv);
600 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
602 hsv = wxImage::RGBtoHSV(rgb);
603 hsv.hue += 60. / 360.;
604 hsv.value = hsv.value * factor_night;
605 nrgb = wxImage::HSVtoRGB(hsv);
606 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
612 m_pos_image_red = &m_os_image_red_day;
613 m_pos_image_yellow = &m_os_image_yellow_day;
614 m_pos_image_grey = &m_os_image_grey_day;
618 m_pBrightPopup = NULL;
621 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
626 m_Piano =
new Piano(
this);
628 m_bShowCompassWin =
true;
630 m_Compass->SetScaleFactor(g_compass_scalefactor);
631 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
633 if (IsPrimaryCanvas()) {
635 m_notification_button->SetScaleFactor(g_compass_scalefactor);
636 m_notification_button->Show(
true);
639 m_pianoFrozen =
false;
641 SetMinSize(wxSize(200, 200));
643 m_displayScale = 1.0;
644#if defined(__WXOSX__) || defined(__WXGTK3__)
646 m_displayScale = GetContentScaleFactor();
648 VPoint.SetPixelScale(m_displayScale);
650#ifdef HAVE_WX_GESTURE_EVENTS
653 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
654 wxLogError(
"Failed to enable touch events");
659 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
660 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
662 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
663 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
665 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
666 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
668 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
669 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
674 auto ¬eman = NotificationManager::GetInstance();
676 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
677 evt_notificationlist_change_listener.Listen(
678 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
679 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
680 if (m_NotificationsList && m_NotificationsList->IsShown()) {
681 m_NotificationsList->ReloadNotificationList();
687ChartCanvas::~ChartCanvas() {
688 delete pThumbDIBShow;
696 delete pCursorPencil;
700 delete pMovementTimer;
701 delete pMovementStopTimer;
702 delete pCurTrackTimer;
704 delete m_DoubleClickTimer;
706 delete m_pTrackRolloverWin;
707 delete m_pRouteRolloverWin;
708 delete m_pAISRolloverWin;
709 delete m_pBrightPopup;
715 m_dc_route.SelectObject(wxNullBitmap);
718 delete pWorldBackgroundChart;
719 delete pss_overlay_bmp;
723 delete m_pEM_Fathoms;
725 delete m_pEM_OverZoom;
730 delete m_pos_image_user_day;
731 delete m_pos_image_user_dusk;
732 delete m_pos_image_user_night;
733 delete m_pos_image_user_grey_day;
734 delete m_pos_image_user_grey_dusk;
735 delete m_pos_image_user_grey_night;
736 delete m_pos_image_user_yellow_day;
737 delete m_pos_image_user_yellow_dusk;
738 delete m_pos_image_user_yellow_night;
742 if (!g_bdisable_opengl) {
745#if wxCHECK_VERSION(2, 9, 0)
746 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
753 MUIBar *muiBar = m_muiBar;
757 delete m_pCurrentStack;
760 delete m_notification_button;
763void ChartCanvas::SetupGridFont() {
764 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
766 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
768 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
769 FALSE, wxString(
"Arial"));
772void ChartCanvas::RebuildCursors() {
778 delete pCursorPencil;
782 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
786 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
787 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
788 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
789 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
790 wxImage ICursorPencil =
791 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
792 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
794#if !defined(__WXMSW__) && !defined(__WXQT__)
795 ICursorLeft.ConvertAlphaToMask(128);
796 ICursorRight.ConvertAlphaToMask(128);
797 ICursorUp.ConvertAlphaToMask(128);
798 ICursorDown.ConvertAlphaToMask(128);
799 ICursorPencil.ConvertAlphaToMask(10);
800 ICursorCross.ConvertAlphaToMask(10);
803 if (ICursorLeft.Ok()) {
804 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
805 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
806 pCursorLeft =
new wxCursor(ICursorLeft);
808 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
810 if (ICursorRight.Ok()) {
811 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
812 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
813 pCursorRight =
new wxCursor(ICursorRight);
815 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
817 if (ICursorUp.Ok()) {
818 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
819 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
820 pCursorUp =
new wxCursor(ICursorUp);
822 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
824 if (ICursorDown.Ok()) {
825 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
826 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
827 pCursorDown =
new wxCursor(ICursorDown);
829 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
831 if (ICursorPencil.Ok()) {
832 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
833 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
834 pCursorPencil =
new wxCursor(ICursorPencil);
836 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
838 if (ICursorCross.Ok()) {
839 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
840 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
841 pCursorCross =
new wxCursor(ICursorCross);
843 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
845 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
846 pPlugIn_Cursor = NULL;
849void ChartCanvas::CanvasApplyLocale() {
850 CreateDepthUnitEmbossMaps(m_cs);
851 CreateOZEmbossMapData(m_cs);
854void ChartCanvas::SetupGlCanvas() {
857 if (!g_bdisable_opengl) {
859 wxLogMessage(
"Creating glChartCanvas");
864 if (IsPrimaryCanvas()) {
871 wxGLContext *pctx =
new wxGLContext(m_glcc);
872 m_glcc->SetContext(pctx);
876 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
878 m_glcc->SetContext(g_pGLcontext);
888 if (!g_bdisable_opengl) {
891 wxLogMessage(
"Creating glChartCanvas");
895 if (IsPrimaryCanvas()) {
896 qDebug() <<
"Creating Primary glChartCanvas";
904 wxGLContext *pctx =
new wxGLContext(m_glcc);
905 m_glcc->SetContext(pctx);
907 m_glcc->m_pParentCanvas =
this;
910 qDebug() <<
"Creating Secondary glChartCanvas";
916 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
919 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
920 m_glcc->SetContext(pwxctx);
921 m_glcc->m_pParentCanvas =
this;
929void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
930 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
945 if (m_routeState && m_FinishRouteOnKillFocus)
946 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
948 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
952void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
953 m_routeFinishTimer.Stop();
957 gFrame->UpdateGlobalMenuItems(
this);
959 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
962void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
963 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
966#ifdef HAVE_WX_GESTURE_EVENTS
967void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
974 m_popupWanted =
true;
976 m_inLongPress = !g_bhide_context_menus;
979 m_menuPos =
event.GetPosition();
980 wxMouseEvent ev(wxEVT_LEFT_UP);
981 ev.m_x = m_menuPos.x;
982 ev.m_y = m_menuPos.y;
983 wxPostEvent(
this, ev);
987 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
988 ev_right_click.m_x = m_menuPos.x;
989 ev_right_click.m_y = m_menuPos.y;
990 MouseEvent(ev_right_click);
995void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
999void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1001void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1003void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1005 long dt = m_sw_left_up.Time() - m_sw_up_time;
1006 m_sw_up_time = m_sw_left_up.Time();
1017 wxPoint pos =
event.GetPosition();
1021 if (!m_popupWanted) {
1022 wxMouseEvent ev(wxEVT_LEFT_UP);
1029 m_popupWanted =
false;
1031 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1038void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1043 long dt = m_sw_left_down.Time() - m_sw_down_time;
1044 m_sw_down_time = m_sw_left_down.Time();
1068 int max_double_click_distance = wxSystemSettings::GetMetric(wxSYS_DCLICK_X) *
1070 wxRect tap_area(m_lastTapPos.x - max_double_click_distance,
1071 m_lastTapPos.y - max_double_click_distance,
1072 max_double_click_distance * 2, max_double_click_distance * 2);
1075 if (m_tap_timer.IsRunning() && tap_area.Contains(event.GetPosition())) {
1081 m_lastTapPos =
event.GetPosition();
1082 m_tap_timer.StartOnce(
1086 if (m_tap_count == 2) {
1090 wxMouseEvent ev(wxEVT_LEFT_DCLICK);
1103void ChartCanvas::OnMotion(wxMouseEvent &event) {
1108 event.m_leftDown = m_leftdown;
1112void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1114 if (event.IsGestureEnd())
return;
1116 double factor =
event.GetZoomFactor();
1118 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1123 double wanted_factor = m_oldVPSScale / current_vps * factor;
1128 if (event.IsGestureStart()) {
1129 m_zoomStartPoint =
event.GetPosition();
1131 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1133 m_zoomStartPoint =
event.GetPosition();
1137void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1139void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1140 DoRotateCanvas(0.0);
1144void ChartCanvas::OnTapTimer(wxTimerEvent &event) {
1149void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1150 m_FinishRouteOnKillFocus =
false;
1151 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1152 m_FinishRouteOnKillFocus =
true;
1155void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1160 m_restore_dbindex = pcc->DBindex;
1162 if (pcc->GroupID < 0) pcc->GroupID = 0;
1167 m_groupIndex = pcc->GroupID;
1169 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1183 m_encDisplayCategory = pcc->nENCDisplayCategory;
1184 m_encShowDepth = pcc->bShowENCDepths;
1185 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1186 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1187 m_encShowLights = pcc->bShowENCLights;
1188 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1189 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1190 m_encShowDataQual = pcc->bShowENCDataQuality;
1194 m_upMode = NORTH_UP_MODE;
1196 m_upMode = COURSE_UP_MODE;
1198 m_upMode = HEAD_UP_MODE;
1202 m_singleChart = NULL;
1205void ChartCanvas::ApplyGlobalSettings() {
1208 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1209 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1211 if (m_notification_button) m_notification_button->UpdateStatus();
1214void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1215 bool groupOK = CheckGroup(m_groupIndex);
1218 SetGroupIndex(m_groupIndex,
true);
1222void ChartCanvas::SetShowGPS(
bool bshow) {
1223 if (m_bShowGPS != bshow) {
1226 m_Compass->SetScaleFactor(g_compass_scalefactor);
1227 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1232void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1233 m_bShowCompassWin = bshow;
1235 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1236 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1240int ChartCanvas::GetPianoHeight() {
1242 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1247void ChartCanvas::ConfigureChartBar() {
1250 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1251 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1253 if (GetQuiltMode()) {
1254 m_Piano->SetRoundedRectangles(
true);
1256 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1257 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1258 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1261void ChartCanvas::ShowTides(
bool bShow) {
1262 gFrame->LoadHarmonics();
1265 SetbShowTide(bShow);
1267 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1269 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1270 SetbShowTide(
false);
1271 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1274 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1275 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1286void ChartCanvas::ShowCurrents(
bool bShow) {
1287 gFrame->LoadHarmonics();
1290 SetbShowCurrent(bShow);
1291 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1293 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1294 SetbShowCurrent(
false);
1295 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1298 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1299 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1316void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1318void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1321 int new_index = index;
1324 bool bgroup_override =
false;
1325 int old_group_index = new_index;
1327 if (!CheckGroup(new_index)) {
1329 bgroup_override =
true;
1332 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1336 int current_chart_native_scale = GetCanvasChartNativeScale();
1339 m_groupIndex = new_index;
1345 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1349 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1353 g_sticky_chart = -1;
1357 UpdateCanvasOnGroupChange();
1360 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1362 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1365 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1366 double best_scale = GetBestStartScale(dbi_hint, vp);
1370 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1374 canvasChartsRefresh(dbi_hint);
1376 UpdateCanvasControlBar();
1378 if (!autoSwitch && bgroup_override) {
1380 wxString msg(_(
"Group \""));
1383 msg += pGroup->m_group_name;
1385 msg += _(
"\" is empty.");
1387 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1394 if (bgroup_override) {
1395 wxString msg(_(
"Group \""));
1398 msg += pGroup->m_group_name;
1400 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1402 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1406bool ChartCanvas::CheckGroup(
int igroup) {
1409 if (igroup == 0)
return true;
1416 if (pGroup->m_element_array.empty())
1420 for (
const auto &elem : pGroup->m_element_array) {
1421 for (
unsigned int ic = 0;
1422 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1424 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1426 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1431 for (
const auto &elem : pGroup->m_element_array) {
1432 const wxString &element_root = elem.m_element_name;
1433 wxString test_string =
"GSHH";
1434 if (element_root.Upper().Contains(test_string))
return true;
1440void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1443 AbstractPlatform::ShowBusySpinner();
1447 SetQuiltRefChart(-1);
1449 m_singleChart = NULL;
1455 if (!m_pCurrentStack) {
1457 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1460 if (-1 != dbi_hint) {
1461 if (GetQuiltMode()) {
1462 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1463 SetQuiltRefChart(dbi_hint);
1467 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1469 if (pTentative_Chart) {
1472 if (m_singleChart) m_singleChart->Deactivate();
1474 m_singleChart = pTentative_Chart;
1475 m_singleChart->Activate();
1477 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1478 GetpCurrentStack(), m_singleChart->GetFullPath());
1486 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1487 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1488 SetQuiltRefChart(selected_index);
1492 SetupCanvasQuiltMode();
1493 if (!GetQuiltMode() && m_singleChart == 0) {
1495 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1496 m_singleChart = pDummyChart;
1502 UpdateCanvasControlBar();
1503 UpdateGPSCompassStatusBox(
true);
1505 SetCursor(wxCURSOR_ARROW);
1507 AbstractPlatform::HideBusySpinner();
1510bool ChartCanvas::DoCanvasUpdate() {
1512 double vpLat, vpLon;
1513 bool blong_jump =
false;
1514 meters_to_shift = 0;
1517 bool bNewChart =
false;
1518 bool bNewView =
false;
1519 bool bCanvasChartAutoOpen =
true;
1521 bool bNewPiano =
false;
1522 bool bOpenSpecified;
1528 if (bDBUpdateInProgress)
return false;
1532 if (m_chart_drag_inertia_active)
return false;
1558 double dx = m_OSoffsetx;
1559 double dy = m_OSoffsety;
1563 if (GetUpMode() == NORTH_UP_MODE) {
1564 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1566 double offset_angle = atan2(d_north, d_east);
1567 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1568 double chart_angle = GetVPRotation();
1569 double target_angle = chart_angle + offset_angle;
1570 double d_east_mod = offset_distance * cos(target_angle);
1571 double d_north_mod = offset_distance * sin(target_angle);
1572 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1576 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1577 double cog_to_use =
gCog;
1579 (fabs(
gCog - gCog_gt) > 20)) {
1580 cog_to_use = gCog_gt;
1583 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1585 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1587 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1588 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1590 double pixel_delta_tent =
1591 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1593 double pixel_delta = 0;
1598 if (!std::isnan(
gSog)) {
1602 pixel_delta = pixel_delta_tent;
1605 meters_to_shift = 0;
1607 if (!std::isnan(
gCog)) {
1608 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1609 dir_to_shift = cog_to_use;
1610 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1616 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1630 if (GetQuiltMode()) {
1631 int current_db_index = -1;
1632 if (m_pCurrentStack)
1635 ->GetCurrentEntrydbIndex();
1643 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1645 if (m_pCurrentStack->nEntry) {
1646 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1648 SelectQuiltRefdbChart(new_dbIndex,
true);
1649 m_bautofind =
false;
1653 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1654 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1659 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1665 double proposed_scale_onscreen =
1668 int initial_db_index = m_restore_dbindex;
1669 if (initial_db_index < 0) {
1670 if (m_pCurrentStack->nEntry) {
1672 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1677 if (m_pCurrentStack->nEntry) {
1678 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1683 if (!IsChartQuiltableRef(initial_db_index)) {
1687 int stack_index = 0;
1689 if (stack_index >= 0) {
1690 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1691 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1692 if (IsChartQuiltableRef(test_db_index) &&
1694 ChartData->GetDBChartType(initial_db_index))) {
1695 initial_db_index = test_db_index;
1705 SetQuiltRefChart(initial_db_index);
1706 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1714 0, GetVPRotation());
1719 bool super_jump =
false;
1721 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1722 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1723 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1726 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1728 if (blong_jump) nstep = 20;
1729 StartTimedMovementVP(vpLat, vpLon, nstep);
1740 pLast_Ch = m_singleChart;
1741 ChartTypeEnum new_open_type;
1742 ChartFamilyEnum new_open_family;
1744 new_open_type = pLast_Ch->GetChartType();
1745 new_open_family = pLast_Ch->GetChartFamily();
1747 new_open_type = CHART_TYPE_KAP;
1748 new_open_family = CHART_FAMILY_RASTER;
1751 bOpenSpecified = m_bFirstAuto;
1754 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1757 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1759 if (NULL == pDummyChart) {
1765 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1767 m_singleChart = pDummyChart;
1772 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1774 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1777 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1778 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1785 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1791 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1796 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1799 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1804 if (NULL != m_singleChart)
1805 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1806 m_singleChart->GetFullPath());
1809 m_pCurrentStack->CurrentStackEntry = tEntry;
1819 if (bCanvasChartAutoOpen) {
1820 bool search_direction =
1822 int start_index = 0;
1826 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1827 (LastStack.nEntry == 0)) {
1828 search_direction =
true;
1829 start_index = m_pCurrentStack->nEntry - 1;
1833 if (bOpenSpecified) {
1834 search_direction =
false;
1836 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1839 new_open_type = CHART_TYPE_DONTCARE;
1842 pProposed =
ChartData->OpenStackChartConditional(
1843 m_pCurrentStack, start_index, search_direction, new_open_type,
1847 if (NULL == pProposed)
1848 pProposed =
ChartData->OpenStackChartConditional(
1849 m_pCurrentStack, start_index, search_direction,
1850 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1852 if (NULL == pProposed)
1853 pProposed =
ChartData->OpenStackChartConditional(
1854 m_pCurrentStack, start_index, search_direction,
1855 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1866 if (NULL == pProposed) {
1867 if (NULL == pDummyChart) {
1873 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1875 pProposed = pDummyChart;
1879 if (m_singleChart) m_singleChart->Deactivate();
1880 m_singleChart = pProposed;
1882 if (m_singleChart) {
1883 m_singleChart->Activate();
1884 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1885 m_pCurrentStack, m_singleChart->GetFullPath());
1890 if (NULL != m_singleChart) {
1896 if (!GetVP().IsValid())
1897 set_scale = 1. / 20000.;
1899 double proposed_scale_onscreen;
1902 double new_scale_ppm =
1903 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1911 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1912 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1913 double equivalent_vp_scale =
1915 double new_scale_ppm =
1916 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1921 proposed_scale_onscreen =
1922 wxMin(proposed_scale_onscreen,
1925 proposed_scale_onscreen =
1926 wxMax(proposed_scale_onscreen,
1935 m_singleChart->GetChartSkew() * PI / 180.,
1942 if ((m_bFollow) && m_singleChart)
1944 m_singleChart->GetChartSkew() * PI / 180.,
1953 m_bFirstAuto =
false;
1957 if (bNewChart && !bNewView) Refresh(
false);
1962 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1965 return bNewChart | bNewView;
1968void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1969 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1971 SetQuiltRefChart(db_index);
1976 double best_scale_ppm = GetBestVPScale(pc);
1980 SetQuiltRefChart(-1);
1982 SetQuiltRefChart(-1);
1985void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1986 std::vector<int> piano_chart_index_array =
1987 GetQuiltExtendedStackdbIndexArray();
1988 int current_db_index = piano_chart_index_array[selected_index];
1990 SelectQuiltRefdbChart(current_db_index);
1993double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1997 if ((g_bPreserveScaleOnX) ||
1998 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
2004 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
2005 double equivalent_vp_scale =
2007 double new_scale_ppm =
2008 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
2015 double max_underzoom_multiplier = 2.0;
2016 if (GetVP().b_quilt) {
2017 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
2018 pchart->GetChartType(),
2019 pchart->GetChartFamily());
2020 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
2023 proposed_scale_onscreen = wxMin(
2024 proposed_scale_onscreen,
2026 max_underzoom_multiplier);
2029 proposed_scale_onscreen =
2030 wxMax(proposed_scale_onscreen,
2038void ChartCanvas::SetupCanvasQuiltMode() {
2043 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2047 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2048 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2049 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2050 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2052 m_Piano->SetRoundedRectangles(
true);
2055 int target_new_dbindex = -1;
2056 if (m_pCurrentStack) {
2057 target_new_dbindex =
2058 GetQuiltReferenceChartIndex();
2060 if (-1 != target_new_dbindex) {
2061 if (!IsChartQuiltableRef(target_new_dbindex)) {
2062 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
2063 int type =
ChartData->GetDBChartType(target_new_dbindex);
2066 int stack_index = m_pCurrentStack->CurrentStackEntry;
2068 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2069 (stack_index >= 0)) {
2070 int proj_tent =
ChartData->GetDBChartProj(
2071 m_pCurrentStack->GetDBIndex(stack_index));
2072 int type_tent =
ChartData->GetDBChartType(
2073 m_pCurrentStack->GetDBIndex(stack_index));
2075 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2076 if ((proj == proj_tent) && (type_tent == type)) {
2077 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2087 if (IsChartQuiltableRef(target_new_dbindex))
2088 SelectQuiltRefdbChart(target_new_dbindex,
2091 SelectQuiltRefdbChart(-1,
false);
2093 m_singleChart = NULL;
2096 AdjustQuiltRefChart();
2104 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2108 std::vector<int> empty_array;
2109 m_Piano->SetActiveKeyArray(empty_array);
2110 m_Piano->SetNoshowIndexArray(empty_array);
2111 m_Piano->SetEclipsedIndexArray(empty_array);
2114 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2115 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2116 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2117 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2119 m_Piano->SetRoundedRectangles(
false);
2125 if (!GetQuiltMode()) {
2130 if (m_bFollow ==
true) {
2138 if (!m_singleChart) {
2141 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2149 int cur_max_scale = (int)1e8;
2151 ChartBase *pChart = GetFirstQuiltChart();
2155 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2157 if (pChart->GetNativeScale() < cur_max_scale) {
2158 Candidate_Chart = pChart;
2159 cur_max_scale = pChart->GetNativeScale();
2162 pChart = GetNextQuiltChart();
2165 m_singleChart = Candidate_Chart;
2169 if (NULL == m_singleChart) {
2170 m_singleChart =
ChartData->OpenStackChartConditional(
2171 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2172 CHART_FAMILY_DONTCARE);
2178 InvalidateAllQuiltPatchs();
2180 if (m_singleChart) {
2181 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2182 std::vector<int> one_array;
2183 one_array.push_back(dbi);
2184 m_Piano->SetActiveKeyArray(one_array);
2187 if (m_singleChart) {
2188 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2192 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2196bool ChartCanvas::IsTempMenuBarEnabled() {
2199 wxGetOsVersion(&major);
2207double ChartCanvas::GetCanvasRangeMeters() {
2209 GetSize(&width, &height);
2210 int minDimension = wxMin(width, height);
2213 range *= cos(GetVP().clat * PI / 180.);
2217void ChartCanvas::SetCanvasRangeMeters(
double range) {
2219 GetSize(&width, &height);
2220 int minDimension = wxMin(width, height);
2222 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2226bool ChartCanvas::SetUserOwnship() {
2230 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2231 double factor_dusk = 0.5;
2232 double factor_night = 0.25;
2234 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2235 m_pos_image_user_day =
new wxImage;
2236 *m_pos_image_user_day = pbmp->ConvertToImage();
2237 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2239 int gimg_width = m_pos_image_user_day->GetWidth();
2240 int gimg_height = m_pos_image_user_day->GetHeight();
2243 m_pos_image_user_dusk =
new wxImage;
2244 m_pos_image_user_night =
new wxImage;
2246 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2247 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2249 for (
int iy = 0; iy < gimg_height; iy++) {
2250 for (
int ix = 0; ix < gimg_width; ix++) {
2251 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2252 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2253 m_pos_image_user_day->GetGreen(ix, iy),
2254 m_pos_image_user_day->GetBlue(ix, iy));
2255 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2256 hsv.value = hsv.value * factor_dusk;
2257 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2258 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2261 hsv = wxImage::RGBtoHSV(rgb);
2262 hsv.value = hsv.value * factor_night;
2263 nrgb = wxImage::HSVtoRGB(hsv);
2264 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2271 m_pos_image_user_grey_day =
new wxImage;
2272 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2274 m_pos_image_user_grey_dusk =
new wxImage;
2275 m_pos_image_user_grey_night =
new wxImage;
2277 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2278 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2280 for (
int iy = 0; iy < gimg_height; iy++) {
2281 for (
int ix = 0; ix < gimg_width; ix++) {
2282 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2283 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2284 m_pos_image_user_grey_day->GetGreen(ix, iy),
2285 m_pos_image_user_grey_day->GetBlue(ix, iy));
2286 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2287 hsv.value = hsv.value * factor_dusk;
2288 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2289 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2292 hsv = wxImage::RGBtoHSV(rgb);
2293 hsv.value = hsv.value * factor_night;
2294 nrgb = wxImage::HSVtoRGB(hsv);
2295 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2302 m_pos_image_user_yellow_day =
new wxImage;
2303 m_pos_image_user_yellow_dusk =
new wxImage;
2304 m_pos_image_user_yellow_night =
new wxImage;
2306 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2307 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2308 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2310 for (
int iy = 0; iy < gimg_height; iy++) {
2311 for (
int ix = 0; ix < gimg_width; ix++) {
2312 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2313 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2314 m_pos_image_user_grey_day->GetGreen(ix, iy),
2315 m_pos_image_user_grey_day->GetBlue(ix, iy));
2319 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2320 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2321 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2323 hsv = wxImage::RGBtoHSV(rgb);
2324 hsv.value = hsv.value * factor_dusk;
2325 nrgb = wxImage::HSVtoRGB(hsv);
2326 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2328 hsv = wxImage::RGBtoHSV(rgb);
2329 hsv.value = hsv.value * factor_night;
2330 nrgb = wxImage::HSVtoRGB(hsv);
2331 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2343 m_display_size_mm = size;
2350 double horizontal = sd.x;
2354 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2355 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2359 ps52plib->SetPPMM(m_pix_per_mm);
2364 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2366 m_display_size_mm, sd.x, sd.y);
2372 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2375 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2378void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2380 wxString msg(event.m_string.c_str(), wxConvUTF8);
2382 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2383 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2386 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2388 compress_msg_array.RemoveAt(event.thread);
2389 compress_msg_array.Insert( msg, event.thread);
2392 compress_msg_array.Add(msg);
2395 wxString combined_msg;
2396 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2397 combined_msg += compress_msg_array[i];
2398 combined_msg +=
"\n";
2402 pprog->Update(pprog_count, combined_msg, &skip );
2403 pprog->SetSize(pprog_size);
2408void ChartCanvas::InvalidateGL() {
2409 if (!m_glcc)
return;
2411 if (g_bopengl) m_glcc->Invalidate();
2413 if (m_Compass) m_Compass->UpdateStatus(
true);
2416int ChartCanvas::GetCanvasChartNativeScale() {
2418 if (!VPoint.b_quilt) {
2419 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2421 ret = (int)m_pQuilt->GetRefNativeScale();
2426ChartBase *ChartCanvas::GetChartAtCursor() {
2428 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2429 target_chart = m_singleChart;
2430 else if (VPoint.b_quilt)
2431 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2433 target_chart = NULL;
2434 return target_chart;
2437ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2441 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2443 target_chart = NULL;
2444 return target_chart;
2447int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2448 int new_dbIndex = -1;
2449 if (!VPoint.b_quilt) {
2450 if (m_pCurrentStack) {
2451 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2452 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2454 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2464 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2466 for (
unsigned int is = 0; is < im; is++) {
2468 m_pQuilt->GetExtendedStackIndexArray()[is]);
2471 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2481void ChartCanvas::EnablePaint(
bool b_enable) {
2482 m_b_paint_enable = b_enable;
2484 if (m_glcc) m_glcc->EnablePaint(b_enable);
2488bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2490void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2492std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2493 return m_pQuilt->GetQuiltIndexArray();
2497void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2498 VPoint.b_quilt = b_quilt;
2499 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2502bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2504int ChartCanvas::GetQuiltReferenceChartIndex() {
2505 return m_pQuilt->GetRefChartdbIndex();
2508void ChartCanvas::InvalidateAllQuiltPatchs() {
2509 m_pQuilt->InvalidateAllQuiltPatchs();
2512ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2513 return m_pQuilt->GetLargestScaleChart();
2516ChartBase *ChartCanvas::GetFirstQuiltChart() {
2517 return m_pQuilt->GetFirstChart();
2520ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2522int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2524void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2525 m_pQuilt->SetHiliteIndex(dbIndex);
2528void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2529 m_pQuilt->SetHiliteIndexArray(hilite_array);
2532void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2533 m_pQuilt->ClearHiliteIndexArray();
2536std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2538 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2541int ChartCanvas::GetQuiltRefChartdbIndex() {
2542 return m_pQuilt->GetRefChartdbIndex();
2545std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2546 return m_pQuilt->GetExtendedStackIndexArray();
2549std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2550 return m_pQuilt->GetFullscreenIndexArray();
2553std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2554 return m_pQuilt->GetEclipsedStackIndexArray();
2557void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2559double ChartCanvas::GetQuiltMaxErrorFactor() {
2560 return m_pQuilt->GetMaxErrorFactor();
2563bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2564 return m_pQuilt->IsChartQuiltableRef(db_index);
2568 double chartMaxScale =
2570 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2573void ChartCanvas::StartMeasureRoute() {
2574 if (!m_routeState) {
2575 if (m_bMeasure_Active) {
2577 m_pMeasureRoute = NULL;
2580 m_bMeasure_Active =
true;
2581 m_nMeasureState = 1;
2582 m_bDrawingRoute =
false;
2584 SetCursor(*pCursorPencil);
2589void ChartCanvas::CancelMeasureRoute() {
2590 m_bMeasure_Active =
false;
2591 m_nMeasureState = 0;
2592 m_bDrawingRoute =
false;
2595 m_pMeasureRoute = NULL;
2597 SetCursor(*pCursorArrow);
2600ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2602void ChartCanvas::SetVP(
ViewPort &vp) {
2613void ChartCanvas::TriggerDeferredFocus() {
2616 m_deferredFocusTimer.Start(20,
true);
2618#if defined(__WXGTK__) || defined(__WXOSX__)
2629void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2634void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2635 if (SendKeyEventToPlugins(event))
2639 int key_char =
event.GetKeyCode();
2642 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2648 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2653 if (g_benable_rotate) {
2674void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2675 if (SendKeyEventToPlugins(event))
2679 bool b_handled =
false;
2681 m_modkeys =
event.GetModifiers();
2683 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2685#ifdef OCPN_ALT_MENUBAR
2691 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2693 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2694 if (!g_bTempShowMenuBar) {
2695 g_bTempShowMenuBar =
true;
2696 parent_frame->ApplyGlobalSettings(
false);
2698 m_bMayToggleMenuBar =
false;
2704 if (event.GetKeyCode() != WXK_ALT) {
2705 m_bMayToggleMenuBar =
false;
2712 switch (event.GetKeyCode()) {
2719 event.GetPosition(&x, &y);
2720 m_FinishRouteOnKillFocus =
false;
2721 CallPopupMenu(x, y);
2722 m_FinishRouteOnKillFocus =
true;
2726 m_modkeys |= wxMOD_ALT;
2730 m_modkeys |= wxMOD_CONTROL;
2735 case WXK_RAW_CONTROL:
2736 m_modkeys |= wxMOD_RAW_CONTROL;
2741 if (m_modkeys == wxMOD_CONTROL)
2742 parent_frame->DoStackDown(
this);
2744 StartTimedMovement();
2754 StartTimedMovement();
2762 if (m_modkeys == wxMOD_CONTROL)
2763 parent_frame->DoStackUp(
this);
2765 StartTimedMovement();
2775 StartTimedMovement();
2783 if (event.ShiftDown()) {
2785 ChartFamilyEnum target_family = CHART_FAMILY_RASTER;
2787 std::shared_ptr<HostApi> host_api;
2789 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2792 api_121->SelectChartFamily(m_canvasIndex,
2799 if (event.ShiftDown()) {
2801 ChartFamilyEnum target_family = CHART_FAMILY_VECTOR;
2803 std::shared_ptr<HostApi> host_api;
2805 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2808 api_121->SelectChartFamily(m_canvasIndex,
2811 SetShowENCText(!GetShowENCText());
2818 if (!m_bMeasure_Active) {
2819 if (event.ShiftDown())
2820 m_bMeasure_DistCircle =
true;
2822 m_bMeasure_DistCircle =
false;
2824 StartMeasureRoute();
2826 CancelMeasureRoute();
2828 SetCursor(*pCursorArrow);
2838 parent_frame->ToggleColorScheme();
2840 TriggerDeferredFocus();
2844 int mod = m_modkeys & wxMOD_SHIFT;
2845 if (mod != m_brightmod) {
2847 m_bbrightdir = !m_bbrightdir;
2850 if (!m_bbrightdir) {
2851 g_nbrightness -= 10;
2852 if (g_nbrightness <= MIN_BRIGHT) {
2853 g_nbrightness = MIN_BRIGHT;
2854 m_bbrightdir =
true;
2857 g_nbrightness += 10;
2858 if (g_nbrightness >= MAX_BRIGHT) {
2859 g_nbrightness = MAX_BRIGHT;
2860 m_bbrightdir =
false;
2864 SetScreenBrightness(g_nbrightness);
2865 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2874 parent_frame->DoStackDown(
this);
2878 parent_frame->DoStackUp(
this);
2883 ToggleCanvasQuiltMode();
2889 parent_frame->ToggleFullScreen();
2894 if (m_modkeys == wxMOD_ALT) {
2897 ToggleChartOutlines();
2903 parent_frame->ActivateMOB();
2907 case WXK_NUMPAD_ADD:
2912 case WXK_NUMPAD_SUBTRACT:
2913 case WXK_PAGEDOWN: {
2914 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2919 if (m_bMeasure_Active) {
2920 if (m_nMeasureState > 2) {
2921 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2923 m_pMeasureRoute->GetnPoints();
2925 gFrame->RefreshAllCanvas();
2927 CancelMeasureRoute();
2928 StartMeasureRoute();
2936 if (event.GetKeyCode() < 128)
2938 int key_char =
event.GetKeyCode();
2942 if (!g_b_assume_azerty) {
2944 if (g_benable_rotate) {
2976 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2983 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2984 m_modkeys & wxMOD_RAW_CONTROL) {
2985 parent_frame->ToggleFullScreen();
2990 if (event.ControlDown()) key_char -= 64;
2992 if (key_char >=
'0' && key_char <=
'9')
2993 SetGroupIndex(key_char -
'0');
2998 SetShowENCAnchor(!GetShowENCAnchor());
3004 parent_frame->ToggleColorScheme();
3009 event.GetPosition(&x, &y);
3010 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3011 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3014 if (VPoint.b_quilt) {
3016 if (m_pQuilt->GetChartAtPix(
3021 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3023 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3028 if (m_singleChart) {
3029 ChartType = m_singleChart->GetChartType();
3030 ChartFam = m_singleChart->GetChartFamily();
3034 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3035 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3037 this, -1, ChartType, ChartFam,
3038 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3039 wxDefaultSize, wxSIMPLE_BORDER,
"");
3052 m_nmea_log->Raise();
3056 SetShowENCLights(!GetShowENCLights());
3062 if (event.ShiftDown())
3063 m_bMeasure_DistCircle =
true;
3065 m_bMeasure_DistCircle =
false;
3067 StartMeasureRoute();
3071 if (g_bInlandEcdis && ps52plib) {
3072 SetENCDisplayCategory((_DisCat)STANDARD);
3077 ToggleChartOutlines();
3081 ToggleCanvasQuiltMode();
3085 parent_frame->ToggleTestPause();
3088 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3089 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3090 g_iNavAidRadarRingsNumberVisible = 1;
3091 else if (!g_bNavAidRadarRingsShown &&
3092 g_iNavAidRadarRingsNumberVisible == 1)
3093 g_iNavAidRadarRingsNumberVisible = 0;
3096 SetShowENCDepth(!m_encShowDepth);
3101 SetShowENCText(!GetShowENCText());
3106 SetShowENCDataQual(!GetShowENCDataQual());
3111 m_bShowNavobjects = !m_bShowNavobjects;
3126 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3131 if (event.ControlDown()) gFrame->DropMarker(
false);
3138 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3139 if ((indexActive + 1) <= r->GetnPoints()) {
3150 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3156 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3162 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3169 parent_frame->DoSettings();
3173 parent_frame->Close();
3189 if (undo->AnythingToRedo()) {
3190 undo->RedoNextAction();
3197 if (event.ShiftDown()) {
3198 if (undo->AnythingToRedo()) {
3199 undo->RedoNextAction();
3204 if (undo->AnythingToUndo()) {
3205 undo->UndoLastAction();
3214 if (m_bMeasure_Active) {
3215 CancelMeasureRoute();
3217 SetCursor(*pCursorArrow);
3220 gFrame->RefreshAllCanvas();
3234 switch (gamma_state) {
3254 SetScreenBrightness(g_nbrightness);
3259 if (event.ControlDown()) {
3260 m_bShowCompassWin = !m_bShowCompassWin;
3261 SetShowGPSCompassWindow(m_bShowCompassWin);
3278void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3279 if (SendKeyEventToPlugins(event))
3283 switch (event.GetKeyCode()) {
3285 parent_frame->SwitchKBFocus(
this);
3291 if (!m_pany) m_panspeed = 0;
3297 if (!m_panx) m_panspeed = 0;
3300 case WXK_NUMPAD_ADD:
3301 case WXK_NUMPAD_SUBTRACT:
3310 m_modkeys &= ~wxMOD_ALT;
3311#ifdef OCPN_ALT_MENUBAR
3316 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3317 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3318 parent_frame->ApplyGlobalSettings(
false);
3320 m_bMayToggleMenuBar =
true;
3326 m_modkeys &= ~wxMOD_CONTROL;
3330 if (event.GetKeyCode() < 128)
3332 int key_char =
event.GetKeyCode();
3336 if (!g_b_assume_azerty) {
3351 m_rotation_speed = 0;
3369void ChartCanvas::ToggleChartOutlines() {
3370 m_bShowOutlines = !m_bShowOutlines;
3376 if (g_bopengl) InvalidateGL();
3380void ChartCanvas::ToggleLookahead() {
3381 m_bLookAhead = !m_bLookAhead;
3386void ChartCanvas::SetUpMode(
int mode) {
3389 if (mode != NORTH_UP_MODE) {
3392 if (!std::isnan(
gCog)) stuff =
gCog;
3395 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3398 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3400 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3401 SetVPRotation(GetVPSkew());
3406 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3407 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3409 UpdateGPSCompassStatusBox(
true);
3410 gFrame->DoChartUpdate();
3413bool ChartCanvas::DoCanvasCOGSet() {
3414 if (GetUpMode() == NORTH_UP_MODE)
return false;
3416 if (g_btenhertz) cog_use =
gCog;
3418 double rotation = 0;
3419 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3420 rotation = -
gHdt * PI / 180.;
3421 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3422 rotation = -cog_use * PI / 180.;
3424 SetVPRotation(rotation);
3428double easeOutCubic(
double t) {
3430 return 1.0 - pow(1.0 - t, 3.0);
3433void ChartCanvas::StartChartDragInertia() {
3434 m_bChartDragging =
false;
3437 m_chart_drag_inertia_time = 750;
3438 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3443 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3447 size_t length = m_drag_vec_t.size();
3448 for (
size_t i = 0; i < n_vel; i++) {
3449 xacc += m_drag_vec_x.at(length - 1 - i);
3450 yacc += m_drag_vec_y.at(length - 1 - i);
3451 tacc += m_drag_vec_t.at(length - 1 - i);
3454 if (tacc == 0)
return;
3456 double drag_velocity_x = xacc / tacc;
3457 double drag_velocity_y = yacc / tacc;
3463 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3465 m_chart_drag_velocity_x = drag_velocity_x;
3466 m_chart_drag_velocity_y = drag_velocity_y;
3468 m_chart_drag_inertia_active =
true;
3470 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3473void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3474 if (!m_chart_drag_inertia_active)
return;
3476 wxLongLong now = wxGetLocalTimeMillis();
3477 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3478 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3479 if (t > 1.0) t = 1.0;
3480 double e = 1.0 - easeOutCubic(t);
3483 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3485 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3487 m_last_elapsed = elapsed;
3491 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3492 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3493 double inertia_lat, inertia_lon;
3497 if (!IsOwnshipOnScreen()) {
3499 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3500 UpdateFollowButtonState();
3511 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3512 m_chart_drag_inertia_timer.Stop();
3515 m_target_lat = GetVP().
clat;
3516 m_target_lon = GetVP().
clon;
3517 m_pan_drag.x = m_pan_drag.y = 0;
3518 m_panx = m_pany = 0;
3519 m_chart_drag_inertia_active =
false;
3523 int target_redraw_interval = 40;
3524 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3528void ChartCanvas::StopMovement() {
3529 m_panx = m_pany = 0;
3532 m_rotation_speed = 0;
3535#if !defined(__WXGTK__) && !defined(__WXQT__)
3546bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3548 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3550 if (!pMovementTimer->IsRunning()) {
3551 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3554 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3559 m_last_movement_time = wxDateTime::UNow();
3563void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3566 m_target_lat = target_lat;
3567 m_target_lon = target_lon;
3570 m_start_lat = GetVP().
clat;
3571 m_start_lon = GetVP().
clon;
3573 m_VPMovementTimer.Start(1,
true);
3574 m_timed_move_vp_active =
true;
3576 m_timedVP_step = nstep;
3579void ChartCanvas::DoTimedMovementVP() {
3580 if (!m_timed_move_vp_active)
return;
3581 if (m_stvpc++ > m_timedVP_step * 2) {
3588 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3603 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3604 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3606 m_run_lat = new_lat;
3607 m_run_lon = new_lon;
3612void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3614void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3616void ChartCanvas::StartTimedMovementTarget() {}
3618void ChartCanvas::DoTimedMovementTarget() {}
3620void ChartCanvas::StopMovementTarget() {}
3623void ChartCanvas::DoTimedMovement() {
3624 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3628 wxDateTime now = wxDateTime::UNow();
3630 if (m_last_movement_time.IsValid())
3631 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3633 m_last_movement_time = now;
3643 if (dt == 0) dt = 1;
3646 if (m_mustmove < 0) m_mustmove = 0;
3649 if (m_pan_drag.x || m_pan_drag.y) {
3651 m_pan_drag.x = m_pan_drag.y = 0;
3654 if (m_panx || m_pany) {
3655 const double slowpan = .1, maxpan = 2;
3656 if (m_modkeys == wxMOD_ALT)
3657 m_panspeed = slowpan;
3659 m_panspeed += (double)dt / 500;
3660 m_panspeed = wxMin(maxpan, m_panspeed);
3662 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3665 if (m_zoom_factor != 1) {
3666 double alpha = 400, beta = 1.5;
3667 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3669 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3671 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3676 if (zoom_factor > 1) {
3677 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3681 else if (zoom_factor < 1) {
3682 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3687 if (fabs(zoom_factor - 1) > 1e-4) {
3688 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3693 if (m_wheelzoom_stop_oneshot > 0) {
3694 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3695 m_wheelzoom_stop_oneshot = 0;
3700 if (zoom_factor > 1) {
3702 m_wheelzoom_stop_oneshot = 0;
3705 }
else if (zoom_factor < 1) {
3707 m_wheelzoom_stop_oneshot = 0;
3714 if (m_rotation_speed) {
3715 double speed = m_rotation_speed;
3716 if (m_modkeys == wxMOD_ALT) speed /= 10;
3717 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3721void ChartCanvas::SetColorScheme(ColorScheme cs) {
3726 case GLOBAL_COLOR_SCHEME_DAY:
3727 m_pos_image_red = &m_os_image_red_day;
3728 m_pos_image_grey = &m_os_image_grey_day;
3729 m_pos_image_yellow = &m_os_image_yellow_day;
3730 m_pos_image_user = m_pos_image_user_day;
3731 m_pos_image_user_grey = m_pos_image_user_grey_day;
3732 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3733 m_cTideBitmap = m_bmTideDay;
3734 m_cCurrentBitmap = m_bmCurrentDay;
3737 case GLOBAL_COLOR_SCHEME_DUSK:
3738 m_pos_image_red = &m_os_image_red_dusk;
3739 m_pos_image_grey = &m_os_image_grey_dusk;
3740 m_pos_image_yellow = &m_os_image_yellow_dusk;
3741 m_pos_image_user = m_pos_image_user_dusk;
3742 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3743 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3744 m_cTideBitmap = m_bmTideDusk;
3745 m_cCurrentBitmap = m_bmCurrentDusk;
3747 case GLOBAL_COLOR_SCHEME_NIGHT:
3748 m_pos_image_red = &m_os_image_red_night;
3749 m_pos_image_grey = &m_os_image_grey_night;
3750 m_pos_image_yellow = &m_os_image_yellow_night;
3751 m_pos_image_user = m_pos_image_user_night;
3752 m_pos_image_user_grey = m_pos_image_user_grey_night;
3753 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3754 m_cTideBitmap = m_bmTideNight;
3755 m_cCurrentBitmap = m_bmCurrentNight;
3758 m_pos_image_red = &m_os_image_red_day;
3759 m_pos_image_grey = &m_os_image_grey_day;
3760 m_pos_image_yellow = &m_os_image_yellow_day;
3761 m_pos_image_user = m_pos_image_user_day;
3762 m_pos_image_user_grey = m_pos_image_user_grey_day;
3763 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3764 m_cTideBitmap = m_bmTideDay;
3765 m_cCurrentBitmap = m_bmCurrentDay;
3769 CreateDepthUnitEmbossMaps(cs);
3770 CreateOZEmbossMapData(cs);
3773 m_fog_color = wxColor(
3777 case GLOBAL_COLOR_SCHEME_DUSK:
3780 case GLOBAL_COLOR_SCHEME_NIGHT:
3786 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3787 m_fog_color.Blue() * dim);
3791 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3792 SetBackgroundColour( wxColour(0,0,0) );
3794 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3797 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3799 SetBackgroundColour( wxNullColour );
3806 m_Piano->SetColorScheme(cs);
3808 m_Compass->SetColorScheme(cs);
3810 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3812 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3814 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3815 if (m_notification_button) {
3816 m_notification_button->SetColorScheme(cs);
3820 if (g_bopengl && m_glcc) {
3821 m_glcc->SetColorScheme(cs);
3827 m_brepaint_piano =
true;
3834wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3835 wxImage img = Bitmap.ConvertToImage();
3836 int sx = img.GetWidth();
3837 int sy = img.GetHeight();
3839 wxImage new_img(img);
3841 for (
int i = 0; i < sx; i++) {
3842 for (
int j = 0; j < sy; j++) {
3843 if (!img.IsTransparent(i, j)) {
3844 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3845 (
unsigned char)(img.GetGreen(i, j) * factor),
3846 (
unsigned char)(img.GetBlue(i, j) * factor));
3851 wxBitmap ret = wxBitmap(new_img);
3856void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3859 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3861 if (!m_pBrightPopup) {
3864 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3868 m_pBrightPopup->SetSize(x, y);
3869 m_pBrightPopup->Move(120, 120);
3872 int bmpsx = m_pBrightPopup->GetSize().x;
3873 int bmpsy = m_pBrightPopup->GetSize().y;
3875 wxBitmap bmp(bmpsx, bmpsx);
3876 wxMemoryDC mdc(bmp);
3878 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3879 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3880 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3881 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3884 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3886 mdc.SetFont(*pfont);
3889 if (brightness == max)
3891 else if (brightness == min)
3894 val.Printf(
"%3d", brightness);
3896 mdc.DrawText(val, 0, 0);
3898 mdc.SelectObject(wxNullBitmap);
3900 m_pBrightPopup->SetBitmap(bmp);
3901 m_pBrightPopup->Show();
3902 m_pBrightPopup->Refresh();
3905void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3906 m_b_rot_hidef =
true;
3910void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3913 bool b_need_refresh =
false;
3915 wxSize win_size = GetSize() * m_displayScale;
3919 bool showAISRollover =
false;
3921 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3925 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3926 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3929 showAISRollover =
true;
3931 if (NULL == m_pAISRolloverWin) {
3933 m_pAISRolloverWin->IsActive(
false);
3934 b_need_refresh =
true;
3935 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3936 m_AISRollover_MMSI != FoundAIS_MMSI) {
3942 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3943 m_pAISRolloverWin->IsActive(
false);
3944 m_AISRollover_MMSI = 0;
3949 m_AISRollover_MMSI = FoundAIS_MMSI;
3951 if (!m_pAISRolloverWin->IsActive()) {
3952 wxString s = ptarget->GetRolloverString();
3953 m_pAISRolloverWin->SetString(s);
3955 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3956 AIS_ROLLOVER, win_size);
3957 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3958 m_pAISRolloverWin->IsActive(
true);
3959 b_need_refresh =
true;
3963 m_AISRollover_MMSI = 0;
3964 showAISRollover =
false;
3969 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3970 m_pAISRolloverWin->IsActive(
false);
3971 m_AISRollover_MMSI = 0;
3972 b_need_refresh =
true;
3977 bool showRouteRollover =
false;
3979 if (NULL == m_pRolloverRouteSeg) {
3983 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3984 SelectableItemList SelList =
pSelect->FindSelectionList(
3986 auto node = SelList.begin();
3987 while (node != SelList.end()) {
3992 if (pr && pr->IsVisible()) {
3993 m_pRolloverRouteSeg = pFindSel;
3994 showRouteRollover =
true;
3996 if (NULL == m_pRouteRolloverWin) {
3998 m_pRouteRolloverWin->IsActive(
false);
4001 if (!m_pRouteRolloverWin->IsActive()) {
4009 DistanceBearingMercator(
4010 segShow_point_b->m_lat, segShow_point_b->m_lon,
4011 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4013 if (!pr->m_bIsInLayer)
4014 s.Append(_(
"Route") +
": ");
4016 s.Append(_(
"Layer Route: "));
4018 if (pr->m_RouteNameString.IsEmpty())
4019 s.Append(_(
"(unnamed)"));
4021 s.Append(pr->m_RouteNameString);
4026 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4027 << segShow_point_b->GetName() <<
"\n";
4030 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4031 (
int)floor(brg + 0.5), 0x00B0);
4034 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4036 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4037 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4039 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4040 (
int)floor(varBrg + 0.5), 0x00B0);
4048 double shiptoEndLeg = 0.;
4049 bool validActive =
false;
4050 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4053 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4054 auto node = pr->pRoutePointList->begin();
4056 float dist_to_endleg = 0;
4059 for (++node; node != pr->pRoutePointList->end(); ++node) {
4066 if (prp->IsSame(segShow_point_a))
break;
4074 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4077 ->GetCurrentRngToActivePoint();
4086 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4091 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4092 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4094 << wxString(ttg_sec > SECONDS_PER_DAY
4095 ? ttg_span.Format(_(
"%Dd %H:%M"))
4096 : ttg_span.Format(_(
"%H:%M")));
4097 wxDateTime dtnow, eta;
4098 eta = dtnow.SetToCurrent().Add(ttg_span);
4099 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4100 << eta.Format(
" %d %H:%M");
4104 m_pRouteRolloverWin->SetString(s);
4106 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4107 LEG_ROLLOVER, win_size);
4108 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4109 m_pRouteRolloverWin->IsActive(
true);
4110 b_need_refresh =
true;
4111 showRouteRollover =
true;
4120 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4122 m_pRolloverRouteSeg))
4123 showRouteRollover =
false;
4124 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4125 showRouteRollover =
false;
4127 showRouteRollover =
true;
4131 if (m_routeState) showRouteRollover =
false;
4134 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4135 showRouteRollover =
false;
4137 if (m_pRouteRolloverWin &&
4138 !showRouteRollover) {
4139 m_pRouteRolloverWin->IsActive(
false);
4140 m_pRolloverRouteSeg = NULL;
4141 m_pRouteRolloverWin->Destroy();
4142 m_pRouteRolloverWin = NULL;
4143 b_need_refresh =
true;
4144 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4145 m_pRouteRolloverWin->IsActive(
true);
4146 b_need_refresh =
true;
4151 bool showTrackRollover =
false;
4153 if (NULL == m_pRolloverTrackSeg) {
4157 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4158 SelectableItemList SelList =
pSelect->FindSelectionList(
4161 auto node = SelList.begin();
4162 while (node != SelList.end()) {
4167 if (pt && pt->IsVisible()) {
4168 m_pRolloverTrackSeg = pFindSel;
4169 showTrackRollover =
true;
4171 if (NULL == m_pTrackRolloverWin) {
4173 m_pTrackRolloverWin->IsActive(
false);
4176 if (!m_pTrackRolloverWin->IsActive()) {
4184 DistanceBearingMercator(
4185 segShow_point_b->m_lat, segShow_point_b->m_lon,
4186 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4188 if (!pt->m_bIsInLayer)
4189 s.Append(_(
"Track") +
": ");
4191 s.Append(_(
"Layer Track: "));
4193 if (pt->GetName().IsEmpty())
4194 s.Append(_(
"(unnamed)"));
4196 s.Append(pt->GetName());
4197 double tlenght = pt->Length();
4199 if (pt->GetLastPoint()->GetTimeString() &&
4200 pt->GetPoint(0)->GetTimeString()) {
4201 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4202 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4203 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4204 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4205 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4206 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4207 << getUsrSpeedUnit();
4208 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4209 : ttime.Format(
" %H:%M"));
4213 if (g_bShowTrackPointTime &&
4214 strlen(segShow_point_b->GetTimeString())) {
4215 wxString stamp = segShow_point_b->GetTimeString();
4216 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4217 if (timestamp.IsValid()) {
4221 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4223 s <<
"\n" << _(
"Segment Created: ") << stamp;
4228 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4233 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4235 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4236 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4238 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4244 if (segShow_point_a->GetTimeString() &&
4245 segShow_point_b->GetTimeString()) {
4246 wxDateTime apoint = segShow_point_a->GetCreateTime();
4247 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4248 if (apoint.IsValid() && bpoint.IsValid()) {
4249 double segmentSpeed = toUsrSpeed(
4250 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4251 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4252 << getUsrSpeedUnit();
4256 m_pTrackRolloverWin->SetString(s);
4258 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4259 LEG_ROLLOVER, win_size);
4260 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4261 m_pTrackRolloverWin->IsActive(
true);
4262 b_need_refresh =
true;
4263 showTrackRollover =
true;
4272 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4274 m_pRolloverTrackSeg))
4275 showTrackRollover =
false;
4276 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4277 showTrackRollover =
false;
4279 showTrackRollover =
true;
4283 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4284 showTrackRollover =
false;
4287 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4288 showTrackRollover =
false;
4294 if (m_pTrackRolloverWin &&
4295 !showTrackRollover) {
4296 m_pTrackRolloverWin->IsActive(
false);
4297 m_pRolloverTrackSeg = NULL;
4298 m_pTrackRolloverWin->Destroy();
4299 m_pTrackRolloverWin = NULL;
4300 b_need_refresh =
true;
4301 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4302 m_pTrackRolloverWin->IsActive(
true);
4303 b_need_refresh =
true;
4306 if (b_need_refresh) Refresh();
4309void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4310 if ((GetShowENCLights() || m_bsectors_shown) &&
4311 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4312 extendedSectorLegs)) {
4313 if (!m_bsectors_shown) {
4315 m_bsectors_shown =
true;
4318 if (m_bsectors_shown) {
4320 m_bsectors_shown =
false;
4328#if defined(__WXGTK__) || defined(__WXQT__)
4333 double cursor_lat, cursor_lon;
4336 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4337 while (cursor_lon < -180.) cursor_lon += 360.;
4339 while (cursor_lon > 180.) cursor_lon -= 360.;
4341 SetCursorStatus(cursor_lat, cursor_lon);
4347void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4348 if (!parent_frame->m_pStatusBar)
return;
4352 s1 += toSDMM(1, cursor_lat);
4354 s1 += toSDMM(2, cursor_lon);
4356 if (STAT_FIELD_CURSOR_LL >= 0)
4357 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4359 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4364 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4365 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4366 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4368 wxString s = st + sm;
4381 if (g_bShowLiveETA) {
4384 float boatSpeedDefault = g_defaultBoatSpeed;
4389 if (!std::isnan(
gSog)) {
4391 if (boatSpeed < 0.5) {
4394 realTimeETA = dist / boatSpeed * 60;
4403 s << minutesToHoursDays(realTimeETA);
4408 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4409 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4411 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4416 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4424wxString minutesToHoursDays(
float timeInMinutes) {
4427 if (timeInMinutes == 0) {
4432 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4433 s << wxString::Format(
"%d", (
int)timeInMinutes);
4438 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4441 hours = (int)timeInMinutes / 60;
4442 min = (int)timeInMinutes % 60;
4445 s << wxString::Format(
"%d", hours);
4448 s << wxString::Format(
"%d", hours);
4450 s << wxString::Format(
"%d", min);
4457 else if (timeInMinutes > 24 * 60) {
4460 days = (int)(timeInMinutes / 60) / 24;
4461 hours = (int)(timeInMinutes / 60) % 24;
4464 s << wxString::Format(
"%d", days);
4467 s << wxString::Format(
"%d", days);
4469 s << wxString::Format(
"%d", hours);
4481void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4489 wxPoint2DDouble *r) {
4494 double rlon, wxPoint2DDouble *r) {
4505 if (!g_bopengl && m_singleChart &&
4506 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4507 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4508 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4509 (m_singleChart->GetChartProjectionType() !=
4510 PROJECTION_TRANSVERSE_MERCATOR) &&
4511 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4512 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4513 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4527 Cur_BSB_Ch->SetVPRasterParms(vp);
4528 double rpixxd, rpixyd;
4529 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4555 if (std::isnan(p.m_x)) {
4556 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4560 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4561 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4563 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4582 if (!g_bopengl && m_singleChart &&
4583 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4584 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4585 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4586 (m_singleChart->GetChartProjectionType() !=
4587 PROJECTION_TRANSVERSE_MERCATOR) &&
4588 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4589 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4590 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4601 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4604 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4609 else if (slon > 180.)
4620 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4626 DoZoomCanvas(factor,
false);
4627 extendedSectorLegs.clear();
4632 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4635 if (StartTimedMovement(stoptimer)) {
4637 m_zoom_factor = factor;
4642 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4644 DoZoomCanvas(factor, can_zoom_to_cursor);
4647 extendedSectorLegs.clear();
4650void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4653 if (!m_pCurrentStack)
return;
4659 if (m_bzooming)
return;
4668 double proposed_scale_onscreen =
4671 bool b_do_zoom =
false;
4680 if (!VPoint.b_quilt) {
4683 if (!m_disable_adjust_on_zoom) {
4684 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4685 if (new_db_index >= 0)
4686 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4690 int current_ref_stack_index = -1;
4691 if (m_pCurrentStack->nEntry) {
4693 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4694 m_pQuilt->SetReferenceChart(trial_index);
4695 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4696 if (new_db_index >= 0)
4697 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4701 if (m_pCurrentStack)
4702 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4713 double min_allowed_scale =
4716 if (proposed_scale_onscreen < min_allowed_scale) {
4721 proposed_scale_onscreen = min_allowed_scale;
4725 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4728 }
else if (factor < 1) {
4733 bool b_smallest =
false;
4735 if (!VPoint.b_quilt) {
4740 LLBBox viewbox = VPoint.GetBBox();
4742 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4743 double max_allowed_scale;
4757 if (proposed_scale_onscreen > max_allowed_scale) {
4759 proposed_scale_onscreen = max_allowed_scale;
4764 if (!m_disable_adjust_on_zoom) {
4766 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4767 if (new_db_index >= 0)
4768 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4770 if (m_pCurrentStack)
4771 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4774 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4776 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4777 proposed_scale_onscreen =
4778 wxMin(proposed_scale_onscreen,
4784 m_absolute_min_scale_ppm)
4785 proposed_scale_onscreen =
4794 bool b_allow_ztc =
true;
4795 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4796 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4798 double brg, distance;
4799 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4802 meters_to_shift = distance * 1852;
4810 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4813 if (m_bFollow) DoCanvasUpdate();
4820void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4822 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4826void ChartCanvas::RotateCanvas(
double dir) {
4830 if (StartTimedMovement()) {
4832 m_rotation_speed = dir * 60;
4835 double speed = dir * 10;
4836 if (m_modkeys == wxMOD_ALT) speed /= 20;
4837 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4841void ChartCanvas::DoRotateCanvas(
double rotation) {
4842 while (rotation < 0) rotation += 2 * PI;
4843 while (rotation > 2 * PI) rotation -= 2 * PI;
4845 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4847 SetVPRotation(rotation);
4848 parent_frame->UpdateRotationState(VPoint.
rotation);
4851void ChartCanvas::DoTiltCanvas(
double tilt) {
4852 while (tilt < 0) tilt = 0;
4853 while (tilt > .95) tilt = .95;
4855 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4861void ChartCanvas::TogglebFollow() {
4868void ChartCanvas::ClearbFollow() {
4871 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4873 UpdateFollowButtonState();
4877 parent_frame->SetChartUpdatePeriod();
4880void ChartCanvas::SetbFollow() {
4883 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4884 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4892 p.m_x += m_OSoffsetx;
4893 p.m_y -= m_OSoffsety;
4902 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4903 UpdateFollowButtonState();
4905 if (!g_bSmoothRecenter) {
4909 parent_frame->SetChartUpdatePeriod();
4912void ChartCanvas::UpdateFollowButtonState() {
4915 m_muiBar->SetFollowButtonState(0);
4918 m_muiBar->SetFollowButtonState(2);
4920 m_muiBar->SetFollowButtonState(1);
4926 androidSetFollowTool(0);
4929 androidSetFollowTool(2);
4931 androidSetFollowTool(1);
4938 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4939 if (pic->m_enabled && pic->m_init_state) {
4940 switch (pic->m_api_version) {
4943 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4954void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4955 if (g_bSmoothRecenter && !m_routeState) {
4956 if (StartSmoothJump(lat, lon, scale_ppm))
4960 double gcDist, gcBearingEnd;
4961 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4963 gcBearingEnd += 180;
4964 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4967 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4968 double new_lat = lat + (lat_offset / (1852 * 60));
4969 double new_lon = lon + (lon_offset / (1852 * 60));
4972 StartSmoothJump(lat, lon, scale_ppm);
4977 if (lon > 180.0) lon -= 360.0;
4983 if (!GetQuiltMode()) {
4985 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4986 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4990 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4991 AdjustQuiltRefChart();
4998 UpdateFollowButtonState();
5006bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5011 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5012 double distance_pixels = gcDist *
GetVPScale();
5013 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5019 m_startLat = m_vLat;
5020 m_startLon = m_vLon;
5025 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5026 m_endScale = scale_ppm;
5029 m_animationDuration = 600;
5030 m_animationStart = wxGetLocalTimeMillis();
5037 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5038 m_animationActive =
true;
5043void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5045 wxLongLong now = wxGetLocalTimeMillis();
5046 double elapsed = (now - m_animationStart).ToDouble();
5047 double t = elapsed / m_animationDuration.ToDouble();
5048 if (t > 1.0) t = 1.0;
5051 double e = easeOutCubic(t);
5054 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5055 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5056 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5061 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5067 m_animationActive =
false;
5068 UpdateFollowButtonState();
5077 extendedSectorLegs.clear();
5086 if (iters++ > 5)
return false;
5087 if (!std::isnan(dlat))
break;
5090 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5096 else if (dlat < -90)
5099 if (dlon > 360.) dlon -= 360.;
5100 if (dlon < -360.) dlon += 360.;
5115 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5119 if (VPoint.b_quilt) {
5120 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5121 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5125 double tweak_scale_ppm =
5131 if (new_ref_dbIndex == -1) {
5132#pragma GCC diagnostic push
5133#pragma GCC diagnostic ignored "-Warray-bounds"
5140 int trial_index = -1;
5141 if (m_pCurrentStack->nEntry) {
5143 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5146 if (trial_index < 0) {
5147 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5148 if (full_screen_array.size())
5149 trial_index = full_screen_array[full_screen_array.size() - 1];
5152 if (trial_index >= 0) {
5153 m_pQuilt->SetReferenceChart(trial_index);
5158#pragma GCC diagnostic pop
5165 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5167 double offset_angle = atan2(offy, offx);
5168 double offset_distance = sqrt((offy * offy) + (offx * offx));
5169 double chart_angle = GetVPRotation();
5170 double target_angle = chart_angle - offset_angle;
5171 double d_east_mod = offset_distance * cos(target_angle);
5172 double d_north_mod = offset_distance * sin(target_angle);
5177 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5178 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5180 UpdateFollowButtonState();
5186 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5191bool ChartCanvas::IsOwnshipOnScreen() {
5194 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5195 ((r.y > 0) && r.y < GetCanvasHeight()))
5201void ChartCanvas::ReloadVP(
bool b_adjust) {
5202 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5204 LoadVP(VPoint, b_adjust);
5207void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5209 if (g_bopengl && m_glcc) {
5210 m_glcc->Invalidate();
5211 if (m_glcc->GetSize() != GetSize()) {
5212 m_glcc->SetSize(GetSize());
5217 m_cache_vp.Invalidate();
5218 m_bm_cache_vp.Invalidate();
5221 VPoint.Invalidate();
5223 if (m_pQuilt) m_pQuilt->Invalidate();
5232 vp.m_projection_type, b_adjust);
5235void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5236 m_pQuilt->SetReferenceChart(dbIndex);
5237 VPoint.Invalidate();
5238 m_pQuilt->Invalidate();
5241double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5243 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5250int ChartCanvas::AdjustQuiltRefChart() {
5255 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5257 double min_ref_scale =
5258 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5259 double max_ref_scale =
5260 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5263 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5264 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5265 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5267 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5270 int target_stack_index = wxNOT_FOUND;
5272 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5273 if (index == m_pQuilt->GetRefChartdbIndex()) {
5274 target_stack_index = il;
5279 if (wxNOT_FOUND == target_stack_index)
5280 target_stack_index = 0;
5282 int ref_family = pc->GetChartFamily();
5283 int extended_array_count =
5284 m_pQuilt->GetExtendedStackIndexArray().size();
5285 while ((!brender_ok) &&
5286 ((
int)target_stack_index < (extended_array_count - 1))) {
5287 target_stack_index++;
5289 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5291 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5292 IsChartQuiltableRef(test_db_index)) {
5295 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5297 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5304 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5305 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5306 IsChartQuiltableRef(new_db_index)) {
5307 m_pQuilt->SetReferenceChart(new_db_index);
5310 ret = m_pQuilt->GetRefChartdbIndex();
5312 ret = m_pQuilt->GetRefChartdbIndex();
5315 ret = m_pQuilt->GetRefChartdbIndex();
5324void ChartCanvas::UpdateCanvasOnGroupChange() {
5325 delete m_pCurrentStack;
5337bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5338 double latNE,
double lonNE) {
5340 double latc = (latSW + latNE) / 2.0;
5341 double lonc = (lonSW + lonNE) / 2.0;
5344 double ne_easting, ne_northing;
5345 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5347 double sw_easting, sw_northing;
5348 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5350 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5357 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5360bool ChartCanvas::SetVPProjection(
int projection) {
5366 double prev_true_scale_ppm = m_true_scale_ppm;
5371 m_absolute_min_scale_ppm));
5379bool ChartCanvas::SetVPRotation(
double angle) {
5381 VPoint.
skew, angle);
5384 double skew,
double rotation,
int projection,
5385 bool b_adjust,
bool b_refresh) {
5390 if (VPoint.IsValid()) {
5391 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5392 (fabs(VPoint.
skew - skew) < 1e-9) &&
5393 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5394 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5395 (VPoint.m_projection_type == projection ||
5396 projection == PROJECTION_UNKNOWN))
5399 if (VPoint.m_projection_type != projection)
5400 VPoint.InvalidateTransformCache();
5410 if (projection != PROJECTION_UNKNOWN)
5411 VPoint.SetProjectionType(projection);
5412 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5413 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5416 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5417 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5418 if (VPoint.
clat > 89.5)
5420 else if (VPoint.
clat < -89.5)
5421 VPoint.
clat = -89.5;
5426 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5427 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5439 bool bwasValid = VPoint.IsValid();
5444 m_cache_vp.Invalidate();
5449 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5453 int mouseX = mouse_x;
5454 int mouseY = mouse_y;
5455 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5461 SendCursorLatLonToAllPlugIns(lat, lon);
5464 if (!VPoint.b_quilt && m_singleChart) {
5469 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5473 if ((!m_cache_vp.IsValid()) ||
5478 wxPoint cp_last, cp_this;
5482 if (cp_last != cp_this) {
5488 if (m_pCurrentStack) {
5490 int current_db_index;
5492 m_pCurrentStack->GetCurrentEntrydbIndex();
5494 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5496 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5499 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5503 if (VPoint.b_quilt) {
5507 m_pQuilt->InvalidateAllQuiltPatchs();
5511 if (!m_pCurrentStack)
return false;
5513 int current_db_index;
5515 m_pCurrentStack->GetCurrentEntrydbIndex();
5517 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5518 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5521 int current_ref_stack_index = -1;
5522 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5523 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5524 current_ref_stack_index = i;
5527 if (g_bFullScreenQuilt) {
5528 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5532 bool b_needNewRef =
false;
5535 if ((-1 == current_ref_stack_index) &&
5536 (m_pQuilt->GetRefChartdbIndex() >= 0))
5537 b_needNewRef =
true;
5544 bool renderable =
true;
5546 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5547 if (referenceChart) {
5548 double chartMaxScale = referenceChart->GetNormalScaleMax(
5550 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5552 if (!renderable) b_needNewRef =
true;
5555 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5557 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5558 int target_scale = cte_ref.GetScale();
5559 int target_type = cte_ref.GetChartType();
5560 int candidate_stack_index;
5567 candidate_stack_index = 0;
5568 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5570 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5571 int candidate_scale = cte_candidate.GetScale();
5572 int candidate_type = cte_candidate.GetChartType();
5574 if ((candidate_scale >= target_scale) &&
5575 (candidate_type == target_type)) {
5576 bool renderable =
true;
5578 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5579 if (tentative_referenceChart) {
5580 double chartMaxScale =
5581 tentative_referenceChart->GetNormalScaleMax(
5583 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5586 if (renderable)
break;
5589 candidate_stack_index++;
5594 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5595 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5596 while (candidate_stack_index >= 0) {
5597 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5601 int candidate_scale = cte_candidate.GetScale();
5602 int candidate_type = cte_candidate.GetChartType();
5604 if ((candidate_scale <= target_scale) &&
5605 (candidate_type == target_type))
5608 candidate_stack_index--;
5613 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5614 (candidate_stack_index < 0))
5615 candidate_stack_index = 0;
5617 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5619 m_pQuilt->SetReferenceChart(new_ref_index);
5625 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5630 bool renderable =
true;
5632 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5633 if (referenceChart) {
5634 double chartMaxScale = referenceChart->GetNormalScaleMax(
5636 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5637 proj =
ChartData->GetDBChartProj(ref_db_index);
5639 proj = PROJECTION_MERCATOR;
5641 VPoint.b_MercatorProjectionOverride =
5642 (m_pQuilt->GetnCharts() == 0 || !renderable);
5644 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5646 VPoint.SetProjectionType(proj);
5651 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5656 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5676 m_pQuilt->Invalidate();
5693 if (b_refresh) Refresh(
false);
5700 }
else if (!g_bopengl) {
5701 OcpnProjType projection = PROJECTION_UNKNOWN;
5704 projection = m_singleChart->GetChartProjectionType();
5705 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5706 VPoint.SetProjectionType(projection);
5710 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5711 m_cache_vp.Invalidate();
5715 UpdateCanvasControlBar();
5719 if (VPoint.GetBBox().GetValid()) {
5722 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5731 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5734 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5741 wxPoint2DDouble r, r1;
5743 double delta_check =
5747 double check_point = wxMin(89., VPoint.
clat);
5749 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5752 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5753 VPoint.
clon, 0, &rhumbDist);
5758 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5759 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5761 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5765 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5771 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5773 if (m_true_scale_ppm)
5774 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5779 double round_factor = 1000.;
5783 round_factor = 100.;
5785 round_factor = 1000.;
5788 double retina_coef = 1;
5792 retina_coef = GetContentScaleFactor();
5803 double true_scale_display =
5804 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5809 if (m_displayed_scale_factor > 10.0)
5810 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5811 m_displayed_scale_factor);
5812 else if (m_displayed_scale_factor > 1.0)
5813 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5814 m_displayed_scale_factor);
5815 else if (m_displayed_scale_factor > 0.1) {
5816 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5817 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5818 }
else if (m_displayed_scale_factor > 0.01) {
5819 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5820 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5823 "%s %4.0f (---)", _(
"Scale"),
5824 true_scale_display);
5827 m_scaleValue = true_scale_display;
5829 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5831 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5832 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5834 bool b_noshow =
false;
5838 wxClientDC dc(parent_frame->GetStatusBar());
5840 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5841 dc.SetFont(*templateFont);
5842 dc.GetTextExtent(text, &w, &h);
5847 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5848 if (w && w > rect.width) {
5849 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5853 dc.GetTextExtent(text, &w, &h);
5855 if (w && w > rect.width) {
5861 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5866 m_vLat = VPoint.
clat;
5867 m_vLon = VPoint.
clon;
5881static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5885static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5886 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5888wxColour ChartCanvas::PredColor() {
5891 if (SHIP_NORMAL == m_ownship_state)
5892 return GetGlobalColor(
"URED");
5894 else if (SHIP_LOWACCURACY == m_ownship_state)
5895 return GetGlobalColor(
"YELO1");
5897 return GetGlobalColor(
"NODTA");
5900wxColour ChartCanvas::ShipColor() {
5904 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5906 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5908 return GetGlobalColor(
"URED");
5911void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5912 wxPoint2DDouble lShipMidPoint) {
5913 dc.SetPen(wxPen(PredColor(), 2));
5915 if (SHIP_NORMAL == m_ownship_state)
5916 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5918 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5920 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5921 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5923 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5925 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5926 lShipMidPoint.m_y + 12);
5929void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5930 wxPoint GPSOffsetPixels,
5931 wxPoint2DDouble lGPSPoint) {
5936 float ref_dim = m_display_size_mm / 24;
5937 ref_dim = wxMin(ref_dim, 12);
5938 ref_dim = wxMax(ref_dim, 6);
5941 cPred.Set(g_cog_predictor_color);
5942 if (cPred == wxNullColour) cPred = PredColor();
5949 double nominal_line_width_pix = wxMax(
5951 floor(m_pix_per_mm / 2));
5955 if (nominal_line_width_pix > g_cog_predictor_width)
5956 g_cog_predictor_width = nominal_line_width_pix;
5959 wxPoint lPredPoint, lHeadPoint;
5961 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5962 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5964 double pred_lat, pred_lon;
5965 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5966 &pred_lat, &pred_lon);
5977 float ndelta_pix = 10.;
5978 double hdg_pred_lat, hdg_pred_lon;
5979 bool b_render_hdt =
false;
5980 if (!std::isnan(
gHdt)) {
5982 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5985 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5986 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5987 if (dist > ndelta_pix ) {
5988 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5989 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5994 wxPoint lShipMidPoint;
5995 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5996 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5997 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5998 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
6000 if (lpp >= img_height / 2) {
6001 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
6002 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
6003 !std::isnan(
gSog)) {
6005 float dash_length = ref_dim;
6006 wxDash dash_long[2];
6008 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6009 g_cog_predictor_width);
6010 dash_long[1] = dash_long[0] / 2.0;
6014 if (dash_length > 250.) {
6015 dash_long[0] = 250. / g_cog_predictor_width;
6016 dash_long[1] = dash_long[0] / 2;
6019 wxPen ppPen2(cPred, g_cog_predictor_width,
6020 (wxPenStyle)g_cog_predictor_style);
6021 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6022 ppPen2.SetDashes(2, dash_long);
6025 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6026 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6028 if (g_cog_predictor_width > 1) {
6029 float line_width = g_cog_predictor_width / 3.;
6031 wxDash dash_long3[2];
6032 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6033 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6035 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6036 (wxPenStyle)g_cog_predictor_style);
6037 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6038 ppPen3.SetDashes(2, dash_long3);
6040 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6041 lGPSPoint.m_y + GPSOffsetPixels.y,
6042 lPredPoint.x + GPSOffsetPixels.x,
6043 lPredPoint.y + GPSOffsetPixels.y);
6046 if (g_cog_predictor_endmarker) {
6048 double png_pred_icon_scale_factor = .4;
6049 if (g_ShipScaleFactorExp > 1.0)
6050 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6051 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6055 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6056 (
float)(lPredPoint.x - lShipMidPoint.x));
6057 cog_rad += (float)PI;
6059 for (
int i = 0; i < 4; i++) {
6061 double pxa = (double)(s_png_pred_icon[j]);
6062 double pya = (double)(s_png_pred_icon[j + 1]);
6064 pya *= png_pred_icon_scale_factor;
6065 pxa *= png_pred_icon_scale_factor;
6067 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6068 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6070 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6071 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6075 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6078 dc.SetBrush(wxBrush(cPred));
6080 dc.StrokePolygon(4, icon);
6087 float hdt_dash_length = ref_dim * 0.4;
6089 cPred.Set(g_ownship_HDTpredictor_color);
6090 if (cPred == wxNullColour) cPred = PredColor();
6092 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6093 : g_cog_predictor_width * 0.8);
6094 wxDash dash_short[2];
6096 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6099 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6102 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6103 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6104 ppPen2.SetDashes(2, dash_short);
6108 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6109 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6111 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6113 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6115 if (g_ownship_HDTpredictor_endmarker) {
6116 double nominal_circle_size_pixels = wxMax(
6117 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6120 if (g_ShipScaleFactorExp > 1.0)
6121 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6123 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6124 lHeadPoint.y + GPSOffsetPixels.y,
6125 nominal_circle_size_pixels / 2);
6130 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6131 double factor = 1.00;
6132 if (g_pNavAidRadarRingsStepUnits == 1)
6134 else if (g_pNavAidRadarRingsStepUnits == 2) {
6135 if (std::isnan(
gSog))
6140 factor *= g_fNavAidRadarRingsStep;
6144 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6147 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6148 pow((
double)(lGPSPoint.m_y - r.y), 2));
6149 int pix_radius = (int)lpp;
6151 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6153 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6156 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6158 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6159 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6163void ChartCanvas::ComputeShipScaleFactor(
6164 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6165 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6166 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6167 float screenResolution = m_pix_per_mm;
6170 double ship_bow_lat, ship_bow_lon;
6171 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6172 &ship_bow_lat, &ship_bow_lon);
6173 wxPoint lShipBowPoint;
6174 wxPoint2DDouble b_point =
6178 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6179 powf((
float)(b_point.m_y - a_point.m_y), 2));
6182 float shipLength_mm = shipLength_px / screenResolution;
6185 float ownship_min_mm = g_n_ownship_min_mm;
6186 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6189 float hdt_ant = icon_hdt + 180.;
6190 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6191 float dx = g_n_gps_antenna_offset_x / 1852.;
6192 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6200 if (shipLength_mm < ownship_min_mm) {
6201 dy /= shipLength_mm / ownship_min_mm;
6202 dx /= shipLength_mm / ownship_min_mm;
6205 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6207 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6208 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6214 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6215 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6217 float scale_factor = shipLength_px / ownShipLength;
6220 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6223 scale_factor = wxMax(scale_factor, scale_factor_min);
6225 scale_factor_y = scale_factor;
6226 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6227 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6230void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6231 if (!GetVP().IsValid())
return;
6233 wxPoint GPSOffsetPixels(0, 0);
6234 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6237 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6238 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6242 lShipMidPoint = lGPSPoint;
6246 float icon_hdt = pCog;
6247 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6250 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6254 double osd_head_lat, osd_head_lon;
6255 wxPoint osd_head_point;
6257 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6262 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6263 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6264 icon_rad += (float)PI;
6266 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6270 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6274 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6275 if (GetVP().chart_scale >
6278 ShipDrawLargeScale(dc, lShipMidPoint);
6284 if (m_pos_image_user)
6285 pos_image = m_pos_image_user->Copy();
6286 else if (SHIP_NORMAL == m_ownship_state)
6287 pos_image = m_pos_image_red->Copy();
6288 if (SHIP_LOWACCURACY == m_ownship_state)
6289 pos_image = m_pos_image_yellow->Copy();
6290 else if (SHIP_NORMAL != m_ownship_state)
6291 pos_image = m_pos_image_grey->Copy();
6294 if (m_pos_image_user) {
6295 pos_image = m_pos_image_user->Copy();
6297 if (SHIP_LOWACCURACY == m_ownship_state)
6298 pos_image = m_pos_image_user_yellow->Copy();
6299 else if (SHIP_NORMAL != m_ownship_state)
6300 pos_image = m_pos_image_user_grey->Copy();
6303 img_height = pos_image.GetHeight();
6305 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6306 g_OwnShipIconType > 0)
6308 int ownShipWidth = 22;
6309 int ownShipLength = 84;
6310 if (g_OwnShipIconType == 1) {
6311 ownShipWidth = pos_image.GetWidth();
6312 ownShipLength = pos_image.GetHeight();
6315 float scale_factor_x, scale_factor_y;
6316 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6317 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6318 scale_factor_x, scale_factor_y);
6320 if (g_OwnShipIconType == 1) {
6321 pos_image.Rescale(ownShipWidth * scale_factor_x,
6322 ownShipLength * scale_factor_y,
6323 wxIMAGE_QUALITY_HIGH);
6324 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6326 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6329 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6330 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6331 if (rot_image.GetAlpha(ip, jp) > 64)
6332 rot_image.SetAlpha(ip, jp, 255);
6334 wxBitmap os_bm(rot_image);
6336 int w = os_bm.GetWidth();
6337 int h = os_bm.GetHeight();
6340 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6341 lShipMidPoint.m_y - h / 2,
true);
6344 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6345 lShipMidPoint.m_y - h / 2);
6346 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6347 lShipMidPoint.m_y - h / 2 + h);
6350 else if (g_OwnShipIconType == 2) {
6351 wxPoint ownship_icon[10];
6353 for (
int i = 0; i < 10; i++) {
6355 float pxa = (float)(s_ownship_icon[j]);
6356 float pya = (float)(s_ownship_icon[j + 1]);
6357 pya *= scale_factor_y;
6358 pxa *= scale_factor_x;
6360 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6361 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6363 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6364 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6367 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6369 dc.SetBrush(wxBrush(ShipColor()));
6371 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6374 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6376 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6380 img_height = ownShipLength * scale_factor_y;
6384 if (m_pos_image_user) circle_rad = 1;
6386 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6387 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6388 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6391 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6393 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6396 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6397 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6398 if (rot_image.GetAlpha(ip, jp) > 64)
6399 rot_image.SetAlpha(ip, jp, 255);
6401 wxBitmap os_bm(rot_image);
6403 if (g_ShipScaleFactorExp > 1) {
6404 wxImage scaled_image = os_bm.ConvertToImage();
6405 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6407 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6408 scaled_image.GetHeight() * factor,
6409 wxIMAGE_QUALITY_HIGH));
6411 int w = os_bm.GetWidth();
6412 int h = os_bm.GetHeight();
6415 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6416 lShipMidPoint.m_y - h / 2,
true);
6420 if (m_pos_image_user) circle_rad = 1;
6422 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6423 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6424 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6427 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6428 lShipMidPoint.m_y - h / 2);
6429 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6430 lShipMidPoint.m_y - h / 2 + h);
6435 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6448void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6449 float &MinorSpacing) {
6454 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6455 {.000001f, 45.0f, 15.0f},
6456 {.0002f, 30.0f, 10.0f},
6457 {.0003f, 10.0f, 2.0f},
6458 {.0008f, 5.0f, 1.0f},
6459 {.001f, 2.0f, 30.0f / 60.0f},
6460 {.003f, 1.0f, 20.0f / 60.0f},
6461 {.006f, 0.5f, 10.0f / 60.0f},
6462 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6463 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6464 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6465 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6466 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6467 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6468 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6469 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6472 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6473 if (view_scale_ppm < lltab[tabi][0])
break;
6474 MajorSpacing = lltab[tabi][1];
6475 MinorSpacing = lltab[tabi][2];
6489wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6490 int deg = (int)fabs(latlon);
6491 float min = fabs((fabs(latlon) - deg) * 60.0);
6501 }
else if (latlon < 0.0) {
6513 if (spacing >= 1.0) {
6514 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6515 }
else if (spacing >= (1.0 / 60.0)) {
6516 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6518 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6535void ChartCanvas::GridDraw(
ocpnDC &dc) {
6536 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6538 double nlat, elon, slat, wlon;
6541 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6543 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6545 if (!m_pgridFont) SetupGridFont();
6546 dc.SetFont(*m_pgridFont);
6547 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6550 h = m_canvas_height;
6561 dlon = dlon + 360.0;
6564 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6567 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6570 while (lat < nlat) {
6573 CalcGridText(lat, gridlatMajor,
true);
6575 dc.
DrawLine(0, r.y, w, r.y,
false);
6576 dc.DrawText(st, 0, r.y);
6577 lat = lat + gridlatMajor;
6579 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6583 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6586 while (lat < nlat) {
6589 dc.
DrawLine(0, r.y, 10, r.y,
false);
6590 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6591 lat = lat + gridlatMinor;
6595 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6598 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6601 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6603 wxString st = CalcGridText(lon, gridlonMajor,
false);
6605 dc.
DrawLine(r.x, 0, r.x, h,
false);
6606 dc.DrawText(st, r.x, 0);
6607 lon = lon + gridlonMajor;
6612 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6616 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6618 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6621 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6622 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6623 lon = lon + gridlonMinor;
6630void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6632 double blat, blon, tlat, tlon;
6635 int x_origin = m_bDisplayGrid ? 60 : 20;
6636 int y_origin = m_canvas_height - 50;
6642 if (GetVP().chart_scale > 80000)
6646 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6647 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6652 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6653 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6657 double rotation = -VPoint.
rotation;
6659 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6661 int l1 = (y_origin - r.y) / count;
6663 for (
int i = 0; i < count; i++) {
6670 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6673 double blat, blon, tlat, tlon;
6680 int y_origin = m_canvas_height - chartbar_height - 5;
6684 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6691 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6696 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6697 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6701 float places = floor(logdist), rem = logdist - places;
6702 dist = pow(10, places);
6709 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6710 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6711 double rotation = -VPoint.
rotation;
6717 int l1 = r.x - x_origin;
6719 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6724 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6725 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6726 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6728 if (!m_pgridFont) SetupGridFont();
6729 dc.SetFont(*m_pgridFont);
6730 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6732 dc.GetTextExtent(s, &w, &h);
6738 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6742void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6747 double ra_max = 40.;
6749 wxPen pen_save = dc.GetPen();
6751 wxDateTime now = wxDateTime::Now();
6757 x0 = x1 = x + radius;
6762 while (angle < 360.) {
6763 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6766 if (angle > 360.) angle = 360.;
6768 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6776 x1 = (int)(x + cos(angle * PI / 180.) * r);
6777 y1 = (int)(y + sin(angle * PI / 180.) * r);
6787 dc.
DrawLine(x + radius, y, x1, y1);
6789 dc.SetPen(pen_save);
6792static bool bAnchorSoundPlaying =
false;
6794static void onAnchorSoundFinished(
void *ptr) {
6795 o_sound::g_anchorwatch_sound->UnLoad();
6796 bAnchorSoundPlaying =
false;
6799void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6800 using namespace o_sound;
6802 bool play_sound =
false;
6804 if (AnchorAlertOn1) {
6805 wxPoint TargetPoint;
6808 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6809 TargetPoint.y, 100);
6813 AnchorAlertOn1 =
false;
6816 if (AnchorAlertOn2) {
6817 wxPoint TargetPoint;
6820 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6821 TargetPoint.y, 100);
6825 AnchorAlertOn2 =
false;
6828 if (!bAnchorSoundPlaying) {
6829 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6830 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6831 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6832 if (g_anchorwatch_sound->IsOk()) {
6833 bAnchorSoundPlaying =
true;
6834 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6835 g_anchorwatch_sound->Play();
6841void ChartCanvas::UpdateShips() {
6844 wxClientDC dc(
this);
6845 if (!dc.IsOk())
return;
6847 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6848 if (!test_bitmap.IsOk())
return;
6850 wxMemoryDC temp_dc(test_bitmap);
6852 temp_dc.ResetBoundingBox();
6853 temp_dc.DestroyClippingRegion();
6854 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6865 ocpndc.CalcBoundingBox(px.x, px.y);
6870 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6871 temp_dc.MaxY() - temp_dc.MinY());
6873 wxRect own_ship_update_rect = ship_draw_rect;
6875 if (!own_ship_update_rect.IsEmpty()) {
6878 own_ship_update_rect.Union(ship_draw_last_rect);
6879 own_ship_update_rect.Inflate(2);
6882 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6884 ship_draw_last_rect = ship_draw_rect;
6886 temp_dc.SelectObject(wxNullBitmap);
6889void ChartCanvas::UpdateAlerts() {
6894 wxClientDC dc(
this);
6898 dc.GetSize(&sx, &sy);
6901 wxBitmap test_bitmap(sx, sy, -1);
6905 temp_dc.SelectObject(test_bitmap);
6907 temp_dc.ResetBoundingBox();
6908 temp_dc.DestroyClippingRegion();
6909 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6916 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6917 temp_dc.MaxX() - temp_dc.MinX(),
6918 temp_dc.MaxY() - temp_dc.MinY());
6920 if (!alert_rect.IsEmpty())
6921 alert_rect.Inflate(2);
6923 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6926 wxRect alert_update_rect = alert_draw_rect;
6927 alert_update_rect.Union(alert_rect);
6930 RefreshRect(alert_update_rect,
false);
6934 alert_draw_rect = alert_rect;
6936 temp_dc.SelectObject(wxNullBitmap);
6939void ChartCanvas::UpdateAIS() {
6945 wxClientDC dc(
this);
6949 dc.GetSize(&sx, &sy);
6957 if (
g_pAIS->GetTargetList().size() > 10) {
6958 ais_rect = wxRect(0, 0, sx, sy);
6961 wxBitmap test_bitmap(sx, sy, -1);
6965 temp_dc.SelectObject(test_bitmap);
6967 temp_dc.ResetBoundingBox();
6968 temp_dc.DestroyClippingRegion();
6969 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6973 AISDraw(ocpndc, GetVP(),
this);
6974 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6978 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6979 temp_dc.MaxY() - temp_dc.MinY());
6981 if (!ais_rect.IsEmpty())
6982 ais_rect.Inflate(2);
6984 temp_dc.SelectObject(wxNullBitmap);
6987 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6990 wxRect ais_update_rect = ais_draw_rect;
6991 ais_update_rect.Union(ais_rect);
6994 RefreshRect(ais_update_rect,
false);
6998 ais_draw_rect = ais_rect;
7001void ChartCanvas::ToggleCPAWarn() {
7002 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7008 g_bTCPA_Max =
false;
7012 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7013 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7015 if (!g_AisFirstTimeUse) {
7016 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7017 _(
"CPA") +
" " + mess, 4, 4);
7022void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7024void ChartCanvas::OnSize(wxSizeEvent &event) {
7025 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7027 GetClientSize(&m_canvas_width, &m_canvas_height);
7031 m_displayScale = GetContentScaleFactor();
7035 m_canvas_width *= m_displayScale;
7036 m_canvas_height *= m_displayScale;
7049 m_absolute_min_scale_ppm =
7051 (1.2 * WGS84_semimajor_axis_meters * PI);
7054 gFrame->ProcessCanvasResize();
7064 SetMUIBarPosition();
7065 UpdateFollowButtonState();
7066 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7070 xr_margin = m_canvas_width * 95 / 100;
7071 xl_margin = m_canvas_width * 5 / 100;
7072 yt_margin = m_canvas_height * 5 / 100;
7073 yb_margin = m_canvas_height * 95 / 100;
7076 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7081 m_brepaint_piano =
true;
7084 m_dc_route.SelectObject(wxNullBitmap);
7087 m_dc_route.SelectObject(*proute_bm);
7101 m_glcc->OnSize(event);
7110void ChartCanvas::ProcessNewGUIScale() {
7118void ChartCanvas::CreateMUIBar() {
7119 if (g_useMUI && !m_muiBar) {
7120 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7121 m_muiBar->SetColorScheme(m_cs);
7122 m_muiBarHOSize = m_muiBar->m_size;
7130 SetMUIBarPosition();
7131 UpdateFollowButtonState();
7132 m_muiBar->UpdateDynamicValues();
7133 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7137void ChartCanvas::SetMUIBarPosition() {
7141 int pianoWidth = GetClientSize().x * 0.6f;
7146 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7147 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7149 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7150 m_muiBar->SetColorScheme(m_cs);
7154 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7155 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7157 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7158 m_muiBar->SetColorScheme(m_cs);
7162 m_muiBar->SetBestPosition();
7166void ChartCanvas::DestroyMuiBar() {
7173void ChartCanvas::ShowCompositeInfoWindow(
7174 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7176 if (NULL == m_pCIWin) {
7181 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7184 s = _(
"Composite of ");
7187 s1.Printf(
"%d ", n_charts);
7195 s1.Printf(_(
"Chart scale"));
7198 s2.Printf(
"1:%d\n",
scale);
7202 s1 = _(
"Zoom in for more information");
7206 int char_width = s1.Length();
7207 int char_height = 3;
7209 if (g_bChartBarEx) {
7212 for (
int i : index_vector) {
7214 wxString path = cte.GetFullSystemPath();
7218 char_width = wxMax(char_width, path.Length());
7219 if (j++ >= 9)
break;
7222 s +=
" .\n .\n .\n";
7231 m_pCIWin->SetString(s);
7233 m_pCIWin->FitToChars(char_width, char_height);
7236 p.x = x / GetContentScaleFactor();
7237 if ((p.x + m_pCIWin->GetWinSize().x) >
7238 (m_canvas_width / GetContentScaleFactor()))
7239 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7240 m_pCIWin->GetWinSize().x) /
7243 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7244 4 - m_pCIWin->GetWinSize().y;
7246 m_pCIWin->dbIndex = 0;
7247 m_pCIWin->chart_scale = 0;
7248 m_pCIWin->SetPosition(p);
7249 m_pCIWin->SetBitmap();
7250 m_pCIWin->Refresh();
7254 HideChartInfoWindow();
7258void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7260 if (NULL == m_pCIWin) {
7265 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7274 dbIndex, FULL_INIT);
7276 int char_width, char_height;
7277 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7278 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7280 m_pCIWin->SetString(s);
7281 m_pCIWin->FitToChars(char_width, char_height);
7284 p.x = x / GetContentScaleFactor();
7285 if ((p.x + m_pCIWin->GetWinSize().x) >
7286 (m_canvas_width / GetContentScaleFactor()))
7287 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7288 m_pCIWin->GetWinSize().x) /
7291 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7292 4 - m_pCIWin->GetWinSize().y;
7294 m_pCIWin->dbIndex = dbIndex;
7295 m_pCIWin->SetPosition(p);
7296 m_pCIWin->SetBitmap();
7297 m_pCIWin->Refresh();
7301 HideChartInfoWindow();
7305void ChartCanvas::HideChartInfoWindow() {
7308 m_pCIWin->Destroy();
7312 androidForceFullRepaint();
7317void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7318 wxMouseEvent ev(wxEVT_MOTION);
7321 ev.m_leftDown = mouse_leftisdown;
7323 wxEvtHandler *evthp = GetEventHandler();
7325 ::wxPostEvent(evthp, ev);
7328void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7329 if ((m_panx_target_final - m_panx_target_now) ||
7330 (m_pany_target_final - m_pany_target_now)) {
7331 DoTimedMovementTarget();
7336void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7338bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7340 if (m_disable_edge_pan)
return false;
7343 int pan_margin = m_canvas_width * margin / 100;
7344 int pan_timer_set = 200;
7345 double pan_delta = GetVP().
pix_width * delta / 100;
7349 if (x > m_canvas_width - pan_margin) {
7354 else if (x < pan_margin) {
7359 if (y < pan_margin) {
7364 else if (y > m_canvas_height - pan_margin) {
7373 wxMouseState state = ::wxGetMouseState();
7374#if wxCHECK_VERSION(3, 0, 0)
7375 if (!state.LeftIsDown())
7377 if (!state.LeftDown())
7382 if ((bft) && !pPanTimer->IsRunning()) {
7384 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7390 if ((!bft) && pPanTimer->IsRunning()) {
7400void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7401 bool setBeingEdited) {
7402 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7403 m_pRoutePointEditTarget = NULL;
7404 m_pFoundPoint = NULL;
7407 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7408 SelectableItemList SelList =
pSelect->FindSelectionList(
7418 bool brp_viz =
false;
7419 if (m_pEditRouteArray) {
7420 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7421 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7422 if (pr->IsVisible()) {
7428 brp_viz = frp->IsVisible();
7432 if (m_pEditRouteArray)
7434 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7435 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7438 m_bRouteEditing = setBeingEdited;
7441 frp->m_bRPIsBeingEdited = setBeingEdited;
7442 m_bMarkEditing = setBeingEdited;
7445 m_pRoutePointEditTarget = frp;
7446 m_pFoundPoint = pFind;
7451std::shared_ptr<HostApi121::PiPointContext>
7452ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7466 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7467 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7468 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7469 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7470 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7474 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7477 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7482 int FoundAIS_MMSI = 0;
7484 FoundAIS_MMSI = pFindAIS->GetUserData();
7487 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7488 seltype |= SELTYPE_AISTARGET;
7494 Route *SelectedRoute = NULL;
7500 Route *pSelectedActiveRoute = NULL;
7501 Route *pSelectedVizRoute = NULL;
7504 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7505 SelectableItemList SelList =
7506 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7514 bool brp_viz =
false;
7516 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7518 if (pr->IsVisible()) {
7523 if (!brp_viz && prp->IsShared())
7525 brp_viz = prp->IsVisible();
7528 brp_viz = prp->IsVisible();
7530 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7536 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7539 pSelectedActiveRoute = pr;
7540 pFoundActiveRoutePoint = prp;
7545 if (NULL == pSelectedVizRoute) {
7546 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7548 if (pr->IsVisible()) {
7549 pSelectedVizRoute = pr;
7550 pFoundVizRoutePoint = prp;
7556 delete proute_array;
7561 if (pFoundActiveRoutePoint) {
7562 FoundRoutePoint = pFoundActiveRoutePoint;
7563 SelectedRoute = pSelectedActiveRoute;
7564 }
else if (pFoundVizRoutePoint) {
7565 FoundRoutePoint = pFoundVizRoutePoint;
7566 SelectedRoute = pSelectedVizRoute;
7569 FoundRoutePoint = pFirstVizPoint;
7571 if (SelectedRoute) {
7572 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7573 }
else if (FoundRoutePoint) {
7574 seltype |= SELTYPE_MARKPOINT;
7579 if (m_pFoundRoutePoint) {
7583 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7584 RefreshRect(wp_rect,
true);
7593 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7594 SelectableItemList SelList =
7595 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7597 if (NULL == SelectedRoute)
7602 if (pr->IsVisible()) {
7609 if (SelectedRoute) {
7610 if (NULL == FoundRoutePoint)
7611 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7614 seltype |= SELTYPE_ROUTESEGMENT;
7618 if (pFindTrackSeg) {
7619 m_pSelectedTrack = NULL;
7620 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7621 SelectableItemList SelList =
7622 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7627 if (pt->IsVisible()) {
7628 m_pSelectedTrack = pt;
7632 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7635 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7638 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7639 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7640 rstruct->object_ident =
"";
7642 if (seltype == SELTYPE_AISTARGET) {
7643 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7645 val.Printf(
"%d", FoundAIS_MMSI);
7646 rstruct->object_ident = val.ToStdString();
7647 }
else if (seltype & SELTYPE_MARKPOINT) {
7648 if (FoundRoutePoint) {
7649 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7650 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7652 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7653 if (SelectedRoute) {
7654 rstruct->object_type =
7655 HostApi121::PiContextObjectType::kObjectRoutesegment;
7656 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7658 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7659 if (m_pSelectedTrack) {
7660 rstruct->object_type =
7661 HostApi121::PiContextObjectType::kObjectTracksegment;
7662 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7669void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7670 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7671 singleClickEventIsValid =
false;
7672 m_DoubleClickTimer->Stop();
7677bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7678 if (!m_bChartDragging && !m_bDrawingRoute) {
7683 if (m_Compass && m_Compass->IsShown()) {
7685 bool isInCompass = logicalRect.Contains(event.GetPosition());
7686 if (isInCompass || m_mouseWasInCompass) {
7687 if (m_Compass->MouseEvent(event)) {
7688 cursor_region = CENTER;
7689 if (!g_btouch) SetCanvasCursor(event);
7690 m_mouseWasInCompass = isInCompass;
7694 m_mouseWasInCompass = isInCompass;
7697 if (m_notification_button && m_notification_button->IsShown()) {
7699 bool isinButton = logicalRect.Contains(event.GetPosition());
7701 SetCursor(*pCursorArrow);
7702 if (event.LeftDown()) HandleNotificationMouseClick();
7707 if (MouseEventToolbar(event))
return true;
7709 if (MouseEventChartBar(event))
return true;
7711 if (MouseEventMUIBar(event))
return true;
7713 if (MouseEventIENCBar(event))
return true;
7718void ChartCanvas::HandleNotificationMouseClick() {
7719 if (!m_NotificationsList) {
7723 m_NotificationsList->RecalculateSize();
7724 m_NotificationsList->Hide();
7727 if (m_NotificationsList->IsShown()) {
7728 m_NotificationsList->Hide();
7730 m_NotificationsList->RecalculateSize();
7731 m_NotificationsList->ReloadNotificationList();
7732 m_NotificationsList->Show();
7735bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7736 if (!g_bShowChartBar)
return false;
7738 if (!m_Piano->MouseEvent(event))
return false;
7740 cursor_region = CENTER;
7741 if (!g_btouch) SetCanvasCursor(event);
7745bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7746 if (!IsPrimaryCanvas())
return false;
7755 cursor_region = CENTER;
7756 if (!g_btouch) SetCanvasCursor(event);
7760bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7761 if (!IsPrimaryCanvas())
return false;
7774bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7776 if (!m_muiBar->MouseEvent(event))
return false;
7779 cursor_region = CENTER;
7780 if (!g_btouch) SetCanvasCursor(event);
7792 event.GetPosition(&x, &y);
7794 x *= m_displayScale;
7795 y *= m_displayScale;
7797 m_MouseDragging =
event.Dragging();
7803 if (event.Dragging()) {
7804 if ((x == mouse_x) && (y == mouse_y))
return true;
7810 mouse_leftisdown =
event.LeftDown();
7814 cursor_region = CENTER;
7818 if (m_Compass && m_Compass->IsShown() &&
7819 m_Compass->
GetRect().Contains(event.GetPosition())) {
7820 cursor_region = CENTER;
7821 }
else if (x > xr_margin) {
7822 cursor_region = MID_RIGHT;
7823 }
else if (x < xl_margin) {
7824 cursor_region = MID_LEFT;
7825 }
else if (y > yb_margin - chartbar_height &&
7826 y < m_canvas_height - chartbar_height) {
7827 cursor_region = MID_TOP;
7828 }
else if (y < yt_margin) {
7829 cursor_region = MID_BOT;
7831 cursor_region = CENTER;
7834 if (!g_btouch) SetCanvasCursor(event);
7838 leftIsDown =
event.LeftDown();
7841 if (event.LeftDown()) {
7842 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7845 g_bTempShowMenuBar =
false;
7846 parent_frame->ApplyGlobalSettings(
false);
7854 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7855 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7859 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7860 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7863 event.SetEventObject(
this);
7864 if (SendMouseEventToPlugins(event))
7871 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7872 StartChartDragInertia();
7875 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7876 !singleClickEventIsValid) {
7878 if (m_DoubleClickTimer->IsRunning()) {
7879 m_DoubleClickTimer->Stop();
7884 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7885 singleClickEvent = event;
7886 singleClickEventIsValid =
true;
7895 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7896 if (g_click_stop > 0) {
7904 if (GetUpMode() == COURSE_UP_MODE) {
7905 m_b_rot_hidef =
false;
7906 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7908 pRotDefTimer->Stop();
7911 bool bRoll = !g_btouch;
7916 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7917 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7918 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7919 m_RolloverPopupTimer.Start(
7923 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7927 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7936#if !defined(__WXGTK__) && !defined(__WXQT__)
7944 if ((x >= 0) && (y >= 0))
7949 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7950 wxPoint p = ClientToScreen(wxPoint(x, y));
7956 if (m_routeState >= 2) {
7959 m_bDrawingRoute =
true;
7961 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7966 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7969 m_bDrawingRoute =
true;
7971 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7984#if defined(__WXMAC__) || defined(__ANDROID__)
7988 wxClientDC cdc(GetParent());
8000 if (m_pSelectedRoute) {
8002 m_pSelectedRoute->DeSelectRoute();
8004 if (g_bopengl && m_glcc) {
8009 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8012 if (m_pFoundRoutePoint) {
8020 if (g_btouch && m_pRoutePointEditTarget) {
8023 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8027 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8028 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8029 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8030 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8031 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8035 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8038 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8044 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8047 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8048 seltype |= SELTYPE_AISTARGET;
8053 m_pFoundRoutePoint = NULL;
8058 Route *pSelectedActiveRoute = NULL;
8059 Route *pSelectedVizRoute = NULL;
8062 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8063 SelectableItemList SelList =
8064 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8072 bool brp_viz =
false;
8074 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8076 if (pr->IsVisible()) {
8081 if (!brp_viz && prp->IsShared())
8083 brp_viz = prp->IsVisible();
8086 brp_viz = prp->IsVisible();
8088 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8093 m_pSelectedRoute = NULL;
8095 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8098 pSelectedActiveRoute = pr;
8099 pFoundActiveRoutePoint = prp;
8104 if (NULL == pSelectedVizRoute) {
8105 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8107 if (pr->IsVisible()) {
8108 pSelectedVizRoute = pr;
8109 pFoundVizRoutePoint = prp;
8115 delete proute_array;
8120 if (pFoundActiveRoutePoint) {
8121 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8122 m_pSelectedRoute = pSelectedActiveRoute;
8123 }
else if (pFoundVizRoutePoint) {
8124 m_pFoundRoutePoint = pFoundVizRoutePoint;
8125 m_pSelectedRoute = pSelectedVizRoute;
8128 m_pFoundRoutePoint = pFirstVizPoint;
8130 if (m_pSelectedRoute) {
8131 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8132 }
else if (m_pFoundRoutePoint) {
8133 seltype |= SELTYPE_MARKPOINT;
8137 if (m_pFoundRoutePoint) {
8141 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8142 RefreshRect(wp_rect,
true);
8150 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8151 SelectableItemList SelList =
8152 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8154 if (NULL == m_pSelectedRoute)
8159 if (pr->IsVisible()) {
8160 m_pSelectedRoute = pr;
8166 if (m_pSelectedRoute) {
8167 if (NULL == m_pFoundRoutePoint)
8168 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8173 if (g_bopengl && m_glcc) {
8178 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8180 seltype |= SELTYPE_ROUTESEGMENT;
8184 if (pFindTrackSeg) {
8185 m_pSelectedTrack = NULL;
8186 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8187 SelectableItemList SelList =
8188 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8193 if (pt->IsVisible()) {
8194 m_pSelectedTrack = pt;
8198 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8204 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8205 seltype |= SELTYPE_CURRENTPOINT;
8208 else if (pFindTide) {
8209 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8210 seltype |= SELTYPE_TIDEPOINT;
8215 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8220IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8230 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8231 SelectableItemList SelList =
8232 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8235 pFind = *SelList.begin();
8236 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8238 auto node = SelList.begin();
8239 if (SelList.size() > 1) {
8240 for (++node; node != SelList.end(); ++node) {
8243 if (pIDX_candidate->
IDX_type ==
'c') {
8244 pIDX_best_candidate = pIDX_candidate;
8249 pFind = *SelList.begin();
8250 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8253 return pIDX_best_candidate;
8255void ChartCanvas::CallPopupMenu(
int x,
int y) {
8259 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8267 if (SELTYPE_CURRENTPOINT == seltype) {
8273 if (SELTYPE_TIDEPOINT == seltype) {
8279 InvokeCanvasMenu(x, y, seltype);
8282 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8286 m_pSelectedRoute = NULL;
8288 if (m_pFoundRoutePoint) {
8289 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8292 m_pFoundRoutePoint = NULL;
8298bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8306 event.GetPosition(&x, &y);
8312 SelectRadius = g_Platform->GetSelectRadiusPix() /
8313 (m_true_scale_ppm * 1852 * 60);
8320 if (event.LeftDClick() && (cursor_region == CENTER)) {
8321 m_DoubleClickTimer->Start();
8322 singleClickEventIsValid =
false;
8328 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8331 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8334 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8335 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8336 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8342 SelectableItemList rpSelList =
8343 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8344 bool b_onRPtarget =
false;
8347 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8348 b_onRPtarget =
true;
8356 std::unique_ptr<HostApi> host_api =
GetHostApi();
8357 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8359 if (m_pRoutePointEditTarget) {
8361 if ((api_121->GetContextMenuMask() &
8362 api_121->kContextMenuDisableWaypoint))
8364 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8370 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8373 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8374 m_pRoutePointEditTarget = NULL;
8375 RefreshRect(wp_rect,
true);
8379 auto node = rpSelList.begin();
8380 if (node != rpSelList.end()) {
8384 wxArrayPtrVoid *proute_array =
8389 bool brp_viz =
false;
8391 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8393 if (pr->IsVisible()) {
8398 delete proute_array;
8402 brp_viz = frp->IsVisible();
8404 brp_viz = frp->IsVisible();
8407 if ((api_121->GetContextMenuMask() &
8408 api_121->kContextMenuDisableWaypoint))
8411 ShowMarkPropertiesDialog(frp);
8420 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8422 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8425 if (pr->IsVisible()) {
8426 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8431 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8433 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8436 if (pt->IsVisible()) {
8437 ShowTrackPropertiesDialog(pt);
8446 if (m_bShowCurrent) {
8448 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8450 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8452 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8453 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8455 if (pic->m_enabled && pic->m_init_state &&
8456 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8459 if (m_pIDXCandidate) {
8460 info.point_type = CURRENT_STATION;
8464 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8465 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8469 if (plugin) plugin->OnTideCurrentClick(info);
8484 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8486 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8488 auto plugin_array = PluginLoader::GetInstance()->
GetPlugInArray();
8489 for (
unsigned int i = 0; i < plugin_array->GetCount(); i++) {
8491 if (pic->m_enabled && pic->m_init_state &&
8492 (pic->
m_cap_flag & WANTS_TIDECURRENT_CLICK)) {
8495 if (m_pIDXCandidate) {
8496 info.point_type = TIDE_STATION;
8500 info.getTide = [](time_t t,
int idx,
float &value,
float &dir) {
8501 return ptcmgr->GetTideOrCurrent(t, idx, value, dir);
8505 if (plugin) plugin->OnTideCurrentClick(info);
8520 ShowObjectQueryWindow(x, y, zlat, zlon);
8525 if (event.LeftDown()) {
8541 bool appending =
false;
8542 bool inserting =
false;
8545 SetCursor(*pCursorPencil);
8549 m_bRouteEditing =
true;
8551 if (m_routeState == 1) {
8552 m_pMouseRoute =
new Route();
8553 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8563 double nearby_radius_meters =
8564 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8567 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8568 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8569 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8570 wxArrayPtrVoid *proute_array =
8575 bool brp_viz =
false;
8577 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8579 if (pr->IsVisible()) {
8584 delete proute_array;
8586 pNearbyPoint->IsShared())
8589 pNearbyPoint->IsVisible();
8591 brp_viz = pNearbyPoint->IsVisible();
8594 wxString msg = _(
"Use nearby waypoint?");
8596 const bool noname(pNearbyPoint->GetName() ==
"");
8599 _(
"Use nearby nameless waypoint and name it M with"
8600 " a unique number?");
8603 m_FinishRouteOnKillFocus =
false;
8605 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8606 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8607 m_FinishRouteOnKillFocus =
true;
8608 if (dlg_return == wxID_YES) {
8610 if (m_pMouseRoute) {
8611 int last_wp_num = m_pMouseRoute->GetnPoints();
8613 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8614 wxString wp_name = wxString::Format(
8615 "M%002i-%s", last_wp_num + 1, guid_short);
8616 pNearbyPoint->SetName(wp_name);
8618 pNearbyPoint->SetName(
"WPXX");
8620 pMousePoint = pNearbyPoint;
8623 if (m_routeState > 1)
8624 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8625 Undo_HasParent, NULL);
8628 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8629 bool procede =
false;
8633 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8639 m_FinishRouteOnKillFocus =
false;
8645 _(
"Insert first part of this route in the new route?");
8646 if (tail->GetIndexOf(pMousePoint) ==
8649 dmsg = _(
"Insert this route in the new route?");
8651 if (tail->GetIndexOf(pMousePoint) != 1) {
8652 dlg_return = OCPNMessageBox(
8653 this, dmsg, _(
"OpenCPN Route Create"),
8654 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8655 m_FinishRouteOnKillFocus =
true;
8657 if (dlg_return == wxID_YES) {
8664 _(
"Append last part of this route to the new route?");
8665 if (tail->GetIndexOf(pMousePoint) == 1)
8667 "Append this route to the new route?");
8672 if (tail->GetLastPoint() != pMousePoint) {
8673 dlg_return = OCPNMessageBox(
8674 this, dmsg, _(
"OpenCPN Route Create"),
8675 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8676 m_FinishRouteOnKillFocus =
true;
8678 if (dlg_return == wxID_YES) {
8689 if (!FindRouteContainingWaypoint(pMousePoint))
8690 pMousePoint->SetShared(
true);
8695 if (NULL == pMousePoint) {
8696 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8698 pMousePoint->SetNameShown(
false);
8702 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8704 if (m_routeState > 1)
8705 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8706 Undo_IsOrphanded, NULL);
8709 if (m_pMouseRoute) {
8710 if (m_routeState == 1) {
8712 m_pMouseRoute->AddPoint(pMousePoint);
8716 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8717 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8718 &rhumbBearing, &rhumbDist);
8719 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8720 rlat, &gcDist, &gcBearing, NULL);
8721 double gcDistNM = gcDist / 1852.0;
8724 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8725 pow(rhumbDist - gcDistNM - 1, 0.5);
8728 msg << _(
"For this leg the Great Circle route is ")
8730 << _(
" shorter than rhumbline.\n\n")
8731 << _(
"Would you like include the Great Circle routing points "
8734 m_FinishRouteOnKillFocus =
false;
8735 m_disable_edge_pan =
true;
8738 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8739 wxYES_NO | wxNO_DEFAULT);
8741 m_disable_edge_pan =
false;
8742 m_FinishRouteOnKillFocus =
true;
8744 if (answer == wxID_YES) {
8746 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8747 wxRealPoint gcCoord;
8749 for (
int i = 1; i <= segmentCount; i++) {
8750 double fraction = (double)i * (1.0 / (
double)segmentCount);
8751 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8752 gcDist * fraction, gcBearing,
8753 &gcCoord.x, &gcCoord.y, NULL);
8755 if (i < segmentCount) {
8756 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8758 gcPoint->SetNameShown(
false);
8760 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8762 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8765 gcPoint = pMousePoint;
8768 m_pMouseRoute->AddPoint(gcPoint);
8769 pSelect->AddSelectableRouteSegment(
8770 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8771 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8772 prevGcPoint = gcPoint;
8775 undo->CancelUndoableAction(
true);
8778 m_pMouseRoute->AddPoint(pMousePoint);
8779 pSelect->AddSelectableRouteSegment(
8780 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8781 pMousePoint, m_pMouseRoute);
8782 undo->AfterUndoableAction(m_pMouseRoute);
8786 m_pMouseRoute->AddPoint(pMousePoint);
8787 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8788 rlon, m_prev_pMousePoint,
8789 pMousePoint, m_pMouseRoute);
8790 undo->AfterUndoableAction(m_pMouseRoute);
8796 m_prev_pMousePoint = pMousePoint;
8804 int connect = tail->GetIndexOf(pMousePoint);
8809 int length = tail->GetnPoints();
8814 start = connect + 1;
8819 m_pMouseRoute->RemovePoint(
8823 for (i = start; i <= stop; i++) {
8824 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8827 m_pMouseRoute->GetnPoints();
8829 gFrame->RefreshAllCanvas();
8833 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8835 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8836 m_pMouseRoute->FinalizeForRendering();
8838 gFrame->RefreshAllCanvas();
8842 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8844 SetCursor(*pCursorPencil);
8846 if (!m_pMeasureRoute) {
8847 m_pMeasureRoute =
new Route();
8851 if (m_nMeasureState == 1) {
8858 wxEmptyString, wxEmptyString);
8860 pMousePoint->SetShowWaypointRangeRings(
false);
8862 m_pMeasureRoute->AddPoint(pMousePoint);
8866 m_prev_pMousePoint = pMousePoint;
8870 gFrame->RefreshAllCanvas();
8875 FindRoutePointsAtCursor(SelectRadius,
true);
8879 m_last_touch_down_pos =
event.GetPosition();
8881 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8889 if (ret)
return true;
8892 if (event.Dragging()) {
8895 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8897 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8899 SelectableItemList SelList =
pSelect->FindSelectionList(
8903 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8908 if (m_pRoutePointEditTarget &&
8909 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8911 SelectableItemList SelList =
pSelect->FindSelectionList(
8915 if (m_pRoutePointEditTarget == frp) {
8916 m_bIsInRadius =
true;
8921 if (!m_dragoffsetSet) {
8923 .PresetDragOffset(
this, mouse_x, mouse_y);
8924 m_dragoffsetSet =
true;
8929 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8930 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8933 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8935 DraggingAllowed =
false;
8937 if (m_pRoutePointEditTarget &&
8938 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8939 DraggingAllowed =
false;
8941 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8943 if (DraggingAllowed) {
8944 if (!undo->InUndoableAction()) {
8945 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8946 Undo_NeedsCopy, m_pFoundPoint);
8952 if (!g_bopengl && m_pEditRouteArray) {
8953 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8954 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8961 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8962 pre_rect.Union(route_rect);
8970 if (CheckEdgePan(x, y,
true, 5, 2))
8978 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8980 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8981 m_pRoutePointEditTarget,
8982 SELTYPE_DRAGHANDLE);
8983 m_pFoundPoint->m_slat =
8984 m_pRoutePointEditTarget->m_lat;
8985 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8987 m_pRoutePointEditTarget->m_lat =
8989 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8990 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8991 m_pFoundPoint->m_slat =
8993 m_pFoundPoint->m_slon = new_cursor_lon;
9009 if (m_pEditRouteArray) {
9010 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9012 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9015 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9016 post_rect.Union(route_rect);
9022 pre_rect.Union(post_rect);
9023 RefreshRect(pre_rect,
false);
9025 gFrame->RefreshCanvasOther(
this);
9026 m_bRoutePoinDragging =
true;
9031 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
9032 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
9035 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
9037 DraggingAllowed =
false;
9039 if (m_pRoutePointEditTarget &&
9040 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
9041 DraggingAllowed =
false;
9043 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
9045 if (DraggingAllowed) {
9046 if (!undo->InUndoableAction()) {
9047 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
9048 Undo_NeedsCopy, m_pFoundPoint);
9062 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9068 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9069 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9070 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9071 (
int)(lppmax - (pre_rect.height / 2)));
9079 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9082 m_pRoutePointEditTarget,
9083 SELTYPE_DRAGHANDLE);
9084 m_pFoundPoint->m_slat =
9085 m_pRoutePointEditTarget->m_lat;
9086 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9088 m_pRoutePointEditTarget->m_lat =
9091 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9104 if (!g_btouch) InvalidateGL();
9110 .CalculateDCRect(m_dc_route,
this, &post_rect);
9111 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9112 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9113 (
int)(lppmax - (post_rect.height / 2)));
9116 pre_rect.Union(post_rect);
9117 RefreshRect(pre_rect,
false);
9119 gFrame->RefreshCanvasOther(
this);
9120 m_bRoutePoinDragging =
true;
9122 ret = g_btouch ? m_bRoutePoinDragging :
true;
9125 if (ret)
return true;
9128 if (event.LeftUp()) {
9129 bool b_startedit_route =
false;
9130 m_dragoffsetSet =
false;
9133 m_bChartDragging =
false;
9134 m_bIsInRadius =
false;
9138 if (m_ignore_next_leftup) {
9139 m_ignore_next_leftup =
false;
9144 m_bedge_pan =
false;
9149 bool appending =
false;
9150 bool inserting =
false;
9156 if (m_pRoutePointEditTarget) {
9162 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9163 RefreshRect(wp_rect,
true);
9165 m_pRoutePointEditTarget = NULL;
9167 m_bRouteEditing =
true;
9169 if (m_routeState == 1) {
9170 m_pMouseRoute =
new Route();
9171 m_pMouseRoute->SetHiLite(50);
9175 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9182 double nearby_radius_meters =
9183 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9186 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9187 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9188 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9191 m_FinishRouteOnKillFocus =
9193 dlg_return = OCPNMessageBox(
9194 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9195 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9196 m_FinishRouteOnKillFocus =
true;
9198 dlg_return = wxID_YES;
9200 if (dlg_return == wxID_YES) {
9201 pMousePoint = pNearbyPoint;
9204 if (m_routeState > 1)
9205 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9206 Undo_HasParent, NULL);
9207 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9209 bool procede =
false;
9213 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9219 m_FinishRouteOnKillFocus =
false;
9220 if (m_routeState == 1) {
9224 _(
"Insert first part of this route in the new route?");
9225 if (tail->GetIndexOf(pMousePoint) ==
9228 dmsg = _(
"Insert this route in the new route?");
9230 if (tail->GetIndexOf(pMousePoint) != 1) {
9232 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9233 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9234 m_FinishRouteOnKillFocus =
true;
9236 if (dlg_return == wxID_YES) {
9243 _(
"Append last part of this route to the new route?");
9244 if (tail->GetIndexOf(pMousePoint) == 1)
9246 "Append this route to the new route?");
9250 if (tail->GetLastPoint() != pMousePoint) {
9252 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9253 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9254 m_FinishRouteOnKillFocus =
true;
9256 if (dlg_return == wxID_YES) {
9267 if (!FindRouteContainingWaypoint(pMousePoint))
9268 pMousePoint->SetShared(
true);
9272 if (NULL == pMousePoint) {
9273 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9275 pMousePoint->SetNameShown(
false);
9277 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9279 if (m_routeState > 1)
9280 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9281 Undo_IsOrphanded, NULL);
9284 if (m_routeState == 1) {
9286 m_pMouseRoute->AddPoint(pMousePoint);
9287 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9291 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9292 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9293 &rhumbBearing, &rhumbDist);
9294 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9295 &gcDist, &gcBearing, NULL);
9296 double gcDistNM = gcDist / 1852.0;
9299 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9300 pow(rhumbDist - gcDistNM - 1, 0.5);
9303 msg << _(
"For this leg the Great Circle route is ")
9305 << _(
" shorter than rhumbline.\n\n")
9306 << _(
"Would you like include the Great Circle routing points "
9310 m_FinishRouteOnKillFocus =
false;
9311 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9312 wxYES_NO | wxNO_DEFAULT);
9313 m_FinishRouteOnKillFocus =
true;
9315 int answer = wxID_NO;
9318 if (answer == wxID_YES) {
9320 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9321 wxRealPoint gcCoord;
9323 for (
int i = 1; i <= segmentCount; i++) {
9324 double fraction = (double)i * (1.0 / (
double)segmentCount);
9325 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9326 gcDist * fraction, gcBearing,
9327 &gcCoord.x, &gcCoord.y, NULL);
9329 if (i < segmentCount) {
9330 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9332 gcPoint->SetNameShown(
false);
9333 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9336 gcPoint = pMousePoint;
9339 m_pMouseRoute->AddPoint(gcPoint);
9340 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9342 pSelect->AddSelectableRouteSegment(
9343 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9344 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9345 prevGcPoint = gcPoint;
9348 undo->CancelUndoableAction(
true);
9351 m_pMouseRoute->AddPoint(pMousePoint);
9352 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9353 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9354 rlon, m_prev_pMousePoint,
9355 pMousePoint, m_pMouseRoute);
9356 undo->AfterUndoableAction(m_pMouseRoute);
9360 m_pMouseRoute->AddPoint(pMousePoint);
9361 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9363 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9364 rlon, m_prev_pMousePoint,
9365 pMousePoint, m_pMouseRoute);
9366 undo->AfterUndoableAction(m_pMouseRoute);
9372 m_prev_pMousePoint = pMousePoint;
9379 int connect = tail->GetIndexOf(pMousePoint);
9384 int length = tail->GetnPoints();
9389 start = connect + 1;
9394 m_pMouseRoute->RemovePoint(
9398 for (i = start; i <= stop; i++) {
9399 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9402 m_pMouseRoute->GetnPoints();
9404 gFrame->RefreshAllCanvas();
9408 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9410 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9411 m_pMouseRoute->FinalizeForRendering();
9416 }
else if (m_bMeasure_Active && m_nMeasureState)
9419 m_bedge_pan =
false;
9423 if (m_ignore_next_leftup) {
9424 m_ignore_next_leftup =
false;
9428 if (m_nMeasureState == 1) {
9429 m_pMeasureRoute =
new Route();
9435 if (m_pMeasureRoute) {
9438 wxEmptyString, wxEmptyString);
9441 m_pMeasureRoute->AddPoint(pMousePoint);
9445 m_prev_pMousePoint = pMousePoint;
9447 m_pMeasureRoute->GetnPoints();
9451 CancelMeasureRoute();
9457 bool bSelectAllowed =
true;
9459 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9461 bSelectAllowed =
false;
9465 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9466 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9467 significant_drag) ||
9468 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9469 significant_drag)) {
9470 bSelectAllowed =
false;
9478 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9480 if (bSelectAllowed) {
9481 bool b_was_editing_mark = m_bMarkEditing;
9482 bool b_was_editing_route = m_bRouteEditing;
9483 FindRoutePointsAtCursor(SelectRadius,
9489 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9490 m_pRoutePointEditTarget = NULL;
9492 if (!b_was_editing_route) {
9493 if (m_pEditRouteArray) {
9494 b_startedit_route =
true;
9498 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9499 m_pTrackRolloverWin->IsActive(
false);
9501 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9502 m_pRouteRolloverWin->IsActive(
false);
9506 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9508 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9516 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9517 pre_rect.Union(route_rect);
9520 RefreshRect(pre_rect,
true);
9523 b_startedit_route =
false;
9527 if (m_pRoutePointEditTarget) {
9528 if (b_was_editing_mark ||
9529 b_was_editing_route) {
9530 if (m_lastRoutePointEditTarget) {
9534 .EnableDragHandle(
false);
9535 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9536 SELTYPE_DRAGHANDLE);
9540 if (m_pRoutePointEditTarget) {
9543 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9544 wxPoint2DDouble dragHandlePoint =
9546 .GetDragHandlePoint(
this);
9548 dragHandlePoint.m_y, dragHandlePoint.m_x,
9549 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9552 if (m_lastRoutePointEditTarget) {
9556 .EnableDragHandle(
false);
9557 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9558 SELTYPE_DRAGHANDLE);
9561 wxArrayPtrVoid *lastEditRouteArray =
9563 m_lastRoutePointEditTarget);
9564 if (lastEditRouteArray) {
9565 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9567 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9572 delete lastEditRouteArray;
9583 if (m_lastRoutePointEditTarget) {
9586 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9587 RefreshRect(wp_rect,
true);
9590 if (m_pRoutePointEditTarget) {
9593 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9594 RefreshRect(wp_rect,
true);
9602 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9603 bool b_start_rollover =
false;
9607 if (pFind) b_start_rollover =
true;
9610 if (!b_start_rollover && !b_startedit_route) {
9611 SelectableItemList SelList =
pSelect->FindSelectionList(
9615 if (pr && pr->IsVisible()) {
9616 b_start_rollover =
true;
9622 if (!b_start_rollover && !b_startedit_route) {
9623 SelectableItemList SelList =
pSelect->FindSelectionList(
9627 if (tr && tr->IsVisible()) {
9628 b_start_rollover =
true;
9634 if (b_start_rollover)
9635 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9639 bool appending =
false;
9640 bool inserting =
false;
9642 if (m_bRouteEditing ) {
9644 if (m_pRoutePointEditTarget) {
9650 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9651 double nearby_radius_meters =
9652 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9653 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9654 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9655 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9657 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9661 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9663 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9667 std::find(list->begin(), list->end(), pNearbyPoint);
9668 if (pos != list->end()) {
9680 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9685 OCPNMessageBox(
this,
9686 _(
"Replace this RoutePoint by the nearby "
9688 _(
"OpenCPN RoutePoint change"),
9689 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9690 if (dlg_return == wxID_YES) {
9695 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9698 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9700 if (tail && current && (tail != current)) {
9702 connect = tail->GetIndexOf(pNearbyPoint);
9703 int index_current_route =
9704 current->GetIndexOf(m_pRoutePointEditTarget);
9705 index_last = current->GetIndexOf(current->GetLastPoint());
9706 dlg_return1 = wxID_NO;
9708 index_current_route) {
9710 if (connect != tail->GetnPoints()) {
9713 _(
"Last part of route to be appended to dragged "
9717 _(
"Full route to be appended to dragged route?");
9719 dlg_return1 = OCPNMessageBox(
9720 this, dmsg, _(
"OpenCPN Route Create"),
9721 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9722 if (dlg_return1 == wxID_YES) {
9726 }
else if (index_current_route ==
9731 _(
"First part of route to be inserted into dragged "
9733 if (connect == tail->GetnPoints())
9735 "Full route to be inserted into dragged route?");
9737 dlg_return1 = OCPNMessageBox(
9738 this, dmsg, _(
"OpenCPN Route Create"),
9739 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9740 if (dlg_return1 == wxID_YES) {
9747 if (m_pRoutePointEditTarget->IsShared()) {
9749 dlg_return = OCPNMessageBox(
9751 _(
"Do you really want to delete and replace this "
9753 "\n" + _(
"which has been created manually?"),
9754 (
"OpenCPN RoutePoint warning"),
9755 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9758 if (dlg_return == wxID_YES) {
9759 pMousePoint = pNearbyPoint;
9761 pMousePoint->SetShared(
true);
9771 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9773 if (m_pEditRouteArray) {
9774 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9776 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9781 auto pos = std::find(list->begin(), list->end(),
9782 m_pRoutePointEditTarget);
9784 pSelect->DeleteAllSelectableRoutePoints(pr);
9785 pSelect->DeleteAllSelectableRouteSegments(pr);
9788 pos = std::find(list->begin(), list->end(),
9789 m_pRoutePointEditTarget);
9792 pSelect->AddAllSelectableRouteSegments(pr);
9793 pSelect->AddAllSelectableRoutePoints(pr);
9795 pr->FinalizeForRendering();
9796 pr->UpdateSegmentDistances();
9797 if (m_bRoutePoinDragging) {
9799 NavObj_dB::GetInstance().UpdateRoute(pr);
9807 if (m_pEditRouteArray) {
9808 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9810 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9829 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9836 delete m_pRoutePointEditTarget;
9837 m_lastRoutePointEditTarget = NULL;
9838 m_pRoutePointEditTarget = NULL;
9839 undo->AfterUndoableAction(pMousePoint);
9840 undo->InvalidateUndo();
9845 else if (m_bMarkEditing) {
9846 if (m_pRoutePointEditTarget)
9847 if (m_bRoutePoinDragging) {
9849 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9853 if (m_pRoutePointEditTarget)
9854 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9856 if (!m_pRoutePointEditTarget) {
9857 delete m_pEditRouteArray;
9858 m_pEditRouteArray = NULL;
9859 m_bRouteEditing =
false;
9861 m_bRoutePoinDragging =
false;
9868 int length = tail->GetnPoints();
9869 for (
int i = connect + 1; i <= length; i++) {
9870 current->AddPointAndSegment(tail->GetPoint(i),
false);
9873 gFrame->RefreshAllCanvas();
9876 current->FinalizeForRendering();
9882 pSelect->DeleteAllSelectableRoutePoints(current);
9883 pSelect->DeleteAllSelectableRouteSegments(current);
9884 for (
int i = 1; i < connect; i++) {
9885 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9887 pSelect->AddAllSelectableRouteSegments(current);
9888 pSelect->AddAllSelectableRoutePoints(current);
9889 current->FinalizeForRendering();
9896 if (m_pEditRouteArray) {
9897 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9898 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9911 if (m_bRouteEditing) {
9914 bool appending =
false;
9915 bool inserting =
false;
9918 if (m_pRoutePointEditTarget) {
9919 m_pRoutePointEditTarget->
m_bBlink =
false;
9923 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9924 double nearby_radius_meters =
9925 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9926 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9927 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9928 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9930 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9931 bool duplicate =
false;
9933 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9935 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9939 std::find(list->begin(), list->end(), pNearbyPoint);
9940 if (pos != list->end()) {
9952 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9957 OCPNMessageBox(
this,
9958 _(
"Replace this RoutePoint by the nearby "
9960 _(
"OpenCPN RoutePoint change"),
9961 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9962 if (dlg_return == wxID_YES) {
9966 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9969 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9971 if (tail && current && (tail != current)) {
9973 connect = tail->GetIndexOf(pNearbyPoint);
9974 int index_current_route =
9975 current->GetIndexOf(m_pRoutePointEditTarget);
9976 index_last = current->GetIndexOf(current->GetLastPoint());
9977 dlg_return1 = wxID_NO;
9979 index_current_route) {
9981 if (connect != tail->GetnPoints()) {
9984 _(
"Last part of route to be appended to dragged "
9988 _(
"Full route to be appended to dragged route?");
9990 dlg_return1 = OCPNMessageBox(
9991 this, dmsg, _(
"OpenCPN Route Create"),
9992 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9993 if (dlg_return1 == wxID_YES) {
9997 }
else if (index_current_route ==
10002 _(
"First part of route to be inserted into dragged "
10004 if (connect == tail->GetnPoints())
10006 "Full route to be inserted into dragged route?");
10008 dlg_return1 = OCPNMessageBox(
10009 this, dmsg, _(
"OpenCPN Route Create"),
10010 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10011 if (dlg_return1 == wxID_YES) {
10018 if (m_pRoutePointEditTarget->IsShared()) {
10019 dlg_return = wxID_NO;
10020 dlg_return = OCPNMessageBox(
10022 _(
"Do you really want to delete and replace this "
10024 "\n" + _(
"which has been created manually?"),
10025 (
"OpenCPN RoutePoint warning"),
10026 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10029 if (dlg_return == wxID_YES) {
10030 pMousePoint = pNearbyPoint;
10032 pMousePoint->SetShared(
true);
10042 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
10044 if (m_pEditRouteArray) {
10045 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10047 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10051 auto pos = std::find(list->begin(), list->end(),
10052 m_pRoutePointEditTarget);
10054 pSelect->DeleteAllSelectableRoutePoints(pr);
10055 pSelect->DeleteAllSelectableRouteSegments(pr);
10058 pos = std::find(list->begin(), list->end(),
10059 m_pRoutePointEditTarget);
10060 if (pos != list->end()) list->erase(pos);
10063 pSelect->AddAllSelectableRouteSegments(pr);
10064 pSelect->AddAllSelectableRoutePoints(pr);
10066 pr->FinalizeForRendering();
10067 pr->UpdateSegmentDistances();
10070 if (m_bRoutePoinDragging) {
10075 NavObj_dB::GetInstance().UpdateRoutePoint(
10076 m_pRoutePointEditTarget);
10078 NavObj_dB::GetInstance().UpdateRoute(pr);
10090 int length = tail->GetnPoints();
10091 for (
int i = connect + 1; i <= length; i++) {
10092 current->AddPointAndSegment(tail->GetPoint(i),
false);
10096 gFrame->RefreshAllCanvas();
10099 current->FinalizeForRendering();
10105 pSelect->DeleteAllSelectableRoutePoints(current);
10106 pSelect->DeleteAllSelectableRouteSegments(current);
10107 for (
int i = 1; i < connect; i++) {
10108 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10110 pSelect->AddAllSelectableRouteSegments(current);
10111 pSelect->AddAllSelectableRoutePoints(current);
10112 current->FinalizeForRendering();
10119 if (m_pEditRouteArray) {
10120 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10122 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10134 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10141 delete m_pRoutePointEditTarget;
10142 m_lastRoutePointEditTarget = NULL;
10143 undo->AfterUndoableAction(pMousePoint);
10144 undo->InvalidateUndo();
10149 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10152 delete m_pEditRouteArray;
10153 m_pEditRouteArray = NULL;
10157 m_bRouteEditing =
false;
10158 m_pRoutePointEditTarget = NULL;
10164 else if (m_bMarkEditing) {
10165 if (m_pRoutePointEditTarget) {
10166 if (m_bRoutePoinDragging) {
10168 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10170 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10175 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10177 RefreshRect(wp_rect,
true);
10180 m_pRoutePointEditTarget = NULL;
10181 m_bMarkEditing =
false;
10186 else if (leftIsDown) {
10187 leftIsDown =
false;
10191 if (!m_bChartDragging && !m_bMeasure_Active) {
10193 m_bChartDragging =
false;
10197 m_bRoutePoinDragging =
false;
10200 if (ret)
return true;
10203 if (event.RightDown()) {
10214 m_FinishRouteOnKillFocus =
false;
10215 CallPopupMenu(mx, my);
10216 m_FinishRouteOnKillFocus =
true;
10226 if (event.ShiftDown()) {
10230 event.GetPosition(&x, &y);
10232 x *= m_displayScale;
10233 y *= m_displayScale;
10239 int wheel_dir =
event.GetWheelRotation();
10242 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10243 wheel_dir = wheel_dir > 0 ? 1 : -1;
10245 double factor = g_mouse_zoom_sensitivity;
10246 if (wheel_dir < 0) factor = 1 / factor;
10249 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10250 if (wheel_dir == m_last_wheel_dir) {
10251 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10256 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10257 m_wheelstopwatch.Start(0);
10262 m_last_wheel_dir = wheel_dir;
10267 if (event.LeftDown()) {
10273 last_drag.x = x, last_drag.y = y;
10274 panleftIsDown =
true;
10277 if (event.LeftUp()) {
10278 if (panleftIsDown) {
10280 panleftIsDown =
false;
10283 if (!m_bChartDragging && !m_bMeasure_Active) {
10284 switch (cursor_region) {
10306 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10311 m_bChartDragging =
false;
10317 if (event.Dragging() && event.LeftIsDown()) {
10333 if (g_btouch && !m_inPinch) {
10334 struct timespec now;
10335 clock_gettime(CLOCK_MONOTONIC, &now);
10336 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10338 bool trigger_hold =
false;
10339 if (
false == m_bChartDragging) {
10340 if (m_DragTrigger < 0) {
10343 m_DragTriggerStartTime = tnow;
10344 trigger_hold =
true;
10346 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10347 m_DragTrigger = -1;
10352 if (trigger_hold)
return true;
10354 if (
false == m_bChartDragging) {
10357 last_drag.x = x - 1, last_drag.y = y - 1;
10358 m_bChartDragging =
true;
10359 m_chart_drag_total_time = 0;
10360 m_chart_drag_total_x = 0;
10361 m_chart_drag_total_y = 0;
10362 m_inertia_last_drag_x = x;
10363 m_inertia_last_drag_y = y;
10364 m_drag_vec_x.clear();
10365 m_drag_vec_y.clear();
10366 m_drag_vec_t.clear();
10367 m_last_drag_time = tnow;
10371 uint64_t delta_t = tnow - m_last_drag_time;
10372 double delta_tf = delta_t / 1e9;
10374 m_chart_drag_total_time += delta_tf;
10375 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10376 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10378 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10379 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10380 m_drag_vec_t.push_back(delta_tf);
10382 m_inertia_last_drag_x = x;
10383 m_inertia_last_drag_y = y;
10384 m_last_drag_time = tnow;
10386 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10387 m_bChartDragging =
true;
10388 StartTimedMovement();
10389 m_pan_drag.x += last_drag.x - x;
10390 m_pan_drag.y += last_drag.y - y;
10391 last_drag.x = x, last_drag.y = y;
10393 }
else if (!g_btouch) {
10394 if ((last_drag.x != x) || (last_drag.y != y)) {
10395 if (!m_routeState) {
10398 m_bChartDragging =
true;
10399 StartTimedMovement();
10400 m_pan_drag.x += last_drag.x - x;
10401 m_pan_drag.y += last_drag.y - y;
10402 last_drag.x = x, last_drag.y = y;
10409 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10411 m_ignore_next_leftup =
true;
10412 m_DoubleClickTimer->Start();
10413 singleClickEventIsValid =
false;
10421void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10422 if (MouseEventOverlayWindows(event))
return;
10426 bool nm = MouseEventProcessObjects(event);
10430void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10433 wxCursor *ptarget_cursor = pCursorArrow;
10434 if (!pPlugIn_Cursor) {
10435 ptarget_cursor = pCursorArrow;
10436 if ((!m_routeState) &&
10437 (!m_bMeasure_Active) ) {
10438 if (cursor_region == MID_RIGHT) {
10439 ptarget_cursor = pCursorRight;
10440 }
else if (cursor_region == MID_LEFT) {
10441 ptarget_cursor = pCursorLeft;
10442 }
else if (cursor_region == MID_TOP) {
10443 ptarget_cursor = pCursorDown;
10444 }
else if (cursor_region == MID_BOT) {
10445 ptarget_cursor = pCursorUp;
10447 ptarget_cursor = pCursorArrow;
10449 }
else if (m_bMeasure_Active ||
10451 ptarget_cursor = pCursorPencil;
10453 ptarget_cursor = pPlugIn_Cursor;
10456 SetCursor(*ptarget_cursor);
10459void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10460 SetCursor(*pCursorArrow);
10463void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10467 wxArrayString files;
10469 ChartBase *target_chart = GetChartAtCursor();
10470 if (target_chart) {
10471 file.Assign(target_chart->GetFullPath());
10472 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10473 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10476 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10478 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10479 unsigned int im = stackIndexArray.size();
10480 int scale = 2147483647;
10481 if (VPoint.b_quilt && im > 0) {
10482 for (
unsigned int is = 0; is < im; is++) {
10483 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10484 CHART_TYPE_MBTILES) {
10485 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10487 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10488 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10490 .Contains(lat, lon)) {
10491 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10494 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10495 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10503 std::vector<Ais8_001_22 *> area_notices;
10505 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10508 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10509 auto target_data = target.second;
10510 if (!target_data->area_notices.empty()) {
10511 for (
auto &ani : target_data->area_notices) {
10516 for (Ais8_001_22_SubAreaList::iterator sa =
10517 area_notice.sub_areas.begin();
10518 sa != area_notice.sub_areas.end(); ++sa) {
10519 switch (sa->shape) {
10520 case AIS8_001_22_SHAPE_CIRCLE: {
10521 wxPoint target_point;
10523 bbox.Expand(target_point);
10524 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10527 case AIS8_001_22_SHAPE_RECT: {
10528 wxPoint target_point;
10530 bbox.Expand(target_point);
10531 if (sa->e_dim_m > sa->n_dim_m)
10532 bbox.EnLarge(sa->e_dim_m * vp_scale);
10534 bbox.EnLarge(sa->n_dim_m * vp_scale);
10537 case AIS8_001_22_SHAPE_POLYGON:
10538 case AIS8_001_22_SHAPE_POLYLINE: {
10539 for (
int i = 0; i < 4; ++i) {
10540 double lat = sa->latitude;
10541 double lon = sa->longitude;
10542 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10544 wxPoint target_point;
10546 bbox.Expand(target_point);
10550 case AIS8_001_22_SHAPE_SECTOR: {
10551 double lat1 = sa->latitude;
10552 double lon1 = sa->longitude;
10554 wxPoint target_point;
10556 bbox.Expand(target_point);
10557 for (
int i = 0; i < 18; ++i) {
10560 sa->left_bound_deg +
10561 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10562 sa->radius_m / 1852.0, &lat, &lon);
10564 bbox.Expand(target_point);
10566 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10569 bbox.Expand(target_point);
10575 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10576 area_notices.push_back(&area_notice);
10583 if (target_chart || !area_notices.empty() || file.HasName()) {
10585 int sel_rad_pix = 5;
10586 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10591 SetCursor(wxCURSOR_WAIT);
10592 bool lightsVis = m_encShowLights;
10593 if (!lightsVis) SetShowENCLights(
true);
10596 ListOfObjRazRules *rule_list = NULL;
10597 ListOfPI_S57Obj *pi_rule_list = NULL;
10600 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10601 else if (target_plugin_chart)
10602 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10603 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10605 ListOfObjRazRules *overlay_rule_list = NULL;
10606 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10609 if (CHs57_Overlay) {
10610 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10611 zlat, zlon, SelectRadius, &GetVP());
10614 if (!lightsVis) SetShowENCLights(
false);
10617 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10618 wxString face = dFont->GetFaceName();
10622 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10623 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10627 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10635 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10636 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10639 int points = dFont->GetPointSize();
10641 int points = dFont->GetPointSize() + 1;
10645 for (
int i = -2; i < 5; i++) {
10646 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10650 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10652 if (overlay_rule_list && CHs57_Overlay) {
10653 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10654 objText <<
"<hr noshade>";
10657 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10658 an != area_notices.end(); ++an) {
10659 objText <<
"<b>AIS Area Notice:</b> ";
10660 objText << ais8_001_22_notice_names[(*an)->notice_type];
10661 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10662 (*an)->sub_areas.begin();
10663 sa != (*an)->sub_areas.end(); ++sa)
10664 if (!sa->text.empty()) objText << sa->text;
10665 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10666 objText <<
"<hr noshade>";
10670 objText << Chs57->CreateObjDescriptions(rule_list);
10671 else if (target_plugin_chart)
10672 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10675 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10678 wxString AddFiles, filenameOK;
10680 if (!target_plugin_chart) {
10683 AddFiles = wxString::Format(
10684 "<hr noshade><br><b>Additional info files attached to: </b> "
10686 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10688 file.GetFullName());
10690 file.Assign(file.GetPath(),
"");
10691 wxDir dir(file.GetFullPath());
10693 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10695 file.Assign(dir.GetNameWithSep().append(filename));
10696 wxString FormatString =
10697 "<td valign=top><font size=-2><a "
10698 "href=\"%s\">%s</a></font></td>";
10699 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10700 filenameOK = file.GetFullPath();
10702 if (3 * ((
int)filecount / 3) == filecount)
10703 FormatString.Prepend(
"<tr>");
10705 FormatString.Prepend(
10706 "<td>  </td>");
10709 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10710 file.GetFullName());
10713 cont = dir.GetNext(&filename);
10715 objText << AddFiles <<
"</table>";
10717 objText <<
"</font>";
10718 objText <<
"</body></html>";
10720 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10724 if ((!Chs57 && filecount == 1)) {
10726 wxHtmlLinkInfo hli(filenameOK);
10727 wxHtmlLinkEvent hle(1, hli);
10731 if (rule_list) rule_list->Clear();
10734 if (overlay_rule_list) overlay_rule_list->Clear();
10735 delete overlay_rule_list;
10737 if (pi_rule_list) pi_rule_list->Clear();
10738 delete pi_rule_list;
10740 SetCursor(wxCURSOR_ARROW);
10744void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10753 wxSize canvas_size = GetSize();
10760 wxPoint canvas_pos = GetPosition();
10763 bool newFit =
false;
10764 if (canvas_size.x < fitted_size.x) {
10765 fitted_size.x = canvas_size.x - 40;
10766 if (canvas_size.y < fitted_size.y)
10767 fitted_size.y -= 40;
10769 if (canvas_size.y < fitted_size.y) {
10770 fitted_size.y = canvas_size.y - 40;
10771 if (canvas_size.x < fitted_size.x)
10772 fitted_size.x -= 40;
10783 wxString title_base = _(
"Mark Properties");
10785 title_base = _(
"Waypoint Properties");
10790 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10802void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10812 if (g_bresponsive) {
10813 wxSize canvas_size = GetSize();
10814 wxPoint canvas_pos = GetPosition();
10818 if (canvas_size.x < fitted_size.x) {
10819 fitted_size.x = canvas_size.x;
10820 if (canvas_size.y < fitted_size.y)
10821 fitted_size.y -= 20;
10823 if (canvas_size.y < fitted_size.y) {
10824 fitted_size.y = canvas_size.y;
10825 if (canvas_size.x < fitted_size.x)
10826 fitted_size.x -= 20;
10835 wxPoint xxp = ClientToScreen(canvas_pos);
10846void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10858void pupHandler_PasteWaypoint() {
10861 int pasteBuffer = kml.ParsePasteBuffer();
10862 RoutePoint *pasted = kml.GetParsedRoutePoint();
10863 if (!pasted)
return;
10865 double nearby_radius_meters =
10866 g_Platform->GetSelectRadiusPix() /
10867 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10869 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10870 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10872 int answer = wxID_NO;
10876 "There is an existing waypoint at the same location as the one you are "
10877 "pasting. Would you like to merge the pasted data with it?\n\n");
10878 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10879 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10880 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10883 if (answer == wxID_YES) {
10884 nearPoint->SetName(pasted->GetName());
10886 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10887 pRouteManagerDialog->UpdateWptListCtrl();
10890 if (answer == wxID_NO) {
10893 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10896 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10899 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10900 pRouteManagerDialog->UpdateWptListCtrl();
10905 gFrame->InvalidateAllGL();
10906 gFrame->RefreshAllCanvas(
false);
10909void pupHandler_PasteRoute() {
10912 int pasteBuffer = kml.ParsePasteBuffer();
10913 Route *pasted = kml.GetParsedRoute();
10914 if (!pasted)
return;
10916 double nearby_radius_meters =
10917 g_Platform->GetSelectRadiusPix() /
10918 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10924 bool mergepoints =
false;
10925 bool createNewRoute =
true;
10926 int existingWaypointCounter = 0;
10928 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10929 curPoint = pasted->GetPoint(i);
10930 nearPoint = pWayPointMan->GetNearbyWaypoint(
10931 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10933 mergepoints =
true;
10934 existingWaypointCounter++;
10942 int answer = wxID_NO;
10946 "There are existing waypoints at the same location as some of the ones "
10947 "you are pasting. Would you like to just merge the pasted data into "
10949 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10950 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10951 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10953 if (answer == wxID_CANCEL) {
10960 if (mergepoints && answer == wxID_YES &&
10961 existingWaypointCounter == pasted->GetnPoints()) {
10964 createNewRoute =
false;
10970 Route *newRoute = 0;
10973 if (createNewRoute) {
10974 newRoute =
new Route();
10978 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10979 curPoint = pasted->GetPoint(i);
10982 newPoint = pWayPointMan->GetNearbyWaypoint(
10983 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10984 newPoint->SetName(curPoint->GetName());
10987 if (createNewRoute) newRoute->AddPoint(newPoint);
10993 newPoint->SetIconName(
"circle");
10996 newPoint->SetShared(
false);
10998 newRoute->AddPoint(newPoint);
10999 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
11002 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
11005 if (i > 1 && createNewRoute)
11006 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
11007 curPoint->m_lat, curPoint->m_lon,
11008 prevPoint, newPoint, newRoute);
11009 prevPoint = newPoint;
11012 if (createNewRoute) {
11015 NavObj_dB::GetInstance().InsertRoute(newRoute);
11021 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
11022 pRouteManagerDialog->UpdateRouteListCtrl();
11023 pRouteManagerDialog->UpdateWptListCtrl();
11025 gFrame->InvalidateAllGL();
11026 gFrame->RefreshAllCanvas(
false);
11032void pupHandler_PasteTrack() {
11035 int pasteBuffer = kml.ParsePasteBuffer();
11036 Track *pasted = kml.GetParsedTrack();
11037 if (!pasted)
return;
11045 newTrack->SetName(pasted->GetName());
11047 for (
int i = 0; i < pasted->GetnPoints(); i++) {
11048 curPoint = pasted->GetPoint(i);
11052 wxDateTime now = wxDateTime::Now();
11055 newTrack->AddPoint(newPoint);
11058 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11059 newPoint->m_lat, newPoint->m_lon,
11060 prevPoint, newPoint, newTrack);
11062 prevPoint = newPoint;
11067 NavObj_dB::GetInstance().InsertTrack(newTrack);
11069 gFrame->InvalidateAllGL();
11070 gFrame->RefreshAllCanvas(
false);
11073bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11076 v[
"CursorPosition_x"] = x;
11077 v[
"CursorPosition_y"] = y;
11080 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11081 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11082 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11087 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11089 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11092#define SELTYPE_UNKNOWN 0x0001
11093#define SELTYPE_ROUTEPOINT 0x0002
11094#define SELTYPE_ROUTESEGMENT 0x0004
11095#define SELTYPE_TIDEPOINT 0x0008
11096#define SELTYPE_CURRENTPOINT 0x0010
11097#define SELTYPE_ROUTECREATE 0x0020
11098#define SELTYPE_AISTARGET 0x0040
11099#define SELTYPE_MARKPOINT 0x0080
11100#define SELTYPE_TRACKSEGMENT 0x0100
11101#define SELTYPE_DRAGHANDLE 0x0200
11104 if (g_bhide_context_menus)
return true;
11106 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11107 m_pIDXCandidate, m_nmea_log);
11110 wxEVT_COMMAND_MENU_SELECTED,
11111 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11117 if (m_inLongPress) {
11118 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11119 m_inLongPress =
false;
11123 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11126 wxEVT_COMMAND_MENU_SELECTED,
11127 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11129 delete m_canvasMenu;
11130 m_canvasMenu = NULL;
11140void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11143 if (m_canvasMenu) {
11144 m_canvasMenu->PopupMenuHandler(event);
11149void ChartCanvas::StartRoute() {
11151 if (g_brouteCreating)
return;
11155 g_brouteCreating =
true;
11157 m_bDrawingRoute =
false;
11158 SetCursor(*pCursorPencil);
11160 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11162 HideGlobalToolbar();
11165 androidSetRouteAnnunciator(
true);
11169wxString ChartCanvas::FinishRoute() {
11171 m_prev_pMousePoint = NULL;
11172 m_bDrawingRoute =
false;
11174 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11177 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11179 androidSetRouteAnnunciator(
false);
11182 SetCursor(*pCursorArrow);
11184 if (m_pMouseRoute) {
11185 if (m_bAppendingRoute) {
11187 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11189 if (m_pMouseRoute->GetnPoints() > 1) {
11191 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11194 m_pMouseRoute = NULL;
11197 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11204 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11205 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11206 pRouteManagerDialog->UpdateRouteListCtrl();
11209 m_bAppendingRoute =
false;
11210 m_pMouseRoute = NULL;
11212 m_pSelectedRoute = NULL;
11214 undo->InvalidateUndo();
11215 gFrame->RefreshAllCanvas(
true);
11219 ShowGlobalToolbar();
11221 g_brouteCreating =
false;
11226void ChartCanvas::HideGlobalToolbar() {
11227 if (m_canvasIndex == 0) {
11228 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11232void ChartCanvas::ShowGlobalToolbar() {
11233 if (m_canvasIndex == 0) {
11234 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11238void ChartCanvas::ShowAISTargetList() {
11239 if (NULL == g_pAISTargetList) {
11243 g_pAISTargetList->UpdateAISTargetList();
11246void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11247 if (!m_bShowOutlines)
return;
11251 int nEntry =
ChartData->GetChartTableEntries();
11253 for (
int i = 0; i < nEntry; i++) {
11257 bool b_group_draw =
false;
11258 if (m_groupIndex > 0) {
11259 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11260 int index = pt->GetGroupArray()[ig];
11261 if (m_groupIndex == index) {
11262 b_group_draw =
true;
11267 b_group_draw =
true;
11269 if (b_group_draw) RenderChartOutline(dc, i, vp);
11275 if (VPoint.b_quilt) {
11276 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11277 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11281 }
else if (m_singleChart &&
11282 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11286 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11289 if (zoom_factor > 8.0) {
11290 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11293 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11297 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11301void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11303 if (g_bopengl && m_glcc) {
11305 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11310 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11311 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11314 float plylat, plylon;
11315 float plylat1, plylon1;
11317 int pixx, pixy, pixx1, pixy1;
11320 ChartData->GetDBBoundingBox(dbIndex, box);
11324 if (box.GetLonRange() == 360)
return;
11326 double lon_bias = 0;
11328 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11330 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11332 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11333 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11335 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11336 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11339 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11342 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11343 if (0 == nAuxPlyEntries)
11347 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11348 plylon += lon_bias;
11354 for (
int i = 0; i < nPly - 1; i++) {
11355 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11356 plylon1 += lon_bias;
11362 int pixxs1 = pixx1;
11363 int pixys1 = pixy1;
11365 bool b_skip =
false;
11369 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11370 pow((
double)(pixy1 - pixy), 2)) /
11376 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11381 if (fabs(dist - distgc) > 10000. * 1852.)
11387 ClipResult res = cohen_sutherland_line_clip_i(
11389 if (res != Invisible && !b_skip)
11390 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11398 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11399 plylon1 += lon_bias;
11405 ClipResult res = cohen_sutherland_line_clip_i(
11407 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11414 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11415 for (
int j = 0; j < nAuxPlyEntries; j++) {
11417 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11422 for (
int i = 0; i < nAuxPly - 1; i++) {
11423 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11429 int pixxs1 = pixx1;
11430 int pixys1 = pixy1;
11432 bool b_skip =
false;
11436 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11437 ((pixy1 - pixy) * (pixy1 - pixy))) /
11442 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11447 if (fabs(dist - distgc) > 10000. * 1852.)
11453 ClipResult res = cohen_sutherland_line_clip_i(
11455 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11463 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11468 ClipResult res = cohen_sutherland_line_clip_i(
11470 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11475static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11476 const wxArrayString &legend) {
11477 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11479 int pointsize = dFont->GetPointSize();
11483 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11484 false, dFont->GetFaceName());
11486 dc.SetFont(*psRLI_font);
11493 int hilite_offset = 3;
11495 for (wxString line : legend) {
11498 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11500 dc.GetTextExtent(line, &wl, &hl);
11509 xp = ref_point.x - w;
11511 yp += hilite_offset;
11513 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11515 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11516 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11518 for (wxString line : legend) {
11519 dc.DrawText(line, xp, yp);
11524void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11525 if (!g_bAllowShipToActive)
return;
11531 wxPoint2DDouble pa, pb;
11538 if (rt->
m_width != wxPENSTYLE_INVALID)
11540 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11541 g_shipToActiveStyle, 5)];
11542 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11544 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11547 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11550 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11553 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11554 (
int)pb.m_y, GetVP(),
true);
11558#ifdef USE_ANDROID_GLES2
11559 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11561 if (style != wxPENSTYLE_SOLID) {
11562 if (glChartCanvas::dash_map.find(style) !=
11563 glChartCanvas::dash_map.end()) {
11564 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11568 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11571 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11572 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11578void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11580 if (m_routeState >= 2) route = m_pMouseRoute;
11581 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11582 route = m_pMeasureRoute;
11584 if (!route)
return;
11592 int np = route->GetnPoints();
11594 if (g_btouch && (np > 1)) np--;
11596 render_lat = rp.m_lat;
11597 render_lon = rp.m_lon;
11600 double rhumbBearing, rhumbDist;
11602 &rhumbBearing, &rhumbDist);
11603 double brg = rhumbBearing;
11604 double dist = rhumbDist;
11608 double gcBearing, gcBearing2, gcDist;
11609 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11612 double gcDistm = gcDist / 1852.0;
11615 rhumbBearing = 90.;
11617 wxPoint destPoint, lastPoint;
11620 int milesDiff = rhumbDist - gcDistm;
11621 if (milesDiff > 1) {
11632 for (
int i = 1; i <= milesDiff; i++) {
11633 double p = (double)i * (1.0 / (
double)milesDiff);
11635 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11636 &pLon, &pLat, &gcBearing2);
11638 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11640 lastPoint = destPoint;
11643 if (r_rband.x && r_rband.y) {
11644 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11646 if (m_bMeasure_DistCircle) {
11647 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11648 powf((
float)(r_rband.y - lastPoint.y), 2));
11651 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11652 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11658 wxString routeInfo;
11659 wxArrayString infoArray;
11662 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11668 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11670 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11671 (
int)varBrg, 0x00B0);
11674 infoArray.Add(routeInfo);
11680 routeInfo <<
"Reverse: ";
11682 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11683 (
int)(brg + 180.) % 360, 0x00B0);
11685 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11686 (
int)(varBrg + 180.) % 360, 0x00B0);
11687 infoArray.Add(routeInfo);
11693 s0.Append(_(
"Route") +
": ");
11695 s0.Append(_(
"Layer Route: "));
11698 if (!g_btouch) disp_length += dist;
11704 RouteLegInfo(dc, r_rband, infoArray);
11706 m_brepaint_piano =
true;
11709void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11710 if (!m_bShowVisibleSectors)
return;
11712 if (g_bDeferredInitDone) {
11714 double rhumbBearing, rhumbDist;
11715 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11716 &rhumbBearing, &rhumbDist);
11718 if (rhumbDist > 0.05)
11720 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11721 m_sectorlegsVisible);
11722 m_sector_glat =
gLat;
11723 m_sector_glon =
gLon;
11725 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11729void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11737void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11738 if (!ps52plib)
return;
11740 if (VPoint.b_quilt) {
11741 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11743 if (m_pQuilt->IsQuiltVector()) {
11744 if (ps52plib->GetStateHash() != m_s52StateHash) {
11746 m_s52StateHash = ps52plib->GetStateHash();
11750 if (ps52plib->GetStateHash() != m_s52StateHash) {
11752 m_s52StateHash = ps52plib->GetStateHash();
11757 bool bSendPlibState =
true;
11758 if (VPoint.b_quilt) {
11759 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11762 if (bSendPlibState) {
11764 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11765 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11766 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11767 v[
"OpenCPN Version Date"] = VERSION_DATE;
11768 v[
"OpenCPN Version Full"] = VERSION_FULL;
11771 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11772 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11773 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11774 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11775 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11776 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11777 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11781 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11782 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11786 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11787 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11788 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11789 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11790 ps52plib->m_bShowS57ImportantTextOnly;
11791 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11792 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11793 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11794 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11795 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11798 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11799 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11800 v[
"OpenCPN Scale Factor Exp"] =
11801 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11808 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11809 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11810 g_lastS52PLIBPluginMessage = out;
11817 wxPaintDC dc(
this);
11827 if (!m_b_paint_enable) {
11835 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11837 if (m_glcc && g_bopengl) {
11838 if (!s_in_update) {
11848 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11850 wxRegion ru = GetUpdateRegion();
11852 int rx, ry, rwidth, rheight;
11853 ru.GetBox(rx, ry, rwidth, rheight);
11855#ifdef ocpnUSE_DIBSECTION
11858 wxMemoryDC temp_dc;
11866 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11867 height += m_Piano->GetHeight();
11869 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11873 int thumbx, thumby, thumbsx, thumbsy;
11874 pthumbwin->GetPosition(&thumbx, &thumby);
11875 pthumbwin->GetSize(&thumbsx, &thumbsy);
11876 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11879 rgn_chart.Subtract(rgn_thumbwin);
11880 ru.Subtract(rgn_thumbwin);
11886 wxRegion rgn_blit = ru;
11887 if (g_bShowChartBar) {
11888 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11889 GetClientSize().x, m_Piano->GetHeight());
11892 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11893 if (style->chartStatusWindowTransparent)
11894 m_brepaint_piano =
true;
11896 ru.Subtract(chart_bar_rect);
11900 if (m_Compass && m_Compass->IsShown()) {
11901 wxRect compassRect = m_Compass->
GetRect();
11902 if (ru.Contains(compassRect) != wxOutRegion) {
11903 ru.Subtract(compassRect);
11907 if (m_notification_button) {
11908 wxRect noteRect = m_notification_button->
GetRect();
11909 if (ru.Contains(noteRect) != wxOutRegion) {
11910 ru.Subtract(noteRect);
11915 bool b_newview =
true;
11920 m_cache_vp.IsValid()) {
11926 bool b_rcache_ok =
false;
11927 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11928 b_rcache_ok = !b_newview;
11931 if (VPoint.b_MercatorProjectionOverride)
11932 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11946 if (b_rcache_ok) chart_get_region.Clear();
11949 if (VPoint.b_quilt)
11951 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11953 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11958 AbstractPlatform::ShowBusySpinner();
11962 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11963 (m_working_bm.GetHeight() != svp.
pix_height))
11967 if (fabs(VPoint.
rotation) < 0.01) {
11968 bool b_save =
true;
11973 m_cache_vp.Invalidate();
11987 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11992 int dy = c_new.y - c_old.y;
11993 int dx = c_new.x - c_old.x;
11998 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
12002 temp_dc.SelectObject(m_working_bm);
12004 wxMemoryDC cache_dc;
12005 cache_dc.SelectObject(m_cached_chart_bm);
12009 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
12012 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
12018 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
12021 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
12029 update_region.Union(
12032 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
12037 update_region.Union(
12040 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
12044 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12046 cache_dc.SelectObject(wxNullBitmap);
12050 temp_dc.SelectObject(m_cached_chart_bm);
12053 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
12057 temp_dc.SelectObject(m_working_bm);
12058 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12063 temp_dc.SelectObject(m_cached_chart_bm);
12068 temp_dc.SelectObject(m_working_bm);
12069 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12082 wxMemoryDC scratch_dc_0;
12083 scratch_dc_0.SelectObject(m_cached_chart_bm);
12086 scratch_dc_0.SelectObject(wxNullBitmap);
12095 temp_dc.SelectObject(m_working_bm);
12098 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12099 chart_get_all_region);
12102 AbstractPlatform::HideBusySpinner();
12108 if (!m_singleChart) {
12109 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12114 if (!chart_get_region.IsEmpty()) {
12115 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12119 if (temp_dc.IsOk()) {
12124 if (!VPoint.b_quilt) {
12127 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12128 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12135 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12136 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12139 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12141 temp_dc.DestroyClippingRegion();
12146 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12148 if (!backgroundRegion.IsEmpty()) {
12154 wxColour water = pWorldBackgroundChart->water;
12155 if (water.IsOk()) {
12156 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12157 temp_dc.SetBrush(wxBrush(water));
12159 while (upd.HaveRects()) {
12160 wxRect rect = upd.GetRect();
12161 temp_dc.DrawRectangle(rect);
12166 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12167 temp_dc.SetDeviceClippingRegion(*clip_region);
12168 delete clip_region;
12172 SetVPRotation(VPoint.
skew);
12181 wxMemoryDC *pChartDC = &temp_dc;
12182 wxMemoryDC rotd_dc;
12184 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12186 if (!b_rcache_ok) {
12188 wxMemoryDC tbase_dc;
12190 tbase_dc.SelectObject(bm_base);
12192 tbase_dc.SelectObject(wxNullBitmap);
12194 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12197 wxImage base_image;
12198 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12206 bool b_rot_ok =
false;
12207 if (base_image.IsOk()) {
12210 m_b_rot_hidef =
false;
12214 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12215 m_b_rot_hidef, &m_roffset);
12220 rot_vp.IsValid() && (ri.IsOk())) {
12227 m_prot_bm =
new wxBitmap(ri);
12230 m_roffset.x += VPoint.rv_rect.x;
12231 m_roffset.y += VPoint.rv_rect.y;
12234 if (m_prot_bm && m_prot_bm->IsOk()) {
12235 rotd_dc.SelectObject(*m_prot_bm);
12236 pChartDC = &rotd_dc;
12238 pChartDC = &temp_dc;
12239 m_roffset = wxPoint(0, 0);
12242 pChartDC = &temp_dc;
12243 m_roffset = wxPoint(0, 0);
12246 wxPoint offset = m_roffset;
12249 m_cache_vp = VPoint;
12252 wxMemoryDC mscratch_dc;
12253 mscratch_dc.SelectObject(*pscratch_bm);
12255 mscratch_dc.ResetBoundingBox();
12256 mscratch_dc.DestroyClippingRegion();
12257 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12260 wxRegionIterator upd(rgn_blit);
12262 wxRect rect = upd.GetRect();
12264 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12265 rect.x - offset.x, rect.y - offset.y);
12271 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12272 if (
this == wxWindow::FindFocus()) {
12275 wxColour colour = GetGlobalColor(
"BLUE4");
12276 mscratch_dc.SetPen(wxPen(colour));
12277 mscratch_dc.SetBrush(wxBrush(colour));
12279 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12280 mscratch_dc.DrawRectangle(activeRect);
12285 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12286 unsigned int im = stackIndexArray.size();
12287 if (VPoint.b_quilt && im > 0) {
12288 std::vector<int> tiles_to_show;
12289 for (
unsigned int is = 0; is < im; is++) {
12291 ChartData->GetChartTableEntry(stackIndexArray[is]);
12292 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12295 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12296 tiles_to_show.push_back(stackIndexArray[is]);
12300 if (tiles_to_show.size())
12301 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12307 ocpnDC scratch_dc(mscratch_dc);
12308 RenderAlertMessage(mscratch_dc, GetVP());
12314#ifdef ocpnUSE_DIBSECTION
12319 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12320 q_dc.SelectObject(qbm);
12323 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12326 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12327 q_dc.SetBrush(qbr);
12328 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12331 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12334 q_dc.SelectObject(wxNullBitmap);
12343 if( VPoint.b_quilt ) {
12344 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12345 ChartBase *chart = m_pQuilt->GetRefChart();
12346 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12351 ChPI->ClearPLIBTextList();
12354 ps52plib->ClearTextList();
12358 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12360 wxColor maskBackground = wxColour(1,0,0);
12361 t_dc.SelectObject( qbm );
12362 t_dc.SetBackground(wxBrush(maskBackground));
12366 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12369 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12370 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12373 wxRegionIterator upd_final( ru );
12374 while( upd_final ) {
12375 wxRect rect = upd_final.GetRect();
12376 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12380 t_dc.SelectObject( wxNullBitmap );
12386 if (VPoint.b_quilt) {
12387 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12388 ChartBase *chart = m_pQuilt->GetRefChart();
12389 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12393 ChPI->ClearPLIBTextList();
12395 if (ps52plib) ps52plib->ClearTextList();
12400 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12402 if (g_bShowChartBar && m_Piano) {
12403 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12404 GetVP().pix_width, m_Piano->GetHeight());
12407 if (!style->chartStatusWindowTransparent)
12408 chart_all_text_region.Subtract(chart_bar_rect);
12411 if (m_Compass && m_Compass->IsShown()) {
12412 wxRect compassRect = m_Compass->
GetRect();
12413 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12414 chart_all_text_region.Subtract(compassRect);
12418 mscratch_dc.DestroyClippingRegion();
12420 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12421 chart_all_text_region);
12427 ocpnDC scratch_dc(mscratch_dc);
12428 DrawOverlayObjects(scratch_dc, ru);
12431 wxRegionIterator upd_final(rgn_blit);
12432 while (upd_final) {
12433 wxRect rect = upd_final.GetRect();
12434 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12441 temp_dc.SelectObject(wxNullBitmap);
12443 mscratch_dc.SelectObject(wxNullBitmap);
12445 dc.DestroyClippingRegion();
12450void ChartCanvas::PaintCleanup() {
12452 if (m_inPinch)
return;
12463 m_bTCupdate =
false;
12467 WarpPointer(warp_x, warp_y);
12474 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12475 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12479wxColour GetErrorGraphicColor(
double val)
12498 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12499 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12500 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12501 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12502 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12503 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12504 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12505 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12506 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12507 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12508 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12509 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12510 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12511 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12512 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12513 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12514 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12515 else if( val >= 48) c.Set(
"#410000");
12520void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12523 gr_image.InitAlpha();
12525 double maxval = -10000;
12526 double minval = 10000;
12543 maxval = wxMax(maxval, (glat - rlat));
12544 minval = wxMin(minval, (glat - rlat));
12561 double f = ((glat - rlat)-minval)/(maxval - minval);
12563 double dy = (f * 40);
12565 wxColour c = GetErrorGraphicColor(dy);
12566 unsigned char r = c.Red();
12567 unsigned char g = c.Green();
12568 unsigned char b = c.Blue();
12570 gr_image.SetRGB(j, i, r,g,b);
12571 if((glat - rlat )!= 0)
12572 gr_image.SetAlpha(j, i, 128);
12574 gr_image.SetAlpha(j, i, 255);
12581 wxBitmap *pbm =
new wxBitmap(gr_image);
12582 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12583 pbm->SetMask(gr_mask);
12585 pmdc->DrawBitmap(*pbm, 0,0);
12593void ChartCanvas::CancelMouseRoute() {
12595 m_pMouseRoute = NULL;
12596 m_bDrawingRoute =
false;
12599int ChartCanvas::GetNextContextMenuId() {
12600 return CanvasMenuHandler::GetNextContextMenuId();
12603bool ChartCanvas::SetCursor(
const wxCursor &c) {
12605 if (g_bopengl && m_glcc)
12606 return m_glcc->SetCursor(c);
12609 return wxWindow::SetCursor(c);
12612void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12613 if (g_bquiting)
return;
12623 if (!m_RolloverPopupTimer.IsRunning() &&
12624 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12625 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12626 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12627 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12630 if (m_glcc && g_bopengl) {
12633 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12635 m_glcc->Refresh(eraseBackground,
12652 if (m_pCIWin && m_pCIWin->IsShown()) {
12654 m_pCIWin->Refresh(
false);
12662 wxWindow::Refresh(eraseBackground, rect);
12665void ChartCanvas::Update() {
12666 if (m_glcc && g_bopengl) {
12671 wxWindow::Update();
12675 if (!pemboss)
return;
12676 int x = pemboss->x, y = pemboss->y;
12677 const double factor = 200;
12679 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12680 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12681 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12684 wxMemoryDC snip_dc;
12685 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12686 snip_dc.SelectObject(snip_bmp);
12688 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12689 snip_dc.SelectObject(wxNullBitmap);
12691 wxImage snip_img = snip_bmp.ConvertToImage();
12694 unsigned char *pdata = snip_img.GetData();
12696 for (
int y = 0; y < pemboss->height; y++) {
12697 int map_index = (y * pemboss->width);
12698 for (
int x = 0; x < pemboss->width; x++) {
12699 double val = (pemboss->pmap[map_index] * factor) / 256.;
12701 int nred = (int)((*pdata) + val);
12702 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12703 *pdata++ = (
unsigned char)nred;
12705 int ngreen = (int)((*pdata) + val);
12706 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12707 *pdata++ = (
unsigned char)ngreen;
12709 int nblue = (int)((*pdata) + val);
12710 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12711 *pdata++ = (
unsigned char)nblue;
12719 wxBitmap emb_bmp(snip_img);
12722 wxMemoryDC result_dc;
12723 result_dc.SelectObject(emb_bmp);
12726 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12728 result_dc.SelectObject(wxNullBitmap);
12734 if (GetQuiltMode()) {
12736 int refIndex = GetQuiltRefChartdbIndex();
12737 if (refIndex >= 0) {
12739 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12740 if (current_type == CHART_TYPE_MBTILES) {
12741 ChartBase *pChart = m_pQuilt->GetRefChart();
12744 zoom_factor = ptc->GetZoomFactor();
12749 if (zoom_factor <= 3.9)
return NULL;
12751 if (m_singleChart) {
12752 if (zoom_factor <= 3.9)
return NULL;
12757 if (m_pEM_OverZoom) {
12758 m_pEM_OverZoom->x = 4;
12759 m_pEM_OverZoom->y = 0;
12761 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12762 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12765 return m_pEM_OverZoom;
12768void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12781 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12782 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12786 AISDrawAreaNotices(dc, GetVP(),
this);
12788 wxDC *pdc = dc.GetDC();
12790 pdc->DestroyClippingRegion();
12791 wxDCClipper(*pdc, ru);
12794 if (m_bShowNavobjects) {
12795 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12796 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12797 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12798 DrawAnchorWatchPoints(dc);
12800 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12801 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12804 AISDraw(dc, GetVP(),
this);
12808 RenderVisibleSectorLights(dc);
12810 RenderAllChartOutlines(dc, GetVP());
12811 RenderRouteLegs(dc);
12812 RenderShipToActive(dc,
false);
12814 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12816 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12820 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12821 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12824 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12829 RebuildTideSelectList(GetVP().GetBBox());
12830 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12833 if (m_bShowCurrent) {
12834 RebuildCurrentSelectList(GetVP().GetBBox());
12835 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12838 if (!g_PrintingInProgress) {
12839 if (IsPrimaryCanvas()) {
12843 if (IsPrimaryCanvas()) {
12847 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12849 if (m_pTrackRolloverWin) {
12850 m_pTrackRolloverWin->Draw(dc);
12851 m_brepaint_piano =
true;
12854 if (m_pRouteRolloverWin) {
12855 m_pRouteRolloverWin->Draw(dc);
12856 m_brepaint_piano =
true;
12859 if (m_pAISRolloverWin) {
12860 m_pAISRolloverWin->Draw(dc);
12861 m_brepaint_piano =
true;
12863 if (m_brepaint_piano && g_bShowChartBar) {
12864 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12867 if (m_Compass) m_Compass->Paint(dc);
12869 if (!g_CanvasHideNotificationIcon) {
12870 if (IsPrimaryCanvas()) {
12871 auto ¬eman = NotificationManager::GetInstance();
12872 if (noteman.GetNotificationCount()) {
12873 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12874 if (m_notification_button->UpdateStatus()) Refresh();
12875 m_notification_button->Show(
true);
12876 m_notification_button->Paint(dc);
12878 m_notification_button->Show(
false);
12884 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12890 if (!m_bShowDepthUnits)
return NULL;
12892 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12894 if (GetQuiltMode()) {
12895 wxString s = m_pQuilt->GetQuiltDepthUnit();
12898 depth_unit_type = DEPTH_UNIT_FEET;
12899 else if (s.StartsWith(
"FATHOMS"))
12900 depth_unit_type = DEPTH_UNIT_FATHOMS;
12901 else if (s.StartsWith(
"METERS"))
12902 depth_unit_type = DEPTH_UNIT_METERS;
12903 else if (s.StartsWith(
"METRES"))
12904 depth_unit_type = DEPTH_UNIT_METERS;
12905 else if (s.StartsWith(
"METRIC"))
12906 depth_unit_type = DEPTH_UNIT_METERS;
12907 else if (s.StartsWith(
"METER"))
12908 depth_unit_type = DEPTH_UNIT_METERS;
12911 if (m_singleChart) {
12912 depth_unit_type = m_singleChart->GetDepthUnitType();
12913 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12914 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12919 switch (depth_unit_type) {
12920 case DEPTH_UNIT_FEET:
12923 case DEPTH_UNIT_METERS:
12924 ped = m_pEM_Meters;
12926 case DEPTH_UNIT_FATHOMS:
12927 ped = m_pEM_Fathoms;
12933 ped->x = (GetVP().
pix_width - ped->width);
12935 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12936 wxRect r = m_Compass->
GetRect();
12937 ped->y = r.y + r.height;
12944void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12947 if (style->embossFont == wxEmptyString) {
12948 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12950 font.SetPointSize(60);
12951 font.SetWeight(wxFONTWEIGHT_BOLD);
12953 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12954 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12956 int emboss_width = 500;
12957 int emboss_height = 200;
12961 delete m_pEM_Meters;
12962 delete m_pEM_Fathoms;
12966 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12968 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12970 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12973#define OVERZOOM_TEXT _("OverZoom")
12975void ChartCanvas::SetOverzoomFont() {
12980 if (style->embossFont == wxEmptyString) {
12981 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12983 font.SetPointSize(40);
12984 font.SetWeight(wxFONTWEIGHT_BOLD);
12986 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12987 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12989 wxClientDC dc(
this);
12991 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12993 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12994 font.SetPointSize(font.GetPointSize() - 1);
12996 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12998 m_overzoomFont = font;
12999 m_overzoomTextWidth = w;
13000 m_overzoomTextHeight = h;
13003void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
13004 delete m_pEM_OverZoom;
13006 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
13008 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
13009 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
13012emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
13013 int height,
const wxString &str,
13018 wxBitmap bmp(width, height, -1);
13021 wxMemoryDC temp_dc;
13022 temp_dc.SelectObject(bmp);
13025 temp_dc.SetBackground(*wxWHITE_BRUSH);
13026 temp_dc.SetTextBackground(*wxWHITE);
13027 temp_dc.SetTextForeground(*wxBLACK);
13031 temp_dc.SetFont(font);
13034 temp_dc.GetTextExtent(str, &str_w, &str_h);
13036 temp_dc.DrawText(str, 1, 1);
13039 temp_dc.SelectObject(wxNullBitmap);
13042 wxImage img = bmp.ConvertToImage();
13044 int image_width = str_w * 105 / 100;
13045 int image_height = str_h * 105 / 100;
13046 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
13047 wxMin(image_height, img.GetHeight()));
13048 wxImage imgs = img.GetSubImage(r);
13052 case GLOBAL_COLOR_SCHEME_DAY:
13056 case GLOBAL_COLOR_SCHEME_DUSK:
13059 case GLOBAL_COLOR_SCHEME_NIGHT:
13066 const int w = imgs.GetWidth();
13067 const int h = imgs.GetHeight();
13068 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13073 for (
int y = 1; y < h - 1; y++) {
13074 for (
int x = 1; x < w - 1; x++) {
13076 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13077 val = (int)(val * val_factor);
13078 index = (y * w) + x;
13091void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13092 Track *active_track = NULL;
13095 active_track = pTrackDraw;
13099 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13102 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13105void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13106 Track *active_track = NULL;
13109 active_track = pTrackDraw;
13113 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13116void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13117 Route *active_route = NULL;
13119 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13120 active_route = pRouteDraw;
13125 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13130 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13133void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13134 Route *active_route = NULL;
13137 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13138 active_route = pRouteDraw;
13142 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13145void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13146 if (!pWayPointMan)
return;
13148 auto node = pWayPointMan->GetWaypointList()->begin();
13150 while (node != pWayPointMan->GetWaypointList()->end()) {
13159 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13163 if (pWP->GetShowWaypointRangeRings() &&
13164 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13165 double factor = 1.00;
13166 if (pWP->GetWaypointRangeRingsStepUnits() ==
13168 factor = 1 / 1.852;
13170 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13171 pWP->GetWaypointRangeRingsStep() / 60.;
13175 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13176 pWP->m_lat + radius, pWP->m_lon + radius);
13177 if (!BltBBox.IntersectOut(radar_box)) {
13188void ChartCanvas::DrawBlinkObjects() {
13190 wxRect update_rect;
13192 if (!pWayPointMan)
return;
13194 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13201 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13204void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13209 wxPoint lAnchorPoint1, lAnchorPoint2;
13223 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13224 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13226 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13227 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13228 dc.SetBrush(*ppBrush);
13232 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13237 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13242 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13247 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13252double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13255 wxPoint lAnchorPoint;
13258 double tlat1, tlon1;
13260 if (pAnchorWatchPoint) {
13261 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13262 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13263 dabs = fabs(d1 / 1852.);
13264 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13269 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13270 pow((
double)(lAnchorPoint.y - r1.y), 2));
13273 if (d1 < 0) lpp = -lpp;
13281void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13284 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13286 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13292 if ((type ==
't') || (type ==
'T')) {
13293 if (BBox.Contains(lat, lon)) {
13295 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13301void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13304 wxDateTime this_now = gTimeSource;
13305 bool cur_time = !gTimeSource.IsValid();
13306 if (cur_time) this_now = wxDateTime::Now();
13307 time_t t_this_now = this_now.GetTicks();
13309 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13311 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13312 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13313 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13314 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13316 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13317 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13318 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13319 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13320 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13321 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13323 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13324 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13325 int font_size = wxMax(10, dFont->GetPointSize());
13328 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13329 false, dFont->GetFaceName());
13331 dc.SetPen(*pblack_pen);
13332 dc.SetBrush(*pgreen_brush);
13336 case GLOBAL_COLOR_SCHEME_DAY:
13339 case GLOBAL_COLOR_SCHEME_DUSK:
13342 case GLOBAL_COLOR_SCHEME_NIGHT:
13343 bm = m_bmTideNight;
13350 int bmw = bm.GetWidth();
13351 int bmh = bm.GetHeight();
13353 float scale_factor = 1.0;
13357 float icon_pixelRefDim = 45;
13362 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13364 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13366 scale_factor *= pix_factor;
13373 scale_factor *= user_scale_factor;
13374 scale_factor *= GetContentScaleFactor();
13377 double marge = 0.05;
13378 std::vector<LLBBox> drawn_boxes;
13379 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13383 if ((type ==
't') || (type ==
'T'))
13388 if (BBox.ContainsMarge(lat, lon, marge)) {
13390 if (GetVP().chart_scale < 500000) {
13391 bool bdrawn =
false;
13392 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13393 if (drawn_boxes[i].Contains(lat, lon)) {
13398 if (bdrawn)
continue;
13401 this_box.Set(lat, lon, lat, lon);
13402 this_box.EnLarge(.005);
13403 drawn_boxes.push_back(this_box);
13409 if (GetVP().chart_scale > 500000) {
13410 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13414 dc.SetFont(*plabelFont);
13426 if (
ptcmgr->GetTideFlowSens(
13427 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13431 ptcmgr->GetHightOrLowTide(
13432 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13433 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13445 if (tctime > t_this_now)
13446 ptcmgr->GetHightOrLowTide(
13447 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13448 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13452 ptcmgr->GetHightOrLowTide(
13453 t_this_now, FORWARD_TEN_MINUTES_STEP,
13454 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13468 int width = (int)(12 * scale_factor + 0.5);
13469 int height = (int)(45 * scale_factor + 0.5);
13470 int linew = wxMax(1, (
int)(scale_factor));
13471 int xDraw = r.x - (width / 2);
13472 int yDraw = r.y - (height / 2);
13475 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13476 int hs = (httime > lttime) ? -4 : 4;
13477 hs *= (int)(scale_factor + 0.5);
13478 if (ts > 0.995 || ts < 0.005) hs = 0;
13479 int ht_y = (int)(height * ts);
13482 pblack_pen->SetWidth(linew);
13483 dc.SetPen(*pblack_pen);
13484 dc.SetBrush(*pyelo_brush);
13485 dc.DrawRectangle(xDraw, yDraw, width, height);
13489 dc.SetPen(*pblue_pen);
13490 dc.SetBrush(*pblue_brush);
13491 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13492 (width - (4 * linew)), height - ht_y);
13498 arrow[0].x = xDraw + 2 * linew;
13499 arrow[1].x = xDraw + width / 2;
13500 arrow[2].x = xDraw + width - 2 * linew;
13501 pyelo_pen->SetWidth(linew);
13502 pblue_pen->SetWidth(linew);
13503 if (ts > 0.35 || ts < 0.15)
13505 hl = (int)(height * 0.25) + yDraw;
13507 arrow[1].y = hl + hs;
13510 dc.SetPen(*pyelo_pen);
13512 dc.SetPen(*pblue_pen);
13513 dc.DrawLines(3, arrow);
13515 if (ts > 0.60 || ts < 0.40)
13517 hl = (int)(height * 0.5) + yDraw;
13519 arrow[1].y = hl + hs;
13522 dc.SetPen(*pyelo_pen);
13524 dc.SetPen(*pblue_pen);
13525 dc.DrawLines(3, arrow);
13527 if (ts < 0.65 || ts > 0.85)
13529 hl = (int)(height * 0.75) + yDraw;
13531 arrow[1].y = hl + hs;
13534 dc.SetPen(*pyelo_pen);
13536 dc.SetPen(*pblue_pen);
13537 dc.DrawLines(3, arrow);
13541 s.Printf(
"%3.1f", nowlev);
13543 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13545 dc.GetTextExtent(s, &wx1, NULL);
13547 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13562void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13565 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13567 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13573 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13574 if ((BBox.Contains(lat, lon))) {
13576 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13582void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13585 float tcvalue, dir;
13589 double lon_last = 0.;
13590 double lat_last = 0.;
13592 double marge = 0.2;
13593 bool cur_time = !gTimeSource.IsValid();
13595 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13596 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13598 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13600 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13601 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13602 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13603 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13604 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13605 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13606 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13607 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13609 double skew_angle = GetVPRotation();
13611 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13612 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13613 int font_size = wxMax(10, dFont->GetPointSize());
13616 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13617 false, dFont->GetFaceName());
13619 float scale_factor = 1.0;
13625 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13627 float nominal_icon_size_pixels = 15;
13628 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13630 scale_factor *= pix_factor;
13637 scale_factor *= user_scale_factor;
13639 scale_factor *= GetContentScaleFactor();
13642 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13648 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13649 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13654 int dd = (int)(5.0 * scale_factor + 0.5);
13665 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13666 dc.SetPen(*pblack_pen);
13667 dc.SetBrush(*porange_brush);
13668 dc.DrawPolygon(4, d);
13671 dc.SetBrush(*pblack_brush);
13672 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13676 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13690 double a1 = fabs(tcvalue) * 10.;
13692 a1 = wxMax(1.0, a1);
13693 double a2 = log10(a1);
13695 float cscale = scale_factor * a2 * 0.3;
13697 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13698 dc.SetPen(*porange_pen);
13699 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13703 if (bDrawCurrentValues) {
13704 dc.SetFont(*pTCFont);
13705 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13706 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13732 if (!pvIDX)
return;
13737 if (pCwin && pCwin->IsShown()) {
13745 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13760 pCwin =
new TCWin(
this, x, y, pvIDX);
13778#define NUM_CURRENT_ARROW_POINTS 9
13779static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13780 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13781 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13782 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13784void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13786 if (
scale > 1e-2) {
13787 float sin_rot = sin(rot_angle * PI / 180.);
13788 float cos_rot = cos(rot_angle * PI / 180.);
13792 float xt = CurrentArrowArray[0].x;
13793 float yt = CurrentArrowArray[0].y;
13795 float xp = (xt * cos_rot) - (yt * sin_rot);
13796 float yp = (xt * sin_rot) + (yt * cos_rot);
13797 int x1 = (int)(xp *
scale);
13798 int y1 = (int)(yp *
scale);
13801 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13802 xt = CurrentArrowArray[ip].x;
13803 yt = CurrentArrowArray[ip].y;
13805 float xp = (xt * cos_rot) - (yt * sin_rot);
13806 float yp = (xt * sin_rot) + (yt * cos_rot);
13807 int x2 = (int)(xp *
scale);
13808 int y2 = (int)(yp *
scale);
13810 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13818wxString ChartCanvas::FindValidUploadPort() {
13821 if (!g_uploadConnection.IsEmpty() &&
13822 g_uploadConnection.StartsWith(
"Serial")) {
13823 port = g_uploadConnection;
13829 for (
auto *cp : TheConnectionParams()) {
13830 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13831 port <<
"Serial:" << cp->Port;
13837void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13840 if (NULL == g_pais_query_dialog_active) {
13841 int pos_x = g_ais_query_dialog_x;
13842 int pos_y = g_ais_query_dialog_y;
13844 if (g_pais_query_dialog_active) {
13845 g_pais_query_dialog_active->Destroy();
13851 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13852 wxPoint(pos_x, pos_y));
13854 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13855 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13856 g_pais_query_dialog_active->SetMMSI(mmsi);
13857 g_pais_query_dialog_active->UpdateText();
13858 wxSize sz = g_pais_query_dialog_active->GetSize();
13860 bool b_reset_pos =
false;
13865 RECT frame_title_rect;
13866 frame_title_rect.left = pos_x;
13867 frame_title_rect.top = pos_y;
13868 frame_title_rect.right = pos_x + sz.x;
13869 frame_title_rect.bottom = pos_y + 30;
13871 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13872 b_reset_pos =
true;
13877 wxRect window_title_rect;
13878 window_title_rect.x = pos_x;
13879 window_title_rect.y = pos_y;
13880 window_title_rect.width = sz.x;
13881 window_title_rect.height = 30;
13883 wxRect ClientRect = wxGetClientDisplayRect();
13884 ClientRect.Deflate(
13886 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13890 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13893 g_pais_query_dialog_active->SetMMSI(mmsi);
13894 g_pais_query_dialog_active->UpdateText();
13897 g_pais_query_dialog_active->Show();
13900void ChartCanvas::ToggleCanvasQuiltMode() {
13901 bool cur_mode = GetQuiltMode();
13903 if (!GetQuiltMode())
13904 SetQuiltMode(
true);
13905 else if (GetQuiltMode()) {
13906 SetQuiltMode(
false);
13907 g_sticky_chart = GetQuiltReferenceChartIndex();
13910 if (cur_mode != GetQuiltMode()) {
13911 SetupCanvasQuiltMode();
13920 if (ps52plib) ps52plib->GenerateStateHash();
13922 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13923 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13926void ChartCanvas::DoCanvasStackDelta(
int direction) {
13927 if (!GetQuiltMode()) {
13928 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13929 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13930 if ((current_stack_index + direction) < 0)
return;
13932 if (m_bpersistent_quilt ) {
13934 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13936 if (IsChartQuiltableRef(new_dbIndex)) {
13937 ToggleCanvasQuiltMode();
13938 SelectQuiltRefdbChart(new_dbIndex);
13939 m_bpersistent_quilt =
false;
13942 SelectChartFromStack(current_stack_index + direction);
13945 std::vector<int> piano_chart_index_array =
13946 GetQuiltExtendedStackdbIndexArray();
13947 int refdb = GetQuiltRefChartdbIndex();
13950 int current_index = -1;
13951 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13952 if (refdb == piano_chart_index_array[i]) {
13957 if (current_index == -1)
return;
13960 int target_family = ctet.GetChartFamily();
13962 int new_index = -1;
13963 int check_index = current_index + direction;
13964 bool found =
false;
13965 int check_dbIndex = -1;
13966 int new_dbIndex = -1;
13970 (
unsigned int)check_index < piano_chart_index_array.size() &&
13971 (check_index >= 0)) {
13972 check_dbIndex = piano_chart_index_array[check_index];
13974 if (target_family == cte.GetChartFamily()) {
13976 new_index = check_index;
13977 new_dbIndex = check_dbIndex;
13981 check_index += direction;
13984 if (!found)
return;
13986 if (!IsChartQuiltableRef(new_dbIndex)) {
13987 ToggleCanvasQuiltMode();
13988 SelectdbChart(new_dbIndex);
13989 m_bpersistent_quilt =
true;
13991 SelectQuiltRefChart(new_index);
13995 gFrame->UpdateGlobalMenuItems();
13997 SetQuiltChartHiLiteIndex(-1);
14008void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
14011 switch (event.GetId()) {
14023 DoCanvasStackDelta(1);
14028 DoCanvasStackDelta(-1);
14038 ShowCurrents(!GetbShowCurrent());
14045 ShowTides(!GetbShowTide());
14052 if (0 == m_routeState) {
14059 androidSetRouteAnnunciator(m_routeState == 1);
14065 SetAISCanvasDisplayStyle(-1);
14077void ChartCanvas::SetShowAIS(
bool show) {
14079 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14080 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14083void ChartCanvas::SetAttenAIS(
bool show) {
14084 m_bShowAISScaled = show;
14085 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14086 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14089void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14092 bool bShowAIS_Array[3] = {
true,
true,
false};
14093 bool bShowScaled_Array[3] = {
false,
true,
true};
14094 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14095 _(
"Attenuate less critical AIS targets"),
14096 _(
"Hide AIS Targets")};
14097 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14099 int AIS_Toolbar_Switch = 0;
14100 if (StyleIndx == -1) {
14102 for (
int i = 1; i < ArraySize; i++) {
14103 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14104 (bShowScaled_Array[i] == m_bShowAISScaled))
14105 AIS_Toolbar_Switch = i;
14107 AIS_Toolbar_Switch++;
14108 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14109 AIS_Toolbar_Switch++;
14112 AIS_Toolbar_Switch = StyleIndx;
14115 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14117 int AIS_Toolbar_Switch_Next =
14118 AIS_Toolbar_Switch + 1;
14119 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14120 AIS_Toolbar_Switch_Next++;
14121 if (AIS_Toolbar_Switch_Next >= ArraySize)
14122 AIS_Toolbar_Switch_Next = 0;
14125 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14126 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14129void ChartCanvas::TouchAISToolActive() {}
14131void ChartCanvas::UpdateAISTBTool() {}
14139void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14141 bool b_update =
false;
14142 int cc1_edge_comp = 2;
14143 wxRect rect = m_Compass->
GetRect();
14144 wxSize parent_size = GetSize();
14146 parent_size *= m_displayScale;
14150 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14151 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14152 wxRect compass_rect(compass_pt, rect.GetSize());
14154 m_Compass->Move(compass_pt);
14156 if (m_Compass && m_Compass->IsShown())
14157 m_Compass->UpdateStatus(b_force_new | b_update);
14159 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14160 scaler = wxMax(scaler, 1.0);
14161 wxPoint note_point = wxPoint(
14162 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14163 if (m_notification_button) {
14164 m_notification_button->Move(note_point);
14165 m_notification_button->UpdateStatus();
14168 if (b_force_new | b_update) Refresh();
14171void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14172 ChartTypeEnum New_Type,
14173 ChartFamilyEnum New_Family) {
14174 if (!GetpCurrentStack())
return;
14177 if (index < GetpCurrentStack()->nEntry) {
14180 pTentative_Chart =
ChartData->OpenStackChartConditional(
14181 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14183 if (pTentative_Chart) {
14184 if (m_singleChart) m_singleChart->Deactivate();
14186 m_singleChart = pTentative_Chart;
14187 m_singleChart->Activate();
14189 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14190 GetpCurrentStack(), m_singleChart->GetFullPath());
14203 double best_scale_ppm = GetBestVPScale(m_singleChart);
14204 double rotation = GetVPRotation();
14205 double oldskew = GetVPSkew();
14206 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14208 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14209 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14210 if (fabs(newskew) > 0.0001) rotation = newskew;
14213 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14215 UpdateGPSCompassStatusBox(
true);
14219 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14220 if (idx < 0)
return;
14222 std::vector<int> piano_active_chart_index_array;
14223 piano_active_chart_index_array.push_back(
14224 GetpCurrentStack()->GetCurrentEntrydbIndex());
14225 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14228void ChartCanvas::SelectdbChart(
int dbindex) {
14229 if (!GetpCurrentStack())
return;
14232 if (dbindex >= 0) {
14235 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14237 if (pTentative_Chart) {
14238 if (m_singleChart) m_singleChart->Deactivate();
14240 m_singleChart = pTentative_Chart;
14241 m_singleChart->Activate();
14243 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14244 GetpCurrentStack(), m_singleChart->GetFullPath());
14257 double best_scale_ppm = GetBestVPScale(m_singleChart);
14261 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14271void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14274 if (!GetQuiltMode()) {
14275 if (GetpCurrentStack()) {
14276 int stack_index = -1;
14277 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14278 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14279 if (check_dbIndex < 0)
continue;
14281 ChartData->GetChartTableEntry(check_dbIndex);
14282 if (type == cte.GetChartType()) {
14285 }
else if (family == cte.GetChartFamily()) {
14291 if (stack_index >= 0) {
14292 SelectChartFromStack(stack_index);
14296 int sel_dbIndex = -1;
14297 std::vector<int> piano_chart_index_array =
14298 GetQuiltExtendedStackdbIndexArray();
14299 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14300 int check_dbIndex = piano_chart_index_array[i];
14302 if (type == cte.GetChartType()) {
14303 if (IsChartQuiltableRef(check_dbIndex)) {
14304 sel_dbIndex = check_dbIndex;
14307 }
else if (family == cte.GetChartFamily()) {
14308 if (IsChartQuiltableRef(check_dbIndex)) {
14309 sel_dbIndex = check_dbIndex;
14315 if (sel_dbIndex >= 0) {
14316 SelectQuiltRefdbChart(sel_dbIndex,
false);
14318 AdjustQuiltRefChart();
14325 SetQuiltChartHiLiteIndex(-1);
14330bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14331 return std::find(m_tile_yesshow_index_array.begin(),
14332 m_tile_yesshow_index_array.end(),
14333 index) != m_tile_yesshow_index_array.end();
14336bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14337 return std::find(m_tile_noshow_index_array.begin(),
14338 m_tile_noshow_index_array.end(),
14339 index) != m_tile_noshow_index_array.end();
14342void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14343 if (std::find(m_tile_noshow_index_array.begin(),
14344 m_tile_noshow_index_array.end(),
14345 index) == m_tile_noshow_index_array.end()) {
14346 m_tile_noshow_index_array.push_back(index);
14356void ChartCanvas::HandlePianoClick(
14357 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14360 if (!m_pCurrentStack)
return;
14376 double distance = 25000;
14377 int closest_index = -1;
14378 for (
int chart_index : selected_dbIndex_array) {
14380 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14381 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14384 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14385 if (test_distance < distance) {
14386 distance = test_distance;
14387 closest_index = chart_index;
14391 int selected_dbIndex = selected_dbIndex_array[0];
14392 if (closest_index >= 0) selected_dbIndex = closest_index;
14394 if (!GetQuiltMode()) {
14395 if (m_bpersistent_quilt ) {
14396 if (IsChartQuiltableRef(selected_dbIndex)) {
14397 ToggleCanvasQuiltMode();
14398 SelectQuiltRefdbChart(selected_dbIndex);
14399 m_bpersistent_quilt =
false;
14401 SelectChartFromStack(selected_index);
14404 SelectChartFromStack(selected_index);
14405 g_sticky_chart = selected_dbIndex;
14409 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14413 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14414 bool bfound =
false;
14415 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14416 if (m_tile_noshow_index_array[i] ==
14417 selected_dbIndex) {
14418 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14425 m_tile_noshow_index_array.push_back(selected_dbIndex);
14429 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14430 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14434 if (IsChartQuiltableRef(selected_dbIndex)) {
14440 bool set_scale =
false;
14441 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14442 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14448 SelectQuiltRefdbChart(selected_dbIndex,
true);
14450 SelectQuiltRefdbChart(selected_dbIndex,
false);
14455 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14457 double proposed_scale_onscreen =
14460 if (g_bPreserveScaleOnX) {
14461 proposed_scale_onscreen =
14462 wxMin(proposed_scale_onscreen,
14464 GetCanvasWidth()));
14466 proposed_scale_onscreen =
14467 wxMin(proposed_scale_onscreen,
14469 GetCanvasWidth()));
14471 proposed_scale_onscreen =
14472 wxMax(proposed_scale_onscreen,
14481 ToggleCanvasQuiltMode();
14482 SelectdbChart(selected_dbIndex);
14483 m_bpersistent_quilt =
true;
14488 SetQuiltChartHiLiteIndex(-1);
14489 gFrame->UpdateGlobalMenuItems();
14491 HideChartInfoWindow();
14496void ChartCanvas::HandlePianoRClick(
14497 int x,
int y,
int selected_index,
14498 const std::vector<int> &selected_dbIndex_array) {
14501 if (!GetpCurrentStack())
return;
14503 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14504 UpdateCanvasControlBar();
14506 SetQuiltChartHiLiteIndex(-1);
14509void ChartCanvas::HandlePianoRollover(
14510 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14511 int n_charts,
int scale) {
14514 if (!GetpCurrentStack())
return;
14519 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14521 if (!GetQuiltMode()) {
14522 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14525 std::vector<int> piano_chart_index_array;
14526 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14527 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14528 if ((GetpCurrentStack()->nEntry > 1) ||
14529 (piano_chart_index_array.size() >= 1)) {
14530 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14532 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14534 }
else if (GetpCurrentStack()->nEntry == 1) {
14536 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14537 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14538 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14540 }
else if ((-1 == selected_index) &&
14541 (0 == selected_dbIndex_array.size())) {
14542 ShowChartInfoWindow(key_location.x, -1);
14546 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14548 if ((GetpCurrentStack()->nEntry > 1) ||
14549 (piano_chart_index_array.size() >= 1)) {
14551 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14552 selected_dbIndex_array);
14553 else if (n_charts == 1)
14554 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14556 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14563void ChartCanvas::ClearPianoRollover() {
14564 ClearQuiltChartHiLiteIndexArray();
14565 ShowChartInfoWindow(0, -1);
14566 std::vector<int> vec;
14567 ShowCompositeInfoWindow(0, 0, 0, vec);
14571void ChartCanvas::UpdateCanvasControlBar() {
14572 if (m_pianoFrozen)
return;
14574 if (!GetpCurrentStack())
return;
14576 if (!g_bShowChartBar)
return;
14579 int sel_family = -1;
14581 std::vector<int> piano_chart_index_array;
14582 std::vector<int> empty_piano_chart_index_array;
14584 wxString old_hash = m_Piano->GetStoredHash();
14586 if (GetQuiltMode()) {
14587 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14588 GetQuiltFullScreendbIndexArray());
14590 std::vector<int> piano_active_chart_index_array =
14591 GetQuiltCandidatedbIndexArray();
14592 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14594 std::vector<int> piano_eclipsed_chart_index_array =
14595 GetQuiltEclipsedStackdbIndexArray();
14596 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14598 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14599 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14601 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14602 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14604 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14605 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14608 if (m_singleChart) {
14609 sel_type = m_singleChart->GetChartType();
14610 sel_family = m_singleChart->GetChartFamily();
14615 std::vector<int> piano_skew_chart_index_array;
14616 std::vector<int> piano_tmerc_chart_index_array;
14617 std::vector<int> piano_poly_chart_index_array;
14619 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14621 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14622 double skew_norm = ctei.GetChartSkew();
14623 if (skew_norm > 180.) skew_norm -= 360.;
14625 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14626 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14629 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14630 if (fabs(skew_norm) > 1.)
14631 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14633 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14634 }
else if (fabs(skew_norm) > 1.)
14635 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14637 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14638 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14639 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14641 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14642 if (new_hash != old_hash) {
14643 m_Piano->FormatKeys();
14644 HideChartInfoWindow();
14645 m_Piano->ResetRollover();
14646 SetQuiltChartHiLiteIndex(-1);
14647 m_brepaint_piano =
true;
14653 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14655 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14656 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14657 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14658 if (e == CHART_FAMILY_RASTER) mask |= 1;
14659 if (e == CHART_FAMILY_VECTOR) {
14660 if (t == CHART_TYPE_CM93COMP)
14667 wxString s_indicated;
14668 if (sel_type == CHART_TYPE_CM93COMP)
14669 s_indicated =
"cm93";
14671 if (sel_family == CHART_FAMILY_RASTER)
14672 s_indicated =
"raster";
14673 else if (sel_family == CHART_FAMILY_VECTOR)
14674 s_indicated =
"vector";
14677 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14680void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14682void ChartCanvas::PianoPopupMenu(
14683 int x,
int y,
int selected_index,
14684 const std::vector<int> &selected_dbIndex_array) {
14685 if (!GetpCurrentStack())
return;
14688 if (!GetQuiltMode())
return;
14690 m_piano_ctx_menu =
new wxMenu();
14692 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14702 menu_selected_dbIndex = selected_dbIndex_array[0];
14703 menu_selected_index = selected_index;
14706 bool b_is_in_noshow =
false;
14707 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14708 if (m_quilt_noshow_index_array[i] ==
14709 menu_selected_dbIndex)
14711 b_is_in_noshow =
true;
14716 if (b_is_in_noshow) {
14717 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14718 _(
"Show This Chart"));
14719 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14720 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14721 }
else if (GetpCurrentStack()->nEntry > 1) {
14722 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14723 _(
"Hide This Chart"));
14724 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14725 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14729 wxPoint pos = wxPoint(x, y - 30);
14732 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14733 PopupMenu(m_piano_ctx_menu, pos);
14735 delete m_piano_ctx_menu;
14736 m_piano_ctx_menu = NULL;
14738 HideChartInfoWindow();
14739 m_Piano->ResetRollover();
14741 SetQuiltChartHiLiteIndex(-1);
14742 ClearQuiltChartHiLiteIndexArray();
14747void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14748 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14749 if (m_quilt_noshow_index_array[i] ==
14750 menu_selected_dbIndex)
14752 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14758void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14759 if (!GetpCurrentStack())
return;
14762 RemoveChartFromQuilt(menu_selected_dbIndex);
14766 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14767 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14769 int i = menu_selected_index + 1;
14770 bool b_success =
false;
14771 while (i < GetpCurrentStack()->nEntry - 1) {
14772 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14773 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14774 SelectQuiltRefChart(i);
14784 i = menu_selected_index - 1;
14786 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14787 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14788 SelectQuiltRefChart(i);
14798void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14800 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14801 if (m_quilt_noshow_index_array[i] ==
14804 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14809 m_quilt_noshow_index_array.push_back(dbIndex);
14812bool ChartCanvas::UpdateS52State() {
14813 bool retval =
false;
14816 ps52plib->SetShowS57Text(m_encShowText);
14817 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14818 ps52plib->m_bShowSoundg = m_encShowDepth;
14819 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14820 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14823 if (!m_encShowLights)
14824 ps52plib->AddObjNoshow(
"LIGHTS");
14826 ps52plib->RemoveObjNoshow(
"LIGHTS");
14827 ps52plib->SetLightsOff(!m_encShowLights);
14828 ps52plib->m_bExtendLightSectors =
true;
14831 ps52plib->SetAnchorOn(m_encShowAnchor);
14832 ps52plib->SetQualityOfData(m_encShowDataQual);
14838void ChartCanvas::SetShowENCDataQual(
bool show) {
14839 m_encShowDataQual = show;
14840 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14841 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14843 m_s52StateHash = 0;
14846void ChartCanvas::SetShowENCText(
bool show) {
14847 m_encShowText = show;
14848 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14849 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14851 m_s52StateHash = 0;
14854void ChartCanvas::SetENCDisplayCategory(
int category) {
14855 m_encDisplayCategory = category;
14856 m_s52StateHash = 0;
14859void ChartCanvas::SetShowENCDepth(
bool show) {
14860 m_encShowDepth = show;
14861 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14862 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14864 m_s52StateHash = 0;
14867void ChartCanvas::SetShowENCLightDesc(
bool show) {
14868 m_encShowLightDesc = show;
14869 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14870 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14872 m_s52StateHash = 0;
14875void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14876 m_encShowBuoyLabels = show;
14877 m_s52StateHash = 0;
14880void ChartCanvas::SetShowENCLights(
bool show) {
14881 m_encShowLights = show;
14882 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14883 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14885 m_s52StateHash = 0;
14888void ChartCanvas::SetShowENCAnchor(
bool show) {
14889 m_encShowAnchor = show;
14890 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14891 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14893 m_s52StateHash = 0;
14896wxRect ChartCanvas::GetMUIBarRect() {
14899 rv = m_muiBar->GetRect();
14905void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14906 if (!GetAlertString().IsEmpty()) {
14907 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14908 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14910 dc.SetFont(*pfont);
14911 dc.SetPen(*wxTRANSPARENT_PEN);
14913 dc.SetBrush(wxColour(243, 229, 47));
14915 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14919 wxRect sbr = GetScaleBarRect();
14920 int xp = sbr.x + sbr.width + 10;
14921 int yp = (sbr.y + sbr.height) - h;
14923 int wdraw = w + 10;
14924 dc.DrawRectangle(xp, yp, wdraw, h);
14925 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14926 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14936#define BRIGHT_XCALIB
14937#define __OPCPN_USEICC__
14940#ifdef __OPCPN_USEICC__
14941int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14942 double co_green,
double co_blue);
14944wxString temp_file_name;
14948class ocpnCurtain:
public wxDialog
14950 DECLARE_CLASS( ocpnCurtain )
14951 DECLARE_EVENT_TABLE()
14954 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14956 bool ProcessEvent(wxEvent& event);
14960IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14962BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14965ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14967 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14970ocpnCurtain::~ocpnCurtain()
14974bool ocpnCurtain::ProcessEvent(wxEvent& event)
14976 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14977 return GetParent()->GetEventHandler()->ProcessEvent(event);
14982#include <windows.h>
14985typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14986typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14987SetDeviceGammaRamp_ptr_type
14988 g_pSetDeviceGammaRamp;
14989GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14991WORD *g_pSavedGammaMap;
14995int InitScreenBrightness() {
14998 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15002 if (NULL == hGDI32DLL) {
15003 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
15005 if (NULL != hGDI32DLL) {
15007 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15008 hGDI32DLL,
"SetDeviceGammaRamp");
15009 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15010 hGDI32DLL,
"GetDeviceGammaRamp");
15013 if ((NULL == g_pSetDeviceGammaRamp) ||
15014 (NULL == g_pGetDeviceGammaRamp)) {
15015 FreeLibrary(hGDI32DLL);
15024 if (!g_pSavedGammaMap) {
15025 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
15028 bbr = g_pGetDeviceGammaRamp(
15029 hDC, g_pSavedGammaMap);
15030 ReleaseDC(NULL, hDC);
15035 wxRegKey *pRegKey =
new wxRegKey(
15036 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
15037 "NT\\CurrentVersion\\ICM");
15038 if (!pRegKey->Exists()) pRegKey->Create();
15039 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
15041 g_brightness_init =
true;
15047 if (NULL == g_pcurtain) {
15048 if (gFrame->CanSetTransparent()) {
15050 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
15051 wxPoint(0, 0), ::wxGetDisplaySize(),
15052 wxNO_BORDER | wxTRANSPARENT_WINDOW |
15053 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15060 g_pcurtain->Hide();
15062 HWND hWnd = GetHwndOf(g_pcurtain);
15063 SetWindowLong(hWnd, GWL_EXSTYLE,
15064 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15065 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15066 g_pcurtain->SetTransparent(0);
15068 g_pcurtain->Maximize();
15069 g_pcurtain->Show();
15072 g_pcurtain->Enable();
15073 g_pcurtain->Disable();
15080 g_brightness_init =
true;
15086 wxString cmd(
"xcalib -version");
15088 wxArrayString output;
15089 long r = wxExecute(cmd, output);
15092 " External application \"xcalib\" not found. Screen brightness "
15095 g_brightness_init =
true;
15100int RestoreScreenBrightness() {
15103 if (g_pSavedGammaMap) {
15104 HDC hDC = GetDC(NULL);
15105 g_pSetDeviceGammaRamp(hDC,
15107 ReleaseDC(NULL, hDC);
15109 free(g_pSavedGammaMap);
15110 g_pSavedGammaMap = NULL;
15114 g_pcurtain->Close();
15115 g_pcurtain->Destroy();
15119 g_brightness_init =
false;
15124#ifdef BRIGHT_XCALIB
15125 if (g_brightness_init) {
15127 cmd =
"xcalib -clear";
15128 wxExecute(cmd, wxEXEC_ASYNC);
15129 g_brightness_init =
false;
15139int SetScreenBrightness(
int brightness) {
15146 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15148 g_pcurtain->Close();
15149 g_pcurtain->Destroy();
15153 InitScreenBrightness();
15155 if (NULL == hGDI32DLL) {
15157 wchar_t wdll_name[80];
15158 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15159 LPCWSTR cstr = wdll_name;
15161 hGDI32DLL = LoadLibrary(cstr);
15163 if (NULL != hGDI32DLL) {
15165 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15166 hGDI32DLL,
"SetDeviceGammaRamp");
15167 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15168 hGDI32DLL,
"GetDeviceGammaRamp");
15171 if ((NULL == g_pSetDeviceGammaRamp) ||
15172 (NULL == g_pGetDeviceGammaRamp)) {
15173 FreeLibrary(hGDI32DLL);
15180 HDC hDC = GetDC(NULL);
15191 int increment = brightness * 256 / 100;
15194 WORD GammaTable[3][256];
15197 for (
int i = 0; i < 256; i++) {
15198 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15199 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15200 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15202 table_val += increment;
15204 if (table_val > 65535) table_val = 65535;
15207 g_pSetDeviceGammaRamp(hDC, GammaTable);
15208 ReleaseDC(NULL, hDC);
15215 if (g_pSavedGammaMap) {
15216 HDC hDC = GetDC(NULL);
15217 g_pSetDeviceGammaRamp(hDC,
15219 ReleaseDC(NULL, hDC);
15222 if (brightness < 100) {
15223 if (NULL == g_pcurtain) InitScreenBrightness();
15226 int sbrite = wxMax(1, brightness);
15227 sbrite = wxMin(100, sbrite);
15229 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15233 g_pcurtain->Close();
15234 g_pcurtain->Destroy();
15244#ifdef BRIGHT_XCALIB
15246 if (!g_brightness_init) {
15247 last_brightness = 100;
15248 g_brightness_init =
true;
15249 temp_file_name = wxFileName::CreateTempFileName(
"");
15250 InitScreenBrightness();
15253#ifdef __OPCPN_USEICC__
15256 if (!CreateSimpleICCProfileFile(
15257 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15258 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15259 wxString cmd(
"xcalib ");
15260 cmd += temp_file_name;
15262 wxExecute(cmd, wxEXEC_ASYNC);
15271 if (brightness > last_brightness) {
15273 cmd =
"xcalib -clear";
15274 wxExecute(cmd, wxEXEC_ASYNC);
15276 ::wxMilliSleep(10);
15278 int brite_adj = wxMax(1, brightness);
15279 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15280 wxExecute(cmd, wxEXEC_ASYNC);
15282 int brite_adj = wxMax(1, brightness);
15283 int factor = (brite_adj * 100) / last_brightness;
15284 factor = wxMax(1, factor);
15286 cmd.Printf(
"xcalib -co %2d -a", factor);
15287 wxExecute(cmd, wxEXEC_ASYNC);
15292 last_brightness = brightness;
15299#ifdef __OPCPN_USEICC__
15301#define MLUT_TAG 0x6d4c5554L
15302#define VCGT_TAG 0x76636774L
15304int GetIntEndian(
unsigned char *s) {
15309 p = (
unsigned char *)&ret;
15312 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15314 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15319unsigned short GetShortEndian(
unsigned char *s) {
15320 unsigned short ret;
15324 p = (
unsigned char *)&ret;
15327 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15329 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15335int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15336 double co_green,
double co_blue) {
15340 fp = fopen(file_name,
"wb");
15341 if (!fp)
return -1;
15347 for (
int i = 0; i < 128; i++) header[i] = 0;
15349 fwrite(header, 128, 1, fp);
15353 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15354 fwrite(&numTags, 1, 4, fp);
15356 int tagName0 = VCGT_TAG;
15357 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15358 fwrite(&tagName, 1, 4, fp);
15360 int tagOffset0 = 128 + 4 *
sizeof(int);
15361 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15362 fwrite(&tagOffset, 1, 4, fp);
15365 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15366 fwrite(&tagSize, 1, 4, fp);
15368 fwrite(&tagName, 1, 4, fp);
15370 fwrite(&tagName, 1, 4, fp);
15375 int gammatype0 = 0;
15376 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15377 fwrite(&gammatype, 1, 4, fp);
15379 int numChannels0 = 3;
15380 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15381 fwrite(&numChannels, 1, 2, fp);
15383 int numEntries0 = 256;
15384 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15385 fwrite(&numEntries, 1, 2, fp);
15387 int entrySize0 = 1;
15388 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15389 fwrite(&entrySize, 1, 2, fp);
15391 unsigned char ramp[256];
15394 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15395 fwrite(ramp, 256, 1, fp);
15398 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15399 fwrite(ramp, 256, 1, fp);
15402 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15403 fwrite(ramp, 256, 1, fp);
Select * pSelectAIS
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetQueryDialog.
std::unique_ptr< HostApi > GetHostApi()
HostApi factory,.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
ChartCanvas * g_focusCanvas
Global instance.
arrayofCanvasPtr g_canvasArray
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void CloseTideDialog()
Close any open tide dialog.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
void OnPaint(wxPaintEvent &event)
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void ShowSingleTideDialog(int x, int y, void *pvIDX)
Display tide/current dialog with single-instance management.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
int PrepareContextSelections(double lat, double lon)
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
EventVar json_msg
Notified with message targeting all plugins.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
bool IsTideDialogOpen() const
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Centers the view on a specific lat/lon position.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
Data for a loaded plugin, including dl-loaded library.
int m_cap_flag
PlugIn Capabilities descriptor.
PluginLoader is a backend module without any direct GUI functionality.
const ArrayOfPlugIns * GetPlugInArray()
Return list of currently loaded plugins.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
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.
ChartFamilyEnumPI
Enumeration of chart families (broad categories).
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
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.