33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
44#include "model/geodesic.h"
50#include "model/nav_object_database.h"
106#include "SystemCmdSound.h"
110#include "tide_time.h"
117#include "s57_ocpn_utils.h"
120#include "androidUTIL.h"
130#include <wx/msw/msvcrt.h>
139#define printf printf2
141int __cdecl printf2(
const char *format, ...) {
145 va_start(argptr, format);
146 int ret = vsnprintf(str,
sizeof(str), format, argptr);
148 OutputDebugStringA(str);
153#if defined(__MSVC__) && (_MSC_VER < 1700)
154#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
160#define OCPN_ALT_MENUBAR 1
168extern ColorScheme global_color_scheme;
169extern wxColor GetDimColor(wxColor c);
171static bool g_bSmoothRecenter =
true;
172static bool bDrawCurrentValues;
193static bool mouse_leftisdown;
194static bool g_brouteCreating;
195static int r_gamma_mult;
196static int g_gamma_mult;
197static int b_gamma_mult;
198static int gamma_state;
199static bool g_brightness_init;
200static int last_brightness;
201static wxGLContext *g_pGLcontext;
204static wxDialog *g_pcurtain;
206static wxString g_lastS52PLIBPluginMessage;
209#define MAX_BRIGHT 100
215EVT_PAINT(ChartCanvas::OnPaint)
216EVT_ACTIVATE(ChartCanvas::OnActivate)
217EVT_SIZE(ChartCanvas::OnSize)
218#ifndef HAVE_WX_GESTURE_EVENTS
219EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
221EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
222EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
223EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
224EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
225EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
226EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
227EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
228EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
229EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
230EVT_KEY_UP(ChartCanvas::OnKeyUp)
231EVT_CHAR(ChartCanvas::OnKeyChar)
232EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
233EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
234EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
235EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
236EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
237EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
238EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
239EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
240EVT_TIMER(MENU_TIMER, ChartCanvas::OnMenuTimer)
246 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
247 m_nmea_log(nmea_log) {
248 parent_frame = (
MyFrame *)frame;
249 m_canvasIndex = canvasIndex;
253 SetBackgroundColour(wxColour(0, 0, 0));
254 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
258 m_bDrawingRoute =
false;
259 m_bRouteEditing =
false;
260 m_bMarkEditing =
false;
261 m_bRoutePoinDragging =
false;
262 m_bIsInRadius =
false;
263 m_bMayToggleMenuBar =
true;
266 m_bShowNavobjects =
true;
268 m_bAppendingRoute =
false;
269 pThumbDIBShow = NULL;
270 m_bShowCurrent =
false;
272 bShowingCurrent =
false;
276 m_b_paint_enable =
true;
279 pss_overlay_bmp = NULL;
280 pss_overlay_mask = NULL;
281 m_bChartDragging =
false;
282 m_bMeasure_Active =
false;
283 m_bMeasure_DistCircle =
false;
284 m_pMeasureRoute = NULL;
285 m_pTrackRolloverWin = NULL;
286 m_pRouteRolloverWin = NULL;
287 m_pAISRolloverWin = NULL;
289 m_disable_edge_pan =
false;
290 m_dragoffsetSet =
false;
294 m_singleChart = NULL;
295 m_upMode = NORTH_UP_MODE;
297 m_bShowAISScaled =
false;
298 m_timed_move_vp_active =
false;
300 m_disable_adjust_on_zoom =
false;
307 m_pSelectedRoute = NULL;
308 m_pSelectedTrack = NULL;
309 m_pRoutePointEditTarget = NULL;
310 m_pFoundPoint = NULL;
311 m_pMouseRoute = NULL;
312 m_prev_pMousePoint = NULL;
313 m_pEditRouteArray = NULL;
314 m_pFoundRoutePoint = NULL;
315 m_FinishRouteOnKillFocus =
true;
317 m_pRolloverRouteSeg = NULL;
318 m_pRolloverTrackSeg = NULL;
319 m_bsectors_shown =
false;
321 m_bbrightdir =
false;
326 m_pos_image_user_day = NULL;
327 m_pos_image_user_dusk = NULL;
328 m_pos_image_user_night = NULL;
329 m_pos_image_user_grey_day = NULL;
330 m_pos_image_user_grey_dusk = NULL;
331 m_pos_image_user_grey_night = NULL;
334 m_rotation_speed = 0;
340 m_pos_image_user_yellow_day = NULL;
341 m_pos_image_user_yellow_dusk = NULL;
342 m_pos_image_user_yellow_night = NULL;
344 SetOwnShipState(SHIP_INVALID);
346 undo =
new Undo(
this);
352 m_focus_indicator_pix = 1;
354 m_pCurrentStack = NULL;
355 m_bpersistent_quilt =
false;
356 m_piano_ctx_menu = NULL;
358 m_NotificationsList = NULL;
359 m_notification_button = NULL;
361 g_ChartNotRenderScaleFactor = 2.0;
362 m_bShowScaleInStatusBar =
true;
365 m_bShowScaleInStatusBar =
false;
366 m_show_focus_bar =
true;
368 m_bShowOutlines =
false;
369 m_bDisplayGrid =
false;
370 m_bShowDepthUnits =
true;
371 m_encDisplayCategory = (int)STANDARD;
373 m_encShowLights =
true;
374 m_encShowAnchor =
true;
375 m_encShowDataQual =
false;
377 m_pQuilt =
new Quilt(
this);
382 g_PrintingInProgress =
false;
384#ifdef HAVE_WX_GESTURE_EVENTS
385 m_oldVPSScale = -1.0;
386 m_popupWanted =
false;
389 m_inLongPress =
false;
392 singleClickEventIsValid =
false;
401 pCursorPencil = NULL;
406 SetCursor(*pCursorArrow);
408 pPanTimer =
new wxTimer(
this, m_MouseDragging);
411 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
412 pMovementTimer->Stop();
414 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
415 pMovementStopTimer->Stop();
417 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
418 pRotDefTimer->Stop();
420 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
421 m_DoubleClickTimer->Stop();
423 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
424 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
425 m_chart_drag_inertia_active =
false;
427 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
428 m_animationActive =
false;
429 m_menuTimer.SetOwner(
this, MENU_TIMER);
433 m_panx_target_final = m_pany_target_final = 0;
434 m_panx_target_now = m_pany_target_now = 0;
436 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
437 pCurTrackTimer->Stop();
438 m_curtrack_timer_msec = 10;
440 m_wheelzoom_stop_oneshot = 0;
441 m_last_wheel_dir = 0;
443 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
445 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
447 m_rollover_popup_timer_msec = 20;
449 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
451 m_b_rot_hidef =
true;
456 m_upMode = NORTH_UP_MODE;
457 m_bLookAhead =
false;
461 m_cs = GLOBAL_COLOR_SCHEME_DAY;
464 VPoint.view_scale_ppm = 1;
468 m_canvas_scale_factor = 1.;
470 m_canvas_width = 1000;
472 m_overzoomTextWidth = 0;
473 m_overzoomTextHeight = 0;
482 m_pEM_Fathoms = NULL;
484 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
486 m_pEM_OverZoom = NULL;
488 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
496 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
499 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
502 double factor_dusk = 0.5;
503 double factor_night = 0.25;
506 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
508 int rimg_width = m_os_image_red_day.GetWidth();
509 int rimg_height = m_os_image_red_day.GetHeight();
511 m_os_image_red_dusk = m_os_image_red_day.Copy();
512 m_os_image_red_night = m_os_image_red_day.Copy();
514 for (
int iy = 0; iy < rimg_height; iy++) {
515 for (
int ix = 0; ix < rimg_width; ix++) {
516 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
517 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
518 m_os_image_red_day.GetGreen(ix, iy),
519 m_os_image_red_day.GetBlue(ix, iy));
520 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
521 hsv.value = hsv.value * factor_dusk;
522 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
523 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
525 hsv = wxImage::RGBtoHSV(rgb);
526 hsv.value = hsv.value * factor_night;
527 nrgb = wxImage::HSVtoRGB(hsv);
528 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
534 m_os_image_grey_day =
535 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
537 int gimg_width = m_os_image_grey_day.GetWidth();
538 int gimg_height = m_os_image_grey_day.GetHeight();
540 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
541 m_os_image_grey_night = m_os_image_grey_day.Copy();
543 for (
int iy = 0; iy < gimg_height; iy++) {
544 for (
int ix = 0; ix < gimg_width; ix++) {
545 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
546 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
547 m_os_image_grey_day.GetGreen(ix, iy),
548 m_os_image_grey_day.GetBlue(ix, iy));
549 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
550 hsv.value = hsv.value * factor_dusk;
551 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
552 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
554 hsv = wxImage::RGBtoHSV(rgb);
555 hsv.value = hsv.value * factor_night;
556 nrgb = wxImage::HSVtoRGB(hsv);
557 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
563 m_os_image_yellow_day = m_os_image_red_day.Copy();
565 gimg_width = m_os_image_yellow_day.GetWidth();
566 gimg_height = m_os_image_yellow_day.GetHeight();
568 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
569 m_os_image_yellow_night = m_os_image_red_day.Copy();
571 for (
int iy = 0; iy < gimg_height; iy++) {
572 for (
int ix = 0; ix < gimg_width; ix++) {
573 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
574 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
575 m_os_image_yellow_day.GetGreen(ix, iy),
576 m_os_image_yellow_day.GetBlue(ix, iy));
577 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
578 hsv.hue += 60. / 360.;
579 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
580 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
582 hsv = wxImage::RGBtoHSV(rgb);
583 hsv.value = hsv.value * factor_dusk;
584 hsv.hue += 60. / 360.;
585 nrgb = wxImage::HSVtoRGB(hsv);
586 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
588 hsv = wxImage::RGBtoHSV(rgb);
589 hsv.hue += 60. / 360.;
590 hsv.value = hsv.value * factor_night;
591 nrgb = wxImage::HSVtoRGB(hsv);
592 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
598 m_pos_image_red = &m_os_image_red_day;
599 m_pos_image_yellow = &m_os_image_yellow_day;
600 m_pos_image_grey = &m_os_image_grey_day;
604 m_pBrightPopup = NULL;
607 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
612 m_Piano =
new Piano(
this);
614 m_bShowCompassWin =
true;
616 m_Compass->SetScaleFactor(g_compass_scalefactor);
617 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
620 m_notification_button->SetScaleFactor(g_compass_scalefactor);
621 m_notification_button->Show(
true);
623 m_pianoFrozen =
false;
625 SetMinSize(wxSize(200, 200));
627 m_displayScale = 1.0;
628#if defined(__WXOSX__) || defined(__WXGTK3__)
630 m_displayScale = GetContentScaleFactor();
632 VPoint.SetPixelScale(m_displayScale);
634#ifdef HAVE_WX_GESTURE_EVENTS
637 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
638 wxLogError(
"Failed to enable touch events");
643 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
644 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
646 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
647 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
649 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
650 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
652 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
653 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
658 auto ¬eman = NotificationManager::GetInstance();
660 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
661 evt_notificationlist_change_listener.Listen(
662 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
663 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
664 if (m_NotificationsList && m_NotificationsList->IsShown()) {
665 m_NotificationsList->ReloadNotificationList();
671ChartCanvas::~ChartCanvas() {
672 delete pThumbDIBShow;
680 delete pCursorPencil;
684 delete pMovementTimer;
685 delete pMovementStopTimer;
686 delete pCurTrackTimer;
688 delete m_DoubleClickTimer;
690 delete m_pTrackRolloverWin;
691 delete m_pRouteRolloverWin;
692 delete m_pAISRolloverWin;
693 delete m_pBrightPopup;
699 m_dc_route.SelectObject(wxNullBitmap);
702 delete pWorldBackgroundChart;
703 delete pss_overlay_bmp;
707 delete m_pEM_Fathoms;
709 delete m_pEM_OverZoom;
714 delete m_pos_image_user_day;
715 delete m_pos_image_user_dusk;
716 delete m_pos_image_user_night;
717 delete m_pos_image_user_grey_day;
718 delete m_pos_image_user_grey_dusk;
719 delete m_pos_image_user_grey_night;
720 delete m_pos_image_user_yellow_day;
721 delete m_pos_image_user_yellow_dusk;
722 delete m_pos_image_user_yellow_night;
726 if (!g_bdisable_opengl) {
729#if wxCHECK_VERSION(2, 9, 0)
730 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
737 MUIBar *muiBar = m_muiBar;
741 delete m_pCurrentStack;
746void ChartCanvas::SetupGridFont() {
747 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
749 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
751 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
752 FALSE, wxString(
"Arial"));
755void ChartCanvas::RebuildCursors() {
761 delete pCursorPencil;
765 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
769 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
770 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
771 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
772 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
773 wxImage ICursorPencil =
774 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
775 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
777#if !defined(__WXMSW__) && !defined(__WXQT__)
778 ICursorLeft.ConvertAlphaToMask(128);
779 ICursorRight.ConvertAlphaToMask(128);
780 ICursorUp.ConvertAlphaToMask(128);
781 ICursorDown.ConvertAlphaToMask(128);
782 ICursorPencil.ConvertAlphaToMask(10);
783 ICursorCross.ConvertAlphaToMask(10);
786 if (ICursorLeft.Ok()) {
787 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
788 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
789 pCursorLeft =
new wxCursor(ICursorLeft);
791 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
793 if (ICursorRight.Ok()) {
794 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
795 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
796 pCursorRight =
new wxCursor(ICursorRight);
798 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
800 if (ICursorUp.Ok()) {
801 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
802 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
803 pCursorUp =
new wxCursor(ICursorUp);
805 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
807 if (ICursorDown.Ok()) {
808 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
809 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
810 pCursorDown =
new wxCursor(ICursorDown);
812 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
814 if (ICursorPencil.Ok()) {
815 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
816 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
817 pCursorPencil =
new wxCursor(ICursorPencil);
819 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
821 if (ICursorCross.Ok()) {
822 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
823 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
824 pCursorCross =
new wxCursor(ICursorCross);
826 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
828 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
829 pPlugIn_Cursor = NULL;
832void ChartCanvas::CanvasApplyLocale() {
833 CreateDepthUnitEmbossMaps(m_cs);
834 CreateOZEmbossMapData(m_cs);
837void ChartCanvas::SetupGlCanvas() {
840 if (!g_bdisable_opengl) {
842 wxLogMessage(
"Creating glChartCanvas");
847 if (IsPrimaryCanvas()) {
854 wxGLContext *pctx =
new wxGLContext(m_glcc);
855 m_glcc->SetContext(pctx);
859 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
861 m_glcc->SetContext(g_pGLcontext);
871 if (!g_bdisable_opengl) {
874 wxLogMessage(
"Creating glChartCanvas");
878 if (IsPrimaryCanvas()) {
879 qDebug() <<
"Creating Primary glChartCanvas";
887 wxGLContext *pctx =
new wxGLContext(m_glcc);
888 m_glcc->SetContext(pctx);
890 m_glcc->m_pParentCanvas =
this;
893 qDebug() <<
"Creating Secondary glChartCanvas";
899 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
902 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
903 m_glcc->SetContext(pwxctx);
904 m_glcc->m_pParentCanvas =
this;
912void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
913 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
928 if (m_routeState && m_FinishRouteOnKillFocus)
929 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
931 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
935void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
936 m_routeFinishTimer.Stop();
940 gFrame->UpdateGlobalMenuItems(
this);
942 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
945void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
946 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
949#ifdef HAVE_WX_GESTURE_EVENTS
950void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
957 m_popupWanted =
true;
961 m_menuPos =
event.GetPosition();
962 wxMouseEvent ev(wxEVT_LEFT_UP);
963 ev.m_x = m_menuPos.x;
964 ev.m_y = m_menuPos.y;
965 wxPostEvent(
this, ev);
968 wxMouseEvent ev_right_click(wxEVT_RIGHT_DOWN);
969 ev_right_click.m_x = m_menuPos.x;
970 ev_right_click.m_y = m_menuPos.y;
971 MouseEvent(ev_right_click);
977void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
981void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
983void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
985void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
986 wxPoint pos =
event.GetPosition();
990 if (!m_popupWanted) {
991 wxMouseEvent ev(wxEVT_LEFT_UP);
998 m_popupWanted =
false;
1000 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1007void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1010 wxPoint pos =
event.GetPosition();
1014void ChartCanvas::OnMotion(wxMouseEvent &event) {
1019 event.m_leftDown = m_leftdown;
1023void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1025 if (event.IsGestureEnd())
return;
1027 double factor =
event.GetZoomFactor();
1029 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1034 double wanted_factor = m_oldVPSScale / current_vps * factor;
1039 if (event.IsGestureStart()) {
1040 m_zoomStartPoint =
event.GetPosition();
1042 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1044 m_zoomStartPoint =
event.GetPosition();
1048void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1050void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1051 DoRotateCanvas(0.0);
1054void ChartCanvas::OnMenuTimer(wxTimerEvent &event) {
1055 m_FinishRouteOnKillFocus =
false;
1056 CallPopupMenu(m_menuPos.x, m_menuPos.y);
1057 m_FinishRouteOnKillFocus =
true;
1060void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1065 m_restore_dbindex = pcc->DBindex;
1067 if (pcc->GroupID < 0) pcc->GroupID = 0;
1072 m_groupIndex = pcc->GroupID;
1074 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1088 m_encDisplayCategory = pcc->nENCDisplayCategory;
1089 m_encShowDepth = pcc->bShowENCDepths;
1090 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1091 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1092 m_encShowLights = pcc->bShowENCLights;
1093 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1094 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1095 m_encShowDataQual = pcc->bShowENCDataQuality;
1099 m_upMode = NORTH_UP_MODE;
1101 m_upMode = COURSE_UP_MODE;
1103 m_upMode = HEAD_UP_MODE;
1107 m_singleChart = NULL;
1110void ChartCanvas::ApplyGlobalSettings() {
1113 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1114 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1116 m_notification_button->UpdateStatus();
1119void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1120 bool groupOK = CheckGroup(m_groupIndex);
1123 SetGroupIndex(m_groupIndex,
true);
1127void ChartCanvas::SetShowGPS(
bool bshow) {
1128 if (m_bShowGPS != bshow) {
1131 m_Compass->SetScaleFactor(g_compass_scalefactor);
1132 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1137void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1138 m_bShowCompassWin = bshow;
1140 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1141 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1145int ChartCanvas::GetPianoHeight() {
1147 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1152void ChartCanvas::ConfigureChartBar() {
1155 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1156 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1158 if (GetQuiltMode()) {
1159 m_Piano->SetRoundedRectangles(
true);
1161 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1162 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1163 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1166void ChartCanvas::ShowTides(
bool bShow) {
1167 gFrame->LoadHarmonics();
1170 SetbShowTide(bShow);
1172 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1174 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1175 SetbShowTide(
false);
1176 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1179 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1180 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1191void ChartCanvas::ShowCurrents(
bool bShow) {
1192 gFrame->LoadHarmonics();
1195 SetbShowCurrent(bShow);
1196 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1198 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1199 SetbShowCurrent(
false);
1200 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1203 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1204 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1221void ChartCanvas::canvasRefreshGroupIndex() { SetGroupIndex(m_groupIndex); }
1223void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1226 int new_index = index;
1229 bool bgroup_override =
false;
1230 int old_group_index = new_index;
1232 if (!CheckGroup(new_index)) {
1234 bgroup_override =
true;
1237 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1241 int current_chart_native_scale = GetCanvasChartNativeScale();
1244 m_groupIndex = new_index;
1250 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1254 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1258 g_sticky_chart = -1;
1262 UpdateCanvasOnGroupChange();
1265 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1267 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1270 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1271 double best_scale = GetBestStartScale(dbi_hint, vp);
1275 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1279 canvasChartsRefresh(dbi_hint);
1281 UpdateCanvasControlBar();
1283 if (!autoSwitch && bgroup_override) {
1285 wxString msg(_(
"Group \""));
1288 msg += pGroup->m_group_name;
1290 msg += _(
"\" is empty.");
1292 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1299 if (bgroup_override) {
1300 wxString msg(_(
"Group \""));
1303 msg += pGroup->m_group_name;
1305 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1307 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1311bool ChartCanvas::CheckGroup(
int igroup) {
1314 if (igroup == 0)
return true;
1321 if (pGroup->m_element_array.empty())
1325 for (
const auto &elem : pGroup->m_element_array) {
1326 for (
unsigned int ic = 0;
1327 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1329 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1331 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1336 for (
const auto &elem : pGroup->m_element_array) {
1337 const wxString &element_root = elem.m_element_name;
1338 wxString test_string =
"GSHH";
1339 if (element_root.Upper().Contains(test_string))
return true;
1345void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1348 AbstractPlatform::ShowBusySpinner();
1352 SetQuiltRefChart(-1);
1354 m_singleChart = NULL;
1360 if (!m_pCurrentStack) {
1362 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1365 if (-1 != dbi_hint) {
1366 if (GetQuiltMode()) {
1367 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1368 SetQuiltRefChart(dbi_hint);
1372 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1374 if (pTentative_Chart) {
1377 if (m_singleChart) m_singleChart->Deactivate();
1379 m_singleChart = pTentative_Chart;
1380 m_singleChart->Activate();
1382 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1383 GetpCurrentStack(), m_singleChart->GetFullPath());
1391 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1392 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1393 SetQuiltRefChart(selected_index);
1397 SetupCanvasQuiltMode();
1398 if (!GetQuiltMode() && m_singleChart == 0) {
1400 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1401 m_singleChart = pDummyChart;
1407 UpdateCanvasControlBar();
1408 UpdateGPSCompassStatusBox(
true);
1410 SetCursor(wxCURSOR_ARROW);
1412 AbstractPlatform::HideBusySpinner();
1415bool ChartCanvas::DoCanvasUpdate() {
1417 double vpLat, vpLon;
1418 bool blong_jump =
false;
1419 meters_to_shift = 0;
1422 bool bNewChart =
false;
1423 bool bNewView =
false;
1424 bool bCanvasChartAutoOpen =
true;
1426 bool bNewPiano =
false;
1427 bool bOpenSpecified;
1433 if (bDBUpdateInProgress)
return false;
1437 if (m_chart_drag_inertia_active)
return false;
1463 double dx = m_OSoffsetx;
1464 double dy = m_OSoffsety;
1468 if (GetUpMode() == NORTH_UP_MODE) {
1469 fromSM(d_east, d_north,
gLat,
gLon, &vpLat, &vpLon);
1471 double offset_angle = atan2(d_north, d_east);
1472 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1473 double chart_angle = GetVPRotation();
1474 double target_angle = chart_angle + offset_angle;
1475 double d_east_mod = offset_distance * cos(target_angle);
1476 double d_north_mod = offset_distance * sin(target_angle);
1477 fromSM(d_east_mod, d_north_mod,
gLat,
gLon, &vpLat, &vpLon);
1481 if (m_bLookAhead &&
bGPSValid && !m_MouseDragging) {
1482 double cog_to_use =
gCog;
1484 (fabs(
gCog - gCog_gt) > 20)) {
1485 cog_to_use = gCog_gt;
1488 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1490 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1492 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1493 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1495 double pixel_delta_tent =
1496 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1498 double pixel_delta = 0;
1503 if (!std::isnan(
gSog)) {
1507 pixel_delta = pixel_delta_tent;
1510 meters_to_shift = 0;
1512 if (!std::isnan(
gCog)) {
1513 meters_to_shift = cos(
gLat * PI / 180.) * pixel_delta /
GetVPScale();
1514 dir_to_shift = cog_to_use;
1515 ll_gc_ll(
gLat,
gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1521 }
else if (m_bLookAhead && (!
bGPSValid || m_MouseDragging)) {
1535 if (GetQuiltMode()) {
1536 int current_db_index = -1;
1537 if (m_pCurrentStack)
1540 ->GetCurrentEntrydbIndex();
1548 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1550 if (m_pCurrentStack->nEntry) {
1551 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1553 SelectQuiltRefdbChart(new_dbIndex,
true);
1554 m_bautofind =
false;
1558 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1559 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1564 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1570 double proposed_scale_onscreen =
1573 int initial_db_index = m_restore_dbindex;
1574 if (initial_db_index < 0) {
1575 if (m_pCurrentStack->nEntry) {
1577 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1582 if (m_pCurrentStack->nEntry) {
1583 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1588 if (!IsChartQuiltableRef(initial_db_index)) {
1592 int stack_index = 0;
1594 if (stack_index >= 0) {
1595 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1596 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1597 if (IsChartQuiltableRef(test_db_index) &&
1599 ChartData->GetDBChartType(initial_db_index))) {
1600 initial_db_index = test_db_index;
1610 SetQuiltRefChart(initial_db_index);
1611 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1619 0, GetVPRotation());
1624 bool super_jump =
false;
1626 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1627 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1628 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1631 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1633 if (blong_jump) nstep = 20;
1634 StartTimedMovementVP(vpLat, vpLon, nstep);
1645 pLast_Ch = m_singleChart;
1646 ChartTypeEnum new_open_type;
1647 ChartFamilyEnum new_open_family;
1649 new_open_type = pLast_Ch->GetChartType();
1650 new_open_family = pLast_Ch->GetChartFamily();
1652 new_open_type = CHART_TYPE_KAP;
1653 new_open_family = CHART_FAMILY_RASTER;
1656 bOpenSpecified = m_bFirstAuto;
1659 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1662 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1664 if (NULL == pDummyChart) {
1670 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1672 m_singleChart = pDummyChart;
1677 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1679 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1682 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1683 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1690 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1696 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1701 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1704 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1709 if (NULL != m_singleChart)
1710 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1711 m_singleChart->GetFullPath());
1714 m_pCurrentStack->CurrentStackEntry = tEntry;
1724 if (bCanvasChartAutoOpen) {
1725 bool search_direction =
1727 int start_index = 0;
1731 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1732 (LastStack.nEntry == 0)) {
1733 search_direction =
true;
1734 start_index = m_pCurrentStack->nEntry - 1;
1738 if (bOpenSpecified) {
1739 search_direction =
false;
1741 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1744 new_open_type = CHART_TYPE_DONTCARE;
1747 pProposed =
ChartData->OpenStackChartConditional(
1748 m_pCurrentStack, start_index, search_direction, new_open_type,
1752 if (NULL == pProposed)
1753 pProposed =
ChartData->OpenStackChartConditional(
1754 m_pCurrentStack, start_index, search_direction,
1755 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1757 if (NULL == pProposed)
1758 pProposed =
ChartData->OpenStackChartConditional(
1759 m_pCurrentStack, start_index, search_direction,
1760 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1771 if (NULL == pProposed) {
1772 if (NULL == pDummyChart) {
1778 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1780 pProposed = pDummyChart;
1784 if (m_singleChart) m_singleChart->Deactivate();
1785 m_singleChart = pProposed;
1787 if (m_singleChart) {
1788 m_singleChart->Activate();
1789 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1790 m_pCurrentStack, m_singleChart->GetFullPath());
1795 if (NULL != m_singleChart) {
1801 if (!GetVP().IsValid())
1802 set_scale = 1. / 20000.;
1804 double proposed_scale_onscreen;
1807 double new_scale_ppm =
1808 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1816 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1817 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1818 double equivalent_vp_scale =
1820 double new_scale_ppm =
1821 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1826 proposed_scale_onscreen =
1827 wxMin(proposed_scale_onscreen,
1830 proposed_scale_onscreen =
1831 wxMax(proposed_scale_onscreen,
1840 m_singleChart->GetChartSkew() * PI / 180.,
1847 if ((m_bFollow) && m_singleChart)
1849 m_singleChart->GetChartSkew() * PI / 180.,
1858 m_bFirstAuto =
false;
1862 if (bNewChart && !bNewView) Refresh(
false);
1867 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1870 return bNewChart | bNewView;
1873void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1874 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1876 SetQuiltRefChart(db_index);
1881 double best_scale_ppm = GetBestVPScale(pc);
1885 SetQuiltRefChart(-1);
1887 SetQuiltRefChart(-1);
1890void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1891 std::vector<int> piano_chart_index_array =
1892 GetQuiltExtendedStackdbIndexArray();
1893 int current_db_index = piano_chart_index_array[selected_index];
1895 SelectQuiltRefdbChart(current_db_index);
1898double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1902 if ((g_bPreserveScaleOnX) ||
1903 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
1909 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
1910 double equivalent_vp_scale =
1912 double new_scale_ppm =
1913 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1920 double max_underzoom_multiplier = 2.0;
1921 if (GetVP().b_quilt) {
1922 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
1923 pchart->GetChartType(),
1924 pchart->GetChartFamily());
1925 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
1928 proposed_scale_onscreen = wxMin(
1929 proposed_scale_onscreen,
1931 max_underzoom_multiplier);
1934 proposed_scale_onscreen =
1935 wxMax(proposed_scale_onscreen,
1943void ChartCanvas::SetupCanvasQuiltMode() {
1948 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
1952 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1953 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1954 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1955 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1957 m_Piano->SetRoundedRectangles(
true);
1960 int target_new_dbindex = -1;
1961 if (m_pCurrentStack) {
1962 target_new_dbindex =
1963 GetQuiltReferenceChartIndex();
1965 if (-1 != target_new_dbindex) {
1966 if (!IsChartQuiltableRef(target_new_dbindex)) {
1967 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
1968 int type =
ChartData->GetDBChartType(target_new_dbindex);
1971 int stack_index = m_pCurrentStack->CurrentStackEntry;
1973 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
1974 (stack_index >= 0)) {
1975 int proj_tent =
ChartData->GetDBChartProj(
1976 m_pCurrentStack->GetDBIndex(stack_index));
1977 int type_tent =
ChartData->GetDBChartType(
1978 m_pCurrentStack->GetDBIndex(stack_index));
1980 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
1981 if ((proj == proj_tent) && (type_tent == type)) {
1982 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
1992 if (IsChartQuiltableRef(target_new_dbindex))
1993 SelectQuiltRefdbChart(target_new_dbindex,
1996 SelectQuiltRefdbChart(-1,
false);
1998 m_singleChart = NULL;
2001 AdjustQuiltRefChart();
2009 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2013 std::vector<int> empty_array;
2014 m_Piano->SetActiveKeyArray(empty_array);
2015 m_Piano->SetNoshowIndexArray(empty_array);
2016 m_Piano->SetEclipsedIndexArray(empty_array);
2019 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
2020 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
2021 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
2022 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
2024 m_Piano->SetRoundedRectangles(
false);
2030 if (!GetQuiltMode()) {
2035 if (m_bFollow ==
true) {
2043 if (!m_singleChart) {
2046 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2054 int cur_max_scale = (int)1e8;
2056 ChartBase *pChart = GetFirstQuiltChart();
2060 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2062 if (pChart->GetNativeScale() < cur_max_scale) {
2063 Candidate_Chart = pChart;
2064 cur_max_scale = pChart->GetNativeScale();
2067 pChart = GetNextQuiltChart();
2070 m_singleChart = Candidate_Chart;
2074 if (NULL == m_singleChart) {
2075 m_singleChart =
ChartData->OpenStackChartConditional(
2076 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2077 CHART_FAMILY_DONTCARE);
2083 InvalidateAllQuiltPatchs();
2085 if (m_singleChart) {
2086 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2087 std::vector<int> one_array;
2088 one_array.push_back(dbi);
2089 m_Piano->SetActiveKeyArray(one_array);
2092 if (m_singleChart) {
2093 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2097 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2101bool ChartCanvas::IsTempMenuBarEnabled() {
2104 wxGetOsVersion(&major);
2112double ChartCanvas::GetCanvasRangeMeters() {
2114 GetSize(&width, &height);
2115 int minDimension = wxMin(width, height);
2118 range *= cos(GetVP().clat * PI / 180.);
2122void ChartCanvas::SetCanvasRangeMeters(
double range) {
2124 GetSize(&width, &height);
2125 int minDimension = wxMin(width, height);
2127 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2131bool ChartCanvas::SetUserOwnship() {
2135 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2136 double factor_dusk = 0.5;
2137 double factor_night = 0.25;
2139 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2140 m_pos_image_user_day =
new wxImage;
2141 *m_pos_image_user_day = pbmp->ConvertToImage();
2142 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2144 int gimg_width = m_pos_image_user_day->GetWidth();
2145 int gimg_height = m_pos_image_user_day->GetHeight();
2148 m_pos_image_user_dusk =
new wxImage;
2149 m_pos_image_user_night =
new wxImage;
2151 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2152 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2154 for (
int iy = 0; iy < gimg_height; iy++) {
2155 for (
int ix = 0; ix < gimg_width; ix++) {
2156 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2157 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2158 m_pos_image_user_day->GetGreen(ix, iy),
2159 m_pos_image_user_day->GetBlue(ix, iy));
2160 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2161 hsv.value = hsv.value * factor_dusk;
2162 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2163 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2166 hsv = wxImage::RGBtoHSV(rgb);
2167 hsv.value = hsv.value * factor_night;
2168 nrgb = wxImage::HSVtoRGB(hsv);
2169 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2176 m_pos_image_user_grey_day =
new wxImage;
2177 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2179 m_pos_image_user_grey_dusk =
new wxImage;
2180 m_pos_image_user_grey_night =
new wxImage;
2182 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2183 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2185 for (
int iy = 0; iy < gimg_height; iy++) {
2186 for (
int ix = 0; ix < gimg_width; ix++) {
2187 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2188 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2189 m_pos_image_user_grey_day->GetGreen(ix, iy),
2190 m_pos_image_user_grey_day->GetBlue(ix, iy));
2191 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2192 hsv.value = hsv.value * factor_dusk;
2193 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2194 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2197 hsv = wxImage::RGBtoHSV(rgb);
2198 hsv.value = hsv.value * factor_night;
2199 nrgb = wxImage::HSVtoRGB(hsv);
2200 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2207 m_pos_image_user_yellow_day =
new wxImage;
2208 m_pos_image_user_yellow_dusk =
new wxImage;
2209 m_pos_image_user_yellow_night =
new wxImage;
2211 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2212 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2213 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2215 for (
int iy = 0; iy < gimg_height; iy++) {
2216 for (
int ix = 0; ix < gimg_width; ix++) {
2217 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2218 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2219 m_pos_image_user_grey_day->GetGreen(ix, iy),
2220 m_pos_image_user_grey_day->GetBlue(ix, iy));
2224 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2225 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2226 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2228 hsv = wxImage::RGBtoHSV(rgb);
2229 hsv.value = hsv.value * factor_dusk;
2230 nrgb = wxImage::HSVtoRGB(hsv);
2231 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2233 hsv = wxImage::RGBtoHSV(rgb);
2234 hsv.value = hsv.value * factor_night;
2235 nrgb = wxImage::HSVtoRGB(hsv);
2236 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2248 m_display_size_mm = size;
2255 double horizontal = sd.x;
2259 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2260 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2264 ps52plib->SetPPMM(m_pix_per_mm);
2269 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2271 m_display_size_mm, sd.x, sd.y);
2277 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2280 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2283void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2285 wxString msg(event.m_string.c_str(), wxConvUTF8);
2287 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2288 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2291 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2293 compress_msg_array.RemoveAt(event.thread);
2294 compress_msg_array.Insert( msg, event.thread);
2297 compress_msg_array.Add(msg);
2300 wxString combined_msg;
2301 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2302 combined_msg += compress_msg_array[i];
2303 combined_msg +=
"\n";
2307 pprog->Update(pprog_count, combined_msg, &skip );
2308 pprog->SetSize(pprog_size);
2313void ChartCanvas::InvalidateGL() {
2314 if (!m_glcc)
return;
2316 if (g_bopengl) m_glcc->Invalidate();
2318 if (m_Compass) m_Compass->UpdateStatus(
true);
2321int ChartCanvas::GetCanvasChartNativeScale() {
2323 if (!VPoint.b_quilt) {
2324 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2326 ret = (int)m_pQuilt->GetRefNativeScale();
2331ChartBase *ChartCanvas::GetChartAtCursor() {
2333 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2334 target_chart = m_singleChart;
2335 else if (VPoint.b_quilt)
2336 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2338 target_chart = NULL;
2339 return target_chart;
2342ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2346 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2348 target_chart = NULL;
2349 return target_chart;
2352int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2353 int new_dbIndex = -1;
2354 if (!VPoint.b_quilt) {
2355 if (m_pCurrentStack) {
2356 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2357 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2359 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2369 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2371 for (
unsigned int is = 0; is < im; is++) {
2373 m_pQuilt->GetExtendedStackIndexArray()[is]);
2376 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2386void ChartCanvas::EnablePaint(
bool b_enable) {
2387 m_b_paint_enable = b_enable;
2389 if (m_glcc) m_glcc->EnablePaint(b_enable);
2393bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2395void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2397std::vector<int> ChartCanvas::GetQuiltIndexArray() {
2398 return m_pQuilt->GetQuiltIndexArray();
2402void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2403 VPoint.b_quilt = b_quilt;
2404 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2407bool ChartCanvas::GetQuiltMode() {
return VPoint.b_quilt; }
2409int ChartCanvas::GetQuiltReferenceChartIndex() {
2410 return m_pQuilt->GetRefChartdbIndex();
2413void ChartCanvas::InvalidateAllQuiltPatchs() {
2414 m_pQuilt->InvalidateAllQuiltPatchs();
2417ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2418 return m_pQuilt->GetLargestScaleChart();
2421ChartBase *ChartCanvas::GetFirstQuiltChart() {
2422 return m_pQuilt->GetFirstChart();
2425ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2427int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2429void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2430 m_pQuilt->SetHiliteIndex(dbIndex);
2433void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2434 m_pQuilt->SetHiliteIndexArray(hilite_array);
2437void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2438 m_pQuilt->ClearHiliteIndexArray();
2441std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2443 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2446int ChartCanvas::GetQuiltRefChartdbIndex() {
2447 return m_pQuilt->GetRefChartdbIndex();
2450std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2451 return m_pQuilt->GetExtendedStackIndexArray();
2454std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2455 return m_pQuilt->GetFullscreenIndexArray();
2458std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2459 return m_pQuilt->GetEclipsedStackIndexArray();
2462void ChartCanvas::InvalidateQuilt() {
return m_pQuilt->Invalidate(); }
2464double ChartCanvas::GetQuiltMaxErrorFactor() {
2465 return m_pQuilt->GetMaxErrorFactor();
2468bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2469 return m_pQuilt->IsChartQuiltableRef(db_index);
2473 double chartMaxScale =
2475 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2478void ChartCanvas::StartMeasureRoute() {
2479 if (!m_routeState) {
2480 if (m_bMeasure_Active) {
2482 m_pMeasureRoute = NULL;
2485 m_bMeasure_Active =
true;
2486 m_nMeasureState = 1;
2487 m_bDrawingRoute =
false;
2489 SetCursor(*pCursorPencil);
2494void ChartCanvas::CancelMeasureRoute() {
2495 m_bMeasure_Active =
false;
2496 m_nMeasureState = 0;
2497 m_bDrawingRoute =
false;
2500 m_pMeasureRoute = NULL;
2502 SetCursor(*pCursorArrow);
2505ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2507void ChartCanvas::SetVP(
ViewPort &vp) {
2518void ChartCanvas::TriggerDeferredFocus() {
2521 m_deferredFocusTimer.Start(20,
true);
2523#if defined(__WXGTK__) || defined(__WXOSX__)
2534void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2539void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2540 if (SendKeyEventToPlugins(event))
2544 int key_char =
event.GetKeyCode();
2547 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2553 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2558 if (g_benable_rotate) {
2579void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2580 if (SendKeyEventToPlugins(event))
2584 bool b_handled =
false;
2586 m_modkeys =
event.GetModifiers();
2588 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2590#ifdef OCPN_ALT_MENUBAR
2596 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2598 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2599 if (!g_bTempShowMenuBar) {
2600 g_bTempShowMenuBar =
true;
2601 parent_frame->ApplyGlobalSettings(
false);
2603 m_bMayToggleMenuBar =
false;
2609 if (event.GetKeyCode() != WXK_ALT) {
2610 m_bMayToggleMenuBar =
false;
2617 switch (event.GetKeyCode()) {
2624 event.GetPosition(&x, &y);
2625 m_FinishRouteOnKillFocus =
false;
2626 CallPopupMenu(x, y);
2627 m_FinishRouteOnKillFocus =
true;
2631 m_modkeys |= wxMOD_ALT;
2635 m_modkeys |= wxMOD_CONTROL;
2640 case WXK_RAW_CONTROL:
2641 m_modkeys |= wxMOD_RAW_CONTROL;
2646 if (m_modkeys == wxMOD_CONTROL)
2647 parent_frame->DoStackDown(
this);
2649 StartTimedMovement();
2659 StartTimedMovement();
2667 if (m_modkeys == wxMOD_CONTROL)
2668 parent_frame->DoStackUp(
this);
2670 StartTimedMovement();
2680 StartTimedMovement();
2692 SetShowENCText(!GetShowENCText());
2698 if (!m_bMeasure_Active) {
2699 if (event.ShiftDown())
2700 m_bMeasure_DistCircle =
true;
2702 m_bMeasure_DistCircle =
false;
2704 StartMeasureRoute();
2706 CancelMeasureRoute();
2708 SetCursor(*pCursorArrow);
2718 parent_frame->ToggleColorScheme();
2720 TriggerDeferredFocus();
2724 int mod = m_modkeys & wxMOD_SHIFT;
2725 if (mod != m_brightmod) {
2727 m_bbrightdir = !m_bbrightdir;
2730 if (!m_bbrightdir) {
2731 g_nbrightness -= 10;
2732 if (g_nbrightness <= MIN_BRIGHT) {
2733 g_nbrightness = MIN_BRIGHT;
2734 m_bbrightdir =
true;
2737 g_nbrightness += 10;
2738 if (g_nbrightness >= MAX_BRIGHT) {
2739 g_nbrightness = MAX_BRIGHT;
2740 m_bbrightdir =
false;
2744 SetScreenBrightness(g_nbrightness);
2745 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2754 parent_frame->DoStackDown(
this);
2758 parent_frame->DoStackUp(
this);
2763 ToggleCanvasQuiltMode();
2769 parent_frame->ToggleFullScreen();
2774 if (m_modkeys == wxMOD_ALT) {
2777 ToggleChartOutlines();
2783 parent_frame->ActivateMOB();
2787 case WXK_NUMPAD_ADD:
2792 case WXK_NUMPAD_SUBTRACT:
2793 case WXK_PAGEDOWN: {
2794 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2799 if (m_bMeasure_Active) {
2800 if (m_nMeasureState > 2) {
2801 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2803 m_pMeasureRoute->GetnPoints();
2805 gFrame->RefreshAllCanvas();
2807 CancelMeasureRoute();
2808 StartMeasureRoute();
2816 if (event.GetKeyCode() < 128)
2818 int key_char =
event.GetKeyCode();
2822 if (!g_b_assume_azerty) {
2824 if (g_benable_rotate) {
2856 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2863 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2864 m_modkeys & wxMOD_RAW_CONTROL) {
2865 parent_frame->ToggleFullScreen();
2870 if (event.ControlDown()) key_char -= 64;
2872 if (key_char >=
'0' && key_char <=
'9')
2873 SetGroupIndex(key_char -
'0');
2878 SetShowENCAnchor(!GetShowENCAnchor());
2884 parent_frame->ToggleColorScheme();
2889 event.GetPosition(&x, &y);
2890 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2891 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2894 if (VPoint.b_quilt) {
2896 if (m_pQuilt->GetChartAtPix(
2901 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2903 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2908 if (m_singleChart) {
2909 ChartType = m_singleChart->GetChartType();
2910 ChartFam = m_singleChart->GetChartFamily();
2914 if ((ChartType != CHART_TYPE_UNKNOWN) ||
2915 (ChartFam != CHART_FAMILY_UNKNOWN)) {
2917 this, -1, ChartType, ChartFam,
2918 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
2919 wxDefaultSize, wxSIMPLE_BORDER,
"");
2932 m_nmea_log->Raise();
2936 SetShowENCLights(!GetShowENCLights());
2942 if (event.ShiftDown())
2943 m_bMeasure_DistCircle =
true;
2945 m_bMeasure_DistCircle =
false;
2947 StartMeasureRoute();
2951 if (g_bInlandEcdis && ps52plib) {
2952 SetENCDisplayCategory((_DisCat)STANDARD);
2957 ToggleChartOutlines();
2961 ToggleCanvasQuiltMode();
2965 parent_frame->ToggleTestPause();
2968 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
2969 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
2970 g_iNavAidRadarRingsNumberVisible = 1;
2971 else if (!g_bNavAidRadarRingsShown &&
2972 g_iNavAidRadarRingsNumberVisible == 1)
2973 g_iNavAidRadarRingsNumberVisible = 0;
2976 SetShowENCDepth(!m_encShowDepth);
2981 SetShowENCText(!GetShowENCText());
2986 SetShowENCDataQual(!GetShowENCDataQual());
2991 m_bShowNavobjects = !m_bShowNavobjects;
3006 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3011 if (event.ControlDown()) gFrame->DropMarker(
false);
3018 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3019 if ((indexActive + 1) <= r->GetnPoints()) {
3030 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3036 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3042 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3049 parent_frame->DoSettings();
3053 parent_frame->Close();
3069 if (undo->AnythingToRedo()) {
3070 undo->RedoNextAction();
3077 if (event.ShiftDown()) {
3078 if (undo->AnythingToRedo()) {
3079 undo->RedoNextAction();
3084 if (undo->AnythingToUndo()) {
3085 undo->UndoLastAction();
3094 if (m_bMeasure_Active) {
3095 CancelMeasureRoute();
3097 SetCursor(*pCursorArrow);
3100 gFrame->RefreshAllCanvas();
3114 switch (gamma_state) {
3134 SetScreenBrightness(g_nbrightness);
3139 if (event.ControlDown()) {
3140 m_bShowCompassWin = !m_bShowCompassWin;
3141 SetShowGPSCompassWindow(m_bShowCompassWin);
3158void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3159 if (SendKeyEventToPlugins(event))
3163 switch (event.GetKeyCode()) {
3165 parent_frame->SwitchKBFocus(
this);
3171 if (!m_pany) m_panspeed = 0;
3177 if (!m_panx) m_panspeed = 0;
3180 case WXK_NUMPAD_ADD:
3181 case WXK_NUMPAD_SUBTRACT:
3190 m_modkeys &= ~wxMOD_ALT;
3191#ifdef OCPN_ALT_MENUBAR
3196 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3197 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3198 parent_frame->ApplyGlobalSettings(
false);
3200 m_bMayToggleMenuBar =
true;
3206 m_modkeys &= ~wxMOD_CONTROL;
3210 if (event.GetKeyCode() < 128)
3212 int key_char =
event.GetKeyCode();
3216 if (!g_b_assume_azerty) {
3231 m_rotation_speed = 0;
3249void ChartCanvas::ToggleChartOutlines() {
3250 m_bShowOutlines = !m_bShowOutlines;
3256 if (g_bopengl) InvalidateGL();
3260void ChartCanvas::ToggleLookahead() {
3261 m_bLookAhead = !m_bLookAhead;
3266void ChartCanvas::SetUpMode(
int mode) {
3269 if (mode != NORTH_UP_MODE) {
3272 if (!std::isnan(
gCog)) stuff =
gCog;
3275 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3278 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3280 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3281 SetVPRotation(GetVPSkew());
3286 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3287 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3289 UpdateGPSCompassStatusBox(
true);
3290 gFrame->DoChartUpdate();
3293bool ChartCanvas::DoCanvasCOGSet() {
3294 if (GetUpMode() == NORTH_UP_MODE)
return false;
3296 if (g_btenhertz) cog_use =
gCog;
3298 double rotation = 0;
3299 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(
gHdt)) {
3300 rotation = -
gHdt * PI / 180.;
3301 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3302 rotation = -cog_use * PI / 180.;
3304 SetVPRotation(rotation);
3308double easeOutCubic(
double t) {
3310 return 1.0 - pow(1.0 - t, 3.0);
3313void ChartCanvas::StartChartDragInertia() {
3314 m_bChartDragging =
false;
3317 m_chart_drag_inertia_time = 750;
3318 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3323 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3327 size_t length = m_drag_vec_t.size();
3328 for (
size_t i = 0; i < n_vel; i++) {
3329 xacc += m_drag_vec_x.at(length - 1 - i);
3330 yacc += m_drag_vec_y.at(length - 1 - i);
3331 tacc += m_drag_vec_t.at(length - 1 - i);
3334 if (tacc == 0)
return;
3336 m_chart_drag_velocity_x = xacc / tacc;
3337 m_chart_drag_velocity_y = yacc / tacc;
3339 m_chart_drag_inertia_active =
true;
3341 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3344void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3345 if (!m_chart_drag_inertia_active)
return;
3347 wxLongLong now = wxGetLocalTimeMillis();
3348 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3349 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3350 if (t > 1.0) t = 1.0;
3351 double e = 1.0 - easeOutCubic(t);
3354 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3356 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3358 m_last_elapsed = elapsed;
3362 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3363 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3364 double inertia_lat, inertia_lon;
3368 if (!IsOwnshipOnScreen()) {
3370 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3371 UpdateFollowButtonState();
3382 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3383 m_chart_drag_inertia_timer.Stop();
3386 m_target_lat = GetVP().
clat;
3387 m_target_lon = GetVP().
clon;
3388 m_pan_drag.x = m_pan_drag.y = 0;
3389 m_panx = m_pany = 0;
3390 m_chart_drag_inertia_active =
false;
3394 int target_redraw_interval = 40;
3395 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3399void ChartCanvas::StopMovement() {
3400 m_panx = m_pany = 0;
3403 m_rotation_speed = 0;
3406#if !defined(__WXGTK__) && !defined(__WXQT__)
3417bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3419 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3421 if (!pMovementTimer->IsRunning()) {
3422 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3425 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3430 m_last_movement_time = wxDateTime::UNow();
3434void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3437 m_target_lat = target_lat;
3438 m_target_lon = target_lon;
3441 m_start_lat = GetVP().
clat;
3442 m_start_lon = GetVP().
clon;
3444 m_VPMovementTimer.Start(1,
true);
3445 m_timed_move_vp_active =
true;
3447 m_timedVP_step = nstep;
3450void ChartCanvas::DoTimedMovementVP() {
3451 if (!m_timed_move_vp_active)
return;
3452 if (m_stvpc++ > m_timedVP_step * 2) {
3459 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3474 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3475 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3477 m_run_lat = new_lat;
3478 m_run_lon = new_lon;
3483void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3485void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3487void ChartCanvas::StartTimedMovementTarget() {}
3489void ChartCanvas::DoTimedMovementTarget() {}
3491void ChartCanvas::StopMovementTarget() {}
3494void ChartCanvas::DoTimedMovement() {
3495 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3499 wxDateTime now = wxDateTime::UNow();
3501 if (m_last_movement_time.IsValid())
3502 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3504 m_last_movement_time = now;
3514 if (dt == 0) dt = 1;
3517 if (m_mustmove < 0) m_mustmove = 0;
3520 if (m_pan_drag.x || m_pan_drag.y) {
3522 m_pan_drag.x = m_pan_drag.y = 0;
3525 if (m_panx || m_pany) {
3526 const double slowpan = .1, maxpan = 2;
3527 if (m_modkeys == wxMOD_ALT)
3528 m_panspeed = slowpan;
3530 m_panspeed += (double)dt / 500;
3531 m_panspeed = wxMin(maxpan, m_panspeed);
3533 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3536 if (m_zoom_factor != 1) {
3537 double alpha = 400, beta = 1.5;
3538 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3540 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3542 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3547 if (zoom_factor > 1) {
3548 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3552 else if (zoom_factor < 1) {
3553 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3558 if (fabs(zoom_factor - 1) > 1e-4) {
3559 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3564 if (m_wheelzoom_stop_oneshot > 0) {
3565 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3566 m_wheelzoom_stop_oneshot = 0;
3571 if (zoom_factor > 1) {
3573 m_wheelzoom_stop_oneshot = 0;
3576 }
else if (zoom_factor < 1) {
3578 m_wheelzoom_stop_oneshot = 0;
3585 if (m_rotation_speed) {
3586 double speed = m_rotation_speed;
3587 if (m_modkeys == wxMOD_ALT) speed /= 10;
3588 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3592void ChartCanvas::SetColorScheme(ColorScheme cs) {
3597 case GLOBAL_COLOR_SCHEME_DAY:
3598 m_pos_image_red = &m_os_image_red_day;
3599 m_pos_image_grey = &m_os_image_grey_day;
3600 m_pos_image_yellow = &m_os_image_yellow_day;
3601 m_pos_image_user = m_pos_image_user_day;
3602 m_pos_image_user_grey = m_pos_image_user_grey_day;
3603 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3604 m_cTideBitmap = m_bmTideDay;
3605 m_cCurrentBitmap = m_bmCurrentDay;
3608 case GLOBAL_COLOR_SCHEME_DUSK:
3609 m_pos_image_red = &m_os_image_red_dusk;
3610 m_pos_image_grey = &m_os_image_grey_dusk;
3611 m_pos_image_yellow = &m_os_image_yellow_dusk;
3612 m_pos_image_user = m_pos_image_user_dusk;
3613 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3614 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3615 m_cTideBitmap = m_bmTideDusk;
3616 m_cCurrentBitmap = m_bmCurrentDusk;
3618 case GLOBAL_COLOR_SCHEME_NIGHT:
3619 m_pos_image_red = &m_os_image_red_night;
3620 m_pos_image_grey = &m_os_image_grey_night;
3621 m_pos_image_yellow = &m_os_image_yellow_night;
3622 m_pos_image_user = m_pos_image_user_night;
3623 m_pos_image_user_grey = m_pos_image_user_grey_night;
3624 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3625 m_cTideBitmap = m_bmTideNight;
3626 m_cCurrentBitmap = m_bmCurrentNight;
3629 m_pos_image_red = &m_os_image_red_day;
3630 m_pos_image_grey = &m_os_image_grey_day;
3631 m_pos_image_yellow = &m_os_image_yellow_day;
3632 m_pos_image_user = m_pos_image_user_day;
3633 m_pos_image_user_grey = m_pos_image_user_grey_day;
3634 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3635 m_cTideBitmap = m_bmTideDay;
3636 m_cCurrentBitmap = m_bmCurrentDay;
3640 CreateDepthUnitEmbossMaps(cs);
3641 CreateOZEmbossMapData(cs);
3644 m_fog_color = wxColor(
3648 case GLOBAL_COLOR_SCHEME_DUSK:
3651 case GLOBAL_COLOR_SCHEME_NIGHT:
3657 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3658 m_fog_color.Blue() * dim);
3662 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3663 SetBackgroundColour( wxColour(0,0,0) );
3665 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3668 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3670 SetBackgroundColour( wxNullColour );
3677 m_Piano->SetColorScheme(cs);
3679 m_Compass->SetColorScheme(cs);
3681 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3683 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3685 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3686 if (m_notification_button) {
3687 m_notification_button->SetColorScheme(cs);
3691 if (g_bopengl && m_glcc) {
3692 m_glcc->SetColorScheme(cs);
3698 m_brepaint_piano =
true;
3705wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3706 wxImage img = Bitmap.ConvertToImage();
3707 int sx = img.GetWidth();
3708 int sy = img.GetHeight();
3710 wxImage new_img(img);
3712 for (
int i = 0; i < sx; i++) {
3713 for (
int j = 0; j < sy; j++) {
3714 if (!img.IsTransparent(i, j)) {
3715 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3716 (
unsigned char)(img.GetGreen(i, j) * factor),
3717 (
unsigned char)(img.GetBlue(i, j) * factor));
3722 wxBitmap ret = wxBitmap(new_img);
3727void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3730 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3732 if (!m_pBrightPopup) {
3735 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3739 m_pBrightPopup->SetSize(x, y);
3740 m_pBrightPopup->Move(120, 120);
3743 int bmpsx = m_pBrightPopup->GetSize().x;
3744 int bmpsy = m_pBrightPopup->GetSize().y;
3746 wxBitmap bmp(bmpsx, bmpsx);
3747 wxMemoryDC mdc(bmp);
3749 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3750 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3751 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3752 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3755 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3757 mdc.SetFont(*pfont);
3760 if (brightness == max)
3762 else if (brightness == min)
3765 val.Printf(
"%3d", brightness);
3767 mdc.DrawText(val, 0, 0);
3769 mdc.SelectObject(wxNullBitmap);
3771 m_pBrightPopup->SetBitmap(bmp);
3772 m_pBrightPopup->Show();
3773 m_pBrightPopup->Refresh();
3776void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3777 m_b_rot_hidef =
true;
3781void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3784 bool b_need_refresh =
false;
3786 wxSize win_size = GetSize() * m_displayScale;
3790 bool showAISRollover =
false;
3792 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3796 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3797 auto ptarget =
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3800 showAISRollover =
true;
3802 if (NULL == m_pAISRolloverWin) {
3804 m_pAISRolloverWin->IsActive(
false);
3805 b_need_refresh =
true;
3806 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3807 m_AISRollover_MMSI != FoundAIS_MMSI) {
3813 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3814 m_pAISRolloverWin->IsActive(
false);
3815 m_AISRollover_MMSI = 0;
3820 m_AISRollover_MMSI = FoundAIS_MMSI;
3822 if (!m_pAISRolloverWin->IsActive()) {
3823 wxString s = ptarget->GetRolloverString();
3824 m_pAISRolloverWin->SetString(s);
3826 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3827 AIS_ROLLOVER, win_size);
3828 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3829 m_pAISRolloverWin->IsActive(
true);
3830 b_need_refresh =
true;
3834 m_AISRollover_MMSI = 0;
3835 showAISRollover =
false;
3840 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3841 m_pAISRolloverWin->IsActive(
false);
3842 m_AISRollover_MMSI = 0;
3843 b_need_refresh =
true;
3848 bool showRouteRollover =
false;
3850 if (NULL == m_pRolloverRouteSeg) {
3854 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3855 SelectableItemList SelList =
pSelect->FindSelectionList(
3857 auto node = SelList.begin();
3858 while (node != SelList.end()) {
3863 if (pr && pr->IsVisible()) {
3864 m_pRolloverRouteSeg = pFindSel;
3865 showRouteRollover =
true;
3867 if (NULL == m_pRouteRolloverWin) {
3869 m_pRouteRolloverWin->IsActive(
false);
3872 if (!m_pRouteRolloverWin->IsActive()) {
3880 DistanceBearingMercator(
3881 segShow_point_b->m_lat, segShow_point_b->m_lon,
3882 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3884 if (!pr->m_bIsInLayer)
3885 s.Append(_(
"Route") +
": ");
3887 s.Append(_(
"Layer Route: "));
3889 if (pr->m_RouteNameString.IsEmpty())
3890 s.Append(_(
"(unnamed)"));
3892 s.Append(pr->m_RouteNameString);
3897 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3898 << segShow_point_b->GetName() <<
"\n";
3901 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
3902 (
int)floor(brg + 0.5), 0x00B0);
3905 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3907 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3908 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3910 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
3911 (
int)floor(varBrg + 0.5), 0x00B0);
3919 double shiptoEndLeg = 0.;
3920 bool validActive =
false;
3921 if (pr->IsActive() && (*pr->pRoutePointList->begin())->m_bIsActive)
3924 if (segShow_point_a != *pr->pRoutePointList->begin()) {
3925 auto node = pr->pRoutePointList->begin();
3928 float dist_to_endleg = 0;
3931 while (node != pr->pRoutePointList->end()) {
3938 if (prp->IsSame(segShow_point_a))
break;
3947 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
3950 ->GetCurrentRngToActivePoint();
3959 if (!std::isnan(
gCog) && !std::isnan(
gSog))
3964 float ttg_sec = (shiptoEndLeg /
gSog) * 3600.;
3965 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
3967 << wxString(ttg_sec > SECONDS_PER_DAY
3968 ? ttg_span.Format(_(
"%Dd %H:%M"))
3969 : ttg_span.Format(_(
"%H:%M")));
3970 wxDateTime dtnow, eta;
3971 eta = dtnow.SetToCurrent().Add(ttg_span);
3972 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
3973 << eta.Format(
" %d %H:%M");
3977 m_pRouteRolloverWin->SetString(s);
3979 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3980 LEG_ROLLOVER, win_size);
3981 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
3982 m_pRouteRolloverWin->IsActive(
true);
3983 b_need_refresh =
true;
3984 showRouteRollover =
true;
3993 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3995 m_pRolloverRouteSeg))
3996 showRouteRollover =
false;
3997 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
3998 showRouteRollover =
false;
4000 showRouteRollover =
true;
4004 if (m_routeState) showRouteRollover =
false;
4007 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4008 showRouteRollover =
false;
4010 if (m_pRouteRolloverWin &&
4011 !showRouteRollover) {
4012 m_pRouteRolloverWin->IsActive(
false);
4013 m_pRolloverRouteSeg = NULL;
4014 m_pRouteRolloverWin->Destroy();
4015 m_pRouteRolloverWin = NULL;
4016 b_need_refresh =
true;
4017 }
else if (m_pRouteRolloverWin && showRouteRollover) {
4018 m_pRouteRolloverWin->IsActive(
true);
4019 b_need_refresh =
true;
4024 bool showTrackRollover =
false;
4026 if (NULL == m_pRolloverTrackSeg) {
4030 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4031 SelectableItemList SelList =
pSelect->FindSelectionList(
4034 auto node = SelList.begin();
4035 while (node != SelList.end()) {
4040 if (pt && pt->IsVisible()) {
4041 m_pRolloverTrackSeg = pFindSel;
4042 showTrackRollover =
true;
4044 if (NULL == m_pTrackRolloverWin) {
4046 m_pTrackRolloverWin->IsActive(
false);
4049 if (!m_pTrackRolloverWin->IsActive()) {
4057 DistanceBearingMercator(
4058 segShow_point_b->m_lat, segShow_point_b->m_lon,
4059 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4061 if (!pt->m_bIsInLayer)
4062 s.Append(_(
"Track") +
": ");
4064 s.Append(_(
"Layer Track: "));
4066 if (pt->GetName().IsEmpty())
4067 s.Append(_(
"(unnamed)"));
4069 s.Append(pt->GetName());
4070 double tlenght = pt->Length();
4072 if (pt->GetLastPoint()->GetTimeString() &&
4073 pt->GetPoint(0)->GetTimeString()) {
4074 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4075 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4076 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4077 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4078 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4079 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4080 << getUsrSpeedUnit();
4081 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4082 : ttime.Format(
" %H:%M"));
4086 if (g_bShowTrackPointTime &&
4087 strlen(segShow_point_b->GetTimeString())) {
4088 wxString stamp = segShow_point_b->GetTimeString();
4089 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4090 if (timestamp.IsValid()) {
4094 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4096 s <<
"\n" << _(
"Segment Created: ") << stamp;
4101 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4106 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4108 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4109 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4111 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4117 if (segShow_point_a->GetTimeString() &&
4118 segShow_point_b->GetTimeString()) {
4119 wxDateTime apoint = segShow_point_a->GetCreateTime();
4120 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4121 if (apoint.IsValid() && bpoint.IsValid()) {
4122 double segmentSpeed = toUsrSpeed(
4123 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4124 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4125 << getUsrSpeedUnit();
4129 m_pTrackRolloverWin->SetString(s);
4131 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4132 LEG_ROLLOVER, win_size);
4133 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4134 m_pTrackRolloverWin->IsActive(
true);
4135 b_need_refresh =
true;
4136 showTrackRollover =
true;
4145 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4147 m_pRolloverTrackSeg))
4148 showTrackRollover =
false;
4149 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4150 showTrackRollover =
false;
4152 showTrackRollover =
true;
4156 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4157 showTrackRollover =
false;
4160 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4161 showTrackRollover =
false;
4167 if (m_pTrackRolloverWin &&
4168 !showTrackRollover) {
4169 m_pTrackRolloverWin->IsActive(
false);
4170 m_pRolloverTrackSeg = NULL;
4171 m_pTrackRolloverWin->Destroy();
4172 m_pTrackRolloverWin = NULL;
4173 b_need_refresh =
true;
4174 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4175 m_pTrackRolloverWin->IsActive(
true);
4176 b_need_refresh =
true;
4179 if (b_need_refresh) Refresh();
4182void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4183 if ((GetShowENCLights() || m_bsectors_shown) &&
4184 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4185 extendedSectorLegs)) {
4186 if (!m_bsectors_shown) {
4188 m_bsectors_shown =
true;
4191 if (m_bsectors_shown) {
4193 m_bsectors_shown =
false;
4201#if defined(__WXGTK__) || defined(__WXQT__)
4206 double cursor_lat, cursor_lon;
4209 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4210 while (cursor_lon < -180.) cursor_lon += 360.;
4212 while (cursor_lon > 180.) cursor_lon -= 360.;
4214 SetCursorStatus(cursor_lat, cursor_lon);
4220void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4221 if (!parent_frame->m_pStatusBar)
return;
4225 s1 += toSDMM(1, cursor_lat);
4227 s1 += toSDMM(2, cursor_lon);
4229 if (STAT_FIELD_CURSOR_LL >= 0)
4230 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4232 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4237 DistanceBearingMercator(cursor_lat, cursor_lon,
gLat,
gLon, &brg, &dist);
4238 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4239 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4241 wxString s = st + sm;
4254 if (g_bShowLiveETA) {
4257 float boatSpeedDefault = g_defaultBoatSpeed;
4262 if (!std::isnan(
gSog)) {
4264 if (boatSpeed < 0.5) {
4267 realTimeETA = dist / boatSpeed * 60;
4276 s << minutesToHoursDays(realTimeETA);
4281 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4282 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4284 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4289 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4297wxString minutesToHoursDays(
float timeInMinutes) {
4300 if (timeInMinutes == 0) {
4305 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4306 s << wxString::Format(
"%d", (
int)timeInMinutes);
4311 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4314 hours = (int)timeInMinutes / 60;
4315 min = (int)timeInMinutes % 60;
4318 s << wxString::Format(
"%d", hours);
4321 s << wxString::Format(
"%d", hours);
4323 s << wxString::Format(
"%d", min);
4330 else if (timeInMinutes > 24 * 60) {
4333 days = (int)(timeInMinutes / 60) / 24;
4334 hours = (int)(timeInMinutes / 60) % 24;
4337 s << wxString::Format(
"%d", days);
4340 s << wxString::Format(
"%d", days);
4342 s << wxString::Format(
"%d", hours);
4354void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4362 wxPoint2DDouble *r) {
4367 double rlon, wxPoint2DDouble *r) {
4378 if (!g_bopengl && m_singleChart &&
4379 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4380 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4381 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4382 (m_singleChart->GetChartProjectionType() !=
4383 PROJECTION_TRANSVERSE_MERCATOR) &&
4384 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4385 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4386 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4400 Cur_BSB_Ch->SetVPRasterParms(vp);
4401 double rpixxd, rpixyd;
4402 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4428 if (std::isnan(p.m_x)) {
4429 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4433 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4434 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4436 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4455 if (!g_bopengl && m_singleChart &&
4456 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4457 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4458 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4459 (m_singleChart->GetChartProjectionType() !=
4460 PROJECTION_TRANSVERSE_MERCATOR) &&
4461 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4462 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4463 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4474 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4477 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4482 else if (slon > 180.)
4493 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4499 DoZoomCanvas(factor,
false);
4500 extendedSectorLegs.clear();
4505 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4508 if (StartTimedMovement(stoptimer)) {
4510 m_zoom_factor = factor;
4515 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4517 DoZoomCanvas(factor, can_zoom_to_cursor);
4520 extendedSectorLegs.clear();
4523void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4526 if (!m_pCurrentStack)
return;
4532 if (m_bzooming)
return;
4541 double proposed_scale_onscreen =
4544 bool b_do_zoom =
false;
4553 if (!VPoint.b_quilt) {
4556 if (!m_disable_adjust_on_zoom) {
4557 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4558 if (new_db_index >= 0)
4559 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4563 int current_ref_stack_index = -1;
4564 if (m_pCurrentStack->nEntry) {
4566 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4567 m_pQuilt->SetReferenceChart(trial_index);
4568 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4569 if (new_db_index >= 0)
4570 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4574 if (m_pCurrentStack)
4575 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4586 double min_allowed_scale =
4589 if (proposed_scale_onscreen < min_allowed_scale) {
4594 proposed_scale_onscreen = min_allowed_scale;
4598 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4601 }
else if (factor < 1) {
4606 bool b_smallest =
false;
4608 if (!VPoint.b_quilt) {
4613 LLBBox viewbox = VPoint.GetBBox();
4615 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4616 double max_allowed_scale;
4630 if (proposed_scale_onscreen > max_allowed_scale) {
4632 proposed_scale_onscreen = max_allowed_scale;
4637 if (!m_disable_adjust_on_zoom) {
4639 m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4640 if (new_db_index >= 0)
4641 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4643 if (m_pCurrentStack)
4644 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4647 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4649 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4650 proposed_scale_onscreen =
4651 wxMin(proposed_scale_onscreen,
4657 m_absolute_min_scale_ppm)
4658 proposed_scale_onscreen =
4667 bool b_allow_ztc =
true;
4668 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4669 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4671 double brg, distance;
4672 ll_gc_ll_reverse(
gLat,
gLon, GetVP().clat, GetVP().clon, &brg,
4675 meters_to_shift = distance * 1852;
4683 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4686 if (m_bFollow) DoCanvasUpdate();
4693void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4695 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4699void ChartCanvas::RotateCanvas(
double dir) {
4703 if (StartTimedMovement()) {
4705 m_rotation_speed = dir * 60;
4708 double speed = dir * 10;
4709 if (m_modkeys == wxMOD_ALT) speed /= 20;
4710 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4714void ChartCanvas::DoRotateCanvas(
double rotation) {
4715 while (rotation < 0) rotation += 2 * PI;
4716 while (rotation > 2 * PI) rotation -= 2 * PI;
4718 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4720 SetVPRotation(rotation);
4721 parent_frame->UpdateRotationState(VPoint.
rotation);
4724void ChartCanvas::DoTiltCanvas(
double tilt) {
4725 while (tilt < 0) tilt = 0;
4726 while (tilt > .95) tilt = .95;
4728 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4734void ChartCanvas::TogglebFollow() {
4741void ChartCanvas::ClearbFollow() {
4744 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4746 UpdateFollowButtonState();
4750 parent_frame->SetChartUpdatePeriod();
4753void ChartCanvas::SetbFollow() {
4756 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4757 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4765 p.m_x += m_OSoffsetx;
4766 p.m_y -= m_OSoffsety;
4775 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4776 UpdateFollowButtonState();
4778 if (!g_bSmoothRecenter) {
4782 parent_frame->SetChartUpdatePeriod();
4785void ChartCanvas::UpdateFollowButtonState() {
4788 m_muiBar->SetFollowButtonState(0);
4791 m_muiBar->SetFollowButtonState(2);
4793 m_muiBar->SetFollowButtonState(1);
4799 androidSetFollowTool(0);
4802 androidSetFollowTool(2);
4804 androidSetFollowTool(1);
4811 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4812 if (pic->m_enabled && pic->m_init_state) {
4813 switch (pic->m_api_version) {
4816 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4827void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4828 if (g_bSmoothRecenter && !m_routeState) {
4829 if (StartSmoothJump(lat, lon, scale_ppm))
4833 double gcDist, gcBearingEnd;
4834 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4836 gcBearingEnd += 180;
4837 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4840 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4841 double new_lat = lat + (lat_offset / (1852 * 60));
4842 double new_lon = lon + (lon_offset / (1852 * 60));
4845 StartSmoothJump(lat, lon, scale_ppm);
4850 if (lon > 180.0) lon -= 360.0;
4856 if (!GetQuiltMode()) {
4858 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4859 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4863 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4864 AdjustQuiltRefChart();
4871 UpdateFollowButtonState();
4879bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4884 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4885 double distance_pixels = gcDist *
GetVPScale();
4886 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4892 m_startLat = m_vLat;
4893 m_startLon = m_vLon;
4898 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4899 m_endScale = scale_ppm;
4902 m_animationDuration = 600;
4903 m_animationStart = wxGetLocalTimeMillis();
4910 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
4911 m_animationActive =
true;
4916void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
4918 wxLongLong now = wxGetLocalTimeMillis();
4919 double elapsed = (now - m_animationStart).ToDouble();
4920 double t = elapsed / m_animationDuration.ToDouble();
4921 if (t > 1.0) t = 1.0;
4924 double e = easeOutCubic(t);
4927 double curLat = m_startLat + (m_endLat - m_startLat) * e;
4928 double curLon = m_startLon + (m_endLon - m_startLon) * e;
4929 double curScale = m_startScale + (m_endScale - m_startScale) * e;
4934 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
4940 m_animationActive =
false;
4941 UpdateFollowButtonState();
4950 extendedSectorLegs.clear();
4959 if (iters++ > 5)
return false;
4960 if (!std::isnan(dlat))
break;
4963 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
4969 else if (dlat < -90)
4972 if (dlon > 360.) dlon -= 360.;
4973 if (dlon < -360.) dlon += 360.;
4988 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4992 if (VPoint.b_quilt) {
4993 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4994 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
4998 double tweak_scale_ppm =
5004 if (new_ref_dbIndex == -1) {
5005#pragma GCC diagnostic push
5006#pragma GCC diagnostic ignored "-Warray-bounds"
5013 int trial_index = -1;
5014 if (m_pCurrentStack->nEntry) {
5016 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
5019 if (trial_index < 0) {
5020 auto full_screen_array = GetQuiltFullScreendbIndexArray();
5021 if (full_screen_array.size())
5022 trial_index = full_screen_array[full_screen_array.size() - 1];
5025 if (trial_index >= 0) {
5026 m_pQuilt->SetReferenceChart(trial_index);
5031#pragma GCC diagnostic pop
5038 toSM(dlat, dlon,
gLat,
gLon, &offx, &offy);
5040 double offset_angle = atan2(offy, offx);
5041 double offset_distance = sqrt((offy * offy) + (offx * offx));
5042 double chart_angle = GetVPRotation();
5043 double target_angle = chart_angle - offset_angle;
5044 double d_east_mod = offset_distance * cos(target_angle);
5045 double d_north_mod = offset_distance * sin(target_angle);
5050 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5051 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5053 UpdateFollowButtonState();
5059 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5064bool ChartCanvas::IsOwnshipOnScreen() {
5067 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5068 ((r.y > 0) && r.y < GetCanvasHeight()))
5074void ChartCanvas::ReloadVP(
bool b_adjust) {
5075 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5077 LoadVP(VPoint, b_adjust);
5080void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5082 if (g_bopengl && m_glcc) {
5083 m_glcc->Invalidate();
5084 if (m_glcc->GetSize() != GetSize()) {
5085 m_glcc->SetSize(GetSize());
5090 m_cache_vp.Invalidate();
5091 m_bm_cache_vp.Invalidate();
5094 VPoint.Invalidate();
5096 if (m_pQuilt) m_pQuilt->Invalidate();
5105 vp.m_projection_type, b_adjust);
5108void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5109 m_pQuilt->SetReferenceChart(dbIndex);
5110 VPoint.Invalidate();
5111 m_pQuilt->Invalidate();
5114double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5116 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5123int ChartCanvas::AdjustQuiltRefChart() {
5128 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5130 double min_ref_scale =
5131 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5132 double max_ref_scale =
5133 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5136 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5137 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5138 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5140 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5143 int target_stack_index = wxNOT_FOUND;
5145 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5146 if (index == m_pQuilt->GetRefChartdbIndex()) {
5147 target_stack_index = il;
5152 if (wxNOT_FOUND == target_stack_index)
5153 target_stack_index = 0;
5155 int ref_family = pc->GetChartFamily();
5156 int extended_array_count =
5157 m_pQuilt->GetExtendedStackIndexArray().size();
5158 while ((!brender_ok) &&
5159 ((
int)target_stack_index < (extended_array_count - 1))) {
5160 target_stack_index++;
5162 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5164 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5165 IsChartQuiltableRef(test_db_index)) {
5168 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5170 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5177 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5178 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5179 IsChartQuiltableRef(new_db_index)) {
5180 m_pQuilt->SetReferenceChart(new_db_index);
5183 ret = m_pQuilt->GetRefChartdbIndex();
5185 ret = m_pQuilt->GetRefChartdbIndex();
5188 ret = m_pQuilt->GetRefChartdbIndex();
5197void ChartCanvas::UpdateCanvasOnGroupChange() {
5198 delete m_pCurrentStack;
5210bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5211 double latNE,
double lonNE) {
5213 double latc = (latSW + latNE) / 2.0;
5214 double lonc = (lonSW + lonNE) / 2.0;
5217 double ne_easting, ne_northing;
5218 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5220 double sw_easting, sw_northing;
5221 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5223 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5230 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5233bool ChartCanvas::SetVPProjection(
int projection) {
5239 double prev_true_scale_ppm = m_true_scale_ppm;
5244 m_absolute_min_scale_ppm));
5252bool ChartCanvas::SetVPRotation(
double angle) {
5254 VPoint.
skew, angle);
5257 double skew,
double rotation,
int projection,
5258 bool b_adjust,
bool b_refresh) {
5263 if (VPoint.IsValid()) {
5264 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5265 (fabs(VPoint.
skew - skew) < 1e-9) &&
5266 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5267 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5268 (VPoint.m_projection_type == projection ||
5269 projection == PROJECTION_UNKNOWN))
5272 if (VPoint.m_projection_type != projection)
5273 VPoint.InvalidateTransformCache();
5283 if (projection != PROJECTION_UNKNOWN)
5284 VPoint.SetProjectionType(projection);
5285 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5286 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5289 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5290 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5291 if (VPoint.
clat > 89.5)
5293 else if (VPoint.
clat < -89.5)
5294 VPoint.
clat = -89.5;
5299 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5300 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5312 bool bwasValid = VPoint.IsValid();
5317 m_cache_vp.Invalidate();
5322 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5326 int mouseX = mouse_x;
5327 int mouseY = mouse_y;
5328 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5334 SendCursorLatLonToAllPlugIns(lat, lon);
5337 if (!VPoint.b_quilt && m_singleChart) {
5342 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5346 if ((!m_cache_vp.IsValid()) ||
5351 wxPoint cp_last, cp_this;
5355 if (cp_last != cp_this) {
5361 if (m_pCurrentStack) {
5363 int current_db_index;
5365 m_pCurrentStack->GetCurrentEntrydbIndex();
5367 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5369 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5372 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5376 if (VPoint.b_quilt) {
5378 m_pQuilt->InvalidateAllQuiltPatchs();
5382 if (!m_pCurrentStack)
return false;
5384 int current_db_index;
5386 m_pCurrentStack->GetCurrentEntrydbIndex();
5388 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5389 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5392 int current_ref_stack_index = -1;
5393 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5394 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5395 current_ref_stack_index = i;
5398 if (g_bFullScreenQuilt) {
5399 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5403 bool b_needNewRef =
false;
5406 if ((-1 == current_ref_stack_index) &&
5407 (m_pQuilt->GetRefChartdbIndex() >= 0))
5408 b_needNewRef =
true;
5415 bool renderable =
true;
5417 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5418 if (referenceChart) {
5419 double chartMaxScale = referenceChart->GetNormalScaleMax(
5421 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5423 if (!renderable) b_needNewRef =
true;
5426 if (b_needNewRef && !m_disable_adjust_on_zoom) {
5428 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5429 int target_scale = cte_ref.GetScale();
5430 int target_type = cte_ref.GetChartType();
5431 int candidate_stack_index;
5438 candidate_stack_index = 0;
5439 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5441 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5442 int candidate_scale = cte_candidate.GetScale();
5443 int candidate_type = cte_candidate.GetChartType();
5445 if ((candidate_scale >= target_scale) &&
5446 (candidate_type == target_type)) {
5447 bool renderable =
true;
5449 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5450 if (tentative_referenceChart) {
5451 double chartMaxScale =
5452 tentative_referenceChart->GetNormalScaleMax(
5454 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5457 if (renderable)
break;
5460 candidate_stack_index++;
5465 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5466 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5467 while (candidate_stack_index >= 0) {
5468 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5472 int candidate_scale = cte_candidate.GetScale();
5473 int candidate_type = cte_candidate.GetChartType();
5475 if ((candidate_scale <= target_scale) &&
5476 (candidate_type == target_type))
5479 candidate_stack_index--;
5484 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5485 (candidate_stack_index < 0))
5486 candidate_stack_index = 0;
5488 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5490 m_pQuilt->SetReferenceChart(new_ref_index);
5496 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5501 bool renderable =
true;
5503 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5504 if (referenceChart) {
5505 double chartMaxScale = referenceChart->GetNormalScaleMax(
5507 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5508 proj =
ChartData->GetDBChartProj(ref_db_index);
5510 proj = PROJECTION_MERCATOR;
5512 VPoint.b_MercatorProjectionOverride =
5513 (m_pQuilt->GetnCharts() == 0 || !renderable);
5515 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5517 VPoint.SetProjectionType(proj);
5524 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5529 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5549 m_pQuilt->Invalidate();
5566 if (b_refresh) Refresh(
false);
5573 }
else if (!g_bopengl) {
5574 OcpnProjType projection = PROJECTION_UNKNOWN;
5577 projection = m_singleChart->GetChartProjectionType();
5578 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5579 VPoint.SetProjectionType(projection);
5583 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5584 m_cache_vp.Invalidate();
5588 UpdateCanvasControlBar();
5594 if (VPoint.GetBBox().GetValid()) {
5597 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5606 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5609 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5616 wxPoint2DDouble r, r1;
5618 double delta_check =
5622 double check_point = wxMin(89., VPoint.
clat);
5624 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5627 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5628 VPoint.
clon, 0, &rhumbDist);
5633 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5634 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5636 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5640 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5646 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5648 if (m_true_scale_ppm)
5649 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5654 double round_factor = 1000.;
5658 round_factor = 100.;
5660 round_factor = 1000.;
5663 double retina_coef = 1;
5667 retina_coef = GetContentScaleFactor();
5678 double true_scale_display =
5679 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5684 if (m_displayed_scale_factor > 10.0)
5685 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5686 m_displayed_scale_factor);
5687 else if (m_displayed_scale_factor > 1.0)
5688 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5689 m_displayed_scale_factor);
5690 else if (m_displayed_scale_factor > 0.1) {
5691 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5692 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5693 }
else if (m_displayed_scale_factor > 0.01) {
5694 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5695 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5698 "%s %4.0f (---)", _(
"Scale"),
5699 true_scale_display);
5702 m_scaleValue = true_scale_display;
5704 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5706 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5707 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5709 bool b_noshow =
false;
5713 wxClientDC dc(parent_frame->GetStatusBar());
5715 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5716 dc.SetFont(*templateFont);
5717 dc.GetTextExtent(text, &w, &h);
5722 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5723 if (w && w > rect.width) {
5724 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5728 dc.GetTextExtent(text, &w, &h);
5730 if (w && w > rect.width) {
5736 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5741 m_vLat = VPoint.
clat;
5742 m_vLon = VPoint.
clon;
5756static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5760static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5761 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5763wxColour ChartCanvas::PredColor() {
5766 if (SHIP_NORMAL == m_ownship_state)
5767 return GetGlobalColor(
"URED");
5769 else if (SHIP_LOWACCURACY == m_ownship_state)
5770 return GetGlobalColor(
"YELO1");
5772 return GetGlobalColor(
"NODTA");
5775wxColour ChartCanvas::ShipColor() {
5779 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5781 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5783 return GetGlobalColor(
"URED");
5786void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5787 wxPoint2DDouble lShipMidPoint) {
5788 dc.SetPen(wxPen(PredColor(), 2));
5790 if (SHIP_NORMAL == m_ownship_state)
5791 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5793 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5795 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5796 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5798 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5800 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5801 lShipMidPoint.m_y + 12);
5804void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5805 wxPoint GPSOffsetPixels,
5806 wxPoint2DDouble lGPSPoint) {
5811 float ref_dim = m_display_size_mm / 24;
5812 ref_dim = wxMin(ref_dim, 12);
5813 ref_dim = wxMax(ref_dim, 6);
5816 cPred.Set(g_cog_predictor_color);
5817 if (cPred == wxNullColour) cPred = PredColor();
5824 double nominal_line_width_pix = wxMax(
5826 floor(m_pix_per_mm / 2));
5830 if (nominal_line_width_pix > g_cog_predictor_width)
5831 g_cog_predictor_width = nominal_line_width_pix;
5834 wxPoint lPredPoint, lHeadPoint;
5836 float pCog = std::isnan(
gCog) ? 0 :
gCog;
5837 float pSog = std::isnan(
gSog) ? 0 :
gSog;
5839 double pred_lat, pred_lon;
5840 ll_gc_ll(
gLat,
gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5841 &pred_lat, &pred_lon);
5852 float ndelta_pix = 10.;
5853 double hdg_pred_lat, hdg_pred_lon;
5854 bool b_render_hdt =
false;
5855 if (!std::isnan(
gHdt)) {
5857 ll_gc_ll(
gLat,
gLon,
gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5860 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5861 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5862 if (dist > ndelta_pix ) {
5863 box.SetFromSegment(
gLat,
gLon, hdg_pred_lat, hdg_pred_lon);
5864 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5869 wxPoint lShipMidPoint;
5870 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5871 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5872 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5873 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5875 if (lpp >= img_height / 2) {
5876 box.SetFromSegment(
gLat,
gLon, pred_lat, pred_lon);
5877 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(
gCog) &&
5878 !std::isnan(
gSog)) {
5880 float dash_length = ref_dim;
5881 wxDash dash_long[2];
5883 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5884 g_cog_predictor_width);
5885 dash_long[1] = dash_long[0] / 2.0;
5889 if (dash_length > 250.) {
5890 dash_long[0] = 250. / g_cog_predictor_width;
5891 dash_long[1] = dash_long[0] / 2;
5894 wxPen ppPen2(cPred, g_cog_predictor_width,
5895 (wxPenStyle)g_cog_predictor_style);
5896 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5897 ppPen2.SetDashes(2, dash_long);
5900 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5901 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5903 if (g_cog_predictor_width > 1) {
5904 float line_width = g_cog_predictor_width / 3.;
5906 wxDash dash_long3[2];
5907 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5908 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5910 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
5911 (wxPenStyle)g_cog_predictor_style);
5912 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5913 ppPen3.SetDashes(2, dash_long3);
5915 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
5916 lGPSPoint.m_y + GPSOffsetPixels.y,
5917 lPredPoint.x + GPSOffsetPixels.x,
5918 lPredPoint.y + GPSOffsetPixels.y);
5921 if (g_cog_predictor_endmarker) {
5923 double png_pred_icon_scale_factor = .4;
5924 if (g_ShipScaleFactorExp > 1.0)
5925 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5926 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
5930 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
5931 (
float)(lPredPoint.x - lShipMidPoint.x));
5932 cog_rad += (float)PI;
5934 for (
int i = 0; i < 4; i++) {
5936 double pxa = (double)(s_png_pred_icon[j]);
5937 double pya = (double)(s_png_pred_icon[j + 1]);
5939 pya *= png_pred_icon_scale_factor;
5940 pxa *= png_pred_icon_scale_factor;
5942 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
5943 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
5945 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
5946 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
5950 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
5953 dc.SetBrush(wxBrush(cPred));
5955 dc.StrokePolygon(4, icon);
5962 float hdt_dash_length = ref_dim * 0.4;
5964 cPred.Set(g_ownship_HDTpredictor_color);
5965 if (cPred == wxNullColour) cPred = PredColor();
5967 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
5968 : g_cog_predictor_width * 0.8);
5969 wxDash dash_short[2];
5971 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
5974 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
5977 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
5978 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
5979 ppPen2.SetDashes(2, dash_short);
5983 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5984 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
5986 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
5988 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
5990 if (g_ownship_HDTpredictor_endmarker) {
5991 double nominal_circle_size_pixels = wxMax(
5992 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
5995 if (g_ShipScaleFactorExp > 1.0)
5996 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5998 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
5999 lHeadPoint.y + GPSOffsetPixels.y,
6000 nominal_circle_size_pixels / 2);
6005 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
6006 double factor = 1.00;
6007 if (g_pNavAidRadarRingsStepUnits == 1)
6009 else if (g_pNavAidRadarRingsStepUnits == 2) {
6010 if (std::isnan(
gSog))
6015 factor *= g_fNavAidRadarRingsStep;
6019 ll_gc_ll(
gLat,
gLon, 0, factor, &tlat, &tlon);
6022 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
6023 pow((
double)(lGPSPoint.m_y - r.y), 2));
6024 int pix_radius = (int)lpp;
6026 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
6028 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6031 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6033 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6034 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6038void ChartCanvas::ComputeShipScaleFactor(
6039 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6040 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6041 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6042 float screenResolution = m_pix_per_mm;
6045 double ship_bow_lat, ship_bow_lon;
6046 ll_gc_ll(
gLat,
gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6047 &ship_bow_lat, &ship_bow_lon);
6048 wxPoint lShipBowPoint;
6049 wxPoint2DDouble b_point =
6053 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6054 powf((
float)(b_point.m_y - a_point.m_y), 2));
6057 float shipLength_mm = shipLength_px / screenResolution;
6060 float ownship_min_mm = g_n_ownship_min_mm;
6061 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6064 float hdt_ant = icon_hdt + 180.;
6065 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6066 float dx = g_n_gps_antenna_offset_x / 1852.;
6067 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6075 if (shipLength_mm < ownship_min_mm) {
6076 dy /= shipLength_mm / ownship_min_mm;
6077 dx /= shipLength_mm / ownship_min_mm;
6080 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6082 ll_gc_ll(
gLat,
gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6083 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6089 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6090 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6092 float scale_factor = shipLength_px / ownShipLength;
6095 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6098 scale_factor = wxMax(scale_factor, scale_factor_min);
6100 scale_factor_y = scale_factor;
6101 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6102 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6105void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6106 if (!GetVP().IsValid())
return;
6108 wxPoint GPSOffsetPixels(0, 0);
6109 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6112 float pCog = std::isnan(
gCog) ? 0 :
gCog;
6113 float pSog = std::isnan(
gSog) ? 0 :
gSog;
6117 lShipMidPoint = lGPSPoint;
6121 float icon_hdt = pCog;
6122 if (!std::isnan(
gHdt)) icon_hdt =
gHdt;
6125 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6129 double osd_head_lat, osd_head_lon;
6130 wxPoint osd_head_point;
6132 ll_gc_ll(
gLat,
gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6137 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6138 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6139 icon_rad += (float)PI;
6141 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6145 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6149 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6150 if (GetVP().chart_scale >
6153 ShipDrawLargeScale(dc, lShipMidPoint);
6159 if (m_pos_image_user)
6160 pos_image = m_pos_image_user->Copy();
6161 else if (SHIP_NORMAL == m_ownship_state)
6162 pos_image = m_pos_image_red->Copy();
6163 if (SHIP_LOWACCURACY == m_ownship_state)
6164 pos_image = m_pos_image_yellow->Copy();
6165 else if (SHIP_NORMAL != m_ownship_state)
6166 pos_image = m_pos_image_grey->Copy();
6169 if (m_pos_image_user) {
6170 pos_image = m_pos_image_user->Copy();
6172 if (SHIP_LOWACCURACY == m_ownship_state)
6173 pos_image = m_pos_image_user_yellow->Copy();
6174 else if (SHIP_NORMAL != m_ownship_state)
6175 pos_image = m_pos_image_user_grey->Copy();
6178 img_height = pos_image.GetHeight();
6180 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6181 g_OwnShipIconType > 0)
6183 int ownShipWidth = 22;
6184 int ownShipLength = 84;
6185 if (g_OwnShipIconType == 1) {
6186 ownShipWidth = pos_image.GetWidth();
6187 ownShipLength = pos_image.GetHeight();
6190 float scale_factor_x, scale_factor_y;
6191 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6192 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6193 scale_factor_x, scale_factor_y);
6195 if (g_OwnShipIconType == 1) {
6196 pos_image.Rescale(ownShipWidth * scale_factor_x,
6197 ownShipLength * scale_factor_y,
6198 wxIMAGE_QUALITY_HIGH);
6199 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6201 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6204 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6205 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6206 if (rot_image.GetAlpha(ip, jp) > 64)
6207 rot_image.SetAlpha(ip, jp, 255);
6209 wxBitmap os_bm(rot_image);
6211 int w = os_bm.GetWidth();
6212 int h = os_bm.GetHeight();
6215 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6216 lShipMidPoint.m_y - h / 2,
true);
6219 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6220 lShipMidPoint.m_y - h / 2);
6221 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6222 lShipMidPoint.m_y - h / 2 + h);
6225 else if (g_OwnShipIconType == 2) {
6226 wxPoint ownship_icon[10];
6228 for (
int i = 0; i < 10; i++) {
6230 float pxa = (float)(s_ownship_icon[j]);
6231 float pya = (float)(s_ownship_icon[j + 1]);
6232 pya *= scale_factor_y;
6233 pxa *= scale_factor_x;
6235 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6236 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6238 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6239 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6242 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6244 dc.SetBrush(wxBrush(ShipColor()));
6246 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6249 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6251 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6255 img_height = ownShipLength * scale_factor_y;
6259 if (m_pos_image_user) circle_rad = 1;
6261 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6262 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6263 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6266 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6268 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6271 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6272 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6273 if (rot_image.GetAlpha(ip, jp) > 64)
6274 rot_image.SetAlpha(ip, jp, 255);
6276 wxBitmap os_bm(rot_image);
6278 if (g_ShipScaleFactorExp > 1) {
6279 wxImage scaled_image = os_bm.ConvertToImage();
6280 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6282 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6283 scaled_image.GetHeight() * factor,
6284 wxIMAGE_QUALITY_HIGH));
6286 int w = os_bm.GetWidth();
6287 int h = os_bm.GetHeight();
6290 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6291 lShipMidPoint.m_y - h / 2,
true);
6295 if (m_pos_image_user) circle_rad = 1;
6297 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6298 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6299 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6302 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6303 lShipMidPoint.m_y - h / 2);
6304 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6305 lShipMidPoint.m_y - h / 2 + h);
6310 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6323void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6324 float &MinorSpacing) {
6329 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6330 {.000001f, 45.0f, 15.0f},
6331 {.0002f, 30.0f, 10.0f},
6332 {.0003f, 10.0f, 2.0f},
6333 {.0008f, 5.0f, 1.0f},
6334 {.001f, 2.0f, 30.0f / 60.0f},
6335 {.003f, 1.0f, 20.0f / 60.0f},
6336 {.006f, 0.5f, 10.0f / 60.0f},
6337 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6338 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6339 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6340 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6341 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6342 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6343 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6344 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6347 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6348 if (view_scale_ppm < lltab[tabi][0])
break;
6349 MajorSpacing = lltab[tabi][1];
6350 MinorSpacing = lltab[tabi][2];
6364wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6365 int deg = (int)fabs(latlon);
6366 float min = fabs((fabs(latlon) - deg) * 60.0);
6376 }
else if (latlon < 0.0) {
6388 if (spacing >= 1.0) {
6389 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6390 }
else if (spacing >= (1.0 / 60.0)) {
6391 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6393 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6410void ChartCanvas::GridDraw(
ocpnDC &dc) {
6411 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6413 double nlat, elon, slat, wlon;
6416 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6418 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6420 if (!m_pgridFont) SetupGridFont();
6421 dc.SetFont(*m_pgridFont);
6422 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6425 h = m_canvas_height;
6436 dlon = dlon + 360.0;
6439 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6442 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6445 while (lat < nlat) {
6448 CalcGridText(lat, gridlatMajor,
true);
6450 dc.
DrawLine(0, r.y, w, r.y,
false);
6451 dc.DrawText(st, 0, r.y);
6452 lat = lat + gridlatMajor;
6454 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6458 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6461 while (lat < nlat) {
6464 dc.
DrawLine(0, r.y, 10, r.y,
false);
6465 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6466 lat = lat + gridlatMinor;
6470 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6473 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6476 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6478 wxString st = CalcGridText(lon, gridlonMajor,
false);
6480 dc.
DrawLine(r.x, 0, r.x, h,
false);
6481 dc.DrawText(st, r.x, 0);
6482 lon = lon + gridlonMajor;
6487 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6491 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6493 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6496 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6497 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6498 lon = lon + gridlonMinor;
6505void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6507 double blat, blon, tlat, tlon;
6510 int x_origin = m_bDisplayGrid ? 60 : 20;
6511 int y_origin = m_canvas_height - 50;
6517 if (GetVP().chart_scale > 80000)
6521 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6522 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6527 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6528 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6532 double rotation = -VPoint.
rotation;
6534 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6536 int l1 = (y_origin - r.y) / count;
6538 for (
int i = 0; i < count; i++) {
6545 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6548 double blat, blon, tlat, tlon;
6555 int y_origin = m_canvas_height - chartbar_height - 5;
6559 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6566 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6571 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6572 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6576 float places = floor(logdist), rem = logdist - places;
6577 dist = pow(10, places);
6584 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6585 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6586 double rotation = -VPoint.
rotation;
6592 int l1 = r.x - x_origin;
6594 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6599 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6600 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6601 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6603 if (!m_pgridFont) SetupGridFont();
6604 dc.SetFont(*m_pgridFont);
6605 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6607 dc.GetTextExtent(s, &w, &h);
6613 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6617void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6622 double ra_max = 40.;
6624 wxPen pen_save = dc.GetPen();
6626 wxDateTime now = wxDateTime::Now();
6632 x0 = x1 = x + radius;
6637 while (angle < 360.) {
6638 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6641 if (angle > 360.) angle = 360.;
6643 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6651 x1 = (int)(x + cos(angle * PI / 180.) * r);
6652 y1 = (int)(y + sin(angle * PI / 180.) * r);
6662 dc.
DrawLine(x + radius, y, x1, y1);
6664 dc.SetPen(pen_save);
6667static bool bAnchorSoundPlaying =
false;
6669static void onAnchorSoundFinished(
void *ptr) {
6670 g_anchorwatch_sound->UnLoad();
6671 bAnchorSoundPlaying =
false;
6674void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6676 bool play_sound =
false;
6678 if (AnchorAlertOn1) {
6679 wxPoint TargetPoint;
6682 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6683 TargetPoint.y, 100);
6687 AnchorAlertOn1 =
false;
6690 if (AnchorAlertOn2) {
6691 wxPoint TargetPoint;
6694 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6695 TargetPoint.y, 100);
6699 AnchorAlertOn2 =
false;
6702 if (!bAnchorSoundPlaying) {
6703 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6704 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6705 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6706 if (g_anchorwatch_sound->IsOk()) {
6707 bAnchorSoundPlaying =
true;
6708 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6709 g_anchorwatch_sound->Play();
6715void ChartCanvas::UpdateShips() {
6718 wxClientDC dc(
this);
6719 if (!dc.IsOk())
return;
6721 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6722 if (!test_bitmap.IsOk())
return;
6724 wxMemoryDC temp_dc(test_bitmap);
6726 temp_dc.ResetBoundingBox();
6727 temp_dc.DestroyClippingRegion();
6728 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6739 ocpndc.CalcBoundingBox(px.x, px.y);
6744 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6745 temp_dc.MaxY() - temp_dc.MinY());
6747 wxRect own_ship_update_rect = ship_draw_rect;
6749 if (!own_ship_update_rect.IsEmpty()) {
6752 own_ship_update_rect.Union(ship_draw_last_rect);
6753 own_ship_update_rect.Inflate(2);
6756 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6758 ship_draw_last_rect = ship_draw_rect;
6760 temp_dc.SelectObject(wxNullBitmap);
6763void ChartCanvas::UpdateAlerts() {
6768 wxClientDC dc(
this);
6772 dc.GetSize(&sx, &sy);
6775 wxBitmap test_bitmap(sx, sy, -1);
6779 temp_dc.SelectObject(test_bitmap);
6781 temp_dc.ResetBoundingBox();
6782 temp_dc.DestroyClippingRegion();
6783 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6790 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6791 temp_dc.MaxX() - temp_dc.MinX(),
6792 temp_dc.MaxY() - temp_dc.MinY());
6794 if (!alert_rect.IsEmpty())
6795 alert_rect.Inflate(2);
6797 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6800 wxRect alert_update_rect = alert_draw_rect;
6801 alert_update_rect.Union(alert_rect);
6804 RefreshRect(alert_update_rect,
false);
6808 alert_draw_rect = alert_rect;
6810 temp_dc.SelectObject(wxNullBitmap);
6813void ChartCanvas::UpdateAIS() {
6819 wxClientDC dc(
this);
6823 dc.GetSize(&sx, &sy);
6831 if (
g_pAIS->GetTargetList().size() > 10) {
6832 ais_rect = wxRect(0, 0, sx, sy);
6835 wxBitmap test_bitmap(sx, sy, -1);
6839 temp_dc.SelectObject(test_bitmap);
6841 temp_dc.ResetBoundingBox();
6842 temp_dc.DestroyClippingRegion();
6843 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6847 AISDraw(ocpndc, GetVP(),
this);
6848 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6852 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6853 temp_dc.MaxY() - temp_dc.MinY());
6855 if (!ais_rect.IsEmpty())
6856 ais_rect.Inflate(2);
6858 temp_dc.SelectObject(wxNullBitmap);
6861 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6864 wxRect ais_update_rect = ais_draw_rect;
6865 ais_update_rect.Union(ais_rect);
6868 RefreshRect(ais_update_rect,
false);
6872 ais_draw_rect = ais_rect;
6875void ChartCanvas::ToggleCPAWarn() {
6876 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6882 g_bTCPA_Max =
false;
6886 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6887 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6889 if (!g_AisFirstTimeUse) {
6890 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
6891 _(
"CPA") +
" " + mess, 4, 4);
6896void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6898void ChartCanvas::OnSize(wxSizeEvent &event) {
6899 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6901 GetClientSize(&m_canvas_width, &m_canvas_height);
6905 m_displayScale = GetContentScaleFactor();
6909 m_canvas_width *= m_displayScale;
6910 m_canvas_height *= m_displayScale;
6923 m_absolute_min_scale_ppm =
6925 (1.2 * WGS84_semimajor_axis_meters * PI);
6928 gFrame->ProcessCanvasResize();
6938 SetMUIBarPosition();
6939 UpdateFollowButtonState();
6940 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6944 xr_margin = m_canvas_width * 95 / 100;
6945 xl_margin = m_canvas_width * 5 / 100;
6946 yt_margin = m_canvas_height * 5 / 100;
6947 yb_margin = m_canvas_height * 95 / 100;
6950 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
6955 m_brepaint_piano =
true;
6958 m_dc_route.SelectObject(wxNullBitmap);
6961 m_dc_route.SelectObject(*proute_bm);
6975 m_glcc->OnSize(event);
6984void ChartCanvas::ProcessNewGUIScale() {
6992void ChartCanvas::CreateMUIBar() {
6993 if (g_useMUI && !m_muiBar) {
6999 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7000 m_muiBar->SetColorScheme(m_cs);
7001 m_muiBarHOSize = m_muiBar->m_size;
7005 SetMUIBarPosition();
7006 UpdateFollowButtonState();
7007 m_muiBar->UpdateDynamicValues();
7008 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
7012void ChartCanvas::SetMUIBarPosition() {
7016 int pianoWidth = GetClientSize().x * 0.6f;
7021 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
7022 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
7024 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
7025 m_muiBar->SetColorScheme(m_cs);
7029 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
7030 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7032 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7033 m_muiBar->SetColorScheme(m_cs);
7037 m_muiBar->SetBestPosition();
7041void ChartCanvas::DestroyMuiBar() {
7048void ChartCanvas::ShowCompositeInfoWindow(
7049 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7051 if (NULL == m_pCIWin) {
7056 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7059 s = _(
"Composite of ");
7062 s1.Printf(
"%d ", n_charts);
7070 s1.Printf(_(
"Chart scale"));
7073 s2.Printf(
"1:%d\n",
scale);
7077 s1 = _(
"Zoom in for more information");
7081 int char_width = s1.Length();
7082 int char_height = 3;
7084 if (g_bChartBarEx) {
7087 for (
int i : index_vector) {
7089 wxString path = cte.GetFullSystemPath();
7093 char_width = wxMax(char_width, path.Length());
7094 if (j++ >= 9)
break;
7097 s +=
" .\n .\n .\n";
7106 m_pCIWin->SetString(s);
7108 m_pCIWin->FitToChars(char_width, char_height);
7111 p.x = x / GetContentScaleFactor();
7112 if ((p.x + m_pCIWin->GetWinSize().x) >
7113 (m_canvas_width / GetContentScaleFactor()))
7114 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7115 m_pCIWin->GetWinSize().x) /
7118 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7119 4 - m_pCIWin->GetWinSize().y;
7121 m_pCIWin->dbIndex = 0;
7122 m_pCIWin->chart_scale = 0;
7123 m_pCIWin->SetPosition(p);
7124 m_pCIWin->SetBitmap();
7125 m_pCIWin->Refresh();
7129 HideChartInfoWindow();
7133void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7135 if (NULL == m_pCIWin) {
7140 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7149 dbIndex, FULL_INIT);
7151 int char_width, char_height;
7152 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7153 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7155 m_pCIWin->SetString(s);
7156 m_pCIWin->FitToChars(char_width, char_height);
7159 p.x = x / GetContentScaleFactor();
7160 if ((p.x + m_pCIWin->GetWinSize().x) >
7161 (m_canvas_width / GetContentScaleFactor()))
7162 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7163 m_pCIWin->GetWinSize().x) /
7166 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7167 4 - m_pCIWin->GetWinSize().y;
7169 m_pCIWin->dbIndex = dbIndex;
7170 m_pCIWin->SetPosition(p);
7171 m_pCIWin->SetBitmap();
7172 m_pCIWin->Refresh();
7176 HideChartInfoWindow();
7180void ChartCanvas::HideChartInfoWindow() {
7183 m_pCIWin->Destroy();
7187 androidForceFullRepaint();
7192void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7193 wxMouseEvent ev(wxEVT_MOTION);
7196 ev.m_leftDown = mouse_leftisdown;
7198 wxEvtHandler *evthp = GetEventHandler();
7200 ::wxPostEvent(evthp, ev);
7203void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7204 if ((m_panx_target_final - m_panx_target_now) ||
7205 (m_pany_target_final - m_pany_target_now)) {
7206 DoTimedMovementTarget();
7211void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7213bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7215 if (m_disable_edge_pan)
return false;
7218 int pan_margin = m_canvas_width * margin / 100;
7219 int pan_timer_set = 200;
7220 double pan_delta = GetVP().
pix_width * delta / 100;
7224 if (x > m_canvas_width - pan_margin) {
7229 else if (x < pan_margin) {
7234 if (y < pan_margin) {
7239 else if (y > m_canvas_height - pan_margin) {
7248 wxMouseState state = ::wxGetMouseState();
7249#if wxCHECK_VERSION(3, 0, 0)
7250 if (!state.LeftIsDown())
7252 if (!state.LeftDown())
7257 if ((bft) && !pPanTimer->IsRunning()) {
7259 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7265 if ((!bft) && pPanTimer->IsRunning()) {
7275void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7276 bool setBeingEdited) {
7277 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7278 m_pRoutePointEditTarget = NULL;
7279 m_pFoundPoint = NULL;
7282 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7283 SelectableItemList SelList =
pSelect->FindSelectionList(
7293 bool brp_viz =
false;
7294 if (m_pEditRouteArray) {
7295 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7296 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7297 if (pr->IsVisible()) {
7303 brp_viz = frp->IsVisible();
7307 if (m_pEditRouteArray)
7309 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7310 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7313 m_bRouteEditing = setBeingEdited;
7316 frp->m_bRPIsBeingEdited = setBeingEdited;
7317 m_bMarkEditing = setBeingEdited;
7320 m_pRoutePointEditTarget = frp;
7321 m_pFoundPoint = pFind;
7326std::shared_ptr<PI_PointContext> ChartCanvas::GetCanvasContextAtPoint(
int x,
7341 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7342 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7343 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7344 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7345 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7349 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7352 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7357 int FoundAIS_MMSI = 0;
7359 FoundAIS_MMSI = pFindAIS->GetUserData();
7362 if (
g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7363 seltype |= SELTYPE_AISTARGET;
7369 Route *SelectedRoute = NULL;
7375 Route *pSelectedActiveRoute = NULL;
7376 Route *pSelectedVizRoute = NULL;
7379 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7380 SelectableItemList SelList =
7381 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7389 bool brp_viz =
false;
7391 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7393 if (pr->IsVisible()) {
7398 if (!brp_viz && prp->IsShared())
7400 brp_viz = prp->IsVisible();
7403 brp_viz = prp->IsVisible();
7405 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7411 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7414 pSelectedActiveRoute = pr;
7415 pFoundActiveRoutePoint = prp;
7420 if (NULL == pSelectedVizRoute) {
7421 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7423 if (pr->IsVisible()) {
7424 pSelectedVizRoute = pr;
7425 pFoundVizRoutePoint = prp;
7431 delete proute_array;
7436 if (pFoundActiveRoutePoint) {
7437 FoundRoutePoint = pFoundActiveRoutePoint;
7438 SelectedRoute = pSelectedActiveRoute;
7439 }
else if (pFoundVizRoutePoint) {
7440 FoundRoutePoint = pFoundVizRoutePoint;
7441 SelectedRoute = pSelectedVizRoute;
7444 FoundRoutePoint = pFirstVizPoint;
7446 if (SelectedRoute) {
7447 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7448 }
else if (FoundRoutePoint) {
7449 seltype |= SELTYPE_MARKPOINT;
7454 if (m_pFoundRoutePoint) {
7458 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7459 RefreshRect(wp_rect,
true);
7468 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7469 SelectableItemList SelList =
7470 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7472 if (NULL == SelectedRoute)
7477 if (pr->IsVisible()) {
7484 if (SelectedRoute) {
7485 if (NULL == FoundRoutePoint)
7486 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7489 seltype |= SELTYPE_ROUTESEGMENT;
7494 if (pFindTrackSeg) {
7495 m_pSelectedTrack = NULL;
7496 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7497 SelectableItemList SelList =
7498 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7501 wxSelectableItemListNode *node = SelList.GetFirst();
7506 if (pt->IsVisible()) {
7507 m_pSelectedTrack = pt;
7510 node = node->GetNext();
7513 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7518 bool bseltc =
false;
7531 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7532 SelectableItemList SelList =
pSelectTC->FindSelectionList(
7536 wxSelectableItemListNode *node = SelList.GetFirst();
7537 pFind = node->GetData();
7538 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7540 if (SelList.GetCount() > 1) {
7541 node = node->GetNext();
7543 pFind = node->GetData();
7545 if (pIDX_candidate->
IDX_type ==
'c') {
7546 pIDX_best_candidate = pIDX_candidate;
7550 node = node->GetNext();
7553 wxSelectableItemListNode *node = SelList.GetFirst();
7554 pFind = node->GetData();
7555 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7558 m_pIDXCandidate = pIDX_best_candidate;
7565 seltype |= SELTYPE_CURRENTPOINT;
7568 else if (pFindTide) {
7569 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7576 seltype |= SELTYPE_TIDEPOINT;
7581 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7584 auto rstruct = std::make_shared<PI_PointContext>();
7585 rstruct->object_type = OBJECT_CHART;
7586 rstruct->object_ident =
"";
7588 if (seltype == SELTYPE_AISTARGET) {
7589 rstruct->object_type = OBJECT_AISTARGET;
7591 val.Printf(
"%d", FoundAIS_MMSI);
7592 rstruct->object_ident = val.ToStdString();
7593 }
else if (seltype & SELTYPE_MARKPOINT) {
7594 if (FoundRoutePoint) {
7595 rstruct->object_type = OBJECT_ROUTEPOINT;
7596 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7598 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7599 if (SelectedRoute) {
7600 rstruct->object_type = OBJECT_ROUTESEGMENT;
7601 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7608void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7609 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7610 singleClickEventIsValid =
false;
7611 m_DoubleClickTimer->Stop();
7616bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7617 if (!m_bChartDragging && !m_bDrawingRoute) {
7622 if (m_Compass && m_Compass->IsShown()) {
7624 bool isInCompass = logicalRect.Contains(event.GetPosition());
7625 if (isInCompass || m_mouseWasInCompass) {
7626 if (m_Compass->MouseEvent(event)) {
7627 cursor_region = CENTER;
7628 if (!g_btouch) SetCanvasCursor(event);
7629 m_mouseWasInCompass = isInCompass;
7633 m_mouseWasInCompass = isInCompass;
7636 if (m_notification_button && m_notification_button->IsShown()) {
7638 bool isinButton = logicalRect.Contains(event.GetPosition());
7640 SetCursor(*pCursorArrow);
7641 if (event.LeftDown()) HandleNotificationMouseClick();
7646 if (MouseEventToolbar(event))
return true;
7648 if (MouseEventChartBar(event))
return true;
7650 if (MouseEventMUIBar(event))
return true;
7652 if (MouseEventIENCBar(event))
return true;
7657void ChartCanvas::HandleNotificationMouseClick() {
7658 if (!m_NotificationsList) {
7662 m_NotificationsList->RecalculateSize();
7663 m_NotificationsList->Hide();
7666 if (m_NotificationsList->IsShown()) {
7667 m_NotificationsList->Hide();
7669 m_NotificationsList->RecalculateSize();
7670 m_NotificationsList->ReloadNotificationList();
7671 m_NotificationsList->Show();
7674bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7675 if (!g_bShowChartBar)
return false;
7677 if (!m_Piano->MouseEvent(event))
return false;
7679 cursor_region = CENTER;
7680 if (!g_btouch) SetCanvasCursor(event);
7684bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7685 if (!IsPrimaryCanvas())
return false;
7694 cursor_region = CENTER;
7695 if (!g_btouch) SetCanvasCursor(event);
7699bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7700 if (!IsPrimaryCanvas())
return false;
7713bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7715 if (!m_muiBar->MouseEvent(event))
return false;
7718 cursor_region = CENTER;
7719 if (!g_btouch) SetCanvasCursor(event);
7731 event.GetPosition(&x, &y);
7733 x *= m_displayScale;
7734 y *= m_displayScale;
7736 m_MouseDragging =
event.Dragging();
7742 if (event.Dragging()) {
7743 if ((x == mouse_x) && (y == mouse_y))
return true;
7749 mouse_leftisdown =
event.LeftDown();
7753 cursor_region = CENTER;
7757 if (m_Compass && m_Compass->IsShown() &&
7758 m_Compass->
GetRect().Contains(event.GetPosition())) {
7759 cursor_region = CENTER;
7760 }
else if (x > xr_margin) {
7761 cursor_region = MID_RIGHT;
7762 }
else if (x < xl_margin) {
7763 cursor_region = MID_LEFT;
7764 }
else if (y > yb_margin - chartbar_height &&
7765 y < m_canvas_height - chartbar_height) {
7766 cursor_region = MID_TOP;
7767 }
else if (y < yt_margin) {
7768 cursor_region = MID_BOT;
7770 cursor_region = CENTER;
7773 if (!g_btouch) SetCanvasCursor(event);
7777 leftIsDown =
event.LeftDown();
7780 if (event.LeftDown()) {
7781 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7784 g_bTempShowMenuBar =
false;
7785 parent_frame->ApplyGlobalSettings(
false);
7793 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7794 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7798 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7799 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7802 event.SetEventObject(
this);
7803 if (SendMouseEventToPlugins(event))
7810 if (g_btouch && !m_inPinch && m_bChartDragging && event.LeftUp()) {
7811 StartChartDragInertia();
7814 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7816 if (m_DoubleClickTimer->IsRunning()) {
7817 m_DoubleClickTimer->Stop();
7822 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7823 singleClickEvent = event;
7824 singleClickEventIsValid =
true;
7833 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7834 if (g_click_stop > 0) {
7842 if (GetUpMode() == COURSE_UP_MODE) {
7843 m_b_rot_hidef =
false;
7844 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7846 pRotDefTimer->Stop();
7849 bool bRoll = !g_btouch;
7854 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7855 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7856 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7857 m_RolloverPopupTimer.Start(
7861 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7865 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7874#if !defined(__WXGTK__) && !defined(__WXQT__)
7882 if ((x >= 0) && (y >= 0))
7887 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7888 wxPoint p = ClientToScreen(wxPoint(x, y));
7894 if (m_routeState >= 2) {
7897 m_bDrawingRoute =
true;
7899 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7904 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7907 m_bDrawingRoute =
true;
7909 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7922#if defined(__WXMAC__) || defined(__ANDROID__)
7926 wxClientDC cdc(GetParent());
7938 if (m_pSelectedRoute) {
7940 m_pSelectedRoute->DeSelectRoute();
7942 if (g_bopengl && m_glcc) {
7947 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7950 if (m_pFoundRoutePoint) {
7958 if (g_btouch && m_pRoutePointEditTarget) {
7961 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7965 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7966 pFindAIS =
pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7967 pFindRP =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7968 pFindRouteSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7969 pFindTrackSeg =
pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7973 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7976 pFindTide =
pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7982 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7985 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7986 seltype |= SELTYPE_AISTARGET;
7991 m_pFoundRoutePoint = NULL;
7996 Route *pSelectedActiveRoute = NULL;
7997 Route *pSelectedVizRoute = NULL;
8000 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8001 SelectableItemList SelList =
8002 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
8010 bool brp_viz =
false;
8012 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8014 if (pr->IsVisible()) {
8019 if (!brp_viz && prp->IsShared())
8021 brp_viz = prp->IsVisible();
8024 brp_viz = prp->IsVisible();
8026 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8031 m_pSelectedRoute = NULL;
8033 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8036 pSelectedActiveRoute = pr;
8037 pFoundActiveRoutePoint = prp;
8042 if (NULL == pSelectedVizRoute) {
8043 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8045 if (pr->IsVisible()) {
8046 pSelectedVizRoute = pr;
8047 pFoundVizRoutePoint = prp;
8053 delete proute_array;
8058 if (pFoundActiveRoutePoint) {
8059 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8060 m_pSelectedRoute = pSelectedActiveRoute;
8061 }
else if (pFoundVizRoutePoint) {
8062 m_pFoundRoutePoint = pFoundVizRoutePoint;
8063 m_pSelectedRoute = pSelectedVizRoute;
8066 m_pFoundRoutePoint = pFirstVizPoint;
8068 if (m_pSelectedRoute) {
8069 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8070 }
else if (m_pFoundRoutePoint) {
8071 seltype |= SELTYPE_MARKPOINT;
8075 if (m_pFoundRoutePoint) {
8079 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8080 RefreshRect(wp_rect,
true);
8088 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8089 SelectableItemList SelList =
8090 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8092 if (NULL == m_pSelectedRoute)
8097 if (pr->IsVisible()) {
8098 m_pSelectedRoute = pr;
8104 if (m_pSelectedRoute) {
8105 if (NULL == m_pFoundRoutePoint)
8106 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8111 if (g_bopengl && m_glcc) {
8116 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8118 seltype |= SELTYPE_ROUTESEGMENT;
8122 if (pFindTrackSeg) {
8123 m_pSelectedTrack = NULL;
8124 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8125 SelectableItemList SelList =
8126 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8131 if (pt->IsVisible()) {
8132 m_pSelectedTrack = pt;
8136 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8150 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8151 SelectableItemList SelList =
8152 pSelectTC->FindSelectionList(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8155 pFind = *SelList.begin();
8156 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8158 auto node = SelList.begin();
8159 if (SelList.size() > 1) {
8160 for (++node; node != SelList.end(); ++node) {
8163 if (pIDX_candidate->
IDX_type ==
'c') {
8164 pIDX_best_candidate = pIDX_candidate;
8169 pFind = *SelList.begin();
8170 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8173 m_pIDXCandidate = pIDX_best_candidate;
8174 seltype |= SELTYPE_CURRENTPOINT;
8177 else if (pFindTide) {
8178 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8179 seltype |= SELTYPE_TIDEPOINT;
8183 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8188void ChartCanvas::CallPopupMenu(
int x,
int y) {
8192 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8200 if (SELTYPE_CURRENTPOINT == seltype) {
8206 if (SELTYPE_TIDEPOINT == seltype) {
8212 InvokeCanvasMenu(x, y, seltype);
8215 if (m_pSelectedRoute &&
g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8219 m_pSelectedRoute = NULL;
8221 if (m_pFoundRoutePoint) {
8222 if (
pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8225 m_pFoundRoutePoint = NULL;
8231bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8239 event.GetPosition(&x, &y);
8245 SelectRadius = g_Platform->GetSelectRadiusPix() /
8246 (m_true_scale_ppm * 1852 * 60);
8253 if (event.LeftDClick() && (cursor_region == CENTER)) {
8254 m_DoubleClickTimer->Start();
8255 singleClickEventIsValid =
false;
8261 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8264 pFindAIS =
pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8267 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8268 if (
g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8269 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8275 SelectableItemList rpSelList =
8276 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8277 bool b_onRPtarget =
false;
8280 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8281 b_onRPtarget =
true;
8288 if (m_pRoutePointEditTarget) {
8290 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8296 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8299 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8300 m_pRoutePointEditTarget = NULL;
8301 RefreshRect(wp_rect,
true);
8305 auto node = rpSelList.begin();
8306 if (node != rpSelList.end()) {
8310 wxArrayPtrVoid *proute_array =
8315 bool brp_viz =
false;
8317 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8319 if (pr->IsVisible()) {
8324 delete proute_array;
8328 brp_viz = frp->IsVisible();
8330 brp_viz = frp->IsVisible();
8333 ShowMarkPropertiesDialog(frp);
8341 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8345 if (pr->IsVisible()) {
8346 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8351 cursorItem =
pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8355 if (pt->IsVisible()) {
8356 ShowTrackPropertiesDialog(pt);
8363 ShowObjectQueryWindow(x, y, zlat, zlon);
8368 if (event.LeftDown()) {
8384 bool appending =
false;
8385 bool inserting =
false;
8388 SetCursor(*pCursorPencil);
8392 m_bRouteEditing =
true;
8394 if (m_routeState == 1) {
8395 m_pMouseRoute =
new Route();
8396 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8406 double nearby_radius_meters =
8407 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8410 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8411 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8412 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8413 wxArrayPtrVoid *proute_array =
8418 bool brp_viz =
false;
8420 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8422 if (pr->IsVisible()) {
8427 delete proute_array;
8429 pNearbyPoint->IsShared())
8432 pNearbyPoint->IsVisible();
8434 brp_viz = pNearbyPoint->IsVisible();
8437 wxString msg = _(
"Use nearby waypoint?");
8439 const bool noname(pNearbyPoint->GetName() ==
"");
8442 _(
"Use nearby nameless waypoint and name it M with"
8443 " a unique number?");
8446 m_FinishRouteOnKillFocus =
false;
8448 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8449 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8450 m_FinishRouteOnKillFocus =
true;
8451 if (dlg_return == wxID_YES) {
8453 if (m_pMouseRoute) {
8454 int last_wp_num = m_pMouseRoute->GetnPoints();
8456 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8457 wxString wp_name = wxString::Format(
8458 "M%002i-%s", last_wp_num + 1, guid_short);
8459 pNearbyPoint->SetName(wp_name);
8461 pNearbyPoint->SetName(
"WPXX");
8463 pMousePoint = pNearbyPoint;
8466 if (m_routeState > 1)
8467 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8468 Undo_HasParent, NULL);
8471 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8472 bool procede =
false;
8476 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8482 m_FinishRouteOnKillFocus =
false;
8488 _(
"Insert first part of this route in the new route?");
8489 if (tail->GetIndexOf(pMousePoint) ==
8492 dmsg = _(
"Insert this route in the new route?");
8494 if (tail->GetIndexOf(pMousePoint) != 1) {
8495 dlg_return = OCPNMessageBox(
8496 this, dmsg, _(
"OpenCPN Route Create"),
8497 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8498 m_FinishRouteOnKillFocus =
true;
8500 if (dlg_return == wxID_YES) {
8507 _(
"Append last part of this route to the new route?");
8508 if (tail->GetIndexOf(pMousePoint) == 1)
8510 "Append this route to the new route?");
8515 if (tail->GetLastPoint() != pMousePoint) {
8516 dlg_return = OCPNMessageBox(
8517 this, dmsg, _(
"OpenCPN Route Create"),
8518 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8519 m_FinishRouteOnKillFocus =
true;
8521 if (dlg_return == wxID_YES) {
8532 if (!FindRouteContainingWaypoint(pMousePoint))
8533 pMousePoint->SetShared(
true);
8538 if (NULL == pMousePoint) {
8539 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8541 pMousePoint->SetNameShown(
false);
8545 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8547 if (m_routeState > 1)
8548 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8549 Undo_IsOrphanded, NULL);
8552 if (m_pMouseRoute) {
8553 if (m_routeState == 1) {
8555 m_pMouseRoute->AddPoint(pMousePoint);
8559 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8560 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8561 &rhumbBearing, &rhumbDist);
8562 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8563 rlat, &gcDist, &gcBearing, NULL);
8564 double gcDistNM = gcDist / 1852.0;
8567 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8568 pow(rhumbDist - gcDistNM - 1, 0.5);
8571 msg << _(
"For this leg the Great Circle route is ")
8573 << _(
" shorter than rhumbline.\n\n")
8574 << _(
"Would you like include the Great Circle routing points "
8577 m_FinishRouteOnKillFocus =
false;
8578 m_disable_edge_pan =
true;
8581 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8582 wxYES_NO | wxNO_DEFAULT);
8584 m_disable_edge_pan =
false;
8585 m_FinishRouteOnKillFocus =
true;
8587 if (answer == wxID_YES) {
8589 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8590 wxRealPoint gcCoord;
8592 for (
int i = 1; i <= segmentCount; i++) {
8593 double fraction = (double)i * (1.0 / (
double)segmentCount);
8594 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8595 gcDist * fraction, gcBearing,
8596 &gcCoord.x, &gcCoord.y, NULL);
8598 if (i < segmentCount) {
8599 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8601 gcPoint->SetNameShown(
false);
8603 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8605 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8608 gcPoint = pMousePoint;
8611 m_pMouseRoute->AddPoint(gcPoint);
8612 pSelect->AddSelectableRouteSegment(
8613 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8614 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8615 prevGcPoint = gcPoint;
8618 undo->CancelUndoableAction(
true);
8621 m_pMouseRoute->AddPoint(pMousePoint);
8622 pSelect->AddSelectableRouteSegment(
8623 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8624 pMousePoint, m_pMouseRoute);
8625 undo->AfterUndoableAction(m_pMouseRoute);
8629 m_pMouseRoute->AddPoint(pMousePoint);
8630 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8631 rlon, m_prev_pMousePoint,
8632 pMousePoint, m_pMouseRoute);
8633 undo->AfterUndoableAction(m_pMouseRoute);
8639 m_prev_pMousePoint = pMousePoint;
8647 int connect = tail->GetIndexOf(pMousePoint);
8652 int length = tail->GetnPoints();
8657 start = connect + 1;
8662 m_pMouseRoute->RemovePoint(
8666 for (i = start; i <= stop; i++) {
8667 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8670 m_pMouseRoute->GetnPoints();
8672 gFrame->RefreshAllCanvas();
8676 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8678 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8679 m_pMouseRoute->FinalizeForRendering();
8681 gFrame->RefreshAllCanvas();
8685 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8687 SetCursor(*pCursorPencil);
8689 if (!m_pMeasureRoute) {
8690 m_pMeasureRoute =
new Route();
8694 if (m_nMeasureState == 1) {
8701 wxEmptyString, wxEmptyString);
8703 pMousePoint->SetShowWaypointRangeRings(
false);
8705 m_pMeasureRoute->AddPoint(pMousePoint);
8709 m_prev_pMousePoint = pMousePoint;
8713 gFrame->RefreshAllCanvas();
8718 FindRoutePointsAtCursor(SelectRadius,
true);
8723 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8731 if (ret)
return true;
8734 if (event.Dragging()) {
8737 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8739 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8741 SelectableItemList SelList =
pSelect->FindSelectionList(
8745 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8750 if (m_pRoutePointEditTarget &&
8751 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8753 SelectableItemList SelList =
pSelect->FindSelectionList(
8757 if (m_pRoutePointEditTarget == frp) {
8758 m_bIsInRadius =
true;
8763 if (!m_dragoffsetSet) {
8765 .PresetDragOffset(
this, mouse_x, mouse_y);
8766 m_dragoffsetSet =
true;
8771 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8772 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8775 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8777 DraggingAllowed =
false;
8779 if (m_pRoutePointEditTarget &&
8780 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8781 DraggingAllowed =
false;
8783 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8785 if (DraggingAllowed) {
8786 if (!undo->InUndoableAction()) {
8787 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8788 Undo_NeedsCopy, m_pFoundPoint);
8794 if (!g_bopengl && m_pEditRouteArray) {
8795 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8796 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8803 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8804 pre_rect.Union(route_rect);
8812 if (CheckEdgePan(x, y,
true, 5, 2))
8820 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8822 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8823 m_pRoutePointEditTarget,
8824 SELTYPE_DRAGHANDLE);
8825 m_pFoundPoint->m_slat =
8826 m_pRoutePointEditTarget->m_lat;
8827 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8829 m_pRoutePointEditTarget->m_lat =
8831 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8832 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8833 m_pFoundPoint->m_slat =
8835 m_pFoundPoint->m_slon = new_cursor_lon;
8851 if (m_pEditRouteArray) {
8852 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8854 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8857 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8858 post_rect.Union(route_rect);
8864 pre_rect.Union(post_rect);
8865 RefreshRect(pre_rect,
false);
8867 gFrame->RefreshCanvasOther(
this);
8868 m_bRoutePoinDragging =
true;
8873 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8874 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8877 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8879 DraggingAllowed =
false;
8881 if (m_pRoutePointEditTarget &&
8882 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8883 DraggingAllowed =
false;
8885 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8887 if (DraggingAllowed) {
8888 if (!undo->InUndoableAction()) {
8889 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8890 Undo_NeedsCopy, m_pFoundPoint);
8904 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8910 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8911 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8912 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8913 (
int)(lppmax - (pre_rect.height / 2)));
8921 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8924 m_pRoutePointEditTarget,
8925 SELTYPE_DRAGHANDLE);
8926 m_pFoundPoint->m_slat =
8927 m_pRoutePointEditTarget->m_lat;
8928 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8930 m_pRoutePointEditTarget->m_lat =
8933 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8946 if (!g_btouch) InvalidateGL();
8952 .CalculateDCRect(m_dc_route,
this, &post_rect);
8953 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8954 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8955 (
int)(lppmax - (post_rect.height / 2)));
8958 pre_rect.Union(post_rect);
8959 RefreshRect(pre_rect,
false);
8961 gFrame->RefreshCanvasOther(
this);
8962 m_bRoutePoinDragging =
true;
8967 if (ret)
return true;
8970 if (event.LeftUp()) {
8971 bool b_startedit_route =
false;
8972 m_dragoffsetSet =
false;
8975 m_bChartDragging =
false;
8976 m_bIsInRadius =
false;
8981 m_bedge_pan =
false;
8986 bool appending =
false;
8987 bool inserting =
false;
8993 if (m_pRoutePointEditTarget) {
8999 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9000 RefreshRect(wp_rect,
true);
9002 m_pRoutePointEditTarget = NULL;
9004 m_bRouteEditing =
true;
9006 if (m_routeState == 1) {
9007 m_pMouseRoute =
new Route();
9008 m_pMouseRoute->SetHiLite(50);
9012 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9019 double nearby_radius_meters =
9020 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9023 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9024 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9025 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9028 m_FinishRouteOnKillFocus =
9030 dlg_return = OCPNMessageBox(
9031 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9032 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9033 m_FinishRouteOnKillFocus =
true;
9035 dlg_return = wxID_YES;
9037 if (dlg_return == wxID_YES) {
9038 pMousePoint = pNearbyPoint;
9041 if (m_routeState > 1)
9042 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9043 Undo_HasParent, NULL);
9044 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9046 bool procede =
false;
9050 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9056 m_FinishRouteOnKillFocus =
false;
9057 if (m_routeState == 1) {
9061 _(
"Insert first part of this route in the new route?");
9062 if (tail->GetIndexOf(pMousePoint) ==
9065 dmsg = _(
"Insert this route in the new route?");
9067 if (tail->GetIndexOf(pMousePoint) != 1) {
9069 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9070 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9071 m_FinishRouteOnKillFocus =
true;
9073 if (dlg_return == wxID_YES) {
9080 _(
"Append last part of this route to the new route?");
9081 if (tail->GetIndexOf(pMousePoint) == 1)
9083 "Append this route to the new route?");
9087 if (tail->GetLastPoint() != pMousePoint) {
9089 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9090 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9091 m_FinishRouteOnKillFocus =
true;
9093 if (dlg_return == wxID_YES) {
9104 if (!FindRouteContainingWaypoint(pMousePoint))
9105 pMousePoint->SetShared(
true);
9109 if (NULL == pMousePoint) {
9110 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9112 pMousePoint->SetNameShown(
false);
9114 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9116 if (m_routeState > 1)
9117 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9118 Undo_IsOrphanded, NULL);
9121 if (m_routeState == 1) {
9123 m_pMouseRoute->AddPoint(pMousePoint);
9124 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9128 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9129 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9130 &rhumbBearing, &rhumbDist);
9131 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9132 &gcDist, &gcBearing, NULL);
9133 double gcDistNM = gcDist / 1852.0;
9136 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9137 pow(rhumbDist - gcDistNM - 1, 0.5);
9140 msg << _(
"For this leg the Great Circle route is ")
9142 << _(
" shorter than rhumbline.\n\n")
9143 << _(
"Would you like include the Great Circle routing points "
9147 m_FinishRouteOnKillFocus =
false;
9148 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9149 wxYES_NO | wxNO_DEFAULT);
9150 m_FinishRouteOnKillFocus =
true;
9152 int answer = wxID_NO;
9155 if (answer == wxID_YES) {
9157 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9158 wxRealPoint gcCoord;
9160 for (
int i = 1; i <= segmentCount; i++) {
9161 double fraction = (double)i * (1.0 / (
double)segmentCount);
9162 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9163 gcDist * fraction, gcBearing,
9164 &gcCoord.x, &gcCoord.y, NULL);
9166 if (i < segmentCount) {
9167 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9169 gcPoint->SetNameShown(
false);
9170 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9173 gcPoint = pMousePoint;
9176 m_pMouseRoute->AddPoint(gcPoint);
9177 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9179 pSelect->AddSelectableRouteSegment(
9180 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9181 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9182 prevGcPoint = gcPoint;
9185 undo->CancelUndoableAction(
true);
9188 m_pMouseRoute->AddPoint(pMousePoint);
9189 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9190 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9191 rlon, m_prev_pMousePoint,
9192 pMousePoint, m_pMouseRoute);
9193 undo->AfterUndoableAction(m_pMouseRoute);
9197 m_pMouseRoute->AddPoint(pMousePoint);
9198 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9200 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9201 rlon, m_prev_pMousePoint,
9202 pMousePoint, m_pMouseRoute);
9203 undo->AfterUndoableAction(m_pMouseRoute);
9209 m_prev_pMousePoint = pMousePoint;
9216 int connect = tail->GetIndexOf(pMousePoint);
9221 int length = tail->GetnPoints();
9226 start = connect + 1;
9231 m_pMouseRoute->RemovePoint(
9235 for (i = start; i <= stop; i++) {
9236 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9239 m_pMouseRoute->GetnPoints();
9241 gFrame->RefreshAllCanvas();
9245 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9247 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9248 m_pMouseRoute->FinalizeForRendering();
9253 }
else if (m_bMeasure_Active && m_nMeasureState)
9256 m_bedge_pan =
false;
9260 if (m_nMeasureState == 1) {
9261 m_pMeasureRoute =
new Route();
9267 if (m_pMeasureRoute) {
9270 wxEmptyString, wxEmptyString);
9273 m_pMeasureRoute->AddPoint(pMousePoint);
9277 m_prev_pMousePoint = pMousePoint;
9279 m_pMeasureRoute->GetnPoints();
9283 CancelMeasureRoute();
9289 bool bSelectAllowed =
true;
9291 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9293 bSelectAllowed =
false;
9300 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9302 if (bSelectAllowed) {
9303 bool b_was_editing_mark = m_bMarkEditing;
9304 bool b_was_editing_route = m_bRouteEditing;
9305 FindRoutePointsAtCursor(SelectRadius,
9311 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9312 m_pRoutePointEditTarget = NULL;
9314 if (!b_was_editing_route) {
9315 if (m_pEditRouteArray) {
9316 b_startedit_route =
true;
9320 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9321 m_pTrackRolloverWin->IsActive(
false);
9323 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9324 m_pRouteRolloverWin->IsActive(
false);
9328 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9330 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9338 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9339 pre_rect.Union(route_rect);
9342 RefreshRect(pre_rect,
true);
9345 b_startedit_route =
false;
9349 if (m_pRoutePointEditTarget) {
9350 if (b_was_editing_mark ||
9351 b_was_editing_route) {
9352 if (m_lastRoutePointEditTarget) {
9356 .EnableDragHandle(
false);
9357 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9358 SELTYPE_DRAGHANDLE);
9362 if (m_pRoutePointEditTarget) {
9365 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9366 wxPoint2DDouble dragHandlePoint =
9368 .GetDragHandlePoint(
this);
9370 dragHandlePoint.m_y, dragHandlePoint.m_x,
9371 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9374 if (m_lastRoutePointEditTarget) {
9378 .EnableDragHandle(
false);
9379 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9380 SELTYPE_DRAGHANDLE);
9383 wxArrayPtrVoid *lastEditRouteArray =
9385 m_lastRoutePointEditTarget);
9386 if (lastEditRouteArray) {
9387 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9389 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9394 delete lastEditRouteArray;
9405 if (m_lastRoutePointEditTarget) {
9408 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9409 RefreshRect(wp_rect,
true);
9412 if (m_pRoutePointEditTarget) {
9415 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9416 RefreshRect(wp_rect,
true);
9424 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
9425 bool b_start_rollover =
false;
9429 if (pFind) b_start_rollover =
true;
9432 if (!b_start_rollover && !b_startedit_route) {
9433 SelectableItemList SelList =
pSelect->FindSelectionList(
9437 if (pr && pr->IsVisible()) {
9438 b_start_rollover =
true;
9444 if (!b_start_rollover && !b_startedit_route) {
9445 SelectableItemList SelList =
pSelect->FindSelectionList(
9449 if (tr && tr->IsVisible()) {
9450 b_start_rollover =
true;
9456 if (b_start_rollover)
9457 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9461 bool appending =
false;
9462 bool inserting =
false;
9464 if (m_bRouteEditing ) {
9466 if (m_pRoutePointEditTarget) {
9472 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9473 double nearby_radius_meters =
9474 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9475 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9476 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9477 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9479 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9483 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9485 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9489 std::find(list->begin(), list->end(), pNearbyPoint);
9490 if (pos != list->end()) {
9502 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9507 OCPNMessageBox(
this,
9508 _(
"Replace this RoutePoint by the nearby "
9510 _(
"OpenCPN RoutePoint change"),
9511 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9512 if (dlg_return == wxID_YES) {
9517 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9520 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9522 if (tail && current && (tail != current)) {
9524 connect = tail->GetIndexOf(pNearbyPoint);
9525 int index_current_route =
9526 current->GetIndexOf(m_pRoutePointEditTarget);
9527 index_last = current->GetIndexOf(current->GetLastPoint());
9528 dlg_return1 = wxID_NO;
9530 index_current_route) {
9532 if (connect != tail->GetnPoints()) {
9535 _(
"Last part of route to be appended to dragged "
9539 _(
"Full route to be appended to dragged route?");
9541 dlg_return1 = OCPNMessageBox(
9542 this, dmsg, _(
"OpenCPN Route Create"),
9543 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9544 if (dlg_return1 == wxID_YES) {
9548 }
else if (index_current_route ==
9553 _(
"First part of route to be inserted into dragged "
9555 if (connect == tail->GetnPoints())
9557 "Full route to be inserted into dragged route?");
9559 dlg_return1 = OCPNMessageBox(
9560 this, dmsg, _(
"OpenCPN Route Create"),
9561 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9562 if (dlg_return1 == wxID_YES) {
9569 if (m_pRoutePointEditTarget->IsShared()) {
9571 dlg_return = OCPNMessageBox(
9573 _(
"Do you really want to delete and replace this "
9575 "\n" + _(
"which has been created manually?"),
9576 (
"OpenCPN RoutePoint warning"),
9577 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9580 if (dlg_return == wxID_YES) {
9581 pMousePoint = pNearbyPoint;
9583 pMousePoint->SetShared(
true);
9593 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9595 if (m_pEditRouteArray) {
9596 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9598 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9603 auto pos = std::find(list->begin(), list->end(),
9604 m_pRoutePointEditTarget);
9606 pSelect->DeleteAllSelectableRoutePoints(pr);
9607 pSelect->DeleteAllSelectableRouteSegments(pr);
9610 pos = std::find(list->begin(), list->end(),
9611 m_pRoutePointEditTarget);
9614 pSelect->AddAllSelectableRouteSegments(pr);
9615 pSelect->AddAllSelectableRoutePoints(pr);
9617 pr->FinalizeForRendering();
9618 pr->UpdateSegmentDistances();
9619 if (m_bRoutePoinDragging) {
9621 NavObj_dB::GetInstance().UpdateRoute(pr);
9629 if (m_pEditRouteArray) {
9630 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9632 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9651 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9658 delete m_pRoutePointEditTarget;
9659 m_lastRoutePointEditTarget = NULL;
9660 m_pRoutePointEditTarget = NULL;
9661 undo->AfterUndoableAction(pMousePoint);
9662 undo->InvalidateUndo();
9667 else if (m_bMarkEditing) {
9668 if (m_pRoutePointEditTarget)
9669 if (m_bRoutePoinDragging) {
9671 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9675 if (m_pRoutePointEditTarget)
9676 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9678 if (!m_pRoutePointEditTarget) {
9679 delete m_pEditRouteArray;
9680 m_pEditRouteArray = NULL;
9681 m_bRouteEditing =
false;
9683 m_bRoutePoinDragging =
false;
9690 int length = tail->GetnPoints();
9691 for (
int i = connect + 1; i <= length; i++) {
9692 current->AddPointAndSegment(tail->GetPoint(i),
false);
9695 gFrame->RefreshAllCanvas();
9698 current->FinalizeForRendering();
9704 pSelect->DeleteAllSelectableRoutePoints(current);
9705 pSelect->DeleteAllSelectableRouteSegments(current);
9706 for (
int i = 1; i < connect; i++) {
9707 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9709 pSelect->AddAllSelectableRouteSegments(current);
9710 pSelect->AddAllSelectableRoutePoints(current);
9711 current->FinalizeForRendering();
9718 if (m_pEditRouteArray) {
9719 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9720 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9733 if (m_bRouteEditing) {
9736 bool appending =
false;
9737 bool inserting =
false;
9740 if (m_pRoutePointEditTarget) {
9741 m_pRoutePointEditTarget->
m_bBlink =
false;
9745 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9746 double nearby_radius_meters =
9747 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9748 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9749 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9750 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9752 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9753 bool duplicate =
false;
9755 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9757 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9761 std::find(list->begin(), list->end(), pNearbyPoint);
9762 if (pos != list->end()) {
9774 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9779 OCPNMessageBox(
this,
9780 _(
"Replace this RoutePoint by the nearby "
9782 _(
"OpenCPN RoutePoint change"),
9783 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9784 if (dlg_return == wxID_YES) {
9788 tail =
g_pRouteMan->FindVisibleRouteContainingWaypoint(
9791 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9793 if (tail && current && (tail != current)) {
9795 connect = tail->GetIndexOf(pNearbyPoint);
9796 int index_current_route =
9797 current->GetIndexOf(m_pRoutePointEditTarget);
9798 index_last = current->GetIndexOf(current->GetLastPoint());
9799 dlg_return1 = wxID_NO;
9801 index_current_route) {
9803 if (connect != tail->GetnPoints()) {
9806 _(
"Last part of route to be appended to dragged "
9810 _(
"Full route to be appended to dragged route?");
9812 dlg_return1 = OCPNMessageBox(
9813 this, dmsg, _(
"OpenCPN Route Create"),
9814 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9815 if (dlg_return1 == wxID_YES) {
9819 }
else if (index_current_route ==
9824 _(
"First part of route to be inserted into dragged "
9826 if (connect == tail->GetnPoints())
9828 "Full route to be inserted into dragged route?");
9830 dlg_return1 = OCPNMessageBox(
9831 this, dmsg, _(
"OpenCPN Route Create"),
9832 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9833 if (dlg_return1 == wxID_YES) {
9840 if (m_pRoutePointEditTarget->IsShared()) {
9841 dlg_return = wxID_NO;
9842 dlg_return = OCPNMessageBox(
9844 _(
"Do you really want to delete and replace this "
9846 "\n" + _(
"which has been created manually?"),
9847 (
"OpenCPN RoutePoint warning"),
9848 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9851 if (dlg_return == wxID_YES) {
9852 pMousePoint = pNearbyPoint;
9854 pMousePoint->SetShared(
true);
9864 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9866 if (m_pEditRouteArray) {
9867 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9869 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9873 auto pos = std::find(list->begin(), list->end(),
9874 m_pRoutePointEditTarget);
9876 pSelect->DeleteAllSelectableRoutePoints(pr);
9877 pSelect->DeleteAllSelectableRouteSegments(pr);
9880 pos = std::find(list->begin(), list->end(),
9881 m_pRoutePointEditTarget);
9882 if (pos != list->end()) list->erase(pos);
9885 pSelect->AddAllSelectableRouteSegments(pr);
9886 pSelect->AddAllSelectableRoutePoints(pr);
9888 pr->FinalizeForRendering();
9889 pr->UpdateSegmentDistances();
9892 if (m_bRoutePoinDragging) {
9897 NavObj_dB::GetInstance().UpdateRoutePoint(
9898 m_pRoutePointEditTarget);
9900 NavObj_dB::GetInstance().UpdateRoute(pr);
9912 int length = tail->GetnPoints();
9913 for (
int i = connect + 1; i <= length; i++) {
9914 current->AddPointAndSegment(tail->GetPoint(i),
false);
9918 gFrame->RefreshAllCanvas();
9921 current->FinalizeForRendering();
9927 pSelect->DeleteAllSelectableRoutePoints(current);
9928 pSelect->DeleteAllSelectableRouteSegments(current);
9929 for (
int i = 1; i < connect; i++) {
9930 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9932 pSelect->AddAllSelectableRouteSegments(current);
9933 pSelect->AddAllSelectableRoutePoints(current);
9934 current->FinalizeForRendering();
9941 if (m_pEditRouteArray) {
9942 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9944 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9956 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9963 delete m_pRoutePointEditTarget;
9964 m_lastRoutePointEditTarget = NULL;
9965 undo->AfterUndoableAction(pMousePoint);
9966 undo->InvalidateUndo();
9971 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9974 delete m_pEditRouteArray;
9975 m_pEditRouteArray = NULL;
9979 m_bRouteEditing =
false;
9980 m_pRoutePointEditTarget = NULL;
9986 else if (m_bMarkEditing) {
9987 if (m_pRoutePointEditTarget) {
9988 if (m_bRoutePoinDragging) {
9990 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9992 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9997 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9999 RefreshRect(wp_rect,
true);
10002 m_pRoutePointEditTarget = NULL;
10003 m_bMarkEditing =
false;
10008 else if (leftIsDown) {
10009 leftIsDown =
false;
10013 if (!m_bChartDragging && !m_bMeasure_Active) {
10015 m_bChartDragging =
false;
10019 m_bRoutePoinDragging =
false;
10022 if (ret)
return true;
10025 if (event.RightDown()) {
10036 m_FinishRouteOnKillFocus =
false;
10037 CallPopupMenu(mx, my);
10038 m_FinishRouteOnKillFocus =
true;
10049 if (event.ShiftDown()) {
10053 event.GetPosition(&x, &y);
10055 x *= m_displayScale;
10056 y *= m_displayScale;
10062 int wheel_dir =
event.GetWheelRotation();
10065 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10066 wheel_dir = wheel_dir > 0 ? 1 : -1;
10068 double factor = g_mouse_zoom_sensitivity;
10069 if (wheel_dir < 0) factor = 1 / factor;
10072 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10073 if (wheel_dir == m_last_wheel_dir) {
10074 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10079 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10080 m_wheelstopwatch.Start(0);
10085 m_last_wheel_dir = wheel_dir;
10090 if (event.LeftDown()) {
10096 last_drag.x = x, last_drag.y = y;
10097 panleftIsDown =
true;
10100 if (event.LeftUp()) {
10101 if (panleftIsDown) {
10103 panleftIsDown =
false;
10106 if (!m_bChartDragging && !m_bMeasure_Active) {
10107 switch (cursor_region) {
10129 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10134 m_bChartDragging =
false;
10140 if (event.Dragging() && event.LeftIsDown()) {
10157 if (g_btouch && !m_inPinch) {
10158 struct timespec now;
10159 clock_gettime(CLOCK_MONOTONIC, &now);
10160 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10162 if (
false == m_bChartDragging) {
10164 last_drag.x = x, last_drag.y = y;
10165 m_bChartDragging =
true;
10166 m_chart_drag_total_time = 0;
10167 m_chart_drag_total_x = 0;
10168 m_chart_drag_total_y = 0;
10169 m_inertia_last_drag_x = x;
10170 m_inertia_last_drag_y = y;
10171 m_drag_vec_x.clear();
10172 m_drag_vec_y.clear();
10173 m_drag_vec_t.clear();
10174 m_last_drag_time = tnow;
10178 uint64_t delta_t = tnow - m_last_drag_time;
10179 double delta_tf = delta_t / 1e9;
10181 m_chart_drag_total_time += delta_tf;
10182 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10183 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10185 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10186 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10187 m_drag_vec_t.push_back(delta_tf);
10189 m_inertia_last_drag_x = x;
10190 m_inertia_last_drag_y = y;
10191 m_last_drag_time = tnow;
10193 if ((last_drag.x != x) || (last_drag.y != y)) {
10194 if (!m_routeState) {
10197 m_bChartDragging =
true;
10198 StartTimedMovement();
10199 m_pan_drag.x += last_drag.x - x;
10200 m_pan_drag.y += last_drag.y - y;
10201 last_drag.x = x, last_drag.y = y;
10204 }
else if (!g_btouch) {
10205 if ((last_drag.x != x) || (last_drag.y != y)) {
10206 if (!m_routeState) {
10209 m_bChartDragging =
true;
10210 StartTimedMovement();
10211 m_pan_drag.x += last_drag.x - x;
10212 m_pan_drag.y += last_drag.y - y;
10213 last_drag.x = x, last_drag.y = y;
10220 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10222 m_DoubleClickTimer->Start();
10223 singleClickEventIsValid =
false;
10231void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10232 if (MouseEventOverlayWindows(event))
return;
10239void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10242 wxCursor *ptarget_cursor = pCursorArrow;
10243 if (!pPlugIn_Cursor) {
10244 ptarget_cursor = pCursorArrow;
10245 if ((!m_routeState) &&
10246 (!m_bMeasure_Active) ) {
10247 if (cursor_region == MID_RIGHT) {
10248 ptarget_cursor = pCursorRight;
10249 }
else if (cursor_region == MID_LEFT) {
10250 ptarget_cursor = pCursorLeft;
10251 }
else if (cursor_region == MID_TOP) {
10252 ptarget_cursor = pCursorDown;
10253 }
else if (cursor_region == MID_BOT) {
10254 ptarget_cursor = pCursorUp;
10256 ptarget_cursor = pCursorArrow;
10258 }
else if (m_bMeasure_Active ||
10260 ptarget_cursor = pCursorPencil;
10262 ptarget_cursor = pPlugIn_Cursor;
10265 SetCursor(*ptarget_cursor);
10268void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10269 SetCursor(*pCursorArrow);
10272void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10276 wxArrayString files;
10278 ChartBase *target_chart = GetChartAtCursor();
10279 if (target_chart) {
10280 file.Assign(target_chart->GetFullPath());
10281 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10282 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10285 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10287 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10288 unsigned int im = stackIndexArray.size();
10289 int scale = 2147483647;
10290 if (VPoint.b_quilt && im > 0) {
10291 for (
unsigned int is = 0; is < im; is++) {
10292 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10293 CHART_TYPE_MBTILES) {
10294 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10296 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10297 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10299 .Contains(lat, lon)) {
10300 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10303 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10304 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10312 std::vector<Ais8_001_22 *> area_notices;
10314 if (
g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10317 for (
const auto &target :
g_pAIS->GetAreaNoticeSourcesList()) {
10318 auto target_data = target.second;
10319 if (!target_data->area_notices.empty()) {
10320 for (
auto &ani : target_data->area_notices) {
10325 for (Ais8_001_22_SubAreaList::iterator sa =
10326 area_notice.sub_areas.begin();
10327 sa != area_notice.sub_areas.end(); ++sa) {
10328 switch (sa->shape) {
10329 case AIS8_001_22_SHAPE_CIRCLE: {
10330 wxPoint target_point;
10332 bbox.Expand(target_point);
10333 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10336 case AIS8_001_22_SHAPE_RECT: {
10337 wxPoint target_point;
10339 bbox.Expand(target_point);
10340 if (sa->e_dim_m > sa->n_dim_m)
10341 bbox.EnLarge(sa->e_dim_m * vp_scale);
10343 bbox.EnLarge(sa->n_dim_m * vp_scale);
10346 case AIS8_001_22_SHAPE_POLYGON:
10347 case AIS8_001_22_SHAPE_POLYLINE: {
10348 for (
int i = 0; i < 4; ++i) {
10349 double lat = sa->latitude;
10350 double lon = sa->longitude;
10351 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10353 wxPoint target_point;
10355 bbox.Expand(target_point);
10359 case AIS8_001_22_SHAPE_SECTOR: {
10360 double lat1 = sa->latitude;
10361 double lon1 = sa->longitude;
10363 wxPoint target_point;
10365 bbox.Expand(target_point);
10366 for (
int i = 0; i < 18; ++i) {
10369 sa->left_bound_deg +
10370 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10371 sa->radius_m / 1852.0, &lat, &lon);
10373 bbox.Expand(target_point);
10375 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10378 bbox.Expand(target_point);
10384 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10385 area_notices.push_back(&area_notice);
10392 if (target_chart || !area_notices.empty() || file.HasName()) {
10394 int sel_rad_pix = 5;
10395 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10400 SetCursor(wxCURSOR_WAIT);
10401 bool lightsVis = m_encShowLights;
10402 if (!lightsVis) SetShowENCLights(
true);
10405 ListOfObjRazRules *rule_list = NULL;
10406 ListOfPI_S57Obj *pi_rule_list = NULL;
10409 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10410 else if (target_plugin_chart)
10411 pi_rule_list =
g_pi_manager->GetPlugInObjRuleListAtLatLon(
10412 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10414 ListOfObjRazRules *overlay_rule_list = NULL;
10415 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10418 if (CHs57_Overlay) {
10419 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10420 zlat, zlon, SelectRadius, &GetVP());
10423 if (!lightsVis) SetShowENCLights(
false);
10426 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10427 wxString face = dFont->GetFaceName();
10431 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10432 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10436 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10444 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10445 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10448 int points = dFont->GetPointSize();
10450 int points = dFont->GetPointSize() + 1;
10454 for (
int i = -2; i < 5; i++) {
10455 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10459 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10461 if (overlay_rule_list && CHs57_Overlay) {
10462 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10463 objText <<
"<hr noshade>";
10466 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10467 an != area_notices.end(); ++an) {
10468 objText <<
"<b>AIS Area Notice:</b> ";
10469 objText << ais8_001_22_notice_names[(*an)->notice_type];
10470 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10471 (*an)->sub_areas.begin();
10472 sa != (*an)->sub_areas.end(); ++sa)
10473 if (!sa->text.empty()) objText << sa->text;
10474 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10475 objText <<
"<hr noshade>";
10479 objText << Chs57->CreateObjDescriptions(rule_list);
10480 else if (target_plugin_chart)
10481 objText <<
g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10484 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10487 wxString AddFiles, filenameOK;
10489 if (!target_plugin_chart) {
10492 AddFiles = wxString::Format(
10493 "<hr noshade><br><b>Additional info files attached to: </b> "
10495 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10497 file.GetFullName());
10499 file.Assign(file.GetPath(),
"");
10500 wxDir dir(file.GetFullPath());
10502 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10504 file.Assign(dir.GetNameWithSep().append(filename));
10505 wxString FormatString =
10506 "<td valign=top><font size=-2><a "
10507 "href=\"%s\">%s</a></font></td>";
10508 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10509 filenameOK = file.GetFullPath();
10511 if (3 * ((
int)filecount / 3) == filecount)
10512 FormatString.Prepend(
"<tr>");
10514 FormatString.Prepend(
10515 "<td>  </td>");
10518 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10519 file.GetFullName());
10522 cont = dir.GetNext(&filename);
10524 objText << AddFiles <<
"</table>";
10526 objText <<
"</font>";
10527 objText <<
"</body></html>";
10529 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10533 if ((!Chs57 && filecount == 1)) {
10535 wxHtmlLinkInfo hli(filenameOK);
10536 wxHtmlLinkEvent hle(1, hli);
10540 if (rule_list) rule_list->Clear();
10543 if (overlay_rule_list) overlay_rule_list->Clear();
10544 delete overlay_rule_list;
10546 if (pi_rule_list) pi_rule_list->Clear();
10547 delete pi_rule_list;
10549 SetCursor(wxCURSOR_ARROW);
10553void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10562 wxSize canvas_size = GetSize();
10569 wxPoint canvas_pos = GetPosition();
10572 bool newFit =
false;
10573 if (canvas_size.x < fitted_size.x) {
10574 fitted_size.x = canvas_size.x - 40;
10575 if (canvas_size.y < fitted_size.y)
10576 fitted_size.y -= 40;
10578 if (canvas_size.y < fitted_size.y) {
10579 fitted_size.y = canvas_size.y - 40;
10580 if (canvas_size.x < fitted_size.x)
10581 fitted_size.x -= 40;
10592 wxString title_base = _(
"Mark Properties");
10594 title_base = _(
"Waypoint Properties");
10599 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10611void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10621 if (g_bresponsive) {
10622 wxSize canvas_size = GetSize();
10623 wxPoint canvas_pos = GetPosition();
10627 if (canvas_size.x < fitted_size.x) {
10628 fitted_size.x = canvas_size.x;
10629 if (canvas_size.y < fitted_size.y)
10630 fitted_size.y -= 20;
10632 if (canvas_size.y < fitted_size.y) {
10633 fitted_size.y = canvas_size.y;
10634 if (canvas_size.x < fitted_size.x)
10635 fitted_size.x -= 20;
10644 wxPoint xxp = ClientToScreen(canvas_pos);
10655void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10667void pupHandler_PasteWaypoint() {
10670 int pasteBuffer = kml.ParsePasteBuffer();
10671 RoutePoint *pasted = kml.GetParsedRoutePoint();
10672 if (!pasted)
return;
10674 double nearby_radius_meters =
10675 g_Platform->GetSelectRadiusPix() /
10676 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10678 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10679 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10681 int answer = wxID_NO;
10685 "There is an existing waypoint at the same location as the one you are "
10686 "pasting. Would you like to merge the pasted data with it?\n\n");
10687 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10688 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10689 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10692 if (answer == wxID_YES) {
10693 nearPoint->SetName(pasted->GetName());
10695 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10696 pRouteManagerDialog->UpdateWptListCtrl();
10699 if (answer == wxID_NO) {
10702 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10705 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10708 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10709 pRouteManagerDialog->UpdateWptListCtrl();
10714 gFrame->InvalidateAllGL();
10715 gFrame->RefreshAllCanvas(
false);
10718void pupHandler_PasteRoute() {
10721 int pasteBuffer = kml.ParsePasteBuffer();
10722 Route *pasted = kml.GetParsedRoute();
10723 if (!pasted)
return;
10725 double nearby_radius_meters =
10726 g_Platform->GetSelectRadiusPix() /
10727 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10733 bool mergepoints =
false;
10734 bool createNewRoute =
true;
10735 int existingWaypointCounter = 0;
10737 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10738 curPoint = pasted->GetPoint(i);
10739 nearPoint = pWayPointMan->GetNearbyWaypoint(
10740 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10742 mergepoints =
true;
10743 existingWaypointCounter++;
10751 int answer = wxID_NO;
10755 "There are existing waypoints at the same location as some of the ones "
10756 "you are pasting. Would you like to just merge the pasted data into "
10758 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10759 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10760 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10762 if (answer == wxID_CANCEL) {
10769 if (mergepoints && answer == wxID_YES &&
10770 existingWaypointCounter == pasted->GetnPoints()) {
10773 createNewRoute =
false;
10779 Route *newRoute = 0;
10782 if (createNewRoute) {
10783 newRoute =
new Route();
10787 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10788 curPoint = pasted->GetPoint(i);
10791 newPoint = pWayPointMan->GetNearbyWaypoint(
10792 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10793 newPoint->SetName(curPoint->GetName());
10796 if (createNewRoute) newRoute->AddPoint(newPoint);
10802 newPoint->SetIconName(
"circle");
10805 newPoint->SetShared(
false);
10807 newRoute->AddPoint(newPoint);
10808 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10811 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10814 if (i > 1 && createNewRoute)
10815 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10816 curPoint->m_lat, curPoint->m_lon,
10817 prevPoint, newPoint, newRoute);
10818 prevPoint = newPoint;
10821 if (createNewRoute) {
10824 NavObj_dB::GetInstance().InsertRoute(newRoute);
10830 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10831 pRouteManagerDialog->UpdateRouteListCtrl();
10832 pRouteManagerDialog->UpdateWptListCtrl();
10834 gFrame->InvalidateAllGL();
10835 gFrame->RefreshAllCanvas(
false);
10841void pupHandler_PasteTrack() {
10844 int pasteBuffer = kml.ParsePasteBuffer();
10845 Track *pasted = kml.GetParsedTrack();
10846 if (!pasted)
return;
10854 newTrack->SetName(pasted->GetName());
10856 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10857 curPoint = pasted->GetPoint(i);
10861 wxDateTime now = wxDateTime::Now();
10864 newTrack->AddPoint(newPoint);
10867 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10868 newPoint->m_lat, newPoint->m_lon,
10869 prevPoint, newPoint, newTrack);
10871 prevPoint = newPoint;
10876 NavObj_dB::GetInstance().InsertTrack(newTrack);
10878 gFrame->InvalidateAllGL();
10879 gFrame->RefreshAllCanvas(
false);
10882bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10885 v[
"CursorPosition_x"] = x;
10886 v[
"CursorPosition_y"] = y;
10889 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10890 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10891 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
10896 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
10898 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
10901#define SELTYPE_UNKNOWN 0x0001
10902#define SELTYPE_ROUTEPOINT 0x0002
10903#define SELTYPE_ROUTESEGMENT 0x0004
10904#define SELTYPE_TIDEPOINT 0x0008
10905#define SELTYPE_CURRENTPOINT 0x0010
10906#define SELTYPE_ROUTECREATE 0x0020
10907#define SELTYPE_AISTARGET 0x0040
10908#define SELTYPE_MARKPOINT 0x0080
10909#define SELTYPE_TRACKSEGMENT 0x0100
10910#define SELTYPE_DRAGHANDLE 0x0200
10913 if (g_bhide_context_menus)
return true;
10915 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10916 m_pIDXCandidate, m_nmea_log);
10919 wxEVT_COMMAND_MENU_SELECTED,
10920 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10926 if (m_inLongPress) {
10927 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10928 m_inLongPress =
false;
10932 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10935 wxEVT_COMMAND_MENU_SELECTED,
10936 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10938 delete m_canvasMenu;
10939 m_canvasMenu = NULL;
10949void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10952 if (m_canvasMenu) {
10953 m_canvasMenu->PopupMenuHandler(event);
10958void ChartCanvas::StartRoute() {
10960 if (g_brouteCreating)
return;
10964 g_brouteCreating =
true;
10966 m_bDrawingRoute =
false;
10967 SetCursor(*pCursorPencil);
10969 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10971 HideGlobalToolbar();
10974 androidSetRouteAnnunciator(
true);
10978wxString ChartCanvas::FinishRoute() {
10980 m_prev_pMousePoint = NULL;
10981 m_bDrawingRoute =
false;
10983 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
10986 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10988 androidSetRouteAnnunciator(
false);
10991 SetCursor(*pCursorArrow);
10993 if (m_pMouseRoute) {
10994 if (m_bAppendingRoute) {
10996 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10998 if (m_pMouseRoute->GetnPoints() > 1) {
11000 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11003 m_pMouseRoute = NULL;
11006 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11013 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11014 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11015 pRouteManagerDialog->UpdateRouteListCtrl();
11018 m_bAppendingRoute =
false;
11019 m_pMouseRoute = NULL;
11021 m_pSelectedRoute = NULL;
11023 undo->InvalidateUndo();
11024 gFrame->RefreshAllCanvas(
true);
11028 ShowGlobalToolbar();
11030 g_brouteCreating =
false;
11035void ChartCanvas::HideGlobalToolbar() {
11036 if (m_canvasIndex == 0) {
11037 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11041void ChartCanvas::ShowGlobalToolbar() {
11042 if (m_canvasIndex == 0) {
11043 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11047void ChartCanvas::ShowAISTargetList() {
11048 if (NULL == g_pAISTargetList) {
11052 g_pAISTargetList->UpdateAISTargetList();
11055void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11056 if (!m_bShowOutlines)
return;
11060 int nEntry =
ChartData->GetChartTableEntries();
11062 for (
int i = 0; i < nEntry; i++) {
11066 bool b_group_draw =
false;
11067 if (m_groupIndex > 0) {
11068 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11069 int index = pt->GetGroupArray()[ig];
11070 if (m_groupIndex == index) {
11071 b_group_draw =
true;
11076 b_group_draw =
true;
11078 if (b_group_draw) RenderChartOutline(dc, i, vp);
11084 if (VPoint.b_quilt) {
11085 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11086 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11090 }
else if (m_singleChart &&
11091 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11095 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11098 if (zoom_factor > 8.0) {
11099 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11102 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11106 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11110void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11112 if (g_bopengl && m_glcc) {
11114 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11119 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11120 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11123 float plylat, plylon;
11124 float plylat1, plylon1;
11126 int pixx, pixy, pixx1, pixy1;
11129 ChartData->GetDBBoundingBox(dbIndex, box);
11133 if (box.GetLonRange() == 360)
return;
11135 double lon_bias = 0;
11137 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11139 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11141 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11142 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11144 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11145 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11148 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11151 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11152 if (0 == nAuxPlyEntries)
11156 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11157 plylon += lon_bias;
11163 for (
int i = 0; i < nPly - 1; i++) {
11164 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11165 plylon1 += lon_bias;
11171 int pixxs1 = pixx1;
11172 int pixys1 = pixy1;
11174 bool b_skip =
false;
11178 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11179 pow((
double)(pixy1 - pixy), 2)) /
11185 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11190 if (fabs(dist - distgc) > 10000. * 1852.)
11196 ClipResult res = cohen_sutherland_line_clip_i(
11198 if (res != Invisible && !b_skip)
11199 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11207 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11208 plylon1 += lon_bias;
11214 ClipResult res = cohen_sutherland_line_clip_i(
11216 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11223 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11224 for (
int j = 0; j < nAuxPlyEntries; j++) {
11226 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11231 for (
int i = 0; i < nAuxPly - 1; i++) {
11232 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11238 int pixxs1 = pixx1;
11239 int pixys1 = pixy1;
11241 bool b_skip =
false;
11245 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11246 ((pixy1 - pixy) * (pixy1 - pixy))) /
11251 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11256 if (fabs(dist - distgc) > 10000. * 1852.)
11262 ClipResult res = cohen_sutherland_line_clip_i(
11264 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11272 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11277 ClipResult res = cohen_sutherland_line_clip_i(
11279 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11284static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11285 const wxString &second) {
11286 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11288 int pointsize = dFont->GetPointSize();
11292 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11293 false, dFont->GetFaceName());
11295 dc.SetFont(*psRLI_font);
11303 int hilite_offset = 3;
11306 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11307 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11309 dc.GetTextExtent(first, &w1, &h1);
11310 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11316 w = wxMax(w1, w2) + (h1 / 2);
11321 xp = ref_point.x - w;
11323 yp += hilite_offset;
11325 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11327 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11328 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11330 dc.DrawText(first, xp, yp);
11331 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11334void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11335 if (!g_bAllowShipToActive)
return;
11341 wxPoint2DDouble pa, pb;
11348 if (rt->
m_width != wxPENSTYLE_INVALID)
11350 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11351 g_shipToActiveStyle, 5)];
11352 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11354 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11357 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11360 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11363 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11364 (
int)pb.m_y, GetVP(),
true);
11368#ifdef USE_ANDROID_GLES2
11369 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11371 if (style != wxPENSTYLE_SOLID) {
11372 if (glChartCanvas::dash_map.find(style) !=
11373 glChartCanvas::dash_map.end()) {
11374 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11378 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11381 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11382 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11388void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11390 if (m_routeState >= 2) route = m_pMouseRoute;
11391 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11392 route = m_pMeasureRoute;
11394 if (!route)
return;
11402 int np = route->GetnPoints();
11404 if (g_btouch && (np > 1)) np--;
11406 render_lat = rp.m_lat;
11407 render_lon = rp.m_lon;
11410 double rhumbBearing, rhumbDist;
11412 &rhumbBearing, &rhumbDist);
11413 double brg = rhumbBearing;
11414 double dist = rhumbDist;
11418 double gcBearing, gcBearing2, gcDist;
11419 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11422 double gcDistm = gcDist / 1852.0;
11425 rhumbBearing = 90.;
11427 wxPoint destPoint, lastPoint;
11430 int milesDiff = rhumbDist - gcDistm;
11431 if (milesDiff > 1) {
11442 for (
int i = 1; i <= milesDiff; i++) {
11443 double p = (double)i * (1.0 / (
double)milesDiff);
11445 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11446 &pLon, &pLat, &gcBearing2);
11448 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11450 lastPoint = destPoint;
11453 if (r_rband.x && r_rband.y) {
11454 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11456 if (m_bMeasure_DistCircle) {
11457 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11458 powf((
float)(r_rband.y - lastPoint.y), 2));
11461 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11462 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11468 wxString routeInfo;
11471 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11477 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11479 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11480 (
int)varBrg, 0x00B0);
11487 routeInfo <<
"\nReverse: ";
11489 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11490 (
int)(brg + 180.) % 360, 0x00B0);
11492 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11493 (
int)(varBrg + 180.) % 360, 0x00B0);
11498 s0.Append(_(
"Route") +
": ");
11500 s0.Append(_(
"Layer Route: "));
11503 if (!g_btouch) disp_length += dist;
11506 RouteLegInfo(dc, r_rband, routeInfo, s0);
11508 m_brepaint_piano =
true;
11511void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11512 if (!m_bShowVisibleSectors)
return;
11514 if (g_bDeferredInitDone) {
11516 double rhumbBearing, rhumbDist;
11517 DistanceBearingMercator(
gLat,
gLon, m_sector_glat, m_sector_glon,
11518 &rhumbBearing, &rhumbDist);
11520 if (rhumbDist > 0.05)
11522 s57_GetVisibleLightSectors(
this,
gLat,
gLon, GetVP(),
11523 m_sectorlegsVisible);
11524 m_sector_glat =
gLat;
11525 m_sector_glon =
gLon;
11527 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11531void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11539void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11540 if (!ps52plib)
return;
11542 if (VPoint.b_quilt) {
11543 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11545 if (m_pQuilt->IsQuiltVector()) {
11546 if (ps52plib->GetStateHash() != m_s52StateHash) {
11548 m_s52StateHash = ps52plib->GetStateHash();
11552 if (ps52plib->GetStateHash() != m_s52StateHash) {
11554 m_s52StateHash = ps52plib->GetStateHash();
11559 bool bSendPlibState =
true;
11560 if (VPoint.b_quilt) {
11561 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11564 if (bSendPlibState) {
11566 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11567 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11568 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11569 v[
"OpenCPN Version Date"] = VERSION_DATE;
11570 v[
"OpenCPN Version Full"] = VERSION_FULL;
11573 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11574 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11575 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11576 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11577 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11578 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11579 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11583 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11584 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11588 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11589 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11590 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11591 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11592 ps52plib->m_bShowS57ImportantTextOnly;
11593 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11594 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11595 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11596 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11597 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11600 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11601 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11602 v[
"OpenCPN Scale Factor Exp"] =
11603 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11610 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11611 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11612 g_lastS52PLIBPluginMessage = out;
11618void ChartCanvas::OnPaint(wxPaintEvent &event) {
11619 wxPaintDC dc(
this);
11629 if (!m_b_paint_enable) {
11634 UpdateCanvasS52PLIBConfig();
11637 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11639 if (m_glcc && g_bopengl) {
11640 if (!s_in_update) {
11650 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11652 wxRegion ru = GetUpdateRegion();
11654 int rx, ry, rwidth, rheight;
11655 ru.GetBox(rx, ry, rwidth, rheight);
11657#ifdef ocpnUSE_DIBSECTION
11660 wxMemoryDC temp_dc;
11668 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11669 height += m_Piano->GetHeight();
11671 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11675 int thumbx, thumby, thumbsx, thumbsy;
11676 pthumbwin->GetPosition(&thumbx, &thumby);
11677 pthumbwin->GetSize(&thumbsx, &thumbsy);
11678 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11681 rgn_chart.Subtract(rgn_thumbwin);
11682 ru.Subtract(rgn_thumbwin);
11688 wxRegion rgn_blit = ru;
11689 if (g_bShowChartBar) {
11690 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11691 GetClientSize().x, m_Piano->GetHeight());
11694 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11695 if (style->chartStatusWindowTransparent)
11696 m_brepaint_piano =
true;
11698 ru.Subtract(chart_bar_rect);
11702 if (m_Compass && m_Compass->IsShown()) {
11703 wxRect compassRect = m_Compass->
GetRect();
11704 if (ru.Contains(compassRect) != wxOutRegion) {
11705 ru.Subtract(compassRect);
11709 wxRect noteRect = m_notification_button->
GetRect();
11710 if (ru.Contains(noteRect) != wxOutRegion) {
11711 ru.Subtract(noteRect);
11715 bool b_newview =
true;
11720 m_cache_vp.IsValid()) {
11726 bool b_rcache_ok =
false;
11727 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11728 b_rcache_ok = !b_newview;
11731 if (VPoint.b_MercatorProjectionOverride)
11732 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11746 if (b_rcache_ok) chart_get_region.Clear();
11749 if (VPoint.b_quilt)
11751 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11753 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11758 AbstractPlatform::ShowBusySpinner();
11762 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11763 (m_working_bm.GetHeight() != svp.
pix_height))
11767 if (fabs(VPoint.
rotation) < 0.01) {
11768 bool b_save =
true;
11773 m_cache_vp.Invalidate();
11787 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11792 int dy = c_new.y - c_old.y;
11793 int dx = c_new.x - c_old.x;
11798 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11802 temp_dc.SelectObject(m_working_bm);
11804 wxMemoryDC cache_dc;
11805 cache_dc.SelectObject(m_cached_chart_bm);
11809 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11812 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11818 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11821 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11829 update_region.Union(
11832 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11837 update_region.Union(
11840 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11844 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11846 cache_dc.SelectObject(wxNullBitmap);
11850 temp_dc.SelectObject(m_cached_chart_bm);
11853 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11857 temp_dc.SelectObject(m_working_bm);
11858 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11863 temp_dc.SelectObject(m_cached_chart_bm);
11868 temp_dc.SelectObject(m_working_bm);
11869 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11882 wxMemoryDC scratch_dc_0;
11883 scratch_dc_0.SelectObject(m_cached_chart_bm);
11886 scratch_dc_0.SelectObject(wxNullBitmap);
11895 temp_dc.SelectObject(m_working_bm);
11898 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11899 chart_get_all_region);
11902 AbstractPlatform::HideBusySpinner();
11908 if (!m_singleChart) {
11909 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11914 if (!chart_get_region.IsEmpty()) {
11915 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11919 if (temp_dc.IsOk()) {
11924 if (!VPoint.b_quilt) {
11927 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11928 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11935 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11936 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11939 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11941 temp_dc.DestroyClippingRegion();
11946 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11948 if (!backgroundRegion.IsEmpty()) {
11954 wxColour water = pWorldBackgroundChart->water;
11955 if (water.IsOk()) {
11956 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11957 temp_dc.SetBrush(wxBrush(water));
11959 while (upd.HaveRects()) {
11960 wxRect rect = upd.GetRect();
11961 temp_dc.DrawRectangle(rect);
11966 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11967 temp_dc.SetDeviceClippingRegion(*clip_region);
11968 delete clip_region;
11972 SetVPRotation(VPoint.
skew);
11981 wxMemoryDC *pChartDC = &temp_dc;
11982 wxMemoryDC rotd_dc;
11984 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11986 if (!b_rcache_ok) {
11988 wxMemoryDC tbase_dc;
11990 tbase_dc.SelectObject(bm_base);
11992 tbase_dc.SelectObject(wxNullBitmap);
11994 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11997 wxImage base_image;
11998 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12006 bool b_rot_ok =
false;
12007 if (base_image.IsOk()) {
12010 m_b_rot_hidef =
false;
12014 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12015 m_b_rot_hidef, &m_roffset);
12020 rot_vp.IsValid() && (ri.IsOk())) {
12027 m_prot_bm =
new wxBitmap(ri);
12030 m_roffset.x += VPoint.rv_rect.x;
12031 m_roffset.y += VPoint.rv_rect.y;
12034 if (m_prot_bm && m_prot_bm->IsOk()) {
12035 rotd_dc.SelectObject(*m_prot_bm);
12036 pChartDC = &rotd_dc;
12038 pChartDC = &temp_dc;
12039 m_roffset = wxPoint(0, 0);
12042 pChartDC = &temp_dc;
12043 m_roffset = wxPoint(0, 0);
12046 wxPoint offset = m_roffset;
12049 m_cache_vp = VPoint;
12052 wxMemoryDC mscratch_dc;
12053 mscratch_dc.SelectObject(*pscratch_bm);
12055 mscratch_dc.ResetBoundingBox();
12056 mscratch_dc.DestroyClippingRegion();
12057 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12060 wxRegionIterator upd(rgn_blit);
12062 wxRect rect = upd.GetRect();
12064 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12065 rect.x - offset.x, rect.y - offset.y);
12071 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12072 if (
this == wxWindow::FindFocus()) {
12075 wxColour colour = GetGlobalColor(
"BLUE4");
12076 mscratch_dc.SetPen(wxPen(colour));
12077 mscratch_dc.SetBrush(wxBrush(colour));
12079 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12080 mscratch_dc.DrawRectangle(activeRect);
12085 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12086 unsigned int im = stackIndexArray.size();
12087 if (VPoint.b_quilt && im > 0) {
12088 std::vector<int> tiles_to_show;
12089 for (
unsigned int is = 0; is < im; is++) {
12091 ChartData->GetChartTableEntry(stackIndexArray[is]);
12092 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12095 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12096 tiles_to_show.push_back(stackIndexArray[is]);
12100 if (tiles_to_show.size())
12101 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12107 ocpnDC scratch_dc(mscratch_dc);
12108 RenderAlertMessage(mscratch_dc, GetVP());
12114#ifdef ocpnUSE_DIBSECTION
12119 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12120 q_dc.SelectObject(qbm);
12123 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12126 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12127 q_dc.SetBrush(qbr);
12128 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12131 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12134 q_dc.SelectObject(wxNullBitmap);
12143 if( VPoint.b_quilt ) {
12144 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12145 ChartBase *chart = m_pQuilt->GetRefChart();
12146 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12151 ChPI->ClearPLIBTextList();
12154 ps52plib->ClearTextList();
12158 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12160 wxColor maskBackground = wxColour(1,0,0);
12161 t_dc.SelectObject( qbm );
12162 t_dc.SetBackground(wxBrush(maskBackground));
12166 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12169 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12170 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12173 wxRegionIterator upd_final( ru );
12174 while( upd_final ) {
12175 wxRect rect = upd_final.GetRect();
12176 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12180 t_dc.SelectObject( wxNullBitmap );
12186 if (VPoint.b_quilt) {
12187 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12188 ChartBase *chart = m_pQuilt->GetRefChart();
12189 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12193 ChPI->ClearPLIBTextList();
12195 if (ps52plib) ps52plib->ClearTextList();
12200 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12202 if (g_bShowChartBar && m_Piano) {
12203 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12204 GetVP().pix_width, m_Piano->GetHeight());
12207 if (!style->chartStatusWindowTransparent)
12208 chart_all_text_region.Subtract(chart_bar_rect);
12211 if (m_Compass && m_Compass->IsShown()) {
12212 wxRect compassRect = m_Compass->
GetRect();
12213 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12214 chart_all_text_region.Subtract(compassRect);
12218 mscratch_dc.DestroyClippingRegion();
12220 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12221 chart_all_text_region);
12227 ocpnDC scratch_dc(mscratch_dc);
12228 DrawOverlayObjects(scratch_dc, ru);
12231 wxRegionIterator upd_final(rgn_blit);
12232 while (upd_final) {
12233 wxRect rect = upd_final.GetRect();
12234 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12241 temp_dc.SelectObject(wxNullBitmap);
12243 mscratch_dc.SelectObject(wxNullBitmap);
12245 dc.DestroyClippingRegion();
12250void ChartCanvas::PaintCleanup() {
12252 if (m_inPinch)
return;
12263 m_bTCupdate =
false;
12267 WarpPointer(warp_x, warp_y);
12274 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12275 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12279wxColour GetErrorGraphicColor(
double val)
12298 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12299 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12300 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12301 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12302 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12303 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12304 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12305 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12306 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12307 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12308 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12309 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12310 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12311 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12312 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12313 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12314 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12315 else if( val >= 48) c.Set(
"#410000");
12320void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12323 gr_image.InitAlpha();
12325 double maxval = -10000;
12326 double minval = 10000;
12343 maxval = wxMax(maxval, (glat - rlat));
12344 minval = wxMin(minval, (glat - rlat));
12361 double f = ((glat - rlat)-minval)/(maxval - minval);
12363 double dy = (f * 40);
12365 wxColour c = GetErrorGraphicColor(dy);
12366 unsigned char r = c.Red();
12367 unsigned char g = c.Green();
12368 unsigned char b = c.Blue();
12370 gr_image.SetRGB(j, i, r,g,b);
12371 if((glat - rlat )!= 0)
12372 gr_image.SetAlpha(j, i, 128);
12374 gr_image.SetAlpha(j, i, 255);
12381 wxBitmap *pbm =
new wxBitmap(gr_image);
12382 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12383 pbm->SetMask(gr_mask);
12385 pmdc->DrawBitmap(*pbm, 0,0);
12393void ChartCanvas::CancelMouseRoute() {
12395 m_pMouseRoute = NULL;
12396 m_bDrawingRoute =
false;
12399int ChartCanvas::GetNextContextMenuId() {
12400 return CanvasMenuHandler::GetNextContextMenuId();
12403bool ChartCanvas::SetCursor(
const wxCursor &c) {
12405 if (g_bopengl && m_glcc)
12406 return m_glcc->SetCursor(c);
12409 return wxWindow::SetCursor(c);
12412void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12413 if (g_bquiting)
return;
12423 if (!m_RolloverPopupTimer.IsRunning() &&
12424 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12425 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12426 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12427 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12430 if (m_glcc && g_bopengl) {
12433 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12435 m_glcc->Refresh(eraseBackground,
12452 if (m_pCIWin && m_pCIWin->IsShown()) {
12454 m_pCIWin->Refresh(
false);
12462 wxWindow::Refresh(eraseBackground, rect);
12465void ChartCanvas::Update() {
12466 if (m_glcc && g_bopengl) {
12471 wxWindow::Update();
12475 if (!pemboss)
return;
12476 int x = pemboss->x, y = pemboss->y;
12477 const double factor = 200;
12479 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12480 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12481 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12484 wxMemoryDC snip_dc;
12485 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12486 snip_dc.SelectObject(snip_bmp);
12488 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12489 snip_dc.SelectObject(wxNullBitmap);
12491 wxImage snip_img = snip_bmp.ConvertToImage();
12494 unsigned char *pdata = snip_img.GetData();
12496 for (
int y = 0; y < pemboss->height; y++) {
12497 int map_index = (y * pemboss->width);
12498 for (
int x = 0; x < pemboss->width; x++) {
12499 double val = (pemboss->pmap[map_index] * factor) / 256.;
12501 int nred = (int)((*pdata) + val);
12502 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12503 *pdata++ = (
unsigned char)nred;
12505 int ngreen = (int)((*pdata) + val);
12506 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12507 *pdata++ = (
unsigned char)ngreen;
12509 int nblue = (int)((*pdata) + val);
12510 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12511 *pdata++ = (
unsigned char)nblue;
12519 wxBitmap emb_bmp(snip_img);
12522 wxMemoryDC result_dc;
12523 result_dc.SelectObject(emb_bmp);
12526 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12528 result_dc.SelectObject(wxNullBitmap);
12534 if (GetQuiltMode()) {
12536 int refIndex = GetQuiltRefChartdbIndex();
12537 if (refIndex >= 0) {
12539 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12540 if (current_type == CHART_TYPE_MBTILES) {
12541 ChartBase *pChart = m_pQuilt->GetRefChart();
12544 zoom_factor = ptc->GetZoomFactor();
12549 if (zoom_factor <= 3.9)
return NULL;
12551 if (m_singleChart) {
12552 if (zoom_factor <= 3.9)
return NULL;
12557 if (m_pEM_OverZoom) {
12558 m_pEM_OverZoom->x = 4;
12559 m_pEM_OverZoom->y = 0;
12561 wxRect masterToolbarRect =
g_MainToolbar->GetToolbarRect();
12562 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12565 return m_pEM_OverZoom;
12568void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12581 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12582 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12586 AISDrawAreaNotices(dc, GetVP(),
this);
12588 wxDC *pdc = dc.GetDC();
12590 pdc->DestroyClippingRegion();
12591 wxDCClipper(*pdc, ru);
12594 if (m_bShowNavobjects) {
12595 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12596 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12597 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12598 DrawAnchorWatchPoints(dc);
12600 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12601 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12604 AISDraw(dc, GetVP(),
this);
12608 RenderVisibleSectorLights(dc);
12610 RenderAllChartOutlines(dc, GetVP());
12611 RenderRouteLegs(dc);
12612 RenderShipToActive(dc,
false);
12614 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12616 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12620 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12621 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12624 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12629 RebuildTideSelectList(GetVP().GetBBox());
12630 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12633 if (m_bShowCurrent) {
12634 RebuildCurrentSelectList(GetVP().GetBBox());
12635 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12638 if (!g_PrintingInProgress) {
12639 if (IsPrimaryCanvas()) {
12643 if (IsPrimaryCanvas()) {
12647 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12649 if (m_pTrackRolloverWin) {
12650 m_pTrackRolloverWin->Draw(dc);
12651 m_brepaint_piano =
true;
12654 if (m_pRouteRolloverWin) {
12655 m_pRouteRolloverWin->Draw(dc);
12656 m_brepaint_piano =
true;
12659 if (m_pAISRolloverWin) {
12660 m_pAISRolloverWin->Draw(dc);
12661 m_brepaint_piano =
true;
12663 if (m_brepaint_piano && g_bShowChartBar) {
12664 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12667 if (m_Compass) m_Compass->Paint(dc);
12669 if (!g_CanvasHideNotificationIcon) {
12670 auto ¬eman = NotificationManager::GetInstance();
12671 if (noteman.GetNotificationCount()) {
12672 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12673 if (m_notification_button->UpdateStatus()) Refresh();
12674 m_notification_button->Show(
true);
12675 m_notification_button->Paint(dc);
12677 m_notification_button->Show(
false);
12682 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12688 if (!m_bShowDepthUnits)
return NULL;
12690 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12692 if (GetQuiltMode()) {
12693 wxString s = m_pQuilt->GetQuiltDepthUnit();
12696 depth_unit_type = DEPTH_UNIT_FEET;
12697 else if (s.StartsWith(
"FATHOMS"))
12698 depth_unit_type = DEPTH_UNIT_FATHOMS;
12699 else if (s.StartsWith(
"METERS"))
12700 depth_unit_type = DEPTH_UNIT_METERS;
12701 else if (s.StartsWith(
"METRES"))
12702 depth_unit_type = DEPTH_UNIT_METERS;
12703 else if (s.StartsWith(
"METRIC"))
12704 depth_unit_type = DEPTH_UNIT_METERS;
12705 else if (s.StartsWith(
"METER"))
12706 depth_unit_type = DEPTH_UNIT_METERS;
12709 if (m_singleChart) {
12710 depth_unit_type = m_singleChart->GetDepthUnitType();
12711 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12712 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12717 switch (depth_unit_type) {
12718 case DEPTH_UNIT_FEET:
12721 case DEPTH_UNIT_METERS:
12722 ped = m_pEM_Meters;
12724 case DEPTH_UNIT_FATHOMS:
12725 ped = m_pEM_Fathoms;
12731 ped->x = (GetVP().
pix_width - ped->width);
12733 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12734 wxRect r = m_Compass->
GetRect();
12735 ped->y = r.y + r.height;
12742void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12745 if (style->embossFont == wxEmptyString) {
12746 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12748 font.SetPointSize(60);
12749 font.SetWeight(wxFONTWEIGHT_BOLD);
12751 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12752 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12754 int emboss_width = 500;
12755 int emboss_height = 200;
12759 delete m_pEM_Meters;
12760 delete m_pEM_Fathoms;
12764 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12766 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12768 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12771#define OVERZOOM_TEXT _("OverZoom")
12773void ChartCanvas::SetOverzoomFont() {
12778 if (style->embossFont == wxEmptyString) {
12779 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12781 font.SetPointSize(40);
12782 font.SetWeight(wxFONTWEIGHT_BOLD);
12784 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12785 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12787 wxClientDC dc(
this);
12789 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12791 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12792 font.SetPointSize(font.GetPointSize() - 1);
12794 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12796 m_overzoomFont = font;
12797 m_overzoomTextWidth = w;
12798 m_overzoomTextHeight = h;
12801void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12802 delete m_pEM_OverZoom;
12804 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12806 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12807 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12810emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12811 int height,
const wxString &str,
12816 wxBitmap bmp(width, height, -1);
12819 wxMemoryDC temp_dc;
12820 temp_dc.SelectObject(bmp);
12823 temp_dc.SetBackground(*wxWHITE_BRUSH);
12824 temp_dc.SetTextBackground(*wxWHITE);
12825 temp_dc.SetTextForeground(*wxBLACK);
12829 temp_dc.SetFont(font);
12832 temp_dc.GetTextExtent(str, &str_w, &str_h);
12834 temp_dc.DrawText(str, 1, 1);
12837 temp_dc.SelectObject(wxNullBitmap);
12840 wxImage img = bmp.ConvertToImage();
12842 int image_width = str_w * 105 / 100;
12843 int image_height = str_h * 105 / 100;
12844 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12845 wxMin(image_height, img.GetHeight()));
12846 wxImage imgs = img.GetSubImage(r);
12850 case GLOBAL_COLOR_SCHEME_DAY:
12854 case GLOBAL_COLOR_SCHEME_DUSK:
12857 case GLOBAL_COLOR_SCHEME_NIGHT:
12864 const int w = imgs.GetWidth();
12865 const int h = imgs.GetHeight();
12866 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12871 for (
int y = 1; y < h - 1; y++) {
12872 for (
int x = 1; x < w - 1; x++) {
12874 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12875 val = (int)(val * val_factor);
12876 index = (y * w) + x;
12889void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12890 Track *active_track = NULL;
12893 active_track = pTrackDraw;
12897 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12900 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12903void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12904 Track *active_track = NULL;
12907 active_track = pTrackDraw;
12911 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12914void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12915 Route *active_route = NULL;
12917 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12918 active_route = pRouteDraw;
12923 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12928 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12931void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12932 Route *active_route = NULL;
12935 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12936 active_route = pRouteDraw;
12940 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12943void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12944 if (!pWayPointMan)
return;
12946 auto node = pWayPointMan->GetWaypointList()->begin();
12948 while (node != pWayPointMan->GetWaypointList()->end()) {
12957 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12961 if (pWP->GetShowWaypointRangeRings() &&
12962 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12963 double factor = 1.00;
12964 if (pWP->GetWaypointRangeRingsStepUnits() ==
12966 factor = 1 / 1.852;
12968 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12969 pWP->GetWaypointRangeRingsStep() / 60.;
12973 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12974 pWP->m_lat + radius, pWP->m_lon + radius);
12975 if (!BltBBox.IntersectOut(radar_box)) {
12986void ChartCanvas::DrawBlinkObjects() {
12988 wxRect update_rect;
12990 if (!pWayPointMan)
return;
12992 for (
RoutePoint *pWP : *pWayPointMan->GetWaypointList()) {
12999 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13002void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13007 wxPoint lAnchorPoint1, lAnchorPoint2;
13021 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13022 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13024 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13025 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13026 dc.SetBrush(*ppBrush);
13030 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13035 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13040 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13045 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13050double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13053 wxPoint lAnchorPoint;
13056 double tlat1, tlon1;
13058 if (pAnchorWatchPoint) {
13059 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13060 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13061 dabs = fabs(d1 / 1852.);
13062 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13067 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13068 pow((
double)(lAnchorPoint.y - r1.y), 2));
13071 if (d1 < 0) lpp = -lpp;
13079void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13082 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13084 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13090 if ((type ==
't') || (type ==
'T')) {
13091 if (BBox.Contains(lat, lon)) {
13093 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13099void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13102 wxDateTime this_now = gTimeSource;
13103 bool cur_time = !gTimeSource.IsValid();
13104 if (cur_time) this_now = wxDateTime::Now();
13105 time_t t_this_now = this_now.GetTicks();
13107 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13109 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13110 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13111 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13112 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13114 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13115 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13116 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13117 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13118 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13119 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13121 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13122 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13123 int font_size = wxMax(10, dFont->GetPointSize());
13126 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13127 false, dFont->GetFaceName());
13129 dc.SetPen(*pblack_pen);
13130 dc.SetBrush(*pgreen_brush);
13134 case GLOBAL_COLOR_SCHEME_DAY:
13137 case GLOBAL_COLOR_SCHEME_DUSK:
13140 case GLOBAL_COLOR_SCHEME_NIGHT:
13141 bm = m_bmTideNight;
13148 int bmw = bm.GetWidth();
13149 int bmh = bm.GetHeight();
13151 float scale_factor = 1.0;
13155 float icon_pixelRefDim = 45;
13160 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13162 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13164 scale_factor *= pix_factor;
13171 scale_factor *= user_scale_factor;
13172 scale_factor *= GetContentScaleFactor();
13175 double marge = 0.05;
13176 std::vector<LLBBox> drawn_boxes;
13177 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13181 if ((type ==
't') || (type ==
'T'))
13186 if (BBox.ContainsMarge(lat, lon, marge)) {
13188 if (GetVP().chart_scale < 500000) {
13189 bool bdrawn =
false;
13190 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13191 if (drawn_boxes[i].Contains(lat, lon)) {
13196 if (bdrawn)
continue;
13199 this_box.Set(lat, lon, lat, lon);
13200 this_box.EnLarge(.005);
13201 drawn_boxes.push_back(this_box);
13207 if (GetVP().chart_scale > 500000) {
13208 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13212 dc.SetFont(*plabelFont);
13224 if (
ptcmgr->GetTideFlowSens(
13225 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13229 ptcmgr->GetHightOrLowTide(
13230 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13231 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13243 if (tctime > t_this_now)
13244 ptcmgr->GetHightOrLowTide(
13245 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13246 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13250 ptcmgr->GetHightOrLowTide(
13251 t_this_now, FORWARD_TEN_MINUTES_STEP,
13252 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13266 int width = (int)(12 * scale_factor + 0.5);
13267 int height = (int)(45 * scale_factor + 0.5);
13268 int linew = wxMax(1, (
int)(scale_factor));
13269 int xDraw = r.x - (width / 2);
13270 int yDraw = r.y - (height / 2);
13273 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13274 int hs = (httime > lttime) ? -4 : 4;
13275 hs *= (int)(scale_factor + 0.5);
13276 if (ts > 0.995 || ts < 0.005) hs = 0;
13277 int ht_y = (int)(height * ts);
13280 pblack_pen->SetWidth(linew);
13281 dc.SetPen(*pblack_pen);
13282 dc.SetBrush(*pyelo_brush);
13283 dc.DrawRectangle(xDraw, yDraw, width, height);
13287 dc.SetPen(*pblue_pen);
13288 dc.SetBrush(*pblue_brush);
13289 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13290 (width - (4 * linew)), height - ht_y);
13296 arrow[0].x = xDraw + 2 * linew;
13297 arrow[1].x = xDraw + width / 2;
13298 arrow[2].x = xDraw + width - 2 * linew;
13299 pyelo_pen->SetWidth(linew);
13300 pblue_pen->SetWidth(linew);
13301 if (ts > 0.35 || ts < 0.15)
13303 hl = (int)(height * 0.25) + yDraw;
13305 arrow[1].y = hl + hs;
13308 dc.SetPen(*pyelo_pen);
13310 dc.SetPen(*pblue_pen);
13311 dc.DrawLines(3, arrow);
13313 if (ts > 0.60 || ts < 0.40)
13315 hl = (int)(height * 0.5) + yDraw;
13317 arrow[1].y = hl + hs;
13320 dc.SetPen(*pyelo_pen);
13322 dc.SetPen(*pblue_pen);
13323 dc.DrawLines(3, arrow);
13325 if (ts < 0.65 || ts > 0.85)
13327 hl = (int)(height * 0.75) + yDraw;
13329 arrow[1].y = hl + hs;
13332 dc.SetPen(*pyelo_pen);
13334 dc.SetPen(*pblue_pen);
13335 dc.DrawLines(3, arrow);
13339 s.Printf(
"%3.1f", nowlev);
13341 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13343 dc.GetTextExtent(s, &wx1, NULL);
13345 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13360void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13363 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13365 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13371 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13372 if ((BBox.Contains(lat, lon))) {
13374 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13380void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13383 float tcvalue, dir;
13387 double lon_last = 0.;
13388 double lat_last = 0.;
13390 double marge = 0.2;
13391 bool cur_time = !gTimeSource.IsValid();
13393 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13394 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13396 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13398 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13399 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13400 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13401 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13402 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13403 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13404 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13405 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13407 double skew_angle = GetVPRotation();
13409 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13410 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13411 int font_size = wxMax(10, dFont->GetPointSize());
13414 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13415 false, dFont->GetFaceName());
13417 float scale_factor = 1.0;
13423 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13425 float nominal_icon_size_pixels = 15;
13426 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13428 scale_factor *= pix_factor;
13435 scale_factor *= user_scale_factor;
13437 scale_factor *= GetContentScaleFactor();
13440 for (
int i = 1; i <
ptcmgr->Get_max_IDX() + 1; i++) {
13446 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13447 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13452 int dd = (int)(5.0 * scale_factor + 0.5);
13463 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13464 dc.SetPen(*pblack_pen);
13465 dc.SetBrush(*porange_brush);
13466 dc.DrawPolygon(4, d);
13469 dc.SetBrush(*pblack_brush);
13470 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13474 if (!
ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13488 double a1 = fabs(tcvalue) * 10.;
13490 a1 = wxMax(1.0, a1);
13491 double a2 = log10(a1);
13493 float cscale = scale_factor * a2 * 0.3;
13495 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13496 dc.SetPen(*porange_pen);
13497 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13501 if (bDrawCurrentValues) {
13502 dc.SetFont(*pTCFont);
13503 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13504 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13530 if (!pvIDX)
return;
13535 if (pCwin && pCwin->IsShown()) {
13543 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13558 pCwin =
new TCWin(
this, x, y, pvIDX);
13576#define NUM_CURRENT_ARROW_POINTS 9
13577static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13578 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13579 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13580 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13582void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13584 if (
scale > 1e-2) {
13585 float sin_rot = sin(rot_angle * PI / 180.);
13586 float cos_rot = cos(rot_angle * PI / 180.);
13590 float xt = CurrentArrowArray[0].x;
13591 float yt = CurrentArrowArray[0].y;
13593 float xp = (xt * cos_rot) - (yt * sin_rot);
13594 float yp = (xt * sin_rot) + (yt * cos_rot);
13595 int x1 = (int)(xp *
scale);
13596 int y1 = (int)(yp *
scale);
13599 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13600 xt = CurrentArrowArray[ip].x;
13601 yt = CurrentArrowArray[ip].y;
13603 float xp = (xt * cos_rot) - (yt * sin_rot);
13604 float yp = (xt * sin_rot) + (yt * cos_rot);
13605 int x2 = (int)(xp *
scale);
13606 int y2 = (int)(yp *
scale);
13608 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13616wxString ChartCanvas::FindValidUploadPort() {
13619 if (!g_uploadConnection.IsEmpty() &&
13620 g_uploadConnection.StartsWith(
"Serial")) {
13621 port = g_uploadConnection;
13627 for (
auto *cp : TheConnectionParams()) {
13628 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13629 port <<
"Serial:" << cp->Port;
13635void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13638 if (NULL == g_pais_query_dialog_active) {
13639 int pos_x = g_ais_query_dialog_x;
13640 int pos_y = g_ais_query_dialog_y;
13642 if (g_pais_query_dialog_active) {
13643 g_pais_query_dialog_active->Destroy();
13649 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13650 wxPoint(pos_x, pos_y));
13652 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13653 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13654 g_pais_query_dialog_active->SetMMSI(mmsi);
13655 g_pais_query_dialog_active->UpdateText();
13656 wxSize sz = g_pais_query_dialog_active->GetSize();
13658 bool b_reset_pos =
false;
13663 RECT frame_title_rect;
13664 frame_title_rect.left = pos_x;
13665 frame_title_rect.top = pos_y;
13666 frame_title_rect.right = pos_x + sz.x;
13667 frame_title_rect.bottom = pos_y + 30;
13669 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13670 b_reset_pos =
true;
13675 wxRect window_title_rect;
13676 window_title_rect.x = pos_x;
13677 window_title_rect.y = pos_y;
13678 window_title_rect.width = sz.x;
13679 window_title_rect.height = 30;
13681 wxRect ClientRect = wxGetClientDisplayRect();
13682 ClientRect.Deflate(
13684 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13688 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13691 g_pais_query_dialog_active->SetMMSI(mmsi);
13692 g_pais_query_dialog_active->UpdateText();
13695 g_pais_query_dialog_active->Show();
13698void ChartCanvas::ToggleCanvasQuiltMode() {
13699 bool cur_mode = GetQuiltMode();
13701 if (!GetQuiltMode())
13702 SetQuiltMode(
true);
13703 else if (GetQuiltMode()) {
13704 SetQuiltMode(
false);
13705 g_sticky_chart = GetQuiltReferenceChartIndex();
13708 if (cur_mode != GetQuiltMode()) {
13709 SetupCanvasQuiltMode();
13718 if (ps52plib) ps52plib->GenerateStateHash();
13720 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13721 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13724void ChartCanvas::DoCanvasStackDelta(
int direction) {
13725 if (!GetQuiltMode()) {
13726 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13727 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13728 if ((current_stack_index + direction) < 0)
return;
13730 if (m_bpersistent_quilt ) {
13732 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13734 if (IsChartQuiltableRef(new_dbIndex)) {
13735 ToggleCanvasQuiltMode();
13736 SelectQuiltRefdbChart(new_dbIndex);
13737 m_bpersistent_quilt =
false;
13740 SelectChartFromStack(current_stack_index + direction);
13743 std::vector<int> piano_chart_index_array =
13744 GetQuiltExtendedStackdbIndexArray();
13745 int refdb = GetQuiltRefChartdbIndex();
13748 int current_index = -1;
13749 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13750 if (refdb == piano_chart_index_array[i]) {
13755 if (current_index == -1)
return;
13758 int target_family = ctet.GetChartFamily();
13760 int new_index = -1;
13761 int check_index = current_index + direction;
13762 bool found =
false;
13763 int check_dbIndex = -1;
13764 int new_dbIndex = -1;
13768 (
unsigned int)check_index < piano_chart_index_array.size() &&
13769 (check_index >= 0)) {
13770 check_dbIndex = piano_chart_index_array[check_index];
13772 if (target_family == cte.GetChartFamily()) {
13774 new_index = check_index;
13775 new_dbIndex = check_dbIndex;
13779 check_index += direction;
13782 if (!found)
return;
13784 if (!IsChartQuiltableRef(new_dbIndex)) {
13785 ToggleCanvasQuiltMode();
13786 SelectdbChart(new_dbIndex);
13787 m_bpersistent_quilt =
true;
13789 SelectQuiltRefChart(new_index);
13793 gFrame->UpdateGlobalMenuItems();
13795 SetQuiltChartHiLiteIndex(-1);
13806void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13809 switch (event.GetId()) {
13821 DoCanvasStackDelta(1);
13826 DoCanvasStackDelta(-1);
13836 ShowCurrents(!GetbShowCurrent());
13843 ShowTides(!GetbShowTide());
13850 if (0 == m_routeState) {
13857 androidSetRouteAnnunciator(m_routeState == 1);
13863 SetAISCanvasDisplayStyle(-1);
13875void ChartCanvas::SetShowAIS(
bool show) {
13877 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13878 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13881void ChartCanvas::SetAttenAIS(
bool show) {
13882 m_bShowAISScaled = show;
13883 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13884 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13887void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13890 bool bShowAIS_Array[3] = {
true,
true,
false};
13891 bool bShowScaled_Array[3] = {
false,
true,
true};
13892 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13893 _(
"Attenuate less critical AIS targets"),
13894 _(
"Hide AIS Targets")};
13895 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
13897 int AIS_Toolbar_Switch = 0;
13898 if (StyleIndx == -1) {
13900 for (
int i = 1; i < ArraySize; i++) {
13901 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13902 (bShowScaled_Array[i] == m_bShowAISScaled))
13903 AIS_Toolbar_Switch = i;
13905 AIS_Toolbar_Switch++;
13906 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13907 AIS_Toolbar_Switch++;
13910 AIS_Toolbar_Switch = StyleIndx;
13913 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13915 int AIS_Toolbar_Switch_Next =
13916 AIS_Toolbar_Switch + 1;
13917 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13918 AIS_Toolbar_Switch_Next++;
13919 if (AIS_Toolbar_Switch_Next >= ArraySize)
13920 AIS_Toolbar_Switch_Next = 0;
13923 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13924 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13927void ChartCanvas::TouchAISToolActive() {}
13929void ChartCanvas::UpdateAISTBTool() {}
13937void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13939 bool b_update =
false;
13940 int cc1_edge_comp = 2;
13941 wxRect rect = m_Compass->
GetRect();
13942 wxSize parent_size = GetSize();
13944 parent_size *= m_displayScale;
13948 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13949 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13950 wxRect compass_rect(compass_pt, rect.GetSize());
13952 m_Compass->Move(compass_pt);
13954 if (m_Compass && m_Compass->IsShown())
13955 m_Compass->UpdateStatus(b_force_new | b_update);
13957 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
13958 scaler = wxMax(scaler, 1.0);
13959 wxPoint note_point = wxPoint(
13960 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
13961 m_notification_button->Move(note_point);
13962 m_notification_button->UpdateStatus();
13964 if (b_force_new | b_update) Refresh();
13967void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13968 ChartTypeEnum New_Type,
13969 ChartFamilyEnum New_Family) {
13970 if (!GetpCurrentStack())
return;
13973 if (index < GetpCurrentStack()->nEntry) {
13976 pTentative_Chart =
ChartData->OpenStackChartConditional(
13977 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13979 if (pTentative_Chart) {
13980 if (m_singleChart) m_singleChart->Deactivate();
13982 m_singleChart = pTentative_Chart;
13983 m_singleChart->Activate();
13985 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
13986 GetpCurrentStack(), m_singleChart->GetFullPath());
13999 double best_scale_ppm = GetBestVPScale(m_singleChart);
14000 double rotation = GetVPRotation();
14001 double oldskew = GetVPSkew();
14002 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14004 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14005 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14006 if (fabs(newskew) > 0.0001) rotation = newskew;
14009 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14011 UpdateGPSCompassStatusBox(
true);
14015 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14016 if (idx < 0)
return;
14018 std::vector<int> piano_active_chart_index_array;
14019 piano_active_chart_index_array.push_back(
14020 GetpCurrentStack()->GetCurrentEntrydbIndex());
14021 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14024void ChartCanvas::SelectdbChart(
int dbindex) {
14025 if (!GetpCurrentStack())
return;
14028 if (dbindex >= 0) {
14031 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14033 if (pTentative_Chart) {
14034 if (m_singleChart) m_singleChart->Deactivate();
14036 m_singleChart = pTentative_Chart;
14037 m_singleChart->Activate();
14039 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14040 GetpCurrentStack(), m_singleChart->GetFullPath());
14053 double best_scale_ppm = GetBestVPScale(m_singleChart);
14057 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14067void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14070 if (!GetQuiltMode()) {
14071 if (GetpCurrentStack()) {
14072 int stack_index = -1;
14073 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14074 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14075 if (check_dbIndex < 0)
continue;
14077 ChartData->GetChartTableEntry(check_dbIndex);
14078 if (type == cte.GetChartType()) {
14081 }
else if (family == cte.GetChartFamily()) {
14087 if (stack_index >= 0) {
14088 SelectChartFromStack(stack_index);
14092 int sel_dbIndex = -1;
14093 std::vector<int> piano_chart_index_array =
14094 GetQuiltExtendedStackdbIndexArray();
14095 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14096 int check_dbIndex = piano_chart_index_array[i];
14098 if (type == cte.GetChartType()) {
14099 if (IsChartQuiltableRef(check_dbIndex)) {
14100 sel_dbIndex = check_dbIndex;
14103 }
else if (family == cte.GetChartFamily()) {
14104 if (IsChartQuiltableRef(check_dbIndex)) {
14105 sel_dbIndex = check_dbIndex;
14111 if (sel_dbIndex >= 0) {
14112 SelectQuiltRefdbChart(sel_dbIndex,
false);
14114 AdjustQuiltRefChart();
14121 SetQuiltChartHiLiteIndex(-1);
14126bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14127 return std::find(m_tile_yesshow_index_array.begin(),
14128 m_tile_yesshow_index_array.end(),
14129 index) != m_tile_yesshow_index_array.end();
14132bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14133 return std::find(m_tile_noshow_index_array.begin(),
14134 m_tile_noshow_index_array.end(),
14135 index) != m_tile_noshow_index_array.end();
14138void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14139 if (std::find(m_tile_noshow_index_array.begin(),
14140 m_tile_noshow_index_array.end(),
14141 index) == m_tile_noshow_index_array.end()) {
14142 m_tile_noshow_index_array.push_back(index);
14152void ChartCanvas::HandlePianoClick(
14153 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14156 if (!m_pCurrentStack)
return;
14172 double distance = 25000;
14173 int closest_index = -1;
14174 for (
int chart_index : selected_dbIndex_array) {
14176 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14177 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14180 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14181 if (test_distance < distance) {
14182 distance = test_distance;
14183 closest_index = chart_index;
14187 int selected_dbIndex = selected_dbIndex_array[0];
14188 if (closest_index >= 0) selected_dbIndex = closest_index;
14190 if (!GetQuiltMode()) {
14191 if (m_bpersistent_quilt ) {
14192 if (IsChartQuiltableRef(selected_dbIndex)) {
14193 ToggleCanvasQuiltMode();
14194 SelectQuiltRefdbChart(selected_dbIndex);
14195 m_bpersistent_quilt =
false;
14197 SelectChartFromStack(selected_index);
14200 SelectChartFromStack(selected_index);
14201 g_sticky_chart = selected_dbIndex;
14205 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14209 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14210 bool bfound =
false;
14211 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14212 if (m_tile_noshow_index_array[i] ==
14213 selected_dbIndex) {
14214 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14221 m_tile_noshow_index_array.push_back(selected_dbIndex);
14225 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14226 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14230 if (IsChartQuiltableRef(selected_dbIndex)) {
14236 bool set_scale =
false;
14237 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14238 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14244 SelectQuiltRefdbChart(selected_dbIndex,
true);
14246 SelectQuiltRefdbChart(selected_dbIndex,
false);
14251 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14253 double proposed_scale_onscreen =
14256 if (g_bPreserveScaleOnX) {
14257 proposed_scale_onscreen =
14258 wxMin(proposed_scale_onscreen,
14260 GetCanvasWidth()));
14262 proposed_scale_onscreen =
14263 wxMin(proposed_scale_onscreen,
14265 GetCanvasWidth()));
14267 proposed_scale_onscreen =
14268 wxMax(proposed_scale_onscreen,
14277 ToggleCanvasQuiltMode();
14278 SelectdbChart(selected_dbIndex);
14279 m_bpersistent_quilt =
true;
14284 SetQuiltChartHiLiteIndex(-1);
14285 gFrame->UpdateGlobalMenuItems();
14287 HideChartInfoWindow();
14292void ChartCanvas::HandlePianoRClick(
14293 int x,
int y,
int selected_index,
14294 const std::vector<int> &selected_dbIndex_array) {
14297 if (!GetpCurrentStack())
return;
14299 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14300 UpdateCanvasControlBar();
14302 SetQuiltChartHiLiteIndex(-1);
14305void ChartCanvas::HandlePianoRollover(
14306 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14307 int n_charts,
int scale) {
14310 if (!GetpCurrentStack())
return;
14315 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14317 if (!GetQuiltMode()) {
14318 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14321 std::vector<int> piano_chart_index_array;
14322 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14323 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14324 if ((GetpCurrentStack()->nEntry > 1) ||
14325 (piano_chart_index_array.size() >= 1)) {
14326 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14328 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14330 }
else if (GetpCurrentStack()->nEntry == 1) {
14332 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14333 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14334 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14336 }
else if ((-1 == selected_index) &&
14337 (0 == selected_dbIndex_array.size())) {
14338 ShowChartInfoWindow(key_location.x, -1);
14342 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14344 if ((GetpCurrentStack()->nEntry > 1) ||
14345 (piano_chart_index_array.size() >= 1)) {
14347 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14348 selected_dbIndex_array);
14349 else if (n_charts == 1)
14350 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14352 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14359void ChartCanvas::ClearPianoRollover() {
14360 ClearQuiltChartHiLiteIndexArray();
14361 ShowChartInfoWindow(0, -1);
14362 std::vector<int> vec;
14363 ShowCompositeInfoWindow(0, 0, 0, vec);
14367void ChartCanvas::UpdateCanvasControlBar() {
14368 if (m_pianoFrozen)
return;
14370 if (!GetpCurrentStack())
return;
14372 if (!g_bShowChartBar)
return;
14375 int sel_family = -1;
14377 std::vector<int> piano_chart_index_array;
14378 std::vector<int> empty_piano_chart_index_array;
14380 wxString old_hash = m_Piano->GetStoredHash();
14382 if (GetQuiltMode()) {
14383 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14384 GetQuiltFullScreendbIndexArray());
14386 std::vector<int> piano_active_chart_index_array =
14387 GetQuiltCandidatedbIndexArray();
14388 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14390 std::vector<int> piano_eclipsed_chart_index_array =
14391 GetQuiltEclipsedStackdbIndexArray();
14392 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14394 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14395 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14397 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14398 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14400 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14401 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14404 if (m_singleChart) {
14405 sel_type = m_singleChart->GetChartType();
14406 sel_family = m_singleChart->GetChartFamily();
14411 std::vector<int> piano_skew_chart_index_array;
14412 std::vector<int> piano_tmerc_chart_index_array;
14413 std::vector<int> piano_poly_chart_index_array;
14415 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14417 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14418 double skew_norm = ctei.GetChartSkew();
14419 if (skew_norm > 180.) skew_norm -= 360.;
14421 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14422 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14425 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14426 if (fabs(skew_norm) > 1.)
14427 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14429 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14430 }
else if (fabs(skew_norm) > 1.)
14431 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14433 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14434 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14435 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14437 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14438 if (new_hash != old_hash) {
14439 m_Piano->FormatKeys();
14440 HideChartInfoWindow();
14441 m_Piano->ResetRollover();
14442 SetQuiltChartHiLiteIndex(-1);
14443 m_brepaint_piano =
true;
14449 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14451 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14452 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14453 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14454 if (e == CHART_FAMILY_RASTER) mask |= 1;
14455 if (e == CHART_FAMILY_VECTOR) {
14456 if (t == CHART_TYPE_CM93COMP)
14463 wxString s_indicated;
14464 if (sel_type == CHART_TYPE_CM93COMP)
14465 s_indicated =
"cm93";
14467 if (sel_family == CHART_FAMILY_RASTER)
14468 s_indicated =
"raster";
14469 else if (sel_family == CHART_FAMILY_VECTOR)
14470 s_indicated =
"vector";
14473 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14476void ChartCanvas::FormatPianoKeys() { m_Piano->FormatKeys(); }
14478void ChartCanvas::PianoPopupMenu(
14479 int x,
int y,
int selected_index,
14480 const std::vector<int> &selected_dbIndex_array) {
14481 if (!GetpCurrentStack())
return;
14484 if (!GetQuiltMode())
return;
14486 m_piano_ctx_menu =
new wxMenu();
14488 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14498 menu_selected_dbIndex = selected_dbIndex_array[0];
14499 menu_selected_index = selected_index;
14502 bool b_is_in_noshow =
false;
14503 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14504 if (m_quilt_noshow_index_array[i] ==
14505 menu_selected_dbIndex)
14507 b_is_in_noshow =
true;
14512 if (b_is_in_noshow) {
14513 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14514 _(
"Show This Chart"));
14515 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14516 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14517 }
else if (GetpCurrentStack()->nEntry > 1) {
14518 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14519 _(
"Hide This Chart"));
14520 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14521 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14525 wxPoint pos = wxPoint(x, y - 30);
14528 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14529 PopupMenu(m_piano_ctx_menu, pos);
14531 delete m_piano_ctx_menu;
14532 m_piano_ctx_menu = NULL;
14534 HideChartInfoWindow();
14535 m_Piano->ResetRollover();
14537 SetQuiltChartHiLiteIndex(-1);
14538 ClearQuiltChartHiLiteIndexArray();
14543void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14544 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14545 if (m_quilt_noshow_index_array[i] ==
14546 menu_selected_dbIndex)
14548 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14554void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14555 if (!GetpCurrentStack())
return;
14558 RemoveChartFromQuilt(menu_selected_dbIndex);
14562 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14563 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14565 int i = menu_selected_index + 1;
14566 bool b_success =
false;
14567 while (i < GetpCurrentStack()->nEntry - 1) {
14568 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14569 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14570 SelectQuiltRefChart(i);
14580 i = menu_selected_index - 1;
14582 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14583 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14584 SelectQuiltRefChart(i);
14594void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14596 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14597 if (m_quilt_noshow_index_array[i] ==
14600 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14605 m_quilt_noshow_index_array.push_back(dbIndex);
14608bool ChartCanvas::UpdateS52State() {
14609 bool retval =
false;
14612 ps52plib->SetShowS57Text(m_encShowText);
14613 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14614 ps52plib->m_bShowSoundg = m_encShowDepth;
14615 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14616 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14619 if (!m_encShowLights)
14620 ps52plib->AddObjNoshow(
"LIGHTS");
14622 ps52plib->RemoveObjNoshow(
"LIGHTS");
14623 ps52plib->SetLightsOff(!m_encShowLights);
14624 ps52plib->m_bExtendLightSectors =
true;
14627 ps52plib->SetAnchorOn(m_encShowAnchor);
14628 ps52plib->SetQualityOfData(m_encShowDataQual);
14634void ChartCanvas::SetShowENCDataQual(
bool show) {
14635 m_encShowDataQual = show;
14636 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14637 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14639 m_s52StateHash = 0;
14642void ChartCanvas::SetShowENCText(
bool show) {
14643 m_encShowText = show;
14644 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14645 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14647 m_s52StateHash = 0;
14650void ChartCanvas::SetENCDisplayCategory(
int category) {
14651 m_encDisplayCategory = category;
14652 m_s52StateHash = 0;
14655void ChartCanvas::SetShowENCDepth(
bool show) {
14656 m_encShowDepth = show;
14657 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14658 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14660 m_s52StateHash = 0;
14663void ChartCanvas::SetShowENCLightDesc(
bool show) {
14664 m_encShowLightDesc = show;
14665 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14666 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14668 m_s52StateHash = 0;
14671void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14672 m_encShowBuoyLabels = show;
14673 m_s52StateHash = 0;
14676void ChartCanvas::SetShowENCLights(
bool show) {
14677 m_encShowLights = show;
14678 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14679 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14681 m_s52StateHash = 0;
14684void ChartCanvas::SetShowENCAnchor(
bool show) {
14685 m_encShowAnchor = show;
14686 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14687 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14689 m_s52StateHash = 0;
14692wxRect ChartCanvas::GetMUIBarRect() {
14695 rv = m_muiBar->GetRect();
14701void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14702 if (!GetAlertString().IsEmpty()) {
14703 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14704 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14706 dc.SetFont(*pfont);
14707 dc.SetPen(*wxTRANSPARENT_PEN);
14709 dc.SetBrush(wxColour(243, 229, 47));
14711 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14715 wxRect sbr = GetScaleBarRect();
14716 int xp = sbr.x + sbr.width + 10;
14717 int yp = (sbr.y + sbr.height) - h;
14719 int wdraw = w + 10;
14720 dc.DrawRectangle(xp, yp, wdraw, h);
14721 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14722 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14732#define BRIGHT_XCALIB
14733#define __OPCPN_USEICC__
14736#ifdef __OPCPN_USEICC__
14737int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14738 double co_green,
double co_blue);
14740wxString temp_file_name;
14744class ocpnCurtain:
public wxDialog
14746 DECLARE_CLASS( ocpnCurtain )
14747 DECLARE_EVENT_TABLE()
14750 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14752 bool ProcessEvent(wxEvent& event);
14756IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14758BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14761ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14763 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14766ocpnCurtain::~ocpnCurtain()
14770bool ocpnCurtain::ProcessEvent(wxEvent& event)
14772 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14773 return GetParent()->GetEventHandler()->ProcessEvent(event);
14778#include <windows.h>
14781typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14782typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14783SetDeviceGammaRamp_ptr_type
14784 g_pSetDeviceGammaRamp;
14785GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14787WORD *g_pSavedGammaMap;
14791int InitScreenBrightness() {
14794 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14798 if (NULL == hGDI32DLL) {
14799 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14801 if (NULL != hGDI32DLL) {
14803 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14804 hGDI32DLL,
"SetDeviceGammaRamp");
14805 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14806 hGDI32DLL,
"GetDeviceGammaRamp");
14809 if ((NULL == g_pSetDeviceGammaRamp) ||
14810 (NULL == g_pGetDeviceGammaRamp)) {
14811 FreeLibrary(hGDI32DLL);
14820 if (!g_pSavedGammaMap) {
14821 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14824 bbr = g_pGetDeviceGammaRamp(
14825 hDC, g_pSavedGammaMap);
14826 ReleaseDC(NULL, hDC);
14831 wxRegKey *pRegKey =
new wxRegKey(
14832 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14833 "NT\\CurrentVersion\\ICM");
14834 if (!pRegKey->Exists()) pRegKey->Create();
14835 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14837 g_brightness_init =
true;
14843 if (NULL == g_pcurtain) {
14844 if (gFrame->CanSetTransparent()) {
14846 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14847 wxPoint(0, 0), ::wxGetDisplaySize(),
14848 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14849 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14856 g_pcurtain->Hide();
14858 HWND hWnd = GetHwndOf(g_pcurtain);
14859 SetWindowLong(hWnd, GWL_EXSTYLE,
14860 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14861 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14862 g_pcurtain->SetTransparent(0);
14864 g_pcurtain->Maximize();
14865 g_pcurtain->Show();
14868 g_pcurtain->Enable();
14869 g_pcurtain->Disable();
14876 g_brightness_init =
true;
14882 wxString cmd(
"xcalib -version");
14884 wxArrayString output;
14885 long r = wxExecute(cmd, output);
14888 " External application \"xcalib\" not found. Screen brightness "
14891 g_brightness_init =
true;
14896int RestoreScreenBrightness() {
14899 if (g_pSavedGammaMap) {
14900 HDC hDC = GetDC(NULL);
14901 g_pSetDeviceGammaRamp(hDC,
14903 ReleaseDC(NULL, hDC);
14905 free(g_pSavedGammaMap);
14906 g_pSavedGammaMap = NULL;
14910 g_pcurtain->Close();
14911 g_pcurtain->Destroy();
14915 g_brightness_init =
false;
14920#ifdef BRIGHT_XCALIB
14921 if (g_brightness_init) {
14923 cmd =
"xcalib -clear";
14924 wxExecute(cmd, wxEXEC_ASYNC);
14925 g_brightness_init =
false;
14935int SetScreenBrightness(
int brightness) {
14942 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14944 g_pcurtain->Close();
14945 g_pcurtain->Destroy();
14949 InitScreenBrightness();
14951 if (NULL == hGDI32DLL) {
14953 wchar_t wdll_name[80];
14954 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14955 LPCWSTR cstr = wdll_name;
14957 hGDI32DLL = LoadLibrary(cstr);
14959 if (NULL != hGDI32DLL) {
14961 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14962 hGDI32DLL,
"SetDeviceGammaRamp");
14963 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14964 hGDI32DLL,
"GetDeviceGammaRamp");
14967 if ((NULL == g_pSetDeviceGammaRamp) ||
14968 (NULL == g_pGetDeviceGammaRamp)) {
14969 FreeLibrary(hGDI32DLL);
14976 HDC hDC = GetDC(NULL);
14987 int increment = brightness * 256 / 100;
14990 WORD GammaTable[3][256];
14993 for (
int i = 0; i < 256; i++) {
14994 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14995 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14996 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14998 table_val += increment;
15000 if (table_val > 65535) table_val = 65535;
15003 g_pSetDeviceGammaRamp(hDC, GammaTable);
15004 ReleaseDC(NULL, hDC);
15011 if (g_pSavedGammaMap) {
15012 HDC hDC = GetDC(NULL);
15013 g_pSetDeviceGammaRamp(hDC,
15015 ReleaseDC(NULL, hDC);
15018 if (brightness < 100) {
15019 if (NULL == g_pcurtain) InitScreenBrightness();
15022 int sbrite = wxMax(1, brightness);
15023 sbrite = wxMin(100, sbrite);
15025 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15029 g_pcurtain->Close();
15030 g_pcurtain->Destroy();
15040#ifdef BRIGHT_XCALIB
15042 if (!g_brightness_init) {
15043 last_brightness = 100;
15044 g_brightness_init =
true;
15045 temp_file_name = wxFileName::CreateTempFileName(
"");
15046 InitScreenBrightness();
15049#ifdef __OPCPN_USEICC__
15052 if (!CreateSimpleICCProfileFile(
15053 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15054 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15055 wxString cmd(
"xcalib ");
15056 cmd += temp_file_name;
15058 wxExecute(cmd, wxEXEC_ASYNC);
15067 if (brightness > last_brightness) {
15069 cmd =
"xcalib -clear";
15070 wxExecute(cmd, wxEXEC_ASYNC);
15072 ::wxMilliSleep(10);
15074 int brite_adj = wxMax(1, brightness);
15075 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15076 wxExecute(cmd, wxEXEC_ASYNC);
15078 int brite_adj = wxMax(1, brightness);
15079 int factor = (brite_adj * 100) / last_brightness;
15080 factor = wxMax(1, factor);
15082 cmd.Printf(
"xcalib -co %2d -a", factor);
15083 wxExecute(cmd, wxEXEC_ASYNC);
15088 last_brightness = brightness;
15095#ifdef __OPCPN_USEICC__
15097#define MLUT_TAG 0x6d4c5554L
15098#define VCGT_TAG 0x76636774L
15100int GetIntEndian(
unsigned char *s) {
15105 p = (
unsigned char *)&ret;
15108 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15110 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15115unsigned short GetShortEndian(
unsigned char *s) {
15116 unsigned short ret;
15120 p = (
unsigned char *)&ret;
15123 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15125 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15131int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15132 double co_green,
double co_blue) {
15136 fp = fopen(file_name,
"wb");
15137 if (!fp)
return -1;
15143 for (
int i = 0; i < 128; i++) header[i] = 0;
15145 fwrite(header, 128, 1, fp);
15149 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15150 fwrite(&numTags, 1, 4, fp);
15152 int tagName0 = VCGT_TAG;
15153 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15154 fwrite(&tagName, 1, 4, fp);
15156 int tagOffset0 = 128 + 4 *
sizeof(int);
15157 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15158 fwrite(&tagOffset, 1, 4, fp);
15161 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15162 fwrite(&tagSize, 1, 4, fp);
15164 fwrite(&tagName, 1, 4, fp);
15166 fwrite(&tagName, 1, 4, fp);
15171 int gammatype0 = 0;
15172 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15173 fwrite(&gammatype, 1, 4, fp);
15175 int numChannels0 = 3;
15176 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15177 fwrite(&numChannels, 1, 2, fp);
15179 int numEntries0 = 256;
15180 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15181 fwrite(&numEntries, 1, 2, fp);
15183 int entrySize0 = 1;
15184 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15185 fwrite(&entrySize, 1, 2, fp);
15187 unsigned char ramp[256];
15190 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15191 fwrite(ramp, 256, 1, fp);
15194 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15195 fwrite(ramp, 256, 1, fp);
15198 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15199 fwrite(ramp, 256, 1, fp);
Select * pSelectAIS
Global instance.
AisDecoder * g_pAIS
Global instance.
Class AisDecoder and helpers.
Global state for AIS decoder.
Class AISTargetAlertDialog and helpers.
Class AISTargetQueryDialog.
Chart canvas configuration state
Class CanvasOptions and helpers – Canvas options Window/Dialog.
ChartDB * ChartData
Global instance.
Charts database management
ChartGroupArray * g_pGroupArray
Global instance.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Generic Chart canvas base.
ChartCanvas * g_focusCanvas
Global instance.
ChartCanvas * g_overlayCanvas
Global instance.
Dialog for displaying a list of AIS targets.
Dialog for querying detailed information about an AIS target.
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &caption=_("Object Query"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=AIS_TARGET_QUERY_STYLE)
Creation.
Handles context menu events for the chart canvas.
A custom panel for displaying chart information.
Base class for BSB (Maptech/NOS) format nautical charts.
Base class for all chart types.
ChartCanvas - Main chart display and interaction component.
void CloseTideDialog()
Close any open tide dialog.
bool GetCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates rounded to nearest integer using specified vie...
bool GetCanvasPointPix(double rlat, double rlon, wxPoint *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) rounded to nearest integer.
void DoMovement(long dt)
Performs a step of smooth movement animation on the chart canvas.
void ShowSingleTideDialog(int x, int y, void *pvIDX)
Display tide/current dialog with single-instance management.
void GetDoubleCanvasPointPixVP(ViewPort &vp, double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision,...
double m_cursor_lat
The latitude in degrees corresponding to the most recently processed cursor position.
double GetCanvasScaleFactor()
Return the number of logical pixels per meter for the screen.
double GetPixPerMM()
Get the number of logical pixels per millimeter on the screen.
void SetDisplaySizeMM(double size)
Set the width of the screen in millimeters.
int PrepareContextSelections(double lat, double lon)
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool PanCanvas(double dx, double dy)
Pans (moves) the canvas by the specified physical pixels in x and y directions.
float GetVPScale()
Return the ViewPort scale factor, in physical pixels per meter.
EventVar json_msg
Notified with message targeting all plugins.
void ZoomCanvasSimple(double factor)
Perform an immediate zoom operation without smooth transitions.
bool SetVPScale(double sc, bool b_refresh=true)
Sets the viewport scale while maintaining the center point.
double m_cursor_lon
The longitude in degrees corresponding to the most recently processed cursor position.
void GetCanvasPixPoint(double x, double y, double &lat, double &lon)
Convert canvas pixel coordinates (physical pixels) to latitude/longitude.
bool IsTideDialogOpen() const
void ZoomCanvas(double factor, bool can_zoom_to_cursor=true, bool stoptimer=true)
Perform a smooth zoom operation on the chart canvas by the specified factor.
void DrawTCWindow(int x, int y, void *pIDX)
Legacy tide dialog creation method.
void GetDoubleCanvasPointPix(double rlat, double rlon, wxPoint2DDouble *r)
Convert latitude/longitude to canvas pixel coordinates (physical pixels) with double precision.
bool SetViewPoint(double lat, double lon)
Centers the view on a specific lat/lon position.
bool MouseEventProcessCanvas(wxMouseEvent &event)
Processes mouse events for core chart panning and zooming operations.
Represents a user-defined collection of logically related charts.
Represents an MBTiles format chart.
Wrapper class for plugin-based charts.
void Notify() override
Notify all listeners, no data supplied.
wxFont * FindOrCreateFont(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline=false, const wxString &facename=wxEmptyString, wxFontEncoding encoding=wxFONTENCODING_DEFAULT)
Creates or finds a matching font in the font cache.
wxColour GetFontColor(const wxString &TextElement) const
Gets the text color for a UI element.
wxFont * GetFont(const wxString &TextElement, int requested_font_size=0)
Get a font object for a UI element.
Modal dialog displaying hotkeys.
Represents an index entry for tidal and current data.
char IDX_type
Entry type identifier "TCtcIUu".
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
bool b_skipTooDeep
Flag to skip processing if depth exceeds limit.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_rec_num
Record number for multiple entries with same name.
Modern User Interface Control Bar for OpenCPN.
Dialog for displaying and editing waypoint properties.
An iterator class for OCPNRegion.
A wrapper class for wxRegion with additional functionality.
PluginLoader is a backend module without any direct GUI functionality.
bool Compose(const ViewPort &vp)
Represents a waypoint or mark within the navigation system.
wxString m_MarkDescription
Description text for the waypoint.
LLBBox m_wpBBox
Bounding box for the waypoint.
bool m_bRPIsBeingEdited
Flag indicating if this waypoint is currently being edited.
wxRect CurrentRect_in_DC
Current rectangle occupied by the waypoint in the display.
wxString m_GUID
Globally Unique Identifier for the waypoint.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
bool m_bIsActive
Flag indicating if this waypoint is active for navigation.
bool m_bIsInRoute
Flag indicating if this waypoint is part of a route.
double m_seg_len
Length of the leg from previous waypoint to this waypoint in nautical miles.
bool m_bShowName
Flag indicating if the waypoint name should be shown.
bool m_bBlink
Flag indicating if the waypoint should blink when displayed.
bool m_bPtIsSelected
Flag indicating if this waypoint is currently selected.
bool m_bIsVisible
Flag indicating if the waypoint should be drawn on the chart.
bool m_bIsInLayer
Flag indicating if the waypoint belongs to a layer.
int m_LayerID
Layer identifier if the waypoint belongs to a layer.
Represents a navigational route in the navigation system.
bool m_bRtIsSelected
Flag indicating whether this route is currently selected in the UI.
RoutePointList * pRoutePointList
Ordered list of waypoints (RoutePoints) that make up this route.
double m_route_length
Total length of the route in nautical miles, calculated using rhumb line (Mercator) distances.
bool m_bRtIsActive
Flag indicating whether this route is currently active for navigation.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
bool m_bIsInLayer
Flag indicating whether this route belongs to a layer.
int m_lastMousePointIndex
Index of the most recently interacted with route point.
bool m_bIsBeingEdited
Flag indicating that the route is currently being edited by the user.
bool m_NextLegGreatCircle
Flag indicating whether the next leg should be calculated using great circle navigation or rhumb line...
wxArrayPtrVoid * GetRouteArrayContaining(RoutePoint *pWP)
Find all routes that contain the given waypoint.
bool ActivateNextPoint(Route *pr, bool skipped)
Activates the next waypoint in a route when the current waypoint is reached.
bool DeleteRoute(Route *pRoute)
Dialog for displaying query results of S57 objects.
IDX_entry * GetCurrentIDX() const
Represents a single point in a track.
wxDateTime GetCreateTime(void)
Retrieves the creation timestamp of a track point as a wxDateTime object.
void SetCreateTime(wxDateTime dt)
Sets the creation timestamp for a track point.
Represents a track, which is a series of connected track points.
ViewPort - Core geographic projection and coordinate transformation engine.
void SetBoxes()
Computes the bounding box coordinates for the current viewport.
double view_scale_ppm
Requested view scale in physical pixels per meter (ppm), before applying projections.
double ref_scale
The nominal scale of the "reference chart" for this view.
int pix_height
Height of the viewport in physical pixels.
double rotation
Rotation angle of the viewport in radians.
void SetPixelScale(double scale)
Set the physical to logical pixel ratio for the display.
int pix_width
Width of the viewport in physical pixels.
wxPoint2DDouble GetDoublePixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates with double precision.
double tilt
Tilt angle for perspective view in radians.
double skew
Angular distortion (shear transform) applied to the viewport in radians.
void GetLLFromPix(const wxPoint &p, double *lat, double *lon)
Convert physical pixel coordinates on the ViewPort to latitude and longitude.
double clon
Center longitude of the viewport in degrees.
double clat
Center latitude of the viewport in degrees.
wxPoint GetPixFromLL(double lat, double lon)
Convert latitude and longitude on the ViewPort to physical pixel coordinates.
double chart_scale
Chart scale denominator (e.g., 50000 for a 1:50000 scale).
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Encapsulates persistent canvas configuration.
double iLat
Latitude of the center of the chart, in degrees.
bool bShowOutlines
Display chart outlines.
bool bShowDepthUnits
Display depth unit indicators.
double iLon
Longitude of the center of the chart, in degrees.
double iRotation
Initial rotation angle in radians.
bool bCourseUp
Orient display to course up.
bool bQuilt
Enable chart quilting.
bool bFollow
Enable vessel following mode.
double iScale
Initial chart scale factor.
bool bShowENCText
Display ENC text elements.
bool bShowAIS
Display AIS targets.
bool bShowGrid
Display coordinate grid.
bool bShowCurrents
Display current information.
bool bShowTides
Display tide information.
bool bLookahead
Enable lookahead mode.
bool bHeadUp
Orient display to heading up.
bool bAttenAIS
Enable AIS target attenuation.
Represents a composite CM93 chart covering multiple scales.
Stores emboss effect data for textures.
OpenGL chart rendering canvas.
Represents a compass display in the OpenCPN navigation system.
wxRect GetRect(void) const
Return the coordinates of the compass widget, in physical pixels relative to the canvas window.
wxRect GetLogicalRect(void) const
Return the coordinates of the compass widget, in logical pixels.
Device context class that can use either wxDC or OpenGL for drawing.
void DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, bool b_hiqual=true)
Draw a line between two points using either wxDC or OpenGL.
Represents an S57 format electronic navigational chart in OpenCPN.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Class cm93chart and helpers – CM93 chart state.
Global variables reflecting command line options and arguments.
APConsole * console
Global instance.
Primary navigation console display for route and vessel tracking.
bool g_bsmoothpanzoom
Controls how the chart panning and zooming smoothing is done during user interactions.
bool g_bRollover
enable/disable mouse rollover GUI effects
double g_COGAvg
Debug only usage.
int g_COGAvgSec
COG average period for Course Up Mode (sec)
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
double g_display_size_mm
Physical display width (mm)
PopUpDSlide * pPopupDetailSlider
Global instance.
Chart display details slider.
std::vector< OCPN_MonitorInfo > g_monitor_info
Information about the monitors connected to the system.
OpenGL chart rendering canvas.
glTextureManager * g_glTextureManager
Global instance.
OpenGL texture container.
GoToPositionDialog * pGoToPositionDialog
Global instance.
GSHHS Chart Object (Global Self-consistent, Hierarchical, High-resolution Shoreline) Derived from htt...
Hooks into gui available in model.
size_t g_current_monitor
Current monitor displaying main application frame.
double g_current_monitor_dip_px_ratio
ratio to convert between DIP and physical pixels.
bool g_b_overzoom_x
Allow high overzoom.
Miscellaneous globals primarely used by gui layer, not persisted in configuration file.
Hotheys help dialog (the '?' button).
GUI constant definitions.
Read and write KML Format.
MarkInfoDlg * g_pMarkInfoDialog
global instance
Waypoint properties maintenance dialog.
MUI (Modern User Interface) Control bar.
Multiplexer class and helpers.
MySQL based storage for routes, tracks, etc.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
User notifications manager.
Notification Manager GUI.
OCPN_AUIManager * g_pauimgr
Global instance.
Optimized wxBitmap Object.
#define OVERLAY_LEGACY
Overlay rendering priorities determine the layering order of plugin graphics.
#define OVERLAY_OVER_UI
Highest priority for overlays above all UI elements.
#define OVERLAY_OVER_EMBOSS
Priority for overlays above embossed chart features.
#define OVERLAY_OVER_SHIPS
Priority for overlays that should appear above ship symbols.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
int GetChartbarHeight()
Gets height of chart bar in pixels.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Layer to use wxDC or opengl.
options * g_options
Global instance.
bool bGPSValid
Indicate whether the Global Navigation Satellite System (GNSS) has a valid position.
double gHdt
True heading in degrees (0-359.99).
double gLat
Vessel's current latitude in decimal degrees.
double gCog
Course over ground in degrees (0-359.99).
double gSog
Speed over ground in knots.
double gLon
Vessel's current longitude in decimal degrees.
Position, course, speed, etc.
Tools to send data to plugins.
PlugInManager * g_pi_manager
Global instance.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Purpose: Track and Trackpoint drawing stuff.
RoutePropDlgImpl * pRoutePropDialog
Global instance.
RoutePoint * pAnchorWatchPoint2
Global instance.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
RoutePoint * pAnchorWatchPoint1
Global instance.
float g_ChartScaleFactorExp
Global instance.
S57QueryDialog * g_pObjectQueryDialog
Global instance.
S57 object query result window.
Select * pSelect
Global instance.
Select * pSelectTC
Global instance.
Selected route, segment, waypoint, etc.
A single, selected generic item.
SENCThreadManager * g_SencThreadManager
Global instance.
ShapeBaseChartSet gShapeBasemap
global instance
Represents an entry in the chart table, containing information about a single chart.
Tide and currents window.
TCMgr * ptcmgr
Global instance.
Tide and Current Manager @TODO Add original author copyright.
ThumbWin * pthumbwin
Global instance.
Timer identification constants.
ActiveTrack * g_pActiveTrack
global instance
std::vector< Track * > g_TrackList
Global instance.
Recorded track abstraction.
Track and Trackpoint drawing stuff.
TrackPropDlg * pTrackPropDialog
Global instance.
Framework for Undo features.