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();
2784 if (event.ShiftDown()) {
2786 auto current_family = m_pQuilt->GetRefFamily();
2787 auto target_family = CHART_FAMILY_UNKNOWN;
2788 if (current_family == CHART_FAMILY_RASTER)
2789 target_family = CHART_FAMILY_VECTOR;
2791 target_family = CHART_FAMILY_RASTER;
2793 std::shared_ptr<HostApi> host_api;
2795 auto api_121 = std::dynamic_pointer_cast<HostApi121>(host_api);
2798 api_121->SelectChartFamily(m_canvasIndex,
2806 SetShowENCText(!GetShowENCText());
2812 if (!m_bMeasure_Active) {
2813 if (event.ShiftDown())
2814 m_bMeasure_DistCircle =
true;
2816 m_bMeasure_DistCircle =
false;
2818 StartMeasureRoute();
2820 CancelMeasureRoute();
2822 SetCursor(*pCursorArrow);
2832 parent_frame->ToggleColorScheme();
2834 TriggerDeferredFocus();
2838 int mod = m_modkeys & wxMOD_SHIFT;
2839 if (mod != m_brightmod) {
2841 m_bbrightdir = !m_bbrightdir;
2844 if (!m_bbrightdir) {
2845 g_nbrightness -= 10;
2846 if (g_nbrightness <= MIN_BRIGHT) {
2847 g_nbrightness = MIN_BRIGHT;
2848 m_bbrightdir =
true;
2851 g_nbrightness += 10;
2852 if (g_nbrightness >= MAX_BRIGHT) {
2853 g_nbrightness = MAX_BRIGHT;
2854 m_bbrightdir =
false;
2858 SetScreenBrightness(g_nbrightness);
2859 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2868 parent_frame->DoStackDown(
this);
2872 parent_frame->DoStackUp(
this);
2877 ToggleCanvasQuiltMode();
2883 parent_frame->ToggleFullScreen();
2888 if (m_modkeys == wxMOD_ALT) {
2891 ToggleChartOutlines();
2897 parent_frame->ActivateMOB();
2901 case WXK_NUMPAD_ADD:
2906 case WXK_NUMPAD_SUBTRACT:
2907 case WXK_PAGEDOWN: {
2908 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2913 if (m_bMeasure_Active) {
2914 if (m_nMeasureState > 2) {
2915 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2917 m_pMeasureRoute->GetnPoints();
2919 gFrame->RefreshAllCanvas();
2921 CancelMeasureRoute();
2922 StartMeasureRoute();
2930 if (event.GetKeyCode() < 128)
2932 int key_char =
event.GetKeyCode();
2936 if (!g_b_assume_azerty) {
2938 if (g_benable_rotate) {
2970 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2977 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2978 m_modkeys & wxMOD_RAW_CONTROL) {
2979 parent_frame->ToggleFullScreen();
2984 if (event.ControlDown()) key_char -= 64;
2986 if (key_char >=
'0' && key_char <=
'9')
2987 SetGroupIndex(key_char -
'0');
2992 SetShowENCAnchor(!GetShowENCAnchor());
2998 parent_frame->ToggleColorScheme();
3003 event.GetPosition(&x, &y);
3004 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
3005 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
3008 if (VPoint.b_quilt) {
3010 if (m_pQuilt->GetChartAtPix(
3015 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3017 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
3022 if (m_singleChart) {
3023 ChartType = m_singleChart->GetChartType();
3024 ChartFam = m_singleChart->GetChartFamily();
3028 if ((ChartType != CHART_TYPE_UNKNOWN) ||
3029 (ChartFam != CHART_FAMILY_UNKNOWN)) {
3031 this, -1, ChartType, ChartFam,
3032 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
3033 wxDefaultSize, wxSIMPLE_BORDER,
"");
3046 m_nmea_log->Raise();
3050 SetShowENCLights(!GetShowENCLights());
3056 if (event.ShiftDown())
3057 m_bMeasure_DistCircle =
true;
3059 m_bMeasure_DistCircle =
false;
3061 StartMeasureRoute();
3065 if (g_bInlandEcdis && ps52plib) {
3066 SetENCDisplayCategory((_DisCat)STANDARD);
3071 ToggleChartOutlines();
3075 ToggleCanvasQuiltMode();
3079 parent_frame->ToggleTestPause();
3082 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3083 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
3084 g_iNavAidRadarRingsNumberVisible = 1;
3085 else if (!g_bNavAidRadarRingsShown &&
3086 g_iNavAidRadarRingsNumberVisible == 1)
3087 g_iNavAidRadarRingsNumberVisible = 0;
3090 SetShowENCDepth(!m_encShowDepth);
3095 SetShowENCText(!GetShowENCText());
3100 SetShowENCDataQual(!GetShowENCDataQual());
3105 m_bShowNavobjects = !m_bShowNavobjects;
3120 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3125 if (event.ControlDown()) gFrame->DropMarker(
false);
3132 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3133 if ((indexActive + 1) <= r->GetnPoints()) {
3144 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3150 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3156 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3163 parent_frame->DoSettings();
3167 parent_frame->Close();
3183 if (undo->AnythingToRedo()) {
3184 undo->RedoNextAction();
3191 if (event.ShiftDown()) {
3192 if (undo->AnythingToRedo()) {
3193 undo->RedoNextAction();
3198 if (undo->AnythingToUndo()) {
3199 undo->UndoLastAction();
3208 if (m_bMeasure_Active) {
3209 CancelMeasureRoute();
3211 SetCursor(*pCursorArrow);
3214 gFrame->RefreshAllCanvas();
3228 switch (gamma_state) {
3248 SetScreenBrightness(g_nbrightness);
3253 if (event.ControlDown()) {
3254 m_bShowCompassWin = !m_bShowCompassWin;
3255 SetShowGPSCompassWindow(m_bShowCompassWin);
3272void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3273 if (SendKeyEventToPlugins(event))
3277 switch (event.GetKeyCode()) {
3279 parent_frame->SwitchKBFocus(
this);
3285 if (!m_pany) m_panspeed = 0;
3291 if (!m_panx) m_panspeed = 0;
3294 case WXK_NUMPAD_ADD:
3295 case WXK_NUMPAD_SUBTRACT:
3304 m_modkeys &= ~wxMOD_ALT;
3305#ifdef OCPN_ALT_MENUBAR
3310 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3311 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3312 parent_frame->ApplyGlobalSettings(
false);
3314 m_bMayToggleMenuBar =
true;
3320 m_modkeys &= ~wxMOD_CONTROL;
3324 if (event.GetKeyCode() < 128)
3326 int key_char =
event.GetKeyCode();
3330 if (!g_b_assume_azerty) {
3345 m_rotation_speed = 0;
3363void ChartCanvas::ToggleChartOutlines() {
3364 m_bShowOutlines = !m_bShowOutlines;
3370 if (g_bopengl) InvalidateGL();
3374void ChartCanvas::ToggleLookahead() {
3375 m_bLookAhead = !m_bLookAhead;
3380void ChartCanvas::SetUpMode(
int mode) {
3383 if (mode != NORTH_UP_MODE) {
3386 if (!std::isnan(
gCog)) stuff =
gCog;
3389 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3392 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3394 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3395 SetVPRotation(GetVPSkew());
3400 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3401 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3403 UpdateGPSCompassStatusBox(
true);
3404 gFrame->DoChartUpdate();
3407bool ChartCanvas::DoCanvasCOGSet() {
3408 if (GetUpMode() == NORTH_UP_MODE)
return false;
3410 if (g_btenhertz) cog_use =
gCog;
3412 double rotation = 0;
3413 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3414 rotation = -
gHdt * PI / 180.;
3415 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3416 rotation = -cog_use * PI / 180.;
3418 SetVPRotation(rotation);
3422double easeOutCubic(
double t) {
3424 return 1.0 - pow(1.0 - t, 3.0);
3427void ChartCanvas::StartChartDragInertia() {
3428 m_bChartDragging =
false;
3431 m_chart_drag_inertia_time = 750;
3432 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3437 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3441 size_t length = m_drag_vec_t.size();
3442 for (
size_t i = 0; i < n_vel; i++) {
3443 xacc += m_drag_vec_x.at(length - 1 - i);
3444 yacc += m_drag_vec_y.at(length - 1 - i);
3445 tacc += m_drag_vec_t.at(length - 1 - i);
3448 if (tacc == 0)
return;
3450 double drag_velocity_x = xacc / tacc;
3451 double drag_velocity_y = yacc / tacc;
3457 if ((fabs(drag_velocity_x) < 200) && (fabs(drag_velocity_y) < 200))
return;
3459 m_chart_drag_velocity_x = drag_velocity_x;
3460 m_chart_drag_velocity_y = drag_velocity_y;
3462 m_chart_drag_inertia_active =
true;
3464 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3467void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3468 if (!m_chart_drag_inertia_active)
return;
3470 wxLongLong now = wxGetLocalTimeMillis();
3471 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3472 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3473 if (t > 1.0) t = 1.0;
3474 double e = 1.0 - easeOutCubic(t);
3477 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3479 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3481 m_last_elapsed = elapsed;
3485 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3486 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3487 double inertia_lat, inertia_lon;
3491 if (!IsOwnshipOnScreen()) {
3493 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3494 UpdateFollowButtonState();
3505 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3506 m_chart_drag_inertia_timer.Stop();
3509 m_target_lat = GetVP().
clat;
3510 m_target_lon = GetVP().
clon;
3511 m_pan_drag.x = m_pan_drag.y = 0;
3512 m_panx = m_pany = 0;
3513 m_chart_drag_inertia_active =
false;
3517 int target_redraw_interval = 40;
3518 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3522void ChartCanvas::StopMovement() {
3523 m_panx = m_pany = 0;
3526 m_rotation_speed = 0;
3529#if !defined(__WXGTK__) && !defined(__WXQT__)
3540bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3542 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3544 if (!pMovementTimer->IsRunning()) {
3545 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3548 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3553 m_last_movement_time = wxDateTime::UNow();
3557void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3560 m_target_lat = target_lat;
3561 m_target_lon = target_lon;
3564 m_start_lat = GetVP().
clat;
3565 m_start_lon = GetVP().
clon;
3567 m_VPMovementTimer.Start(1,
true);
3568 m_timed_move_vp_active =
true;
3570 m_timedVP_step = nstep;
3573void ChartCanvas::DoTimedMovementVP() {
3574 if (!m_timed_move_vp_active)
return;
3575 if (m_stvpc++ > m_timedVP_step * 2) {
3582 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3597 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3598 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3600 m_run_lat = new_lat;
3601 m_run_lon = new_lon;
3606void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3608void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3610void ChartCanvas::StartTimedMovementTarget() {}
3612void ChartCanvas::DoTimedMovementTarget() {}
3614void ChartCanvas::StopMovementTarget() {}
3617void ChartCanvas::DoTimedMovement() {
3618 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3622 wxDateTime now = wxDateTime::UNow();
3624 if (m_last_movement_time.IsValid())
3625 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3627 m_last_movement_time = now;
3637 if (dt == 0) dt = 1;
3640 if (m_mustmove < 0) m_mustmove = 0;
3643 if (m_pan_drag.x || m_pan_drag.y) {
3645 m_pan_drag.x = m_pan_drag.y = 0;
3648 if (m_panx || m_pany) {
3649 const double slowpan = .1, maxpan = 2;
3650 if (m_modkeys == wxMOD_ALT)
3651 m_panspeed = slowpan;
3653 m_panspeed += (double)dt / 500;
3654 m_panspeed = wxMin(maxpan, m_panspeed);
3656 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3659 if (m_zoom_factor != 1) {
3660 double alpha = 400, beta = 1.5;
3661 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3663 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3665 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3670 if (zoom_factor > 1) {
3671 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3675 else if (zoom_factor < 1) {
3676 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3681 if (fabs(zoom_factor - 1) > 1e-4) {
3682 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3687 if (m_wheelzoom_stop_oneshot > 0) {
3688 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3689 m_wheelzoom_stop_oneshot = 0;
3694 if (zoom_factor > 1) {
3696 m_wheelzoom_stop_oneshot = 0;
3699 }
else if (zoom_factor < 1) {
3701 m_wheelzoom_stop_oneshot = 0;
3708 if (m_rotation_speed) {
3709 double speed = m_rotation_speed;
3710 if (m_modkeys == wxMOD_ALT) speed /= 10;
3711 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3715void ChartCanvas::SetColorScheme(ColorScheme cs) {
3720 case GLOBAL_COLOR_SCHEME_DAY:
3721 m_pos_image_red = &m_os_image_red_day;
3722 m_pos_image_grey = &m_os_image_grey_day;
3723 m_pos_image_yellow = &m_os_image_yellow_day;
3724 m_pos_image_user = m_pos_image_user_day;
3725 m_pos_image_user_grey = m_pos_image_user_grey_day;
3726 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3727 m_cTideBitmap = m_bmTideDay;
3728 m_cCurrentBitmap = m_bmCurrentDay;
3731 case GLOBAL_COLOR_SCHEME_DUSK:
3732 m_pos_image_red = &m_os_image_red_dusk;
3733 m_pos_image_grey = &m_os_image_grey_dusk;
3734 m_pos_image_yellow = &m_os_image_yellow_dusk;
3735 m_pos_image_user = m_pos_image_user_dusk;
3736 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3737 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3738 m_cTideBitmap = m_bmTideDusk;
3739 m_cCurrentBitmap = m_bmCurrentDusk;
3741 case GLOBAL_COLOR_SCHEME_NIGHT:
3742 m_pos_image_red = &m_os_image_red_night;
3743 m_pos_image_grey = &m_os_image_grey_night;
3744 m_pos_image_yellow = &m_os_image_yellow_night;
3745 m_pos_image_user = m_pos_image_user_night;
3746 m_pos_image_user_grey = m_pos_image_user_grey_night;
3747 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3748 m_cTideBitmap = m_bmTideNight;
3749 m_cCurrentBitmap = m_bmCurrentNight;
3752 m_pos_image_red = &m_os_image_red_day;
3753 m_pos_image_grey = &m_os_image_grey_day;
3754 m_pos_image_yellow = &m_os_image_yellow_day;
3755 m_pos_image_user = m_pos_image_user_day;
3756 m_pos_image_user_grey = m_pos_image_user_grey_day;
3757 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3758 m_cTideBitmap = m_bmTideDay;
3759 m_cCurrentBitmap = m_bmCurrentDay;
3763 CreateDepthUnitEmbossMaps(cs);
3764 CreateOZEmbossMapData(cs);
3767 m_fog_color = wxColor(
3771 case GLOBAL_COLOR_SCHEME_DUSK:
3774 case GLOBAL_COLOR_SCHEME_NIGHT:
3780 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3781 m_fog_color.Blue() * dim);
3785 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3786 SetBackgroundColour( wxColour(0,0,0) );
3788 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3791 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3793 SetBackgroundColour( wxNullColour );
3800 m_Piano->SetColorScheme(cs);
3802 m_Compass->SetColorScheme(cs);
3804 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3806 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3808 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3809 if (m_notification_button) {
3810 m_notification_button->SetColorScheme(cs);
3814 if (g_bopengl && m_glcc) {
3815 m_glcc->SetColorScheme(cs);
3821 m_brepaint_piano =
true;
3828wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3829 wxImage img = Bitmap.ConvertToImage();
3830 int sx = img.GetWidth();
3831 int sy = img.GetHeight();
3833 wxImage new_img(img);
3835 for (
int i = 0; i < sx; i++) {
3836 for (
int j = 0; j < sy; j++) {
3837 if (!img.IsTransparent(i, j)) {
3838 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3839 (
unsigned char)(img.GetGreen(i, j) * factor),
3840 (
unsigned char)(img.GetBlue(i, j) * factor));
3845 wxBitmap ret = wxBitmap(new_img);
3850void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3853 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3855 if (!m_pBrightPopup) {
3858 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3862 m_pBrightPopup->SetSize(x, y);
3863 m_pBrightPopup->Move(120, 120);
3866 int bmpsx = m_pBrightPopup->GetSize().x;
3867 int bmpsy = m_pBrightPopup->GetSize().y;
3869 wxBitmap bmp(bmpsx, bmpsx);
3870 wxMemoryDC mdc(bmp);
3872 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3873 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3874 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3875 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3878 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3880 mdc.SetFont(*pfont);
3883 if (brightness == max)
3885 else if (brightness == min)
3888 val.Printf(
"%3d", brightness);
3890 mdc.DrawText(val, 0, 0);
3892 mdc.SelectObject(wxNullBitmap);
3894 m_pBrightPopup->SetBitmap(bmp);
3895 m_pBrightPopup->Show();
3896 m_pBrightPopup->Refresh();
3899void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3900 m_b_rot_hidef =
true;
3904void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3907 bool b_need_refresh =
false;
3909 wxSize win_size = GetSize() * m_displayScale;
3913 bool showAISRollover =
false;
3915 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3919 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3920 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3923 showAISRollover =
true;
3925 if (NULL == m_pAISRolloverWin) {
3927 m_pAISRolloverWin->IsActive(
false);
3928 b_need_refresh =
true;
3929 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3930 m_AISRollover_MMSI != FoundAIS_MMSI) {
3936 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3937 m_pAISRolloverWin->IsActive(
false);
3938 m_AISRollover_MMSI = 0;
3943 m_AISRollover_MMSI = FoundAIS_MMSI;
3945 if (!m_pAISRolloverWin->IsActive()) {
3946 wxString s = ptarget->GetRolloverString();
3947 m_pAISRolloverWin->SetString(s);
3949 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3950 AIS_ROLLOVER, win_size);
3951 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3952 m_pAISRolloverWin->IsActive(
true);
3953 b_need_refresh =
true;
3957 m_AISRollover_MMSI = 0;
3958 showAISRollover =
false;
3963 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3964 m_pAISRolloverWin->IsActive(
false);
3965 m_AISRollover_MMSI = 0;
3966 b_need_refresh =
true;
3971 bool showRouteRollover =
false;
3973 if (NULL == m_pRolloverRouteSeg) {
3977 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3978 SelectableItemList SelList =
pSelect->FindSelectionList(
3980 auto node = SelList.begin();
3981 while (node != SelList.end()) {
3986 if (pr && pr->IsVisible()) {
3987 m_pRolloverRouteSeg = pFindSel;
3988 showRouteRollover =
true;
3990 if (NULL == m_pRouteRolloverWin) {
3992 m_pRouteRolloverWin->IsActive(
false);
3995 if (!m_pRouteRolloverWin->IsActive()) {
4003 DistanceBearingMercator(
4004 segShow_point_b->m_lat, segShow_point_b->m_lon,
4005 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4007 if (!pr->m_bIsInLayer)
4008 s.Append(_(
"Route") +
": ");
4010 s.Append(_(
"Layer Route: "));
4012 if (pr->m_RouteNameString.IsEmpty())
4013 s.Append(_(
"(unnamed)"));
4015 s.Append(pr->m_RouteNameString);
4020 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
4021 << segShow_point_b->GetName() <<
"\n";
4024 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
4025 (
int)floor(brg + 0.5), 0x00B0);
4028 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4030 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4031 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4033 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
4034 (
int)floor(varBrg + 0.5), 0x00B0);
4042 double shiptoEndLeg = 0.;
4043 bool validActive =
false;
4044 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
4047 if (segShow_point_a != *pr->pRoutePointList->begin()) {
4048 auto node = pr->pRoutePointList->begin();
4050 float dist_to_endleg = 0;
4053 for (++node; node != pr->pRoutePointList->end(); ++node) {
4060 if (prp->IsSame(segShow_point_a))
break;
4068 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
4071 ->GetCurrentRngToActivePoint();
4080 if (!std::isnan(
gCog) && !std::isnan(
gSog))
4085 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
4086 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
4088 << wxString(ttg_sec > SECONDS_PER_DAY
4089 ? ttg_span.Format(_(
"%Dd %H:%M"))
4090 : ttg_span.Format(_(
"%H:%M")));
4091 wxDateTime dtnow, eta;
4092 eta = dtnow.SetToCurrent().Add(ttg_span);
4093 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
4094 << eta.Format(
" %d %H:%M");
4098 m_pRouteRolloverWin->SetString(s);
4100 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4101 LEG_ROLLOVER, win_size);
4102 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
4103 m_pRouteRolloverWin->IsActive(
true);
4104 b_need_refresh =
true;
4105 showRouteRollover =
true;
4114 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4116 m_pRolloverRouteSeg))
4117 showRouteRollover =
false;
4118 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
4119 showRouteRollover =
false;
4121 showRouteRollover =
true;
4125 if (m_routeState) showRouteRollover =
false;
4128 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4129 showRouteRollover =
false;
4131 if (m_pRouteRolloverWin &&
4132 !showRouteRollover) {
4133 m_pRouteRolloverWin->IsActive(
false);
4134 m_pRolloverRouteSeg = NULL;
4135 m_pRouteRolloverWin->Destroy();
4136 m_pRouteRolloverWin = NULL;
4137 b_need_refresh =
true;
4138 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4139 m_pRouteRolloverWin->IsActive(
true);
4140 b_need_refresh =
true;
4145 bool showTrackRollover =
false;
4147 if (NULL == m_pRolloverTrackSeg) {
4151 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4152 SelectableItemList SelList =
pSelect->FindSelectionList(
4155 auto node = SelList.begin();
4156 while (node != SelList.end()) {
4161 if (pt && pt->IsVisible()) {
4162 m_pRolloverTrackSeg = pFindSel;
4163 showTrackRollover =
true;
4165 if (NULL == m_pTrackRolloverWin) {
4167 m_pTrackRolloverWin->IsActive(
false);
4170 if (!m_pTrackRolloverWin->IsActive()) {
4178 DistanceBearingMercator(
4179 segShow_point_b->m_lat, segShow_point_b->m_lon,
4180 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4182 if (!pt->m_bIsInLayer)
4183 s.Append(_(
"Track") +
": ");
4185 s.Append(_(
"Layer Track: "));
4187 if (pt->GetName().IsEmpty())
4188 s.Append(_(
"(unnamed)"));
4190 s.Append(pt->GetName());
4191 double tlenght = pt->Length();
4193 if (pt->GetLastPoint()->GetTimeString() &&
4194 pt->GetPoint(0)->GetTimeString()) {
4195 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4196 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4197 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4198 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4199 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4200 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4201 << getUsrSpeedUnit();
4202 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4203 : ttime.Format(
" %H:%M"));
4207 if (g_bShowTrackPointTime &&
4208 strlen(segShow_point_b->GetTimeString())) {
4209 wxString stamp = segShow_point_b->GetTimeString();
4210 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4211 if (timestamp.IsValid()) {
4215 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4217 s <<
"\n" << _(
"Segment Created: ") << stamp;
4222 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4227 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4229 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4230 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4232 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4238 if (segShow_point_a->GetTimeString() &&
4239 segShow_point_b->GetTimeString()) {
4240 wxDateTime apoint = segShow_point_a->GetCreateTime();
4241 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4242 if (apoint.IsValid() && bpoint.IsValid()) {
4243 double segmentSpeed = toUsrSpeed(
4244 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4245 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4246 << getUsrSpeedUnit();
4250 m_pTrackRolloverWin->SetString(s);
4252 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4253 LEG_ROLLOVER, win_size);
4254 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4255 m_pTrackRolloverWin->IsActive(
true);
4256 b_need_refresh =
true;
4257 showTrackRollover =
true;
4266 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4268 m_pRolloverTrackSeg))
4269 showTrackRollover =
false;
4270 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4271 showTrackRollover =
false;
4273 showTrackRollover =
true;
4277 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4278 showTrackRollover =
false;
4281 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4282 showTrackRollover =
false;
4288 if (m_pTrackRolloverWin &&
4289 !showTrackRollover) {
4290 m_pTrackRolloverWin->IsActive(
false);
4291 m_pRolloverTrackSeg = NULL;
4292 m_pTrackRolloverWin->Destroy();
4293 m_pTrackRolloverWin = NULL;
4294 b_need_refresh =
true;
4295 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4296 m_pTrackRolloverWin->IsActive(
true);
4297 b_need_refresh =
true;
4300 if (b_need_refresh) Refresh();
4303void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4304 if ((GetShowENCLights() || m_bsectors_shown) &&
4305 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4306 extendedSectorLegs)) {
4307 if (!m_bsectors_shown) {
4309 m_bsectors_shown =
true;
4312 if (m_bsectors_shown) {
4314 m_bsectors_shown =
false;
4322#if defined(__WXGTK__) || defined(__WXQT__)
4327 double cursor_lat, cursor_lon;
4330 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4331 while (cursor_lon < -180.) cursor_lon += 360.;
4333 while (cursor_lon > 180.) cursor_lon -= 360.;
4335 SetCursorStatus(cursor_lat, cursor_lon);
4341void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4342 if (!parent_frame->m_pStatusBar)
return;
4346 s1 += toSDMM(1, cursor_lat);
4348 s1 += toSDMM(2, cursor_lon);
4350 if (STAT_FIELD_CURSOR_LL >= 0)
4351 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4353 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4358 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4359 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4360 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4362 wxString s = st + sm;
4375 if (g_bShowLiveETA) {
4378 float boatSpeedDefault = g_defaultBoatSpeed;
4383 if (!std::isnan(
gSog)) {
4385 if (boatSpeed < 0.5) {
4388 realTimeETA = dist / boatSpeed * 60;
4397 s << minutesToHoursDays(realTimeETA);
4402 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4403 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4405 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4410 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4418wxString minutesToHoursDays(
float timeInMinutes) {
4421 if (timeInMinutes == 0) {
4426 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4427 s << wxString::Format(
"%d", (
int)timeInMinutes);
4432 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4435 hours = (int)timeInMinutes / 60;
4436 min = (int)timeInMinutes % 60;
4439 s << wxString::Format(
"%d", hours);
4442 s << wxString::Format(
"%d", hours);
4444 s << wxString::Format(
"%d", min);
4451 else if (timeInMinutes > 24 * 60) {
4454 days = (int)(timeInMinutes / 60) / 24;
4455 hours = (int)(timeInMinutes / 60) % 24;
4458 s << wxString::Format(
"%d", days);
4461 s << wxString::Format(
"%d", days);
4463 s << wxString::Format(
"%d", hours);
4475void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4483 wxPoint2DDouble *r) {
4488 double rlon, wxPoint2DDouble *r) {
4499 if (!g_bopengl && m_singleChart &&
4500 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4501 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4502 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4503 (m_singleChart->GetChartProjectionType() !=
4504 PROJECTION_TRANSVERSE_MERCATOR) &&
4505 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4506 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4507 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4521 Cur_BSB_Ch->SetVPRasterParms(vp);
4522 double rpixxd, rpixyd;
4523 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4549 if (std::isnan(p.m_x)) {
4550 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4554 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4555 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4557 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4576 if (!g_bopengl && m_singleChart &&
4577 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4578 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4579 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4580 (m_singleChart->GetChartProjectionType() !=
4581 PROJECTION_TRANSVERSE_MERCATOR) &&
4582 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4583 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4584 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4595 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4598 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4603 else if (slon > 180.)
4614 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4620 DoZoomCanvas(factor,
false);
4621 extendedSectorLegs.clear();
4626 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4629 if (StartTimedMovement(stoptimer)) {
4631 m_zoom_factor = factor;
4636 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4638 DoZoomCanvas(factor, can_zoom_to_cursor);
4641 extendedSectorLegs.clear();
4644void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4647 if (!m_pCurrentStack)
return;
4653 if (m_bzooming)
return;
4662 double proposed_scale_onscreen =
4665 bool b_do_zoom =
false;
4674 if (!VPoint.b_quilt) {
4677 if (!m_disable_adjust_on_zoom) {
4678 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4679 if (new_db_index >= 0)
4680 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4684 int current_ref_stack_index = -1;
4685 if (m_pCurrentStack->nEntry) {
4687 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4688 m_pQuilt->SetReferenceChart(trial_index);
4689 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4690 if (new_db_index >= 0)
4691 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4695 if (m_pCurrentStack)
4696 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4707 double min_allowed_scale =
4710 if (proposed_scale_onscreen < min_allowed_scale) {
4715 proposed_scale_onscreen = min_allowed_scale;
4719 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4722 }
else if (factor < 1) {
4727 bool b_smallest =
false;
4729 if (!VPoint.b_quilt) {
4734 LLBBox viewbox = VPoint.GetBBox();
4736 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4737 double max_allowed_scale;
4751 if (proposed_scale_onscreen > max_allowed_scale) {
4753 proposed_scale_onscreen = max_allowed_scale;
4758 if (!m_disable_adjust_on_zoom) {
4760 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4761 if (new_db_index >= 0)
4762 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4764 if (m_pCurrentStack)
4765 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4768 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4770 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4771 proposed_scale_onscreen =
4772 wxMin(proposed_scale_onscreen,
4778 m_absolute_min_scale_ppm)
4779 proposed_scale_onscreen =
4788 bool b_allow_ztc =
true;
4789 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4790 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4792 double brg, distance;
4793 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4796 meters_to_shift = distance * 1852;
4804 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4807 if (m_bFollow) DoCanvasUpdate();
4814void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4816 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4820void ChartCanvas::RotateCanvas(
double dir) {
4824 if (StartTimedMovement()) {
4826 m_rotation_speed = dir * 60;
4829 double speed = dir * 10;
4830 if (m_modkeys == wxMOD_ALT) speed /= 20;
4831 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4835void ChartCanvas::DoRotateCanvas(
double rotation) {
4836 while (rotation < 0) rotation += 2 * PI;
4837 while (rotation > 2 * PI) rotation -= 2 * PI;
4839 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4841 SetVPRotation(rotation);
4842 parent_frame->UpdateRotationState(VPoint.
rotation);
4845void ChartCanvas::DoTiltCanvas(
double tilt) {
4846 while (tilt < 0) tilt = 0;
4847 while (tilt > .95) tilt = .95;
4849 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4855void ChartCanvas::TogglebFollow() {
4862void ChartCanvas::ClearbFollow() {
4865 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4867 UpdateFollowButtonState();
4871 parent_frame->SetChartUpdatePeriod();
4874void ChartCanvas::SetbFollow() {
4877 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4878 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4886 p.m_x += m_OSoffsetx;
4887 p.m_y -= m_OSoffsety;
4896 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4897 UpdateFollowButtonState();
4899 if (!g_bSmoothRecenter) {
4903 parent_frame->SetChartUpdatePeriod();
4906void ChartCanvas::UpdateFollowButtonState() {
4909 m_muiBar->SetFollowButtonState(0);
4912 m_muiBar->SetFollowButtonState(2);
4914 m_muiBar->SetFollowButtonState(1);
4920 androidSetFollowTool(0);
4923 androidSetFollowTool(2);
4925 androidSetFollowTool(1);
4932 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4933 if (pic->m_enabled && pic->m_init_state) {
4934 switch (pic->m_api_version) {
4937 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4948void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4949 if (g_bSmoothRecenter && !m_routeState) {
4950 if (StartSmoothJump(lat, lon, scale_ppm))
4954 double gcDist, gcBearingEnd;
4955 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4957 gcBearingEnd += 180;
4958 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4961 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4962 double new_lat = lat + (lat_offset / (1852 * 60));
4963 double new_lon = lon + (lon_offset / (1852 * 60));
4966 StartSmoothJump(lat, lon, scale_ppm);
4971 if (lon > 180.0) lon -= 360.0;
4977 if (!GetQuiltMode()) {
4979 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4980 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4984 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4985 AdjustQuiltRefChart();
4992 UpdateFollowButtonState();
5000bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
5005 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
5006 double distance_pixels = gcDist *
GetVPScale();
5007 if (distance_pixels > 0.5 * GetCanvasWidth()) {
5013 m_startLat = m_vLat;
5014 m_startLon = m_vLon;
5019 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
5020 m_endScale = scale_ppm;
5023 m_animationDuration = 600;
5024 m_animationStart = wxGetLocalTimeMillis();
5031 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
5032 m_animationActive =
true;
5037void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
5039 wxLongLong now = wxGetLocalTimeMillis();
5040 double elapsed = (now - m_animationStart).ToDouble();
5041 double t = elapsed / m_animationDuration.ToDouble();
5042 if (t > 1.0) t = 1.0;
5045 double e = easeOutCubic(t);
5048 double curLat = m_startLat + (m_endLat - m_startLat) * e;
5049 double curLon = m_startLon + (m_endLon - m_startLon) * e;
5050 double curScale = m_startScale + (m_endScale - m_startScale) * e;
5055 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
5061 m_animationActive =
false;
5062 UpdateFollowButtonState();
5071 extendedSectorLegs.clear();
5080 if (iters++ > 5)
return false;
5081 if (!std::isnan(dlat))
break;
5084 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
5090 else if (dlat < -90)
5093 if (dlon > 360.) dlon -= 360.;
5094 if (dlon < -360.) dlon += 360.;
5109 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5113 if (VPoint.b_quilt) {
5114 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
5115 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
5119 double tweak_scale_ppm =
5125 if (new_ref_dbIndex == -1) {
5126#pragma GCC diagnostic push
5127#pragma GCC diagnostic ignored "-Warray-bounds"
5134 int trial_index = -1;
5135 if (m_pCurrentStack->nEntry) {
5137 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5140 if (trial_index < 0) {
5141 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5142 if (full_screen_array.size())
5143 trial_index = full_screen_array[full_screen_array.size() - 1];
5146 if (trial_index >= 0) {
5147 m_pQuilt->SetReferenceChart(trial_index);
5152#pragma GCC diagnostic pop
5159 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5161 double offset_angle = atan2(offy, offx);
5162 double offset_distance = sqrt((offy * offy) + (offx * offx));
5163 double chart_angle = GetVPRotation();
5164 double target_angle = chart_angle - offset_angle;
5165 double d_east_mod = offset_distance * cos(target_angle);
5166 double d_north_mod = offset_distance * sin(target_angle);
5171 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5172 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5174 UpdateFollowButtonState();
5180 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5185bool ChartCanvas::IsOwnshipOnScreen() {
5188 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5189 ((r.y > 0) && r.y < GetCanvasHeight()))
5195void ChartCanvas::ReloadVP(
bool b_adjust) {
5196 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5198 LoadVP(VPoint, b_adjust);
5201void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5203 if (g_bopengl && m_glcc) {
5204 m_glcc->Invalidate();
5205 if (m_glcc->GetSize() != GetSize()) {
5206 m_glcc->SetSize(GetSize());
5211 m_cache_vp.Invalidate();
5212 m_bm_cache_vp.Invalidate();
5215 VPoint.Invalidate();
5217 if (m_pQuilt) m_pQuilt->Invalidate();
5226 vp.m_projection_type, b_adjust);
5229void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5230 m_pQuilt->SetReferenceChart(dbIndex);
5231 VPoint.Invalidate();
5232 m_pQuilt->Invalidate();
5235double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5237 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5244int ChartCanvas::AdjustQuiltRefChart() {
5249 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5251 double min_ref_scale =
5252 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5253 double max_ref_scale =
5254 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5257 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5258 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5259 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5261 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5264 int target_stack_index = wxNOT_FOUND;
5266 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5267 if (index == m_pQuilt->GetRefChartdbIndex()) {
5268 target_stack_index = il;
5273 if (wxNOT_FOUND == target_stack_index)
5274 target_stack_index = 0;
5276 int ref_family = pc->GetChartFamily();
5277 int extended_array_count =
5278 m_pQuilt->GetExtendedStackIndexArray().size();
5279 while ((!brender_ok) &&
5280 ((
int)target_stack_index < (extended_array_count - 1))) {
5281 target_stack_index++;
5283 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5285 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5286 IsChartQuiltableRef(test_db_index)) {
5289 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5291 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5298 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5299 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5300 IsChartQuiltableRef(new_db_index)) {
5301 m_pQuilt->SetReferenceChart(new_db_index);
5304 ret = m_pQuilt->GetRefChartdbIndex();
5306 ret = m_pQuilt->GetRefChartdbIndex();
5309 ret = m_pQuilt->GetRefChartdbIndex();
5318void ChartCanvas::UpdateCanvasOnGroupChange() {
5319 delete m_pCurrentStack;
5331bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5332 double latNE,
double lonNE) {
5334 double latc = (latSW + latNE) / 2.0;
5335 double lonc = (lonSW + lonNE) / 2.0;
5338 double ne_easting, ne_northing;
5339 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5341 double sw_easting, sw_northing;
5342 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5344 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5351 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5354bool ChartCanvas::SetVPProjection(
int projection) {
5360 double prev_true_scale_ppm = m_true_scale_ppm;
5365 m_absolute_min_scale_ppm));
5373bool ChartCanvas::SetVPRotation(
double angle) {
5375 VPoint.
skew, angle);
5378 double skew,
double rotation,
int projection,
5379 bool b_adjust,
bool b_refresh) {
5384 if (VPoint.IsValid()) {
5385 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5386 (fabs(VPoint.
skew - skew) < 1e-9) &&
5387 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5388 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5389 (VPoint.m_projection_type == projection ||
5390 projection == PROJECTION_UNKNOWN))
5393 if (VPoint.m_projection_type != projection)
5394 VPoint.InvalidateTransformCache();
5404 if (projection != PROJECTION_UNKNOWN)
5405 VPoint.SetProjectionType(projection);
5406 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5407 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5410 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5411 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5412 if (VPoint.
clat > 89.5)
5414 else if (VPoint.
clat < -89.5)
5415 VPoint.
clat = -89.5;
5420 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5421 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5433 bool bwasValid = VPoint.IsValid();
5438 m_cache_vp.Invalidate();
5443 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5447 int mouseX = mouse_x;
5448 int mouseY = mouse_y;
5449 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5455 SendCursorLatLonToAllPlugIns(lat, lon);
5458 if (!VPoint.b_quilt && m_singleChart) {
5463 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5467 if ((!m_cache_vp.IsValid()) ||
5472 wxPoint cp_last, cp_this;
5476 if (cp_last != cp_this) {
5482 if (m_pCurrentStack) {
5484 int current_db_index;
5486 m_pCurrentStack->GetCurrentEntrydbIndex();
5488 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5490 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5493 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5497 if (VPoint.b_quilt) {
5501 m_pQuilt->InvalidateAllQuiltPatchs();
5505 if (!m_pCurrentStack)
return false;
5507 int current_db_index;
5509 m_pCurrentStack->GetCurrentEntrydbIndex();
5511 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5512 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5515 int current_ref_stack_index = -1;
5516 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5517 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5518 current_ref_stack_index = i;
5521 if (g_bFullScreenQuilt) {
5522 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5526 bool b_needNewRef =
false;
5529 if ((-1 == current_ref_stack_index) &&
5530 (m_pQuilt->GetRefChartdbIndex() >= 0))
5531 b_needNewRef =
true;
5538 bool renderable =
true;
5540 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5541 if (referenceChart) {
5542 double chartMaxScale = referenceChart->GetNormalScaleMax(
5544 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5546 if (!renderable) b_needNewRef =
true;
5549 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5551 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5552 int target_scale = cte_ref.GetScale();
5553 int target_type = cte_ref.GetChartType();
5554 int candidate_stack_index;
5561 candidate_stack_index = 0;
5562 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5564 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5565 int candidate_scale = cte_candidate.GetScale();
5566 int candidate_type = cte_candidate.GetChartType();
5568 if ((candidate_scale >= target_scale) &&
5569 (candidate_type == target_type)) {
5570 bool renderable =
true;
5572 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5573 if (tentative_referenceChart) {
5574 double chartMaxScale =
5575 tentative_referenceChart->GetNormalScaleMax(
5577 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5580 if (renderable)
break;
5583 candidate_stack_index++;
5588 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5589 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5590 while (candidate_stack_index >= 0) {
5591 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5595 int candidate_scale = cte_candidate.GetScale();
5596 int candidate_type = cte_candidate.GetChartType();
5598 if ((candidate_scale <= target_scale) &&
5599 (candidate_type == target_type))
5602 candidate_stack_index--;
5607 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5608 (candidate_stack_index < 0))
5609 candidate_stack_index = 0;
5611 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5613 m_pQuilt->SetReferenceChart(new_ref_index);
5619 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5624 bool renderable =
true;
5626 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5627 if (referenceChart) {
5628 double chartMaxScale = referenceChart->GetNormalScaleMax(
5630 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5631 proj =
ChartData->GetDBChartProj(ref_db_index);
5633 proj = PROJECTION_MERCATOR;
5635 VPoint.b_MercatorProjectionOverride =
5636 (m_pQuilt->GetnCharts() == 0 || !renderable);
5638 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5640 VPoint.SetProjectionType(proj);
5645 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5650 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5670 m_pQuilt->Invalidate();
5687 if (b_refresh) Refresh(
false);
5694 }
else if (!g_bopengl) {
5695 OcpnProjType projection = PROJECTION_UNKNOWN;
5698 projection = m_singleChart->GetChartProjectionType();
5699 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5700 VPoint.SetProjectionType(projection);
5704 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5705 m_cache_vp.Invalidate();
5709 UpdateCanvasControlBar();
5713 if (VPoint.GetBBox().GetValid()) {
5716 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5725 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5728 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5735 wxPoint2DDouble r, r1;
5737 double delta_check =
5741 double check_point = wxMin(89., VPoint.
clat);
5743 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5746 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5747 VPoint.
clon, 0, &rhumbDist);
5752 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5753 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5755 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5759 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5765 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5767 if (m_true_scale_ppm)
5768 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5773 double round_factor = 1000.;
5777 round_factor = 100.;
5779 round_factor = 1000.;
5782 double retina_coef = 1;
5786 retina_coef = GetContentScaleFactor();
5797 double true_scale_display =
5798 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5803 if (m_displayed_scale_factor > 10.0)
5804 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5805 m_displayed_scale_factor);
5806 else if (m_displayed_scale_factor > 1.0)
5807 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5808 m_displayed_scale_factor);
5809 else if (m_displayed_scale_factor > 0.1) {
5810 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5811 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5812 }
else if (m_displayed_scale_factor > 0.01) {
5813 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5814 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5817 "%s %4.0f (---)", _(
"Scale"),
5818 true_scale_display);
5821 m_scaleValue = true_scale_display;
5823 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5825 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5826 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5828 bool b_noshow =
false;
5832 wxClientDC dc(parent_frame->GetStatusBar());
5834 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5835 dc.SetFont(*templateFont);
5836 dc.GetTextExtent(text, &w, &h);
5841 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5842 if (w && w > rect.width) {
5843 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5847 dc.GetTextExtent(text, &w, &h);
5849 if (w && w > rect.width) {
5855 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5860 m_vLat = VPoint.
clat;
5861 m_vLon = VPoint.
clon;
5875static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5879static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5880 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5882wxColour ChartCanvas::PredColor() {
5885 if (SHIP_NORMAL == m_ownship_state)
5886 return GetGlobalColor(
"URED");
5888 else if (SHIP_LOWACCURACY == m_ownship_state)
5889 return GetGlobalColor(
"YELO1");
5891 return GetGlobalColor(
"NODTA");
5894wxColour ChartCanvas::ShipColor() {
5898 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5900 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5902 return GetGlobalColor(
"URED");
5905void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5906 wxPoint2DDouble lShipMidPoint) {
5907 dc.SetPen(wxPen(PredColor(), 2));
5909 if (SHIP_NORMAL == m_ownship_state)
5910 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5912 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5914 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5915 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5917 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5919 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5920 lShipMidPoint.m_y + 12);
5923void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5924 wxPoint GPSOffsetPixels,
5925 wxPoint2DDouble lGPSPoint) {
5930 float ref_dim = m_display_size_mm / 24;
5931 ref_dim = wxMin(ref_dim, 12);
5932 ref_dim = wxMax(ref_dim, 6);
5935 cPred.Set(g_cog_predictor_color);
5936 if (cPred == wxNullColour) cPred = PredColor();
5943 double nominal_line_width_pix = wxMax(
5945 floor(m_pix_per_mm / 2));
5949 if (nominal_line_width_pix > g_cog_predictor_width)
5950 g_cog_predictor_width = nominal_line_width_pix;
5953 wxPoint lPredPoint, lHeadPoint;
5955 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5956 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5958 double pred_lat, pred_lon;
5959 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5960 &pred_lat, &pred_lon);
5971 float ndelta_pix = 10.;
5972 double hdg_pred_lat, hdg_pred_lon;
5973 bool b_render_hdt =
false;
5974 if (!std::isnan(
gHdt)) {
5976 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5979 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5980 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5981 if (dist > ndelta_pix ) {
5982 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5983 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5988 wxPoint lShipMidPoint;
5989 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5990 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5991 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5992 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5994 if (lpp >= img_height / 2) {
5995 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5996 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5997 !std::isnan(
gSog)) {
5999 float dash_length = ref_dim;
6000 wxDash dash_long[2];
6002 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
6003 g_cog_predictor_width);
6004 dash_long[1] = dash_long[0] / 2.0;
6008 if (dash_length > 250.) {
6009 dash_long[0] = 250. / g_cog_predictor_width;
6010 dash_long[1] = dash_long[0] / 2;
6013 wxPen ppPen2(cPred, g_cog_predictor_width,
6014 (wxPenStyle)g_cog_predictor_style);
6015 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6016 ppPen2.SetDashes(2, dash_long);
6019 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6020 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
6022 if (g_cog_predictor_width > 1) {
6023 float line_width = g_cog_predictor_width / 3.;
6025 wxDash dash_long3[2];
6026 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
6027 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
6029 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
6030 (wxPenStyle)g_cog_predictor_style);
6031 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
6032 ppPen3.SetDashes(2, dash_long3);
6034 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
6035 lGPSPoint.m_y + GPSOffsetPixels.y,
6036 lPredPoint.x + GPSOffsetPixels.x,
6037 lPredPoint.y + GPSOffsetPixels.y);
6040 if (g_cog_predictor_endmarker) {
6042 double png_pred_icon_scale_factor = .4;
6043 if (g_ShipScaleFactorExp > 1.0)
6044 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6045 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
6049 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
6050 (
float)(lPredPoint.x - lShipMidPoint.x));
6051 cog_rad += (float)PI;
6053 for (
int i = 0; i < 4; i++) {
6055 double pxa = (double)(s_png_pred_icon[j]);
6056 double pya = (double)(s_png_pred_icon[j + 1]);
6058 pya *= png_pred_icon_scale_factor;
6059 pxa *= png_pred_icon_scale_factor;
6061 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
6062 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
6064 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
6065 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
6069 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
6072 dc.SetBrush(wxBrush(cPred));
6074 dc.StrokePolygon(4, icon);
6081 float hdt_dash_length = ref_dim * 0.4;
6083 cPred.Set(g_ownship_HDTpredictor_color);
6084 if (cPred == wxNullColour) cPred = PredColor();
6086 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
6087 : g_cog_predictor_width * 0.8);
6088 wxDash dash_short[2];
6090 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
6093 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
6096 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
6097 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
6098 ppPen2.SetDashes(2, dash_short);
6102 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
6103 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
6105 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
6107 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
6109 if (g_ownship_HDTpredictor_endmarker) {
6110 double nominal_circle_size_pixels = wxMax(
6111 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
6114 if (g_ShipScaleFactorExp > 1.0)
6115 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
6117 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
6118 lHeadPoint.y + GPSOffsetPixels.y,
6119 nominal_circle_size_pixels / 2);
6124 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6125 double factor = 1.00;
6126 if (g_pNavAidRadarRingsStepUnits == 1)
6128 else if (g_pNavAidRadarRingsStepUnits == 2) {
6129 if (std::isnan(
gSog))
6134 factor *= g_fNavAidRadarRingsStep;
6138 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6141 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6142 pow((
double)(lGPSPoint.m_y - r.y), 2));
6143 int pix_radius = (int)lpp;
6145 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6147 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6150 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6152 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6153 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6157void ChartCanvas::ComputeShipScaleFactor(
6158 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6159 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6160 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6161 float screenResolution = m_pix_per_mm;
6164 double ship_bow_lat, ship_bow_lon;
6165 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6166 &ship_bow_lat, &ship_bow_lon);
6167 wxPoint lShipBowPoint;
6168 wxPoint2DDouble b_point =
6172 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6173 powf((
float)(b_point.m_y - a_point.m_y), 2));
6176 float shipLength_mm = shipLength_px / screenResolution;
6179 float ownship_min_mm = g_n_ownship_min_mm;
6180 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6183 float hdt_ant = icon_hdt + 180.;
6184 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6185 float dx = g_n_gps_antenna_offset_x / 1852.;
6186 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6194 if (shipLength_mm < ownship_min_mm) {
6195 dy /= shipLength_mm / ownship_min_mm;
6196 dx /= shipLength_mm / ownship_min_mm;
6199 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6201 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6202 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6208 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6209 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6211 float scale_factor = shipLength_px / ownShipLength;
6214 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6217 scale_factor = wxMax(scale_factor, scale_factor_min);
6219 scale_factor_y = scale_factor;
6220 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6221 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6224void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6225 if (!GetVP().IsValid())
return;
6227 wxPoint GPSOffsetPixels(0, 0);
6228 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6231 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6232 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6236 lShipMidPoint = lGPSPoint;
6240 float icon_hdt = pCog;
6241 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6244 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6248 double osd_head_lat, osd_head_lon;
6249 wxPoint osd_head_point;
6251 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6256 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6257 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6258 icon_rad += (float)PI;
6260 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6264 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6268 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6269 if (GetVP().chart_scale >
6272 ShipDrawLargeScale(dc, lShipMidPoint);
6278 if (m_pos_image_user)
6279 pos_image = m_pos_image_user->Copy();
6280 else if (SHIP_NORMAL == m_ownship_state)
6281 pos_image = m_pos_image_red->Copy();
6282 if (SHIP_LOWACCURACY == m_ownship_state)
6283 pos_image = m_pos_image_yellow->Copy();
6284 else if (SHIP_NORMAL != m_ownship_state)
6285 pos_image = m_pos_image_grey->Copy();
6288 if (m_pos_image_user) {
6289 pos_image = m_pos_image_user->Copy();
6291 if (SHIP_LOWACCURACY == m_ownship_state)
6292 pos_image = m_pos_image_user_yellow->Copy();
6293 else if (SHIP_NORMAL != m_ownship_state)
6294 pos_image = m_pos_image_user_grey->Copy();
6297 img_height = pos_image.GetHeight();
6299 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6300 g_OwnShipIconType > 0)
6302 int ownShipWidth = 22;
6303 int ownShipLength = 84;
6304 if (g_OwnShipIconType == 1) {
6305 ownShipWidth = pos_image.GetWidth();
6306 ownShipLength = pos_image.GetHeight();
6309 float scale_factor_x, scale_factor_y;
6310 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6311 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6312 scale_factor_x, scale_factor_y);
6314 if (g_OwnShipIconType == 1) {
6315 pos_image.Rescale(ownShipWidth * scale_factor_x,
6316 ownShipLength * scale_factor_y,
6317 wxIMAGE_QUALITY_HIGH);
6318 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6320 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6323 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6324 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6325 if (rot_image.GetAlpha(ip, jp) > 64)
6326 rot_image.SetAlpha(ip, jp, 255);
6328 wxBitmap os_bm(rot_image);
6330 int w = os_bm.GetWidth();
6331 int h = os_bm.GetHeight();
6334 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6335 lShipMidPoint.m_y - h / 2,
true);
6338 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6339 lShipMidPoint.m_y - h / 2);
6340 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6341 lShipMidPoint.m_y - h / 2 + h);
6344 else if (g_OwnShipIconType == 2) {
6345 wxPoint ownship_icon[10];
6347 for (
int i = 0; i < 10; i++) {
6349 float pxa = (float)(s_ownship_icon[j]);
6350 float pya = (float)(s_ownship_icon[j + 1]);
6351 pya *= scale_factor_y;
6352 pxa *= scale_factor_x;
6354 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6355 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6357 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6358 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6361 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6363 dc.SetBrush(wxBrush(ShipColor()));
6365 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6368 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6370 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6374 img_height = ownShipLength * scale_factor_y;
6378 if (m_pos_image_user) circle_rad = 1;
6380 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6381 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6382 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6385 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6387 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6390 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6391 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6392 if (rot_image.GetAlpha(ip, jp) > 64)
6393 rot_image.SetAlpha(ip, jp, 255);
6395 wxBitmap os_bm(rot_image);
6397 if (g_ShipScaleFactorExp > 1) {
6398 wxImage scaled_image = os_bm.ConvertToImage();
6399 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6401 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6402 scaled_image.GetHeight() * factor,
6403 wxIMAGE_QUALITY_HIGH));
6405 int w = os_bm.GetWidth();
6406 int h = os_bm.GetHeight();
6409 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6410 lShipMidPoint.m_y - h / 2,
true);
6414 if (m_pos_image_user) circle_rad = 1;
6416 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6417 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6418 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6421 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6422 lShipMidPoint.m_y - h / 2);
6423 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6424 lShipMidPoint.m_y - h / 2 + h);
6429 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6442void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6443 float &MinorSpacing) {
6448 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6449 {.000001f, 45.0f, 15.0f},
6450 {.0002f, 30.0f, 10.0f},
6451 {.0003f, 10.0f, 2.0f},
6452 {.0008f, 5.0f, 1.0f},
6453 {.001f, 2.0f, 30.0f / 60.0f},
6454 {.003f, 1.0f, 20.0f / 60.0f},
6455 {.006f, 0.5f, 10.0f / 60.0f},
6456 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6457 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6458 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6459 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6460 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6461 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6462 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6463 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6466 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6467 if (view_scale_ppm < lltab[tabi][0])
break;
6468 MajorSpacing = lltab[tabi][1];
6469 MinorSpacing = lltab[tabi][2];
6483wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6484 int deg = (int)fabs(latlon);
6485 float min = fabs((fabs(latlon) - deg) * 60.0);
6495 }
else if (latlon < 0.0) {
6507 if (spacing >= 1.0) {
6508 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6509 }
else if (spacing >= (1.0 / 60.0)) {
6510 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6512 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6529void ChartCanvas::GridDraw(
ocpnDC &dc) {
6530 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6532 double nlat, elon, slat, wlon;
6535 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6537 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6539 if (!m_pgridFont) SetupGridFont();
6540 dc.SetFont(*m_pgridFont);
6541 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6544 h = m_canvas_height;
6555 dlon = dlon + 360.0;
6558 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6561 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6564 while (lat < nlat) {
6567 CalcGridText(lat, gridlatMajor,
true);
6569 dc.
DrawLine(0, r.y, w, r.y,
false);
6570 dc.DrawText(st, 0, r.y);
6571 lat = lat + gridlatMajor;
6573 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6577 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6580 while (lat < nlat) {
6583 dc.
DrawLine(0, r.y, 10, r.y,
false);
6584 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6585 lat = lat + gridlatMinor;
6589 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6592 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6595 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6597 wxString st = CalcGridText(lon, gridlonMajor,
false);
6599 dc.
DrawLine(r.x, 0, r.x, h,
false);
6600 dc.DrawText(st, r.x, 0);
6601 lon = lon + gridlonMajor;
6606 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6610 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6612 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6615 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6616 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6617 lon = lon + gridlonMinor;
6624void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6626 double blat, blon, tlat, tlon;
6629 int x_origin = m_bDisplayGrid ? 60 : 20;
6630 int y_origin = m_canvas_height - 50;
6636 if (GetVP().chart_scale > 80000)
6640 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6641 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6646 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6647 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6651 double rotation = -VPoint.
rotation;
6653 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6655 int l1 = (y_origin - r.y) / count;
6657 for (
int i = 0; i < count; i++) {
6664 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6667 double blat, blon, tlat, tlon;
6674 int y_origin = m_canvas_height - chartbar_height - 5;
6678 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6685 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6690 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6691 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6695 float places = floor(logdist), rem = logdist - places;
6696 dist = pow(10, places);
6703 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6704 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6705 double rotation = -VPoint.
rotation;
6711 int l1 = r.x - x_origin;
6713 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6718 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6719 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6720 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6722 if (!m_pgridFont) SetupGridFont();
6723 dc.SetFont(*m_pgridFont);
6724 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6726 dc.GetTextExtent(s, &w, &h);
6732 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6736void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6741 double ra_max = 40.;
6743 wxPen pen_save = dc.GetPen();
6745 wxDateTime now = wxDateTime::Now();
6751 x0 = x1 = x + radius;
6756 while (angle < 360.) {
6757 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6760 if (angle > 360.) angle = 360.;
6762 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6770 x1 = (int)(x + cos(angle * PI / 180.) * r);
6771 y1 = (int)(y + sin(angle * PI / 180.) * r);
6781 dc.
DrawLine(x + radius, y, x1, y1);
6783 dc.SetPen(pen_save);
6786static bool bAnchorSoundPlaying =
false;
6788static void onAnchorSoundFinished(
void *ptr) {
6789 o_sound::g_anchorwatch_sound->UnLoad();
6790 bAnchorSoundPlaying =
false;
6793void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6794 using namespace o_sound;
6796 bool play_sound =
false;
6798 if (AnchorAlertOn1) {
6799 wxPoint TargetPoint;
6802 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6803 TargetPoint.y, 100);
6807 AnchorAlertOn1 =
false;
6810 if (AnchorAlertOn2) {
6811 wxPoint TargetPoint;
6814 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6815 TargetPoint.y, 100);
6819 AnchorAlertOn2 =
false;
6822 if (!bAnchorSoundPlaying) {
6823 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6824 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6825 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6826 if (g_anchorwatch_sound->IsOk()) {
6827 bAnchorSoundPlaying =
true;
6828 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6829 g_anchorwatch_sound->Play();
6835void ChartCanvas::UpdateShips() {
6838 wxClientDC dc(
this);
6839 if (!dc.IsOk())
return;
6841 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6842 if (!test_bitmap.IsOk())
return;
6844 wxMemoryDC temp_dc(test_bitmap);
6846 temp_dc.ResetBoundingBox();
6847 temp_dc.DestroyClippingRegion();
6848 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6859 ocpndc.CalcBoundingBox(px.x, px.y);
6864 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6865 temp_dc.MaxY() - temp_dc.MinY());
6867 wxRect own_ship_update_rect = ship_draw_rect;
6869 if (!own_ship_update_rect.IsEmpty()) {
6872 own_ship_update_rect.Union(ship_draw_last_rect);
6873 own_ship_update_rect.Inflate(2);
6876 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6878 ship_draw_last_rect = ship_draw_rect;
6880 temp_dc.SelectObject(wxNullBitmap);
6883void ChartCanvas::UpdateAlerts() {
6888 wxClientDC dc(
this);
6892 dc.GetSize(&sx, &sy);
6895 wxBitmap test_bitmap(sx, sy, -1);
6899 temp_dc.SelectObject(test_bitmap);
6901 temp_dc.ResetBoundingBox();
6902 temp_dc.DestroyClippingRegion();
6903 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6910 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6911 temp_dc.MaxX() - temp_dc.MinX(),
6912 temp_dc.MaxY() - temp_dc.MinY());
6914 if (!alert_rect.IsEmpty())
6915 alert_rect.Inflate(2);
6917 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6920 wxRect alert_update_rect = alert_draw_rect;
6921 alert_update_rect.Union(alert_rect);
6924 RefreshRect(alert_update_rect,
false);
6928 alert_draw_rect = alert_rect;
6930 temp_dc.SelectObject(wxNullBitmap);
6933void ChartCanvas::UpdateAIS() {
6939 wxClientDC dc(
this);
6943 dc.GetSize(&sx, &sy);
6951 if (
g_pAIS->GetTargetList().size() > 10) {
6952 ais_rect = wxRect(0, 0, sx, sy);
6955 wxBitmap test_bitmap(sx, sy, -1);
6959 temp_dc.SelectObject(test_bitmap);
6961 temp_dc.ResetBoundingBox();
6962 temp_dc.DestroyClippingRegion();
6963 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6967 AISDraw(ocpndc, GetVP(),
this);
6968 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6972 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6973 temp_dc.MaxY() - temp_dc.MinY());
6975 if (!ais_rect.IsEmpty())
6976 ais_rect.Inflate(2);
6978 temp_dc.SelectObject(wxNullBitmap);
6981 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6984 wxRect ais_update_rect = ais_draw_rect;
6985 ais_update_rect.Union(ais_rect);
6988 RefreshRect(ais_update_rect,
false);
6992 ais_draw_rect = ais_rect;
6995void ChartCanvas::ToggleCPAWarn() {
6996 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
7002 g_bTCPA_Max =
false;
7006 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
7007 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
7009 if (!g_AisFirstTimeUse) {
7010 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
7011 _(
"CPA") +
" " + mess, 4, 4);
7016void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
7018void ChartCanvas::OnSize(wxSizeEvent &event) {
7019 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
7021 GetClientSize(&m_canvas_width, &m_canvas_height);
7025 m_displayScale = GetContentScaleFactor();
7029 m_canvas_width *= m_displayScale;
7030 m_canvas_height *= m_displayScale;
7043 m_absolute_min_scale_ppm =
7045 (1.2 * WGS84_semimajor_axis_meters * PI);
7048 gFrame->ProcessCanvasResize();
7058 SetMUIBarPosition();
7059 UpdateFollowButtonState();
7060 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7064 xr_margin = m_canvas_width * 95 / 100;
7065 xl_margin = m_canvas_width * 5 / 100;
7066 yt_margin = m_canvas_height * 5 / 100;
7067 yb_margin = m_canvas_height * 95 / 100;
7070 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
7075 m_brepaint_piano =
true;
7078 m_dc_route.SelectObject(wxNullBitmap);
7081 m_dc_route.SelectObject(*proute_bm);
7095 m_glcc->OnSize(event);
7104void ChartCanvas::ProcessNewGUIScale() {
7112void ChartCanvas::CreateMUIBar() {
7113 if (g_useMUI && !m_muiBar) {
7114 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7115 m_muiBar->SetColorScheme(m_cs);
7116 m_muiBarHOSize = m_muiBar->m_size;
7124 SetMUIBarPosition();
7125 UpdateFollowButtonState();
7126 m_muiBar->UpdateDynamicValues();
7127 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7131void ChartCanvas::SetMUIBarPosition() {
7135 int pianoWidth = GetClientSize().x * 0.6f;
7140 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7141 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7143 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7144 m_muiBar->SetColorScheme(m_cs);
7148 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7149 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7151 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7152 m_muiBar->SetColorScheme(m_cs);
7156 m_muiBar->SetBestPosition();
7160void ChartCanvas::DestroyMuiBar() {
7167void ChartCanvas::ShowCompositeInfoWindow(
7168 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7170 if (NULL == m_pCIWin) {
7175 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7178 s = _(
"Composite of ");
7181 s1.Printf(
"%d ", n_charts);
7189 s1.Printf(_(
"Chart scale"));
7192 s2.Printf(
"1:%d\n",
scale);
7196 s1 = _(
"Zoom in for more information");
7200 int char_width = s1.Length();
7201 int char_height = 3;
7203 if (g_bChartBarEx) {
7206 for (
int i : index_vector) {
7208 wxString path = cte.GetFullSystemPath();
7212 char_width = wxMax(char_width, path.Length());
7213 if (j++ >= 9)
break;
7216 s +=
" .\n .\n .\n";
7225 m_pCIWin->SetString(s);
7227 m_pCIWin->FitToChars(char_width, char_height);
7230 p.x = x / GetContentScaleFactor();
7231 if ((p.x + m_pCIWin->GetWinSize().x) >
7232 (m_canvas_width / GetContentScaleFactor()))
7233 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7234 m_pCIWin->GetWinSize().x) /
7237 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7238 4 - m_pCIWin->GetWinSize().y;
7240 m_pCIWin->dbIndex = 0;
7241 m_pCIWin->chart_scale = 0;
7242 m_pCIWin->SetPosition(p);
7243 m_pCIWin->SetBitmap();
7244 m_pCIWin->Refresh();
7248 HideChartInfoWindow();
7252void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7254 if (NULL == m_pCIWin) {
7259 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7268 dbIndex, FULL_INIT);
7270 int char_width, char_height;
7271 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7272 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7274 m_pCIWin->SetString(s);
7275 m_pCIWin->FitToChars(char_width, char_height);
7278 p.x = x / GetContentScaleFactor();
7279 if ((p.x + m_pCIWin->GetWinSize().x) >
7280 (m_canvas_width / GetContentScaleFactor()))
7281 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7282 m_pCIWin->GetWinSize().x) /
7285 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7286 4 - m_pCIWin->GetWinSize().y;
7288 m_pCIWin->dbIndex = dbIndex;
7289 m_pCIWin->SetPosition(p);
7290 m_pCIWin->SetBitmap();
7291 m_pCIWin->Refresh();
7295 HideChartInfoWindow();
7299void ChartCanvas::HideChartInfoWindow() {
7302 m_pCIWin->Destroy();
7306 androidForceFullRepaint();
7311void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7312 wxMouseEvent ev(wxEVT_MOTION);
7315 ev.m_leftDown = mouse_leftisdown;
7317 wxEvtHandler *evthp = GetEventHandler();
7319 ::wxPostEvent(evthp, ev);
7322void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7323 if ((m_panx_target_final - m_panx_target_now) ||
7324 (m_pany_target_final - m_pany_target_now)) {
7325 DoTimedMovementTarget();
7330void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7332bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7334 if (m_disable_edge_pan)
return false;
7337 int pan_margin = m_canvas_width * margin / 100;
7338 int pan_timer_set = 200;
7339 double pan_delta = GetVP().
pix_width * delta / 100;
7343 if (x > m_canvas_width - pan_margin) {
7348 else if (x < pan_margin) {
7353 if (y < pan_margin) {
7358 else if (y > m_canvas_height - pan_margin) {
7367 wxMouseState state = ::wxGetMouseState();
7368#if wxCHECK_VERSION(3, 0, 0)
7369 if (!state.LeftIsDown())
7371 if (!state.LeftDown())
7376 if ((bft) && !pPanTimer->IsRunning()) {
7378 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7384 if ((!bft) && pPanTimer->IsRunning()) {
7394void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7395 bool setBeingEdited) {
7396 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7397 m_pRoutePointEditTarget = NULL;
7398 m_pFoundPoint = NULL;
7401 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7402 SelectableItemList SelList =
pSelect->FindSelectionList(
7412 bool brp_viz =
false;
7413 if (m_pEditRouteArray) {
7414 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7415 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7416 if (pr->IsVisible()) {
7422 brp_viz = frp->IsVisible();
7426 if (m_pEditRouteArray)
7428 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7429 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7432 m_bRouteEditing = setBeingEdited;
7435 frp->m_bRPIsBeingEdited = setBeingEdited;
7436 m_bMarkEditing = setBeingEdited;
7439 m_pRoutePointEditTarget = frp;
7440 m_pFoundPoint = pFind;
7445std::shared_ptr<HostApi121::PiPointContext>
7446ChartCanvas::GetCanvasContextAtPoint(
int x,
int y) {
7460 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7461 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7462 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7463 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7464 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7468 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7471 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7476 int FoundAIS_MMSI = 0;
7478 FoundAIS_MMSI = pFindAIS->GetUserData();
7481 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7482 seltype |= SELTYPE_AISTARGET;
7488 Route *SelectedRoute = NULL;
7494 Route *pSelectedActiveRoute = NULL;
7495 Route *pSelectedVizRoute = NULL;
7498 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7499 SelectableItemList SelList =
7500 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7508 bool brp_viz =
false;
7510 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7512 if (pr->IsVisible()) {
7517 if (!brp_viz && prp->IsShared())
7519 brp_viz = prp->IsVisible();
7522 brp_viz = prp->IsVisible();
7524 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7530 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7533 pSelectedActiveRoute = pr;
7534 pFoundActiveRoutePoint = prp;
7539 if (NULL == pSelectedVizRoute) {
7540 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7542 if (pr->IsVisible()) {
7543 pSelectedVizRoute = pr;
7544 pFoundVizRoutePoint = prp;
7550 delete proute_array;
7555 if (pFoundActiveRoutePoint) {
7556 FoundRoutePoint = pFoundActiveRoutePoint;
7557 SelectedRoute = pSelectedActiveRoute;
7558 }
else if (pFoundVizRoutePoint) {
7559 FoundRoutePoint = pFoundVizRoutePoint;
7560 SelectedRoute = pSelectedVizRoute;
7563 FoundRoutePoint = pFirstVizPoint;
7565 if (SelectedRoute) {
7566 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7567 }
else if (FoundRoutePoint) {
7568 seltype |= SELTYPE_MARKPOINT;
7573 if (m_pFoundRoutePoint) {
7577 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7578 RefreshRect(wp_rect,
true);
7587 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7588 SelectableItemList SelList =
7589 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7591 if (NULL == SelectedRoute)
7596 if (pr->IsVisible()) {
7603 if (SelectedRoute) {
7604 if (NULL == FoundRoutePoint)
7605 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7608 seltype |= SELTYPE_ROUTESEGMENT;
7612 if (pFindTrackSeg) {
7613 m_pSelectedTrack = NULL;
7614 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7615 SelectableItemList SelList =
7616 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7621 if (pt->IsVisible()) {
7622 m_pSelectedTrack = pt;
7626 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7629 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7632 auto rstruct = std::make_shared<HostApi121::PiPointContext>();
7633 rstruct->object_type = HostApi121::PiContextObjectType::kObjectChart;
7634 rstruct->object_ident =
"";
7636 if (seltype == SELTYPE_AISTARGET) {
7637 rstruct->object_type = HostApi121::PiContextObjectType::kObjectAisTarget;
7639 val.Printf(
"%d", FoundAIS_MMSI);
7640 rstruct->object_ident = val.ToStdString();
7641 }
else if (seltype & SELTYPE_MARKPOINT) {
7642 if (FoundRoutePoint) {
7643 rstruct->object_type = HostApi121::PiContextObjectType::kObjectRoutepoint;
7644 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7646 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7647 if (SelectedRoute) {
7648 rstruct->object_type =
7649 HostApi121::PiContextObjectType::kObjectRoutesegment;
7650 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7652 }
else if (seltype & SELTYPE_TRACKSEGMENT) {
7653 if (m_pSelectedTrack) {
7654 rstruct->object_type =
7655 HostApi121::PiContextObjectType::kObjectTracksegment;
7656 rstruct->object_ident = m_pSelectedTrack->m_GUID.ToStdString();
7663void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7664 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7665 singleClickEventIsValid =
false;
7666 m_DoubleClickTimer->Stop();
7671bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7672 if (!m_bChartDragging && !m_bDrawingRoute) {
7677 if (m_Compass && m_Compass->IsShown()) {
7679 bool isInCompass = logicalRect.Contains(event.GetPosition());
7680 if (isInCompass || m_mouseWasInCompass) {
7681 if (m_Compass->MouseEvent(event)) {
7682 cursor_region = CENTER;
7683 if (!g_btouch) SetCanvasCursor(event);
7684 m_mouseWasInCompass = isInCompass;
7688 m_mouseWasInCompass = isInCompass;
7691 if (m_notification_button && m_notification_button->IsShown()) {
7693 bool isinButton = logicalRect.Contains(event.GetPosition());
7695 SetCursor(*pCursorArrow);
7696 if (event.LeftDown()) HandleNotificationMouseClick();
7701 if (MouseEventToolbar(event))
return true;
7703 if (MouseEventChartBar(event))
return true;
7705 if (MouseEventMUIBar(event))
return true;
7707 if (MouseEventIENCBar(event))
return true;
7712void ChartCanvas::HandleNotificationMouseClick() {
7713 if (!m_NotificationsList) {
7717 m_NotificationsList->RecalculateSize();
7718 m_NotificationsList->Hide();
7721 if (m_NotificationsList->IsShown()) {
7722 m_NotificationsList->Hide();
7724 m_NotificationsList->RecalculateSize();
7725 m_NotificationsList->ReloadNotificationList();
7726 m_NotificationsList->Show();
7729bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7730 if (!g_bShowChartBar)
return false;
7732 if (!m_Piano->MouseEvent(event))
return false;
7734 cursor_region = CENTER;
7735 if (!g_btouch) SetCanvasCursor(event);
7739bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7740 if (!IsPrimaryCanvas())
return false;
7749 cursor_region = CENTER;
7750 if (!g_btouch) SetCanvasCursor(event);
7754bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7755 if (!IsPrimaryCanvas())
return false;
7768bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7770 if (!m_muiBar->MouseEvent(event))
return false;
7773 cursor_region = CENTER;
7774 if (!g_btouch) SetCanvasCursor(event);
7786 event.GetPosition(&x, &y);
7788 x *= m_displayScale;
7789 y *= m_displayScale;
7791 m_MouseDragging =
event.Dragging();
7797 if (event.Dragging()) {
7798 if ((x == mouse_x) && (y == mouse_y))
return true;
7804 mouse_leftisdown =
event.LeftDown();
7808 cursor_region = CENTER;
7812 if (m_Compass && m_Compass->IsShown() &&
7813 m_Compass->
GetRect().Contains(event.GetPosition())) {
7814 cursor_region = CENTER;
7815 }
else if (x > xr_margin) {
7816 cursor_region = MID_RIGHT;
7817 }
else if (x < xl_margin) {
7818 cursor_region = MID_LEFT;
7819 }
else if (y > yb_margin - chartbar_height &&
7820 y < m_canvas_height - chartbar_height) {
7821 cursor_region = MID_TOP;
7822 }
else if (y < yt_margin) {
7823 cursor_region = MID_BOT;
7825 cursor_region = CENTER;
7828 if (!g_btouch) SetCanvasCursor(event);
7832 leftIsDown =
event.LeftDown();
7835 if (event.LeftDown()) {
7836 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7839 g_bTempShowMenuBar =
false;
7840 parent_frame->ApplyGlobalSettings(
false);
7848 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7849 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7853 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7854 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7857 event.SetEventObject(
this);
7858 if (SendMouseEventToPlugins(event))
7865 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7866 StartChartDragInertia();
7869 if (!g_btouch && b_handle_dclick && event.LeftUp() &&
7870 !singleClickEventIsValid) {
7872 if (m_DoubleClickTimer->IsRunning()) {
7873 m_DoubleClickTimer->Stop();
7878 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7879 singleClickEvent = event;
7880 singleClickEventIsValid =
true;
7889 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7890 if (g_click_stop > 0) {
7898 if (GetUpMode() == COURSE_UP_MODE) {
7899 m_b_rot_hidef =
false;
7900 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7902 pRotDefTimer->Stop();
7905 bool bRoll = !g_btouch;
7910 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7911 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7912 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7913 m_RolloverPopupTimer.Start(
7917 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7921 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7930#if !defined(__WXGTK__) && !defined(__WXQT__)
7938 if ((x >= 0) && (y >= 0))
7943 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7944 wxPoint p = ClientToScreen(wxPoint(x, y));
7950 if (m_routeState >= 2) {
7953 m_bDrawingRoute =
true;
7955 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7960 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7963 m_bDrawingRoute =
true;
7965 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7978#if defined(__WXMAC__) || defined(__ANDROID__)
7982 wxClientDC cdc(GetParent());
7994 if (m_pSelectedRoute) {
7996 m_pSelectedRoute->DeSelectRoute();
7998 if (g_bopengl && m_glcc) {
8003 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8006 if (m_pFoundRoutePoint) {
8014 if (g_btouch && m_pRoutePointEditTarget) {
8017 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8021 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8022 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
8023 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8024 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8025 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8029 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8032 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
8038 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8041 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
8042 seltype |= SELTYPE_AISTARGET;
8047 m_pFoundRoutePoint = NULL;
8052 Route *pSelectedActiveRoute = NULL;
8053 Route *pSelectedVizRoute = NULL;
8056 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8057 SelectableItemList SelList =
8058 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8066 bool brp_viz =
false;
8068 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8070 if (pr->IsVisible()) {
8075 if (!brp_viz && prp->IsShared())
8077 brp_viz = prp->IsVisible();
8080 brp_viz = prp->IsVisible();
8082 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8087 m_pSelectedRoute = NULL;
8089 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8092 pSelectedActiveRoute = pr;
8093 pFoundActiveRoutePoint = prp;
8098 if (NULL == pSelectedVizRoute) {
8099 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8101 if (pr->IsVisible()) {
8102 pSelectedVizRoute = pr;
8103 pFoundVizRoutePoint = prp;
8109 delete proute_array;
8114 if (pFoundActiveRoutePoint) {
8115 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8116 m_pSelectedRoute = pSelectedActiveRoute;
8117 }
else if (pFoundVizRoutePoint) {
8118 m_pFoundRoutePoint = pFoundVizRoutePoint;
8119 m_pSelectedRoute = pSelectedVizRoute;
8122 m_pFoundRoutePoint = pFirstVizPoint;
8124 if (m_pSelectedRoute) {
8125 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8126 }
else if (m_pFoundRoutePoint) {
8127 seltype |= SELTYPE_MARKPOINT;
8131 if (m_pFoundRoutePoint) {
8135 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8136 RefreshRect(wp_rect,
true);
8144 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8145 SelectableItemList SelList =
8146 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8148 if (NULL == m_pSelectedRoute)
8153 if (pr->IsVisible()) {
8154 m_pSelectedRoute = pr;
8160 if (m_pSelectedRoute) {
8161 if (NULL == m_pFoundRoutePoint)
8162 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8167 if (g_bopengl && m_glcc) {
8172 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8174 seltype |= SELTYPE_ROUTESEGMENT;
8178 if (pFindTrackSeg) {
8179 m_pSelectedTrack = NULL;
8180 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8181 SelectableItemList SelList =
8182 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8187 if (pt->IsVisible()) {
8188 m_pSelectedTrack = pt;
8192 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8198 m_pIDXCandidate = FindBestCurrentObject(slat, slon);
8199 seltype |= SELTYPE_CURRENTPOINT;
8202 else if (pFindTide) {
8203 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8204 seltype |= SELTYPE_TIDEPOINT;
8209 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8214IDX_entry *ChartCanvas::FindBestCurrentObject(
double lat,
double lon) {
8224 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8225 SelectableItemList SelList =
8226 pSelectTC->FindSelectionList(ctx, lat, lon, SELTYPE_CURRENTPOINT);
8229 pFind = *SelList.begin();
8230 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8232 auto node = SelList.begin();
8233 if (SelList.size() > 1) {
8234 for (++node; node != SelList.end(); ++node) {
8237 if (pIDX_candidate->
IDX_type ==
'c') {
8238 pIDX_best_candidate = pIDX_candidate;
8243 pFind = *SelList.begin();
8244 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8247 return pIDX_best_candidate;
8249void ChartCanvas::CallPopupMenu(
int x,
int y) {
8253 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8261 if (SELTYPE_CURRENTPOINT == seltype) {
8267 if (SELTYPE_TIDEPOINT == seltype) {
8273 InvokeCanvasMenu(x, y, seltype);
8276 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8280 m_pSelectedRoute = NULL;
8282 if (m_pFoundRoutePoint) {
8283 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8286 m_pFoundRoutePoint = NULL;
8292bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8300 event.GetPosition(&x, &y);
8306 SelectRadius = g_Platform->GetSelectRadiusPix() /
8307 (m_true_scale_ppm * 1852 * 60);
8314 if (event.LeftDClick() && (cursor_region == CENTER)) {
8315 m_DoubleClickTimer->Start();
8316 singleClickEventIsValid =
false;
8322 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8325 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8328 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8329 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8330 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8336 SelectableItemList rpSelList =
8337 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8338 bool b_onRPtarget =
false;
8341 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8342 b_onRPtarget =
true;
8350 std::unique_ptr<HostApi> host_api =
GetHostApi();
8351 auto *api_121 =
dynamic_cast<HostApi121 *
>(host_api.get());
8353 if (m_pRoutePointEditTarget) {
8355 if ((api_121->GetContextMenuMask() &
8356 api_121->kContextMenuDisableWaypoint))
8358 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8364 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8367 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8368 m_pRoutePointEditTarget = NULL;
8369 RefreshRect(wp_rect,
true);
8373 auto node = rpSelList.begin();
8374 if (node != rpSelList.end()) {
8378 wxArrayPtrVoid *proute_array =
8383 bool brp_viz =
false;
8385 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8387 if (pr->IsVisible()) {
8392 delete proute_array;
8396 brp_viz = frp->IsVisible();
8398 brp_viz = frp->IsVisible();
8401 if ((api_121->GetContextMenuMask() &
8402 api_121->kContextMenuDisableWaypoint))
8405 ShowMarkPropertiesDialog(frp);
8414 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8416 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableRoute))
8419 if (pr->IsVisible()) {
8420 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8425 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8427 if ((api_121->GetContextMenuMask() & api_121->kContextMenuDisableTrack))
8430 if (pt->IsVisible()) {
8431 ShowTrackPropertiesDialog(pt);
8440 if (m_bShowCurrent) {
8442 pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_CURRENTPOINT);
8444 m_pIDXCandidate = FindBestCurrentObject(zlat, zlon);
8452 pFindTide =
pSelectTC->FindSelection(ctx, zlat, zlon, SELTYPE_TIDEPOINT);
8454 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8462 ShowObjectQueryWindow(x, y, zlat, zlon);
8467 if (event.LeftDown()) {
8483 bool appending =
false;
8484 bool inserting =
false;
8487 SetCursor(*pCursorPencil);
8491 m_bRouteEditing =
true;
8493 if (m_routeState == 1) {
8494 m_pMouseRoute =
new Route();
8495 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8505 double nearby_radius_meters =
8506 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8509 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8510 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8511 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8512 wxArrayPtrVoid *proute_array =
8517 bool brp_viz =
false;
8519 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8521 if (pr->IsVisible()) {
8526 delete proute_array;
8528 pNearbyPoint->IsShared())
8531 pNearbyPoint->IsVisible();
8533 brp_viz = pNearbyPoint->IsVisible();
8536 wxString msg = _(
"Use nearby waypoint?");
8538 const bool noname(pNearbyPoint->GetName() ==
"");
8541 _(
"Use nearby nameless waypoint and name it M with"
8542 " a unique number?");
8545 m_FinishRouteOnKillFocus =
false;
8547 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8548 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8549 m_FinishRouteOnKillFocus =
true;
8550 if (dlg_return == wxID_YES) {
8552 if (m_pMouseRoute) {
8553 int last_wp_num = m_pMouseRoute->GetnPoints();
8555 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8556 wxString wp_name = wxString::Format(
8557 "M%002i-%s", last_wp_num + 1, guid_short);
8558 pNearbyPoint->SetName(wp_name);
8560 pNearbyPoint->SetName(
"WPXX");
8562 pMousePoint = pNearbyPoint;
8565 if (m_routeState > 1)
8566 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8567 Undo_HasParent, NULL);
8570 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8571 bool procede =
false;
8575 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8581 m_FinishRouteOnKillFocus =
false;
8587 _(
"Insert first part of this route in the new route?");
8588 if (tail->GetIndexOf(pMousePoint) ==
8591 dmsg = _(
"Insert this route in the new route?");
8593 if (tail->GetIndexOf(pMousePoint) != 1) {
8594 dlg_return = OCPNMessageBox(
8595 this, dmsg, _(
"OpenCPN Route Create"),
8596 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8597 m_FinishRouteOnKillFocus =
true;
8599 if (dlg_return == wxID_YES) {
8606 _(
"Append last part of this route to the new route?");
8607 if (tail->GetIndexOf(pMousePoint) == 1)
8609 "Append this route to the new route?");
8614 if (tail->GetLastPoint() != pMousePoint) {
8615 dlg_return = OCPNMessageBox(
8616 this, dmsg, _(
"OpenCPN Route Create"),
8617 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8618 m_FinishRouteOnKillFocus =
true;
8620 if (dlg_return == wxID_YES) {
8631 if (!FindRouteContainingWaypoint(pMousePoint))
8632 pMousePoint->SetShared(
true);
8637 if (NULL == pMousePoint) {
8638 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8640 pMousePoint->SetNameShown(
false);
8644 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8646 if (m_routeState > 1)
8647 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8648 Undo_IsOrphanded, NULL);
8651 if (m_pMouseRoute) {
8652 if (m_routeState == 1) {
8654 m_pMouseRoute->AddPoint(pMousePoint);
8658 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8659 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8660 &rhumbBearing, &rhumbDist);
8661 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8662 rlat, &gcDist, &gcBearing, NULL);
8663 double gcDistNM = gcDist / 1852.0;
8666 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8667 pow(rhumbDist - gcDistNM - 1, 0.5);
8670 msg << _(
"For this leg the Great Circle route is ")
8672 << _(
" shorter than rhumbline.\n\n")
8673 << _(
"Would you like include the Great Circle routing points "
8676 m_FinishRouteOnKillFocus =
false;
8677 m_disable_edge_pan =
true;
8680 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8681 wxYES_NO | wxNO_DEFAULT);
8683 m_disable_edge_pan =
false;
8684 m_FinishRouteOnKillFocus =
true;
8686 if (answer == wxID_YES) {
8688 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8689 wxRealPoint gcCoord;
8691 for (
int i = 1; i <= segmentCount; i++) {
8692 double fraction = (double)i * (1.0 / (
double)segmentCount);
8693 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8694 gcDist * fraction, gcBearing,
8695 &gcCoord.x, &gcCoord.y, NULL);
8697 if (i < segmentCount) {
8698 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8700 gcPoint->SetNameShown(
false);
8702 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8704 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8707 gcPoint = pMousePoint;
8710 m_pMouseRoute->AddPoint(gcPoint);
8711 pSelect->AddSelectableRouteSegment(
8712 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8713 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8714 prevGcPoint = gcPoint;
8717 undo->CancelUndoableAction(
true);
8720 m_pMouseRoute->AddPoint(pMousePoint);
8721 pSelect->AddSelectableRouteSegment(
8722 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8723 pMousePoint, m_pMouseRoute);
8724 undo->AfterUndoableAction(m_pMouseRoute);
8728 m_pMouseRoute->AddPoint(pMousePoint);
8729 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8730 rlon, m_prev_pMousePoint,
8731 pMousePoint, m_pMouseRoute);
8732 undo->AfterUndoableAction(m_pMouseRoute);
8738 m_prev_pMousePoint = pMousePoint;
8746 int connect = tail->GetIndexOf(pMousePoint);
8751 int length = tail->GetnPoints();
8756 start = connect + 1;
8761 m_pMouseRoute->RemovePoint(
8765 for (i = start; i <= stop; i++) {
8766 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8769 m_pMouseRoute->GetnPoints();
8771 gFrame->RefreshAllCanvas();
8775 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8777 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8778 m_pMouseRoute->FinalizeForRendering();
8780 gFrame->RefreshAllCanvas();
8784 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8786 SetCursor(*pCursorPencil);
8788 if (!m_pMeasureRoute) {
8789 m_pMeasureRoute =
new Route();
8793 if (m_nMeasureState == 1) {
8800 wxEmptyString, wxEmptyString);
8802 pMousePoint->SetShowWaypointRangeRings(
false);
8804 m_pMeasureRoute->AddPoint(pMousePoint);
8808 m_prev_pMousePoint = pMousePoint;
8812 gFrame->RefreshAllCanvas();
8817 FindRoutePointsAtCursor(SelectRadius,
true);
8821 m_last_touch_down_pos =
event.GetPosition();
8823 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8831 if (ret)
return true;
8834 if (event.Dragging()) {
8837 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8839 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8841 SelectableItemList SelList =
pSelect->FindSelectionList(
8845 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8850 if (m_pRoutePointEditTarget &&
8851 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8853 SelectableItemList SelList =
pSelect->FindSelectionList(
8857 if (m_pRoutePointEditTarget == frp) {
8858 m_bIsInRadius =
true;
8863 if (!m_dragoffsetSet) {
8865 .PresetDragOffset(
this, mouse_x, mouse_y);
8866 m_dragoffsetSet =
true;
8871 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8872 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8875 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8877 DraggingAllowed =
false;
8879 if (m_pRoutePointEditTarget &&
8880 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8881 DraggingAllowed =
false;
8883 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8885 if (DraggingAllowed) {
8886 if (!undo->InUndoableAction()) {
8887 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8888 Undo_NeedsCopy, m_pFoundPoint);
8894 if (!g_bopengl && m_pEditRouteArray) {
8895 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8896 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8903 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8904 pre_rect.Union(route_rect);
8912 if (CheckEdgePan(x, y,
true, 5, 2))
8920 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8922 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8923 m_pRoutePointEditTarget,
8924 SELTYPE_DRAGHANDLE);
8925 m_pFoundPoint->m_slat =
8926 m_pRoutePointEditTarget->m_lat;
8927 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8929 m_pRoutePointEditTarget->m_lat =
8931 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8932 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8933 m_pFoundPoint->m_slat =
8935 m_pFoundPoint->m_slon = new_cursor_lon;
8951 if (m_pEditRouteArray) {
8952 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8954 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8957 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8958 post_rect.Union(route_rect);
8964 pre_rect.Union(post_rect);
8965 RefreshRect(pre_rect,
false);
8967 gFrame->RefreshCanvasOther(
this);
8968 m_bRoutePoinDragging =
true;
8973 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8974 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8977 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8979 DraggingAllowed =
false;
8981 if (m_pRoutePointEditTarget &&
8982 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8983 DraggingAllowed =
false;
8985 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8987 if (DraggingAllowed) {
8988 if (!undo->InUndoableAction()) {
8989 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8990 Undo_NeedsCopy, m_pFoundPoint);
9004 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
9010 .CalculateDCRect(m_dc_route,
this, &pre_rect);
9011 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
9012 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
9013 (
int)(lppmax - (pre_rect.height / 2)));
9021 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
9024 m_pRoutePointEditTarget,
9025 SELTYPE_DRAGHANDLE);
9026 m_pFoundPoint->m_slat =
9027 m_pRoutePointEditTarget->m_lat;
9028 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
9030 m_pRoutePointEditTarget->m_lat =
9033 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
9046 if (!g_btouch) InvalidateGL();
9052 .CalculateDCRect(m_dc_route,
this, &post_rect);
9053 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
9054 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
9055 (
int)(lppmax - (post_rect.height / 2)));
9058 pre_rect.Union(post_rect);
9059 RefreshRect(pre_rect,
false);
9061 gFrame->RefreshCanvasOther(
this);
9062 m_bRoutePoinDragging =
true;
9064 ret = g_btouch ? m_bRoutePoinDragging :
true;
9067 if (ret)
return true;
9070 if (event.LeftUp()) {
9071 bool b_startedit_route =
false;
9072 m_dragoffsetSet =
false;
9075 m_bChartDragging =
false;
9076 m_bIsInRadius =
false;
9080 if (m_ignore_next_leftup) {
9081 m_ignore_next_leftup =
false;
9086 m_bedge_pan =
false;
9091 bool appending =
false;
9092 bool inserting =
false;
9098 if (m_pRoutePointEditTarget) {
9104 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9105 RefreshRect(wp_rect,
true);
9107 m_pRoutePointEditTarget = NULL;
9109 m_bRouteEditing =
true;
9111 if (m_routeState == 1) {
9112 m_pMouseRoute =
new Route();
9113 m_pMouseRoute->SetHiLite(50);
9117 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9124 double nearby_radius_meters =
9125 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9128 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9129 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9130 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9133 m_FinishRouteOnKillFocus =
9135 dlg_return = OCPNMessageBox(
9136 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9137 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9138 m_FinishRouteOnKillFocus =
true;
9140 dlg_return = wxID_YES;
9142 if (dlg_return == wxID_YES) {
9143 pMousePoint = pNearbyPoint;
9146 if (m_routeState > 1)
9147 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9148 Undo_HasParent, NULL);
9149 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9151 bool procede =
false;
9155 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9161 m_FinishRouteOnKillFocus =
false;
9162 if (m_routeState == 1) {
9166 _(
"Insert first part of this route in the new route?");
9167 if (tail->GetIndexOf(pMousePoint) ==
9170 dmsg = _(
"Insert this route in the new route?");
9172 if (tail->GetIndexOf(pMousePoint) != 1) {
9174 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9175 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9176 m_FinishRouteOnKillFocus =
true;
9178 if (dlg_return == wxID_YES) {
9185 _(
"Append last part of this route to the new route?");
9186 if (tail->GetIndexOf(pMousePoint) == 1)
9188 "Append this route to the new route?");
9192 if (tail->GetLastPoint() != pMousePoint) {
9194 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9195 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9196 m_FinishRouteOnKillFocus =
true;
9198 if (dlg_return == wxID_YES) {
9209 if (!FindRouteContainingWaypoint(pMousePoint))
9210 pMousePoint->SetShared(
true);
9214 if (NULL == pMousePoint) {
9215 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9217 pMousePoint->SetNameShown(
false);
9219 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9221 if (m_routeState > 1)
9222 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9223 Undo_IsOrphanded, NULL);
9226 if (m_routeState == 1) {
9228 m_pMouseRoute->AddPoint(pMousePoint);
9229 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9233 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9234 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9235 &rhumbBearing, &rhumbDist);
9236 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9237 &gcDist, &gcBearing, NULL);
9238 double gcDistNM = gcDist / 1852.0;
9241 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9242 pow(rhumbDist - gcDistNM - 1, 0.5);
9245 msg << _(
"For this leg the Great Circle route is ")
9247 << _(
" shorter than rhumbline.\n\n")
9248 << _(
"Would you like include the Great Circle routing points "
9252 m_FinishRouteOnKillFocus =
false;
9253 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9254 wxYES_NO | wxNO_DEFAULT);
9255 m_FinishRouteOnKillFocus =
true;
9257 int answer = wxID_NO;
9260 if (answer == wxID_YES) {
9262 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9263 wxRealPoint gcCoord;
9265 for (
int i = 1; i <= segmentCount; i++) {
9266 double fraction = (double)i * (1.0 / (
double)segmentCount);
9267 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9268 gcDist * fraction, gcBearing,
9269 &gcCoord.x, &gcCoord.y, NULL);
9271 if (i < segmentCount) {
9272 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9274 gcPoint->SetNameShown(
false);
9275 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9278 gcPoint = pMousePoint;
9281 m_pMouseRoute->AddPoint(gcPoint);
9282 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9284 pSelect->AddSelectableRouteSegment(
9285 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9286 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9287 prevGcPoint = gcPoint;
9290 undo->CancelUndoableAction(
true);
9293 m_pMouseRoute->AddPoint(pMousePoint);
9294 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9295 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9296 rlon, m_prev_pMousePoint,
9297 pMousePoint, m_pMouseRoute);
9298 undo->AfterUndoableAction(m_pMouseRoute);
9302 m_pMouseRoute->AddPoint(pMousePoint);
9303 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9305 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9306 rlon, m_prev_pMousePoint,
9307 pMousePoint, m_pMouseRoute);
9308 undo->AfterUndoableAction(m_pMouseRoute);
9314 m_prev_pMousePoint = pMousePoint;
9321 int connect = tail->GetIndexOf(pMousePoint);
9326 int length = tail->GetnPoints();
9331 start = connect + 1;
9336 m_pMouseRoute->RemovePoint(
9340 for (i = start; i <= stop; i++) {
9341 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9344 m_pMouseRoute->GetnPoints();
9346 gFrame->RefreshAllCanvas();
9350 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9352 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9353 m_pMouseRoute->FinalizeForRendering();
9358 }
else if (m_bMeasure_Active && m_nMeasureState)
9361 m_bedge_pan =
false;
9365 if (m_ignore_next_leftup) {
9366 m_ignore_next_leftup =
false;
9370 if (m_nMeasureState == 1) {
9371 m_pMeasureRoute =
new Route();
9377 if (m_pMeasureRoute) {
9380 wxEmptyString, wxEmptyString);
9383 m_pMeasureRoute->AddPoint(pMousePoint);
9387 m_prev_pMousePoint = pMousePoint;
9389 m_pMeasureRoute->GetnPoints();
9393 CancelMeasureRoute();
9399 bool bSelectAllowed =
true;
9401 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9403 bSelectAllowed =
false;
9407 int significant_drag = g_Platform->GetSelectRadiusPix() * 2;
9408 if ((abs(m_last_touch_down_pos.x - event.GetPosition().x) >
9409 significant_drag) ||
9410 (abs(m_last_touch_down_pos.y - event.GetPosition().y) >
9411 significant_drag)) {
9412 bSelectAllowed =
false;
9420 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9422 if (bSelectAllowed) {
9423 bool b_was_editing_mark = m_bMarkEditing;
9424 bool b_was_editing_route = m_bRouteEditing;
9425 FindRoutePointsAtCursor(SelectRadius,
9431 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9432 m_pRoutePointEditTarget = NULL;
9434 if (!b_was_editing_route) {
9435 if (m_pEditRouteArray) {
9436 b_startedit_route =
true;
9440 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9441 m_pTrackRolloverWin->IsActive(
false);
9443 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9444 m_pRouteRolloverWin->IsActive(
false);
9448 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9450 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9458 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9459 pre_rect.Union(route_rect);
9462 RefreshRect(pre_rect,
true);
9465 b_startedit_route =
false;
9469 if (m_pRoutePointEditTarget) {
9470 if (b_was_editing_mark ||
9471 b_was_editing_route) {
9472 if (m_lastRoutePointEditTarget) {
9476 .EnableDragHandle(
false);
9477 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9478 SELTYPE_DRAGHANDLE);
9482 if (m_pRoutePointEditTarget) {
9485 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9486 wxPoint2DDouble dragHandlePoint =
9488 .GetDragHandlePoint(
this);
9490 dragHandlePoint.m_y, dragHandlePoint.m_x,
9491 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9494 if (m_lastRoutePointEditTarget) {
9498 .EnableDragHandle(
false);
9499 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9500 SELTYPE_DRAGHANDLE);
9503 wxArrayPtrVoid *lastEditRouteArray =
9505 m_lastRoutePointEditTarget);
9506 if (lastEditRouteArray) {
9507 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9509 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9514 delete lastEditRouteArray;
9525 if (m_lastRoutePointEditTarget) {
9528 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9529 RefreshRect(wp_rect,
true);
9532 if (m_pRoutePointEditTarget) {
9535 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9536 RefreshRect(wp_rect,
true);
9544 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9545 bool b_start_rollover =
false;
9549 if (pFind) b_start_rollover =
true;
9552 if (!b_start_rollover && !b_startedit_route) {
9553 SelectableItemList SelList =
pSelect->FindSelectionList(
9557 if (pr && pr->IsVisible()) {
9558 b_start_rollover =
true;
9564 if (!b_start_rollover && !b_startedit_route) {
9565 SelectableItemList SelList =
pSelect->FindSelectionList(
9569 if (tr && tr->IsVisible()) {
9570 b_start_rollover =
true;
9576 if (b_start_rollover)
9577 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9581 bool appending =
false;
9582 bool inserting =
false;
9584 if (m_bRouteEditing ) {
9586 if (m_pRoutePointEditTarget) {
9592 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9593 double nearby_radius_meters =
9594 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9595 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9596 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9597 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9599 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9603 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9605 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9609 std::find(list->begin(), list->end(), pNearbyPoint);
9610 if (pos != list->end()) {
9622 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9627 OCPNMessageBox(
this,
9628 _(
"Replace this RoutePoint by the nearby "
9630 _(
"OpenCPN RoutePoint change"),
9631 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9632 if (dlg_return == wxID_YES) {
9637 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9640 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9642 if (tail && current && (tail != current)) {
9644 connect = tail->GetIndexOf(pNearbyPoint);
9645 int index_current_route =
9646 current->GetIndexOf(m_pRoutePointEditTarget);
9647 index_last = current->GetIndexOf(current->GetLastPoint());
9648 dlg_return1 = wxID_NO;
9650 index_current_route) {
9652 if (connect != tail->GetnPoints()) {
9655 _(
"Last part of route to be appended to dragged "
9659 _(
"Full route to be appended to dragged route?");
9661 dlg_return1 = OCPNMessageBox(
9662 this, dmsg, _(
"OpenCPN Route Create"),
9663 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9664 if (dlg_return1 == wxID_YES) {
9668 }
else if (index_current_route ==
9673 _(
"First part of route to be inserted into dragged "
9675 if (connect == tail->GetnPoints())
9677 "Full route to be inserted into dragged route?");
9679 dlg_return1 = OCPNMessageBox(
9680 this, dmsg, _(
"OpenCPN Route Create"),
9681 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9682 if (dlg_return1 == wxID_YES) {
9689 if (m_pRoutePointEditTarget->IsShared()) {
9691 dlg_return = OCPNMessageBox(
9693 _(
"Do you really want to delete and replace this "
9695 "\n" + _(
"which has been created manually?"),
9696 (
"OpenCPN RoutePoint warning"),
9697 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9700 if (dlg_return == wxID_YES) {
9701 pMousePoint = pNearbyPoint;
9703 pMousePoint->SetShared(
true);
9713 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9715 if (m_pEditRouteArray) {
9716 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9718 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9723 auto pos = std::find(list->begin(), list->end(),
9724 m_pRoutePointEditTarget);
9726 pSelect->DeleteAllSelectableRoutePoints(pr);
9727 pSelect->DeleteAllSelectableRouteSegments(pr);
9730 pos = std::find(list->begin(), list->end(),
9731 m_pRoutePointEditTarget);
9734 pSelect->AddAllSelectableRouteSegments(pr);
9735 pSelect->AddAllSelectableRoutePoints(pr);
9737 pr->FinalizeForRendering();
9738 pr->UpdateSegmentDistances();
9739 if (m_bRoutePoinDragging) {
9741 NavObj_dB::GetInstance().UpdateRoute(pr);
9749 if (m_pEditRouteArray) {
9750 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9752 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9771 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9778 delete m_pRoutePointEditTarget;
9779 m_lastRoutePointEditTarget = NULL;
9780 m_pRoutePointEditTarget = NULL;
9781 undo->AfterUndoableAction(pMousePoint);
9782 undo->InvalidateUndo();
9787 else if (m_bMarkEditing) {
9788 if (m_pRoutePointEditTarget)
9789 if (m_bRoutePoinDragging) {
9791 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9795 if (m_pRoutePointEditTarget)
9796 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9798 if (!m_pRoutePointEditTarget) {
9799 delete m_pEditRouteArray;
9800 m_pEditRouteArray = NULL;
9801 m_bRouteEditing =
false;
9803 m_bRoutePoinDragging =
false;
9810 int length = tail->GetnPoints();
9811 for (
int i = connect + 1; i <= length; i++) {
9812 current->AddPointAndSegment(tail->GetPoint(i),
false);
9815 gFrame->RefreshAllCanvas();
9818 current->FinalizeForRendering();
9824 pSelect->DeleteAllSelectableRoutePoints(current);
9825 pSelect->DeleteAllSelectableRouteSegments(current);
9826 for (
int i = 1; i < connect; i++) {
9827 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9829 pSelect->AddAllSelectableRouteSegments(current);
9830 pSelect->AddAllSelectableRoutePoints(current);
9831 current->FinalizeForRendering();
9838 if (m_pEditRouteArray) {
9839 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9840 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9853 if (m_bRouteEditing) {
9856 bool appending =
false;
9857 bool inserting =
false;
9860 if (m_pRoutePointEditTarget) {
9861 m_pRoutePointEditTarget->
m_bBlink =
false;
9865 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9866 double nearby_radius_meters =
9867 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9868 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9869 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9870 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9872 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9873 bool duplicate =
false;
9875 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9877 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9881 std::find(list->begin(), list->end(), pNearbyPoint);
9882 if (pos != list->end()) {
9894 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9899 OCPNMessageBox(
this,
9900 _(
"Replace this RoutePoint by the nearby "
9902 _(
"OpenCPN RoutePoint change"),
9903 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9904 if (dlg_return == wxID_YES) {
9908 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9911 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9913 if (tail && current && (tail != current)) {
9915 connect = tail->GetIndexOf(pNearbyPoint);
9916 int index_current_route =
9917 current->GetIndexOf(m_pRoutePointEditTarget);
9918 index_last = current->GetIndexOf(current->GetLastPoint());
9919 dlg_return1 = wxID_NO;
9921 index_current_route) {
9923 if (connect != tail->GetnPoints()) {
9926 _(
"Last part of route to be appended to dragged "
9930 _(
"Full route to be appended to dragged route?");
9932 dlg_return1 = OCPNMessageBox(
9933 this, dmsg, _(
"OpenCPN Route Create"),
9934 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9935 if (dlg_return1 == wxID_YES) {
9939 }
else if (index_current_route ==
9944 _(
"First part of route to be inserted into dragged "
9946 if (connect == tail->GetnPoints())
9948 "Full route to be inserted into dragged route?");
9950 dlg_return1 = OCPNMessageBox(
9951 this, dmsg, _(
"OpenCPN Route Create"),
9952 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9953 if (dlg_return1 == wxID_YES) {
9960 if (m_pRoutePointEditTarget->IsShared()) {
9961 dlg_return = wxID_NO;
9962 dlg_return = OCPNMessageBox(
9964 _(
"Do you really want to delete and replace this "
9966 "\n" + _(
"which has been created manually?"),
9967 (
"OpenCPN RoutePoint warning"),
9968 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9971 if (dlg_return == wxID_YES) {
9972 pMousePoint = pNearbyPoint;
9974 pMousePoint->SetShared(
true);
9984 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9986 if (m_pEditRouteArray) {
9987 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9989 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9993 auto pos = std::find(list->begin(), list->end(),
9994 m_pRoutePointEditTarget);
9996 pSelect->DeleteAllSelectableRoutePoints(pr);
9997 pSelect->DeleteAllSelectableRouteSegments(pr);
10000 pos = std::find(list->begin(), list->end(),
10001 m_pRoutePointEditTarget);
10002 if (pos != list->end()) list->erase(pos);
10005 pSelect->AddAllSelectableRouteSegments(pr);
10006 pSelect->AddAllSelectableRoutePoints(pr);
10008 pr->FinalizeForRendering();
10009 pr->UpdateSegmentDistances();
10012 if (m_bRoutePoinDragging) {
10017 NavObj_dB::GetInstance().UpdateRoutePoint(
10018 m_pRoutePointEditTarget);
10020 NavObj_dB::GetInstance().UpdateRoute(pr);
10032 int length = tail->GetnPoints();
10033 for (
int i = connect + 1; i <= length; i++) {
10034 current->AddPointAndSegment(tail->GetPoint(i),
false);
10038 gFrame->RefreshAllCanvas();
10041 current->FinalizeForRendering();
10047 pSelect->DeleteAllSelectableRoutePoints(current);
10048 pSelect->DeleteAllSelectableRouteSegments(current);
10049 for (
int i = 1; i < connect; i++) {
10050 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
10052 pSelect->AddAllSelectableRouteSegments(current);
10053 pSelect->AddAllSelectableRoutePoints(current);
10054 current->FinalizeForRendering();
10061 if (m_pEditRouteArray) {
10062 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
10064 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
10076 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
10083 delete m_pRoutePointEditTarget;
10084 m_lastRoutePointEditTarget = NULL;
10085 undo->AfterUndoableAction(pMousePoint);
10086 undo->InvalidateUndo();
10091 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10094 delete m_pEditRouteArray;
10095 m_pEditRouteArray = NULL;
10099 m_bRouteEditing =
false;
10100 m_pRoutePointEditTarget = NULL;
10106 else if (m_bMarkEditing) {
10107 if (m_pRoutePointEditTarget) {
10108 if (m_bRoutePoinDragging) {
10110 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
10112 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10117 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10119 RefreshRect(wp_rect,
true);
10122 m_pRoutePointEditTarget = NULL;
10123 m_bMarkEditing =
false;
10128 else if (leftIsDown) {
10129 leftIsDown =
false;
10133 if (!m_bChartDragging && !m_bMeasure_Active) {
10135 m_bChartDragging =
false;
10139 m_bRoutePoinDragging =
false;
10142 if (ret)
return true;
10145 if (event.RightDown()) {
10156 m_FinishRouteOnKillFocus =
false;
10157 CallPopupMenu(mx, my);
10158 m_FinishRouteOnKillFocus =
true;
10168 if (event.ShiftDown()) {
10172 event.GetPosition(&x, &y);
10174 x *= m_displayScale;
10175 y *= m_displayScale;
10181 int wheel_dir =
event.GetWheelRotation();
10184 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10185 wheel_dir = wheel_dir > 0 ? 1 : -1;
10187 double factor = g_mouse_zoom_sensitivity;
10188 if (wheel_dir < 0) factor = 1 / factor;
10191 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10192 if (wheel_dir == m_last_wheel_dir) {
10193 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10198 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10199 m_wheelstopwatch.Start(0);
10204 m_last_wheel_dir = wheel_dir;
10209 if (event.LeftDown()) {
10215 last_drag.x = x, last_drag.y = y;
10216 panleftIsDown =
true;
10219 if (event.LeftUp()) {
10220 if (panleftIsDown) {
10222 panleftIsDown =
false;
10225 if (!m_bChartDragging && !m_bMeasure_Active) {
10226 switch (cursor_region) {
10248 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10253 m_bChartDragging =
false;
10259 if (event.Dragging() && event.LeftIsDown()) {
10275 if (g_btouch && !m_inPinch) {
10276 struct timespec now;
10277 clock_gettime(CLOCK_MONOTONIC, &now);
10278 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10280 bool trigger_hold =
false;
10281 if (
false == m_bChartDragging) {
10282 if (m_DragTrigger < 0) {
10285 m_DragTriggerStartTime = tnow;
10286 trigger_hold =
true;
10288 if (((tnow - m_DragTriggerStartTime) / 1e6) > 20) {
10289 m_DragTrigger = -1;
10294 if (trigger_hold)
return true;
10296 if (
false == m_bChartDragging) {
10299 last_drag.x = x - 1, last_drag.y = y - 1;
10300 m_bChartDragging =
true;
10301 m_chart_drag_total_time = 0;
10302 m_chart_drag_total_x = 0;
10303 m_chart_drag_total_y = 0;
10304 m_inertia_last_drag_x = x;
10305 m_inertia_last_drag_y = y;
10306 m_drag_vec_x.clear();
10307 m_drag_vec_y.clear();
10308 m_drag_vec_t.clear();
10309 m_last_drag_time = tnow;
10313 uint64_t delta_t = tnow - m_last_drag_time;
10314 double delta_tf = delta_t / 1e9;
10316 m_chart_drag_total_time += delta_tf;
10317 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10318 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10320 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10321 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10322 m_drag_vec_t.push_back(delta_tf);
10324 m_inertia_last_drag_x = x;
10325 m_inertia_last_drag_y = y;
10326 m_last_drag_time = tnow;
10328 if ((abs(last_drag.x - x) > 2) || (abs(last_drag.y - y) > 2)) {
10329 m_bChartDragging =
true;
10330 StartTimedMovement();
10331 m_pan_drag.x += last_drag.x - x;
10332 m_pan_drag.y += last_drag.y - y;
10333 last_drag.x = x, last_drag.y = y;
10335 }
else if (!g_btouch) {
10336 if ((last_drag.x != x) || (last_drag.y != y)) {
10337 if (!m_routeState) {
10340 m_bChartDragging =
true;
10341 StartTimedMovement();
10342 m_pan_drag.x += last_drag.x - x;
10343 m_pan_drag.y += last_drag.y - y;
10344 last_drag.x = x, last_drag.y = y;
10351 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10353 m_ignore_next_leftup =
true;
10354 m_DoubleClickTimer->Start();
10355 singleClickEventIsValid =
false;
10363void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10364 if (MouseEventOverlayWindows(event))
return;
10368 bool nm = MouseEventProcessObjects(event);
10372void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10375 wxCursor *ptarget_cursor = pCursorArrow;
10376 if (!pPlugIn_Cursor) {
10377 ptarget_cursor = pCursorArrow;
10378 if ((!m_routeState) &&
10379 (!m_bMeasure_Active) ) {
10380 if (cursor_region == MID_RIGHT) {
10381 ptarget_cursor = pCursorRight;
10382 }
else if (cursor_region == MID_LEFT) {
10383 ptarget_cursor = pCursorLeft;
10384 }
else if (cursor_region == MID_TOP) {
10385 ptarget_cursor = pCursorDown;
10386 }
else if (cursor_region == MID_BOT) {
10387 ptarget_cursor = pCursorUp;
10389 ptarget_cursor = pCursorArrow;
10391 }
else if (m_bMeasure_Active ||
10393 ptarget_cursor = pCursorPencil;
10395 ptarget_cursor = pPlugIn_Cursor;
10398 SetCursor(*ptarget_cursor);
10401void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10402 SetCursor(*pCursorArrow);
10405void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10409 wxArrayString files;
10411 ChartBase *target_chart = GetChartAtCursor();
10412 if (target_chart) {
10413 file.Assign(target_chart->GetFullPath());
10414 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10415 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10418 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10420 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10421 unsigned int im = stackIndexArray.size();
10422 int scale = 2147483647;
10423 if (VPoint.b_quilt && im > 0) {
10424 for (
unsigned int is = 0; is < im; is++) {
10425 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10426 CHART_TYPE_MBTILES) {
10427 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10429 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10430 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10432 .Contains(lat, lon)) {
10433 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10436 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10437 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10445 std::vector<Ais8_001_22 *> area_notices;
10447 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10450 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10451 auto target_data = target.second;
10452 if (!target_data->area_notices.empty()) {
10453 for (
auto &ani : target_data->area_notices) {
10458 for (Ais8_001_22_SubAreaList::iterator sa =
10459 area_notice.sub_areas.begin();
10460 sa != area_notice.sub_areas.end(); ++sa) {
10461 switch (sa->shape) {
10462 case AIS8_001_22_SHAPE_CIRCLE: {
10463 wxPoint target_point;
10465 bbox.Expand(target_point);
10466 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10469 case AIS8_001_22_SHAPE_RECT: {
10470 wxPoint target_point;
10472 bbox.Expand(target_point);
10473 if (sa->e_dim_m > sa->n_dim_m)
10474 bbox.EnLarge(sa->e_dim_m * vp_scale);
10476 bbox.EnLarge(sa->n_dim_m * vp_scale);
10479 case AIS8_001_22_SHAPE_POLYGON:
10480 case AIS8_001_22_SHAPE_POLYLINE: {
10481 for (
int i = 0; i < 4; ++i) {
10482 double lat = sa->latitude;
10483 double lon = sa->longitude;
10484 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10486 wxPoint target_point;
10488 bbox.Expand(target_point);
10492 case AIS8_001_22_SHAPE_SECTOR: {
10493 double lat1 = sa->latitude;
10494 double lon1 = sa->longitude;
10496 wxPoint target_point;
10498 bbox.Expand(target_point);
10499 for (
int i = 0; i < 18; ++i) {
10502 sa->left_bound_deg +
10503 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10504 sa->radius_m / 1852.0, &lat, &lon);
10506 bbox.Expand(target_point);
10508 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10511 bbox.Expand(target_point);
10517 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10518 area_notices.push_back(&area_notice);
10525 if (target_chart || !area_notices.empty() || file.HasName()) {
10527 int sel_rad_pix = 5;
10528 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10533 SetCursor(wxCURSOR_WAIT);
10534 bool lightsVis = m_encShowLights;
10535 if (!lightsVis) SetShowENCLights(
true);
10538 ListOfObjRazRules *rule_list = NULL;
10539 ListOfPI_S57Obj *pi_rule_list = NULL;
10542 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10543 else if (target_plugin_chart)
10544 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10545 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10547 ListOfObjRazRules *overlay_rule_list = NULL;
10548 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10551 if (CHs57_Overlay) {
10552 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10553 zlat, zlon, SelectRadius, &GetVP());
10556 if (!lightsVis) SetShowENCLights(
false);
10559 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10560 wxString face = dFont->GetFaceName();
10564 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10565 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10569 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10577 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10578 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10581 int points = dFont->GetPointSize();
10583 int points = dFont->GetPointSize() + 1;
10587 for (
int i = -2; i < 5; i++) {
10588 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10592 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10594 if (overlay_rule_list && CHs57_Overlay) {
10595 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10596 objText <<
"<hr noshade>";
10599 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10600 an != area_notices.end(); ++an) {
10601 objText <<
"<b>AIS Area Notice:</b> ";
10602 objText << ais8_001_22_notice_names[(*an)->notice_type];
10603 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10604 (*an)->sub_areas.begin();
10605 sa != (*an)->sub_areas.end(); ++sa)
10606 if (!sa->text.empty()) objText << sa->text;
10607 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10608 objText <<
"<hr noshade>";
10612 objText << Chs57->CreateObjDescriptions(rule_list);
10613 else if (target_plugin_chart)
10614 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10617 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10620 wxString AddFiles, filenameOK;
10622 if (!target_plugin_chart) {
10625 AddFiles = wxString::Format(
10626 "<hr noshade><br><b>Additional info files attached to: </b> "
10628 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10630 file.GetFullName());
10632 file.Assign(file.GetPath(),
"");
10633 wxDir dir(file.GetFullPath());
10635 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10637 file.Assign(dir.GetNameWithSep().append(filename));
10638 wxString FormatString =
10639 "<td valign=top><font size=-2><a "
10640 "href=\"%s\">%s</a></font></td>";
10641 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10642 filenameOK = file.GetFullPath();
10644 if (3 * ((
int)filecount / 3) == filecount)
10645 FormatString.Prepend(
"<tr>");
10647 FormatString.Prepend(
10648 "<td>  </td>");
10651 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10652 file.GetFullName());
10655 cont = dir.GetNext(&filename);
10657 objText << AddFiles <<
"</table>";
10659 objText <<
"</font>";
10660 objText <<
"</body></html>";
10662 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10666 if ((!Chs57 && filecount == 1)) {
10668 wxHtmlLinkInfo hli(filenameOK);
10669 wxHtmlLinkEvent hle(1, hli);
10673 if (rule_list) rule_list->Clear();
10676 if (overlay_rule_list) overlay_rule_list->Clear();
10677 delete overlay_rule_list;
10679 if (pi_rule_list) pi_rule_list->Clear();
10680 delete pi_rule_list;
10682 SetCursor(wxCURSOR_ARROW);
10686void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10695 wxSize canvas_size = GetSize();
10702 wxPoint canvas_pos = GetPosition();
10705 bool newFit =
false;
10706 if (canvas_size.x < fitted_size.x) {
10707 fitted_size.x = canvas_size.x - 40;
10708 if (canvas_size.y < fitted_size.y)
10709 fitted_size.y -= 40;
10711 if (canvas_size.y < fitted_size.y) {
10712 fitted_size.y = canvas_size.y - 40;
10713 if (canvas_size.x < fitted_size.x)
10714 fitted_size.x -= 40;
10725 wxString title_base = _(
"Mark Properties");
10727 title_base = _(
"Waypoint Properties");
10732 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10744void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10754 if (g_bresponsive) {
10755 wxSize canvas_size = GetSize();
10756 wxPoint canvas_pos = GetPosition();
10760 if (canvas_size.x < fitted_size.x) {
10761 fitted_size.x = canvas_size.x;
10762 if (canvas_size.y < fitted_size.y)
10763 fitted_size.y -= 20;
10765 if (canvas_size.y < fitted_size.y) {
10766 fitted_size.y = canvas_size.y;
10767 if (canvas_size.x < fitted_size.x)
10768 fitted_size.x -= 20;
10777 wxPoint xxp = ClientToScreen(canvas_pos);
10788void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10800void pupHandler_PasteWaypoint() {
10803 int pasteBuffer = kml.ParsePasteBuffer();
10804 RoutePoint *pasted = kml.GetParsedRoutePoint();
10805 if (!pasted)
return;
10807 double nearby_radius_meters =
10808 g_Platform->GetSelectRadiusPix() /
10809 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10811 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10812 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10814 int answer = wxID_NO;
10818 "There is an existing waypoint at the same location as the one you are "
10819 "pasting. Would you like to merge the pasted data with it?\n\n");
10820 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10821 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10822 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10825 if (answer == wxID_YES) {
10826 nearPoint->SetName(pasted->GetName());
10828 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10829 pRouteManagerDialog->UpdateWptListCtrl();
10832 if (answer == wxID_NO) {
10835 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10838 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10841 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10842 pRouteManagerDialog->UpdateWptListCtrl();
10847 gFrame->InvalidateAllGL();
10848 gFrame->RefreshAllCanvas(
false);
10851void pupHandler_PasteRoute() {
10854 int pasteBuffer = kml.ParsePasteBuffer();
10855 Route *pasted = kml.GetParsedRoute();
10856 if (!pasted)
return;
10858 double nearby_radius_meters =
10859 g_Platform->GetSelectRadiusPix() /
10860 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10866 bool mergepoints =
false;
10867 bool createNewRoute =
true;
10868 int existingWaypointCounter = 0;
10870 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10871 curPoint = pasted->GetPoint(i);
10872 nearPoint = pWayPointMan->GetNearbyWaypoint(
10873 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10875 mergepoints =
true;
10876 existingWaypointCounter++;
10884 int answer = wxID_NO;
10888 "There are existing waypoints at the same location as some of the ones "
10889 "you are pasting. Would you like to just merge the pasted data into "
10891 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10892 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10893 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10895 if (answer == wxID_CANCEL) {
10902 if (mergepoints && answer == wxID_YES &&
10903 existingWaypointCounter == pasted->GetnPoints()) {
10906 createNewRoute =
false;
10912 Route *newRoute = 0;
10915 if (createNewRoute) {
10916 newRoute =
new Route();
10920 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10921 curPoint = pasted->GetPoint(i);
10924 newPoint = pWayPointMan->GetNearbyWaypoint(
10925 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10926 newPoint->SetName(curPoint->GetName());
10929 if (createNewRoute) newRoute->AddPoint(newPoint);
10935 newPoint->SetIconName(
"circle");
10938 newPoint->SetShared(
false);
10940 newRoute->AddPoint(newPoint);
10941 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10944 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10947 if (i > 1 && createNewRoute)
10948 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10949 curPoint->m_lat, curPoint->m_lon,
10950 prevPoint, newPoint, newRoute);
10951 prevPoint = newPoint;
10954 if (createNewRoute) {
10957 NavObj_dB::GetInstance().InsertRoute(newRoute);
10963 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10964 pRouteManagerDialog->UpdateRouteListCtrl();
10965 pRouteManagerDialog->UpdateWptListCtrl();
10967 gFrame->InvalidateAllGL();
10968 gFrame->RefreshAllCanvas(
false);
10974void pupHandler_PasteTrack() {
10977 int pasteBuffer = kml.ParsePasteBuffer();
10978 Track *pasted = kml.GetParsedTrack();
10979 if (!pasted)
return;
10987 newTrack->SetName(pasted->GetName());
10989 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10990 curPoint = pasted->GetPoint(i);
10994 wxDateTime now = wxDateTime::Now();
10997 newTrack->AddPoint(newPoint);
11000 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
11001 newPoint->m_lat, newPoint->m_lon,
11002 prevPoint, newPoint, newTrack);
11004 prevPoint = newPoint;
11009 NavObj_dB::GetInstance().InsertTrack(newTrack);
11011 gFrame->InvalidateAllGL();
11012 gFrame->RefreshAllCanvas(
false);
11015bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
11018 v[
"CursorPosition_x"] = x;
11019 v[
"CursorPosition_y"] = y;
11022 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
11023 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
11024 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
11029 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
11031 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
11034#define SELTYPE_UNKNOWN 0x0001
11035#define SELTYPE_ROUTEPOINT 0x0002
11036#define SELTYPE_ROUTESEGMENT 0x0004
11037#define SELTYPE_TIDEPOINT 0x0008
11038#define SELTYPE_CURRENTPOINT 0x0010
11039#define SELTYPE_ROUTECREATE 0x0020
11040#define SELTYPE_AISTARGET 0x0040
11041#define SELTYPE_MARKPOINT 0x0080
11042#define SELTYPE_TRACKSEGMENT 0x0100
11043#define SELTYPE_DRAGHANDLE 0x0200
11046 if (g_bhide_context_menus)
return true;
11048 m_pFoundRoutePoint, m_FoundAIS_MMSI,
11049 m_pIDXCandidate, m_nmea_log);
11052 wxEVT_COMMAND_MENU_SELECTED,
11053 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11059 if (m_inLongPress) {
11060 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11061 m_inLongPress =
false;
11065 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
11068 wxEVT_COMMAND_MENU_SELECTED,
11069 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
11071 delete m_canvasMenu;
11072 m_canvasMenu = NULL;
11082void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
11085 if (m_canvasMenu) {
11086 m_canvasMenu->PopupMenuHandler(event);
11091void ChartCanvas::StartRoute() {
11093 if (g_brouteCreating)
return;
11097 g_brouteCreating =
true;
11099 m_bDrawingRoute =
false;
11100 SetCursor(*pCursorPencil);
11102 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
11104 HideGlobalToolbar();
11107 androidSetRouteAnnunciator(
true);
11111wxString ChartCanvas::FinishRoute() {
11113 m_prev_pMousePoint = NULL;
11114 m_bDrawingRoute =
false;
11116 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
11119 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
11121 androidSetRouteAnnunciator(
false);
11124 SetCursor(*pCursorArrow);
11126 if (m_pMouseRoute) {
11127 if (m_bAppendingRoute) {
11129 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11131 if (m_pMouseRoute->GetnPoints() > 1) {
11133 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11136 m_pMouseRoute = NULL;
11139 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11146 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11147 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11148 pRouteManagerDialog->UpdateRouteListCtrl();
11151 m_bAppendingRoute =
false;
11152 m_pMouseRoute = NULL;
11154 m_pSelectedRoute = NULL;
11156 undo->InvalidateUndo();
11157 gFrame->RefreshAllCanvas(
true);
11161 ShowGlobalToolbar();
11163 g_brouteCreating =
false;
11168void ChartCanvas::HideGlobalToolbar() {
11169 if (m_canvasIndex == 0) {
11170 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11174void ChartCanvas::ShowGlobalToolbar() {
11175 if (m_canvasIndex == 0) {
11176 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11180void ChartCanvas::ShowAISTargetList() {
11181 if (NULL == g_pAISTargetList) {
11185 g_pAISTargetList->UpdateAISTargetList();
11188void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11189 if (!m_bShowOutlines)
return;
11193 int nEntry =
ChartData->GetChartTableEntries();
11195 for (
int i = 0; i < nEntry; i++) {
11199 bool b_group_draw =
false;
11200 if (m_groupIndex > 0) {
11201 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11202 int index = pt->GetGroupArray()[ig];
11203 if (m_groupIndex == index) {
11204 b_group_draw =
true;
11209 b_group_draw =
true;
11211 if (b_group_draw) RenderChartOutline(dc, i, vp);
11217 if (VPoint.b_quilt) {
11218 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11219 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11223 }
else if (m_singleChart &&
11224 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11228 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11231 if (zoom_factor > 8.0) {
11232 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11235 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11239 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11243void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11245 if (g_bopengl && m_glcc) {
11247 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11252 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11253 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11256 float plylat, plylon;
11257 float plylat1, plylon1;
11259 int pixx, pixy, pixx1, pixy1;
11262 ChartData->GetDBBoundingBox(dbIndex, box);
11266 if (box.GetLonRange() == 360)
return;
11268 double lon_bias = 0;
11270 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11272 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11274 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11275 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11277 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11278 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11281 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11284 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11285 if (0 == nAuxPlyEntries)
11289 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11290 plylon += lon_bias;
11296 for (
int i = 0; i < nPly - 1; i++) {
11297 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11298 plylon1 += lon_bias;
11304 int pixxs1 = pixx1;
11305 int pixys1 = pixy1;
11307 bool b_skip =
false;
11311 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11312 pow((
double)(pixy1 - pixy), 2)) /
11318 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11323 if (fabs(dist - distgc) > 10000. * 1852.)
11329 ClipResult res = cohen_sutherland_line_clip_i(
11331 if (res != Invisible && !b_skip)
11332 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11340 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11341 plylon1 += lon_bias;
11347 ClipResult res = cohen_sutherland_line_clip_i(
11349 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11356 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11357 for (
int j = 0; j < nAuxPlyEntries; j++) {
11359 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11364 for (
int i = 0; i < nAuxPly - 1; i++) {
11365 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11371 int pixxs1 = pixx1;
11372 int pixys1 = pixy1;
11374 bool b_skip =
false;
11378 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11379 ((pixy1 - pixy) * (pixy1 - pixy))) /
11384 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11389 if (fabs(dist - distgc) > 10000. * 1852.)
11395 ClipResult res = cohen_sutherland_line_clip_i(
11397 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11405 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11410 ClipResult res = cohen_sutherland_line_clip_i(
11412 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11417static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
11418 const wxArrayString &legend) {
11419 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11421 int pointsize = dFont->GetPointSize();
11425 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11426 false, dFont->GetFaceName());
11428 dc.SetFont(*psRLI_font);
11435 int hilite_offset = 3;
11437 for (wxString line : legend) {
11440 sdc.GetTextExtent(line, &wl, &hl, NULL, NULL, psRLI_font);
11442 dc.GetTextExtent(line, &wl, &hl);
11451 xp = ref_point.x - w;
11453 yp += hilite_offset;
11455 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11457 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11458 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11460 for (wxString line : legend) {
11461 dc.DrawText(line, xp, yp);
11466void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11467 if (!g_bAllowShipToActive)
return;
11473 wxPoint2DDouble pa, pb;
11480 if (rt->
m_width != wxPENSTYLE_INVALID)
11482 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11483 g_shipToActiveStyle, 5)];
11484 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11486 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11489 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11492 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11495 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11496 (
int)pb.m_y, GetVP(),
true);
11500#ifdef USE_ANDROID_GLES2
11501 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11503 if (style != wxPENSTYLE_SOLID) {
11504 if (glChartCanvas::dash_map.find(style) !=
11505 glChartCanvas::dash_map.end()) {
11506 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11510 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11513 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11514 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11520void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11522 if (m_routeState >= 2) route = m_pMouseRoute;
11523 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11524 route = m_pMeasureRoute;
11526 if (!route)
return;
11534 int np = route->GetnPoints();
11536 if (g_btouch && (np > 1)) np--;
11538 render_lat = rp.m_lat;
11539 render_lon = rp.m_lon;
11542 double rhumbBearing, rhumbDist;
11544 &rhumbBearing, &rhumbDist);
11545 double brg = rhumbBearing;
11546 double dist = rhumbDist;
11550 double gcBearing, gcBearing2, gcDist;
11551 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11554 double gcDistm = gcDist / 1852.0;
11557 rhumbBearing = 90.;
11559 wxPoint destPoint, lastPoint;
11562 int milesDiff = rhumbDist - gcDistm;
11563 if (milesDiff > 1) {
11574 for (
int i = 1; i <= milesDiff; i++) {
11575 double p = (double)i * (1.0 / (
double)milesDiff);
11577 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11578 &pLon, &pLat, &gcBearing2);
11580 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11582 lastPoint = destPoint;
11585 if (r_rband.x && r_rband.y) {
11586 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11588 if (m_bMeasure_DistCircle) {
11589 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11590 powf((
float)(r_rband.y - lastPoint.y), 2));
11593 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11594 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11600 wxString routeInfo;
11601 wxArrayString infoArray;
11604 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11610 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11612 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11613 (
int)varBrg, 0x00B0);
11616 infoArray.Add(routeInfo);
11622 routeInfo <<
"Reverse: ";
11624 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11625 (
int)(brg + 180.) % 360, 0x00B0);
11627 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11628 (
int)(varBrg + 180.) % 360, 0x00B0);
11629 infoArray.Add(routeInfo);
11635 s0.Append(_(
"Route") +
": ");
11637 s0.Append(_(
"Layer Route: "));
11640 if (!g_btouch) disp_length += dist;
11646 RouteLegInfo(dc, r_rband, infoArray);
11648 m_brepaint_piano =
true;
11651void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11652 if (!m_bShowVisibleSectors)
return;
11654 if (g_bDeferredInitDone) {
11656 double rhumbBearing, rhumbDist;
11657 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11658 &rhumbBearing, &rhumbDist);
11660 if (rhumbDist > 0.05)
11662 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11663 m_sectorlegsVisible);
11664 m_sector_glat =
gLat;
11665 m_sector_glon =
gLon;
11667 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11671void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11679void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11680 if (!ps52plib)
return;
11682 if (VPoint.b_quilt) {
11683 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11685 if (m_pQuilt->IsQuiltVector()) {
11686 if (ps52plib->GetStateHash() != m_s52StateHash) {
11688 m_s52StateHash = ps52plib->GetStateHash();
11692 if (ps52plib->GetStateHash() != m_s52StateHash) {
11694 m_s52StateHash = ps52plib->GetStateHash();
11699 bool bSendPlibState =
true;
11700 if (VPoint.b_quilt) {
11701 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11704 if (bSendPlibState) {
11706 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11707 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11708 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11709 v[
"OpenCPN Version Date"] = VERSION_DATE;
11710 v[
"OpenCPN Version Full"] = VERSION_FULL;
11713 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11714 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11715 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11716 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11717 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11718 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11719 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11723 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11724 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11728 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11729 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11730 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11731 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11732 ps52plib->m_bShowS57ImportantTextOnly;
11733 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11734 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11735 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11736 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11737 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11740 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11741 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11742 v[
"OpenCPN Scale Factor Exp"] =
11743 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11750 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11751 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11752 g_lastS52PLIBPluginMessage = out;
11759 wxPaintDC dc(
this);
11769 if (!m_b_paint_enable) {
11777 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11779 if (m_glcc && g_bopengl) {
11780 if (!s_in_update) {
11790 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11792 wxRegion ru = GetUpdateRegion();
11794 int rx, ry, rwidth, rheight;
11795 ru.GetBox(rx, ry, rwidth, rheight);
11797#ifdef ocpnUSE_DIBSECTION
11800 wxMemoryDC temp_dc;
11808 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11809 height += m_Piano->GetHeight();
11811 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11815 int thumbx, thumby, thumbsx, thumbsy;
11816 pthumbwin->GetPosition(&thumbx, &thumby);
11817 pthumbwin->GetSize(&thumbsx, &thumbsy);
11818 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11821 rgn_chart.Subtract(rgn_thumbwin);
11822 ru.Subtract(rgn_thumbwin);
11828 wxRegion rgn_blit = ru;
11829 if (g_bShowChartBar) {
11830 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11831 GetClientSize().x, m_Piano->GetHeight());
11834 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11835 if (style->chartStatusWindowTransparent)
11836 m_brepaint_piano =
true;
11838 ru.Subtract(chart_bar_rect);
11842 if (m_Compass && m_Compass->IsShown()) {
11843 wxRect compassRect = m_Compass->
GetRect();
11844 if (ru.Contains(compassRect) != wxOutRegion) {
11845 ru.Subtract(compassRect);
11849 if (m_notification_button) {
11850 wxRect noteRect = m_notification_button->
GetRect();
11851 if (ru.Contains(noteRect) != wxOutRegion) {
11852 ru.Subtract(noteRect);
11857 bool b_newview =
true;
11862 m_cache_vp.IsValid()) {
11868 bool b_rcache_ok =
false;
11869 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11870 b_rcache_ok = !b_newview;
11873 if (VPoint.b_MercatorProjectionOverride)
11874 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11888 if (b_rcache_ok) chart_get_region.Clear();
11891 if (VPoint.b_quilt)
11893 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11895 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11900 AbstractPlatform::ShowBusySpinner();
11904 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11905 (m_working_bm.GetHeight() != svp.
pix_height))
11909 if (fabs(VPoint.
rotation) < 0.01) {
11910 bool b_save =
true;
11915 m_cache_vp.Invalidate();
11929 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11934 int dy = c_new.y - c_old.y;
11935 int dx = c_new.x - c_old.x;
11940 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11944 temp_dc.SelectObject(m_working_bm);
11946 wxMemoryDC cache_dc;
11947 cache_dc.SelectObject(m_cached_chart_bm);
11951 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11954 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11960 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11963 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11971 update_region.Union(
11974 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11979 update_region.Union(
11982 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11986 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11988 cache_dc.SelectObject(wxNullBitmap);
11992 temp_dc.SelectObject(m_cached_chart_bm);
11995 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11999 temp_dc.SelectObject(m_working_bm);
12000 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12005 temp_dc.SelectObject(m_cached_chart_bm);
12010 temp_dc.SelectObject(m_working_bm);
12011 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12024 wxMemoryDC scratch_dc_0;
12025 scratch_dc_0.SelectObject(m_cached_chart_bm);
12028 scratch_dc_0.SelectObject(wxNullBitmap);
12037 temp_dc.SelectObject(m_working_bm);
12040 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
12041 chart_get_all_region);
12044 AbstractPlatform::HideBusySpinner();
12050 if (!m_singleChart) {
12051 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
12056 if (!chart_get_region.IsEmpty()) {
12057 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
12061 if (temp_dc.IsOk()) {
12066 if (!VPoint.b_quilt) {
12069 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12070 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
12077 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
12078 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
12081 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
12083 temp_dc.DestroyClippingRegion();
12088 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
12090 if (!backgroundRegion.IsEmpty()) {
12096 wxColour water = pWorldBackgroundChart->water;
12097 if (water.IsOk()) {
12098 temp_dc.SetPen(*wxTRANSPARENT_PEN);
12099 temp_dc.SetBrush(wxBrush(water));
12101 while (upd.HaveRects()) {
12102 wxRect rect = upd.GetRect();
12103 temp_dc.DrawRectangle(rect);
12108 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
12109 temp_dc.SetDeviceClippingRegion(*clip_region);
12110 delete clip_region;
12114 SetVPRotation(VPoint.
skew);
12123 wxMemoryDC *pChartDC = &temp_dc;
12124 wxMemoryDC rotd_dc;
12126 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
12128 if (!b_rcache_ok) {
12130 wxMemoryDC tbase_dc;
12132 tbase_dc.SelectObject(bm_base);
12134 tbase_dc.SelectObject(wxNullBitmap);
12136 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
12139 wxImage base_image;
12140 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12148 bool b_rot_ok =
false;
12149 if (base_image.IsOk()) {
12152 m_b_rot_hidef =
false;
12156 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12157 m_b_rot_hidef, &m_roffset);
12162 rot_vp.IsValid() && (ri.IsOk())) {
12169 m_prot_bm =
new wxBitmap(ri);
12172 m_roffset.x += VPoint.rv_rect.x;
12173 m_roffset.y += VPoint.rv_rect.y;
12176 if (m_prot_bm && m_prot_bm->IsOk()) {
12177 rotd_dc.SelectObject(*m_prot_bm);
12178 pChartDC = &rotd_dc;
12180 pChartDC = &temp_dc;
12181 m_roffset = wxPoint(0, 0);
12184 pChartDC = &temp_dc;
12185 m_roffset = wxPoint(0, 0);
12188 wxPoint offset = m_roffset;
12191 m_cache_vp = VPoint;
12194 wxMemoryDC mscratch_dc;
12195 mscratch_dc.SelectObject(*pscratch_bm);
12197 mscratch_dc.ResetBoundingBox();
12198 mscratch_dc.DestroyClippingRegion();
12199 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12202 wxRegionIterator upd(rgn_blit);
12204 wxRect rect = upd.GetRect();
12206 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12207 rect.x - offset.x, rect.y - offset.y);
12213 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12214 if (
this == wxWindow::FindFocus()) {
12217 wxColour colour = GetGlobalColor(
"BLUE4");
12218 mscratch_dc.SetPen(wxPen(colour));
12219 mscratch_dc.SetBrush(wxBrush(colour));
12221 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12222 mscratch_dc.DrawRectangle(activeRect);
12227 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12228 unsigned int im = stackIndexArray.size();
12229 if (VPoint.b_quilt && im > 0) {
12230 std::vector<int> tiles_to_show;
12231 for (
unsigned int is = 0; is < im; is++) {
12233 ChartData->GetChartTableEntry(stackIndexArray[is]);
12234 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12237 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12238 tiles_to_show.push_back(stackIndexArray[is]);
12242 if (tiles_to_show.size())
12243 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12249 ocpnDC scratch_dc(mscratch_dc);
12250 RenderAlertMessage(mscratch_dc, GetVP());
12256#ifdef ocpnUSE_DIBSECTION
12261 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12262 q_dc.SelectObject(qbm);
12265 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12268 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12269 q_dc.SetBrush(qbr);
12270 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12273 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12276 q_dc.SelectObject(wxNullBitmap);
12285 if( VPoint.b_quilt ) {
12286 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12287 ChartBase *chart = m_pQuilt->GetRefChart();
12288 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12293 ChPI->ClearPLIBTextList();
12296 ps52plib->ClearTextList();
12300 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12302 wxColor maskBackground = wxColour(1,0,0);
12303 t_dc.SelectObject( qbm );
12304 t_dc.SetBackground(wxBrush(maskBackground));
12308 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12311 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12312 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12315 wxRegionIterator upd_final( ru );
12316 while( upd_final ) {
12317 wxRect rect = upd_final.GetRect();
12318 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12322 t_dc.SelectObject( wxNullBitmap );
12328 if (VPoint.b_quilt) {
12329 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12330 ChartBase *chart = m_pQuilt->GetRefChart();
12331 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12335 ChPI->ClearPLIBTextList();
12337 if (ps52plib) ps52plib->ClearTextList();
12342 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12344 if (g_bShowChartBar && m_Piano) {
12345 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12346 GetVP().pix_width, m_Piano->GetHeight());
12349 if (!style->chartStatusWindowTransparent)
12350 chart_all_text_region.Subtract(chart_bar_rect);
12353 if (m_Compass && m_Compass->IsShown()) {
12354 wxRect compassRect = m_Compass->
GetRect();
12355 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12356 chart_all_text_region.Subtract(compassRect);
12360 mscratch_dc.DestroyClippingRegion();
12362 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12363 chart_all_text_region);
12369 ocpnDC scratch_dc(mscratch_dc);
12370 DrawOverlayObjects(scratch_dc, ru);
12373 wxRegionIterator upd_final(rgn_blit);
12374 while (upd_final) {
12375 wxRect rect = upd_final.GetRect();
12376 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12383 temp_dc.SelectObject(wxNullBitmap);
12385 mscratch_dc.SelectObject(wxNullBitmap);
12387 dc.DestroyClippingRegion();
12392void ChartCanvas::PaintCleanup() {
12394 if (m_inPinch)
return;
12405 m_bTCupdate =
false;
12409 WarpPointer(warp_x, warp_y);
12416 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12417 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12421wxColour GetErrorGraphicColor(
double val)
12440 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12441 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12442 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12443 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12444 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12445 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12446 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12447 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12448 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12449 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12450 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12451 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12452 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12453 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12454 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12455 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12456 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12457 else if( val >= 48) c.Set(
"#410000");
12462void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12465 gr_image.InitAlpha();
12467 double maxval = -10000;
12468 double minval = 10000;
12485 maxval = wxMax(maxval, (glat - rlat));
12486 minval = wxMin(minval, (glat - rlat));
12503 double f = ((glat - rlat)-minval)/(maxval - minval);
12505 double dy = (f * 40);
12507 wxColour c = GetErrorGraphicColor(dy);
12508 unsigned char r = c.Red();
12509 unsigned char g = c.Green();
12510 unsigned char b = c.Blue();
12512 gr_image.SetRGB(j, i, r,g,b);
12513 if((glat - rlat )!= 0)
12514 gr_image.SetAlpha(j, i, 128);
12516 gr_image.SetAlpha(j, i, 255);
12523 wxBitmap *pbm =
new wxBitmap(gr_image);
12524 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12525 pbm->SetMask(gr_mask);
12527 pmdc->DrawBitmap(*pbm, 0,0);
12535void ChartCanvas::CancelMouseRoute() {
12537 m_pMouseRoute = NULL;
12538 m_bDrawingRoute =
false;
12541int ChartCanvas::GetNextContextMenuId() {
12542 return CanvasMenuHandler::GetNextContextMenuId();
12545bool ChartCanvas::SetCursor(
const wxCursor &c) {
12547 if (g_bopengl && m_glcc)
12548 return m_glcc->SetCursor(c);
12551 return wxWindow::SetCursor(c);
12554void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12555 if (g_bquiting)
return;
12565 if (!m_RolloverPopupTimer.IsRunning() &&
12566 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12567 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12568 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12569 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12572 if (m_glcc && g_bopengl) {
12575 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12577 m_glcc->Refresh(eraseBackground,
12594 if (m_pCIWin && m_pCIWin->IsShown()) {
12596 m_pCIWin->Refresh(
false);
12604 wxWindow::Refresh(eraseBackground, rect);
12607void ChartCanvas::Update() {
12608 if (m_glcc && g_bopengl) {
12613 wxWindow::Update();
12617 if (!pemboss)
return;
12618 int x = pemboss->x, y = pemboss->y;
12619 const double factor = 200;
12621 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12622 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12623 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12626 wxMemoryDC snip_dc;
12627 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12628 snip_dc.SelectObject(snip_bmp);
12630 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12631 snip_dc.SelectObject(wxNullBitmap);
12633 wxImage snip_img = snip_bmp.ConvertToImage();
12636 unsigned char *pdata = snip_img.GetData();
12638 for (
int y = 0; y < pemboss->height; y++) {
12639 int map_index = (y * pemboss->width);
12640 for (
int x = 0; x < pemboss->width; x++) {
12641 double val = (pemboss->pmap[map_index] * factor) / 256.;
12643 int nred = (int)((*pdata) + val);
12644 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12645 *pdata++ = (
unsigned char)nred;
12647 int ngreen = (int)((*pdata) + val);
12648 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12649 *pdata++ = (
unsigned char)ngreen;
12651 int nblue = (int)((*pdata) + val);
12652 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12653 *pdata++ = (
unsigned char)nblue;
12661 wxBitmap emb_bmp(snip_img);
12664 wxMemoryDC result_dc;
12665 result_dc.SelectObject(emb_bmp);
12668 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12670 result_dc.SelectObject(wxNullBitmap);
12676 if (GetQuiltMode()) {
12678 int refIndex = GetQuiltRefChartdbIndex();
12679 if (refIndex >= 0) {
12681 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12682 if (current_type == CHART_TYPE_MBTILES) {
12683 ChartBase *pChart = m_pQuilt->GetRefChart();
12686 zoom_factor = ptc->GetZoomFactor();
12691 if (zoom_factor <= 3.9)
return NULL;
12693 if (m_singleChart) {
12694 if (zoom_factor <= 3.9)
return NULL;
12699 if (m_pEM_OverZoom) {
12700 m_pEM_OverZoom->x = 4;
12701 m_pEM_OverZoom->y = 0;
12703 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12704 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12707 return m_pEM_OverZoom;
12710void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12723 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12724 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12728 AISDrawAreaNotices(dc, GetVP(),
this);
12730 wxDC *pdc = dc.GetDC();
12732 pdc->DestroyClippingRegion();
12733 wxDCClipper(*pdc, ru);
12736 if (m_bShowNavobjects) {
12737 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12738 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12739 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12740 DrawAnchorWatchPoints(dc);
12742 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12743 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12746 AISDraw(dc, GetVP(),
this);
12750 RenderVisibleSectorLights(dc);
12752 RenderAllChartOutlines(dc, GetVP());
12753 RenderRouteLegs(dc);
12754 RenderShipToActive(dc,
false);
12756 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12758 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12762 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12763 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12766 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12771 RebuildTideSelectList(GetVP().GetBBox());
12772 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12775 if (m_bShowCurrent) {
12776 RebuildCurrentSelectList(GetVP().GetBBox());
12777 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12780 if (!g_PrintingInProgress) {
12781 if (IsPrimaryCanvas()) {
12785 if (IsPrimaryCanvas()) {
12789 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12791 if (m_pTrackRolloverWin) {
12792 m_pTrackRolloverWin->Draw(dc);
12793 m_brepaint_piano =
true;
12796 if (m_pRouteRolloverWin) {
12797 m_pRouteRolloverWin->Draw(dc);
12798 m_brepaint_piano =
true;
12801 if (m_pAISRolloverWin) {
12802 m_pAISRolloverWin->Draw(dc);
12803 m_brepaint_piano =
true;
12805 if (m_brepaint_piano && g_bShowChartBar) {
12806 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12809 if (m_Compass) m_Compass->Paint(dc);
12811 if (!g_CanvasHideNotificationIcon) {
12812 if (IsPrimaryCanvas()) {
12813 auto ¬eman = NotificationManager::GetInstance();
12814 if (noteman.GetNotificationCount()) {
12815 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12816 if (m_notification_button->UpdateStatus()) Refresh();
12817 m_notification_button->Show(
true);
12818 m_notification_button->Paint(dc);
12820 m_notification_button->Show(
false);
12826 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12832 if (!m_bShowDepthUnits)
return NULL;
12834 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12836 if (GetQuiltMode()) {
12837 wxString s = m_pQuilt->GetQuiltDepthUnit();
12840 depth_unit_type = DEPTH_UNIT_FEET;
12841 else if (s.StartsWith(
"FATHOMS"))
12842 depth_unit_type = DEPTH_UNIT_FATHOMS;
12843 else if (s.StartsWith(
"METERS"))
12844 depth_unit_type = DEPTH_UNIT_METERS;
12845 else if (s.StartsWith(
"METRES"))
12846 depth_unit_type = DEPTH_UNIT_METERS;
12847 else if (s.StartsWith(
"METRIC"))
12848 depth_unit_type = DEPTH_UNIT_METERS;
12849 else if (s.StartsWith(
"METER"))
12850 depth_unit_type = DEPTH_UNIT_METERS;
12853 if (m_singleChart) {
12854 depth_unit_type = m_singleChart->GetDepthUnitType();
12855 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12856 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12861 switch (depth_unit_type) {
12862 case DEPTH_UNIT_FEET:
12865 case DEPTH_UNIT_METERS:
12866 ped = m_pEM_Meters;
12868 case DEPTH_UNIT_FATHOMS:
12869 ped = m_pEM_Fathoms;
12875 ped->x = (GetVP().
pix_width - ped->width);
12877 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12878 wxRect r = m_Compass->
GetRect();
12879 ped->y = r.y + r.height;
12886void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12889 if (style->embossFont == wxEmptyString) {
12890 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12892 font.SetPointSize(60);
12893 font.SetWeight(wxFONTWEIGHT_BOLD);
12895 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12896 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12898 int emboss_width = 500;
12899 int emboss_height = 200;
12903 delete m_pEM_Meters;
12904 delete m_pEM_Fathoms;
12908 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12910 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12912 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12915#define OVERZOOM_TEXT _("OverZoom")
12917void ChartCanvas::SetOverzoomFont() {
12922 if (style->embossFont == wxEmptyString) {
12923 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12925 font.SetPointSize(40);
12926 font.SetWeight(wxFONTWEIGHT_BOLD);
12928 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12929 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12931 wxClientDC dc(
this);
12933 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12935 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12936 font.SetPointSize(font.GetPointSize() - 1);
12938 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12940 m_overzoomFont = font;
12941 m_overzoomTextWidth = w;
12942 m_overzoomTextHeight = h;
12945void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12946 delete m_pEM_OverZoom;
12948 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12950 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12951 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12954emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12955 int height,
const wxString &str,
12960 wxBitmap bmp(width, height, -1);
12963 wxMemoryDC temp_dc;
12964 temp_dc.SelectObject(bmp);
12967 temp_dc.SetBackground(*wxWHITE_BRUSH);
12968 temp_dc.SetTextBackground(*wxWHITE);
12969 temp_dc.SetTextForeground(*wxBLACK);
12973 temp_dc.SetFont(font);
12976 temp_dc.GetTextExtent(str, &str_w, &str_h);
12978 temp_dc.DrawText(str, 1, 1);
12981 temp_dc.SelectObject(wxNullBitmap);
12984 wxImage img = bmp.ConvertToImage();
12986 int image_width = str_w * 105 / 100;
12987 int image_height = str_h * 105 / 100;
12988 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12989 wxMin(image_height, img.GetHeight()));
12990 wxImage imgs = img.GetSubImage(r);
12994 case GLOBAL_COLOR_SCHEME_DAY:
12998 case GLOBAL_COLOR_SCHEME_DUSK:
13001 case GLOBAL_COLOR_SCHEME_NIGHT:
13008 const int w = imgs.GetWidth();
13009 const int h = imgs.GetHeight();
13010 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
13015 for (
int y = 1; y < h - 1; y++) {
13016 for (
int x = 1; x < w - 1; x++) {
13018 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
13019 val = (int)(val * val_factor);
13020 index = (y * w) + x;
13033void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13034 Track *active_track = NULL;
13037 active_track = pTrackDraw;
13041 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
13044 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13047void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13048 Track *active_track = NULL;
13051 active_track = pTrackDraw;
13055 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
13058void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13059 Route *active_route = NULL;
13061 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13062 active_route = pRouteDraw;
13067 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
13072 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13075void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13076 Route *active_route = NULL;
13079 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
13080 active_route = pRouteDraw;
13084 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
13087void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
13088 if (!pWayPointMan)
return;
13090 auto node = pWayPointMan->GetWaypointList()->begin();
13092 while (node != pWayPointMan->GetWaypointList()->end()) {
13101 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
13105 if (pWP->GetShowWaypointRangeRings() &&
13106 (pWP->GetWaypointRangeRingsNumber() > 0)) {
13107 double factor = 1.00;
13108 if (pWP->GetWaypointRangeRingsStepUnits() ==
13110 factor = 1 / 1.852;
13112 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
13113 pWP->GetWaypointRangeRingsStep() / 60.;
13117 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
13118 pWP->m_lat + radius, pWP->m_lon + radius);
13119 if (!BltBBox.IntersectOut(radar_box)) {
13130void ChartCanvas::DrawBlinkObjects() {
13132 wxRect update_rect;
13134 if (!pWayPointMan)
return;
13136 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
13143 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13146void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13151 wxPoint lAnchorPoint1, lAnchorPoint2;
13165 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13166 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13168 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13169 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13170 dc.SetBrush(*ppBrush);
13174 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13179 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13184 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13189 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13194double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13197 wxPoint lAnchorPoint;
13200 double tlat1, tlon1;
13202 if (pAnchorWatchPoint) {
13203 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13204 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13205 dabs = fabs(d1 / 1852.);
13206 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13211 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13212 pow((
double)(lAnchorPoint.y - r1.y), 2));
13215 if (d1 < 0) lpp = -lpp;
13223void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13226 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13228 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13234 if ((type ==
't') || (type ==
'T')) {
13235 if (BBox.Contains(lat, lon)) {
13237 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13243void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13246 wxDateTime this_now = gTimeSource;
13247 bool cur_time = !gTimeSource.IsValid();
13248 if (cur_time) this_now = wxDateTime::Now();
13249 time_t t_this_now = this_now.GetTicks();
13251 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13253 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13254 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13255 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13256 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13258 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13259 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13260 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13261 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13262 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13263 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13265 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13266 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13267 int font_size = wxMax(10, dFont->GetPointSize());
13270 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13271 false, dFont->GetFaceName());
13273 dc.SetPen(*pblack_pen);
13274 dc.SetBrush(*pgreen_brush);
13278 case GLOBAL_COLOR_SCHEME_DAY:
13281 case GLOBAL_COLOR_SCHEME_DUSK:
13284 case GLOBAL_COLOR_SCHEME_NIGHT:
13285 bm = m_bmTideNight;
13292 int bmw = bm.GetWidth();
13293 int bmh = bm.GetHeight();
13295 float scale_factor = 1.0;
13299 float icon_pixelRefDim = 45;
13304 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13306 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13308 scale_factor *= pix_factor;
13315 scale_factor *= user_scale_factor;
13316 scale_factor *= GetContentScaleFactor();
13319 double marge = 0.05;
13320 std::vector<LLBBox> drawn_boxes;
13321 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13325 if ((type ==
't') || (type ==
'T'))
13330 if (BBox.ContainsMarge(lat, lon, marge)) {
13332 if (GetVP().chart_scale < 500000) {
13333 bool bdrawn =
false;
13334 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13335 if (drawn_boxes[i].Contains(lat, lon)) {
13340 if (bdrawn)
continue;
13343 this_box.Set(lat, lon, lat, lon);
13344 this_box.EnLarge(.005);
13345 drawn_boxes.push_back(this_box);
13351 if (GetVP().chart_scale > 500000) {
13352 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13356 dc.SetFont(*plabelFont);
13368 if (
ptcmgr->GetTideFlowSens(
13369 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13373 ptcmgr->GetHightOrLowTide(
13374 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13375 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13387 if (tctime > t_this_now)
13388 ptcmgr->GetHightOrLowTide(
13389 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13390 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13394 ptcmgr->GetHightOrLowTide(
13395 t_this_now, FORWARD_TEN_MINUTES_STEP,
13396 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13410 int width = (int)(12 * scale_factor + 0.5);
13411 int height = (int)(45 * scale_factor + 0.5);
13412 int linew = wxMax(1, (
int)(scale_factor));
13413 int xDraw = r.x - (width / 2);
13414 int yDraw = r.y - (height / 2);
13417 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13418 int hs = (httime > lttime) ? -4 : 4;
13419 hs *= (int)(scale_factor + 0.5);
13420 if (ts > 0.995 || ts < 0.005) hs = 0;
13421 int ht_y = (int)(height * ts);
13424 pblack_pen->SetWidth(linew);
13425 dc.SetPen(*pblack_pen);
13426 dc.SetBrush(*pyelo_brush);
13427 dc.DrawRectangle(xDraw, yDraw, width, height);
13431 dc.SetPen(*pblue_pen);
13432 dc.SetBrush(*pblue_brush);
13433 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13434 (width - (4 * linew)), height - ht_y);
13440 arrow[0].x = xDraw + 2 * linew;
13441 arrow[1].x = xDraw + width / 2;
13442 arrow[2].x = xDraw + width - 2 * linew;
13443 pyelo_pen->SetWidth(linew);
13444 pblue_pen->SetWidth(linew);
13445 if (ts > 0.35 || ts < 0.15)
13447 hl = (int)(height * 0.25) + yDraw;
13449 arrow[1].y = hl + hs;
13452 dc.SetPen(*pyelo_pen);
13454 dc.SetPen(*pblue_pen);
13455 dc.DrawLines(3, arrow);
13457 if (ts > 0.60 || ts < 0.40)
13459 hl = (int)(height * 0.5) + yDraw;
13461 arrow[1].y = hl + hs;
13464 dc.SetPen(*pyelo_pen);
13466 dc.SetPen(*pblue_pen);
13467 dc.DrawLines(3, arrow);
13469 if (ts < 0.65 || ts > 0.85)
13471 hl = (int)(height * 0.75) + yDraw;
13473 arrow[1].y = hl + hs;
13476 dc.SetPen(*pyelo_pen);
13478 dc.SetPen(*pblue_pen);
13479 dc.DrawLines(3, arrow);
13483 s.Printf(
"%3.1f", nowlev);
13485 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13487 dc.GetTextExtent(s, &wx1, NULL);
13489 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13504void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13507 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13509 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13515 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13516 if ((BBox.Contains(lat, lon))) {
13518 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13524void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13527 float tcvalue, dir;
13531 double lon_last = 0.;
13532 double lat_last = 0.;
13534 double marge = 0.2;
13535 bool cur_time = !gTimeSource.IsValid();
13537 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13538 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13540 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13542 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13543 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13544 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13545 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13546 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13547 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13548 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13549 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13551 double skew_angle = GetVPRotation();
13553 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13554 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13555 int font_size = wxMax(10, dFont->GetPointSize());
13558 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13559 false, dFont->GetFaceName());
13561 float scale_factor = 1.0;
13567 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13569 float nominal_icon_size_pixels = 15;
13570 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13572 scale_factor *= pix_factor;
13579 scale_factor *= user_scale_factor;
13581 scale_factor *= GetContentScaleFactor();
13584 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13590 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13591 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13596 int dd = (int)(5.0 * scale_factor + 0.5);
13607 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13608 dc.SetPen(*pblack_pen);
13609 dc.SetBrush(*porange_brush);
13610 dc.DrawPolygon(4, d);
13613 dc.SetBrush(*pblack_brush);
13614 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13618 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13632 double a1 = fabs(tcvalue) * 10.;
13634 a1 = wxMax(1.0, a1);
13635 double a2 = log10(a1);
13637 float cscale = scale_factor * a2 * 0.3;
13639 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13640 dc.SetPen(*porange_pen);
13641 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13645 if (bDrawCurrentValues) {
13646 dc.SetFont(*pTCFont);
13647 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13648 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13674 if (!pvIDX)
return;
13679 if (pCwin && pCwin->IsShown()) {
13687 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13702 pCwin =
new TCWin(
this, x, y, pvIDX);
13720#define NUM_CURRENT_ARROW_POINTS 9
13721static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13722 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13723 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13724 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13726void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13728 if (
scale > 1e-2) {
13729 float sin_rot = sin(rot_angle * PI / 180.);
13730 float cos_rot = cos(rot_angle * PI / 180.);
13734 float xt = CurrentArrowArray[0].x;
13735 float yt = CurrentArrowArray[0].y;
13737 float xp = (xt * cos_rot) - (yt * sin_rot);
13738 float yp = (xt * sin_rot) + (yt * cos_rot);
13739 int x1 = (int)(xp *
scale);
13740 int y1 = (int)(yp *
scale);
13743 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13744 xt = CurrentArrowArray[ip].x;
13745 yt = CurrentArrowArray[ip].y;
13747 float xp = (xt * cos_rot) - (yt * sin_rot);
13748 float yp = (xt * sin_rot) + (yt * cos_rot);
13749 int x2 = (int)(xp *
scale);
13750 int y2 = (int)(yp *
scale);
13752 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13760wxString ChartCanvas::FindValidUploadPort() {
13763 if (!g_uploadConnection.IsEmpty() &&
13764 g_uploadConnection.StartsWith(
"Serial")) {
13765 port = g_uploadConnection;
13771 for (
auto *cp : TheConnectionParams()) {
13772 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13773 port <<
"Serial:" << cp->Port;
13779void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13782 if (NULL == g_pais_query_dialog_active) {
13783 int pos_x = g_ais_query_dialog_x;
13784 int pos_y = g_ais_query_dialog_y;
13786 if (g_pais_query_dialog_active) {
13787 g_pais_query_dialog_active->Destroy();
13793 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13794 wxPoint(pos_x, pos_y));
13796 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13797 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13798 g_pais_query_dialog_active->SetMMSI(mmsi);
13799 g_pais_query_dialog_active->UpdateText();
13800 wxSize sz = g_pais_query_dialog_active->GetSize();
13802 bool b_reset_pos =
false;
13807 RECT frame_title_rect;
13808 frame_title_rect.left = pos_x;
13809 frame_title_rect.top = pos_y;
13810 frame_title_rect.right = pos_x + sz.x;
13811 frame_title_rect.bottom = pos_y + 30;
13813 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13814 b_reset_pos =
true;
13819 wxRect window_title_rect;
13820 window_title_rect.x = pos_x;
13821 window_title_rect.y = pos_y;
13822 window_title_rect.width = sz.x;
13823 window_title_rect.height = 30;
13825 wxRect ClientRect = wxGetClientDisplayRect();
13826 ClientRect.Deflate(
13828 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13832 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13835 g_pais_query_dialog_active->SetMMSI(mmsi);
13836 g_pais_query_dialog_active->UpdateText();
13839 g_pais_query_dialog_active->Show();
13842void ChartCanvas::ToggleCanvasQuiltMode() {
13843 bool cur_mode = GetQuiltMode();
13845 if (!GetQuiltMode())
13846 SetQuiltMode(
true);
13847 else if (GetQuiltMode()) {
13848 SetQuiltMode(
false);
13849 g_sticky_chart = GetQuiltReferenceChartIndex();
13852 if (cur_mode != GetQuiltMode()) {
13853 SetupCanvasQuiltMode();
13862 if (ps52plib) ps52plib->GenerateStateHash();
13864 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13865 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13868void ChartCanvas::DoCanvasStackDelta(
int direction) {
13869 if (!GetQuiltMode()) {
13870 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13871 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13872 if ((current_stack_index + direction) < 0)
return;
13874 if (m_bpersistent_quilt ) {
13876 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13878 if (IsChartQuiltableRef(new_dbIndex)) {
13879 ToggleCanvasQuiltMode();
13880 SelectQuiltRefdbChart(new_dbIndex);
13881 m_bpersistent_quilt =
false;
13884 SelectChartFromStack(current_stack_index + direction);
13887 std::vector<int> piano_chart_index_array =
13888 GetQuiltExtendedStackdbIndexArray();
13889 int refdb = GetQuiltRefChartdbIndex();
13892 int current_index = -1;
13893 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13894 if (refdb == piano_chart_index_array[i]) {
13899 if (current_index == -1)
return;
13902 int target_family = ctet.GetChartFamily();
13904 int new_index = -1;
13905 int check_index = current_index + direction;
13906 bool found =
false;
13907 int check_dbIndex = -1;
13908 int new_dbIndex = -1;
13912 (
unsigned int)check_index < piano_chart_index_array.size() &&
13913 (check_index >= 0)) {
13914 check_dbIndex = piano_chart_index_array[check_index];
13916 if (target_family == cte.GetChartFamily()) {
13918 new_index = check_index;
13919 new_dbIndex = check_dbIndex;
13923 check_index += direction;
13926 if (!found)
return;
13928 if (!IsChartQuiltableRef(new_dbIndex)) {
13929 ToggleCanvasQuiltMode();
13930 SelectdbChart(new_dbIndex);
13931 m_bpersistent_quilt =
true;
13933 SelectQuiltRefChart(new_index);
13937 gFrame->UpdateGlobalMenuItems();
13939 SetQuiltChartHiLiteIndex(-1);
13950void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13953 switch (event.GetId()) {
13965 DoCanvasStackDelta(1);
13970 DoCanvasStackDelta(-1);
13980 ShowCurrents(!GetbShowCurrent());
13987 ShowTides(!GetbShowTide());
13994 if (0 == m_routeState) {
14001 androidSetRouteAnnunciator(m_routeState == 1);
14007 SetAISCanvasDisplayStyle(-1);
14019void ChartCanvas::SetShowAIS(
bool show) {
14021 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14022 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14025void ChartCanvas::SetAttenAIS(
bool show) {
14026 m_bShowAISScaled = show;
14027 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14028 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14031void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
14034 bool bShowAIS_Array[3] = {
true,
true,
false};
14035 bool bShowScaled_Array[3] = {
false,
true,
true};
14036 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
14037 _(
"Attenuate less critical AIS targets"),
14038 _(
"Hide AIS Targets")};
14039 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
14041 int AIS_Toolbar_Switch = 0;
14042 if (StyleIndx == -1) {
14044 for (
int i = 1; i < ArraySize; i++) {
14045 if ((bShowAIS_Array[i] == m_bShowAIS) &&
14046 (bShowScaled_Array[i] == m_bShowAISScaled))
14047 AIS_Toolbar_Switch = i;
14049 AIS_Toolbar_Switch++;
14050 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
14051 AIS_Toolbar_Switch++;
14054 AIS_Toolbar_Switch = StyleIndx;
14057 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
14059 int AIS_Toolbar_Switch_Next =
14060 AIS_Toolbar_Switch + 1;
14061 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
14062 AIS_Toolbar_Switch_Next++;
14063 if (AIS_Toolbar_Switch_Next >= ArraySize)
14064 AIS_Toolbar_Switch_Next = 0;
14067 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
14068 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
14071void ChartCanvas::TouchAISToolActive() {}
14073void ChartCanvas::UpdateAISTBTool() {}
14081void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
14083 bool b_update =
false;
14084 int cc1_edge_comp = 2;
14085 wxRect rect = m_Compass->
GetRect();
14086 wxSize parent_size = GetSize();
14088 parent_size *= m_displayScale;
14092 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
14093 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
14094 wxRect compass_rect(compass_pt, rect.GetSize());
14096 m_Compass->Move(compass_pt);
14098 if (m_Compass && m_Compass->IsShown())
14099 m_Compass->UpdateStatus(b_force_new | b_update);
14101 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
14102 scaler = wxMax(scaler, 1.0);
14103 wxPoint note_point = wxPoint(
14104 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
14105 if (m_notification_button) {
14106 m_notification_button->Move(note_point);
14107 m_notification_button->UpdateStatus();
14110 if (b_force_new | b_update) Refresh();
14113void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
14114 ChartTypeEnum New_Type,
14115 ChartFamilyEnum New_Family) {
14116 if (!GetpCurrentStack())
return;
14119 if (index < GetpCurrentStack()->nEntry) {
14122 pTentative_Chart =
ChartData->OpenStackChartConditional(
14123 GetpCurrentStack(), index, bDir, New_Type, New_Family);
14125 if (pTentative_Chart) {
14126 if (m_singleChart) m_singleChart->Deactivate();
14128 m_singleChart = pTentative_Chart;
14129 m_singleChart->Activate();
14131 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14132 GetpCurrentStack(), m_singleChart->GetFullPath());
14145 double best_scale_ppm = GetBestVPScale(m_singleChart);
14146 double rotation = GetVPRotation();
14147 double oldskew = GetVPSkew();
14148 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14150 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14151 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14152 if (fabs(newskew) > 0.0001) rotation = newskew;
14155 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14157 UpdateGPSCompassStatusBox(
true);
14161 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14162 if (idx < 0)
return;
14164 std::vector<int> piano_active_chart_index_array;
14165 piano_active_chart_index_array.push_back(
14166 GetpCurrentStack()->GetCurrentEntrydbIndex());
14167 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14170void ChartCanvas::SelectdbChart(
int dbindex) {
14171 if (!GetpCurrentStack())
return;
14174 if (dbindex >= 0) {
14177 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14179 if (pTentative_Chart) {
14180 if (m_singleChart) m_singleChart->Deactivate();
14182 m_singleChart = pTentative_Chart;
14183 m_singleChart->Activate();
14185 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14186 GetpCurrentStack(), m_singleChart->GetFullPath());
14199 double best_scale_ppm = GetBestVPScale(m_singleChart);
14203 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14213void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14216 if (!GetQuiltMode()) {
14217 if (GetpCurrentStack()) {
14218 int stack_index = -1;
14219 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14220 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14221 if (check_dbIndex < 0)
continue;
14223 ChartData->GetChartTableEntry(check_dbIndex);
14224 if (type == cte.GetChartType()) {
14227 }
else if (family == cte.GetChartFamily()) {
14233 if (stack_index >= 0) {
14234 SelectChartFromStack(stack_index);
14238 int sel_dbIndex = -1;
14239 std::vector<int> piano_chart_index_array =
14240 GetQuiltExtendedStackdbIndexArray();
14241 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14242 int check_dbIndex = piano_chart_index_array[i];
14244 if (type == cte.GetChartType()) {
14245 if (IsChartQuiltableRef(check_dbIndex)) {
14246 sel_dbIndex = check_dbIndex;
14249 }
else if (family == cte.GetChartFamily()) {
14250 if (IsChartQuiltableRef(check_dbIndex)) {
14251 sel_dbIndex = check_dbIndex;
14257 if (sel_dbIndex >= 0) {
14258 SelectQuiltRefdbChart(sel_dbIndex,
false);
14260 AdjustQuiltRefChart();
14267 SetQuiltChartHiLiteIndex(-1);
14272bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14273 return std::find(m_tile_yesshow_index_array.begin(),
14274 m_tile_yesshow_index_array.end(),
14275 index) != m_tile_yesshow_index_array.end();
14278bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14279 return std::find(m_tile_noshow_index_array.begin(),
14280 m_tile_noshow_index_array.end(),
14281 index) != m_tile_noshow_index_array.end();
14284void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14285 if (std::find(m_tile_noshow_index_array.begin(),
14286 m_tile_noshow_index_array.end(),
14287 index) == m_tile_noshow_index_array.end()) {
14288 m_tile_noshow_index_array.push_back(index);
14298void ChartCanvas::HandlePianoClick(
14299 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14302 if (!m_pCurrentStack)
return;
14318 double distance = 25000;
14319 int closest_index = -1;
14320 for (
int chart_index : selected_dbIndex_array) {
14322 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14323 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14326 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14327 if (test_distance < distance) {
14328 distance = test_distance;
14329 closest_index = chart_index;
14333 int selected_dbIndex = selected_dbIndex_array[0];
14334 if (closest_index >= 0) selected_dbIndex = closest_index;
14336 if (!GetQuiltMode()) {
14337 if (m_bpersistent_quilt ) {
14338 if (IsChartQuiltableRef(selected_dbIndex)) {
14339 ToggleCanvasQuiltMode();
14340 SelectQuiltRefdbChart(selected_dbIndex);
14341 m_bpersistent_quilt =
false;
14343 SelectChartFromStack(selected_index);
14346 SelectChartFromStack(selected_index);
14347 g_sticky_chart = selected_dbIndex;
14351 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14355 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14356 bool bfound =
false;
14357 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14358 if (m_tile_noshow_index_array[i] ==
14359 selected_dbIndex) {
14360 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14367 m_tile_noshow_index_array.push_back(selected_dbIndex);
14371 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14372 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14376 if (IsChartQuiltableRef(selected_dbIndex)) {
14382 bool set_scale =
false;
14383 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14384 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14390 SelectQuiltRefdbChart(selected_dbIndex,
true);
14392 SelectQuiltRefdbChart(selected_dbIndex,
false);
14397 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14399 double proposed_scale_onscreen =
14402 if (g_bPreserveScaleOnX) {
14403 proposed_scale_onscreen =
14404 wxMin(proposed_scale_onscreen,
14406 GetCanvasWidth()));
14408 proposed_scale_onscreen =
14409 wxMin(proposed_scale_onscreen,
14411 GetCanvasWidth()));
14413 proposed_scale_onscreen =
14414 wxMax(proposed_scale_onscreen,
14423 ToggleCanvasQuiltMode();
14424 SelectdbChart(selected_dbIndex);
14425 m_bpersistent_quilt =
true;
14430 SetQuiltChartHiLiteIndex(-1);
14431 gFrame->UpdateGlobalMenuItems();
14433 HideChartInfoWindow();
14438void ChartCanvas::HandlePianoRClick(
14439 int x,
int y,
int selected_index,
14440 const std::vector<int> &selected_dbIndex_array) {
14443 if (!GetpCurrentStack())
return;
14445 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14446 UpdateCanvasControlBar();
14448 SetQuiltChartHiLiteIndex(-1);
14451void ChartCanvas::HandlePianoRollover(
14452 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14453 int n_charts,
int scale) {
14456 if (!GetpCurrentStack())
return;
14461 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14463 if (!GetQuiltMode()) {
14464 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14467 std::vector<int> piano_chart_index_array;
14468 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14469 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14470 if ((GetpCurrentStack()->nEntry > 1) ||
14471 (piano_chart_index_array.size() >= 1)) {
14472 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14474 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14476 }
else if (GetpCurrentStack()->nEntry == 1) {
14478 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14479 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14480 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14482 }
else if ((-1 == selected_index) &&
14483 (0 == selected_dbIndex_array.size())) {
14484 ShowChartInfoWindow(key_location.x, -1);
14488 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14490 if ((GetpCurrentStack()->nEntry > 1) ||
14491 (piano_chart_index_array.size() >= 1)) {
14493 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14494 selected_dbIndex_array);
14495 else if (n_charts == 1)
14496 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14498 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14505void ChartCanvas::ClearPianoRollover() {
14506 ClearQuiltChartHiLiteIndexArray();
14507 ShowChartInfoWindow(0, -1);
14508 std::vector<int> vec;
14509 ShowCompositeInfoWindow(0, 0, 0, vec);
14513void ChartCanvas::UpdateCanvasControlBar() {
14514 if (m_pianoFrozen)
return;
14516 if (!GetpCurrentStack())
return;
14518 if (!g_bShowChartBar)
return;
14521 int sel_family = -1;
14523 std::vector<int> piano_chart_index_array;
14524 std::vector<int> empty_piano_chart_index_array;
14526 wxString old_hash = m_Piano->GetStoredHash();
14528 if (GetQuiltMode()) {
14529 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14530 GetQuiltFullScreendbIndexArray());
14532 std::vector<int> piano_active_chart_index_array =
14533 GetQuiltCandidatedbIndexArray();
14534 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14536 std::vector<int> piano_eclipsed_chart_index_array =
14537 GetQuiltEclipsedStackdbIndexArray();
14538 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14540 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14541 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14543 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14544 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14546 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14547 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14550 if (m_singleChart) {
14551 sel_type = m_singleChart->GetChartType();
14552 sel_family = m_singleChart->GetChartFamily();
14557 std::vector<int> piano_skew_chart_index_array;
14558 std::vector<int> piano_tmerc_chart_index_array;
14559 std::vector<int> piano_poly_chart_index_array;
14561 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14563 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14564 double skew_norm = ctei.GetChartSkew();
14565 if (skew_norm > 180.) skew_norm -= 360.;
14567 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14568 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14571 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14572 if (fabs(skew_norm) > 1.)
14573 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14575 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14576 }
else if (fabs(skew_norm) > 1.)
14577 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14579 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14580 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14581 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14583 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14584 if (new_hash != old_hash) {
14585 m_Piano->FormatKeys();
14586 HideChartInfoWindow();
14587 m_Piano->ResetRollover();
14588 SetQuiltChartHiLiteIndex(-1);
14589 m_brepaint_piano =
true;
14595 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14597 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14598 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14599 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14600 if (e == CHART_FAMILY_RASTER) mask |= 1;
14601 if (e == CHART_FAMILY_VECTOR) {
14602 if (t == CHART_TYPE_CM93COMP)
14609 wxString s_indicated;
14610 if (sel_type == CHART_TYPE_CM93COMP)
14611 s_indicated =
"cm93";
14613 if (sel_family == CHART_FAMILY_RASTER)
14614 s_indicated =
"raster";
14615 else if (sel_family == CHART_FAMILY_VECTOR)
14616 s_indicated =
"vector";
14619 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14622void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14624void ChartCanvas::PianoPopupMenu(
14625 int x,
int y,
int selected_index,
14626 const std::vector<int> &selected_dbIndex_array) {
14627 if (!GetpCurrentStack())
return;
14630 if (!GetQuiltMode())
return;
14632 m_piano_ctx_menu =
new wxMenu();
14634 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14644 menu_selected_dbIndex = selected_dbIndex_array[0];
14645 menu_selected_index = selected_index;
14648 bool b_is_in_noshow =
false;
14649 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14650 if (m_quilt_noshow_index_array[i] ==
14651 menu_selected_dbIndex)
14653 b_is_in_noshow =
true;
14658 if (b_is_in_noshow) {
14659 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14660 _(
"Show This Chart"));
14661 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14662 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14663 }
else if (GetpCurrentStack()->nEntry > 1) {
14664 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14665 _(
"Hide This Chart"));
14666 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14667 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14671 wxPoint pos = wxPoint(x, y - 30);
14674 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14675 PopupMenu(m_piano_ctx_menu, pos);
14677 delete m_piano_ctx_menu;
14678 m_piano_ctx_menu = NULL;
14680 HideChartInfoWindow();
14681 m_Piano->ResetRollover();
14683 SetQuiltChartHiLiteIndex(-1);
14684 ClearQuiltChartHiLiteIndexArray();
14689void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14690 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14691 if (m_quilt_noshow_index_array[i] ==
14692 menu_selected_dbIndex)
14694 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14700void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14701 if (!GetpCurrentStack())
return;
14704 RemoveChartFromQuilt(menu_selected_dbIndex);
14708 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14709 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14711 int i = menu_selected_index + 1;
14712 bool b_success =
false;
14713 while (i < GetpCurrentStack()->nEntry - 1) {
14714 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14715 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14716 SelectQuiltRefChart(i);
14726 i = menu_selected_index - 1;
14728 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14729 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14730 SelectQuiltRefChart(i);
14740void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14742 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14743 if (m_quilt_noshow_index_array[i] ==
14746 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14751 m_quilt_noshow_index_array.push_back(dbIndex);
14754bool ChartCanvas::UpdateS52State() {
14755 bool retval =
false;
14758 ps52plib->SetShowS57Text(m_encShowText);
14759 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14760 ps52plib->m_bShowSoundg = m_encShowDepth;
14761 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14762 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14765 if (!m_encShowLights)
14766 ps52plib->AddObjNoshow(
"LIGHTS");
14768 ps52plib->RemoveObjNoshow(
"LIGHTS");
14769 ps52plib->SetLightsOff(!m_encShowLights);
14770 ps52plib->m_bExtendLightSectors =
true;
14773 ps52plib->SetAnchorOn(m_encShowAnchor);
14774 ps52plib->SetQualityOfData(m_encShowDataQual);
14780void ChartCanvas::SetShowENCDataQual(
bool show) {
14781 m_encShowDataQual = show;
14782 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14783 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14785 m_s52StateHash = 0;
14788void ChartCanvas::SetShowENCText(
bool show) {
14789 m_encShowText = show;
14790 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14791 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14793 m_s52StateHash = 0;
14796void ChartCanvas::SetENCDisplayCategory(
int category) {
14797 m_encDisplayCategory = category;
14798 m_s52StateHash = 0;
14801void ChartCanvas::SetShowENCDepth(
bool show) {
14802 m_encShowDepth = show;
14803 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14804 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14806 m_s52StateHash = 0;
14809void ChartCanvas::SetShowENCLightDesc(
bool show) {
14810 m_encShowLightDesc = show;
14811 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14812 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14814 m_s52StateHash = 0;
14817void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14818 m_encShowBuoyLabels = show;
14819 m_s52StateHash = 0;
14822void ChartCanvas::SetShowENCLights(
bool show) {
14823 m_encShowLights = show;
14824 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14825 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14827 m_s52StateHash = 0;
14830void ChartCanvas::SetShowENCAnchor(
bool show) {
14831 m_encShowAnchor = show;
14832 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14833 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14835 m_s52StateHash = 0;
14838wxRect ChartCanvas::GetMUIBarRect() {
14841 rv = m_muiBar->GetRect();
14847void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14848 if (!GetAlertString().IsEmpty()) {
14849 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14850 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14852 dc.SetFont(*pfont);
14853 dc.SetPen(*wxTRANSPARENT_PEN);
14855 dc.SetBrush(wxColour(243, 229, 47));
14857 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14861 wxRect sbr = GetScaleBarRect();
14862 int xp = sbr.x + sbr.width + 10;
14863 int yp = (sbr.y + sbr.height) - h;
14865 int wdraw = w + 10;
14866 dc.DrawRectangle(xp, yp, wdraw, h);
14867 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14868 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14878#define BRIGHT_XCALIB
14879#define __OPCPN_USEICC__
14882#ifdef __OPCPN_USEICC__
14883int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14884 double co_green,
double co_blue);
14886wxString temp_file_name;
14890class ocpnCurtain:
public wxDialog
14892 DECLARE_CLASS( ocpnCurtain )
14893 DECLARE_EVENT_TABLE()
14896 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14898 bool ProcessEvent(wxEvent& event);
14902IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14904BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14907ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14909 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14912ocpnCurtain::~ocpnCurtain()
14916bool ocpnCurtain::ProcessEvent(wxEvent& event)
14918 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14919 return GetParent()->GetEventHandler()->ProcessEvent(event);
14924#include <windows.h>
14927typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14928typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14929SetDeviceGammaRamp_ptr_type
14930 g_pSetDeviceGammaRamp;
14931GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14933WORD *g_pSavedGammaMap;
14937int InitScreenBrightness() {
14940 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14944 if (NULL == hGDI32DLL) {
14945 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14947 if (NULL != hGDI32DLL) {
14949 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14950 hGDI32DLL,
"SetDeviceGammaRamp");
14951 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14952 hGDI32DLL,
"GetDeviceGammaRamp");
14955 if ((NULL == g_pSetDeviceGammaRamp) ||
14956 (NULL == g_pGetDeviceGammaRamp)) {
14957 FreeLibrary(hGDI32DLL);
14966 if (!g_pSavedGammaMap) {
14967 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14970 bbr = g_pGetDeviceGammaRamp(
14971 hDC, g_pSavedGammaMap);
14972 ReleaseDC(NULL, hDC);
14977 wxRegKey *pRegKey =
new wxRegKey(
14978 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14979 "NT\\CurrentVersion\\ICM");
14980 if (!pRegKey->Exists()) pRegKey->Create();
14981 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14983 g_brightness_init =
true;
14989 if (NULL == g_pcurtain) {
14990 if (gFrame->CanSetTransparent()) {
14992 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14993 wxPoint(0, 0), ::wxGetDisplaySize(),
14994 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14995 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
15002 g_pcurtain->Hide();
15004 HWND hWnd = GetHwndOf(g_pcurtain);
15005 SetWindowLong(hWnd, GWL_EXSTYLE,
15006 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
15007 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
15008 g_pcurtain->SetTransparent(0);
15010 g_pcurtain->Maximize();
15011 g_pcurtain->Show();
15014 g_pcurtain->Enable();
15015 g_pcurtain->Disable();
15022 g_brightness_init =
true;
15028 wxString cmd(
"xcalib -version");
15030 wxArrayString output;
15031 long r = wxExecute(cmd, output);
15034 " External application \"xcalib\" not found. Screen brightness "
15037 g_brightness_init =
true;
15042int RestoreScreenBrightness() {
15045 if (g_pSavedGammaMap) {
15046 HDC hDC = GetDC(NULL);
15047 g_pSetDeviceGammaRamp(hDC,
15049 ReleaseDC(NULL, hDC);
15051 free(g_pSavedGammaMap);
15052 g_pSavedGammaMap = NULL;
15056 g_pcurtain->Close();
15057 g_pcurtain->Destroy();
15061 g_brightness_init =
false;
15066#ifdef BRIGHT_XCALIB
15067 if (g_brightness_init) {
15069 cmd =
"xcalib -clear";
15070 wxExecute(cmd, wxEXEC_ASYNC);
15071 g_brightness_init =
false;
15081int SetScreenBrightness(
int brightness) {
15088 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
15090 g_pcurtain->Close();
15091 g_pcurtain->Destroy();
15095 InitScreenBrightness();
15097 if (NULL == hGDI32DLL) {
15099 wchar_t wdll_name[80];
15100 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
15101 LPCWSTR cstr = wdll_name;
15103 hGDI32DLL = LoadLibrary(cstr);
15105 if (NULL != hGDI32DLL) {
15107 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
15108 hGDI32DLL,
"SetDeviceGammaRamp");
15109 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
15110 hGDI32DLL,
"GetDeviceGammaRamp");
15113 if ((NULL == g_pSetDeviceGammaRamp) ||
15114 (NULL == g_pGetDeviceGammaRamp)) {
15115 FreeLibrary(hGDI32DLL);
15122 HDC hDC = GetDC(NULL);
15133 int increment = brightness * 256 / 100;
15136 WORD GammaTable[3][256];
15139 for (
int i = 0; i < 256; i++) {
15140 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15141 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15142 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15144 table_val += increment;
15146 if (table_val > 65535) table_val = 65535;
15149 g_pSetDeviceGammaRamp(hDC, GammaTable);
15150 ReleaseDC(NULL, hDC);
15157 if (g_pSavedGammaMap) {
15158 HDC hDC = GetDC(NULL);
15159 g_pSetDeviceGammaRamp(hDC,
15161 ReleaseDC(NULL, hDC);
15164 if (brightness < 100) {
15165 if (NULL == g_pcurtain) InitScreenBrightness();
15168 int sbrite = wxMax(1, brightness);
15169 sbrite = wxMin(100, sbrite);
15171 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15175 g_pcurtain->Close();
15176 g_pcurtain->Destroy();
15186#ifdef BRIGHT_XCALIB
15188 if (!g_brightness_init) {
15189 last_brightness = 100;
15190 g_brightness_init =
true;
15191 temp_file_name = wxFileName::CreateTempFileName(
"");
15192 InitScreenBrightness();
15195#ifdef __OPCPN_USEICC__
15198 if (!CreateSimpleICCProfileFile(
15199 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15200 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15201 wxString cmd(
"xcalib ");
15202 cmd += temp_file_name;
15204 wxExecute(cmd, wxEXEC_ASYNC);
15213 if (brightness > last_brightness) {
15215 cmd =
"xcalib -clear";
15216 wxExecute(cmd, wxEXEC_ASYNC);
15218 ::wxMilliSleep(10);
15220 int brite_adj = wxMax(1, brightness);
15221 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15222 wxExecute(cmd, wxEXEC_ASYNC);
15224 int brite_adj = wxMax(1, brightness);
15225 int factor = (brite_adj * 100) / last_brightness;
15226 factor = wxMax(1, factor);
15228 cmd.Printf(
"xcalib -co %2d -a", factor);
15229 wxExecute(cmd, wxEXEC_ASYNC);
15234 last_brightness = brightness;
15241#ifdef __OPCPN_USEICC__
15243#define MLUT_TAG 0x6d4c5554L
15244#define VCGT_TAG 0x76636774L
15246int GetIntEndian(
unsigned char *s) {
15251 p = (
unsigned char *)&ret;
15254 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15256 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15261unsigned short GetShortEndian(
unsigned char *s) {
15262 unsigned short ret;
15266 p = (
unsigned char *)&ret;
15269 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15271 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15277int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15278 double co_green,
double co_blue) {
15282 fp = fopen(file_name,
"wb");
15283 if (!fp)
return -1;
15289 for (
int i = 0; i < 128; i++) header[i] = 0;
15291 fwrite(header, 128, 1, fp);
15295 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15296 fwrite(&numTags, 1, 4, fp);
15298 int tagName0 = VCGT_TAG;
15299 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15300 fwrite(&tagName, 1, 4, fp);
15302 int tagOffset0 = 128 + 4 *
sizeof(int);
15303 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15304 fwrite(&tagOffset, 1, 4, fp);
15307 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15308 fwrite(&tagSize, 1, 4, fp);
15310 fwrite(&tagName, 1, 4, fp);
15312 fwrite(&tagName, 1, 4, fp);
15317 int gammatype0 = 0;
15318 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15319 fwrite(&gammatype, 1, 4, fp);
15321 int numChannels0 = 3;
15322 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15323 fwrite(&numChannels, 1, 2, fp);
15325 int numEntries0 = 256;
15326 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15327 fwrite(&numEntries, 1, 2, fp);
15329 int entrySize0 = 1;
15330 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15331 fwrite(&entrySize, 1, 2, fp);
15333 unsigned char ramp[256];
15336 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15337 fwrite(ramp, 256, 1, fp);
15340 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15341 fwrite(ramp, 256, 1, fp);
15344 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15345 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".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
PluginLoader is a backend module without any direct GUI functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
MySQL based storage for routes, tracks, etc.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
User notifications manager.
Notification Manager GUI.
OCPN_AUIManager * g_pauimgr
Global instance.
Optimized wxBitmap Object.
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.