33#include <wx/graphics.h>
34#include <wx/clipbrd.h>
35#include <wx/aui/aui.h>
41#include "model/ais_target_data.h"
43#include "model/conn_params.h"
44#include "model/geodesic.h"
47#include "model/idents.h"
50#include "model/nav_object_database.h"
52#include "model/navutil_base.h"
53#include "model/own_ship.h"
55#include "model/route.h"
56#include "model/routeman.h"
57#include "model/select.h"
58#include "model/select_item.h"
59#include "model/track.h"
75#include "hotkeys_dlg.h"
77#include "glTextureDescriptor.h"
78#include "GoToPositionDialog.h"
80#include "iENCToolbar.h"
87#include "OCPN_AUIManager.h"
89#include "ocpn_frame.h"
90#include "ocpn_pixel.h"
91#include "OCPNRegion.h"
97#include "routemanagerdialog.h"
98#include "route_point_gui.h"
99#include "RoutePropDlgImpl.h"
102#include "S57QueryDialog.h"
104#include "shapefile_basemap.h"
106#include "SystemCmdSound.h"
110#include "tide_time.h"
113#include "track_gui.h"
114#include "TrackPropDlg.h"
117#include "s57_ocpn_utils.h"
120#include "androidUTIL.h"
124#include "glChartCanvas.h"
125#include "notification_manager_gui.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)
245 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
246 m_nmea_log(nmea_log) {
247 parent_frame = (
MyFrame *)frame;
248 m_canvasIndex = canvasIndex;
252 SetBackgroundColour(wxColour(0, 0, 0));
253 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
257 m_bDrawingRoute =
false;
258 m_bRouteEditing =
false;
259 m_bMarkEditing =
false;
260 m_bRoutePoinDragging =
false;
261 m_bIsInRadius =
false;
262 m_bMayToggleMenuBar =
true;
265 m_bShowNavobjects =
true;
267 m_bAppendingRoute =
false;
268 pThumbDIBShow = NULL;
269 m_bShowCurrent =
false;
271 bShowingCurrent =
false;
275 m_b_paint_enable =
true;
278 pss_overlay_bmp = NULL;
279 pss_overlay_mask = NULL;
280 m_bChartDragging =
false;
281 m_bMeasure_Active =
false;
282 m_bMeasure_DistCircle =
false;
283 m_pMeasureRoute = NULL;
284 m_pTrackRolloverWin = NULL;
285 m_pRouteRolloverWin = NULL;
286 m_pAISRolloverWin = NULL;
288 m_disable_edge_pan =
false;
289 m_dragoffsetSet =
false;
293 m_singleChart = NULL;
294 m_upMode = NORTH_UP_MODE;
296 m_bShowAISScaled =
false;
297 m_timed_move_vp_active =
false;
304 m_pSelectedRoute = NULL;
305 m_pSelectedTrack = NULL;
306 m_pRoutePointEditTarget = NULL;
307 m_pFoundPoint = NULL;
308 m_pMouseRoute = NULL;
309 m_prev_pMousePoint = NULL;
310 m_pEditRouteArray = NULL;
311 m_pFoundRoutePoint = NULL;
312 m_FinishRouteOnKillFocus =
true;
314 m_pRolloverRouteSeg = NULL;
315 m_pRolloverTrackSeg = NULL;
316 m_bsectors_shown =
false;
318 m_bbrightdir =
false;
323 m_pos_image_user_day = NULL;
324 m_pos_image_user_dusk = NULL;
325 m_pos_image_user_night = NULL;
326 m_pos_image_user_grey_day = NULL;
327 m_pos_image_user_grey_dusk = NULL;
328 m_pos_image_user_grey_night = NULL;
331 m_rotation_speed = 0;
337 m_pos_image_user_yellow_day = NULL;
338 m_pos_image_user_yellow_dusk = NULL;
339 m_pos_image_user_yellow_night = NULL;
341 SetOwnShipState(SHIP_INVALID);
343 undo =
new Undo(
this);
349 m_focus_indicator_pix = 1;
351 m_pCurrentStack = NULL;
352 m_bpersistent_quilt =
false;
353 m_piano_ctx_menu = NULL;
355 m_NotificationsList = NULL;
356 m_notification_button = NULL;
358 g_ChartNotRenderScaleFactor = 2.0;
359 m_bShowScaleInStatusBar =
true;
362 m_bShowScaleInStatusBar =
false;
363 m_show_focus_bar =
true;
365 m_bShowOutlines =
false;
366 m_bDisplayGrid =
false;
367 m_bShowDepthUnits =
true;
368 m_encDisplayCategory = (int)STANDARD;
370 m_encShowLights =
true;
371 m_encShowAnchor =
true;
372 m_encShowDataQual =
false;
374 m_pQuilt =
new Quilt(
this);
379 g_PrintingInProgress =
false;
381#ifdef HAVE_WX_GESTURE_EVENTS
382 m_oldVPSScale = -1.0;
383 m_popupWanted =
false;
389 singleClickEventIsValid =
false;
398 pCursorPencil = NULL;
403 SetCursor(*pCursorArrow);
405 pPanTimer =
new wxTimer(
this, m_MouseDragging);
408 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
409 pMovementTimer->Stop();
411 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
412 pMovementStopTimer->Stop();
414 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
415 pRotDefTimer->Stop();
417 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
418 m_DoubleClickTimer->Stop();
420 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
421 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
422 m_chart_drag_inertia_active =
false;
424 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
425 m_animationActive =
false;
429 m_panx_target_final = m_pany_target_final = 0;
430 m_panx_target_now = m_pany_target_now = 0;
432 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
433 pCurTrackTimer->Stop();
434 m_curtrack_timer_msec = 10;
436 m_wheelzoom_stop_oneshot = 0;
437 m_last_wheel_dir = 0;
439 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
441 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
443 m_rollover_popup_timer_msec = 20;
445 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
447 m_b_rot_hidef =
true;
452 m_upMode = NORTH_UP_MODE;
453 m_bLookAhead =
false;
457 m_cs = GLOBAL_COLOR_SCHEME_DAY;
460 VPoint.view_scale_ppm = 1;
464 m_canvas_scale_factor = 1.;
466 m_canvas_width = 1000;
468 m_overzoomTextWidth = 0;
469 m_overzoomTextHeight = 0;
473 gShapeBasemap.Reset();
478 m_pEM_Fathoms = NULL;
480 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
482 m_pEM_OverZoom = NULL;
484 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
492 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
495 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
498 double factor_dusk = 0.5;
499 double factor_night = 0.25;
502 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
504 int rimg_width = m_os_image_red_day.GetWidth();
505 int rimg_height = m_os_image_red_day.GetHeight();
507 m_os_image_red_dusk = m_os_image_red_day.Copy();
508 m_os_image_red_night = m_os_image_red_day.Copy();
510 for (
int iy = 0; iy < rimg_height; iy++) {
511 for (
int ix = 0; ix < rimg_width; ix++) {
512 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
513 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
514 m_os_image_red_day.GetGreen(ix, iy),
515 m_os_image_red_day.GetBlue(ix, iy));
516 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
517 hsv.value = hsv.value * factor_dusk;
518 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
519 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
521 hsv = wxImage::RGBtoHSV(rgb);
522 hsv.value = hsv.value * factor_night;
523 nrgb = wxImage::HSVtoRGB(hsv);
524 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
530 m_os_image_grey_day =
531 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
533 int gimg_width = m_os_image_grey_day.GetWidth();
534 int gimg_height = m_os_image_grey_day.GetHeight();
536 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
537 m_os_image_grey_night = m_os_image_grey_day.Copy();
539 for (
int iy = 0; iy < gimg_height; iy++) {
540 for (
int ix = 0; ix < gimg_width; ix++) {
541 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
542 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
543 m_os_image_grey_day.GetGreen(ix, iy),
544 m_os_image_grey_day.GetBlue(ix, iy));
545 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
546 hsv.value = hsv.value * factor_dusk;
547 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
548 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
550 hsv = wxImage::RGBtoHSV(rgb);
551 hsv.value = hsv.value * factor_night;
552 nrgb = wxImage::HSVtoRGB(hsv);
553 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
559 m_os_image_yellow_day = m_os_image_red_day.Copy();
561 gimg_width = m_os_image_yellow_day.GetWidth();
562 gimg_height = m_os_image_yellow_day.GetHeight();
564 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
565 m_os_image_yellow_night = m_os_image_red_day.Copy();
567 for (
int iy = 0; iy < gimg_height; iy++) {
568 for (
int ix = 0; ix < gimg_width; ix++) {
569 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
570 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
571 m_os_image_yellow_day.GetGreen(ix, iy),
572 m_os_image_yellow_day.GetBlue(ix, iy));
573 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
574 hsv.hue += 60. / 360.;
575 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
576 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
578 hsv = wxImage::RGBtoHSV(rgb);
579 hsv.value = hsv.value * factor_dusk;
580 hsv.hue += 60. / 360.;
581 nrgb = wxImage::HSVtoRGB(hsv);
582 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
584 hsv = wxImage::RGBtoHSV(rgb);
585 hsv.hue += 60. / 360.;
586 hsv.value = hsv.value * factor_night;
587 nrgb = wxImage::HSVtoRGB(hsv);
588 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
594 m_pos_image_red = &m_os_image_red_day;
595 m_pos_image_yellow = &m_os_image_yellow_day;
596 m_pos_image_grey = &m_os_image_grey_day;
600 m_pBrightPopup = NULL;
603 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
608 m_Piano =
new Piano(
this);
610 m_bShowCompassWin =
true;
612 m_Compass->SetScaleFactor(g_compass_scalefactor);
613 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
616 m_notification_button->SetScaleFactor(g_compass_scalefactor);
617 m_notification_button->Show(
true);
619 m_pianoFrozen =
false;
621 SetMinSize(wxSize(200, 200));
623 m_displayScale = 1.0;
624#if defined(__WXOSX__) || defined(__WXGTK3__)
626 m_displayScale = GetContentScaleFactor();
628 VPoint.SetPixelScale(m_displayScale);
630#ifdef HAVE_WX_GESTURE_EVENTS
633 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
634 wxLogError(
"Failed to enable touch events");
639 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
640 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
642 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
643 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
645 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
646 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
648 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
649 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
654 auto ¬eman = NotificationManager::GetInstance();
656 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
657 evt_notificationlist_change_listener.Listen(
658 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
659 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
660 if (m_NotificationsList && m_NotificationsList->IsShown()) {
661 m_NotificationsList->ReloadNotificationList();
667ChartCanvas::~ChartCanvas() {
668 delete pThumbDIBShow;
676 delete pCursorPencil;
680 delete pMovementTimer;
681 delete pMovementStopTimer;
682 delete pCurTrackTimer;
684 delete m_DoubleClickTimer;
686 delete m_pTrackRolloverWin;
687 delete m_pRouteRolloverWin;
688 delete m_pAISRolloverWin;
689 delete m_pBrightPopup;
695 m_dc_route.SelectObject(wxNullBitmap);
698 delete pWorldBackgroundChart;
699 delete pss_overlay_bmp;
703 delete m_pEM_Fathoms;
705 delete m_pEM_OverZoom;
710 delete m_pos_image_user_day;
711 delete m_pos_image_user_dusk;
712 delete m_pos_image_user_night;
713 delete m_pos_image_user_grey_day;
714 delete m_pos_image_user_grey_dusk;
715 delete m_pos_image_user_grey_night;
716 delete m_pos_image_user_yellow_day;
717 delete m_pos_image_user_yellow_dusk;
718 delete m_pos_image_user_yellow_night;
722 if (!g_bdisable_opengl) {
725#if wxCHECK_VERSION(2, 9, 0)
726 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
733 MUIBar *muiBar = m_muiBar;
737 delete m_pCurrentStack;
742void ChartCanvas::SetupGridFont() {
743 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
745 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
747 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
748 FALSE, wxString(
"Arial"));
751void ChartCanvas::RebuildCursors() {
757 delete pCursorPencil;
761 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
765 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
766 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
767 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
768 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
769 wxImage ICursorPencil =
770 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
771 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
773#if !defined(__WXMSW__) && !defined(__WXQT__)
774 ICursorLeft.ConvertAlphaToMask(128);
775 ICursorRight.ConvertAlphaToMask(128);
776 ICursorUp.ConvertAlphaToMask(128);
777 ICursorDown.ConvertAlphaToMask(128);
778 ICursorPencil.ConvertAlphaToMask(10);
779 ICursorCross.ConvertAlphaToMask(10);
782 if (ICursorLeft.Ok()) {
783 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
784 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
785 pCursorLeft =
new wxCursor(ICursorLeft);
787 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
789 if (ICursorRight.Ok()) {
790 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
791 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
792 pCursorRight =
new wxCursor(ICursorRight);
794 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
796 if (ICursorUp.Ok()) {
797 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
798 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
799 pCursorUp =
new wxCursor(ICursorUp);
801 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
803 if (ICursorDown.Ok()) {
804 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
805 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
806 pCursorDown =
new wxCursor(ICursorDown);
808 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
810 if (ICursorPencil.Ok()) {
811 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
812 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
813 pCursorPencil =
new wxCursor(ICursorPencil);
815 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
817 if (ICursorCross.Ok()) {
818 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
819 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
820 pCursorCross =
new wxCursor(ICursorCross);
822 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
824 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
825 pPlugIn_Cursor = NULL;
828void ChartCanvas::CanvasApplyLocale() {
829 CreateDepthUnitEmbossMaps(m_cs);
830 CreateOZEmbossMapData(m_cs);
833void ChartCanvas::SetupGlCanvas() {
836 if (!g_bdisable_opengl) {
838 wxLogMessage(
"Creating glChartCanvas");
843 if (IsPrimaryCanvas()) {
850 wxGLContext *pctx =
new wxGLContext(m_glcc);
851 m_glcc->SetContext(pctx);
855 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
857 m_glcc->SetContext(g_pGLcontext);
867 if (!g_bdisable_opengl) {
870 wxLogMessage(
"Creating glChartCanvas");
874 if (IsPrimaryCanvas()) {
875 qDebug() <<
"Creating Primary glChartCanvas";
883 wxGLContext *pctx =
new wxGLContext(m_glcc);
884 m_glcc->SetContext(pctx);
886 m_glcc->m_pParentCanvas =
this;
889 qDebug() <<
"Creating Secondary glChartCanvas";
895 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
898 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
899 m_glcc->SetContext(pwxctx);
900 m_glcc->m_pParentCanvas =
this;
908void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
909 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
924 if (m_routeState && m_FinishRouteOnKillFocus)
925 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
927 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
931void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
932 m_routeFinishTimer.Stop();
936 gFrame->UpdateGlobalMenuItems(
this);
938 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
941void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
942 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
945#ifdef HAVE_WX_GESTURE_EVENTS
946void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
952 m_popupWanted =
true;
955void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
959void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
961void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
963void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
964 wxPoint pos =
event.GetPosition();
968 if (!m_popupWanted) {
969 wxMouseEvent ev(wxEVT_LEFT_UP);
976 m_popupWanted =
false;
978 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
985void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
988 wxPoint pos =
event.GetPosition();
992void ChartCanvas::OnMotion(wxMouseEvent &event) {
997 event.m_leftDown = m_leftdown;
1001void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1003 if (event.IsGestureEnd())
return;
1005 double factor =
event.GetZoomFactor();
1007 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1012 double wanted_factor = m_oldVPSScale / current_vps * factor;
1017 if (event.IsGestureStart()) {
1018 m_zoomStartPoint =
event.GetPosition();
1020 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1022 m_zoomStartPoint =
event.GetPosition();
1026void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1028void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1029 DoRotateCanvas(0.0);
1033void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1038 m_restore_dbindex = pcc->DBindex;
1040 if (pcc->GroupID < 0) pcc->GroupID = 0;
1045 m_groupIndex = pcc->GroupID;
1047 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1061 m_encDisplayCategory = pcc->nENCDisplayCategory;
1062 m_encShowDepth = pcc->bShowENCDepths;
1063 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1064 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1065 m_encShowLights = pcc->bShowENCLights;
1066 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1067 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1068 m_encShowDataQual = pcc->bShowENCDataQuality;
1072 m_upMode = NORTH_UP_MODE;
1074 m_upMode = COURSE_UP_MODE;
1076 m_upMode = HEAD_UP_MODE;
1080 m_singleChart = NULL;
1083void ChartCanvas::ApplyGlobalSettings() {
1086 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1087 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1089 m_notification_button->UpdateStatus();
1092void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1093 bool groupOK = CheckGroup(m_groupIndex);
1096 SetGroupIndex(m_groupIndex,
true);
1100void ChartCanvas::SetShowGPS(
bool bshow) {
1101 if (m_bShowGPS != bshow) {
1104 m_Compass->SetScaleFactor(g_compass_scalefactor);
1105 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1110void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1111 m_bShowCompassWin = bshow;
1113 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1114 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1118int ChartCanvas::GetPianoHeight() {
1120 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1125void ChartCanvas::ConfigureChartBar() {
1128 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1129 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1131 if (GetQuiltMode()) {
1132 m_Piano->SetRoundedRectangles(
true);
1134 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1135 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1136 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1139void ChartCanvas::ShowTides(
bool bShow) {
1140 gFrame->LoadHarmonics();
1142 if (ptcmgr->IsReady()) {
1143 SetbShowTide(bShow);
1145 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1147 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1148 SetbShowTide(
false);
1149 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1152 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1153 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1164void ChartCanvas::ShowCurrents(
bool bShow) {
1165 gFrame->LoadHarmonics();
1167 if (ptcmgr->IsReady()) {
1168 SetbShowCurrent(bShow);
1169 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1171 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1172 SetbShowCurrent(
false);
1173 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1176 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1177 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1194void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1196void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1199 int new_index = index;
1202 bool bgroup_override =
false;
1203 int old_group_index = new_index;
1205 if (!CheckGroup(new_index)) {
1207 bgroup_override =
true;
1210 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1214 int current_chart_native_scale = GetCanvasChartNativeScale();
1217 m_groupIndex = new_index;
1223 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1227 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1231 g_sticky_chart = -1;
1235 UpdateCanvasOnGroupChange();
1238 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1240 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1243 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1244 double best_scale = GetBestStartScale(dbi_hint, vp);
1248 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1252 canvasChartsRefresh(dbi_hint);
1254 UpdateCanvasControlBar();
1256 if (!autoSwitch && bgroup_override) {
1258 wxString msg(_(
"Group \""));
1261 msg += pGroup->m_group_name;
1263 msg += _(
"\" is empty.");
1265 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1272 if (bgroup_override) {
1273 wxString msg(_(
"Group \""));
1276 msg += pGroup->m_group_name;
1278 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1280 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1284bool ChartCanvas::CheckGroup(
int igroup) {
1287 if (igroup == 0)
return true;
1294 if (pGroup->m_element_array.empty())
1298 for (
const auto &elem : pGroup->m_element_array) {
1299 for (
unsigned int ic = 0;
1300 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1302 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1304 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1309 for (
const auto &elem : pGroup->m_element_array) {
1310 const wxString &element_root = elem.m_element_name;
1311 wxString test_string =
"GSHH";
1312 if (element_root.Upper().Contains(test_string))
return true;
1318void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1321 AbstractPlatform::ShowBusySpinner();
1325 SetQuiltRefChart(-1);
1327 m_singleChart = NULL;
1333 if (!m_pCurrentStack) {
1335 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1338 if (-1 != dbi_hint) {
1339 if (GetQuiltMode()) {
1340 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1341 SetQuiltRefChart(dbi_hint);
1345 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1347 if (pTentative_Chart) {
1350 if (m_singleChart) m_singleChart->Deactivate();
1352 m_singleChart = pTentative_Chart;
1353 m_singleChart->Activate();
1355 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1356 GetpCurrentStack(), m_singleChart->GetFullPath());
1364 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1365 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1366 SetQuiltRefChart(selected_index);
1370 SetupCanvasQuiltMode();
1371 if (!GetQuiltMode() && m_singleChart == 0) {
1373 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1374 m_singleChart = pDummyChart;
1380 UpdateCanvasControlBar();
1381 UpdateGPSCompassStatusBox(
true);
1383 SetCursor(wxCURSOR_ARROW);
1385 AbstractPlatform::HideBusySpinner();
1388bool ChartCanvas::DoCanvasUpdate(
void) {
1390 double vpLat, vpLon;
1391 bool blong_jump =
false;
1392 meters_to_shift = 0;
1395 bool bNewChart =
false;
1396 bool bNewView =
false;
1397 bool bCanvasChartAutoOpen =
true;
1399 bool bNewPiano =
false;
1400 bool bOpenSpecified;
1406 if (bDBUpdateInProgress)
return false;
1410 if (m_chart_drag_inertia_active)
return false;
1436 double dx = m_OSoffsetx;
1437 double dy = m_OSoffsety;
1441 if (GetUpMode() == NORTH_UP_MODE) {
1442 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1444 double offset_angle = atan2(d_north, d_east);
1445 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1446 double chart_angle = GetVPRotation();
1447 double target_angle = chart_angle + offset_angle;
1448 double d_east_mod = offset_distance * cos(target_angle);
1449 double d_north_mod = offset_distance * sin(target_angle);
1450 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1454 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1455 double cog_to_use = gCog;
1457 (fabs(gCog - gCog_gt) > 20)) {
1458 cog_to_use = gCog_gt;
1461 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1463 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1465 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1466 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1468 double pixel_delta_tent =
1469 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1471 double pixel_delta = 0;
1476 if (!std::isnan(gSog)) {
1480 pixel_delta = pixel_delta_tent;
1483 meters_to_shift = 0;
1485 if (!std::isnan(gCog)) {
1486 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1487 dir_to_shift = cog_to_use;
1488 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1494 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1508 if (GetQuiltMode()) {
1509 int current_db_index = -1;
1510 if (m_pCurrentStack)
1513 ->GetCurrentEntrydbIndex();
1521 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1523 if (m_pCurrentStack->nEntry) {
1524 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1526 SelectQuiltRefdbChart(new_dbIndex,
true);
1527 m_bautofind =
false;
1531 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1532 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1537 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1543 double proposed_scale_onscreen =
1546 int initial_db_index = m_restore_dbindex;
1547 if (initial_db_index < 0) {
1548 if (m_pCurrentStack->nEntry) {
1550 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1555 if (m_pCurrentStack->nEntry) {
1556 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1561 if (!IsChartQuiltableRef(initial_db_index)) {
1565 int stack_index = 0;
1567 if (stack_index >= 0) {
1568 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1569 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1570 if (IsChartQuiltableRef(test_db_index) &&
1572 ChartData->GetDBChartType(initial_db_index))) {
1573 initial_db_index = test_db_index;
1583 SetQuiltRefChart(initial_db_index);
1584 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1592 0, GetVPRotation());
1597 bool super_jump =
false;
1599 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1600 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1601 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1604 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1606 if (blong_jump) nstep = 20;
1607 StartTimedMovementVP(vpLat, vpLon, nstep);
1618 pLast_Ch = m_singleChart;
1619 ChartTypeEnum new_open_type;
1620 ChartFamilyEnum new_open_family;
1622 new_open_type = pLast_Ch->GetChartType();
1623 new_open_family = pLast_Ch->GetChartFamily();
1625 new_open_type = CHART_TYPE_KAP;
1626 new_open_family = CHART_FAMILY_RASTER;
1629 bOpenSpecified = m_bFirstAuto;
1632 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1635 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1637 if (NULL == pDummyChart) {
1643 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1645 m_singleChart = pDummyChart;
1650 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1652 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1655 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1656 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1663 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1669 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1674 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1677 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1682 if (NULL != m_singleChart)
1683 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1684 m_singleChart->GetFullPath());
1687 m_pCurrentStack->CurrentStackEntry = tEntry;
1697 if (bCanvasChartAutoOpen) {
1698 bool search_direction =
1700 int start_index = 0;
1704 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1705 (LastStack.nEntry == 0)) {
1706 search_direction =
true;
1707 start_index = m_pCurrentStack->nEntry - 1;
1711 if (bOpenSpecified) {
1712 search_direction =
false;
1714 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1717 new_open_type = CHART_TYPE_DONTCARE;
1720 pProposed =
ChartData->OpenStackChartConditional(
1721 m_pCurrentStack, start_index, search_direction, new_open_type,
1725 if (NULL == pProposed)
1726 pProposed =
ChartData->OpenStackChartConditional(
1727 m_pCurrentStack, start_index, search_direction,
1728 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1730 if (NULL == pProposed)
1731 pProposed =
ChartData->OpenStackChartConditional(
1732 m_pCurrentStack, start_index, search_direction,
1733 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1744 if (NULL == pProposed) {
1745 if (NULL == pDummyChart) {
1751 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1753 pProposed = pDummyChart;
1757 if (m_singleChart) m_singleChart->Deactivate();
1758 m_singleChart = pProposed;
1760 if (m_singleChart) {
1761 m_singleChart->Activate();
1762 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1763 m_pCurrentStack, m_singleChart->GetFullPath());
1768 if (NULL != m_singleChart) {
1774 if (!GetVP().IsValid())
1775 set_scale = 1. / 20000.;
1777 double proposed_scale_onscreen;
1780 double new_scale_ppm =
1781 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1789 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1790 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1791 double equivalent_vp_scale =
1793 double new_scale_ppm =
1794 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1799 proposed_scale_onscreen =
1800 wxMin(proposed_scale_onscreen,
1803 proposed_scale_onscreen =
1804 wxMax(proposed_scale_onscreen,
1813 m_singleChart->GetChartSkew() * PI / 180.,
1820 if ((m_bFollow) && m_singleChart)
1822 m_singleChart->GetChartSkew() * PI / 180.,
1831 m_bFirstAuto =
false;
1835 if (bNewChart && !bNewView) Refresh(
false);
1840 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1843 return bNewChart | bNewView;
1846void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1847 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1849 SetQuiltRefChart(db_index);
1854 double best_scale_ppm = GetBestVPScale(pc);
1858 SetQuiltRefChart(-1);
1860 SetQuiltRefChart(-1);
1863void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1864 std::vector<int> piano_chart_index_array =
1865 GetQuiltExtendedStackdbIndexArray();
1866 int current_db_index = piano_chart_index_array[selected_index];
1868 SelectQuiltRefdbChart(current_db_index);
1871double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1875 if ((g_bPreserveScaleOnX) ||
1876 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
1882 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
1883 double equivalent_vp_scale =
1885 double new_scale_ppm =
1886 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1893 double max_underzoom_multiplier = 2.0;
1894 if (GetVP().b_quilt) {
1895 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
1896 pchart->GetChartType(),
1897 pchart->GetChartFamily());
1898 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
1901 proposed_scale_onscreen = wxMin(
1902 proposed_scale_onscreen,
1904 max_underzoom_multiplier);
1907 proposed_scale_onscreen =
1908 wxMax(proposed_scale_onscreen,
1916void ChartCanvas::SetupCanvasQuiltMode(
void) {
1921 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
1925 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1926 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1927 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1928 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1930 m_Piano->SetRoundedRectangles(
true);
1933 int target_new_dbindex = -1;
1934 if (m_pCurrentStack) {
1935 target_new_dbindex =
1936 GetQuiltReferenceChartIndex();
1938 if (-1 != target_new_dbindex) {
1939 if (!IsChartQuiltableRef(target_new_dbindex)) {
1940 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
1941 int type =
ChartData->GetDBChartType(target_new_dbindex);
1944 int stack_index = m_pCurrentStack->CurrentStackEntry;
1946 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
1947 (stack_index >= 0)) {
1948 int proj_tent =
ChartData->GetDBChartProj(
1949 m_pCurrentStack->GetDBIndex(stack_index));
1950 int type_tent =
ChartData->GetDBChartType(
1951 m_pCurrentStack->GetDBIndex(stack_index));
1953 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
1954 if ((proj == proj_tent) && (type_tent == type)) {
1955 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
1965 if (IsChartQuiltableRef(target_new_dbindex))
1966 SelectQuiltRefdbChart(target_new_dbindex,
1969 SelectQuiltRefdbChart(-1,
false);
1971 m_singleChart = NULL;
1974 AdjustQuiltRefChart();
1982 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
1986 std::vector<int> empty_array;
1987 m_Piano->SetActiveKeyArray(empty_array);
1988 m_Piano->SetNoshowIndexArray(empty_array);
1989 m_Piano->SetEclipsedIndexArray(empty_array);
1992 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1993 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1994 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1995 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1997 m_Piano->SetRoundedRectangles(
false);
2003 if (!GetQuiltMode()) {
2008 if (m_bFollow ==
true) {
2016 if (!m_singleChart) {
2019 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2027 int cur_max_scale = (int)1e8;
2029 ChartBase *pChart = GetFirstQuiltChart();
2033 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2035 if (pChart->GetNativeScale() < cur_max_scale) {
2036 Candidate_Chart = pChart;
2037 cur_max_scale = pChart->GetNativeScale();
2040 pChart = GetNextQuiltChart();
2043 m_singleChart = Candidate_Chart;
2047 if (NULL == m_singleChart) {
2048 m_singleChart =
ChartData->OpenStackChartConditional(
2049 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2050 CHART_FAMILY_DONTCARE);
2056 InvalidateAllQuiltPatchs();
2058 if (m_singleChart) {
2059 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2060 std::vector<int> one_array;
2061 one_array.push_back(dbi);
2062 m_Piano->SetActiveKeyArray(one_array);
2065 if (m_singleChart) {
2066 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2070 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2074bool ChartCanvas::IsTempMenuBarEnabled() {
2077 wxGetOsVersion(&major);
2085double ChartCanvas::GetCanvasRangeMeters() {
2087 GetSize(&width, &height);
2088 int minDimension = wxMin(width, height);
2091 range *= cos(GetVP().clat * PI / 180.);
2095void ChartCanvas::SetCanvasRangeMeters(
double range) {
2097 GetSize(&width, &height);
2098 int minDimension = wxMin(width, height);
2100 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2104bool ChartCanvas::SetUserOwnship() {
2108 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2109 double factor_dusk = 0.5;
2110 double factor_night = 0.25;
2112 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2113 m_pos_image_user_day =
new wxImage;
2114 *m_pos_image_user_day = pbmp->ConvertToImage();
2115 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2117 int gimg_width = m_pos_image_user_day->GetWidth();
2118 int gimg_height = m_pos_image_user_day->GetHeight();
2121 m_pos_image_user_dusk =
new wxImage;
2122 m_pos_image_user_night =
new wxImage;
2124 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2125 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2127 for (
int iy = 0; iy < gimg_height; iy++) {
2128 for (
int ix = 0; ix < gimg_width; ix++) {
2129 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2130 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2131 m_pos_image_user_day->GetGreen(ix, iy),
2132 m_pos_image_user_day->GetBlue(ix, iy));
2133 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2134 hsv.value = hsv.value * factor_dusk;
2135 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2136 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2139 hsv = wxImage::RGBtoHSV(rgb);
2140 hsv.value = hsv.value * factor_night;
2141 nrgb = wxImage::HSVtoRGB(hsv);
2142 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2149 m_pos_image_user_grey_day =
new wxImage;
2150 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2152 m_pos_image_user_grey_dusk =
new wxImage;
2153 m_pos_image_user_grey_night =
new wxImage;
2155 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2156 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2158 for (
int iy = 0; iy < gimg_height; iy++) {
2159 for (
int ix = 0; ix < gimg_width; ix++) {
2160 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2161 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2162 m_pos_image_user_grey_day->GetGreen(ix, iy),
2163 m_pos_image_user_grey_day->GetBlue(ix, iy));
2164 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2165 hsv.value = hsv.value * factor_dusk;
2166 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2167 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2170 hsv = wxImage::RGBtoHSV(rgb);
2171 hsv.value = hsv.value * factor_night;
2172 nrgb = wxImage::HSVtoRGB(hsv);
2173 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2180 m_pos_image_user_yellow_day =
new wxImage;
2181 m_pos_image_user_yellow_dusk =
new wxImage;
2182 m_pos_image_user_yellow_night =
new wxImage;
2184 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2185 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2186 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2188 for (
int iy = 0; iy < gimg_height; iy++) {
2189 for (
int ix = 0; ix < gimg_width; ix++) {
2190 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2191 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2192 m_pos_image_user_grey_day->GetGreen(ix, iy),
2193 m_pos_image_user_grey_day->GetBlue(ix, iy));
2197 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2198 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2199 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2201 hsv = wxImage::RGBtoHSV(rgb);
2202 hsv.value = hsv.value * factor_dusk;
2203 nrgb = wxImage::HSVtoRGB(hsv);
2204 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2206 hsv = wxImage::RGBtoHSV(rgb);
2207 hsv.value = hsv.value * factor_night;
2208 nrgb = wxImage::HSVtoRGB(hsv);
2209 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2221 m_display_size_mm = size;
2228 double horizontal = sd.x;
2232 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2233 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2237 ps52plib->SetPPMM(m_pix_per_mm);
2242 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2244 m_display_size_mm, sd.x, sd.y);
2250 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2253 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2256void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2258 wxString msg(event.m_string.c_str(), wxConvUTF8);
2260 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2261 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2264 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2266 compress_msg_array.RemoveAt(event.thread);
2267 compress_msg_array.Insert( msg, event.thread);
2270 compress_msg_array.Add(msg);
2273 wxString combined_msg;
2274 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2275 combined_msg += compress_msg_array[i];
2276 combined_msg +=
"\n";
2280 pprog->Update(pprog_count, combined_msg, &skip );
2281 pprog->SetSize(pprog_size);
2286void ChartCanvas::InvalidateGL() {
2287 if (!m_glcc)
return;
2289 if (g_bopengl) m_glcc->Invalidate();
2291 if (m_Compass) m_Compass->UpdateStatus(
true);
2294int ChartCanvas::GetCanvasChartNativeScale() {
2296 if (!VPoint.b_quilt) {
2297 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2299 ret = (int)m_pQuilt->GetRefNativeScale();
2304ChartBase *ChartCanvas::GetChartAtCursor() {
2306 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2307 target_chart = m_singleChart;
2308 else if (VPoint.b_quilt)
2309 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2311 target_chart = NULL;
2312 return target_chart;
2315ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2319 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2321 target_chart = NULL;
2322 return target_chart;
2325int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2326 int new_dbIndex = -1;
2327 if (!VPoint.b_quilt) {
2328 if (m_pCurrentStack) {
2329 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2330 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2332 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2342 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2344 for (
unsigned int is = 0; is < im; is++) {
2346 m_pQuilt->GetExtendedStackIndexArray()[is]);
2349 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2359void ChartCanvas::EnablePaint(
bool b_enable) {
2360 m_b_paint_enable = b_enable;
2362 if (m_glcc) m_glcc->EnablePaint(b_enable);
2366bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2368void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2370std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2371 return m_pQuilt->GetQuiltIndexArray();
2375void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2376 VPoint.b_quilt = b_quilt;
2377 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2380bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2382int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2383 return m_pQuilt->GetRefChartdbIndex();
2386void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2387 m_pQuilt->InvalidateAllQuiltPatchs();
2390ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2391 return m_pQuilt->GetLargestScaleChart();
2394ChartBase *ChartCanvas::GetFirstQuiltChart() {
2395 return m_pQuilt->GetFirstChart();
2398ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2400int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2402void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2403 m_pQuilt->SetHiliteIndex(dbIndex);
2406void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2407 m_pQuilt->SetHiliteIndexArray(hilite_array);
2410void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2411 m_pQuilt->ClearHiliteIndexArray();
2414std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2416 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2419int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2420 return m_pQuilt->GetRefChartdbIndex();
2423std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2424 return m_pQuilt->GetExtendedStackIndexArray();
2427std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2428 return m_pQuilt->GetFullscreenIndexArray();
2431std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2432 return m_pQuilt->GetEclipsedStackIndexArray();
2435void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2437double ChartCanvas::GetQuiltMaxErrorFactor() {
2438 return m_pQuilt->GetMaxErrorFactor();
2441bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2442 return m_pQuilt->IsChartQuiltableRef(db_index);
2446 double chartMaxScale =
2448 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2451void ChartCanvas::StartMeasureRoute() {
2452 if (!m_routeState) {
2453 if (m_bMeasure_Active) {
2455 m_pMeasureRoute = NULL;
2458 m_bMeasure_Active =
true;
2459 m_nMeasureState = 1;
2460 m_bDrawingRoute =
false;
2462 SetCursor(*pCursorPencil);
2467void ChartCanvas::CancelMeasureRoute() {
2468 m_bMeasure_Active =
false;
2469 m_nMeasureState = 0;
2470 m_bDrawingRoute =
false;
2473 m_pMeasureRoute = NULL;
2475 SetCursor(*pCursorArrow);
2478ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2480void ChartCanvas::SetVP(
ViewPort &vp) {
2491void ChartCanvas::TriggerDeferredFocus() {
2494 m_deferredFocusTimer.Start(20,
true);
2496#if defined(__WXGTK__) || defined(__WXOSX__)
2507void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2512void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2513 if (SendKeyEventToPlugins(event))
2517 int key_char =
event.GetKeyCode();
2520 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2526 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2531 if (g_benable_rotate) {
2552void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2553 if (SendKeyEventToPlugins(event))
2557 bool b_handled =
false;
2559 m_modkeys =
event.GetModifiers();
2561 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2563#ifdef OCPN_ALT_MENUBAR
2569 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2571 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2572 if (!g_bTempShowMenuBar) {
2573 g_bTempShowMenuBar =
true;
2574 parent_frame->ApplyGlobalSettings(
false);
2576 m_bMayToggleMenuBar =
false;
2582 if (event.GetKeyCode() != WXK_ALT) {
2583 m_bMayToggleMenuBar =
false;
2590 switch (event.GetKeyCode()) {
2597 event.GetPosition(&x, &y);
2598 m_FinishRouteOnKillFocus =
false;
2599 CallPopupMenu(x, y);
2600 m_FinishRouteOnKillFocus =
true;
2604 m_modkeys |= wxMOD_ALT;
2608 m_modkeys |= wxMOD_CONTROL;
2613 case WXK_RAW_CONTROL:
2614 m_modkeys |= wxMOD_RAW_CONTROL;
2619 if (m_modkeys == wxMOD_CONTROL)
2620 parent_frame->DoStackDown(
this);
2622 StartTimedMovement();
2632 StartTimedMovement();
2640 if (m_modkeys == wxMOD_CONTROL)
2641 parent_frame->DoStackUp(
this);
2643 StartTimedMovement();
2653 StartTimedMovement();
2665 SetShowENCText(!GetShowENCText());
2671 if (!m_bMeasure_Active) {
2672 if (event.ShiftDown())
2673 m_bMeasure_DistCircle =
true;
2675 m_bMeasure_DistCircle =
false;
2677 StartMeasureRoute();
2679 CancelMeasureRoute();
2681 SetCursor(*pCursorArrow);
2691 parent_frame->ToggleColorScheme();
2693 TriggerDeferredFocus();
2697 int mod = m_modkeys & wxMOD_SHIFT;
2698 if (mod != m_brightmod) {
2700 m_bbrightdir = !m_bbrightdir;
2703 if (!m_bbrightdir) {
2704 g_nbrightness -= 10;
2705 if (g_nbrightness <= MIN_BRIGHT) {
2706 g_nbrightness = MIN_BRIGHT;
2707 m_bbrightdir =
true;
2710 g_nbrightness += 10;
2711 if (g_nbrightness >= MAX_BRIGHT) {
2712 g_nbrightness = MAX_BRIGHT;
2713 m_bbrightdir =
false;
2717 SetScreenBrightness(g_nbrightness);
2718 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2727 parent_frame->DoStackDown(
this);
2731 parent_frame->DoStackUp(
this);
2736 ToggleCanvasQuiltMode();
2742 parent_frame->ToggleFullScreen();
2747 if (m_modkeys == wxMOD_ALT) {
2750 ToggleChartOutlines();
2756 parent_frame->ActivateMOB();
2760 case WXK_NUMPAD_ADD:
2765 case WXK_NUMPAD_SUBTRACT:
2766 case WXK_PAGEDOWN: {
2767 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2772 if (m_bMeasure_Active) {
2773 if (m_nMeasureState > 2) {
2774 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2776 m_pMeasureRoute->GetnPoints();
2778 gFrame->RefreshAllCanvas();
2780 CancelMeasureRoute();
2781 StartMeasureRoute();
2789 if (event.GetKeyCode() < 128)
2791 int key_char =
event.GetKeyCode();
2795 if (!g_b_assume_azerty) {
2797 if (g_benable_rotate) {
2829 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2836 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2837 m_modkeys & wxMOD_RAW_CONTROL) {
2838 parent_frame->ToggleFullScreen();
2843 if (event.ControlDown()) key_char -= 64;
2845 if (key_char >=
'0' && key_char <=
'9')
2846 SetGroupIndex(key_char -
'0');
2851 SetShowENCAnchor(!GetShowENCAnchor());
2857 parent_frame->ToggleColorScheme();
2862 event.GetPosition(&x, &y);
2863 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2864 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2867 if (VPoint.b_quilt) {
2869 if (m_pQuilt->GetChartAtPix(
2874 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2876 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2881 if (m_singleChart) {
2882 ChartType = m_singleChart->GetChartType();
2883 ChartFam = m_singleChart->GetChartFamily();
2887 if ((ChartType != CHART_TYPE_UNKNOWN) ||
2888 (ChartFam != CHART_FAMILY_UNKNOWN)) {
2890 this, -1, ChartType, ChartFam,
2891 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
2892 wxDefaultSize, wxSIMPLE_BORDER,
"");
2905 m_nmea_log->Raise();
2909 SetShowENCLights(!GetShowENCLights());
2915 if (event.ShiftDown())
2916 m_bMeasure_DistCircle =
true;
2918 m_bMeasure_DistCircle =
false;
2920 StartMeasureRoute();
2924 if (g_bInlandEcdis && ps52plib) {
2925 SetENCDisplayCategory((_DisCat)STANDARD);
2930 ToggleChartOutlines();
2934 ToggleCanvasQuiltMode();
2938 parent_frame->ToggleTestPause();
2941 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
2942 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
2943 g_iNavAidRadarRingsNumberVisible = 1;
2944 else if (!g_bNavAidRadarRingsShown &&
2945 g_iNavAidRadarRingsNumberVisible == 1)
2946 g_iNavAidRadarRingsNumberVisible = 0;
2949 SetShowENCDepth(!m_encShowDepth);
2954 SetShowENCText(!GetShowENCText());
2959 SetShowENCDataQual(!GetShowENCDataQual());
2964 m_bShowNavobjects = !m_bShowNavobjects;
2979 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
2984 if (event.ControlDown()) gFrame->DropMarker(
false);
2990 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
2991 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
2992 if ((indexActive + 1) <= r->GetnPoints()) {
3003 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3009 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3015 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3022 parent_frame->DoSettings();
3026 parent_frame->Close();
3034 if (NULL == pGoToPositionDialog)
3037 pGoToPositionDialog->SetCanvas(
this);
3038 pGoToPositionDialog->Show();
3042 if (undo->AnythingToRedo()) {
3043 undo->RedoNextAction();
3050 if (event.ShiftDown()) {
3051 if (undo->AnythingToRedo()) {
3052 undo->RedoNextAction();
3057 if (undo->AnythingToUndo()) {
3058 undo->UndoLastAction();
3067 if (m_bMeasure_Active) {
3068 CancelMeasureRoute();
3070 SetCursor(*pCursorArrow);
3073 gFrame->RefreshAllCanvas();
3087 switch (gamma_state) {
3107 SetScreenBrightness(g_nbrightness);
3112 if (event.ControlDown()) {
3113 m_bShowCompassWin = !m_bShowCompassWin;
3114 SetShowGPSCompassWindow(m_bShowCompassWin);
3131void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3132 if (SendKeyEventToPlugins(event))
3136 switch (event.GetKeyCode()) {
3138 parent_frame->SwitchKBFocus(
this);
3144 if (!m_pany) m_panspeed = 0;
3150 if (!m_panx) m_panspeed = 0;
3153 case WXK_NUMPAD_ADD:
3154 case WXK_NUMPAD_SUBTRACT:
3163 m_modkeys &= ~wxMOD_ALT;
3164#ifdef OCPN_ALT_MENUBAR
3169 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3170 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3171 parent_frame->ApplyGlobalSettings(
false);
3173 m_bMayToggleMenuBar =
true;
3179 m_modkeys &= ~wxMOD_CONTROL;
3183 if (event.GetKeyCode() < 128)
3185 int key_char =
event.GetKeyCode();
3189 if (!g_b_assume_azerty) {
3204 m_rotation_speed = 0;
3222void ChartCanvas::ToggleChartOutlines(
void) {
3223 m_bShowOutlines = !m_bShowOutlines;
3229 if (g_bopengl) InvalidateGL();
3233void ChartCanvas::ToggleLookahead() {
3234 m_bLookAhead = !m_bLookAhead;
3239void ChartCanvas::SetUpMode(
int mode) {
3242 if (mode != NORTH_UP_MODE) {
3245 if (!std::isnan(gCog)) stuff = gCog;
3248 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3251 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3253 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3254 SetVPRotation(GetVPSkew());
3259 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3260 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3262 UpdateGPSCompassStatusBox(
true);
3263 gFrame->DoChartUpdate();
3266bool ChartCanvas::DoCanvasCOGSet(
void) {
3267 if (GetUpMode() == NORTH_UP_MODE)
return false;
3269 if (g_btenhertz) cog_use = gCog;
3271 double rotation = 0;
3272 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3273 rotation = -gHdt * PI / 180.;
3274 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3275 rotation = -cog_use * PI / 180.;
3277 SetVPRotation(rotation);
3281double easeOutCubic(
double t) {
3283 return 1.0 - pow(1.0 - t, 3.0);
3286void ChartCanvas::StartChartDragInertia() {
3287 m_bChartDragging =
false;
3290 m_chart_drag_inertia_time = 750;
3291 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3296 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3300 size_t length = m_drag_vec_t.size();
3301 for (
size_t i = 0; i < n_vel; i++) {
3302 xacc += m_drag_vec_x.at(length - 1 - i);
3303 yacc += m_drag_vec_y.at(length - 1 - i);
3304 tacc += m_drag_vec_t.at(length - 1 - i);
3306 m_chart_drag_velocity_x = xacc / tacc;
3307 m_chart_drag_velocity_y = yacc / tacc;
3309 m_chart_drag_inertia_active =
true;
3311 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3314void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3315 if (!m_chart_drag_inertia_active)
return;
3318 wxLongLong now = wxGetLocalTimeMillis();
3319 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3320 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3321 if (t > 1.0) t = 1.0;
3322 double e = 1.0 - easeOutCubic(t);
3325 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3327 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3329 m_last_elapsed = elapsed;
3333 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3334 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3335 double inertia_lat, inertia_lon;
3339 if (!IsOwnshipOnScreen()) {
3341 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3342 UpdateFollowButtonState();
3353 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3354 m_chart_drag_inertia_timer.Stop();
3357 m_target_lat = GetVP().
clat;
3358 m_target_lon = GetVP().
clon;
3359 m_pan_drag.x = m_pan_drag.y = 0;
3360 m_panx = m_pany = 0;
3361 m_chart_drag_inertia_active =
false;
3365 int target_redraw_interval = 40;
3366 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3370void ChartCanvas::StopMovement() {
3371 m_panx = m_pany = 0;
3374 m_rotation_speed = 0;
3377#if !defined(__WXGTK__) && !defined(__WXQT__)
3388bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3390 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3392 if (!pMovementTimer->IsRunning()) {
3394 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3397 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3402 m_last_movement_time = wxDateTime::UNow();
3406void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3409 m_target_lat = target_lat;
3410 m_target_lon = target_lon;
3413 m_start_lat = GetVP().
clat;
3414 m_start_lon = GetVP().
clon;
3416 m_VPMovementTimer.Start(1,
true);
3417 m_timed_move_vp_active =
true;
3419 m_timedVP_step = nstep;
3422void ChartCanvas::DoTimedMovementVP() {
3423 if (!m_timed_move_vp_active)
return;
3424 if (m_stvpc++ > m_timedVP_step * 2) {
3431 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3446 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3447 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3449 m_run_lat = new_lat;
3450 m_run_lon = new_lon;
3456void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3458void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3460void ChartCanvas::StartTimedMovementTarget() {}
3462void ChartCanvas::DoTimedMovementTarget() {}
3464void ChartCanvas::StopMovementTarget() {}
3466void ChartCanvas::DoTimedMovement() {
3467 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3471 wxDateTime now = wxDateTime::UNow();
3473 if (m_last_movement_time.IsValid())
3474 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3476 m_last_movement_time = now;
3486 if (dt == 0) dt = 1;
3489 if (m_mustmove < 0) m_mustmove = 0;
3491 if (m_pan_drag.x || m_pan_drag.y) {
3493 m_pan_drag.x = m_pan_drag.y = 0;
3496 if (m_panx || m_pany) {
3497 const double slowpan = .1, maxpan = 2;
3498 if (m_modkeys == wxMOD_ALT)
3499 m_panspeed = slowpan;
3501 m_panspeed += (double)dt / 500;
3502 m_panspeed = wxMin(maxpan, m_panspeed);
3504 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3507 if (m_zoom_factor != 1) {
3508 double alpha = 400, beta = 1.5;
3509 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3511 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3513 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3518 if (zoom_factor > 1) {
3519 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3523 else if (zoom_factor < 1) {
3524 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3529 if (fabs(zoom_factor - 1) > 1e-4) {
3530 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3535 if (m_wheelzoom_stop_oneshot > 0) {
3536 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3537 m_wheelzoom_stop_oneshot = 0;
3542 if (zoom_factor > 1) {
3544 m_wheelzoom_stop_oneshot = 0;
3547 }
else if (zoom_factor < 1) {
3549 m_wheelzoom_stop_oneshot = 0;
3556 if (m_rotation_speed) {
3557 double speed = m_rotation_speed;
3558 if (m_modkeys == wxMOD_ALT) speed /= 10;
3559 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3563void ChartCanvas::SetColorScheme(ColorScheme cs) {
3568 case GLOBAL_COLOR_SCHEME_DAY:
3569 m_pos_image_red = &m_os_image_red_day;
3570 m_pos_image_grey = &m_os_image_grey_day;
3571 m_pos_image_yellow = &m_os_image_yellow_day;
3572 m_pos_image_user = m_pos_image_user_day;
3573 m_pos_image_user_grey = m_pos_image_user_grey_day;
3574 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3575 m_cTideBitmap = m_bmTideDay;
3576 m_cCurrentBitmap = m_bmCurrentDay;
3579 case GLOBAL_COLOR_SCHEME_DUSK:
3580 m_pos_image_red = &m_os_image_red_dusk;
3581 m_pos_image_grey = &m_os_image_grey_dusk;
3582 m_pos_image_yellow = &m_os_image_yellow_dusk;
3583 m_pos_image_user = m_pos_image_user_dusk;
3584 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3585 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3586 m_cTideBitmap = m_bmTideDusk;
3587 m_cCurrentBitmap = m_bmCurrentDusk;
3589 case GLOBAL_COLOR_SCHEME_NIGHT:
3590 m_pos_image_red = &m_os_image_red_night;
3591 m_pos_image_grey = &m_os_image_grey_night;
3592 m_pos_image_yellow = &m_os_image_yellow_night;
3593 m_pos_image_user = m_pos_image_user_night;
3594 m_pos_image_user_grey = m_pos_image_user_grey_night;
3595 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3596 m_cTideBitmap = m_bmTideNight;
3597 m_cCurrentBitmap = m_bmCurrentNight;
3600 m_pos_image_red = &m_os_image_red_day;
3601 m_pos_image_grey = &m_os_image_grey_day;
3602 m_pos_image_yellow = &m_os_image_yellow_day;
3603 m_pos_image_user = m_pos_image_user_day;
3604 m_pos_image_user_grey = m_pos_image_user_grey_day;
3605 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3606 m_cTideBitmap = m_bmTideDay;
3607 m_cCurrentBitmap = m_bmCurrentDay;
3611 CreateDepthUnitEmbossMaps(cs);
3612 CreateOZEmbossMapData(cs);
3615 m_fog_color = wxColor(
3619 case GLOBAL_COLOR_SCHEME_DUSK:
3622 case GLOBAL_COLOR_SCHEME_NIGHT:
3628 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3629 m_fog_color.Blue() * dim);
3633 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3634 SetBackgroundColour( wxColour(0,0,0) );
3636 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3639 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3641 SetBackgroundColour( wxNullColour );
3648 m_Piano->SetColorScheme(cs);
3650 m_Compass->SetColorScheme(cs);
3652 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3654 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3656 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3657 if (m_notification_button) {
3658 m_notification_button->SetColorScheme(cs);
3662 if (g_bopengl && m_glcc) {
3663 m_glcc->SetColorScheme(cs);
3664 g_glTextureManager->ClearAllRasterTextures();
3669 m_brepaint_piano =
true;
3676wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3677 wxImage img = Bitmap.ConvertToImage();
3678 int sx = img.GetWidth();
3679 int sy = img.GetHeight();
3681 wxImage new_img(img);
3683 for (
int i = 0; i < sx; i++) {
3684 for (
int j = 0; j < sy; j++) {
3685 if (!img.IsTransparent(i, j)) {
3686 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3687 (
unsigned char)(img.GetGreen(i, j) * factor),
3688 (
unsigned char)(img.GetBlue(i, j) * factor));
3693 wxBitmap ret = wxBitmap(new_img);
3698void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3701 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3703 if (!m_pBrightPopup) {
3706 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3710 m_pBrightPopup->SetSize(x, y);
3711 m_pBrightPopup->Move(120, 120);
3714 int bmpsx = m_pBrightPopup->GetSize().x;
3715 int bmpsy = m_pBrightPopup->GetSize().y;
3717 wxBitmap bmp(bmpsx, bmpsx);
3718 wxMemoryDC mdc(bmp);
3720 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3721 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3722 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3723 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3726 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3728 mdc.SetFont(*pfont);
3731 if (brightness == max)
3733 else if (brightness == min)
3736 val.Printf(
"%3d", brightness);
3738 mdc.DrawText(val, 0, 0);
3740 mdc.SelectObject(wxNullBitmap);
3742 m_pBrightPopup->SetBitmap(bmp);
3743 m_pBrightPopup->Show();
3744 m_pBrightPopup->Refresh();
3747void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3748 m_b_rot_hidef =
true;
3752void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3755 bool b_need_refresh =
false;
3757 wxSize win_size = GetSize() * m_displayScale;
3761 bool showAISRollover =
false;
3762 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3764 SelectItem *pFind = pSelectAIS->FindSelection(
3767 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3768 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3771 showAISRollover =
true;
3773 if (NULL == m_pAISRolloverWin) {
3775 m_pAISRolloverWin->IsActive(
false);
3776 b_need_refresh =
true;
3777 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3778 m_AISRollover_MMSI != FoundAIS_MMSI) {
3784 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3785 m_pAISRolloverWin->IsActive(
false);
3786 m_AISRollover_MMSI = 0;
3791 m_AISRollover_MMSI = FoundAIS_MMSI;
3793 if (!m_pAISRolloverWin->IsActive()) {
3794 wxString s = ptarget->GetRolloverString();
3795 m_pAISRolloverWin->SetString(s);
3797 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3798 AIS_ROLLOVER, win_size);
3799 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3800 m_pAISRolloverWin->IsActive(
true);
3801 b_need_refresh =
true;
3805 m_AISRollover_MMSI = 0;
3806 showAISRollover =
false;
3811 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3812 m_pAISRolloverWin->IsActive(
false);
3813 m_AISRollover_MMSI = 0;
3814 b_need_refresh =
true;
3819 bool showRouteRollover =
false;
3821 if (NULL == m_pRolloverRouteSeg) {
3826 SelectableItemList SelList = pSelect->FindSelectionList(
3828 wxSelectableItemListNode *node = SelList.GetFirst();
3834 if (pr && pr->IsVisible()) {
3835 m_pRolloverRouteSeg = pFindSel;
3836 showRouteRollover =
true;
3838 if (NULL == m_pRouteRolloverWin) {
3840 m_pRouteRolloverWin->IsActive(
false);
3843 if (!m_pRouteRolloverWin->IsActive()) {
3851 DistanceBearingMercator(
3852 segShow_point_b->m_lat, segShow_point_b->m_lon,
3853 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3855 if (!pr->m_bIsInLayer)
3856 s.Append(_(
"Route") +
": ");
3858 s.Append(_(
"Layer Route: "));
3860 if (pr->m_RouteNameString.IsEmpty())
3861 s.Append(_(
"(unnamed)"));
3863 s.Append(pr->m_RouteNameString);
3866 << _(
"Total Length: ") << FormatDistanceAdaptive(pr->m_route_length)
3868 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3869 << segShow_point_b->GetName() <<
"\n";
3872 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
3873 (
int)floor(brg + 0.5), 0x00B0);
3876 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3878 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3879 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3881 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
3882 (
int)floor(varBrg + 0.5), 0x00B0);
3885 s << FormatDistanceAdaptive(dist);
3890 double shiptoEndLeg = 0.;
3891 bool validActive =
false;
3892 if (pr->IsActive() &&
3893 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
3896 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
3897 wxRoutePointListNode *node =
3898 (pr->pRoutePointList)->GetFirst()->GetNext();
3900 float dist_to_endleg = 0;
3904 prp = node->GetData();
3910 if (prp->IsSame(segShow_point_a))
break;
3911 node = node->GetNext();
3913 s <<
" (+" << FormatDistanceAdaptive(dist_to_endleg) <<
")";
3919 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
3922 ->GetCurrentRngToActivePoint();
3927 s << FormatDistanceAdaptive(shiptoEndLeg);
3931 if (!std::isnan(gCog) && !std::isnan(gSog))
3933 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
3936 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
3937 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
3939 << wxString(ttg_sec > SECONDS_PER_DAY
3940 ? ttg_span.Format(_(
"%Dd %H:%M"))
3941 : ttg_span.Format(_(
"%H:%M")));
3942 wxDateTime dtnow, eta;
3943 eta = dtnow.SetToCurrent().Add(ttg_span);
3944 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
3945 << eta.Format(
" %d %H:%M");
3949 m_pRouteRolloverWin->SetString(s);
3951 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3952 LEG_ROLLOVER, win_size);
3953 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
3954 m_pRouteRolloverWin->IsActive(
true);
3955 b_need_refresh =
true;
3956 showRouteRollover =
true;
3960 node = node->GetNext();
3966 m_pRolloverRouteSeg))
3967 showRouteRollover =
false;
3968 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
3969 showRouteRollover =
false;
3971 showRouteRollover =
true;
3975 if (m_routeState) showRouteRollover =
false;
3978 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
3979 showRouteRollover =
false;
3981 if (m_pRouteRolloverWin &&
3982 !showRouteRollover) {
3983 m_pRouteRolloverWin->IsActive(
false);
3984 m_pRolloverRouteSeg = NULL;
3985 m_pRouteRolloverWin->Destroy();
3986 m_pRouteRolloverWin = NULL;
3987 b_need_refresh =
true;
3988 }
else if (m_pRouteRolloverWin && showRouteRollover) {
3989 m_pRouteRolloverWin->IsActive(
true);
3990 b_need_refresh =
true;
3995 bool showTrackRollover =
false;
3997 if (NULL == m_pRolloverTrackSeg) {
4002 SelectableItemList SelList = pSelect->FindSelectionList(
4004 wxSelectableItemListNode *node = SelList.GetFirst();
4010 if (pt && pt->IsVisible()) {
4011 m_pRolloverTrackSeg = pFindSel;
4012 showTrackRollover =
true;
4014 if (NULL == m_pTrackRolloverWin) {
4016 m_pTrackRolloverWin->IsActive(
false);
4019 if (!m_pTrackRolloverWin->IsActive()) {
4027 DistanceBearingMercator(
4028 segShow_point_b->m_lat, segShow_point_b->m_lon,
4029 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4031 if (!pt->m_bIsInLayer)
4032 s.Append(_(
"Track") +
": ");
4034 s.Append(_(
"Layer Track: "));
4036 if (pt->GetName().IsEmpty())
4037 s.Append(_(
"(unnamed)"));
4039 s.Append(pt->GetName());
4040 double tlenght = pt->Length();
4041 s <<
"\n" << _(
"Total Track: ") << FormatDistanceAdaptive(tlenght);
4042 if (pt->GetLastPoint()->GetTimeString() &&
4043 pt->GetPoint(0)->GetTimeString()) {
4044 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4045 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4046 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4047 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4048 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4049 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4050 << getUsrSpeedUnit();
4051 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4052 : ttime.Format(
" %H:%M"));
4056 if (g_bShowTrackPointTime &&
4057 strlen(segShow_point_b->GetTimeString())) {
4058 wxString stamp = segShow_point_b->GetTimeString();
4059 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4060 if (timestamp.IsValid()) {
4064 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4066 s <<
"\n" << _(
"Segment Created: ") << stamp;
4071 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4076 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4078 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4079 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4081 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4085 s << FormatDistanceAdaptive(dist);
4087 if (segShow_point_a->GetTimeString() &&
4088 segShow_point_b->GetTimeString()) {
4089 wxDateTime apoint = segShow_point_a->GetCreateTime();
4090 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4091 if (apoint.IsValid() && bpoint.IsValid()) {
4092 double segmentSpeed = toUsrSpeed(
4093 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4094 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4095 << getUsrSpeedUnit();
4099 m_pTrackRolloverWin->SetString(s);
4101 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4102 LEG_ROLLOVER, win_size);
4103 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4104 m_pTrackRolloverWin->IsActive(
true);
4105 b_need_refresh =
true;
4106 showTrackRollover =
true;
4110 node = node->GetNext();
4116 m_pRolloverTrackSeg))
4117 showTrackRollover =
false;
4118 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4119 showTrackRollover =
false;
4121 showTrackRollover =
true;
4125 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4126 showTrackRollover =
false;
4129 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4130 showTrackRollover =
false;
4136 if (m_pTrackRolloverWin &&
4137 !showTrackRollover) {
4138 m_pTrackRolloverWin->IsActive(
false);
4139 m_pRolloverTrackSeg = NULL;
4140 m_pTrackRolloverWin->Destroy();
4141 m_pTrackRolloverWin = NULL;
4142 b_need_refresh =
true;
4143 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4144 m_pTrackRolloverWin->IsActive(
true);
4145 b_need_refresh =
true;
4148 if (b_need_refresh) Refresh();
4151void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4152 if ((GetShowENCLights() || m_bsectors_shown) &&
4153 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4154 extendedSectorLegs)) {
4155 if (!m_bsectors_shown) {
4157 m_bsectors_shown =
true;
4160 if (m_bsectors_shown) {
4162 m_bsectors_shown =
false;
4170#if defined(__WXGTK__) || defined(__WXQT__)
4175 double cursor_lat, cursor_lon;
4178 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4179 while (cursor_lon < -180.) cursor_lon += 360.;
4181 while (cursor_lon > 180.) cursor_lon -= 360.;
4183 SetCursorStatus(cursor_lat, cursor_lon);
4189void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4190 if (!parent_frame->m_pStatusBar)
return;
4194 s1 += toSDMM(1, cursor_lat);
4196 s1 += toSDMM(2, cursor_lon);
4198 if (STAT_FIELD_CURSOR_LL >= 0)
4199 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4201 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4206 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4207 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4208 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4210 wxString s = st + sm;
4211 s << FormatDistanceAdaptive(dist);
4223 if (g_bShowLiveETA) {
4226 float boatSpeedDefault = g_defaultBoatSpeed;
4231 if (!std::isnan(gSog)) {
4233 if (boatSpeed < 0.5) {
4236 realTimeETA = dist / boatSpeed * 60;
4245 s << minutesToHoursDays(realTimeETA);
4250 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4251 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4253 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4258 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4266wxString minutesToHoursDays(
float timeInMinutes) {
4269 if (timeInMinutes == 0) {
4274 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4275 s << wxString::Format(
"%d", (
int)timeInMinutes);
4280 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4283 hours = (int)timeInMinutes / 60;
4284 min = (int)timeInMinutes % 60;
4287 s << wxString::Format(
"%d", hours);
4290 s << wxString::Format(
"%d", hours);
4292 s << wxString::Format(
"%d", min);
4299 else if (timeInMinutes > 24 * 60) {
4302 days = (int)(timeInMinutes / 60) / 24;
4303 hours = (int)(timeInMinutes / 60) % 24;
4306 s << wxString::Format(
"%d", days);
4309 s << wxString::Format(
"%d", days);
4311 s << wxString::Format(
"%d", hours);
4323void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4331 wxPoint2DDouble *r) {
4336 double rlon, wxPoint2DDouble *r) {
4347 if (!g_bopengl && m_singleChart &&
4348 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4349 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4350 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4351 (m_singleChart->GetChartProjectionType() !=
4352 PROJECTION_TRANSVERSE_MERCATOR) &&
4353 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4354 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4355 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4369 Cur_BSB_Ch->SetVPRasterParms(vp);
4370 double rpixxd, rpixyd;
4371 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4397 if (std::isnan(p.m_x)) {
4398 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4402 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4403 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4405 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4424 if (!g_bopengl && m_singleChart &&
4425 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4426 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4427 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4428 (m_singleChart->GetChartProjectionType() !=
4429 PROJECTION_TRANSVERSE_MERCATOR) &&
4430 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4431 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4432 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4443 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4446 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4451 else if (slon > 180.)
4462 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4468 DoZoomCanvas(factor,
false);
4469 extendedSectorLegs.clear();
4474 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4477 if (StartTimedMovement(stoptimer)) {
4479 m_zoom_factor = factor;
4484 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4486 DoZoomCanvas(factor, can_zoom_to_cursor);
4489 extendedSectorLegs.clear();
4492void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4495 if (!m_pCurrentStack)
return;
4501 if (m_bzooming)
return;
4510 double proposed_scale_onscreen =
4513 bool b_do_zoom =
false;
4522 if (!VPoint.b_quilt) {
4525 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4526 if (new_db_index >= 0)
4527 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4531 int current_ref_stack_index = -1;
4532 if (m_pCurrentStack->nEntry) {
4534 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4535 m_pQuilt->SetReferenceChart(trial_index);
4536 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4537 if (new_db_index >= 0)
4538 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4542 if (m_pCurrentStack)
4543 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4553 double min_allowed_scale =
4556 if (proposed_scale_onscreen < min_allowed_scale) {
4561 proposed_scale_onscreen = min_allowed_scale;
4565 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4568 }
else if (factor < 1) {
4573 bool b_smallest =
false;
4575 if (!VPoint.b_quilt) {
4580 LLBBox viewbox = VPoint.GetBBox();
4582 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4583 double max_allowed_scale;
4597 if (proposed_scale_onscreen > max_allowed_scale) {
4599 proposed_scale_onscreen = max_allowed_scale;
4604 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4605 if (new_db_index >= 0)
4606 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4608 if (m_pCurrentStack)
4609 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4612 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4614 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4615 proposed_scale_onscreen =
4616 wxMin(proposed_scale_onscreen,
4622 m_absolute_min_scale_ppm)
4623 proposed_scale_onscreen =
4632 bool b_allow_ztc =
true;
4633 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4634 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4636 double brg, distance;
4637 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4640 meters_to_shift = distance * 1852;
4648 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4651 if (m_bFollow) DoCanvasUpdate();
4658void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4660 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4664void ChartCanvas::RotateCanvas(
double dir) {
4668 if (StartTimedMovement()) {
4670 m_rotation_speed = dir * 60;
4673 double speed = dir * 10;
4674 if (m_modkeys == wxMOD_ALT) speed /= 20;
4675 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4679void ChartCanvas::DoRotateCanvas(
double rotation) {
4680 while (rotation < 0) rotation += 2 * PI;
4681 while (rotation > 2 * PI) rotation -= 2 * PI;
4683 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4685 SetVPRotation(rotation);
4686 parent_frame->UpdateRotationState(VPoint.
rotation);
4689void ChartCanvas::DoTiltCanvas(
double tilt) {
4690 while (tilt < 0) tilt = 0;
4691 while (tilt > .95) tilt = .95;
4693 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4699void ChartCanvas::TogglebFollow(
void) {
4706void ChartCanvas::ClearbFollow(
void) {
4709 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4711 UpdateFollowButtonState();
4715 parent_frame->SetChartUpdatePeriod();
4718void ChartCanvas::SetbFollow(
void) {
4721 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4722 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4730 p.m_x += m_OSoffsetx;
4731 p.m_y -= m_OSoffsety;
4740 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4741 UpdateFollowButtonState();
4743 if (!g_bSmoothRecenter) {
4747 parent_frame->SetChartUpdatePeriod();
4750void ChartCanvas::UpdateFollowButtonState(
void) {
4753 m_muiBar->SetFollowButtonState(0);
4756 m_muiBar->SetFollowButtonState(2);
4758 m_muiBar->SetFollowButtonState(1);
4764 androidSetFollowTool(0);
4767 androidSetFollowTool(2);
4769 androidSetFollowTool(1);
4776 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4777 if (pic->m_enabled && pic->m_init_state) {
4778 switch (pic->m_api_version) {
4781 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4792void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4793 if (g_bSmoothRecenter && !m_routeState) {
4794 if (StartSmoothJump(lat, lon, scale_ppm))
4798 double gcDist, gcBearingEnd;
4799 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4801 gcBearingEnd += 180;
4802 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4805 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4806 double new_lat = lat + (lat_offset / (1852 * 60));
4807 double new_lon = lon + (lon_offset / (1852 * 60));
4810 StartSmoothJump(lat, lon, scale_ppm);
4815 if (lon > 180.0) lon -= 360.0;
4821 if (!GetQuiltMode()) {
4823 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4824 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4828 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4829 AdjustQuiltRefChart();
4836 UpdateFollowButtonState();
4844bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4849 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4850 double distance_pixels = gcDist *
GetVPScale();
4851 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4857 m_startLat = m_vLat;
4858 m_startLon = m_vLon;
4863 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4864 m_endScale = scale_ppm;
4867 m_animationDuration = 600;
4868 m_animationStart = wxGetLocalTimeMillis();
4875 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
4876 m_animationActive =
true;
4881void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
4883 wxLongLong now = wxGetLocalTimeMillis();
4884 double elapsed = (now - m_animationStart).ToDouble();
4885 double t = elapsed / m_animationDuration.ToDouble();
4886 if (t > 1.0) t = 1.0;
4889 double e = easeOutCubic(t);
4892 double curLat = m_startLat + (m_endLat - m_startLat) * e;
4893 double curLon = m_startLon + (m_endLon - m_startLon) * e;
4894 double curScale = m_startScale + (m_endScale - m_startScale) * e;
4899 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
4905 m_animationActive =
false;
4906 UpdateFollowButtonState();
4916 extendedSectorLegs.clear();
4925 if (iters++ > 5)
return false;
4926 if (!std::isnan(dlat))
break;
4929 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
4935 else if (dlat < -90)
4938 if (dlon > 360.) dlon -= 360.;
4939 if (dlon < -360.) dlon += 360.;
4954 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4958 if (VPoint.b_quilt) {
4959 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4960 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
4964 double tweak_scale_ppm =
4970 if (new_ref_dbIndex == -1) {
4971#pragma GCC diagnostic push
4972#pragma GCC diagnostic ignored "-Warray-bounds"
4979 int trial_index = -1;
4980 if (m_pCurrentStack->nEntry) {
4982 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4985 if (trial_index < 0) {
4986 auto full_screen_array = GetQuiltFullScreendbIndexArray();
4987 if (full_screen_array.size())
4988 trial_index = full_screen_array[full_screen_array.size() - 1];
4991 if (trial_index >= 0) {
4992 m_pQuilt->SetReferenceChart(trial_index);
4997#pragma GCC diagnostic pop
5004 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5006 double offset_angle = atan2(offy, offx);
5007 double offset_distance = sqrt((offy * offy) + (offx * offx));
5008 double chart_angle = GetVPRotation();
5009 double target_angle = chart_angle - offset_angle;
5010 double d_east_mod = offset_distance * cos(target_angle);
5011 double d_north_mod = offset_distance * sin(target_angle);
5016 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5017 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5019 UpdateFollowButtonState();
5025 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5030bool ChartCanvas::IsOwnshipOnScreen() {
5033 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5034 ((r.y > 0) && r.y < GetCanvasHeight()))
5040void ChartCanvas::ReloadVP(
bool b_adjust) {
5041 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5043 LoadVP(VPoint, b_adjust);
5046void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5048 if (g_bopengl && m_glcc) {
5049 m_glcc->Invalidate();
5050 if (m_glcc->GetSize() != GetSize()) {
5051 m_glcc->SetSize(GetSize());
5056 m_cache_vp.Invalidate();
5057 m_bm_cache_vp.Invalidate();
5060 VPoint.Invalidate();
5062 if (m_pQuilt) m_pQuilt->Invalidate();
5071 vp.m_projection_type, b_adjust);
5074void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5075 m_pQuilt->SetReferenceChart(dbIndex);
5076 VPoint.Invalidate();
5077 m_pQuilt->Invalidate();
5080double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5082 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5089int ChartCanvas::AdjustQuiltRefChart() {
5094 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5096 double min_ref_scale =
5097 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5098 double max_ref_scale =
5099 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5102 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5103 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5104 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5106 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5109 int target_stack_index = wxNOT_FOUND;
5111 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5112 if (index == m_pQuilt->GetRefChartdbIndex()) {
5113 target_stack_index = il;
5118 if (wxNOT_FOUND == target_stack_index)
5119 target_stack_index = 0;
5121 int ref_family = pc->GetChartFamily();
5122 int extended_array_count =
5123 m_pQuilt->GetExtendedStackIndexArray().size();
5124 while ((!brender_ok) &&
5125 ((
int)target_stack_index < (extended_array_count - 1))) {
5126 target_stack_index++;
5128 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5130 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5131 IsChartQuiltableRef(test_db_index)) {
5134 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5136 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5143 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5144 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5145 IsChartQuiltableRef(new_db_index)) {
5146 m_pQuilt->SetReferenceChart(new_db_index);
5149 ret = m_pQuilt->GetRefChartdbIndex();
5151 ret = m_pQuilt->GetRefChartdbIndex();
5154 ret = m_pQuilt->GetRefChartdbIndex();
5163void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5164 delete m_pCurrentStack;
5176bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5177 double latNE,
double lonNE) {
5179 double latc = (latSW + latNE) / 2.0;
5180 double lonc = (lonSW + lonNE) / 2.0;
5183 double ne_easting, ne_northing;
5184 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5186 double sw_easting, sw_northing;
5187 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5189 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5196 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5199bool ChartCanvas::SetVPProjection(
int projection) {
5205 double prev_true_scale_ppm = m_true_scale_ppm;
5210 m_absolute_min_scale_ppm));
5218bool ChartCanvas::SetVPRotation(
double angle) {
5220 VPoint.
skew, angle);
5223 double skew,
double rotation,
int projection,
5224 bool b_adjust,
bool b_refresh) {
5229 if (VPoint.IsValid()) {
5230 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5231 (fabs(VPoint.
skew - skew) < 1e-9) &&
5232 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5233 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5234 (VPoint.m_projection_type == projection ||
5235 projection == PROJECTION_UNKNOWN))
5238 if (VPoint.m_projection_type != projection)
5239 VPoint.InvalidateTransformCache();
5249 if (projection != PROJECTION_UNKNOWN)
5250 VPoint.SetProjectionType(projection);
5251 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5252 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5255 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5256 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5257 if (VPoint.
clat > 89.5)
5259 else if (VPoint.
clat < -89.5)
5260 VPoint.
clat = -89.5;
5265 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5266 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5278 bool bwasValid = VPoint.IsValid();
5283 m_cache_vp.Invalidate();
5288 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5292 int mouseX = mouse_x;
5293 int mouseY = mouse_y;
5294 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5300 SendCursorLatLonToAllPlugIns(lat, lon);
5303 if (!VPoint.b_quilt && m_singleChart) {
5308 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5312 if ((!m_cache_vp.IsValid()) ||
5317 wxPoint cp_last, cp_this;
5321 if (cp_last != cp_this) {
5327 if (m_pCurrentStack) {
5329 int current_db_index;
5331 m_pCurrentStack->GetCurrentEntrydbIndex();
5333 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5335 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5338 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5342 if (VPoint.b_quilt) {
5344 m_pQuilt->InvalidateAllQuiltPatchs();
5348 if (!m_pCurrentStack)
return false;
5350 int current_db_index;
5352 m_pCurrentStack->GetCurrentEntrydbIndex();
5354 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5355 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5358 int current_ref_stack_index = -1;
5359 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5360 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5361 current_ref_stack_index = i;
5364 if (g_bFullScreenQuilt) {
5365 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5369 bool b_needNewRef =
false;
5372 if ((-1 == current_ref_stack_index) &&
5373 (m_pQuilt->GetRefChartdbIndex() >= 0))
5374 b_needNewRef =
true;
5381 bool renderable =
true;
5383 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5384 if (referenceChart) {
5385 double chartMaxScale = referenceChart->GetNormalScaleMax(
5387 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5389 if (!renderable) b_needNewRef =
true;
5394 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5395 int target_scale = cte_ref.GetScale();
5396 int target_type = cte_ref.GetChartType();
5397 int candidate_stack_index;
5404 candidate_stack_index = 0;
5405 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5407 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5408 int candidate_scale = cte_candidate.GetScale();
5409 int candidate_type = cte_candidate.GetChartType();
5411 if ((candidate_scale >= target_scale) &&
5412 (candidate_type == target_type)) {
5413 bool renderable =
true;
5415 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5416 if (tentative_referenceChart) {
5417 double chartMaxScale =
5418 tentative_referenceChart->GetNormalScaleMax(
5420 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5423 if (renderable)
break;
5426 candidate_stack_index++;
5431 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5432 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5433 while (candidate_stack_index >= 0) {
5434 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5438 int candidate_scale = cte_candidate.GetScale();
5439 int candidate_type = cte_candidate.GetChartType();
5441 if ((candidate_scale <= target_scale) &&
5442 (candidate_type == target_type))
5445 candidate_stack_index--;
5450 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5451 (candidate_stack_index < 0))
5452 candidate_stack_index = 0;
5454 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5456 m_pQuilt->SetReferenceChart(new_ref_index);
5462 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5467 bool renderable =
true;
5469 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5470 if (referenceChart) {
5471 double chartMaxScale = referenceChart->GetNormalScaleMax(
5473 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5474 proj =
ChartData->GetDBChartProj(ref_db_index);
5476 proj = PROJECTION_MERCATOR;
5478 VPoint.b_MercatorProjectionOverride =
5479 (m_pQuilt->GetnCharts() == 0 || !renderable);
5481 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5483 VPoint.SetProjectionType(proj);
5490 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5495 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5515 m_pQuilt->Invalidate();
5532 if (b_refresh) Refresh(
false);
5539 }
else if (!g_bopengl) {
5540 OcpnProjType projection = PROJECTION_UNKNOWN;
5543 projection = m_singleChart->GetChartProjectionType();
5544 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5545 VPoint.SetProjectionType(projection);
5549 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5550 m_cache_vp.Invalidate();
5554 UpdateCanvasControlBar();
5560 if (VPoint.GetBBox().GetValid()) {
5563 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5572 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5575 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5582 wxPoint2DDouble r, r1;
5584 double delta_check =
5588 double check_point = wxMin(89., VPoint.
clat);
5590 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5593 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5594 VPoint.
clon, 0, &rhumbDist);
5599 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5600 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5602 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5606 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5612 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5614 if (m_true_scale_ppm)
5615 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5620 double round_factor = 1000.;
5624 round_factor = 100.;
5626 round_factor = 1000.;
5629 double retina_coef = 1;
5633 retina_coef = GetContentScaleFactor();
5644 double true_scale_display =
5645 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5650 if (m_displayed_scale_factor > 10.0)
5651 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5652 m_displayed_scale_factor);
5653 else if (m_displayed_scale_factor > 1.0)
5654 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5655 m_displayed_scale_factor);
5656 else if (m_displayed_scale_factor > 0.1) {
5657 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5658 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5659 }
else if (m_displayed_scale_factor > 0.01) {
5660 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5661 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5664 "%s %4.0f (---)", _(
"Scale"),
5665 true_scale_display);
5668 m_scaleValue = true_scale_display;
5670 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5672 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5673 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5675 bool b_noshow =
false;
5679 wxClientDC dc(parent_frame->GetStatusBar());
5681 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5682 dc.SetFont(*templateFont);
5683 dc.GetTextExtent(text, &w, &h);
5688 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5689 if (w && w > rect.width) {
5690 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5694 dc.GetTextExtent(text, &w, &h);
5696 if (w && w > rect.width) {
5702 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5707 m_vLat = VPoint.
clat;
5708 m_vLon = VPoint.
clon;
5722static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5726static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5727 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5729wxColour ChartCanvas::PredColor() {
5732 if (SHIP_NORMAL == m_ownship_state)
5733 return GetGlobalColor(
"URED");
5735 else if (SHIP_LOWACCURACY == m_ownship_state)
5736 return GetGlobalColor(
"YELO1");
5738 return GetGlobalColor(
"NODTA");
5741wxColour ChartCanvas::ShipColor() {
5745 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(
"GREY1");
5747 if (SHIP_LOWACCURACY == m_ownship_state)
return GetGlobalColor(
"YELO1");
5749 return GetGlobalColor(
"URED");
5752void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5753 wxPoint2DDouble lShipMidPoint) {
5754 dc.SetPen(wxPen(PredColor(), 2));
5756 if (SHIP_NORMAL == m_ownship_state)
5757 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5759 dc.SetBrush(wxBrush(GetGlobalColor(
"YELO1")));
5761 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5762 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5764 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5766 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5767 lShipMidPoint.m_y + 12);
5770void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5771 wxPoint GPSOffsetPixels,
5772 wxPoint2DDouble lGPSPoint) {
5777 float ref_dim = m_display_size_mm / 24;
5778 ref_dim = wxMin(ref_dim, 12);
5779 ref_dim = wxMax(ref_dim, 6);
5782 cPred.Set(g_cog_predictor_color);
5783 if (cPred == wxNullColour) cPred = PredColor();
5790 double nominal_line_width_pix = wxMax(
5792 floor(m_pix_per_mm / 2));
5796 if (nominal_line_width_pix > g_cog_predictor_width)
5797 g_cog_predictor_width = nominal_line_width_pix;
5800 wxPoint lPredPoint, lHeadPoint;
5802 float pCog = std::isnan(gCog) ? 0 : gCog;
5803 float pSog = std::isnan(gSog) ? 0 : gSog;
5805 double pred_lat, pred_lon;
5806 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5807 &pred_lat, &pred_lon);
5818 float ndelta_pix = 10.;
5819 double hdg_pred_lat, hdg_pred_lon;
5820 bool b_render_hdt =
false;
5821 if (!std::isnan(gHdt)) {
5823 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5826 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5827 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5828 if (dist > ndelta_pix ) {
5829 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5830 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5835 wxPoint lShipMidPoint;
5836 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5837 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5838 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5839 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5841 if (lpp >= img_height / 2) {
5842 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5843 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5844 !std::isnan(gSog)) {
5846 float dash_length = ref_dim;
5847 wxDash dash_long[2];
5849 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5850 g_cog_predictor_width);
5851 dash_long[1] = dash_long[0] / 2.0;
5855 if (dash_length > 250.) {
5856 dash_long[0] = 250. / g_cog_predictor_width;
5857 dash_long[1] = dash_long[0] / 2;
5860 wxPen ppPen2(cPred, g_cog_predictor_width,
5861 (wxPenStyle)g_cog_predictor_style);
5862 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5863 ppPen2.SetDashes(2, dash_long);
5866 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5867 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5869 if (g_cog_predictor_width > 1) {
5870 float line_width = g_cog_predictor_width / 3.;
5872 wxDash dash_long3[2];
5873 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5874 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5876 wxPen ppPen3(GetGlobalColor(
"UBLCK"), wxMax(1, line_width),
5877 (wxPenStyle)g_cog_predictor_style);
5878 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5879 ppPen3.SetDashes(2, dash_long3);
5881 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
5882 lGPSPoint.m_y + GPSOffsetPixels.y,
5883 lPredPoint.x + GPSOffsetPixels.x,
5884 lPredPoint.y + GPSOffsetPixels.y);
5887 if (g_cog_predictor_endmarker) {
5889 double png_pred_icon_scale_factor = .4;
5890 if (g_ShipScaleFactorExp > 1.0)
5891 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5892 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
5896 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
5897 (
float)(lPredPoint.x - lShipMidPoint.x));
5898 cog_rad += (float)PI;
5900 for (
int i = 0; i < 4; i++) {
5902 double pxa = (double)(s_png_pred_icon[j]);
5903 double pya = (double)(s_png_pred_icon[j + 1]);
5905 pya *= png_pred_icon_scale_factor;
5906 pxa *= png_pred_icon_scale_factor;
5908 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
5909 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
5911 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
5912 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
5916 wxPen ppPen1(GetGlobalColor(
"UBLCK"), g_cog_predictor_width / 2,
5919 dc.SetBrush(wxBrush(cPred));
5921 dc.StrokePolygon(4, icon);
5928 float hdt_dash_length = ref_dim * 0.4;
5930 cPred.Set(g_ownship_HDTpredictor_color);
5931 if (cPred == wxNullColour) cPred = PredColor();
5933 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
5934 : g_cog_predictor_width * 0.8);
5935 wxDash dash_short[2];
5937 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
5940 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
5943 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
5944 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
5945 ppPen2.SetDashes(2, dash_short);
5949 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5950 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
5952 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
5954 dc.SetBrush(wxBrush(GetGlobalColor(
"GREY2")));
5956 if (g_ownship_HDTpredictor_endmarker) {
5957 double nominal_circle_size_pixels = wxMax(
5958 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
5961 if (g_ShipScaleFactorExp > 1.0)
5962 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5964 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
5965 lHeadPoint.y + GPSOffsetPixels.y,
5966 nominal_circle_size_pixels / 2);
5971 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
5972 double factor = 1.00;
5973 if (g_pNavAidRadarRingsStepUnits == 1)
5975 else if (g_pNavAidRadarRingsStepUnits == 2) {
5976 if (std::isnan(gSog))
5981 factor *= g_fNavAidRadarRingsStep;
5985 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
5988 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
5989 pow((
double)(lGPSPoint.m_y - r.y), 2));
5990 int pix_radius = (int)lpp;
5992 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
5994 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
5997 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
5999 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6000 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6004void ChartCanvas::ComputeShipScaleFactor(
6005 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6006 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6007 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6008 float screenResolution = m_pix_per_mm;
6011 double ship_bow_lat, ship_bow_lon;
6012 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6013 &ship_bow_lat, &ship_bow_lon);
6014 wxPoint lShipBowPoint;
6015 wxPoint2DDouble b_point =
6019 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6020 powf((
float)(b_point.m_y - a_point.m_y), 2));
6023 float shipLength_mm = shipLength_px / screenResolution;
6026 float ownship_min_mm = g_n_ownship_min_mm;
6027 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6030 float hdt_ant = icon_hdt + 180.;
6031 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6032 float dx = g_n_gps_antenna_offset_x / 1852.;
6033 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6041 if (shipLength_mm < ownship_min_mm) {
6042 dy /= shipLength_mm / ownship_min_mm;
6043 dx /= shipLength_mm / ownship_min_mm;
6046 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6048 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6049 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6055 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6056 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6058 float scale_factor = shipLength_px / ownShipLength;
6061 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6064 scale_factor = wxMax(scale_factor, scale_factor_min);
6066 scale_factor_y = scale_factor;
6067 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6068 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6071void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6072 if (!GetVP().IsValid())
return;
6074 wxPoint GPSOffsetPixels(0, 0);
6075 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6078 float pCog = std::isnan(gCog) ? 0 : gCog;
6079 float pSog = std::isnan(gSog) ? 0 : gSog;
6083 lShipMidPoint = lGPSPoint;
6087 float icon_hdt = pCog;
6088 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6091 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6095 double osd_head_lat, osd_head_lon;
6096 wxPoint osd_head_point;
6098 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6103 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6104 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6105 icon_rad += (float)PI;
6107 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6111 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6115 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6116 if (GetVP().chart_scale >
6119 ShipDrawLargeScale(dc, lShipMidPoint);
6125 if (m_pos_image_user)
6126 pos_image = m_pos_image_user->Copy();
6127 else if (SHIP_NORMAL == m_ownship_state)
6128 pos_image = m_pos_image_red->Copy();
6129 if (SHIP_LOWACCURACY == m_ownship_state)
6130 pos_image = m_pos_image_yellow->Copy();
6131 else if (SHIP_NORMAL != m_ownship_state)
6132 pos_image = m_pos_image_grey->Copy();
6135 if (m_pos_image_user) {
6136 pos_image = m_pos_image_user->Copy();
6138 if (SHIP_LOWACCURACY == m_ownship_state)
6139 pos_image = m_pos_image_user_yellow->Copy();
6140 else if (SHIP_NORMAL != m_ownship_state)
6141 pos_image = m_pos_image_user_grey->Copy();
6144 img_height = pos_image.GetHeight();
6146 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6147 g_OwnShipIconType > 0)
6149 int ownShipWidth = 22;
6150 int ownShipLength = 84;
6151 if (g_OwnShipIconType == 1) {
6152 ownShipWidth = pos_image.GetWidth();
6153 ownShipLength = pos_image.GetHeight();
6156 float scale_factor_x, scale_factor_y;
6157 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6158 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6159 scale_factor_x, scale_factor_y);
6161 if (g_OwnShipIconType == 1) {
6162 pos_image.Rescale(ownShipWidth * scale_factor_x,
6163 ownShipLength * scale_factor_y,
6164 wxIMAGE_QUALITY_HIGH);
6165 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6167 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6170 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6171 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6172 if (rot_image.GetAlpha(ip, jp) > 64)
6173 rot_image.SetAlpha(ip, jp, 255);
6175 wxBitmap os_bm(rot_image);
6177 int w = os_bm.GetWidth();
6178 int h = os_bm.GetHeight();
6181 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6182 lShipMidPoint.m_y - h / 2,
true);
6185 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6186 lShipMidPoint.m_y - h / 2);
6187 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6188 lShipMidPoint.m_y - h / 2 + h);
6191 else if (g_OwnShipIconType == 2) {
6192 wxPoint ownship_icon[10];
6194 for (
int i = 0; i < 10; i++) {
6196 float pxa = (float)(s_ownship_icon[j]);
6197 float pya = (float)(s_ownship_icon[j + 1]);
6198 pya *= scale_factor_y;
6199 pxa *= scale_factor_x;
6201 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6202 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6204 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6205 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6208 wxPen ppPen1(GetGlobalColor(
"UBLCK"), 1, wxPENSTYLE_SOLID);
6210 dc.SetBrush(wxBrush(ShipColor()));
6212 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6215 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6217 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6221 img_height = ownShipLength * scale_factor_y;
6225 if (m_pos_image_user) circle_rad = 1;
6227 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6228 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6229 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6232 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6234 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6237 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6238 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6239 if (rot_image.GetAlpha(ip, jp) > 64)
6240 rot_image.SetAlpha(ip, jp, 255);
6242 wxBitmap os_bm(rot_image);
6244 if (g_ShipScaleFactorExp > 1) {
6245 wxImage scaled_image = os_bm.ConvertToImage();
6246 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6248 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6249 scaled_image.GetHeight() * factor,
6250 wxIMAGE_QUALITY_HIGH));
6252 int w = os_bm.GetWidth();
6253 int h = os_bm.GetHeight();
6256 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6257 lShipMidPoint.m_y - h / 2,
true);
6261 if (m_pos_image_user) circle_rad = 1;
6263 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK"), 1));
6264 dc.SetBrush(wxBrush(GetGlobalColor(
"UIBCK")));
6265 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6268 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6269 lShipMidPoint.m_y - h / 2);
6270 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6271 lShipMidPoint.m_y - h / 2 + h);
6276 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6289void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6290 float &MinorSpacing) {
6295 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6296 {.000001f, 45.0f, 15.0f},
6297 {.0002f, 30.0f, 10.0f},
6298 {.0003f, 10.0f, 2.0f},
6299 {.0008f, 5.0f, 1.0f},
6300 {.001f, 2.0f, 30.0f / 60.0f},
6301 {.003f, 1.0f, 20.0f / 60.0f},
6302 {.006f, 0.5f, 10.0f / 60.0f},
6303 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6304 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6305 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6306 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6307 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6308 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6309 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6310 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6313 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6314 if (view_scale_ppm < lltab[tabi][0])
break;
6315 MajorSpacing = lltab[tabi][1];
6316 MinorSpacing = lltab[tabi][2];
6330wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6331 int deg = (int)fabs(latlon);
6332 float min = fabs((fabs(latlon) - deg) * 60.0);
6342 }
else if (latlon < 0.0) {
6354 if (spacing >= 1.0) {
6355 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6356 }
else if (spacing >= (1.0 / 60.0)) {
6357 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6359 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6376void ChartCanvas::GridDraw(
ocpnDC &dc) {
6377 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6379 double nlat, elon, slat, wlon;
6382 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6384 wxPen GridPen(GetGlobalColor(
"SNDG1"), 1, wxPENSTYLE_SOLID);
6386 if (!m_pgridFont) SetupGridFont();
6387 dc.SetFont(*m_pgridFont);
6388 dc.SetTextForeground(GetGlobalColor(
"SNDG1"));
6391 h = m_canvas_height;
6402 dlon = dlon + 360.0;
6405 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6408 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6411 while (lat < nlat) {
6414 CalcGridText(lat, gridlatMajor,
true);
6416 dc.
DrawLine(0, r.y, w, r.y,
false);
6417 dc.DrawText(st, 0, r.y);
6418 lat = lat + gridlatMajor;
6420 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6424 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6427 while (lat < nlat) {
6430 dc.
DrawLine(0, r.y, 10, r.y,
false);
6431 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6432 lat = lat + gridlatMinor;
6436 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6439 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6442 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6444 wxString st = CalcGridText(lon, gridlonMajor,
false);
6446 dc.
DrawLine(r.x, 0, r.x, h,
false);
6447 dc.DrawText(st, r.x, 0);
6448 lon = lon + gridlonMajor;
6453 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6457 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6459 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6462 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6463 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6464 lon = lon + gridlonMinor;
6471void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6473 double blat, blon, tlat, tlon;
6476 int x_origin = m_bDisplayGrid ? 60 : 20;
6477 int y_origin = m_canvas_height - 50;
6483 if (GetVP().chart_scale > 80000)
6487 pen1 = wxPen(GetGlobalColor(
"SNDG2"), 3, wxPENSTYLE_SOLID);
6488 pen2 = wxPen(GetGlobalColor(
"SNDG1"), 3, wxPENSTYLE_SOLID);
6493 pen1 = wxPen(GetGlobalColor(
"SCLBR"), 3, wxPENSTYLE_SOLID);
6494 pen2 = wxPen(GetGlobalColor(
"CHGRD"), 3, wxPENSTYLE_SOLID);
6498 double rotation = -VPoint.
rotation;
6500 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6502 int l1 = (y_origin - r.y) / count;
6504 for (
int i = 0; i < count; i++) {
6511 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6514 double blat, blon, tlat, tlon;
6521 int y_origin = m_canvas_height - chartbar_height - 5;
6525 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6532 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6535 int unit = g_iDistanceFormat;
6537 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6538 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6541 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6542 float places = floor(logdist), rem = logdist - places;
6543 dist = pow(10, places);
6550 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6551 wxPen pen1 = wxPen(GetGlobalColor(
"UBLCK"), 3, wxPENSTYLE_SOLID);
6552 double rotation = -VPoint.
rotation;
6554 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6558 int l1 = r.x - x_origin;
6560 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6565 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6566 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6567 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6569 if (!m_pgridFont) SetupGridFont();
6570 dc.SetFont(*m_pgridFont);
6571 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
6573 dc.GetTextExtent(s, &w, &h);
6579 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6583void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6588 double ra_max = 40.;
6590 wxPen pen_save = dc.GetPen();
6592 wxDateTime now = wxDateTime::Now();
6598 x0 = x1 = x + radius;
6603 while (angle < 360.) {
6604 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6607 if (angle > 360.) angle = 360.;
6609 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6617 x1 = (int)(x + cos(angle * PI / 180.) * r);
6618 y1 = (int)(y + sin(angle * PI / 180.) * r);
6628 dc.
DrawLine(x + radius, y, x1, y1);
6630 dc.SetPen(pen_save);
6633static bool bAnchorSoundPlaying =
false;
6635static void onAnchorSoundFinished(
void *ptr) {
6636 g_anchorwatch_sound->UnLoad();
6637 bAnchorSoundPlaying =
false;
6640void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6642 bool play_sound =
false;
6643 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6644 if (AnchorAlertOn1) {
6645 wxPoint TargetPoint;
6648 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6649 TargetPoint.y, 100);
6653 AnchorAlertOn1 =
false;
6655 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6656 if (AnchorAlertOn2) {
6657 wxPoint TargetPoint;
6660 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6661 TargetPoint.y, 100);
6665 AnchorAlertOn2 =
false;
6668 if (!bAnchorSoundPlaying) {
6669 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6670 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6671 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6672 if (g_anchorwatch_sound->IsOk()) {
6673 bAnchorSoundPlaying =
true;
6674 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6675 g_anchorwatch_sound->Play();
6681void ChartCanvas::UpdateShips() {
6684 wxClientDC dc(
this);
6685 if (!dc.IsOk())
return;
6687 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6688 if (!test_bitmap.IsOk())
return;
6690 wxMemoryDC temp_dc(test_bitmap);
6692 temp_dc.ResetBoundingBox();
6693 temp_dc.DestroyClippingRegion();
6694 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6700 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6701 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6705 ocpndc.CalcBoundingBox(px.x, px.y);
6710 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6711 temp_dc.MaxY() - temp_dc.MinY());
6713 wxRect own_ship_update_rect = ship_draw_rect;
6715 if (!own_ship_update_rect.IsEmpty()) {
6718 own_ship_update_rect.Union(ship_draw_last_rect);
6719 own_ship_update_rect.Inflate(2);
6722 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6724 ship_draw_last_rect = ship_draw_rect;
6726 temp_dc.SelectObject(wxNullBitmap);
6729void ChartCanvas::UpdateAlerts() {
6734 wxClientDC dc(
this);
6738 dc.GetSize(&sx, &sy);
6741 wxBitmap test_bitmap(sx, sy, -1);
6745 temp_dc.SelectObject(test_bitmap);
6747 temp_dc.ResetBoundingBox();
6748 temp_dc.DestroyClippingRegion();
6749 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6756 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6757 temp_dc.MaxX() - temp_dc.MinX(),
6758 temp_dc.MaxY() - temp_dc.MinY());
6760 if (!alert_rect.IsEmpty())
6761 alert_rect.Inflate(2);
6763 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6766 wxRect alert_update_rect = alert_draw_rect;
6767 alert_update_rect.Union(alert_rect);
6770 RefreshRect(alert_update_rect,
false);
6774 alert_draw_rect = alert_rect;
6776 temp_dc.SelectObject(wxNullBitmap);
6779void ChartCanvas::UpdateAIS() {
6780 if (!g_pAIS)
return;
6785 wxClientDC dc(
this);
6789 dc.GetSize(&sx, &sy);
6797 if (g_pAIS->GetTargetList().size() > 10) {
6798 ais_rect = wxRect(0, 0, sx, sy);
6801 wxBitmap test_bitmap(sx, sy, -1);
6805 temp_dc.SelectObject(test_bitmap);
6807 temp_dc.ResetBoundingBox();
6808 temp_dc.DestroyClippingRegion();
6809 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6813 AISDraw(ocpndc, GetVP(),
this);
6814 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6818 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6819 temp_dc.MaxY() - temp_dc.MinY());
6821 if (!ais_rect.IsEmpty())
6822 ais_rect.Inflate(2);
6824 temp_dc.SelectObject(wxNullBitmap);
6827 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6830 wxRect ais_update_rect = ais_draw_rect;
6831 ais_update_rect.Union(ais_rect);
6834 RefreshRect(ais_update_rect,
false);
6838 ais_draw_rect = ais_rect;
6841void ChartCanvas::ToggleCPAWarn() {
6842 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6848 g_bTCPA_Max =
false;
6852 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6853 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6855 if (!g_AisFirstTimeUse) {
6856 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
6857 _(
"CPA") +
" " + mess, 4, 4);
6862void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6864void ChartCanvas::OnSize(wxSizeEvent &event) {
6865 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6867 GetClientSize(&m_canvas_width, &m_canvas_height);
6871 m_displayScale = GetContentScaleFactor();
6875 m_canvas_width *= m_displayScale;
6876 m_canvas_height *= m_displayScale;
6889 m_absolute_min_scale_ppm =
6891 (1.2 * WGS84_semimajor_axis_meters * PI);
6894 gFrame->ProcessCanvasResize();
6904 SetMUIBarPosition();
6905 UpdateFollowButtonState();
6906 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6910 xr_margin = m_canvas_width * 95 / 100;
6911 xl_margin = m_canvas_width * 5 / 100;
6912 yt_margin = m_canvas_height * 5 / 100;
6913 yb_margin = m_canvas_height * 95 / 100;
6916 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
6921 m_brepaint_piano =
true;
6924 m_dc_route.SelectObject(wxNullBitmap);
6927 m_dc_route.SelectObject(*proute_bm);
6941 m_glcc->OnSize(event);
6950void ChartCanvas::ProcessNewGUIScale() {
6958void ChartCanvas::CreateMUIBar() {
6959 if (g_useMUI && !m_muiBar) {
6965 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6966 m_muiBar->SetColorScheme(m_cs);
6967 m_muiBarHOSize = m_muiBar->m_size;
6971 SetMUIBarPosition();
6972 UpdateFollowButtonState();
6973 m_muiBar->UpdateDynamicValues();
6974 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6978void ChartCanvas::SetMUIBarPosition() {
6982 int pianoWidth = GetClientSize().x * 0.6f;
6987 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
6988 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
6990 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
6991 m_muiBar->SetColorScheme(m_cs);
6995 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
6996 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
6998 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6999 m_muiBar->SetColorScheme(m_cs);
7003 m_muiBar->SetBestPosition();
7007void ChartCanvas::DestroyMuiBar() {
7014void ChartCanvas::ShowCompositeInfoWindow(
7015 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7017 if (NULL == m_pCIWin) {
7022 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7025 s = _(
"Composite of ");
7028 s1.Printf(
"%d ", n_charts);
7036 s1.Printf(_(
"Chart scale"));
7039 s2.Printf(
"1:%d\n",
scale);
7043 s1 = _(
"Zoom in for more information");
7047 int char_width = s1.Length();
7048 int char_height = 3;
7050 if (g_bChartBarEx) {
7053 for (
int i : index_vector) {
7055 wxString path = cte.GetFullSystemPath();
7059 char_width = wxMax(char_width, path.Length());
7060 if (j++ >= 9)
break;
7063 s +=
" .\n .\n .\n";
7072 m_pCIWin->SetString(s);
7074 m_pCIWin->FitToChars(char_width, char_height);
7077 p.x = x / GetContentScaleFactor();
7078 if ((p.x + m_pCIWin->GetWinSize().x) >
7079 (m_canvas_width / GetContentScaleFactor()))
7080 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7081 m_pCIWin->GetWinSize().x) /
7084 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7085 4 - m_pCIWin->GetWinSize().y;
7087 m_pCIWin->dbIndex = 0;
7088 m_pCIWin->chart_scale = 0;
7089 m_pCIWin->SetPosition(p);
7090 m_pCIWin->SetBitmap();
7091 m_pCIWin->Refresh();
7095 HideChartInfoWindow();
7099void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7101 if (NULL == m_pCIWin) {
7106 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7115 dbIndex, FULL_INIT);
7117 int char_width, char_height;
7118 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7119 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7121 m_pCIWin->SetString(s);
7122 m_pCIWin->FitToChars(char_width, char_height);
7125 p.x = x / GetContentScaleFactor();
7126 if ((p.x + m_pCIWin->GetWinSize().x) >
7127 (m_canvas_width / GetContentScaleFactor()))
7128 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7129 m_pCIWin->GetWinSize().x) /
7132 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7133 4 - m_pCIWin->GetWinSize().y;
7135 m_pCIWin->dbIndex = dbIndex;
7136 m_pCIWin->SetPosition(p);
7137 m_pCIWin->SetBitmap();
7138 m_pCIWin->Refresh();
7142 HideChartInfoWindow();
7146void ChartCanvas::HideChartInfoWindow(
void) {
7149 m_pCIWin->Destroy();
7153 androidForceFullRepaint();
7158void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7159 wxMouseEvent ev(wxEVT_MOTION);
7162 ev.m_leftDown = mouse_leftisdown;
7164 wxEvtHandler *evthp = GetEventHandler();
7166 ::wxPostEvent(evthp, ev);
7169void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7170 if ((m_panx_target_final - m_panx_target_now) ||
7171 (m_pany_target_final - m_pany_target_now)) {
7172 DoTimedMovementTarget();
7177void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7179bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7181 if (m_disable_edge_pan)
return false;
7184 int pan_margin = m_canvas_width * margin / 100;
7185 int pan_timer_set = 200;
7186 double pan_delta = GetVP().
pix_width * delta / 100;
7190 if (x > m_canvas_width - pan_margin) {
7195 else if (x < pan_margin) {
7200 if (y < pan_margin) {
7205 else if (y > m_canvas_height - pan_margin) {
7214 wxMouseState state = ::wxGetMouseState();
7215#if wxCHECK_VERSION(3, 0, 0)
7216 if (!state.LeftIsDown())
7218 if (!state.LeftDown())
7223 if ((bft) && !pPanTimer->IsRunning()) {
7225 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7231 if ((!bft) && pPanTimer->IsRunning()) {
7241void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7242 bool setBeingEdited) {
7243 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7244 m_pRoutePointEditTarget = NULL;
7245 m_pFoundPoint = NULL;
7249 SelectableItemList SelList = pSelect->FindSelectionList(
7251 wxSelectableItemListNode *node = SelList.GetFirst();
7253 pFind = node->GetData();
7262 bool brp_viz =
false;
7263 if (m_pEditRouteArray) {
7264 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7265 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7266 if (pr->IsVisible()) {
7272 brp_viz = frp->IsVisible();
7276 if (m_pEditRouteArray)
7278 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7279 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7282 m_bRouteEditing = setBeingEdited;
7285 frp->m_bRPIsBeingEdited = setBeingEdited;
7286 m_bMarkEditing = setBeingEdited;
7289 m_pRoutePointEditTarget = frp;
7290 m_pFoundPoint = pFind;
7294 node = node->GetNext();
7297std::shared_ptr<PI_PointContext> ChartCanvas::GetCanvasContextAtPoint(
int x,
7313 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7314 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7315 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7316 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7320 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7323 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7328 int FoundAIS_MMSI = 0;
7330 FoundAIS_MMSI = pFindAIS->GetUserData();
7333 if (g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7334 seltype |= SELTYPE_AISTARGET;
7340 Route *SelectedRoute = NULL;
7346 Route *pSelectedActiveRoute = NULL;
7347 Route *pSelectedVizRoute = NULL;
7351 SelectableItemList SelList =
7352 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7353 wxSelectableItemListNode *node = SelList.GetFirst();
7363 bool brp_viz =
false;
7365 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7367 if (pr->IsVisible()) {
7372 if (!brp_viz && prp->IsShared())
7374 brp_viz = prp->IsVisible();
7377 brp_viz = prp->IsVisible();
7379 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7385 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7388 pSelectedActiveRoute = pr;
7389 pFoundActiveRoutePoint = prp;
7394 if (NULL == pSelectedVizRoute) {
7395 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7397 if (pr->IsVisible()) {
7398 pSelectedVizRoute = pr;
7399 pFoundVizRoutePoint = prp;
7405 delete proute_array;
7408 node = node->GetNext();
7412 if (pFoundActiveRoutePoint) {
7413 FoundRoutePoint = pFoundActiveRoutePoint;
7414 SelectedRoute = pSelectedActiveRoute;
7415 }
else if (pFoundVizRoutePoint) {
7416 FoundRoutePoint = pFoundVizRoutePoint;
7417 SelectedRoute = pSelectedVizRoute;
7420 FoundRoutePoint = pFirstVizPoint;
7422 if (SelectedRoute) {
7423 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7424 }
else if (FoundRoutePoint) {
7425 seltype |= SELTYPE_MARKPOINT;
7430 if (m_pFoundRoutePoint) {
7434 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7435 RefreshRect(wp_rect,
true);
7445 SelectableItemList SelList =
7446 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7448 if (NULL == SelectedRoute)
7451 wxSelectableItemListNode *node = SelList.GetFirst();
7456 if (pr->IsVisible()) {
7460 node = node->GetNext();
7464 if (SelectedRoute) {
7465 if (NULL == FoundRoutePoint)
7466 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7469 seltype |= SELTYPE_ROUTESEGMENT;
7474 if (pFindTrackSeg) {
7475 m_pSelectedTrack = NULL;
7477 SelectableItemList SelList =
7478 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7481 wxSelectableItemListNode *node = SelList.GetFirst();
7486 if (pt->IsVisible()) {
7487 m_pSelectedTrack = pt;
7490 node = node->GetNext();
7493 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7498 bool bseltc =
false;
7512 SelectableItemList SelList = pSelectTC->FindSelectionList(
7516 wxSelectableItemListNode *node = SelList.GetFirst();
7517 pFind = node->GetData();
7518 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7520 if (SelList.GetCount() > 1) {
7521 node = node->GetNext();
7523 pFind = node->GetData();
7525 if (pIDX_candidate->
IDX_type ==
'c') {
7526 pIDX_best_candidate = pIDX_candidate;
7530 node = node->GetNext();
7533 wxSelectableItemListNode *node = SelList.GetFirst();
7534 pFind = node->GetData();
7535 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7538 m_pIDXCandidate = pIDX_best_candidate;
7545 seltype |= SELTYPE_CURRENTPOINT;
7548 else if (pFindTide) {
7549 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7556 seltype |= SELTYPE_TIDEPOINT;
7561 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7564 auto rstruct = std::make_shared<PI_PointContext>();
7565 rstruct->object_type = OBJECT_CHART;
7566 rstruct->object_ident =
"";
7568 if (seltype == SELTYPE_AISTARGET) {
7569 rstruct->object_type = OBJECT_AISTARGET;
7571 val.Printf(
"%d", FoundAIS_MMSI);
7572 rstruct->object_ident = val.ToStdString();
7573 }
else if (seltype & SELTYPE_MARKPOINT) {
7574 if (FoundRoutePoint) {
7575 rstruct->object_type = OBJECT_ROUTEPOINT;
7576 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7578 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7579 if (SelectedRoute) {
7580 rstruct->object_type = OBJECT_ROUTESEGMENT;
7581 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7588void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7589 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7590 singleClickEventIsValid =
false;
7591 m_DoubleClickTimer->Stop();
7596bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7597 if (!m_bChartDragging && !m_bDrawingRoute) {
7602 if (m_Compass && m_Compass->IsShown()) {
7604 bool isInCompass = logicalRect.Contains(event.GetPosition());
7606 if (m_Compass->MouseEvent(event)) {
7607 cursor_region = CENTER;
7608 if (!g_btouch) SetCanvasCursor(event);
7614 if (m_notification_button && m_notification_button->IsShown()) {
7616 bool isinButton = logicalRect.Contains(event.GetPosition());
7618 SetCursor(*pCursorArrow);
7619 if (event.LeftDown()) HandleNotificationMouseClick();
7624 if (MouseEventToolbar(event))
return true;
7626 if (MouseEventChartBar(event))
return true;
7628 if (MouseEventMUIBar(event))
return true;
7630 if (MouseEventIENCBar(event))
return true;
7635void ChartCanvas::HandleNotificationMouseClick() {
7636 if (!m_NotificationsList) {
7640 m_NotificationsList->RecalculateSize();
7641 m_NotificationsList->Hide();
7644 if (m_NotificationsList->IsShown()) {
7645 m_NotificationsList->Hide();
7647 m_NotificationsList->RecalculateSize();
7648 m_NotificationsList->ReloadNotificationList();
7649 m_NotificationsList->Show();
7652bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7653 if (!g_bShowChartBar)
return false;
7655 if (!m_Piano->MouseEvent(event))
return false;
7657 cursor_region = CENTER;
7658 if (!g_btouch) SetCanvasCursor(event);
7662bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7663 if (!IsPrimaryCanvas())
return false;
7665 if (g_MainToolbar) {
7666 if (!g_MainToolbar->MouseEvent(event))
7669 g_MainToolbar->RefreshToolbar();
7672 cursor_region = CENTER;
7673 if (!g_btouch) SetCanvasCursor(event);
7677bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7678 if (!IsPrimaryCanvas())
return false;
7680 if (g_iENCToolbar) {
7681 if (!g_iENCToolbar->MouseEvent(event))
7684 g_iENCToolbar->RefreshToolbar();
7691bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7693 if (!m_muiBar->MouseEvent(event))
return false;
7696 cursor_region = CENTER;
7697 if (!g_btouch) SetCanvasCursor(event);
7709 event.GetPosition(&x, &y);
7711 x *= m_displayScale;
7712 y *= m_displayScale;
7714 m_MouseDragging =
event.Dragging();
7720 if (event.Dragging()) {
7721 if ((x == mouse_x) && (y == mouse_y))
return true;
7727 mouse_leftisdown =
event.LeftDown();
7731 cursor_region = CENTER;
7735 if (m_Compass && m_Compass->IsShown() &&
7736 m_Compass->
GetRect().Contains(event.GetPosition())) {
7737 cursor_region = CENTER;
7738 }
else if (x > xr_margin) {
7739 cursor_region = MID_RIGHT;
7740 }
else if (x < xl_margin) {
7741 cursor_region = MID_LEFT;
7742 }
else if (y > yb_margin - chartbar_height &&
7743 y < m_canvas_height - chartbar_height) {
7744 cursor_region = MID_TOP;
7745 }
else if (y < yt_margin) {
7746 cursor_region = MID_BOT;
7748 cursor_region = CENTER;
7751 if (!g_btouch) SetCanvasCursor(event);
7755 leftIsDown =
event.LeftDown();
7758 if (event.LeftDown()) {
7759 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7762 g_bTempShowMenuBar =
false;
7763 parent_frame->ApplyGlobalSettings(
false);
7771 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7772 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7776 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7777 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7780 event.SetEventObject(
this);
7781 if (SendMouseEventToPlugins(event))
7788 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7789 StartChartDragInertia();
7792 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7794 if (m_DoubleClickTimer->IsRunning()) {
7795 m_DoubleClickTimer->Stop();
7800 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7801 singleClickEvent = event;
7802 singleClickEventIsValid =
true;
7811 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7812 if (g_click_stop > 0) {
7820 if (GetUpMode() == COURSE_UP_MODE) {
7821 m_b_rot_hidef =
false;
7822 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7824 pRotDefTimer->Stop();
7827 bool bRoll = !g_btouch;
7832 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7833 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7834 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7835 m_RolloverPopupTimer.Start(
7839 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7843 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7852#if !defined(__WXGTK__) && !defined(__WXQT__)
7860 if ((x >= 0) && (y >= 0))
7865 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7866 wxPoint p = ClientToScreen(wxPoint(x, y));
7872 if (m_routeState >= 2) {
7875 m_bDrawingRoute =
true;
7877 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7882 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7885 m_bDrawingRoute =
true;
7887 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7900#if defined(__WXMAC__) || defined(__ANDROID__)
7904 wxClientDC cdc(GetParent());
7916 if (m_pSelectedRoute) {
7918 m_pSelectedRoute->DeSelectRoute();
7920 if (g_bopengl && m_glcc) {
7925 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7928 if (m_pFoundRoutePoint) {
7936 if (g_btouch && m_pRoutePointEditTarget) {
7939 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7944 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7945 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7946 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7947 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7951 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7954 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7960 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7963 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7964 seltype |= SELTYPE_AISTARGET;
7969 m_pFoundRoutePoint = NULL;
7974 Route *pSelectedActiveRoute = NULL;
7975 Route *pSelectedVizRoute = NULL;
7979 SelectableItemList SelList =
7980 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7981 wxSelectableItemListNode *node = SelList.GetFirst();
7991 bool brp_viz =
false;
7993 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7995 if (pr->IsVisible()) {
8000 if (!brp_viz && prp->IsShared())
8002 brp_viz = prp->IsVisible();
8005 brp_viz = prp->IsVisible();
8007 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8012 m_pSelectedRoute = NULL;
8014 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8017 pSelectedActiveRoute = pr;
8018 pFoundActiveRoutePoint = prp;
8023 if (NULL == pSelectedVizRoute) {
8024 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8026 if (pr->IsVisible()) {
8027 pSelectedVizRoute = pr;
8028 pFoundVizRoutePoint = prp;
8034 delete proute_array;
8036 node = node->GetNext();
8040 if (pFoundActiveRoutePoint) {
8041 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8042 m_pSelectedRoute = pSelectedActiveRoute;
8043 }
else if (pFoundVizRoutePoint) {
8044 m_pFoundRoutePoint = pFoundVizRoutePoint;
8045 m_pSelectedRoute = pSelectedVizRoute;
8048 m_pFoundRoutePoint = pFirstVizPoint;
8050 if (m_pSelectedRoute) {
8051 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8052 }
else if (m_pFoundRoutePoint) {
8053 seltype |= SELTYPE_MARKPOINT;
8057 if (m_pFoundRoutePoint) {
8061 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8062 RefreshRect(wp_rect,
true);
8071 SelectableItemList SelList =
8072 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8074 if (NULL == m_pSelectedRoute)
8077 wxSelectableItemListNode *node = SelList.GetFirst();
8082 if (pr->IsVisible()) {
8083 m_pSelectedRoute = pr;
8086 node = node->GetNext();
8090 if (m_pSelectedRoute) {
8091 if (NULL == m_pFoundRoutePoint)
8092 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8097 if (g_bopengl && m_glcc) {
8102 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8104 seltype |= SELTYPE_ROUTESEGMENT;
8108 if (pFindTrackSeg) {
8109 m_pSelectedTrack = NULL;
8111 SelectableItemList SelList =
8112 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8115 wxSelectableItemListNode *node = SelList.GetFirst();
8120 if (pt->IsVisible()) {
8121 m_pSelectedTrack = pt;
8124 node = node->GetNext();
8126 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8141 SelectableItemList SelList =
8142 pSelectTC->FindSelectionList(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8145 wxSelectableItemListNode *node = SelList.GetFirst();
8146 pFind = node->GetData();
8147 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8149 if (SelList.GetCount() > 1) {
8150 node = node->GetNext();
8152 pFind = node->GetData();
8154 if (pIDX_candidate->
IDX_type ==
'c') {
8155 pIDX_best_candidate = pIDX_candidate;
8159 node = node->GetNext();
8162 wxSelectableItemListNode *node = SelList.GetFirst();
8163 pFind = node->GetData();
8164 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8167 m_pIDXCandidate = pIDX_best_candidate;
8168 seltype |= SELTYPE_CURRENTPOINT;
8171 else if (pFindTide) {
8172 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8173 seltype |= SELTYPE_TIDEPOINT;
8177 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8182void ChartCanvas::CallPopupMenu(
int x,
int y) {
8186 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8194 if (SELTYPE_CURRENTPOINT == seltype) {
8200 if (SELTYPE_TIDEPOINT == seltype) {
8206 InvokeCanvasMenu(x, y, seltype);
8209 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8213 m_pSelectedRoute = NULL;
8215 if (m_pFoundRoutePoint) {
8216 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8219 m_pFoundRoutePoint = NULL;
8225bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8233 event.GetPosition(&x, &y);
8239 SelectRadius = g_Platform->GetSelectRadiusPix() /
8240 (m_true_scale_ppm * 1852 * 60);
8247 if (event.LeftDClick() && (cursor_region == CENTER)) {
8248 m_DoubleClickTimer->Start();
8249 singleClickEventIsValid =
false;
8258 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8261 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8262 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8263 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8269 SelectableItemList rpSelList =
8270 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8271 wxSelectableItemListNode *node = rpSelList.GetFirst();
8272 bool b_onRPtarget =
false;
8276 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8277 b_onRPtarget =
true;
8280 node = node->GetNext();
8285 if (m_pRoutePointEditTarget) {
8287 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8293 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8296 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8297 m_pRoutePointEditTarget = NULL;
8298 RefreshRect(wp_rect,
true);
8302 node = rpSelList.GetFirst();
8307 wxArrayPtrVoid *proute_array =
8312 bool brp_viz =
false;
8314 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8316 if (pr->IsVisible()) {
8321 delete proute_array;
8325 brp_viz = frp->IsVisible();
8327 brp_viz = frp->IsVisible();
8330 ShowMarkPropertiesDialog(frp);
8338 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8342 if (pr->IsVisible()) {
8343 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8348 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8352 if (pt->IsVisible()) {
8353 ShowTrackPropertiesDialog(pt);
8360 ShowObjectQueryWindow(x, y, zlat, zlon);
8365 if (event.LeftDown()) {
8381 bool appending =
false;
8382 bool inserting =
false;
8385 SetCursor(*pCursorPencil);
8389 m_bRouteEditing =
true;
8391 if (m_routeState == 1) {
8392 m_pMouseRoute =
new Route();
8393 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8394 pRouteList->Append(m_pMouseRoute);
8403 double nearby_radius_meters =
8404 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8407 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8408 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8409 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8410 wxArrayPtrVoid *proute_array =
8415 bool brp_viz =
false;
8417 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8419 if (pr->IsVisible()) {
8424 delete proute_array;
8426 pNearbyPoint->IsShared())
8429 pNearbyPoint->IsVisible();
8431 brp_viz = pNearbyPoint->IsVisible();
8434 wxString msg = _(
"Use nearby waypoint?");
8436 const bool noname(pNearbyPoint->GetName() ==
"");
8439 _(
"Use nearby nameless waypoint and name it M with"
8440 " a unique number?");
8443 m_FinishRouteOnKillFocus =
false;
8445 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8446 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8447 m_FinishRouteOnKillFocus =
true;
8448 if (dlg_return == wxID_YES) {
8450 if (m_pMouseRoute) {
8451 int last_wp_num = m_pMouseRoute->GetnPoints();
8453 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8454 wxString wp_name = wxString::Format(
8455 "M%002i-%s", last_wp_num + 1, guid_short);
8456 pNearbyPoint->SetName(wp_name);
8458 pNearbyPoint->SetName(
"WPXX");
8460 pMousePoint = pNearbyPoint;
8463 if (m_routeState > 1)
8464 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8465 Undo_HasParent, NULL);
8468 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8469 bool procede =
false;
8473 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8479 m_FinishRouteOnKillFocus =
false;
8485 _(
"Insert first part of this route in the new route?");
8486 if (tail->GetIndexOf(pMousePoint) ==
8489 dmsg = _(
"Insert this route in the new route?");
8491 if (tail->GetIndexOf(pMousePoint) != 1) {
8492 dlg_return = OCPNMessageBox(
8493 this, dmsg, _(
"OpenCPN Route Create"),
8494 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8495 m_FinishRouteOnKillFocus =
true;
8497 if (dlg_return == wxID_YES) {
8504 _(
"Append last part of this route to the new route?");
8505 if (tail->GetIndexOf(pMousePoint) == 1)
8507 "Append this route to the new route?");
8512 if (tail->GetLastPoint() != pMousePoint) {
8513 dlg_return = OCPNMessageBox(
8514 this, dmsg, _(
"OpenCPN Route Create"),
8515 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8516 m_FinishRouteOnKillFocus =
true;
8518 if (dlg_return == wxID_YES) {
8529 if (!FindRouteContainingWaypoint(pMousePoint))
8530 pMousePoint->SetShared(
true);
8535 if (NULL == pMousePoint) {
8536 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8538 pMousePoint->SetNameShown(
false);
8542 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8544 if (m_routeState > 1)
8545 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8546 Undo_IsOrphanded, NULL);
8549 if (m_pMouseRoute) {
8550 if (m_routeState == 1) {
8552 m_pMouseRoute->AddPoint(pMousePoint);
8556 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8557 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8558 &rhumbBearing, &rhumbDist);
8559 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8560 rlat, &gcDist, &gcBearing, NULL);
8561 double gcDistNM = gcDist / 1852.0;
8564 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8565 pow(rhumbDist - gcDistNM - 1, 0.5);
8568 msg << _(
"For this leg the Great Circle route is ")
8569 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8570 << _(
" shorter than rhumbline.\n\n")
8571 << _(
"Would you like include the Great Circle routing points "
8574 m_FinishRouteOnKillFocus =
false;
8575 m_disable_edge_pan =
true;
8578 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8579 wxYES_NO | wxNO_DEFAULT);
8581 m_disable_edge_pan =
false;
8582 m_FinishRouteOnKillFocus =
true;
8584 if (answer == wxID_YES) {
8586 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8587 wxRealPoint gcCoord;
8589 for (
int i = 1; i <= segmentCount; i++) {
8590 double fraction = (double)i * (1.0 / (
double)segmentCount);
8591 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8592 gcDist * fraction, gcBearing,
8593 &gcCoord.x, &gcCoord.y, NULL);
8595 if (i < segmentCount) {
8596 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8598 gcPoint->SetNameShown(
false);
8600 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8602 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8605 gcPoint = pMousePoint;
8608 m_pMouseRoute->AddPoint(gcPoint);
8609 pSelect->AddSelectableRouteSegment(
8610 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8611 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8612 prevGcPoint = gcPoint;
8615 undo->CancelUndoableAction(
true);
8618 m_pMouseRoute->AddPoint(pMousePoint);
8619 pSelect->AddSelectableRouteSegment(
8620 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8621 pMousePoint, m_pMouseRoute);
8622 undo->AfterUndoableAction(m_pMouseRoute);
8626 m_pMouseRoute->AddPoint(pMousePoint);
8627 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8628 rlon, m_prev_pMousePoint,
8629 pMousePoint, m_pMouseRoute);
8630 undo->AfterUndoableAction(m_pMouseRoute);
8636 m_prev_pMousePoint = pMousePoint;
8644 int connect = tail->GetIndexOf(pMousePoint);
8649 int length = tail->GetnPoints();
8654 start = connect + 1;
8659 m_pMouseRoute->RemovePoint(
8663 for (i = start; i <= stop; i++) {
8664 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8667 m_pMouseRoute->GetnPoints();
8669 gFrame->RefreshAllCanvas();
8673 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8675 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8676 m_pMouseRoute->FinalizeForRendering();
8678 gFrame->RefreshAllCanvas();
8682 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8684 SetCursor(*pCursorPencil);
8686 if (!m_pMeasureRoute) {
8687 m_pMeasureRoute =
new Route();
8688 pRouteList->Append(m_pMeasureRoute);
8691 if (m_nMeasureState == 1) {
8698 wxEmptyString, wxEmptyString);
8700 pMousePoint->SetShowWaypointRangeRings(
false);
8702 m_pMeasureRoute->AddPoint(pMousePoint);
8706 m_prev_pMousePoint = pMousePoint;
8710 gFrame->RefreshAllCanvas();
8715 FindRoutePointsAtCursor(SelectRadius,
true);
8720 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8728 if (ret)
return true;
8731 if (event.Dragging()) {
8736 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8738 SelectableItemList SelList = pSelect->FindSelectionList(
8740 wxSelectableItemListNode *node = SelList.GetFirst();
8742 pFind = node->GetData();
8744 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8745 node = node->GetNext();
8750 if (m_pRoutePointEditTarget &&
8751 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8753 SelectableItemList SelList = pSelect->FindSelectionList(
8755 wxSelectableItemListNode *node = SelList.GetFirst();
8757 pFind = node->GetData();
8759 if (m_pRoutePointEditTarget == frp) {
8760 m_bIsInRadius =
true;
8763 node = node->GetNext();
8766 if (!m_dragoffsetSet) {
8768 .PresetDragOffset(
this, mouse_x, mouse_y);
8769 m_dragoffsetSet =
true;
8774 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8775 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8777 if (NULL == g_pMarkInfoDialog) {
8778 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8779 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8780 DraggingAllowed =
false;
8782 if (m_pRoutePointEditTarget &&
8783 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8784 DraggingAllowed =
false;
8786 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8788 if (DraggingAllowed) {
8789 if (!undo->InUndoableAction()) {
8790 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8791 Undo_NeedsCopy, m_pFoundPoint);
8797 if (!g_bopengl && m_pEditRouteArray) {
8798 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8799 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8804 if (g_pRouteMan->IsRouteValid(pr)) {
8806 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8807 pre_rect.Union(route_rect);
8815 if (CheckEdgePan(x, y,
true, 5, 2))
8823 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8825 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8826 m_pRoutePointEditTarget,
8827 SELTYPE_DRAGHANDLE);
8828 m_pFoundPoint->m_slat =
8829 m_pRoutePointEditTarget->m_lat;
8830 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8832 m_pRoutePointEditTarget->m_lat =
8834 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8835 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8836 m_pFoundPoint->m_slat =
8838 m_pFoundPoint->m_slon = new_cursor_lon;
8842 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8843 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8844 g_pMarkInfoDialog->UpdateProperties(
true);
8854 if (m_pEditRouteArray) {
8855 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8857 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8858 if (g_pRouteMan->IsRouteValid(pr)) {
8860 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8861 post_rect.Union(route_rect);
8867 pre_rect.Union(post_rect);
8868 RefreshRect(pre_rect,
false);
8870 gFrame->RefreshCanvasOther(
this);
8871 m_bRoutePoinDragging =
true;
8876 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8877 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8879 if (NULL == g_pMarkInfoDialog) {
8880 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8881 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8882 DraggingAllowed =
false;
8884 if (m_pRoutePointEditTarget &&
8885 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8886 DraggingAllowed =
false;
8888 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8890 if (DraggingAllowed) {
8891 if (!undo->InUndoableAction()) {
8892 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8893 Undo_NeedsCopy, m_pFoundPoint);
8901 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8902 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8904 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8905 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8907 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8913 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8914 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8915 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8916 (
int)(lppmax - (pre_rect.height / 2)));
8924 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8927 m_pRoutePointEditTarget,
8928 SELTYPE_DRAGHANDLE);
8929 m_pFoundPoint->m_slat =
8930 m_pRoutePointEditTarget->m_lat;
8931 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8933 m_pRoutePointEditTarget->m_lat =
8936 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8942 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8943 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8944 g_pMarkInfoDialog->UpdateProperties(
true);
8949 if (!g_btouch) InvalidateGL();
8955 .CalculateDCRect(m_dc_route,
this, &post_rect);
8956 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8957 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8958 (
int)(lppmax - (post_rect.height / 2)));
8961 pre_rect.Union(post_rect);
8962 RefreshRect(pre_rect,
false);
8964 gFrame->RefreshCanvasOther(
this);
8965 m_bRoutePoinDragging =
true;
8970 if (ret)
return true;
8973 if (event.LeftUp()) {
8974 bool b_startedit_route =
false;
8975 m_dragoffsetSet =
false;
8978 m_bChartDragging =
false;
8979 m_bIsInRadius =
false;
8984 m_bedge_pan =
false;
8989 bool appending =
false;
8990 bool inserting =
false;
8996 if (m_pRoutePointEditTarget) {
9002 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9003 RefreshRect(wp_rect,
true);
9005 m_pRoutePointEditTarget = NULL;
9007 m_bRouteEditing =
true;
9009 if (m_routeState == 1) {
9010 m_pMouseRoute =
new Route();
9011 m_pMouseRoute->SetHiLite(50);
9012 pRouteList->Append(m_pMouseRoute);
9015 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9022 double nearby_radius_meters =
9023 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9026 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9027 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9028 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9031 m_FinishRouteOnKillFocus =
9033 dlg_return = OCPNMessageBox(
9034 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9035 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9036 m_FinishRouteOnKillFocus =
true;
9038 dlg_return = wxID_YES;
9040 if (dlg_return == wxID_YES) {
9041 pMousePoint = pNearbyPoint;
9044 if (m_routeState > 1)
9045 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9046 Undo_HasParent, NULL);
9047 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9049 bool procede =
false;
9053 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9059 m_FinishRouteOnKillFocus =
false;
9060 if (m_routeState == 1) {
9064 _(
"Insert first part of this route in the new route?");
9065 if (tail->GetIndexOf(pMousePoint) ==
9068 dmsg = _(
"Insert this route in the new route?");
9070 if (tail->GetIndexOf(pMousePoint) != 1) {
9072 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9073 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9074 m_FinishRouteOnKillFocus =
true;
9076 if (dlg_return == wxID_YES) {
9083 _(
"Append last part of this route to the new route?");
9084 if (tail->GetIndexOf(pMousePoint) == 1)
9086 "Append this route to the new route?");
9090 if (tail->GetLastPoint() != pMousePoint) {
9092 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9093 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9094 m_FinishRouteOnKillFocus =
true;
9096 if (dlg_return == wxID_YES) {
9107 if (!FindRouteContainingWaypoint(pMousePoint))
9108 pMousePoint->SetShared(
true);
9112 if (NULL == pMousePoint) {
9113 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9115 pMousePoint->SetNameShown(
false);
9117 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9119 if (m_routeState > 1)
9120 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9121 Undo_IsOrphanded, NULL);
9124 if (m_routeState == 1) {
9126 m_pMouseRoute->AddPoint(pMousePoint);
9127 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9131 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9132 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9133 &rhumbBearing, &rhumbDist);
9134 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9135 &gcDist, &gcBearing, NULL);
9136 double gcDistNM = gcDist / 1852.0;
9139 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9140 pow(rhumbDist - gcDistNM - 1, 0.5);
9143 msg << _(
"For this leg the Great Circle route is ")
9144 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9145 << _(
" shorter than rhumbline.\n\n")
9146 << _(
"Would you like include the Great Circle routing points "
9150 m_FinishRouteOnKillFocus =
false;
9151 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9152 wxYES_NO | wxNO_DEFAULT);
9153 m_FinishRouteOnKillFocus =
true;
9155 int answer = wxID_NO;
9158 if (answer == wxID_YES) {
9160 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9161 wxRealPoint gcCoord;
9163 for (
int i = 1; i <= segmentCount; i++) {
9164 double fraction = (double)i * (1.0 / (
double)segmentCount);
9165 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9166 gcDist * fraction, gcBearing,
9167 &gcCoord.x, &gcCoord.y, NULL);
9169 if (i < segmentCount) {
9170 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9172 gcPoint->SetNameShown(
false);
9173 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9176 gcPoint = pMousePoint;
9179 m_pMouseRoute->AddPoint(gcPoint);
9180 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9182 pSelect->AddSelectableRouteSegment(
9183 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9184 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9185 prevGcPoint = gcPoint;
9188 undo->CancelUndoableAction(
true);
9191 m_pMouseRoute->AddPoint(pMousePoint);
9192 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9193 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9194 rlon, m_prev_pMousePoint,
9195 pMousePoint, m_pMouseRoute);
9196 undo->AfterUndoableAction(m_pMouseRoute);
9200 m_pMouseRoute->AddPoint(pMousePoint);
9201 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9203 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9204 rlon, m_prev_pMousePoint,
9205 pMousePoint, m_pMouseRoute);
9206 undo->AfterUndoableAction(m_pMouseRoute);
9212 m_prev_pMousePoint = pMousePoint;
9219 int connect = tail->GetIndexOf(pMousePoint);
9224 int length = tail->GetnPoints();
9229 start = connect + 1;
9234 m_pMouseRoute->RemovePoint(
9238 for (i = start; i <= stop; i++) {
9239 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9242 m_pMouseRoute->GetnPoints();
9244 gFrame->RefreshAllCanvas();
9248 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9250 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9251 m_pMouseRoute->FinalizeForRendering();
9256 }
else if (m_bMeasure_Active && m_nMeasureState)
9259 m_bedge_pan =
false;
9263 if (m_nMeasureState == 1) {
9264 m_pMeasureRoute =
new Route();
9265 pRouteList->Append(m_pMeasureRoute);
9270 if (m_pMeasureRoute) {
9273 wxEmptyString, wxEmptyString);
9276 m_pMeasureRoute->AddPoint(pMousePoint);
9280 m_prev_pMousePoint = pMousePoint;
9282 m_pMeasureRoute->GetnPoints();
9286 CancelMeasureRoute();
9292 bool bSelectAllowed =
true;
9293 if (NULL == g_pMarkInfoDialog) {
9294 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9295 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9296 bSelectAllowed =
false;
9303 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9305 if (bSelectAllowed) {
9306 bool b_was_editing_mark = m_bMarkEditing;
9307 bool b_was_editing_route = m_bRouteEditing;
9308 FindRoutePointsAtCursor(SelectRadius,
9314 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9315 m_pRoutePointEditTarget = NULL;
9317 if (!b_was_editing_route) {
9318 if (m_pEditRouteArray) {
9319 b_startedit_route =
true;
9323 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9324 m_pTrackRolloverWin->IsActive(
false);
9326 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9327 m_pRouteRolloverWin->IsActive(
false);
9331 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9333 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9338 if (g_pRouteMan->IsRouteValid(pr)) {
9341 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9342 pre_rect.Union(route_rect);
9345 RefreshRect(pre_rect,
true);
9348 b_startedit_route =
false;
9352 if (m_pRoutePointEditTarget) {
9353 if (b_was_editing_mark ||
9354 b_was_editing_route) {
9355 if (m_lastRoutePointEditTarget) {
9359 .EnableDragHandle(
false);
9360 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9361 SELTYPE_DRAGHANDLE);
9365 if (m_pRoutePointEditTarget) {
9368 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9369 wxPoint2DDouble dragHandlePoint =
9371 .GetDragHandlePoint(
this);
9372 pSelect->AddSelectablePoint(
9373 dragHandlePoint.m_y, dragHandlePoint.m_x,
9374 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9377 if (m_lastRoutePointEditTarget) {
9381 .EnableDragHandle(
false);
9382 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9383 SELTYPE_DRAGHANDLE);
9386 wxArrayPtrVoid *lastEditRouteArray =
9388 m_lastRoutePointEditTarget);
9389 if (lastEditRouteArray) {
9390 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9392 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9393 if (g_pRouteMan->IsRouteValid(pr)) {
9397 delete lastEditRouteArray;
9408 if (m_lastRoutePointEditTarget) {
9411 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9412 RefreshRect(wp_rect,
true);
9415 if (m_pRoutePointEditTarget) {
9418 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9419 RefreshRect(wp_rect,
true);
9428 bool b_start_rollover =
false;
9429 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9430 SelectItem *pFind = pSelectAIS->FindSelection(
9432 if (pFind) b_start_rollover =
true;
9435 if (!b_start_rollover && !b_startedit_route) {
9436 SelectableItemList SelList = pSelect->FindSelectionList(
9438 wxSelectableItemListNode *node = SelList.GetFirst();
9444 if (pr && pr->IsVisible()) {
9445 b_start_rollover =
true;
9448 node = node->GetNext();
9452 if (!b_start_rollover && !b_startedit_route) {
9453 SelectableItemList SelList = pSelect->FindSelectionList(
9455 wxSelectableItemListNode *node = SelList.GetFirst();
9461 if (tr && tr->IsVisible()) {
9462 b_start_rollover =
true;
9465 node = node->GetNext();
9469 if (b_start_rollover)
9470 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9474 bool appending =
false;
9475 bool inserting =
false;
9477 if (m_bRouteEditing ) {
9479 if (m_pRoutePointEditTarget) {
9485 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9486 double nearby_radius_meters =
9487 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9488 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9489 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9490 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9492 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9496 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9498 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9513 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9518 OCPNMessageBox(
this,
9519 _(
"Replace this RoutePoint by the nearby "
9521 _(
"OpenCPN RoutePoint change"),
9522 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9523 if (dlg_return == wxID_YES) {
9528 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9531 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9533 if (tail && current && (tail != current)) {
9535 connect = tail->GetIndexOf(pNearbyPoint);
9536 int index_current_route =
9537 current->GetIndexOf(m_pRoutePointEditTarget);
9538 index_last = current->GetIndexOf(current->GetLastPoint());
9539 dlg_return1 = wxID_NO;
9541 index_current_route) {
9543 if (connect != tail->GetnPoints()) {
9546 _(
"Last part of route to be appended to dragged "
9550 _(
"Full route to be appended to dragged route?");
9552 dlg_return1 = OCPNMessageBox(
9553 this, dmsg, _(
"OpenCPN Route Create"),
9554 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9555 if (dlg_return1 == wxID_YES) {
9559 }
else if (index_current_route ==
9564 _(
"First part of route to be inserted into dragged "
9566 if (connect == tail->GetnPoints())
9568 "Full route to be inserted into dragged route?");
9570 dlg_return1 = OCPNMessageBox(
9571 this, dmsg, _(
"OpenCPN Route Create"),
9572 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9573 if (dlg_return1 == wxID_YES) {
9580 if (m_pRoutePointEditTarget->IsShared()) {
9582 dlg_return = OCPNMessageBox(
9584 _(
"Do you really want to delete and replace this "
9586 "\n" + _(
"which has been created manually?"),
9587 (
"OpenCPN RoutePoint warning"),
9588 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9591 if (dlg_return == wxID_YES) {
9592 pMousePoint = pNearbyPoint;
9594 pMousePoint->SetShared(
true);
9604 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9606 if (m_pEditRouteArray) {
9607 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9609 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9610 if (g_pRouteMan->IsRouteValid(pr)) {
9616 pSelect->DeleteAllSelectableRoutePoints(pr);
9617 pSelect->DeleteAllSelectableRouteSegments(pr);
9622 pSelect->AddAllSelectableRouteSegments(pr);
9623 pSelect->AddAllSelectableRoutePoints(pr);
9625 pr->FinalizeForRendering();
9626 pr->UpdateSegmentDistances();
9627 if (m_bRoutePoinDragging) {
9629 NavObj_dB::GetInstance().UpdateRoute(pr);
9636 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9637 if (m_pEditRouteArray) {
9638 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9640 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9641 if (g_pRouteMan->IsRouteValid(pr)) {
9642 if (pRoutePropDialog->GetRoute() == pr) {
9643 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9659 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9662 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9663 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9664 g_pMarkInfoDialog->Hide();
9666 delete m_pRoutePointEditTarget;
9667 m_lastRoutePointEditTarget = NULL;
9668 m_pRoutePointEditTarget = NULL;
9669 undo->AfterUndoableAction(pMousePoint);
9670 undo->InvalidateUndo();
9675 else if (m_bMarkEditing) {
9676 if (m_pRoutePointEditTarget)
9677 if (m_bRoutePoinDragging) {
9679 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9683 if (m_pRoutePointEditTarget)
9684 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9686 if (!m_pRoutePointEditTarget) {
9687 delete m_pEditRouteArray;
9688 m_pEditRouteArray = NULL;
9689 m_bRouteEditing =
false;
9691 m_bRoutePoinDragging =
false;
9698 int length = tail->GetnPoints();
9699 for (
int i = connect + 1; i <= length; i++) {
9700 current->AddPointAndSegment(tail->GetPoint(i),
false);
9703 gFrame->RefreshAllCanvas();
9706 current->FinalizeForRendering();
9712 pSelect->DeleteAllSelectableRoutePoints(current);
9713 pSelect->DeleteAllSelectableRouteSegments(current);
9714 for (
int i = 1; i < connect; i++) {
9715 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9717 pSelect->AddAllSelectableRouteSegments(current);
9718 pSelect->AddAllSelectableRoutePoints(current);
9719 current->FinalizeForRendering();
9725 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9726 if (m_pEditRouteArray) {
9727 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9728 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9729 if (g_pRouteMan->IsRouteValid(pr)) {
9730 if (pRoutePropDialog->GetRoute() == pr) {
9731 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9741 if (m_bRouteEditing) {
9744 bool appending =
false;
9745 bool inserting =
false;
9748 if (m_pRoutePointEditTarget) {
9749 m_pRoutePointEditTarget->
m_bBlink =
false;
9753 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9754 double nearby_radius_meters =
9755 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9756 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9757 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9758 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9760 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9761 bool duplicate =
false;
9763 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9765 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9780 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9785 OCPNMessageBox(
this,
9786 _(
"Replace this RoutePoint by the nearby "
9788 _(
"OpenCPN RoutePoint change"),
9789 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9790 if (dlg_return == wxID_YES) {
9794 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9797 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9799 if (tail && current && (tail != current)) {
9801 connect = tail->GetIndexOf(pNearbyPoint);
9802 int index_current_route =
9803 current->GetIndexOf(m_pRoutePointEditTarget);
9804 index_last = current->GetIndexOf(current->GetLastPoint());
9805 dlg_return1 = wxID_NO;
9807 index_current_route) {
9809 if (connect != tail->GetnPoints()) {
9812 _(
"Last part of route to be appended to dragged "
9816 _(
"Full route to be appended to dragged route?");
9818 dlg_return1 = OCPNMessageBox(
9819 this, dmsg, _(
"OpenCPN Route Create"),
9820 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9821 if (dlg_return1 == wxID_YES) {
9825 }
else if (index_current_route ==
9830 _(
"First part of route to be inserted into dragged "
9832 if (connect == tail->GetnPoints())
9834 "Full route to be inserted into dragged route?");
9836 dlg_return1 = OCPNMessageBox(
9837 this, dmsg, _(
"OpenCPN Route Create"),
9838 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9839 if (dlg_return1 == wxID_YES) {
9846 if (m_pRoutePointEditTarget->IsShared()) {
9847 dlg_return = wxID_NO;
9848 dlg_return = OCPNMessageBox(
9850 _(
"Do you really want to delete and replace this "
9852 "\n" + _(
"which has been created manually?"),
9853 (
"OpenCPN RoutePoint warning"),
9854 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9857 if (dlg_return == wxID_YES) {
9858 pMousePoint = pNearbyPoint;
9860 pMousePoint->SetShared(
true);
9870 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9872 if (m_pEditRouteArray) {
9873 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9875 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9876 if (g_pRouteMan->IsRouteValid(pr)) {
9881 pSelect->DeleteAllSelectableRoutePoints(pr);
9882 pSelect->DeleteAllSelectableRouteSegments(pr);
9887 pSelect->AddAllSelectableRouteSegments(pr);
9888 pSelect->AddAllSelectableRoutePoints(pr);
9890 pr->FinalizeForRendering();
9891 pr->UpdateSegmentDistances();
9894 if (m_bRoutePoinDragging) {
9899 NavObj_dB::GetInstance().UpdateRoutePoint(
9900 m_pRoutePointEditTarget);
9902 NavObj_dB::GetInstance().UpdateRoute(pr);
9914 int length = tail->GetnPoints();
9915 for (
int i = connect + 1; i <= length; i++) {
9916 current->AddPointAndSegment(tail->GetPoint(i),
false);
9920 gFrame->RefreshAllCanvas();
9923 current->FinalizeForRendering();
9929 pSelect->DeleteAllSelectableRoutePoints(current);
9930 pSelect->DeleteAllSelectableRouteSegments(current);
9931 for (
int i = 1; i < connect; i++) {
9932 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9934 pSelect->AddAllSelectableRouteSegments(current);
9935 pSelect->AddAllSelectableRoutePoints(current);
9936 current->FinalizeForRendering();
9942 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9943 if (m_pEditRouteArray) {
9944 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9946 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9947 if (g_pRouteMan->IsRouteValid(pr)) {
9948 if (pRoutePropDialog->GetRoute() == pr) {
9949 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9958 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9961 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9962 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9963 g_pMarkInfoDialog->Hide();
9965 delete m_pRoutePointEditTarget;
9966 m_lastRoutePointEditTarget = NULL;
9967 undo->AfterUndoableAction(pMousePoint);
9968 undo->InvalidateUndo();
9973 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9976 delete m_pEditRouteArray;
9977 m_pEditRouteArray = NULL;
9981 m_bRouteEditing =
false;
9982 m_pRoutePointEditTarget = NULL;
9988 else if (m_bMarkEditing) {
9989 if (m_pRoutePointEditTarget) {
9990 if (m_bRoutePoinDragging) {
9992 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9994 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9999 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10001 RefreshRect(wp_rect,
true);
10004 m_pRoutePointEditTarget = NULL;
10005 m_bMarkEditing =
false;
10010 else if (leftIsDown) {
10011 leftIsDown =
false;
10015 if (!m_bChartDragging && !m_bMeasure_Active) {
10017 m_bChartDragging =
false;
10021 m_bRoutePoinDragging =
false;
10024 if (ret)
return true;
10027 if (event.RightDown()) {
10038 m_FinishRouteOnKillFocus =
false;
10039 CallPopupMenu(mx, my);
10040 m_FinishRouteOnKillFocus =
true;
10051 if (event.ShiftDown()) {
10055 event.GetPosition(&x, &y);
10057 x *= m_displayScale;
10058 y *= m_displayScale;
10064 int wheel_dir =
event.GetWheelRotation();
10067 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10068 wheel_dir = wheel_dir > 0 ? 1 : -1;
10070 double factor = g_mouse_zoom_sensitivity;
10071 if (wheel_dir < 0) factor = 1 / factor;
10074 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10075 if (wheel_dir == m_last_wheel_dir) {
10076 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10081 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10082 m_wheelstopwatch.Start(0);
10087 m_last_wheel_dir = wheel_dir;
10092 if (event.LeftDown()) {
10099 last_drag.x = x, last_drag.y = y;
10100 panleftIsDown =
true;
10103 if (event.LeftUp()) {
10104 if (panleftIsDown) {
10106 panleftIsDown =
false;
10109 if (!m_bChartDragging && !m_bMeasure_Active) {
10110 switch (cursor_region) {
10132 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10137 m_bChartDragging =
false;
10143 if (event.Dragging() && event.LeftIsDown()) {
10161 struct timespec now;
10162 clock_gettime(CLOCK_MONOTONIC, &now);
10163 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10165 if (
false == m_bChartDragging) {
10167 last_drag.x = x, last_drag.y = y;
10168 m_bChartDragging =
true;
10169 m_chart_drag_total_time = 0;
10170 m_chart_drag_total_x = 0;
10171 m_chart_drag_total_y = 0;
10172 m_inertia_last_drag_x = x;
10173 m_inertia_last_drag_y = y;
10174 m_drag_vec_x.clear();
10175 m_drag_vec_y.clear();
10176 m_drag_vec_t.clear();
10177 m_last_drag_time = tnow;
10181 uint64_t delta_t = tnow - m_last_drag_time;
10182 double delta_tf = delta_t / 1e9;
10184 m_chart_drag_total_time += delta_tf;
10185 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10186 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10188 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10189 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10190 m_drag_vec_t.push_back(delta_tf);
10192 m_inertia_last_drag_x = x;
10193 m_inertia_last_drag_y = y;
10194 m_last_drag_time = tnow;
10196 if ((last_drag.x != x) || (last_drag.y != y)) {
10197 if (!m_routeState) {
10200 m_bChartDragging =
true;
10201 StartTimedMovement();
10202 m_pan_drag.x += last_drag.x - x;
10203 m_pan_drag.y += last_drag.y - y;
10204 last_drag.x = x, last_drag.y = y;
10208 if ((last_drag.x != x) || (last_drag.y != y)) {
10209 if (!m_routeState) {
10212 m_bChartDragging =
true;
10213 StartTimedMovement();
10214 m_pan_drag.x += last_drag.x - x;
10215 m_pan_drag.y += last_drag.y - y;
10216 last_drag.x = x, last_drag.y = y;
10223 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10225 m_DoubleClickTimer->Start();
10226 singleClickEventIsValid =
false;
10234void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10235 if (MouseEventOverlayWindows(event))
return;
10242void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10245 wxCursor *ptarget_cursor = pCursorArrow;
10246 if (!pPlugIn_Cursor) {
10247 ptarget_cursor = pCursorArrow;
10248 if ((!m_routeState) &&
10249 (!m_bMeasure_Active) ) {
10250 if (cursor_region == MID_RIGHT) {
10251 ptarget_cursor = pCursorRight;
10252 }
else if (cursor_region == MID_LEFT) {
10253 ptarget_cursor = pCursorLeft;
10254 }
else if (cursor_region == MID_TOP) {
10255 ptarget_cursor = pCursorDown;
10256 }
else if (cursor_region == MID_BOT) {
10257 ptarget_cursor = pCursorUp;
10259 ptarget_cursor = pCursorArrow;
10261 }
else if (m_bMeasure_Active ||
10263 ptarget_cursor = pCursorPencil;
10265 ptarget_cursor = pPlugIn_Cursor;
10268 SetCursor(*ptarget_cursor);
10271void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10272 SetCursor(*pCursorArrow);
10275void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10279 wxArrayString files;
10281 ChartBase *target_chart = GetChartAtCursor();
10282 if (target_chart) {
10283 file.Assign(target_chart->GetFullPath());
10284 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10285 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10288 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10290 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10291 unsigned int im = stackIndexArray.size();
10292 int scale = 2147483647;
10293 if (VPoint.b_quilt && im > 0) {
10294 for (
unsigned int is = 0; is < im; is++) {
10295 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10296 CHART_TYPE_MBTILES) {
10297 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10299 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10300 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10302 .Contains(lat, lon)) {
10303 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10306 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10307 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10315 std::vector<Ais8_001_22 *> area_notices;
10317 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10320 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10321 auto target_data = target.second;
10322 if (!target_data->area_notices.empty()) {
10323 for (
auto &ani : target_data->area_notices) {
10328 for (Ais8_001_22_SubAreaList::iterator sa =
10329 area_notice.sub_areas.begin();
10330 sa != area_notice.sub_areas.end(); ++sa) {
10331 switch (sa->shape) {
10332 case AIS8_001_22_SHAPE_CIRCLE: {
10333 wxPoint target_point;
10335 bbox.Expand(target_point);
10336 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10339 case AIS8_001_22_SHAPE_RECT: {
10340 wxPoint target_point;
10342 bbox.Expand(target_point);
10343 if (sa->e_dim_m > sa->n_dim_m)
10344 bbox.EnLarge(sa->e_dim_m * vp_scale);
10346 bbox.EnLarge(sa->n_dim_m * vp_scale);
10349 case AIS8_001_22_SHAPE_POLYGON:
10350 case AIS8_001_22_SHAPE_POLYLINE: {
10351 for (
int i = 0; i < 4; ++i) {
10352 double lat = sa->latitude;
10353 double lon = sa->longitude;
10354 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10356 wxPoint target_point;
10358 bbox.Expand(target_point);
10362 case AIS8_001_22_SHAPE_SECTOR: {
10363 double lat1 = sa->latitude;
10364 double lon1 = sa->longitude;
10366 wxPoint target_point;
10368 bbox.Expand(target_point);
10369 for (
int i = 0; i < 18; ++i) {
10372 sa->left_bound_deg +
10373 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10374 sa->radius_m / 1852.0, &lat, &lon);
10376 bbox.Expand(target_point);
10378 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10381 bbox.Expand(target_point);
10387 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10388 area_notices.push_back(&area_notice);
10395 if (target_chart || !area_notices.empty() || file.HasName()) {
10397 int sel_rad_pix = 5;
10398 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10403 SetCursor(wxCURSOR_WAIT);
10404 bool lightsVis = m_encShowLights;
10405 if (!lightsVis) SetShowENCLights(
true);
10408 ListOfObjRazRules *rule_list = NULL;
10409 ListOfPI_S57Obj *pi_rule_list = NULL;
10412 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10413 else if (target_plugin_chart)
10414 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10415 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10417 ListOfObjRazRules *overlay_rule_list = NULL;
10418 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10421 if (CHs57_Overlay) {
10422 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10423 zlat, zlon, SelectRadius, &GetVP());
10426 if (!lightsVis) SetShowENCLights(
false);
10429 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10430 wxString face = dFont->GetFaceName();
10432 if (NULL == g_pObjectQueryDialog) {
10433 g_pObjectQueryDialog =
10434 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10435 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10438 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10439 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10443 fg = g_pObjectQueryDialog->GetForegroundColour();
10447 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10448 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10451 int points = dFont->GetPointSize();
10453 int points = dFont->GetPointSize() + 1;
10457 for (
int i = -2; i < 5; i++) {
10458 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10460 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10462 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10464 if (overlay_rule_list && CHs57_Overlay) {
10465 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10466 objText <<
"<hr noshade>";
10469 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10470 an != area_notices.end(); ++an) {
10471 objText <<
"<b>AIS Area Notice:</b> ";
10472 objText << ais8_001_22_notice_names[(*an)->notice_type];
10473 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10474 (*an)->sub_areas.begin();
10475 sa != (*an)->sub_areas.end(); ++sa)
10476 if (!sa->text.empty()) objText << sa->text;
10477 objText <<
"<br>expires: " << (*an)->expiry_time.Format();
10478 objText <<
"<hr noshade>";
10482 objText << Chs57->CreateObjDescriptions(rule_list);
10483 else if (target_plugin_chart)
10484 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10487 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10490 wxString AddFiles, filenameOK;
10492 if (!target_plugin_chart) {
10495 AddFiles = wxString::Format(
10496 "<hr noshade><br><b>Additional info files attached to: </b> "
10498 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10500 file.GetFullName());
10502 file.Assign(file.GetPath(),
"");
10503 wxDir dir(file.GetFullPath());
10505 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10507 file.Assign(dir.GetNameWithSep().append(filename));
10508 wxString FormatString =
10509 "<td valign=top><font size=-2><a "
10510 "href=\"%s\">%s</a></font></td>";
10511 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10512 filenameOK = file.GetFullPath();
10514 if (3 * ((
int)filecount / 3) == filecount)
10515 FormatString.Prepend(
"<tr>");
10517 FormatString.Prepend(
10518 "<td>  </td>");
10521 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10522 file.GetFullName());
10525 cont = dir.GetNext(&filename);
10527 objText << AddFiles <<
"</table>";
10529 objText <<
"</font>";
10530 objText <<
"</body></html>";
10532 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10533 g_pObjectQueryDialog->SetHTMLPage(objText);
10534 g_pObjectQueryDialog->Show();
10536 if ((!Chs57 && filecount == 1)) {
10538 wxHtmlLinkInfo hli(filenameOK);
10539 wxHtmlLinkEvent hle(1, hli);
10540 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10543 if (rule_list) rule_list->Clear();
10546 if (overlay_rule_list) overlay_rule_list->Clear();
10547 delete overlay_rule_list;
10549 if (pi_rule_list) pi_rule_list->Clear();
10550 delete pi_rule_list;
10552 SetCursor(wxCURSOR_ARROW);
10556void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10558 if (!g_pMarkInfoDialog) {
10565 wxSize canvas_size = GetSize();
10568 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10570 g_pMarkInfoDialog->Layout();
10572 wxPoint canvas_pos = GetPosition();
10573 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10575 bool newFit =
false;
10576 if (canvas_size.x < fitted_size.x) {
10577 fitted_size.x = canvas_size.x - 40;
10578 if (canvas_size.y < fitted_size.y)
10579 fitted_size.y -= 40;
10581 if (canvas_size.y < fitted_size.y) {
10582 fitted_size.y = canvas_size.y - 40;
10583 if (canvas_size.x < fitted_size.x)
10584 fitted_size.x -= 40;
10588 g_pMarkInfoDialog->SetSize(fitted_size);
10589 g_pMarkInfoDialog->Centre();
10595 wxString title_base = _(
"Mark Properties");
10597 title_base = _(
"Waypoint Properties");
10599 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10600 g_pMarkInfoDialog->UpdateProperties();
10602 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10604 g_pMarkInfoDialog->SetDialogTitle(caption);
10606 g_pMarkInfoDialog->SetDialogTitle(title_base);
10608 g_pMarkInfoDialog->Show();
10609 g_pMarkInfoDialog->Raise();
10610 g_pMarkInfoDialog->InitialFocus();
10611 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10614void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10615 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10616 pRoutePropDialog->SetRouteAndUpdate(selected);
10618 pRoutePropDialog->Show();
10619 pRoutePropDialog->Raise();
10621 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10624 if (g_bresponsive) {
10625 wxSize canvas_size = GetSize();
10626 wxPoint canvas_pos = GetPosition();
10627 wxSize fitted_size = pRoutePropDialog->GetSize();
10630 if (canvas_size.x < fitted_size.x) {
10631 fitted_size.x = canvas_size.x;
10632 if (canvas_size.y < fitted_size.y)
10633 fitted_size.y -= 20;
10635 if (canvas_size.y < fitted_size.y) {
10636 fitted_size.y = canvas_size.y;
10637 if (canvas_size.x < fitted_size.x)
10638 fitted_size.x -= 20;
10641 pRoutePropDialog->SetSize(fitted_size);
10642 pRoutePropDialog->Centre();
10647 wxPoint xxp = ClientToScreen(canvas_pos);
10651 pRoutePropDialog->SetRouteAndUpdate(selected);
10653 pRoutePropDialog->Show();
10658void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10659 pTrackPropDialog = TrackPropDlg::getInstance(
10662 pTrackPropDialog->SetTrackAndUpdate(selected);
10665 pTrackPropDialog->Show();
10670void pupHandler_PasteWaypoint() {
10673 int pasteBuffer = kml.ParsePasteBuffer();
10674 RoutePoint *pasted = kml.GetParsedRoutePoint();
10675 if (!pasted)
return;
10677 double nearby_radius_meters =
10678 g_Platform->GetSelectRadiusPix() /
10679 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10681 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10682 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10684 int answer = wxID_NO;
10688 "There is an existing waypoint at the same location as the one you are "
10689 "pasting. Would you like to merge the pasted data with it?\n\n");
10690 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10691 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10692 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10695 if (answer == wxID_YES) {
10696 nearPoint->SetName(pasted->GetName());
10698 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10699 pRouteManagerDialog->UpdateWptListCtrl();
10702 if (answer == wxID_NO) {
10705 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10708 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10711 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10712 pRouteManagerDialog->UpdateWptListCtrl();
10717 gFrame->InvalidateAllGL();
10718 gFrame->RefreshAllCanvas(
false);
10721void pupHandler_PasteRoute() {
10724 int pasteBuffer = kml.ParsePasteBuffer();
10725 Route *pasted = kml.GetParsedRoute();
10726 if (!pasted)
return;
10728 double nearby_radius_meters =
10729 g_Platform->GetSelectRadiusPix() /
10730 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10736 bool mergepoints =
false;
10737 bool createNewRoute =
true;
10738 int existingWaypointCounter = 0;
10740 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10741 curPoint = pasted->GetPoint(i);
10742 nearPoint = pWayPointMan->GetNearbyWaypoint(
10743 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10745 mergepoints =
true;
10746 existingWaypointCounter++;
10754 int answer = wxID_NO;
10758 "There are existing waypoints at the same location as some of the ones "
10759 "you are pasting. Would you like to just merge the pasted data into "
10761 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10762 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10763 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10765 if (answer == wxID_CANCEL) {
10772 if (mergepoints && answer == wxID_YES &&
10773 existingWaypointCounter == pasted->GetnPoints()) {
10774 wxRouteListNode *route_node = pRouteList->GetFirst();
10775 while (route_node) {
10776 Route *proute = route_node->GetData();
10779 createNewRoute =
false;
10782 route_node = route_node->GetNext();
10786 Route *newRoute = 0;
10789 if (createNewRoute) {
10790 newRoute =
new Route();
10794 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10795 curPoint = pasted->GetPoint(i);
10798 newPoint = pWayPointMan->GetNearbyWaypoint(
10799 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10800 newPoint->SetName(curPoint->GetName());
10803 if (createNewRoute) newRoute->AddPoint(newPoint);
10809 newPoint->SetIconName(
"circle");
10812 newPoint->SetShared(
false);
10814 newRoute->AddPoint(newPoint);
10815 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10818 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10821 if (i > 1 && createNewRoute)
10822 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10823 curPoint->m_lat, curPoint->m_lon,
10824 prevPoint, newPoint, newRoute);
10825 prevPoint = newPoint;
10828 if (createNewRoute) {
10829 pRouteList->Append(newRoute);
10831 NavObj_dB::GetInstance().InsertRoute(newRoute);
10833 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10834 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10837 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10838 pRouteManagerDialog->UpdateRouteListCtrl();
10839 pRouteManagerDialog->UpdateWptListCtrl();
10841 gFrame->InvalidateAllGL();
10842 gFrame->RefreshAllCanvas(
false);
10848void pupHandler_PasteTrack() {
10851 int pasteBuffer = kml.ParsePasteBuffer();
10852 Track *pasted = kml.GetParsedTrack();
10853 if (!pasted)
return;
10861 newTrack->SetName(pasted->GetName());
10863 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10864 curPoint = pasted->GetPoint(i);
10868 wxDateTime now = wxDateTime::Now();
10871 newTrack->AddPoint(newPoint);
10874 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10875 newPoint->m_lat, newPoint->m_lon,
10876 prevPoint, newPoint, newTrack);
10878 prevPoint = newPoint;
10881 g_TrackList.push_back(newTrack);
10883 NavObj_dB::GetInstance().InsertTrack(newTrack);
10885 gFrame->InvalidateAllGL();
10886 gFrame->RefreshAllCanvas(
false);
10889bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10892 v[
"CursorPosition_x"] = x;
10893 v[
"CursorPosition_y"] = y;
10896 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10897 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10898 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
10903 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
10905 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
10908#define SELTYPE_UNKNOWN 0x0001
10909#define SELTYPE_ROUTEPOINT 0x0002
10910#define SELTYPE_ROUTESEGMENT 0x0004
10911#define SELTYPE_TIDEPOINT 0x0008
10912#define SELTYPE_CURRENTPOINT 0x0010
10913#define SELTYPE_ROUTECREATE 0x0020
10914#define SELTYPE_AISTARGET 0x0040
10915#define SELTYPE_MARKPOINT 0x0080
10916#define SELTYPE_TRACKSEGMENT 0x0100
10917#define SELTYPE_DRAGHANDLE 0x0200
10920 if (g_bhide_context_menus)
return true;
10922 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10923 m_pIDXCandidate, m_nmea_log);
10926 wxEVT_COMMAND_MENU_SELECTED,
10927 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10929 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10932 wxEVT_COMMAND_MENU_SELECTED,
10933 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10935 delete m_canvasMenu;
10936 m_canvasMenu = NULL;
10946void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10949 if (m_canvasMenu) {
10950 m_canvasMenu->PopupMenuHandler(event);
10955void ChartCanvas::StartRoute(
void) {
10957 if (g_brouteCreating)
return;
10959 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10961 g_brouteCreating =
true;
10963 m_bDrawingRoute =
false;
10964 SetCursor(*pCursorPencil);
10966 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10968 HideGlobalToolbar();
10971 androidSetRouteAnnunciator(
true);
10975wxString ChartCanvas::FinishRoute(
void) {
10977 m_prev_pMousePoint = NULL;
10978 m_bDrawingRoute =
false;
10980 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
10983 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10985 androidSetRouteAnnunciator(
false);
10988 SetCursor(*pCursorArrow);
10990 if (m_pMouseRoute) {
10991 if (m_bAppendingRoute) {
10993 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10995 if (m_pMouseRoute->GetnPoints() > 1) {
10997 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11000 m_pMouseRoute = NULL;
11003 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11005 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
11006 (pRoutePropDialog->IsShown())) {
11007 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
11010 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11011 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11012 pRouteManagerDialog->UpdateRouteListCtrl();
11015 m_bAppendingRoute =
false;
11016 m_pMouseRoute = NULL;
11018 m_pSelectedRoute = NULL;
11020 undo->InvalidateUndo();
11021 gFrame->RefreshAllCanvas(
true);
11023 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
11025 ShowGlobalToolbar();
11027 g_brouteCreating =
false;
11032void ChartCanvas::HideGlobalToolbar() {
11033 if (m_canvasIndex == 0) {
11034 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11038void ChartCanvas::ShowGlobalToolbar() {
11039 if (m_canvasIndex == 0) {
11040 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11044void ChartCanvas::ShowAISTargetList(
void) {
11045 if (NULL == g_pAISTargetList) {
11049 g_pAISTargetList->UpdateAISTargetList();
11052void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11053 if (!m_bShowOutlines)
return;
11057 int nEntry =
ChartData->GetChartTableEntries();
11059 for (
int i = 0; i < nEntry; i++) {
11063 bool b_group_draw =
false;
11064 if (m_groupIndex > 0) {
11065 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11066 int index = pt->GetGroupArray()[ig];
11067 if (m_groupIndex == index) {
11068 b_group_draw =
true;
11073 b_group_draw =
true;
11075 if (b_group_draw) RenderChartOutline(dc, i, vp);
11081 if (VPoint.b_quilt) {
11082 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11083 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11087 }
else if (m_singleChart &&
11088 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11092 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11095 if (zoom_factor > 8.0) {
11096 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11099 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11103 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11107void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11109 if (g_bopengl && m_glcc) {
11111 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11116 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11117 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11120 float plylat, plylon;
11121 float plylat1, plylon1;
11123 int pixx, pixy, pixx1, pixy1;
11126 ChartData->GetDBBoundingBox(dbIndex, box);
11130 if (box.GetLonRange() == 360)
return;
11132 double lon_bias = 0;
11134 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11136 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11138 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11139 dc.SetPen(wxPen(GetGlobalColor(
"YELO1"), 1, wxPENSTYLE_SOLID));
11141 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11142 dc.SetPen(wxPen(GetGlobalColor(
"UINFG"), 1, wxPENSTYLE_SOLID));
11145 dc.SetPen(wxPen(GetGlobalColor(
"UINFR"), 1, wxPENSTYLE_SOLID));
11148 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11149 if (0 == nAuxPlyEntries)
11153 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11154 plylon += lon_bias;
11160 for (
int i = 0; i < nPly - 1; i++) {
11161 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11162 plylon1 += lon_bias;
11168 int pixxs1 = pixx1;
11169 int pixys1 = pixy1;
11171 bool b_skip =
false;
11175 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11176 pow((
double)(pixy1 - pixy), 2)) /
11182 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11187 if (fabs(dist - distgc) > 10000. * 1852.)
11193 ClipResult res = cohen_sutherland_line_clip_i(
11195 if (res != Invisible && !b_skip)
11196 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11204 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11205 plylon1 += lon_bias;
11211 ClipResult res = cohen_sutherland_line_clip_i(
11213 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11220 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11221 for (
int j = 0; j < nAuxPlyEntries; j++) {
11223 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11228 for (
int i = 0; i < nAuxPly - 1; i++) {
11229 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11235 int pixxs1 = pixx1;
11236 int pixys1 = pixy1;
11238 bool b_skip =
false;
11242 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11243 ((pixy1 - pixy) * (pixy1 - pixy))) /
11248 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11253 if (fabs(dist - distgc) > 10000. * 1852.)
11259 ClipResult res = cohen_sutherland_line_clip_i(
11261 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11269 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11274 ClipResult res = cohen_sutherland_line_clip_i(
11276 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11281static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11282 const wxString &second) {
11283 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11285 int pointsize = dFont->GetPointSize();
11289 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11290 false, dFont->GetFaceName());
11292 dc.SetFont(*psRLI_font);
11300 int hilite_offset = 3;
11303 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11304 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11306 dc.GetTextExtent(first, &w1, &h1);
11307 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11313 w = wxMax(w1, w2) + (h1 / 2);
11318 xp = ref_point.x - w;
11320 yp += hilite_offset;
11322 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(
"YELO1"), 172);
11324 dc.SetPen(wxPen(GetGlobalColor(
"UBLCK")));
11325 dc.SetTextForeground(GetGlobalColor(
"UBLCK"));
11327 dc.DrawText(first, xp, yp);
11328 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11331void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11332 if (!g_bAllowShipToActive)
return;
11334 Route *rt = g_pRouteMan->GetpActiveRoute();
11337 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11338 wxPoint2DDouble pa, pb;
11344 g_pRouteMan->GetRoutePen()->GetWidth();
11345 if (rt->
m_width != wxPENSTYLE_INVALID)
11347 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11348 g_shipToActiveStyle, 5)];
11349 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11351 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11353 g_pRouteMan->GetActiveRoutePen()->GetColour();
11354 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11357 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11360 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11361 (
int)pb.m_y, GetVP(),
true);
11365#ifdef USE_ANDROID_GLES2
11366 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11368 if (style != wxPENSTYLE_SOLID) {
11369 if (glChartCanvas::dash_map.find(style) !=
11370 glChartCanvas::dash_map.end()) {
11371 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11375 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11378 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11379 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11385void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11387 if (m_routeState >= 2) route = m_pMouseRoute;
11388 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11389 route = m_pMeasureRoute;
11391 if (!route)
return;
11394 if (!g_pRouteMan->IsRouteValid(route))
return;
11399 int np = route->GetnPoints();
11401 if (g_btouch && (np > 1)) np--;
11403 render_lat = rp.m_lat;
11404 render_lon = rp.m_lon;
11407 double rhumbBearing, rhumbDist;
11409 &rhumbBearing, &rhumbDist);
11410 double brg = rhumbBearing;
11411 double dist = rhumbDist;
11415 double gcBearing, gcBearing2, gcDist;
11416 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11419 double gcDistm = gcDist / 1852.0;
11422 rhumbBearing = 90.;
11424 wxPoint destPoint, lastPoint;
11427 int milesDiff = rhumbDist - gcDistm;
11428 if (milesDiff > 1) {
11439 for (
int i = 1; i <= milesDiff; i++) {
11440 double p = (double)i * (1.0 / (
double)milesDiff);
11442 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11443 &pLon, &pLat, &gcBearing2);
11445 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11447 lastPoint = destPoint;
11450 if (r_rband.x && r_rband.y) {
11451 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11453 if (m_bMeasure_DistCircle) {
11454 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11455 powf((
float)(r_rband.y - lastPoint.y), 2));
11457 dc.SetPen(*g_pRouteMan->GetRoutePen());
11458 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11459 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11465 wxString routeInfo;
11468 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11474 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11476 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11477 (
int)varBrg, 0x00B0);
11479 routeInfo <<
" " << FormatDistanceAdaptive(dist);
11484 routeInfo <<
"\nReverse: ";
11486 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11487 (
int)(brg + 180.) % 360, 0x00B0);
11489 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11490 (
int)(varBrg + 180.) % 360, 0x00B0);
11495 s0.Append(_(
"Route") +
": ");
11497 s0.Append(_(
"Layer Route: "));
11500 if (!g_btouch) disp_length += dist;
11501 s0 += FormatDistanceAdaptive(disp_length);
11503 RouteLegInfo(dc, r_rband, routeInfo, s0);
11505 m_brepaint_piano =
true;
11508void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11509 if (!m_bShowVisibleSectors)
return;
11511 if (g_bDeferredInitDone) {
11513 double rhumbBearing, rhumbDist;
11514 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11515 &rhumbBearing, &rhumbDist);
11517 if (rhumbDist > 0.05)
11519 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11520 m_sectorlegsVisible);
11521 m_sector_glat = gLat;
11522 m_sector_glon = gLon;
11524 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11528void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11536void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11537 if (!ps52plib)
return;
11539 if (VPoint.b_quilt) {
11540 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11542 if (m_pQuilt->IsQuiltVector()) {
11543 if (ps52plib->GetStateHash() != m_s52StateHash) {
11545 m_s52StateHash = ps52plib->GetStateHash();
11549 if (ps52plib->GetStateHash() != m_s52StateHash) {
11551 m_s52StateHash = ps52plib->GetStateHash();
11556 bool bSendPlibState =
true;
11557 if (VPoint.b_quilt) {
11558 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11561 if (bSendPlibState) {
11563 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11564 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11565 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11566 v[
"OpenCPN Version Date"] = VERSION_DATE;
11567 v[
"OpenCPN Version Full"] = VERSION_FULL;
11570 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11571 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11572 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11573 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11574 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11575 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11576 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11580 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11581 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11585 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11586 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11587 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11588 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11589 ps52plib->m_bShowS57ImportantTextOnly;
11590 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11591 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11592 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11593 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11594 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11597 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11598 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11599 v[
"OpenCPN Scale Factor Exp"] =
11600 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11607 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11608 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11609 g_lastS52PLIBPluginMessage = out;
11615void ChartCanvas::OnPaint(wxPaintEvent &event) {
11616 wxPaintDC dc(
this);
11626 if (!m_b_paint_enable) {
11631 UpdateCanvasS52PLIBConfig();
11634 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11636 if (m_glcc && g_bopengl) {
11637 if (!s_in_update) {
11647 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11649 wxRegion ru = GetUpdateRegion();
11651 int rx, ry, rwidth, rheight;
11652 ru.GetBox(rx, ry, rwidth, rheight);
11656#ifdef ocpnUSE_DIBSECTION
11659 wxMemoryDC temp_dc;
11667 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11668 height += m_Piano->GetHeight();
11670 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11674 int thumbx, thumby, thumbsx, thumbsy;
11675 pthumbwin->GetPosition(&thumbx, &thumby);
11676 pthumbwin->GetSize(&thumbsx, &thumbsy);
11677 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11679 if (pthumbwin->IsShown()) {
11680 rgn_chart.Subtract(rgn_thumbwin);
11681 ru.Subtract(rgn_thumbwin);
11687 wxRegion rgn_blit = ru;
11688 if (g_bShowChartBar) {
11689 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11690 GetClientSize().x, m_Piano->GetHeight());
11693 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11694 if (style->chartStatusWindowTransparent)
11695 m_brepaint_piano =
true;
11697 ru.Subtract(chart_bar_rect);
11701 if (m_Compass && m_Compass->IsShown()) {
11702 wxRect compassRect = m_Compass->
GetRect();
11703 if (ru.Contains(compassRect) != wxOutRegion) {
11704 ru.Subtract(compassRect);
11708 wxRect noteRect = m_notification_button->
GetRect();
11709 if (ru.Contains(noteRect) != wxOutRegion) {
11710 ru.Subtract(noteRect);
11714 bool b_newview =
true;
11719 m_cache_vp.IsValid()) {
11725 bool b_rcache_ok =
false;
11726 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11727 b_rcache_ok = !b_newview;
11730 if (VPoint.b_MercatorProjectionOverride)
11731 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11745 if (b_rcache_ok) chart_get_region.Clear();
11748 if (VPoint.b_quilt)
11750 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11752 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11757 AbstractPlatform::ShowBusySpinner();
11761 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11762 (m_working_bm.GetHeight() != svp.
pix_height))
11766 if (fabs(VPoint.
rotation) < 0.01) {
11767 bool b_save =
true;
11769 if (g_SencThreadManager) {
11770 if (g_SencThreadManager->GetJobCount()) {
11772 m_cache_vp.Invalidate();
11786 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11791 int dy = c_new.y - c_old.y;
11792 int dx = c_new.x - c_old.x;
11797 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11801 temp_dc.SelectObject(m_working_bm);
11803 wxMemoryDC cache_dc;
11804 cache_dc.SelectObject(m_cached_chart_bm);
11808 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11811 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11817 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11820 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11828 update_region.Union(
11831 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11836 update_region.Union(
11839 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11843 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11845 cache_dc.SelectObject(wxNullBitmap);
11849 temp_dc.SelectObject(m_cached_chart_bm);
11852 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11856 temp_dc.SelectObject(m_working_bm);
11857 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11862 temp_dc.SelectObject(m_cached_chart_bm);
11867 temp_dc.SelectObject(m_working_bm);
11868 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11881 wxMemoryDC scratch_dc_0;
11882 scratch_dc_0.SelectObject(m_cached_chart_bm);
11885 scratch_dc_0.SelectObject(wxNullBitmap);
11894 temp_dc.SelectObject(m_working_bm);
11897 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11898 chart_get_all_region);
11901 AbstractPlatform::HideBusySpinner();
11907 if (!m_singleChart) {
11908 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11913 if (!chart_get_region.IsEmpty()) {
11914 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11918 if (temp_dc.IsOk()) {
11923 if (!VPoint.b_quilt) {
11926 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11927 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11934 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11935 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11938 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11940 temp_dc.DestroyClippingRegion();
11945 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11947 if (!backgroundRegion.IsEmpty()) {
11953 wxColour water = pWorldBackgroundChart->water;
11954 if (water.IsOk()) {
11955 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11956 temp_dc.SetBrush(wxBrush(water));
11958 while (upd.HaveRects()) {
11959 wxRect rect = upd.GetRect();
11960 temp_dc.DrawRectangle(rect);
11965 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11966 temp_dc.SetDeviceClippingRegion(*clip_region);
11967 delete clip_region;
11971 SetVPRotation(VPoint.
skew);
11974 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11980 wxMemoryDC *pChartDC = &temp_dc;
11981 wxMemoryDC rotd_dc;
11983 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11985 if (!b_rcache_ok) {
11987 wxMemoryDC tbase_dc;
11989 tbase_dc.SelectObject(bm_base);
11991 tbase_dc.SelectObject(wxNullBitmap);
11993 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11996 wxImage base_image;
11997 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12005 bool b_rot_ok =
false;
12006 if (base_image.IsOk()) {
12009 m_b_rot_hidef =
false;
12013 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12014 m_b_rot_hidef, &m_roffset);
12019 rot_vp.IsValid() && (ri.IsOk())) {
12026 m_prot_bm =
new wxBitmap(ri);
12029 m_roffset.x += VPoint.rv_rect.x;
12030 m_roffset.y += VPoint.rv_rect.y;
12033 if (m_prot_bm && m_prot_bm->IsOk()) {
12034 rotd_dc.SelectObject(*m_prot_bm);
12035 pChartDC = &rotd_dc;
12037 pChartDC = &temp_dc;
12038 m_roffset = wxPoint(0, 0);
12041 pChartDC = &temp_dc;
12042 m_roffset = wxPoint(0, 0);
12045 wxPoint offset = m_roffset;
12048 m_cache_vp = VPoint;
12051 wxMemoryDC mscratch_dc;
12052 mscratch_dc.SelectObject(*pscratch_bm);
12054 mscratch_dc.ResetBoundingBox();
12055 mscratch_dc.DestroyClippingRegion();
12056 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12059 wxRegionIterator upd(rgn_blit);
12061 wxRect rect = upd.GetRect();
12063 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12064 rect.x - offset.x, rect.y - offset.y);
12070 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12071 if (
this == wxWindow::FindFocus()) {
12074 wxColour colour = GetGlobalColor(
"BLUE4");
12075 mscratch_dc.SetPen(wxPen(colour));
12076 mscratch_dc.SetBrush(wxBrush(colour));
12078 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12079 mscratch_dc.DrawRectangle(activeRect);
12084 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12085 unsigned int im = stackIndexArray.size();
12086 if (VPoint.b_quilt && im > 0) {
12087 std::vector<int> tiles_to_show;
12088 for (
unsigned int is = 0; is < im; is++) {
12090 ChartData->GetChartTableEntry(stackIndexArray[is]);
12091 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12094 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12095 tiles_to_show.push_back(stackIndexArray[is]);
12099 if (tiles_to_show.size())
12100 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12106 ocpnDC scratch_dc(mscratch_dc);
12107 RenderAlertMessage(mscratch_dc, GetVP());
12113#ifdef ocpnUSE_DIBSECTION
12118 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12119 q_dc.SelectObject(qbm);
12122 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12125 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12126 q_dc.SetBrush(qbr);
12127 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12130 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12133 q_dc.SelectObject(wxNullBitmap);
12142 if( VPoint.b_quilt ) {
12143 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12144 ChartBase *chart = m_pQuilt->GetRefChart();
12145 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12150 ChPI->ClearPLIBTextList();
12153 ps52plib->ClearTextList();
12157 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12159 wxColor maskBackground = wxColour(1,0,0);
12160 t_dc.SelectObject( qbm );
12161 t_dc.SetBackground(wxBrush(maskBackground));
12165 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12168 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12169 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12172 wxRegionIterator upd_final( ru );
12173 while( upd_final ) {
12174 wxRect rect = upd_final.GetRect();
12175 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12179 t_dc.SelectObject( wxNullBitmap );
12185 if (VPoint.b_quilt) {
12186 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12187 ChartBase *chart = m_pQuilt->GetRefChart();
12188 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12192 ChPI->ClearPLIBTextList();
12194 if (ps52plib) ps52plib->ClearTextList();
12199 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12201 if (g_bShowChartBar && m_Piano) {
12202 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12203 GetVP().pix_width, m_Piano->GetHeight());
12206 if (!style->chartStatusWindowTransparent)
12207 chart_all_text_region.Subtract(chart_bar_rect);
12210 if (m_Compass && m_Compass->IsShown()) {
12211 wxRect compassRect = m_Compass->
GetRect();
12212 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12213 chart_all_text_region.Subtract(compassRect);
12217 mscratch_dc.DestroyClippingRegion();
12219 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12220 chart_all_text_region);
12226 ocpnDC scratch_dc(mscratch_dc);
12227 DrawOverlayObjects(scratch_dc, ru);
12230 wxRegionIterator upd_final(rgn_blit);
12231 while (upd_final) {
12232 wxRect rect = upd_final.GetRect();
12233 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12240 temp_dc.SelectObject(wxNullBitmap);
12242 mscratch_dc.SelectObject(wxNullBitmap);
12244 dc.DestroyClippingRegion();
12249void ChartCanvas::PaintCleanup() {
12261 m_bTCupdate =
false;
12265 WarpPointer(warp_x, warp_y);
12272 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12273 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12277wxColour GetErrorGraphicColor(
double val)
12296 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12297 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12298 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12299 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12300 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12301 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12302 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12303 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12304 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12305 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12306 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12307 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12308 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12309 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12310 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12311 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12312 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12313 else if( val >= 48) c.Set(
"#410000");
12318void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12321 gr_image.InitAlpha();
12323 double maxval = -10000;
12324 double minval = 10000;
12341 maxval = wxMax(maxval, (glat - rlat));
12342 minval = wxMin(minval, (glat - rlat));
12359 double f = ((glat - rlat)-minval)/(maxval - minval);
12361 double dy = (f * 40);
12363 wxColour c = GetErrorGraphicColor(dy);
12364 unsigned char r = c.Red();
12365 unsigned char g = c.Green();
12366 unsigned char b = c.Blue();
12368 gr_image.SetRGB(j, i, r,g,b);
12369 if((glat - rlat )!= 0)
12370 gr_image.SetAlpha(j, i, 128);
12372 gr_image.SetAlpha(j, i, 255);
12379 wxBitmap *pbm =
new wxBitmap(gr_image);
12380 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12381 pbm->SetMask(gr_mask);
12383 pmdc->DrawBitmap(*pbm, 0,0);
12391void ChartCanvas::CancelMouseRoute() {
12393 m_pMouseRoute = NULL;
12394 m_bDrawingRoute =
false;
12397int ChartCanvas::GetNextContextMenuId() {
12398 return CanvasMenuHandler::GetNextContextMenuId();
12401bool ChartCanvas::SetCursor(
const wxCursor &c) {
12403 if (g_bopengl && m_glcc)
12404 return m_glcc->SetCursor(c);
12407 return wxWindow::SetCursor(c);
12410void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12411 if (g_bquiting)
return;
12421 if (!m_RolloverPopupTimer.IsRunning() &&
12422 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12423 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12424 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12425 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12428 if (m_glcc && g_bopengl) {
12431 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12433 m_glcc->Refresh(eraseBackground,
12444 if (pthumbwin && pthumbwin->IsShown()) {
12445 pthumbwin->Raise();
12446 pthumbwin->Refresh(
false);
12450 if (m_pCIWin && m_pCIWin->IsShown()) {
12452 m_pCIWin->Refresh(
false);
12460 wxWindow::Refresh(eraseBackground, rect);
12463void ChartCanvas::Update() {
12464 if (m_glcc && g_bopengl) {
12469 wxWindow::Update();
12473 if (!pemboss)
return;
12474 int x = pemboss->x, y = pemboss->y;
12475 const double factor = 200;
12477 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12478 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12479 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12482 wxMemoryDC snip_dc;
12483 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12484 snip_dc.SelectObject(snip_bmp);
12486 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12487 snip_dc.SelectObject(wxNullBitmap);
12489 wxImage snip_img = snip_bmp.ConvertToImage();
12492 unsigned char *pdata = snip_img.GetData();
12494 for (
int y = 0; y < pemboss->height; y++) {
12495 int map_index = (y * pemboss->width);
12496 for (
int x = 0; x < pemboss->width; x++) {
12497 double val = (pemboss->pmap[map_index] * factor) / 256.;
12499 int nred = (int)((*pdata) + val);
12500 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12501 *pdata++ = (
unsigned char)nred;
12503 int ngreen = (int)((*pdata) + val);
12504 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12505 *pdata++ = (
unsigned char)ngreen;
12507 int nblue = (int)((*pdata) + val);
12508 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12509 *pdata++ = (
unsigned char)nblue;
12517 wxBitmap emb_bmp(snip_img);
12520 wxMemoryDC result_dc;
12521 result_dc.SelectObject(emb_bmp);
12524 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12526 result_dc.SelectObject(wxNullBitmap);
12532 if (GetQuiltMode()) {
12534 int refIndex = GetQuiltRefChartdbIndex();
12535 if (refIndex >= 0) {
12537 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12538 if (current_type == CHART_TYPE_MBTILES) {
12539 ChartBase *pChart = m_pQuilt->GetRefChart();
12542 zoom_factor = ptc->GetZoomFactor();
12547 if (zoom_factor <= 3.9)
return NULL;
12549 if (m_singleChart) {
12550 if (zoom_factor <= 3.9)
return NULL;
12555 if (m_pEM_OverZoom) {
12556 m_pEM_OverZoom->x = 4;
12557 m_pEM_OverZoom->y = 0;
12558 if (g_MainToolbar && IsPrimaryCanvas()) {
12559 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12560 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12563 return m_pEM_OverZoom;
12566void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12578 if (g_pi_manager) {
12579 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12580 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12584 AISDrawAreaNotices(dc, GetVP(),
this);
12586 wxDC *pdc = dc.GetDC();
12588 pdc->DestroyClippingRegion();
12589 wxDCClipper(*pdc, ru);
12592 if (m_bShowNavobjects) {
12593 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12594 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12595 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12596 DrawAnchorWatchPoints(dc);
12598 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12599 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12602 AISDraw(dc, GetVP(),
this);
12606 RenderVisibleSectorLights(dc);
12608 RenderAllChartOutlines(dc, GetVP());
12609 RenderRouteLegs(dc);
12610 RenderShipToActive(dc,
false);
12612 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12613 if (g_pi_manager) {
12614 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12618 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12619 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12621 if (g_pi_manager) {
12622 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12627 RebuildTideSelectList(GetVP().GetBBox());
12628 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12631 if (m_bShowCurrent) {
12632 RebuildCurrentSelectList(GetVP().GetBBox());
12633 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12636 if (!g_PrintingInProgress) {
12637 if (IsPrimaryCanvas()) {
12638 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12641 if (IsPrimaryCanvas()) {
12642 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12645 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12647 if (m_pTrackRolloverWin) {
12648 m_pTrackRolloverWin->Draw(dc);
12649 m_brepaint_piano =
true;
12652 if (m_pRouteRolloverWin) {
12653 m_pRouteRolloverWin->Draw(dc);
12654 m_brepaint_piano =
true;
12657 if (m_pAISRolloverWin) {
12658 m_pAISRolloverWin->Draw(dc);
12659 m_brepaint_piano =
true;
12661 if (m_brepaint_piano && g_bShowChartBar) {
12662 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12665 if (m_Compass) m_Compass->Paint(dc);
12667 if (!g_CanvasHideNotificationIcon) {
12668 auto ¬eman = NotificationManager::GetInstance();
12669 if (noteman.GetNotificationCount()) {
12670 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12671 if (m_notification_button->UpdateStatus()) Refresh();
12672 m_notification_button->Show(
true);
12673 m_notification_button->Paint(dc);
12675 m_notification_button->Show(
false);
12679 if (g_pi_manager) {
12680 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12686 if (!m_bShowDepthUnits)
return NULL;
12688 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12690 if (GetQuiltMode()) {
12691 wxString s = m_pQuilt->GetQuiltDepthUnit();
12694 depth_unit_type = DEPTH_UNIT_FEET;
12695 else if (s.StartsWith(
"FATHOMS"))
12696 depth_unit_type = DEPTH_UNIT_FATHOMS;
12697 else if (s.StartsWith(
"METERS"))
12698 depth_unit_type = DEPTH_UNIT_METERS;
12699 else if (s.StartsWith(
"METRES"))
12700 depth_unit_type = DEPTH_UNIT_METERS;
12701 else if (s.StartsWith(
"METRIC"))
12702 depth_unit_type = DEPTH_UNIT_METERS;
12703 else if (s.StartsWith(
"METER"))
12704 depth_unit_type = DEPTH_UNIT_METERS;
12707 if (m_singleChart) {
12708 depth_unit_type = m_singleChart->GetDepthUnitType();
12709 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12710 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12715 switch (depth_unit_type) {
12716 case DEPTH_UNIT_FEET:
12719 case DEPTH_UNIT_METERS:
12720 ped = m_pEM_Meters;
12722 case DEPTH_UNIT_FATHOMS:
12723 ped = m_pEM_Fathoms;
12729 ped->x = (GetVP().
pix_width - ped->width);
12731 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12732 wxRect r = m_Compass->
GetRect();
12733 ped->y = r.y + r.height;
12740void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12743 if (style->embossFont == wxEmptyString) {
12744 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12746 font.SetPointSize(60);
12747 font.SetWeight(wxFONTWEIGHT_BOLD);
12749 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12750 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12752 int emboss_width = 500;
12753 int emboss_height = 200;
12757 delete m_pEM_Meters;
12758 delete m_pEM_Fathoms;
12762 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12764 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12766 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12769#define OVERZOOM_TEXT _("OverZoom")
12771void ChartCanvas::SetOverzoomFont() {
12776 if (style->embossFont == wxEmptyString) {
12777 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12779 font.SetPointSize(40);
12780 font.SetWeight(wxFONTWEIGHT_BOLD);
12782 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12783 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12785 wxClientDC dc(
this);
12787 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12789 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12790 font.SetPointSize(font.GetPointSize() - 1);
12792 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12794 m_overzoomFont = font;
12795 m_overzoomTextWidth = w;
12796 m_overzoomTextHeight = h;
12799void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12800 delete m_pEM_OverZoom;
12802 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12804 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12805 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12808emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12809 int height,
const wxString &str,
12814 wxBitmap bmp(width, height, -1);
12817 wxMemoryDC temp_dc;
12818 temp_dc.SelectObject(bmp);
12821 temp_dc.SetBackground(*wxWHITE_BRUSH);
12822 temp_dc.SetTextBackground(*wxWHITE);
12823 temp_dc.SetTextForeground(*wxBLACK);
12827 temp_dc.SetFont(font);
12830 temp_dc.GetTextExtent(str, &str_w, &str_h);
12832 temp_dc.DrawText(str, 1, 1);
12835 temp_dc.SelectObject(wxNullBitmap);
12838 wxImage img = bmp.ConvertToImage();
12840 int image_width = str_w * 105 / 100;
12841 int image_height = str_h * 105 / 100;
12842 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12843 wxMin(image_height, img.GetHeight()));
12844 wxImage imgs = img.GetSubImage(r);
12848 case GLOBAL_COLOR_SCHEME_DAY:
12852 case GLOBAL_COLOR_SCHEME_DUSK:
12855 case GLOBAL_COLOR_SCHEME_NIGHT:
12862 const int w = imgs.GetWidth();
12863 const int h = imgs.GetHeight();
12864 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12869 for (
int y = 1; y < h - 1; y++) {
12870 for (
int x = 1; x < w - 1; x++) {
12872 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12873 val = (int)(val * val_factor);
12874 index = (y * w) + x;
12887void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12888 Track *active_track = NULL;
12889 for (
Track *pTrackDraw : g_TrackList) {
12890 if (g_pActiveTrack == pTrackDraw) {
12891 active_track = pTrackDraw;
12895 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12898 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12901void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12902 Track *active_track = NULL;
12903 for (
Track *pTrackDraw : g_TrackList) {
12904 if (g_pActiveTrack == pTrackDraw) {
12905 active_track = pTrackDraw;
12909 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12912void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12913 Route *active_route = NULL;
12915 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12916 node = node->GetNext()) {
12917 Route *pRouteDraw = node->GetData();
12918 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12919 active_route = pRouteDraw;
12924 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12929 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12932void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12933 Route *active_route = NULL;
12935 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12936 node = node->GetNext()) {
12937 Route *pRouteDraw = node->GetData();
12938 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12939 active_route = pRouteDraw;
12943 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12946void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12947 if (!pWayPointMan)
return;
12949 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12955 node = node->GetNext();
12960 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12964 if (pWP->GetShowWaypointRangeRings() &&
12965 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12966 double factor = 1.00;
12967 if (pWP->GetWaypointRangeRingsStepUnits() ==
12969 factor = 1 / 1.852;
12971 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12972 pWP->GetWaypointRangeRingsStep() / 60.;
12976 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12977 pWP->m_lat + radius, pWP->m_lon + radius);
12978 if (!BltBBox.IntersectOut(radar_box)) {
12985 node = node->GetNext();
12989void ChartCanvas::DrawBlinkObjects(
void) {
12991 wxRect update_rect;
12993 if (!pWayPointMan)
return;
12995 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
13005 node = node->GetNext();
13007 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13010void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13013 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
13015 wxPoint lAnchorPoint1, lAnchorPoint2;
13018 if (pAnchorWatchPoint1) {
13019 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
13023 if (pAnchorWatchPoint2) {
13024 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
13029 wxPen ppPeng(GetGlobalColor(
"UGREN"), 2);
13030 wxPen ppPenr(GetGlobalColor(
"URED"), 2);
13032 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13033 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13034 dc.SetBrush(*ppBrush);
13038 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13043 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13048 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13053 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13058double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13061 wxPoint lAnchorPoint;
13064 double tlat1, tlon1;
13066 if (pAnchorWatchPoint) {
13067 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13068 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13069 dabs = fabs(d1 / 1852.);
13070 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13075 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13076 pow((
double)(lAnchorPoint.y - r1.y), 2));
13079 if (d1 < 0) lpp = -lpp;
13087void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13088 if (!ptcmgr)
return;
13090 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13092 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13093 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13098 if ((type ==
't') || (type ==
'T')) {
13099 if (BBox.Contains(lat, lon)) {
13101 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13107void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13108 if (!ptcmgr)
return;
13110 wxDateTime this_now = gTimeSource;
13111 bool cur_time = !gTimeSource.IsValid();
13112 if (cur_time) this_now = wxDateTime::Now();
13113 time_t t_this_now = this_now.GetTicks();
13115 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13117 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13118 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), 1, wxPENSTYLE_SOLID);
13119 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13120 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), 1, wxPENSTYLE_SOLID);
13122 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13123 GetGlobalColor(
"GREEN1"), wxBRUSHSTYLE_SOLID);
13124 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13125 GetGlobalColor(cur_time ?
"BLUE2" :
"BLUE3"), wxBRUSHSTYLE_SOLID);
13126 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13127 GetGlobalColor(cur_time ?
"YELO1" :
"YELO2"), wxBRUSHSTYLE_SOLID);
13129 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13130 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13131 int font_size = wxMax(10, dFont->GetPointSize());
13134 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13135 false, dFont->GetFaceName());
13137 dc.SetPen(*pblack_pen);
13138 dc.SetBrush(*pgreen_brush);
13142 case GLOBAL_COLOR_SCHEME_DAY:
13145 case GLOBAL_COLOR_SCHEME_DUSK:
13148 case GLOBAL_COLOR_SCHEME_NIGHT:
13149 bm = m_bmTideNight;
13156 int bmw = bm.GetWidth();
13157 int bmh = bm.GetHeight();
13159 float scale_factor = 1.0;
13163 float icon_pixelRefDim = 45;
13168 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13170 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13172 scale_factor *= pix_factor;
13174 float user_scale_factor = g_ChartScaleFactorExp;
13175 if (g_ChartScaleFactorExp > 1.0)
13176 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13179 scale_factor *= user_scale_factor;
13180 scale_factor *= GetContentScaleFactor();
13183 double marge = 0.05;
13184 std::vector<LLBBox> drawn_boxes;
13185 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13186 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13189 if ((type ==
't') || (type ==
'T'))
13194 if (BBox.ContainsMarge(lat, lon, marge)) {
13196 if (GetVP().chart_scale < 500000) {
13197 bool bdrawn =
false;
13198 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13199 if (drawn_boxes[i].Contains(lat, lon)) {
13204 if (bdrawn)
continue;
13207 this_box.Set(lat, lon, lat, lon);
13208 this_box.EnLarge(.005);
13209 drawn_boxes.push_back(this_box);
13215 if (GetVP().chart_scale > 500000) {
13216 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13220 dc.SetFont(*plabelFont);
13232 if (ptcmgr->GetTideFlowSens(
13233 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13237 ptcmgr->GetHightOrLowTide(
13238 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13239 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13251 if (tctime > t_this_now)
13252 ptcmgr->GetHightOrLowTide(
13253 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13254 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13258 ptcmgr->GetHightOrLowTide(
13259 t_this_now, FORWARD_TEN_MINUTES_STEP,
13260 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13274 int width = (int)(12 * scale_factor + 0.5);
13275 int height = (int)(45 * scale_factor + 0.5);
13276 int linew = wxMax(1, (
int)(scale_factor));
13277 int xDraw = r.x - (width / 2);
13278 int yDraw = r.y - (height / 2);
13281 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13282 int hs = (httime > lttime) ? -4 : 4;
13283 hs *= (int)(scale_factor + 0.5);
13284 if (ts > 0.995 || ts < 0.005) hs = 0;
13285 int ht_y = (int)(height * ts);
13288 pblack_pen->SetWidth(linew);
13289 dc.SetPen(*pblack_pen);
13290 dc.SetBrush(*pyelo_brush);
13291 dc.DrawRectangle(xDraw, yDraw, width, height);
13295 dc.SetPen(*pblue_pen);
13296 dc.SetBrush(*pblue_brush);
13297 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13298 (width - (4 * linew)), height - ht_y);
13304 arrow[0].x = xDraw + 2 * linew;
13305 arrow[1].x = xDraw + width / 2;
13306 arrow[2].x = xDraw + width - 2 * linew;
13307 pyelo_pen->SetWidth(linew);
13308 pblue_pen->SetWidth(linew);
13309 if (ts > 0.35 || ts < 0.15)
13311 hl = (int)(height * 0.25) + yDraw;
13313 arrow[1].y = hl + hs;
13316 dc.SetPen(*pyelo_pen);
13318 dc.SetPen(*pblue_pen);
13319 dc.DrawLines(3, arrow);
13321 if (ts > 0.60 || ts < 0.40)
13323 hl = (int)(height * 0.5) + yDraw;
13325 arrow[1].y = hl + hs;
13328 dc.SetPen(*pyelo_pen);
13330 dc.SetPen(*pblue_pen);
13331 dc.DrawLines(3, arrow);
13333 if (ts < 0.65 || ts > 0.85)
13335 hl = (int)(height * 0.75) + yDraw;
13337 arrow[1].y = hl + hs;
13340 dc.SetPen(*pyelo_pen);
13342 dc.SetPen(*pblue_pen);
13343 dc.DrawLines(3, arrow);
13347 s.Printf(
"%3.1f", nowlev);
13349 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13351 dc.GetTextExtent(s, &wx1, NULL);
13353 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13368void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13369 if (!ptcmgr)
return;
13371 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13373 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13374 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13379 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13380 if ((BBox.Contains(lat, lon))) {
13382 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13388void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13389 if (!ptcmgr)
return;
13391 float tcvalue, dir;
13395 double lon_last = 0.;
13396 double lat_last = 0.;
13398 double marge = 0.2;
13399 bool cur_time = !gTimeSource.IsValid();
13401 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13402 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13404 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(GetGlobalColor(
"UINFD"), 1,
13406 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13407 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), 1, wxPENSTYLE_SOLID);
13408 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13409 GetGlobalColor(cur_time ?
"UINFO" :
"UINFB"), wxBRUSHSTYLE_SOLID);
13410 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13411 GetGlobalColor(
"UIBDR"), wxBRUSHSTYLE_SOLID);
13412 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13413 GetGlobalColor(
"UINFD"), wxBRUSHSTYLE_SOLID);
13415 double skew_angle = GetVPRotation();
13417 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13418 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13419 int font_size = wxMax(10, dFont->GetPointSize());
13422 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13423 false, dFont->GetFaceName());
13425 float scale_factor = 1.0;
13431 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13433 float nominal_icon_size_pixels = 15;
13434 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13436 scale_factor *= pix_factor;
13438 float user_scale_factor = g_ChartScaleFactorExp;
13439 if (g_ChartScaleFactorExp > 1.0)
13440 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13443 scale_factor *= user_scale_factor;
13445 scale_factor *= GetContentScaleFactor();
13448 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13449 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13454 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13455 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13460 int dd = (int)(5.0 * scale_factor + 0.5);
13471 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13472 dc.SetPen(*pblack_pen);
13473 dc.SetBrush(*porange_brush);
13474 dc.DrawPolygon(4, d);
13477 dc.SetBrush(*pblack_brush);
13478 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13482 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13496 double a1 = fabs(tcvalue) * 10.;
13498 a1 = wxMax(1.0, a1);
13499 double a2 = log10(a1);
13501 float cscale = scale_factor * a2 * 0.3;
13503 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13504 dc.SetPen(*porange_pen);
13505 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13509 if (bDrawCurrentValues) {
13510 dc.SetFont(*pTCFont);
13511 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13512 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13538 if (!pvIDX)
return;
13543 if (pCwin && pCwin->IsShown()) {
13551 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13566 pCwin =
new TCWin(
this, x, y, pvIDX);
13584#define NUM_CURRENT_ARROW_POINTS 9
13585static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13586 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13587 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13588 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13590void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13592 if (
scale > 1e-2) {
13593 float sin_rot = sin(rot_angle * PI / 180.);
13594 float cos_rot = cos(rot_angle * PI / 180.);
13598 float xt = CurrentArrowArray[0].x;
13599 float yt = CurrentArrowArray[0].y;
13601 float xp = (xt * cos_rot) - (yt * sin_rot);
13602 float yp = (xt * sin_rot) + (yt * cos_rot);
13603 int x1 = (int)(xp *
scale);
13604 int y1 = (int)(yp *
scale);
13607 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13608 xt = CurrentArrowArray[ip].x;
13609 yt = CurrentArrowArray[ip].y;
13611 float xp = (xt * cos_rot) - (yt * sin_rot);
13612 float yp = (xt * sin_rot) + (yt * cos_rot);
13613 int x2 = (int)(xp *
scale);
13614 int y2 = (int)(yp *
scale);
13616 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13624wxString ChartCanvas::FindValidUploadPort() {
13627 if (!g_uploadConnection.IsEmpty() &&
13628 g_uploadConnection.StartsWith(
"Serial")) {
13629 port = g_uploadConnection;
13635 for (
auto *cp : TheConnectionParams()) {
13636 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13637 port <<
"Serial:" << cp->Port;
13643void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13646 if (NULL == g_pais_query_dialog_active) {
13647 int pos_x = g_ais_query_dialog_x;
13648 int pos_y = g_ais_query_dialog_y;
13650 if (g_pais_query_dialog_active) {
13651 g_pais_query_dialog_active->Destroy();
13657 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13658 wxPoint(pos_x, pos_y));
13660 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13661 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13662 g_pais_query_dialog_active->SetMMSI(mmsi);
13663 g_pais_query_dialog_active->UpdateText();
13664 wxSize sz = g_pais_query_dialog_active->GetSize();
13666 bool b_reset_pos =
false;
13671 RECT frame_title_rect;
13672 frame_title_rect.left = pos_x;
13673 frame_title_rect.top = pos_y;
13674 frame_title_rect.right = pos_x + sz.x;
13675 frame_title_rect.bottom = pos_y + 30;
13677 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13678 b_reset_pos =
true;
13683 wxRect window_title_rect;
13684 window_title_rect.x = pos_x;
13685 window_title_rect.y = pos_y;
13686 window_title_rect.width = sz.x;
13687 window_title_rect.height = 30;
13689 wxRect ClientRect = wxGetClientDisplayRect();
13690 ClientRect.Deflate(
13692 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13696 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13699 g_pais_query_dialog_active->SetMMSI(mmsi);
13700 g_pais_query_dialog_active->UpdateText();
13703 g_pais_query_dialog_active->Show();
13706void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13707 bool cur_mode = GetQuiltMode();
13709 if (!GetQuiltMode())
13710 SetQuiltMode(
true);
13711 else if (GetQuiltMode()) {
13712 SetQuiltMode(
false);
13713 g_sticky_chart = GetQuiltReferenceChartIndex();
13716 if (cur_mode != GetQuiltMode()) {
13717 SetupCanvasQuiltMode();
13726 if (ps52plib) ps52plib->GenerateStateHash();
13728 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13729 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13732void ChartCanvas::DoCanvasStackDelta(
int direction) {
13733 if (!GetQuiltMode()) {
13734 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13735 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13736 if ((current_stack_index + direction) < 0)
return;
13738 if (m_bpersistent_quilt ) {
13740 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13742 if (IsChartQuiltableRef(new_dbIndex)) {
13743 ToggleCanvasQuiltMode();
13744 SelectQuiltRefdbChart(new_dbIndex);
13745 m_bpersistent_quilt =
false;
13748 SelectChartFromStack(current_stack_index + direction);
13751 std::vector<int> piano_chart_index_array =
13752 GetQuiltExtendedStackdbIndexArray();
13753 int refdb = GetQuiltRefChartdbIndex();
13756 int current_index = -1;
13757 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13758 if (refdb == piano_chart_index_array[i]) {
13763 if (current_index == -1)
return;
13766 int target_family = ctet.GetChartFamily();
13768 int new_index = -1;
13769 int check_index = current_index + direction;
13770 bool found =
false;
13771 int check_dbIndex = -1;
13772 int new_dbIndex = -1;
13776 (
unsigned int)check_index < piano_chart_index_array.size() &&
13777 (check_index >= 0)) {
13778 check_dbIndex = piano_chart_index_array[check_index];
13780 if (target_family == cte.GetChartFamily()) {
13782 new_index = check_index;
13783 new_dbIndex = check_dbIndex;
13787 check_index += direction;
13790 if (!found)
return;
13792 if (!IsChartQuiltableRef(new_dbIndex)) {
13793 ToggleCanvasQuiltMode();
13794 SelectdbChart(new_dbIndex);
13795 m_bpersistent_quilt =
true;
13797 SelectQuiltRefChart(new_index);
13801 gFrame->UpdateGlobalMenuItems();
13803 SetQuiltChartHiLiteIndex(-1);
13814void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13817 switch (event.GetId()) {
13829 DoCanvasStackDelta(1);
13834 DoCanvasStackDelta(-1);
13844 ShowCurrents(!GetbShowCurrent());
13851 ShowTides(!GetbShowTide());
13858 if (0 == m_routeState) {
13865 androidSetRouteAnnunciator(m_routeState == 1);
13871 SetAISCanvasDisplayStyle(-1);
13883void ChartCanvas::SetShowAIS(
bool show) {
13885 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13886 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13889void ChartCanvas::SetAttenAIS(
bool show) {
13890 m_bShowAISScaled = show;
13891 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13892 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13895void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13898 bool bShowAIS_Array[3] = {
true,
true,
false};
13899 bool bShowScaled_Array[3] = {
false,
true,
true};
13900 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13901 _(
"Attenuate less critical AIS targets"),
13902 _(
"Hide AIS Targets")};
13903 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
13905 int AIS_Toolbar_Switch = 0;
13906 if (StyleIndx == -1) {
13908 for (
int i = 1; i < ArraySize; i++) {
13909 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13910 (bShowScaled_Array[i] == m_bShowAISScaled))
13911 AIS_Toolbar_Switch = i;
13913 AIS_Toolbar_Switch++;
13914 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13915 AIS_Toolbar_Switch++;
13918 AIS_Toolbar_Switch = StyleIndx;
13921 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13923 int AIS_Toolbar_Switch_Next =
13924 AIS_Toolbar_Switch + 1;
13925 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13926 AIS_Toolbar_Switch_Next++;
13927 if (AIS_Toolbar_Switch_Next >= ArraySize)
13928 AIS_Toolbar_Switch_Next = 0;
13931 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13932 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13935void ChartCanvas::TouchAISToolActive(
void) {}
13937void ChartCanvas::UpdateAISTBTool(
void) {}
13945void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13947 bool b_update =
false;
13948 int cc1_edge_comp = 2;
13949 wxRect rect = m_Compass->
GetRect();
13950 wxSize parent_size = GetSize();
13952 parent_size *= m_displayScale;
13956 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13957 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13958 wxRect compass_rect(compass_pt, rect.GetSize());
13960 m_Compass->Move(compass_pt);
13962 if (m_Compass && m_Compass->IsShown())
13963 m_Compass->UpdateStatus(b_force_new | b_update);
13965 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
13966 scaler = wxMax(scaler, 1.0);
13967 wxPoint note_point = wxPoint(
13968 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
13969 m_notification_button->Move(note_point);
13970 m_notification_button->UpdateStatus();
13972 if (b_force_new | b_update) Refresh();
13975void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13976 ChartTypeEnum New_Type,
13977 ChartFamilyEnum New_Family) {
13978 if (!GetpCurrentStack())
return;
13981 if (index < GetpCurrentStack()->nEntry) {
13984 pTentative_Chart =
ChartData->OpenStackChartConditional(
13985 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13987 if (pTentative_Chart) {
13988 if (m_singleChart) m_singleChart->Deactivate();
13990 m_singleChart = pTentative_Chart;
13991 m_singleChart->Activate();
13993 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
13994 GetpCurrentStack(), m_singleChart->GetFullPath());
14007 double best_scale_ppm = GetBestVPScale(m_singleChart);
14008 double rotation = GetVPRotation();
14009 double oldskew = GetVPSkew();
14010 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14012 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14013 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14014 if (fabs(newskew) > 0.0001) rotation = newskew;
14017 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14019 UpdateGPSCompassStatusBox(
true);
14023 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14024 if (idx < 0)
return;
14026 std::vector<int> piano_active_chart_index_array;
14027 piano_active_chart_index_array.push_back(
14028 GetpCurrentStack()->GetCurrentEntrydbIndex());
14029 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14032void ChartCanvas::SelectdbChart(
int dbindex) {
14033 if (!GetpCurrentStack())
return;
14036 if (dbindex >= 0) {
14039 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14041 if (pTentative_Chart) {
14042 if (m_singleChart) m_singleChart->Deactivate();
14044 m_singleChart = pTentative_Chart;
14045 m_singleChart->Activate();
14047 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14048 GetpCurrentStack(), m_singleChart->GetFullPath());
14061 double best_scale_ppm = GetBestVPScale(m_singleChart);
14065 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14075void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14078 if (!GetQuiltMode()) {
14079 if (GetpCurrentStack()) {
14080 int stack_index = -1;
14081 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14082 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14083 if (check_dbIndex < 0)
continue;
14085 ChartData->GetChartTableEntry(check_dbIndex);
14086 if (type == cte.GetChartType()) {
14089 }
else if (family == cte.GetChartFamily()) {
14095 if (stack_index >= 0) {
14096 SelectChartFromStack(stack_index);
14100 int sel_dbIndex = -1;
14101 std::vector<int> piano_chart_index_array =
14102 GetQuiltExtendedStackdbIndexArray();
14103 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14104 int check_dbIndex = piano_chart_index_array[i];
14106 if (type == cte.GetChartType()) {
14107 if (IsChartQuiltableRef(check_dbIndex)) {
14108 sel_dbIndex = check_dbIndex;
14111 }
else if (family == cte.GetChartFamily()) {
14112 if (IsChartQuiltableRef(check_dbIndex)) {
14113 sel_dbIndex = check_dbIndex;
14119 if (sel_dbIndex >= 0) {
14120 SelectQuiltRefdbChart(sel_dbIndex,
false);
14122 AdjustQuiltRefChart();
14129 SetQuiltChartHiLiteIndex(-1);
14134bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14135 return std::find(m_tile_yesshow_index_array.begin(),
14136 m_tile_yesshow_index_array.end(),
14137 index) != m_tile_yesshow_index_array.end();
14140bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14141 return std::find(m_tile_noshow_index_array.begin(),
14142 m_tile_noshow_index_array.end(),
14143 index) != m_tile_noshow_index_array.end();
14146void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14147 if (std::find(m_tile_noshow_index_array.begin(),
14148 m_tile_noshow_index_array.end(),
14149 index) == m_tile_noshow_index_array.end()) {
14150 m_tile_noshow_index_array.push_back(index);
14160void ChartCanvas::HandlePianoClick(
14161 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14162 if (g_options && g_options->IsShown())
14164 if (!m_pCurrentStack)
return;
14180 double distance = 25000;
14181 int closest_index = -1;
14182 for (
int chart_index : selected_dbIndex_array) {
14184 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14185 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14188 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14189 if (test_distance < distance) {
14190 distance = test_distance;
14191 closest_index = chart_index;
14195 int selected_dbIndex = selected_dbIndex_array[0];
14196 if (closest_index >= 0) selected_dbIndex = closest_index;
14198 if (!GetQuiltMode()) {
14199 if (m_bpersistent_quilt ) {
14200 if (IsChartQuiltableRef(selected_dbIndex)) {
14201 ToggleCanvasQuiltMode();
14202 SelectQuiltRefdbChart(selected_dbIndex);
14203 m_bpersistent_quilt =
false;
14205 SelectChartFromStack(selected_index);
14208 SelectChartFromStack(selected_index);
14209 g_sticky_chart = selected_dbIndex;
14213 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14217 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14218 bool bfound =
false;
14219 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14220 if (m_tile_noshow_index_array[i] ==
14221 selected_dbIndex) {
14222 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14229 m_tile_noshow_index_array.push_back(selected_dbIndex);
14233 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14234 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14238 if (IsChartQuiltableRef(selected_dbIndex)) {
14244 bool set_scale =
false;
14245 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14246 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14252 SelectQuiltRefdbChart(selected_dbIndex,
true);
14254 SelectQuiltRefdbChart(selected_dbIndex,
false);
14259 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14261 double proposed_scale_onscreen =
14264 if (g_bPreserveScaleOnX) {
14265 proposed_scale_onscreen =
14266 wxMin(proposed_scale_onscreen,
14268 GetCanvasWidth()));
14270 proposed_scale_onscreen =
14271 wxMin(proposed_scale_onscreen,
14273 GetCanvasWidth()));
14275 proposed_scale_onscreen =
14276 wxMax(proposed_scale_onscreen,
14285 ToggleCanvasQuiltMode();
14286 SelectdbChart(selected_dbIndex);
14287 m_bpersistent_quilt =
true;
14292 SetQuiltChartHiLiteIndex(-1);
14293 gFrame->UpdateGlobalMenuItems();
14295 HideChartInfoWindow();
14300void ChartCanvas::HandlePianoRClick(
14301 int x,
int y,
int selected_index,
14302 const std::vector<int> &selected_dbIndex_array) {
14303 if (g_options && g_options->IsShown())
14305 if (!GetpCurrentStack())
return;
14307 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14308 UpdateCanvasControlBar();
14310 SetQuiltChartHiLiteIndex(-1);
14313void ChartCanvas::HandlePianoRollover(
14314 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14315 int n_charts,
int scale) {
14316 if (g_options && g_options->IsShown())
14318 if (!GetpCurrentStack())
return;
14323 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14325 if (!GetQuiltMode()) {
14326 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14329 std::vector<int> piano_chart_index_array;
14330 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14331 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14332 if ((GetpCurrentStack()->nEntry > 1) ||
14333 (piano_chart_index_array.size() >= 1)) {
14334 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14336 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14338 }
else if (GetpCurrentStack()->nEntry == 1) {
14340 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14341 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14342 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14344 }
else if ((-1 == selected_index) &&
14345 (0 == selected_dbIndex_array.size())) {
14346 ShowChartInfoWindow(key_location.x, -1);
14350 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14352 if ((GetpCurrentStack()->nEntry > 1) ||
14353 (piano_chart_index_array.size() >= 1)) {
14355 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14356 selected_dbIndex_array);
14357 else if (n_charts == 1)
14358 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14360 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14367void ChartCanvas::ClearPianoRollover() {
14368 ClearQuiltChartHiLiteIndexArray();
14369 ShowChartInfoWindow(0, -1);
14370 std::vector<int> vec;
14371 ShowCompositeInfoWindow(0, 0, 0, vec);
14375void ChartCanvas::UpdateCanvasControlBar(
void) {
14376 if (m_pianoFrozen)
return;
14378 if (!GetpCurrentStack())
return;
14380 if (!g_bShowChartBar)
return;
14383 int sel_family = -1;
14385 std::vector<int> piano_chart_index_array;
14386 std::vector<int> empty_piano_chart_index_array;
14388 wxString old_hash = m_Piano->GetStoredHash();
14390 if (GetQuiltMode()) {
14391 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14392 GetQuiltFullScreendbIndexArray());
14394 std::vector<int> piano_active_chart_index_array =
14395 GetQuiltCandidatedbIndexArray();
14396 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14398 std::vector<int> piano_eclipsed_chart_index_array =
14399 GetQuiltEclipsedStackdbIndexArray();
14400 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14402 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14403 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14405 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14406 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14408 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14409 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14412 if (m_singleChart) {
14413 sel_type = m_singleChart->GetChartType();
14414 sel_family = m_singleChart->GetChartFamily();
14419 std::vector<int> piano_skew_chart_index_array;
14420 std::vector<int> piano_tmerc_chart_index_array;
14421 std::vector<int> piano_poly_chart_index_array;
14423 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14425 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14426 double skew_norm = ctei.GetChartSkew();
14427 if (skew_norm > 180.) skew_norm -= 360.;
14429 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14430 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14433 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14434 if (fabs(skew_norm) > 1.)
14435 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14437 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14438 }
else if (fabs(skew_norm) > 1.)
14439 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14441 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14442 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14443 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14445 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14446 if (new_hash != old_hash) {
14447 m_Piano->FormatKeys();
14448 HideChartInfoWindow();
14449 m_Piano->ResetRollover();
14450 SetQuiltChartHiLiteIndex(-1);
14451 m_brepaint_piano =
true;
14457 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14459 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14460 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14461 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14462 if (e == CHART_FAMILY_RASTER) mask |= 1;
14463 if (e == CHART_FAMILY_VECTOR) {
14464 if (t == CHART_TYPE_CM93COMP)
14471 wxString s_indicated;
14472 if (sel_type == CHART_TYPE_CM93COMP)
14473 s_indicated =
"cm93";
14475 if (sel_family == CHART_FAMILY_RASTER)
14476 s_indicated =
"raster";
14477 else if (sel_family == CHART_FAMILY_VECTOR)
14478 s_indicated =
"vector";
14481 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14484void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14486void ChartCanvas::PianoPopupMenu(
14487 int x,
int y,
int selected_index,
14488 const std::vector<int> &selected_dbIndex_array) {
14489 if (!GetpCurrentStack())
return;
14492 if (!GetQuiltMode())
return;
14494 m_piano_ctx_menu =
new wxMenu();
14496 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14506 menu_selected_dbIndex = selected_dbIndex_array[0];
14507 menu_selected_index = selected_index;
14510 bool b_is_in_noshow =
false;
14511 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14512 if (m_quilt_noshow_index_array[i] ==
14513 menu_selected_dbIndex)
14515 b_is_in_noshow =
true;
14520 if (b_is_in_noshow) {
14521 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14522 _(
"Show This Chart"));
14523 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14524 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14525 }
else if (GetpCurrentStack()->nEntry > 1) {
14526 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14527 _(
"Hide This Chart"));
14528 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14529 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14533 wxPoint pos = wxPoint(x, y - 30);
14536 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14537 PopupMenu(m_piano_ctx_menu, pos);
14539 delete m_piano_ctx_menu;
14540 m_piano_ctx_menu = NULL;
14542 HideChartInfoWindow();
14543 m_Piano->ResetRollover();
14545 SetQuiltChartHiLiteIndex(-1);
14546 ClearQuiltChartHiLiteIndexArray();
14551void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14552 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14553 if (m_quilt_noshow_index_array[i] ==
14554 menu_selected_dbIndex)
14556 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14562void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14563 if (!GetpCurrentStack())
return;
14566 RemoveChartFromQuilt(menu_selected_dbIndex);
14570 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14571 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14573 int i = menu_selected_index + 1;
14574 bool b_success =
false;
14575 while (i < GetpCurrentStack()->nEntry - 1) {
14576 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14577 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14578 SelectQuiltRefChart(i);
14588 i = menu_selected_index - 1;
14590 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14591 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14592 SelectQuiltRefChart(i);
14602void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14604 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14605 if (m_quilt_noshow_index_array[i] ==
14608 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14613 m_quilt_noshow_index_array.push_back(dbIndex);
14616bool ChartCanvas::UpdateS52State() {
14617 bool retval =
false;
14621 ps52plib->SetShowS57Text(m_encShowText);
14622 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14623 ps52plib->m_bShowSoundg = m_encShowDepth;
14624 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14625 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14628 if (!m_encShowLights)
14629 ps52plib->AddObjNoshow(
"LIGHTS");
14631 ps52plib->RemoveObjNoshow(
"LIGHTS");
14632 ps52plib->SetLightsOff(!m_encShowLights);
14633 ps52plib->m_bExtendLightSectors =
true;
14636 ps52plib->SetAnchorOn(m_encShowAnchor);
14637 ps52plib->SetQualityOfData(m_encShowDataQual);
14643void ChartCanvas::SetShowENCDataQual(
bool show) {
14644 m_encShowDataQual = show;
14645 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14646 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14648 m_s52StateHash = 0;
14651void ChartCanvas::SetShowENCText(
bool show) {
14652 m_encShowText = show;
14653 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14654 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14656 m_s52StateHash = 0;
14659void ChartCanvas::SetENCDisplayCategory(
int category) {
14660 m_encDisplayCategory = category;
14661 m_s52StateHash = 0;
14664void ChartCanvas::SetShowENCDepth(
bool show) {
14665 m_encShowDepth = show;
14666 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14667 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14669 m_s52StateHash = 0;
14672void ChartCanvas::SetShowENCLightDesc(
bool show) {
14673 m_encShowLightDesc = show;
14674 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14675 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14677 m_s52StateHash = 0;
14680void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14681 m_encShowBuoyLabels = show;
14682 m_s52StateHash = 0;
14685void ChartCanvas::SetShowENCLights(
bool show) {
14686 m_encShowLights = show;
14687 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14688 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14690 m_s52StateHash = 0;
14693void ChartCanvas::SetShowENCAnchor(
bool show) {
14694 m_encShowAnchor = show;
14695 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14696 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14698 m_s52StateHash = 0;
14701wxRect ChartCanvas::GetMUIBarRect() {
14704 rv = m_muiBar->GetRect();
14710void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14711 if (!GetAlertString().IsEmpty()) {
14712 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14713 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14715 dc.SetFont(*pfont);
14716 dc.SetPen(*wxTRANSPARENT_PEN);
14718 dc.SetBrush(wxColour(243, 229, 47));
14720 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14724 wxRect sbr = GetScaleBarRect();
14725 int xp = sbr.x + sbr.width + 10;
14726 int yp = (sbr.y + sbr.height) - h;
14728 int wdraw = w + 10;
14729 dc.DrawRectangle(xp, yp, wdraw, h);
14730 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14731 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14741#define BRIGHT_XCALIB
14742#define __OPCPN_USEICC__
14745#ifdef __OPCPN_USEICC__
14746int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14747 double co_green,
double co_blue);
14749wxString temp_file_name;
14753class ocpnCurtain:
public wxDialog
14755 DECLARE_CLASS( ocpnCurtain )
14756 DECLARE_EVENT_TABLE()
14759 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14761 bool ProcessEvent(wxEvent& event);
14765IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14767BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14770ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14772 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14775ocpnCurtain::~ocpnCurtain()
14779bool ocpnCurtain::ProcessEvent(wxEvent& event)
14781 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14782 return GetParent()->GetEventHandler()->ProcessEvent(event);
14787#include <windows.h>
14790typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14791typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14792SetDeviceGammaRamp_ptr_type
14793 g_pSetDeviceGammaRamp;
14794GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14796WORD *g_pSavedGammaMap;
14800int InitScreenBrightness(
void) {
14803 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14807 if (NULL == hGDI32DLL) {
14808 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14810 if (NULL != hGDI32DLL) {
14812 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14813 hGDI32DLL,
"SetDeviceGammaRamp");
14814 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14815 hGDI32DLL,
"GetDeviceGammaRamp");
14818 if ((NULL == g_pSetDeviceGammaRamp) ||
14819 (NULL == g_pGetDeviceGammaRamp)) {
14820 FreeLibrary(hGDI32DLL);
14829 if (!g_pSavedGammaMap) {
14830 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14833 bbr = g_pGetDeviceGammaRamp(
14834 hDC, g_pSavedGammaMap);
14835 ReleaseDC(NULL, hDC);
14840 wxRegKey *pRegKey =
new wxRegKey(
14841 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14842 "NT\\CurrentVersion\\ICM");
14843 if (!pRegKey->Exists()) pRegKey->Create();
14844 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14846 g_brightness_init =
true;
14852 if (NULL == g_pcurtain) {
14853 if (gFrame->CanSetTransparent()) {
14855 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14856 wxPoint(0, 0), ::wxGetDisplaySize(),
14857 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14858 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14865 g_pcurtain->Hide();
14867 HWND hWnd = GetHwndOf(g_pcurtain);
14868 SetWindowLong(hWnd, GWL_EXSTYLE,
14869 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14870 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14871 g_pcurtain->SetTransparent(0);
14873 g_pcurtain->Maximize();
14874 g_pcurtain->Show();
14877 g_pcurtain->Enable();
14878 g_pcurtain->Disable();
14885 g_brightness_init =
true;
14891 wxString cmd(
"xcalib -version");
14893 wxArrayString output;
14894 long r = wxExecute(cmd, output);
14897 " External application \"xcalib\" not found. Screen brightness "
14900 g_brightness_init =
true;
14905int RestoreScreenBrightness(
void) {
14908 if (g_pSavedGammaMap) {
14909 HDC hDC = GetDC(NULL);
14910 g_pSetDeviceGammaRamp(hDC,
14912 ReleaseDC(NULL, hDC);
14914 free(g_pSavedGammaMap);
14915 g_pSavedGammaMap = NULL;
14919 g_pcurtain->Close();
14920 g_pcurtain->Destroy();
14924 g_brightness_init =
false;
14929#ifdef BRIGHT_XCALIB
14930 if (g_brightness_init) {
14932 cmd =
"xcalib -clear";
14933 wxExecute(cmd, wxEXEC_ASYNC);
14934 g_brightness_init =
false;
14944int SetScreenBrightness(
int brightness) {
14951 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14953 g_pcurtain->Close();
14954 g_pcurtain->Destroy();
14958 InitScreenBrightness();
14960 if (NULL == hGDI32DLL) {
14962 wchar_t wdll_name[80];
14963 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14964 LPCWSTR cstr = wdll_name;
14966 hGDI32DLL = LoadLibrary(cstr);
14968 if (NULL != hGDI32DLL) {
14970 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14971 hGDI32DLL,
"SetDeviceGammaRamp");
14972 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14973 hGDI32DLL,
"GetDeviceGammaRamp");
14976 if ((NULL == g_pSetDeviceGammaRamp) ||
14977 (NULL == g_pGetDeviceGammaRamp)) {
14978 FreeLibrary(hGDI32DLL);
14985 HDC hDC = GetDC(NULL);
14996 int increment = brightness * 256 / 100;
14999 WORD GammaTable[3][256];
15002 for (
int i = 0; i < 256; i++) {
15003 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15004 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15005 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15007 table_val += increment;
15009 if (table_val > 65535) table_val = 65535;
15012 g_pSetDeviceGammaRamp(hDC, GammaTable);
15013 ReleaseDC(NULL, hDC);
15020 if (g_pSavedGammaMap) {
15021 HDC hDC = GetDC(NULL);
15022 g_pSetDeviceGammaRamp(hDC,
15024 ReleaseDC(NULL, hDC);
15027 if (brightness < 100) {
15028 if (NULL == g_pcurtain) InitScreenBrightness();
15031 int sbrite = wxMax(1, brightness);
15032 sbrite = wxMin(100, sbrite);
15034 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15038 g_pcurtain->Close();
15039 g_pcurtain->Destroy();
15049#ifdef BRIGHT_XCALIB
15051 if (!g_brightness_init) {
15052 last_brightness = 100;
15053 g_brightness_init =
true;
15054 temp_file_name = wxFileName::CreateTempFileName(
"");
15055 InitScreenBrightness();
15058#ifdef __OPCPN_USEICC__
15061 if (!CreateSimpleICCProfileFile(
15062 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15063 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15064 wxString cmd(
"xcalib ");
15065 cmd += temp_file_name;
15067 wxExecute(cmd, wxEXEC_ASYNC);
15076 if (brightness > last_brightness) {
15078 cmd =
"xcalib -clear";
15079 wxExecute(cmd, wxEXEC_ASYNC);
15081 ::wxMilliSleep(10);
15083 int brite_adj = wxMax(1, brightness);
15084 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15085 wxExecute(cmd, wxEXEC_ASYNC);
15087 int brite_adj = wxMax(1, brightness);
15088 int factor = (brite_adj * 100) / last_brightness;
15089 factor = wxMax(1, factor);
15091 cmd.Printf(
"xcalib -co %2d -a", factor);
15092 wxExecute(cmd, wxEXEC_ASYNC);
15097 last_brightness = brightness;
15104#ifdef __OPCPN_USEICC__
15106#define MLUT_TAG 0x6d4c5554L
15107#define VCGT_TAG 0x76636774L
15109int GetIntEndian(
unsigned char *s) {
15114 p = (
unsigned char *)&ret;
15117 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15119 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15124unsigned short GetShortEndian(
unsigned char *s) {
15125 unsigned short ret;
15129 p = (
unsigned char *)&ret;
15132 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15134 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15140int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15141 double co_green,
double co_blue) {
15145 fp = fopen(file_name,
"wb");
15146 if (!fp)
return -1;
15152 for (
int i = 0; i < 128; i++) header[i] = 0;
15154 fwrite(header, 128, 1, fp);
15158 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15159 fwrite(&numTags, 1, 4, fp);
15161 int tagName0 = VCGT_TAG;
15162 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15163 fwrite(&tagName, 1, 4, fp);
15165 int tagOffset0 = 128 + 4 *
sizeof(int);
15166 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15167 fwrite(&tagOffset, 1, 4, fp);
15170 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15171 fwrite(&tagSize, 1, 4, fp);
15173 fwrite(&tagName, 1, 4, fp);
15175 fwrite(&tagName, 1, 4, fp);
15180 int gammatype0 = 0;
15181 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15182 fwrite(&gammatype, 1, 4, fp);
15184 int numChannels0 = 3;
15185 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15186 fwrite(&numChannels, 1, 2, fp);
15188 int numEntries0 = 256;
15189 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15190 fwrite(&numEntries, 1, 2, fp);
15192 int entrySize0 = 1;
15193 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15194 fwrite(&entrySize, 1, 2, fp);
15196 unsigned char ramp[256];
15199 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15200 fwrite(ramp, 256, 1, fp);
15203 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15204 fwrite(ramp, 256, 1, fp);
15207 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15208 fwrite(ramp, 256, 1, fp);
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.
double GetCanvasTrueScale()
Return the physical pixels per meter at chart center, accounting for latitude distortion.
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)
Set the viewport center point.
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.
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.
void SetBoxes(void)
Computes the bounding box coordinates for the current viewport.
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)
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.
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.
Multiplexer class and helpers.
Class NotificationManager.
#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 GetChartbarHeight(void)
Gets height of chart bar in pixels.
int GetCanvasCount()
Gets total number of chart canvases.
PI_DisCat GetENCDisplayCategory(int CanvasIndex)
Gets current ENC display category.
int GetCanvasIndexUnderMouse(void)
Gets index of chart canvas under mouse cursor.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
Tools to send data to plugins.
PlugInManager and helper classes – Mostly gui parts (dialogs) and plugin API stuff.
Represents an entry in the chart table, containing information about a single chart.