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"
74#include "DetailSlider.h"
76#include "hotkeys_dlg.h"
78#include "glTextureDescriptor.h"
79#include "GoToPositionDialog.h"
81#include "iENCToolbar.h"
88#include "OCPN_AUIManager.h"
90#include "ocpn_frame.h"
91#include "ocpn_pixel.h"
92#include "OCPNRegion.h"
98#include "routemanagerdialog.h"
99#include "route_point_gui.h"
100#include "RoutePropDlgImpl.h"
103#include "S57QueryDialog.h"
105#include "shapefile_basemap.h"
107#include "SystemCmdSound.h"
111#include "tide_time.h"
114#include "track_gui.h"
115#include "TrackPropDlg.h"
118#include "s57_ocpn_utils.h"
121#include "androidUTIL.h"
125#include "glChartCanvas.h"
126#include "notification_manager_gui.h"
131#include <wx/msw/msvcrt.h>
140#define printf printf2
142int __cdecl printf2(
const char *format, ...) {
146 va_start(argptr, format);
147 int ret = vsnprintf(str,
sizeof(str), format, argptr);
149 OutputDebugStringA(str);
154#if defined(__MSVC__) && (_MSC_VER < 1700)
155#define trunc(d) ((d > 0) ? floor(d) : ceil(d))
161#define OCPN_ALT_MENUBAR 1
169extern ColorScheme global_color_scheme;
170extern wxColor GetDimColor(wxColor c);
172static bool g_bSmoothRecenter =
true;
173static bool bDrawCurrentValues;
195static bool mouse_leftisdown;
196static bool g_brouteCreating;
197static int r_gamma_mult;
198static int g_gamma_mult;
199static int b_gamma_mult;
200static int gamma_state;
201static bool g_brightness_init;
202static int last_brightness;
203static wxGLContext *g_pGLcontext;
206static wxDialog *g_pcurtain;
208static wxString g_lastS52PLIBPluginMessage;
211#define MAX_BRIGHT 100
217EVT_PAINT(ChartCanvas::OnPaint)
218EVT_ACTIVATE(ChartCanvas::OnActivate)
219EVT_SIZE(ChartCanvas::OnSize)
220#ifndef HAVE_WX_GESTURE_EVENTS
221EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
223EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
224EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
225EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
226EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
227EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
228EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
229EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
230EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
231EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
232EVT_KEY_UP(ChartCanvas::OnKeyUp)
233EVT_CHAR(ChartCanvas::OnKeyChar)
234EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
235EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
236EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
237EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
238EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
239EVT_TIMER(MOVEMENT_VP_TIMER, ChartCanvas::MovementVPTimerEvent)
240EVT_TIMER(DRAG_INERTIA_TIMER, ChartCanvas::OnChartDragInertiaTimer)
241EVT_TIMER(JUMP_EASE_TIMER, ChartCanvas::OnJumpEaseTimer)
247 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER),
248 m_nmea_log(nmea_log) {
249 parent_frame = (
MyFrame *)frame;
250 m_canvasIndex = canvasIndex;
254 SetBackgroundColour(wxColour(0, 0, 0));
255 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
259 m_bDrawingRoute =
false;
260 m_bRouteEditing =
false;
261 m_bMarkEditing =
false;
262 m_bRoutePoinDragging =
false;
263 m_bIsInRadius =
false;
264 m_bMayToggleMenuBar =
true;
267 m_bShowNavobjects =
true;
269 m_bAppendingRoute =
false;
270 pThumbDIBShow = NULL;
271 m_bShowCurrent =
false;
273 bShowingCurrent =
false;
277 m_b_paint_enable =
true;
280 pss_overlay_bmp = NULL;
281 pss_overlay_mask = NULL;
282 m_bChartDragging =
false;
283 m_bMeasure_Active =
false;
284 m_bMeasure_DistCircle =
false;
285 m_pMeasureRoute = NULL;
286 m_pTrackRolloverWin = NULL;
287 m_pRouteRolloverWin = NULL;
288 m_pAISRolloverWin = NULL;
290 m_disable_edge_pan =
false;
291 m_dragoffsetSet =
false;
295 m_singleChart = NULL;
296 m_upMode = NORTH_UP_MODE;
298 m_bShowAISScaled =
false;
299 m_timed_move_vp_active =
false;
306 m_pSelectedRoute = NULL;
307 m_pSelectedTrack = NULL;
308 m_pRoutePointEditTarget = NULL;
309 m_pFoundPoint = NULL;
310 m_pMouseRoute = NULL;
311 m_prev_pMousePoint = NULL;
312 m_pEditRouteArray = NULL;
313 m_pFoundRoutePoint = NULL;
314 m_FinishRouteOnKillFocus =
true;
316 m_pRolloverRouteSeg = NULL;
317 m_pRolloverTrackSeg = NULL;
318 m_bsectors_shown =
false;
320 m_bbrightdir =
false;
325 m_pos_image_user_day = NULL;
326 m_pos_image_user_dusk = NULL;
327 m_pos_image_user_night = NULL;
328 m_pos_image_user_grey_day = NULL;
329 m_pos_image_user_grey_dusk = NULL;
330 m_pos_image_user_grey_night = NULL;
333 m_rotation_speed = 0;
339 m_pos_image_user_yellow_day = NULL;
340 m_pos_image_user_yellow_dusk = NULL;
341 m_pos_image_user_yellow_night = NULL;
343 SetOwnShipState(SHIP_INVALID);
345 undo =
new Undo(
this);
351 m_focus_indicator_pix = 1;
353 m_pCurrentStack = NULL;
354 m_bpersistent_quilt =
false;
355 m_piano_ctx_menu = NULL;
357 m_NotificationsList = NULL;
358 m_notification_button = NULL;
360 g_ChartNotRenderScaleFactor = 2.0;
361 m_bShowScaleInStatusBar =
true;
364 m_bShowScaleInStatusBar =
false;
365 m_show_focus_bar =
true;
367 m_bShowOutlines =
false;
368 m_bDisplayGrid =
false;
369 m_bShowDepthUnits =
true;
370 m_encDisplayCategory = (int)STANDARD;
372 m_encShowLights =
true;
373 m_encShowAnchor =
true;
374 m_encShowDataQual =
false;
376 m_pQuilt =
new Quilt(
this);
381 g_PrintingInProgress =
false;
383#ifdef HAVE_WX_GESTURE_EVENTS
384 m_oldVPSScale = -1.0;
385 m_popupWanted =
false;
391 singleClickEventIsValid =
false;
400 pCursorPencil = NULL;
405 SetCursor(*pCursorArrow);
407 pPanTimer =
new wxTimer(
this, m_MouseDragging);
410 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
411 pMovementTimer->Stop();
413 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
414 pMovementStopTimer->Stop();
416 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
417 pRotDefTimer->Stop();
419 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
420 m_DoubleClickTimer->Stop();
422 m_VPMovementTimer.SetOwner(
this, MOVEMENT_VP_TIMER);
423 m_chart_drag_inertia_timer.SetOwner(
this, DRAG_INERTIA_TIMER);
424 m_chart_drag_inertia_active =
false;
426 m_easeTimer.SetOwner(
this, JUMP_EASE_TIMER);
427 m_animationActive =
false;
431 m_panx_target_final = m_pany_target_final = 0;
432 m_panx_target_now = m_pany_target_now = 0;
434 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
435 pCurTrackTimer->Stop();
436 m_curtrack_timer_msec = 10;
438 m_wheelzoom_stop_oneshot = 0;
439 m_last_wheel_dir = 0;
441 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
443 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
445 m_rollover_popup_timer_msec = 20;
447 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
449 m_b_rot_hidef =
true;
454 m_upMode = NORTH_UP_MODE;
455 m_bLookAhead =
false;
459 m_cs = GLOBAL_COLOR_SCHEME_DAY;
462 VPoint.view_scale_ppm = 1;
466 m_canvas_scale_factor = 1.;
468 m_canvas_width = 1000;
470 m_overzoomTextWidth = 0;
471 m_overzoomTextHeight = 0;
475 gShapeBasemap.Reset();
480 m_pEM_Fathoms = NULL;
482 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
484 m_pEM_OverZoom = NULL;
486 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
494 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
497 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
500 double factor_dusk = 0.5;
501 double factor_night = 0.25;
504 m_os_image_red_day = style->GetIcon(
"ship-red").ConvertToImage();
506 int rimg_width = m_os_image_red_day.GetWidth();
507 int rimg_height = m_os_image_red_day.GetHeight();
509 m_os_image_red_dusk = m_os_image_red_day.Copy();
510 m_os_image_red_night = m_os_image_red_day.Copy();
512 for (
int iy = 0; iy < rimg_height; iy++) {
513 for (
int ix = 0; ix < rimg_width; ix++) {
514 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
515 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
516 m_os_image_red_day.GetGreen(ix, iy),
517 m_os_image_red_day.GetBlue(ix, iy));
518 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
519 hsv.value = hsv.value * factor_dusk;
520 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
521 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
523 hsv = wxImage::RGBtoHSV(rgb);
524 hsv.value = hsv.value * factor_night;
525 nrgb = wxImage::HSVtoRGB(hsv);
526 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
532 m_os_image_grey_day =
533 style->GetIcon(
"ship-red").ConvertToImage().ConvertToGreyscale();
535 int gimg_width = m_os_image_grey_day.GetWidth();
536 int gimg_height = m_os_image_grey_day.GetHeight();
538 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
539 m_os_image_grey_night = m_os_image_grey_day.Copy();
541 for (
int iy = 0; iy < gimg_height; iy++) {
542 for (
int ix = 0; ix < gimg_width; ix++) {
543 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
544 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
545 m_os_image_grey_day.GetGreen(ix, iy),
546 m_os_image_grey_day.GetBlue(ix, iy));
547 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
548 hsv.value = hsv.value * factor_dusk;
549 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
550 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
552 hsv = wxImage::RGBtoHSV(rgb);
553 hsv.value = hsv.value * factor_night;
554 nrgb = wxImage::HSVtoRGB(hsv);
555 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
561 m_os_image_yellow_day = m_os_image_red_day.Copy();
563 gimg_width = m_os_image_yellow_day.GetWidth();
564 gimg_height = m_os_image_yellow_day.GetHeight();
566 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
567 m_os_image_yellow_night = m_os_image_red_day.Copy();
569 for (
int iy = 0; iy < gimg_height; iy++) {
570 for (
int ix = 0; ix < gimg_width; ix++) {
571 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
572 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
573 m_os_image_yellow_day.GetGreen(ix, iy),
574 m_os_image_yellow_day.GetBlue(ix, iy));
575 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
576 hsv.hue += 60. / 360.;
577 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
578 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
580 hsv = wxImage::RGBtoHSV(rgb);
581 hsv.value = hsv.value * factor_dusk;
582 hsv.hue += 60. / 360.;
583 nrgb = wxImage::HSVtoRGB(hsv);
584 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
586 hsv = wxImage::RGBtoHSV(rgb);
587 hsv.hue += 60. / 360.;
588 hsv.value = hsv.value * factor_night;
589 nrgb = wxImage::HSVtoRGB(hsv);
590 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
596 m_pos_image_red = &m_os_image_red_day;
597 m_pos_image_yellow = &m_os_image_yellow_day;
598 m_pos_image_grey = &m_os_image_grey_day;
602 m_pBrightPopup = NULL;
605 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
610 m_Piano =
new Piano(
this);
612 m_bShowCompassWin =
true;
614 m_Compass->SetScaleFactor(g_compass_scalefactor);
615 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
618 m_notification_button->SetScaleFactor(g_compass_scalefactor);
619 m_notification_button->Show(
true);
621 m_pianoFrozen =
false;
623 SetMinSize(wxSize(200, 200));
625 m_displayScale = 1.0;
626#if defined(__WXOSX__) || defined(__WXGTK3__)
628 m_displayScale = GetContentScaleFactor();
630 VPoint.SetPixelScale(m_displayScale);
632#ifdef HAVE_WX_GESTURE_EVENTS
635 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE | wxTOUCH_PRESS_GESTURES)) {
636 wxLogError(
"Failed to enable touch events");
641 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
642 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
644 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
645 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
647 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
648 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
650 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
651 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
656 auto ¬eman = NotificationManager::GetInstance();
658 wxDEFINE_EVENT(EVT_NOTIFICATIONLIST_CHANGE, wxCommandEvent);
659 evt_notificationlist_change_listener.Listen(
660 noteman.evt_notificationlist_change,
this, EVT_NOTIFICATIONLIST_CHANGE);
661 Bind(EVT_NOTIFICATIONLIST_CHANGE, [&](wxCommandEvent &) {
662 if (m_NotificationsList && m_NotificationsList->IsShown()) {
663 m_NotificationsList->ReloadNotificationList();
669ChartCanvas::~ChartCanvas() {
670 delete pThumbDIBShow;
678 delete pCursorPencil;
682 delete pMovementTimer;
683 delete pMovementStopTimer;
684 delete pCurTrackTimer;
686 delete m_DoubleClickTimer;
688 delete m_pTrackRolloverWin;
689 delete m_pRouteRolloverWin;
690 delete m_pAISRolloverWin;
691 delete m_pBrightPopup;
697 m_dc_route.SelectObject(wxNullBitmap);
700 delete pWorldBackgroundChart;
701 delete pss_overlay_bmp;
705 delete m_pEM_Fathoms;
707 delete m_pEM_OverZoom;
712 delete m_pos_image_user_day;
713 delete m_pos_image_user_dusk;
714 delete m_pos_image_user_night;
715 delete m_pos_image_user_grey_day;
716 delete m_pos_image_user_grey_dusk;
717 delete m_pos_image_user_grey_night;
718 delete m_pos_image_user_yellow_day;
719 delete m_pos_image_user_yellow_dusk;
720 delete m_pos_image_user_yellow_night;
724 if (!g_bdisable_opengl) {
727#if wxCHECK_VERSION(2, 9, 0)
728 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
735 MUIBar *muiBar = m_muiBar;
739 delete m_pCurrentStack;
744void ChartCanvas::SetupGridFont() {
745 wxFont *dFont = FontMgr::Get().
GetFont(_(
"GridText"), 0);
747 int gridFontSize = wxMax(10, dFont->GetPointSize() * dpi_factor);
749 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
750 FALSE, wxString(_T (
"Arial" )));
753void ChartCanvas::RebuildCursors() {
759 delete pCursorPencil;
763 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
767 wxImage ICursorLeft = style->GetIcon(
"left").ConvertToImage();
768 wxImage ICursorRight = style->GetIcon(
"right").ConvertToImage();
769 wxImage ICursorUp = style->GetIcon(
"up").ConvertToImage();
770 wxImage ICursorDown = style->GetIcon(
"down").ConvertToImage();
771 wxImage ICursorPencil =
772 style->GetIconScaled(
"pencil", pencilScale).ConvertToImage();
773 wxImage ICursorCross = style->GetIcon(
"cross").ConvertToImage();
775#if !defined(__WXMSW__) && !defined(__WXQT__)
776 ICursorLeft.ConvertAlphaToMask(128);
777 ICursorRight.ConvertAlphaToMask(128);
778 ICursorUp.ConvertAlphaToMask(128);
779 ICursorDown.ConvertAlphaToMask(128);
780 ICursorPencil.ConvertAlphaToMask(10);
781 ICursorCross.ConvertAlphaToMask(10);
784 if (ICursorLeft.Ok()) {
785 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
786 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
787 pCursorLeft =
new wxCursor(ICursorLeft);
789 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
791 if (ICursorRight.Ok()) {
792 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
793 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
794 pCursorRight =
new wxCursor(ICursorRight);
796 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
798 if (ICursorUp.Ok()) {
799 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
800 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
801 pCursorUp =
new wxCursor(ICursorUp);
803 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
805 if (ICursorDown.Ok()) {
806 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
807 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
808 pCursorDown =
new wxCursor(ICursorDown);
810 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
812 if (ICursorPencil.Ok()) {
813 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
814 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
815 pCursorPencil =
new wxCursor(ICursorPencil);
817 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
819 if (ICursorCross.Ok()) {
820 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
821 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
822 pCursorCross =
new wxCursor(ICursorCross);
824 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
826 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
827 pPlugIn_Cursor = NULL;
830void ChartCanvas::CanvasApplyLocale() {
831 CreateDepthUnitEmbossMaps(m_cs);
832 CreateOZEmbossMapData(m_cs);
835void ChartCanvas::SetupGlCanvas() {
838 if (!g_bdisable_opengl) {
840 wxLogMessage(
"Creating glChartCanvas");
845 if (IsPrimaryCanvas()) {
852 wxGLContext *pctx =
new wxGLContext(m_glcc);
853 m_glcc->SetContext(pctx);
857 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
859 m_glcc->SetContext(g_pGLcontext);
869 if (!g_bdisable_opengl) {
872 wxLogMessage(
"Creating glChartCanvas");
876 if (IsPrimaryCanvas()) {
877 qDebug() <<
"Creating Primary glChartCanvas";
885 wxGLContext *pctx =
new wxGLContext(m_glcc);
886 m_glcc->SetContext(pctx);
888 m_glcc->m_pParentCanvas =
this;
891 qDebug() <<
"Creating Secondary glChartCanvas";
897 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
900 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
901 m_glcc->SetContext(pwxctx);
902 m_glcc->m_pParentCanvas =
this;
910void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
911 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
926 if (m_routeState && m_FinishRouteOnKillFocus)
927 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
929 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
933void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
934 m_routeFinishTimer.Stop();
938 gFrame->UpdateGlobalMenuItems(
this);
940 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
943void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
944 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
947#ifdef HAVE_WX_GESTURE_EVENTS
948void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
954 m_popupWanted =
true;
957void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
961void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
963void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
965void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
966 wxPoint pos =
event.GetPosition();
970 if (!m_popupWanted) {
971 wxMouseEvent ev(wxEVT_LEFT_UP);
978 m_popupWanted =
false;
980 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
987void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
990 wxPoint pos =
event.GetPosition();
994void ChartCanvas::OnMotion(wxMouseEvent &event) {
999 event.m_leftDown = m_leftdown;
1003void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1005 if (event.IsGestureEnd())
return;
1007 double factor =
event.GetZoomFactor();
1009 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1014 double wanted_factor = m_oldVPSScale / current_vps * factor;
1019 if (event.IsGestureStart()) {
1020 m_zoomStartPoint =
event.GetPosition();
1022 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1024 m_zoomStartPoint =
event.GetPosition();
1028void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1030void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1031 DoRotateCanvas(0.0);
1035void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1040 m_restore_dbindex = pcc->DBindex;
1042 if (pcc->GroupID < 0) pcc->GroupID = 0;
1047 m_groupIndex = pcc->GroupID;
1049 if (pcc->
bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1063 m_encDisplayCategory = pcc->nENCDisplayCategory;
1064 m_encShowDepth = pcc->bShowENCDepths;
1065 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1066 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1067 m_encShowLights = pcc->bShowENCLights;
1068 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1069 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1070 m_encShowDataQual = pcc->bShowENCDataQuality;
1074 m_upMode = NORTH_UP_MODE;
1076 m_upMode = COURSE_UP_MODE;
1078 m_upMode = HEAD_UP_MODE;
1082 m_singleChart = NULL;
1085void ChartCanvas::ApplyGlobalSettings() {
1088 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1089 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1091 m_notification_button->UpdateStatus();
1094void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1095 bool groupOK = CheckGroup(m_groupIndex);
1098 SetGroupIndex(m_groupIndex,
true);
1102void ChartCanvas::SetShowGPS(
bool bshow) {
1103 if (m_bShowGPS != bshow) {
1106 m_Compass->SetScaleFactor(g_compass_scalefactor);
1107 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1112void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1113 m_bShowCompassWin = bshow;
1115 m_Compass->Show(m_bShowCompassWin && g_bShowCompassWin);
1116 if (m_bShowCompassWin && g_bShowCompassWin) m_Compass->UpdateStatus();
1120int ChartCanvas::GetPianoHeight() {
1122 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1127void ChartCanvas::ConfigureChartBar() {
1130 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1131 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1133 if (GetQuiltMode()) {
1134 m_Piano->SetRoundedRectangles(
true);
1136 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1137 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(
"polyprj")));
1138 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1141void ChartCanvas::ShowTides(
bool bShow) {
1142 gFrame->LoadHarmonics();
1144 if (ptcmgr->IsReady()) {
1145 SetbShowTide(bShow);
1147 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1149 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1150 SetbShowTide(
false);
1151 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1154 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1155 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1166void ChartCanvas::ShowCurrents(
bool bShow) {
1167 gFrame->LoadHarmonics();
1169 if (ptcmgr->IsReady()) {
1170 SetbShowCurrent(bShow);
1171 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1173 wxLogMessage(
"Chart1::Event...TCMgr Not Available");
1174 SetbShowCurrent(
false);
1175 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1178 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1179 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1196void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1198void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1201 int new_index = index;
1204 bool bgroup_override =
false;
1205 int old_group_index = new_index;
1207 if (!CheckGroup(new_index)) {
1209 bgroup_override =
true;
1212 if (!autoSwitch && (index <= (
int)
g_pGroupArray->GetCount()))
1216 int current_chart_native_scale = GetCanvasChartNativeScale();
1219 m_groupIndex = new_index;
1225 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1229 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1233 g_sticky_chart = -1;
1237 UpdateCanvasOnGroupChange();
1240 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1242 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1245 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1246 double best_scale = GetBestStartScale(dbi_hint, vp);
1250 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1254 canvasChartsRefresh(dbi_hint);
1256 UpdateCanvasControlBar();
1258 if (!autoSwitch && bgroup_override) {
1260 wxString msg(_(
"Group \""));
1263 msg += pGroup->m_group_name;
1265 msg += _(
"\" is empty.");
1267 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1274 if (bgroup_override) {
1275 wxString msg(_(
"Group \""));
1278 msg += pGroup->m_group_name;
1280 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1282 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1286bool ChartCanvas::CheckGroup(
int igroup) {
1289 if (igroup == 0)
return true;
1296 if (pGroup->m_element_array.empty())
1300 for (
const auto &elem : pGroup->m_element_array) {
1301 for (
unsigned int ic = 0;
1302 ic < (
unsigned int)
ChartData->GetChartTableEntries(); ic++) {
1304 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1306 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1311 for (
const auto &elem : pGroup->m_element_array) {
1312 const wxString &element_root = elem.m_element_name;
1313 wxString test_string =
"GSHH";
1314 if (element_root.Upper().Contains(test_string))
return true;
1320void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1323 AbstractPlatform::ShowBusySpinner();
1327 SetQuiltRefChart(-1);
1329 m_singleChart = NULL;
1335 if (!m_pCurrentStack) {
1337 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1340 if (-1 != dbi_hint) {
1341 if (GetQuiltMode()) {
1342 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1343 SetQuiltRefChart(dbi_hint);
1347 pTentative_Chart =
ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1349 if (pTentative_Chart) {
1352 if (m_singleChart) m_singleChart->Deactivate();
1354 m_singleChart = pTentative_Chart;
1355 m_singleChart->Activate();
1357 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
1358 GetpCurrentStack(), m_singleChart->GetFullPath());
1366 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1367 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1368 SetQuiltRefChart(selected_index);
1372 SetupCanvasQuiltMode();
1373 if (!GetQuiltMode() && m_singleChart == 0) {
1375 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1376 m_singleChart = pDummyChart;
1382 UpdateCanvasControlBar();
1383 UpdateGPSCompassStatusBox(
true);
1385 SetCursor(wxCURSOR_ARROW);
1387 AbstractPlatform::HideBusySpinner();
1390bool ChartCanvas::DoCanvasUpdate(
void) {
1392 double vpLat, vpLon;
1393 bool blong_jump =
false;
1394 meters_to_shift = 0;
1397 bool bNewChart =
false;
1398 bool bNewView =
false;
1399 bool bCanvasChartAutoOpen =
true;
1401 bool bNewPiano =
false;
1402 bool bOpenSpecified;
1408 if (bDBUpdateInProgress)
return false;
1412 if (m_chart_drag_inertia_active)
return false;
1438 double dx = m_OSoffsetx;
1439 double dy = m_OSoffsety;
1443 if (GetUpMode() == NORTH_UP_MODE) {
1444 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1446 double offset_angle = atan2(d_north, d_east);
1447 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1448 double chart_angle = GetVPRotation();
1449 double target_angle = chart_angle + offset_angle;
1450 double d_east_mod = offset_distance * cos(target_angle);
1451 double d_north_mod = offset_distance * sin(target_angle);
1452 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1456 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1457 double cog_to_use = gCog;
1459 (fabs(gCog - gCog_gt) > 20)) {
1460 cog_to_use = gCog_gt;
1463 if (!g_btenhertz) cog_to_use =
g_COGAvg;
1465 double angle = cog_to_use + (GetVPRotation() * 180. / PI);
1467 double pixel_deltay = (cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1468 double pixel_deltax = (sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1470 double pixel_delta_tent =
1471 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1473 double pixel_delta = 0;
1478 if (!std::isnan(gSog)) {
1482 pixel_delta = pixel_delta_tent;
1485 meters_to_shift = 0;
1487 if (!std::isnan(gCog)) {
1488 meters_to_shift = cos(gLat * PI / 180.) * pixel_delta /
GetVPScale();
1489 dir_to_shift = cog_to_use;
1490 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1496 }
else if (m_bLookAhead && (!bGPSValid || m_MouseDragging)) {
1510 if (GetQuiltMode()) {
1511 int current_db_index = -1;
1512 if (m_pCurrentStack)
1515 ->GetCurrentEntrydbIndex();
1523 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1525 if (m_pCurrentStack->nEntry) {
1526 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1528 SelectQuiltRefdbChart(new_dbIndex,
true);
1529 m_bautofind =
false;
1533 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1534 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1539 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1545 double proposed_scale_onscreen =
1548 int initial_db_index = m_restore_dbindex;
1549 if (initial_db_index < 0) {
1550 if (m_pCurrentStack->nEntry) {
1552 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1557 if (m_pCurrentStack->nEntry) {
1558 int initial_type =
ChartData->GetDBChartType(initial_db_index);
1563 if (!IsChartQuiltableRef(initial_db_index)) {
1567 int stack_index = 0;
1569 if (stack_index >= 0) {
1570 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1571 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1572 if (IsChartQuiltableRef(test_db_index) &&
1574 ChartData->GetDBChartType(initial_db_index))) {
1575 initial_db_index = test_db_index;
1585 SetQuiltRefChart(initial_db_index);
1586 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1594 0, GetVPRotation());
1599 bool super_jump =
false;
1601 double pixlt = fabs(vpLat - m_vLat) * 1852 * 60 *
GetVPScale();
1602 double pixlg = fabs(vpLon - m_vLon) * 1852 * 60 *
GetVPScale();
1603 if (wxMax(pixlt, pixlg) > GetCanvasWidth()) super_jump =
true;
1606 if (m_bFollow && g_btenhertz && !super_jump && !m_bLookAhead && !g_btouch && !m_bzooming) {
1608 if (blong_jump) nstep = 20;
1609 StartTimedMovementVP(vpLat, vpLon, nstep);
1620 pLast_Ch = m_singleChart;
1621 ChartTypeEnum new_open_type;
1622 ChartFamilyEnum new_open_family;
1624 new_open_type = pLast_Ch->GetChartType();
1625 new_open_family = pLast_Ch->GetChartFamily();
1627 new_open_type = CHART_TYPE_KAP;
1628 new_open_family = CHART_FAMILY_RASTER;
1631 bOpenSpecified = m_bFirstAuto;
1634 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1637 if (0 ==
ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1639 if (NULL == pDummyChart) {
1645 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1647 m_singleChart = pDummyChart;
1652 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1654 bNewView |=
SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1657 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1658 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1665 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1671 if (!
ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1676 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1679 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1684 if (NULL != m_singleChart)
1685 tEntry =
ChartData->GetStackEntry(m_pCurrentStack,
1686 m_singleChart->GetFullPath());
1689 m_pCurrentStack->CurrentStackEntry = tEntry;
1699 if (bCanvasChartAutoOpen) {
1700 bool search_direction =
1702 int start_index = 0;
1706 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1707 (LastStack.nEntry == 0)) {
1708 search_direction =
true;
1709 start_index = m_pCurrentStack->nEntry - 1;
1713 if (bOpenSpecified) {
1714 search_direction =
false;
1716 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1719 new_open_type = CHART_TYPE_DONTCARE;
1722 pProposed =
ChartData->OpenStackChartConditional(
1723 m_pCurrentStack, start_index, search_direction, new_open_type,
1727 if (NULL == pProposed)
1728 pProposed =
ChartData->OpenStackChartConditional(
1729 m_pCurrentStack, start_index, search_direction,
1730 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1732 if (NULL == pProposed)
1733 pProposed =
ChartData->OpenStackChartConditional(
1734 m_pCurrentStack, start_index, search_direction,
1735 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1746 if (NULL == pProposed) {
1747 if (NULL == pDummyChart) {
1753 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1755 pProposed = pDummyChart;
1759 if (m_singleChart) m_singleChart->Deactivate();
1760 m_singleChart = pProposed;
1762 if (m_singleChart) {
1763 m_singleChart->Activate();
1764 m_pCurrentStack->CurrentStackEntry =
ChartData->GetStackEntry(
1765 m_pCurrentStack, m_singleChart->GetFullPath());
1770 if (NULL != m_singleChart) {
1776 if (!GetVP().IsValid())
1777 set_scale = 1. / 20000.;
1779 double proposed_scale_onscreen;
1782 double new_scale_ppm =
1783 m_singleChart->GetNearestPreferredScalePPM(
GetVPScale());
1791 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1792 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1793 double equivalent_vp_scale =
1795 double new_scale_ppm =
1796 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1801 proposed_scale_onscreen =
1802 wxMin(proposed_scale_onscreen,
1805 proposed_scale_onscreen =
1806 wxMax(proposed_scale_onscreen,
1815 m_singleChart->GetChartSkew() * PI / 180.,
1822 if ((m_bFollow) && m_singleChart)
1824 m_singleChart->GetChartSkew() * PI / 180.,
1833 m_bFirstAuto =
false;
1837 if (bNewChart && !bNewView) Refresh(
false);
1842 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1845 return bNewChart | bNewView;
1848void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1849 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1851 SetQuiltRefChart(db_index);
1856 double best_scale_ppm = GetBestVPScale(pc);
1860 SetQuiltRefChart(-1);
1862 SetQuiltRefChart(-1);
1865void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1866 std::vector<int> piano_chart_index_array =
1867 GetQuiltExtendedStackdbIndexArray();
1868 int current_db_index = piano_chart_index_array[selected_index];
1870 SelectQuiltRefdbChart(current_db_index);
1873double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1877 if ((g_bPreserveScaleOnX) ||
1878 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
1884 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
1885 double equivalent_vp_scale =
1887 double new_scale_ppm =
1888 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1895 double max_underzoom_multiplier = 2.0;
1896 if (GetVP().b_quilt) {
1897 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
1898 pchart->GetChartType(),
1899 pchart->GetChartFamily());
1900 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
1903 proposed_scale_onscreen = wxMin(
1904 proposed_scale_onscreen,
1906 max_underzoom_multiplier);
1909 proposed_scale_onscreen =
1910 wxMax(proposed_scale_onscreen,
1918void ChartCanvas::SetupCanvasQuiltMode(
void) {
1923 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
1927 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1928 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1929 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1930 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1932 m_Piano->SetRoundedRectangles(
true);
1935 int target_new_dbindex = -1;
1936 if (m_pCurrentStack) {
1937 target_new_dbindex =
1938 GetQuiltReferenceChartIndex();
1940 if (-1 != target_new_dbindex) {
1941 if (!IsChartQuiltableRef(target_new_dbindex)) {
1942 int proj =
ChartData->GetDBChartProj(target_new_dbindex);
1943 int type =
ChartData->GetDBChartType(target_new_dbindex);
1946 int stack_index = m_pCurrentStack->CurrentStackEntry;
1948 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
1949 (stack_index >= 0)) {
1950 int proj_tent =
ChartData->GetDBChartProj(
1951 m_pCurrentStack->GetDBIndex(stack_index));
1952 int type_tent =
ChartData->GetDBChartType(
1953 m_pCurrentStack->GetDBIndex(stack_index));
1955 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
1956 if ((proj == proj_tent) && (type_tent == type)) {
1957 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
1967 if (IsChartQuiltableRef(target_new_dbindex))
1968 SelectQuiltRefdbChart(target_new_dbindex,
1971 SelectQuiltRefdbChart(-1,
false);
1973 m_singleChart = NULL;
1976 AdjustQuiltRefChart();
1984 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
1988 std::vector<int> empty_array;
1989 m_Piano->SetActiveKeyArray(empty_array);
1990 m_Piano->SetNoshowIndexArray(empty_array);
1991 m_Piano->SetEclipsedIndexArray(empty_array);
1994 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(
"viz")));
1995 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(
"redX")));
1996 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(
"tmercprj")));
1997 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(
"skewprj")));
1999 m_Piano->SetRoundedRectangles(
false);
2005 if (!GetQuiltMode()) {
2010 if (m_bFollow ==
true) {
2018 if (!m_singleChart) {
2021 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2029 int cur_max_scale = (int)1e8;
2031 ChartBase *pChart = GetFirstQuiltChart();
2035 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2037 if (pChart->GetNativeScale() < cur_max_scale) {
2038 Candidate_Chart = pChart;
2039 cur_max_scale = pChart->GetNativeScale();
2042 pChart = GetNextQuiltChart();
2045 m_singleChart = Candidate_Chart;
2049 if (NULL == m_singleChart) {
2050 m_singleChart =
ChartData->OpenStackChartConditional(
2051 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2052 CHART_FAMILY_DONTCARE);
2058 InvalidateAllQuiltPatchs();
2060 if (m_singleChart) {
2061 int dbi =
ChartData->FinddbIndex(m_singleChart->GetFullPath());
2062 std::vector<int> one_array;
2063 one_array.push_back(dbi);
2064 m_Piano->SetActiveKeyArray(one_array);
2067 if (m_singleChart) {
2068 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2072 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2076bool ChartCanvas::IsTempMenuBarEnabled() {
2079 wxGetOsVersion(&major);
2087double ChartCanvas::GetCanvasRangeMeters() {
2089 GetSize(&width, &height);
2090 int minDimension = wxMin(width, height);
2093 range *= cos(GetVP().clat * PI / 180.);
2097void ChartCanvas::SetCanvasRangeMeters(
double range) {
2099 GetSize(&width, &height);
2100 int minDimension = wxMin(width, height);
2102 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2106bool ChartCanvas::SetUserOwnship() {
2110 if (pWayPointMan && pWayPointMan->DoesIconExist(
"ownship")) {
2111 double factor_dusk = 0.5;
2112 double factor_night = 0.25;
2114 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(
"ownship");
2115 m_pos_image_user_day =
new wxImage;
2116 *m_pos_image_user_day = pbmp->ConvertToImage();
2117 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2119 int gimg_width = m_pos_image_user_day->GetWidth();
2120 int gimg_height = m_pos_image_user_day->GetHeight();
2123 m_pos_image_user_dusk =
new wxImage;
2124 m_pos_image_user_night =
new wxImage;
2126 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2127 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2129 for (
int iy = 0; iy < gimg_height; iy++) {
2130 for (
int ix = 0; ix < gimg_width; ix++) {
2131 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2132 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2133 m_pos_image_user_day->GetGreen(ix, iy),
2134 m_pos_image_user_day->GetBlue(ix, iy));
2135 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2136 hsv.value = hsv.value * factor_dusk;
2137 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2138 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2141 hsv = wxImage::RGBtoHSV(rgb);
2142 hsv.value = hsv.value * factor_night;
2143 nrgb = wxImage::HSVtoRGB(hsv);
2144 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2151 m_pos_image_user_grey_day =
new wxImage;
2152 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2154 m_pos_image_user_grey_dusk =
new wxImage;
2155 m_pos_image_user_grey_night =
new wxImage;
2157 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2158 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2160 for (
int iy = 0; iy < gimg_height; iy++) {
2161 for (
int ix = 0; ix < gimg_width; ix++) {
2162 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2163 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2164 m_pos_image_user_grey_day->GetGreen(ix, iy),
2165 m_pos_image_user_grey_day->GetBlue(ix, iy));
2166 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2167 hsv.value = hsv.value * factor_dusk;
2168 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2169 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2172 hsv = wxImage::RGBtoHSV(rgb);
2173 hsv.value = hsv.value * factor_night;
2174 nrgb = wxImage::HSVtoRGB(hsv);
2175 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2182 m_pos_image_user_yellow_day =
new wxImage;
2183 m_pos_image_user_yellow_dusk =
new wxImage;
2184 m_pos_image_user_yellow_night =
new wxImage;
2186 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2187 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2188 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2190 for (
int iy = 0; iy < gimg_height; iy++) {
2191 for (
int ix = 0; ix < gimg_width; ix++) {
2192 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2193 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2194 m_pos_image_user_grey_day->GetGreen(ix, iy),
2195 m_pos_image_user_grey_day->GetBlue(ix, iy));
2199 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2200 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2201 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2203 hsv = wxImage::RGBtoHSV(rgb);
2204 hsv.value = hsv.value * factor_dusk;
2205 nrgb = wxImage::HSVtoRGB(hsv);
2206 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2208 hsv = wxImage::RGBtoHSV(rgb);
2209 hsv.value = hsv.value * factor_night;
2210 nrgb = wxImage::HSVtoRGB(hsv);
2211 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2223 m_display_size_mm = size;
2230 double horizontal = sd.x;
2234 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2235 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2238 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2239 ps52plib->SetPPMM(m_pix_per_mm);
2244 "Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): "
2246 m_display_size_mm, sd.x, sd.y);
2250 ssx = g_monitor_info[g_current_monitor].width;
2251 ssy = g_monitor_info[g_current_monitor].height;
2252 msg.Printf(
"monitor size: %d %d", ssx, ssy);
2255 m_focus_indicator_pix = wxRound(1 *
GetPixPerMM());
2258void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2260 wxString msg(event.m_string.c_str(), wxConvUTF8);
2262 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2263 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2266 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2268 compress_msg_array.RemoveAt(event.thread);
2269 compress_msg_array.Insert( msg, event.thread);
2272 compress_msg_array.Add(msg);
2275 wxString combined_msg;
2276 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2277 combined_msg += compress_msg_array[i];
2278 combined_msg +=
"\n";
2282 pprog->Update(pprog_count, combined_msg, &skip );
2283 pprog->SetSize(pprog_size);
2288void ChartCanvas::InvalidateGL() {
2289 if (!m_glcc)
return;
2291 if (g_bopengl) m_glcc->Invalidate();
2293 if (m_Compass) m_Compass->UpdateStatus(
true);
2296int ChartCanvas::GetCanvasChartNativeScale() {
2298 if (!VPoint.b_quilt) {
2299 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2301 ret = (int)m_pQuilt->GetRefNativeScale();
2306ChartBase *ChartCanvas::GetChartAtCursor() {
2308 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2309 target_chart = m_singleChart;
2310 else if (VPoint.b_quilt)
2311 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2313 target_chart = NULL;
2314 return target_chart;
2317ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2321 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2323 target_chart = NULL;
2324 return target_chart;
2327int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2328 int new_dbIndex = -1;
2329 if (!VPoint.b_quilt) {
2330 if (m_pCurrentStack) {
2331 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2332 int sc =
ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2334 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2344 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2346 for (
unsigned int is = 0; is < im; is++) {
2348 m_pQuilt->GetExtendedStackIndexArray()[is]);
2351 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2361void ChartCanvas::EnablePaint(
bool b_enable) {
2362 m_b_paint_enable = b_enable;
2364 if (m_glcc) m_glcc->EnablePaint(b_enable);
2368bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2370void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2372std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2373 return m_pQuilt->GetQuiltIndexArray();
2377void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2378 VPoint.b_quilt = b_quilt;
2379 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2382bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2384int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2385 return m_pQuilt->GetRefChartdbIndex();
2388void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2389 m_pQuilt->InvalidateAllQuiltPatchs();
2392ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2393 return m_pQuilt->GetLargestScaleChart();
2396ChartBase *ChartCanvas::GetFirstQuiltChart() {
2397 return m_pQuilt->GetFirstChart();
2400ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2402int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2404void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2405 m_pQuilt->SetHiliteIndex(dbIndex);
2408void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2409 m_pQuilt->SetHiliteIndexArray(hilite_array);
2412void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2413 m_pQuilt->ClearHiliteIndexArray();
2416std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2418 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2421int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2422 return m_pQuilt->GetRefChartdbIndex();
2425std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2426 return m_pQuilt->GetExtendedStackIndexArray();
2429std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2430 return m_pQuilt->GetFullscreenIndexArray();
2433std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2434 return m_pQuilt->GetEclipsedStackIndexArray();
2437void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2439double ChartCanvas::GetQuiltMaxErrorFactor() {
2440 return m_pQuilt->GetMaxErrorFactor();
2443bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2444 return m_pQuilt->IsChartQuiltableRef(db_index);
2448 double chartMaxScale =
2450 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.
chart_scale);
2453void ChartCanvas::StartMeasureRoute() {
2454 if (!m_routeState) {
2455 if (m_bMeasure_Active) {
2457 m_pMeasureRoute = NULL;
2460 m_bMeasure_Active =
true;
2461 m_nMeasureState = 1;
2462 m_bDrawingRoute =
false;
2464 SetCursor(*pCursorPencil);
2469void ChartCanvas::CancelMeasureRoute() {
2470 m_bMeasure_Active =
false;
2471 m_nMeasureState = 0;
2472 m_bDrawingRoute =
false;
2475 m_pMeasureRoute = NULL;
2477 SetCursor(*pCursorArrow);
2480ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2482void ChartCanvas::SetVP(
ViewPort &vp) {
2493void ChartCanvas::TriggerDeferredFocus() {
2496 m_deferredFocusTimer.Start(20,
true);
2498#if defined(__WXGTK__) || defined(__WXOSX__)
2509void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2514void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2515 if (SendKeyEventToPlugins(event))
2519 int key_char =
event.GetKeyCode();
2522 HotkeysDlg(wxWindow::FindWindowByName(
"MainWindow")).ShowModal();
2528 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2533 if (g_benable_rotate) {
2554void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2555 if (SendKeyEventToPlugins(event))
2559 bool b_handled =
false;
2561 m_modkeys =
event.GetModifiers();
2563 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2565#ifdef OCPN_ALT_MENUBAR
2571 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2573 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2574 if (!g_bTempShowMenuBar) {
2575 g_bTempShowMenuBar =
true;
2576 parent_frame->ApplyGlobalSettings(
false);
2578 m_bMayToggleMenuBar =
false;
2584 if (event.GetKeyCode() != WXK_ALT) {
2585 m_bMayToggleMenuBar =
false;
2592 switch (event.GetKeyCode()) {
2599 event.GetPosition(&x, &y);
2600 m_FinishRouteOnKillFocus =
false;
2601 CallPopupMenu(x, y);
2602 m_FinishRouteOnKillFocus =
true;
2606 m_modkeys |= wxMOD_ALT;
2610 m_modkeys |= wxMOD_CONTROL;
2615 case WXK_RAW_CONTROL:
2616 m_modkeys |= wxMOD_RAW_CONTROL;
2621 if (m_modkeys == wxMOD_CONTROL)
2622 parent_frame->DoStackDown(
this);
2624 StartTimedMovement();
2634 StartTimedMovement();
2642 if (m_modkeys == wxMOD_CONTROL)
2643 parent_frame->DoStackUp(
this);
2645 StartTimedMovement();
2655 StartTimedMovement();
2667 SetShowENCText(!GetShowENCText());
2673 if (!m_bMeasure_Active) {
2674 if (event.ShiftDown())
2675 m_bMeasure_DistCircle =
true;
2677 m_bMeasure_DistCircle =
false;
2679 StartMeasureRoute();
2681 CancelMeasureRoute();
2683 SetCursor(*pCursorArrow);
2693 parent_frame->ToggleColorScheme();
2695 TriggerDeferredFocus();
2699 int mod = m_modkeys & wxMOD_SHIFT;
2700 if (mod != m_brightmod) {
2702 m_bbrightdir = !m_bbrightdir;
2705 if (!m_bbrightdir) {
2706 g_nbrightness -= 10;
2707 if (g_nbrightness <= MIN_BRIGHT) {
2708 g_nbrightness = MIN_BRIGHT;
2709 m_bbrightdir =
true;
2712 g_nbrightness += 10;
2713 if (g_nbrightness >= MAX_BRIGHT) {
2714 g_nbrightness = MAX_BRIGHT;
2715 m_bbrightdir =
false;
2719 SetScreenBrightness(g_nbrightness);
2720 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2729 parent_frame->DoStackDown(
this);
2733 parent_frame->DoStackUp(
this);
2738 ToggleCanvasQuiltMode();
2744 parent_frame->ToggleFullScreen();
2749 if (m_modkeys == wxMOD_ALT) {
2752 ToggleChartOutlines();
2758 parent_frame->ActivateMOB();
2762 case WXK_NUMPAD_ADD:
2767 case WXK_NUMPAD_SUBTRACT:
2768 case WXK_PAGEDOWN: {
2769 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2774 if (m_bMeasure_Active) {
2775 if (m_nMeasureState > 2) {
2776 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2778 m_pMeasureRoute->GetnPoints();
2780 gFrame->RefreshAllCanvas();
2782 CancelMeasureRoute();
2783 StartMeasureRoute();
2791 if (event.GetKeyCode() < 128)
2793 int key_char =
event.GetKeyCode();
2797 if (!g_b_assume_azerty) {
2799 if (g_benable_rotate) {
2831 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2838 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL &&
2839 m_modkeys & wxMOD_RAW_CONTROL) {
2840 parent_frame->ToggleFullScreen();
2845 if (event.ControlDown()) key_char -= 64;
2847 if (key_char >=
'0' && key_char <=
'9')
2848 SetGroupIndex(key_char -
'0');
2853 SetShowENCAnchor(!GetShowENCAnchor());
2859 parent_frame->ToggleColorScheme();
2864 event.GetPosition(&x, &y);
2865 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2866 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2868 if (!pPopupDetailSlider) {
2869 if (VPoint.b_quilt) {
2871 if (m_pQuilt->GetChartAtPix(
2876 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2878 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2883 if (m_singleChart) {
2884 ChartType = m_singleChart->GetChartType();
2885 ChartFam = m_singleChart->GetChartFamily();
2889 if ((ChartType != CHART_TYPE_UNKNOWN) ||
2890 (ChartFam != CHART_FAMILY_UNKNOWN)) {
2892 this, -1, ChartType, ChartFam,
2893 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
2894 wxDefaultSize, wxSIMPLE_BORDER,
"");
2895 if (pPopupDetailSlider) pPopupDetailSlider->Show();
2899 if (pPopupDetailSlider) pPopupDetailSlider->Close();
2900 pPopupDetailSlider = NULL;
2907 m_nmea_log->Raise();
2911 SetShowENCLights(!GetShowENCLights());
2917 if (event.ShiftDown())
2918 m_bMeasure_DistCircle =
true;
2920 m_bMeasure_DistCircle =
false;
2922 StartMeasureRoute();
2926 if (g_bInlandEcdis && ps52plib) {
2927 SetENCDisplayCategory((_DisCat)STANDARD);
2932 ToggleChartOutlines();
2936 ToggleCanvasQuiltMode();
2940 parent_frame->ToggleTestPause();
2943 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
2944 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible == 0)
2945 g_iNavAidRadarRingsNumberVisible = 1;
2946 else if (!g_bNavAidRadarRingsShown &&
2947 g_iNavAidRadarRingsNumberVisible == 1)
2948 g_iNavAidRadarRingsNumberVisible = 0;
2951 SetShowENCDepth(!m_encShowDepth);
2956 SetShowENCText(!GetShowENCText());
2961 SetShowENCDataQual(!GetShowENCDataQual());
2966 m_bShowNavobjects = !m_bShowNavobjects;
2981 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
2986 if (event.ControlDown()) gFrame->DropMarker(
false);
2992 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
2993 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
2994 if ((indexActive + 1) <= r->GetnPoints()) {
3005 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3011 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3017 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3024 parent_frame->DoSettings();
3028 parent_frame->Close();
3036 if (NULL == pGoToPositionDialog)
3039 pGoToPositionDialog->SetCanvas(
this);
3040 pGoToPositionDialog->Show();
3044 if (undo->AnythingToRedo()) {
3045 undo->RedoNextAction();
3052 if (event.ShiftDown()) {
3053 if (undo->AnythingToRedo()) {
3054 undo->RedoNextAction();
3059 if (undo->AnythingToUndo()) {
3060 undo->UndoLastAction();
3069 if (m_bMeasure_Active) {
3070 CancelMeasureRoute();
3072 SetCursor(*pCursorArrow);
3075 gFrame->RefreshAllCanvas();
3089 switch (gamma_state) {
3109 SetScreenBrightness(g_nbrightness);
3114 if (event.ControlDown()) {
3115 m_bShowCompassWin = !m_bShowCompassWin;
3116 SetShowGPSCompassWindow(m_bShowCompassWin);
3133void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3134 if (SendKeyEventToPlugins(event))
3138 switch (event.GetKeyCode()) {
3140 parent_frame->SwitchKBFocus(
this);
3146 if (!m_pany) m_panspeed = 0;
3152 if (!m_panx) m_panspeed = 0;
3155 case WXK_NUMPAD_ADD:
3156 case WXK_NUMPAD_SUBTRACT:
3165 m_modkeys &= ~wxMOD_ALT;
3166#ifdef OCPN_ALT_MENUBAR
3171 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3172 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3173 parent_frame->ApplyGlobalSettings(
false);
3175 m_bMayToggleMenuBar =
true;
3181 m_modkeys &= ~wxMOD_CONTROL;
3185 if (event.GetKeyCode() < 128)
3187 int key_char =
event.GetKeyCode();
3191 if (!g_b_assume_azerty) {
3206 m_rotation_speed = 0;
3224void ChartCanvas::ToggleChartOutlines(
void) {
3225 m_bShowOutlines = !m_bShowOutlines;
3231 if (g_bopengl) InvalidateGL();
3235void ChartCanvas::ToggleLookahead() {
3236 m_bLookAhead = !m_bLookAhead;
3241void ChartCanvas::SetUpMode(
int mode) {
3244 if (mode != NORTH_UP_MODE) {
3247 if (!std::isnan(gCog)) stuff = gCog;
3250 for (
int i = 0; i <
g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3253 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3255 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3256 SetVPRotation(GetVPSkew());
3261 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3262 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3264 UpdateGPSCompassStatusBox(
true);
3265 gFrame->DoChartUpdate();
3268bool ChartCanvas::DoCanvasCOGSet(
void) {
3269 if (GetUpMode() == NORTH_UP_MODE)
return false;
3271 if (g_btenhertz) cog_use = gCog;
3273 double rotation = 0;
3274 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3275 rotation = -gHdt * PI / 180.;
3276 }
else if ((GetUpMode() == COURSE_UP_MODE) && !std::isnan(cog_use))
3277 rotation = -cog_use * PI / 180.;
3279 SetVPRotation(rotation);
3283double easeOutCubic(
double t) {
3285 return 1.0 - pow(1.0 - t, 3.0);
3288void ChartCanvas::StartChartDragInertia() {
3289 m_bChartDragging =
false;
3292 m_chart_drag_inertia_time = 750;
3293 m_chart_drag_inertia_start_time = wxGetLocalTimeMillis();
3298 n_vel = wxMin(n_vel, m_drag_vec_t.size());
3302 size_t length = m_drag_vec_t.size();
3303 for (
size_t i = 0; i < n_vel; i++) {
3304 xacc += m_drag_vec_x.at(length - 1 - i);
3305 yacc += m_drag_vec_y.at(length - 1 - i);
3306 tacc += m_drag_vec_t.at(length - 1 - i);
3308 m_chart_drag_velocity_x = xacc / tacc;
3309 m_chart_drag_velocity_y = yacc / tacc;
3311 m_chart_drag_inertia_active =
true;
3313 m_chart_drag_inertia_timer.Start(1, wxTIMER_ONE_SHOT);
3316void ChartCanvas::OnChartDragInertiaTimer(wxTimerEvent &event) {
3317 if (!m_chart_drag_inertia_active)
return;
3320 wxLongLong now = wxGetLocalTimeMillis();
3321 double elapsed = (now - m_chart_drag_inertia_start_time).ToDouble();
3322 double t = elapsed / m_chart_drag_inertia_time.ToDouble();
3323 if (t > 1.0) t = 1.0;
3324 double e = 1.0 - easeOutCubic(t);
3327 m_chart_drag_velocity_x * ((elapsed - m_last_elapsed) / 1000.) * e;
3329 m_chart_drag_velocity_y * ((elapsed - m_last_elapsed) / 1000.) * e;
3331 m_last_elapsed = elapsed;
3335 double destination_x = (GetCanvasWidth() / 2) + wxRound(dx);
3336 double destination_y = (GetCanvasHeight() / 2) + wxRound(dy);
3337 double inertia_lat, inertia_lon;
3341 if (!IsOwnshipOnScreen()) {
3343 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
3344 UpdateFollowButtonState();
3355 if ((t >= 1) || (fabs(dx) < 1) || (fabs(dy) < 1)) {
3356 m_chart_drag_inertia_timer.Stop();
3359 m_target_lat = GetVP().
clat;
3360 m_target_lon = GetVP().
clon;
3361 m_pan_drag.x = m_pan_drag.y = 0;
3362 m_panx = m_pany = 0;
3363 m_chart_drag_inertia_active =
false;
3367 int target_redraw_interval = 40;
3368 m_chart_drag_inertia_timer.Start(target_redraw_interval, wxTIMER_ONE_SHOT);
3372void ChartCanvas::StopMovement() {
3373 m_panx = m_pany = 0;
3376 m_rotation_speed = 0;
3379#if !defined(__WXGTK__) && !defined(__WXQT__)
3390bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3392 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3394 if (!pMovementTimer->IsRunning()) {
3396 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3399 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3404 m_last_movement_time = wxDateTime::UNow();
3408void ChartCanvas::StartTimedMovementVP(
double target_lat,
double target_lon,
3411 m_target_lat = target_lat;
3412 m_target_lon = target_lon;
3415 m_start_lat = GetVP().
clat;
3416 m_start_lon = GetVP().
clon;
3418 m_VPMovementTimer.Start(1,
true);
3419 m_timed_move_vp_active =
true;
3421 m_timedVP_step = nstep;
3424void ChartCanvas::DoTimedMovementVP() {
3425 if (!m_timed_move_vp_active)
return;
3426 if (m_stvpc++ > m_timedVP_step * 2) {
3433 pow(m_run_lat - m_target_lat, 2) + pow(m_run_lon - m_target_lon, 2);
3448 double new_lat = GetVP().
clat + (m_target_lat - m_start_lat) / m_timedVP_step;
3449 double new_lon = GetVP().
clon + (m_target_lon - m_start_lon) / m_timedVP_step;
3451 m_run_lat = new_lat;
3452 m_run_lon = new_lon;
3458void ChartCanvas::StopMovementVP() { m_timed_move_vp_active =
false; }
3460void ChartCanvas::MovementVPTimerEvent(wxTimerEvent &) { DoTimedMovementVP(); }
3462void ChartCanvas::StartTimedMovementTarget() {}
3464void ChartCanvas::DoTimedMovementTarget() {}
3466void ChartCanvas::StopMovementTarget() {}
3468void ChartCanvas::DoTimedMovement() {
3469 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3473 wxDateTime now = wxDateTime::UNow();
3475 if (m_last_movement_time.IsValid())
3476 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3478 m_last_movement_time = now;
3488 if (dt == 0) dt = 1;
3491 if (m_mustmove < 0) m_mustmove = 0;
3493 if (m_pan_drag.x || m_pan_drag.y) {
3495 m_pan_drag.x = m_pan_drag.y = 0;
3498 if (m_panx || m_pany) {
3499 const double slowpan = .1, maxpan = 2;
3500 if (m_modkeys == wxMOD_ALT)
3501 m_panspeed = slowpan;
3503 m_panspeed += (double)dt / 500;
3504 m_panspeed = wxMin(maxpan, m_panspeed);
3506 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3509 if (m_zoom_factor != 1) {
3510 double alpha = 400, beta = 1.5;
3511 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3513 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3515 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3520 if (zoom_factor > 1) {
3521 if (VPoint.
chart_scale / zoom_factor <= m_zoom_target)
3525 else if (zoom_factor < 1) {
3526 if (VPoint.
chart_scale / zoom_factor >= m_zoom_target)
3531 if (fabs(zoom_factor - 1) > 1e-4) {
3532 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3537 if (m_wheelzoom_stop_oneshot > 0) {
3538 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3539 m_wheelzoom_stop_oneshot = 0;
3544 if (zoom_factor > 1) {
3546 m_wheelzoom_stop_oneshot = 0;
3549 }
else if (zoom_factor < 1) {
3551 m_wheelzoom_stop_oneshot = 0;
3558 if (m_rotation_speed) {
3559 double speed = m_rotation_speed;
3560 if (m_modkeys == wxMOD_ALT) speed /= 10;
3561 DoRotateCanvas(VPoint.
rotation + speed * PI / 180 * dt / 1000.0);
3565void ChartCanvas::SetColorScheme(ColorScheme cs) {
3570 case GLOBAL_COLOR_SCHEME_DAY:
3571 m_pos_image_red = &m_os_image_red_day;
3572 m_pos_image_grey = &m_os_image_grey_day;
3573 m_pos_image_yellow = &m_os_image_yellow_day;
3574 m_pos_image_user = m_pos_image_user_day;
3575 m_pos_image_user_grey = m_pos_image_user_grey_day;
3576 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3577 m_cTideBitmap = m_bmTideDay;
3578 m_cCurrentBitmap = m_bmCurrentDay;
3581 case GLOBAL_COLOR_SCHEME_DUSK:
3582 m_pos_image_red = &m_os_image_red_dusk;
3583 m_pos_image_grey = &m_os_image_grey_dusk;
3584 m_pos_image_yellow = &m_os_image_yellow_dusk;
3585 m_pos_image_user = m_pos_image_user_dusk;
3586 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3587 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3588 m_cTideBitmap = m_bmTideDusk;
3589 m_cCurrentBitmap = m_bmCurrentDusk;
3591 case GLOBAL_COLOR_SCHEME_NIGHT:
3592 m_pos_image_red = &m_os_image_red_night;
3593 m_pos_image_grey = &m_os_image_grey_night;
3594 m_pos_image_yellow = &m_os_image_yellow_night;
3595 m_pos_image_user = m_pos_image_user_night;
3596 m_pos_image_user_grey = m_pos_image_user_grey_night;
3597 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3598 m_cTideBitmap = m_bmTideNight;
3599 m_cCurrentBitmap = m_bmCurrentNight;
3602 m_pos_image_red = &m_os_image_red_day;
3603 m_pos_image_grey = &m_os_image_grey_day;
3604 m_pos_image_yellow = &m_os_image_yellow_day;
3605 m_pos_image_user = m_pos_image_user_day;
3606 m_pos_image_user_grey = m_pos_image_user_grey_day;
3607 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3608 m_cTideBitmap = m_bmTideDay;
3609 m_cCurrentBitmap = m_bmCurrentDay;
3613 CreateDepthUnitEmbossMaps(cs);
3614 CreateOZEmbossMapData(cs);
3617 m_fog_color = wxColor(
3621 case GLOBAL_COLOR_SCHEME_DUSK:
3624 case GLOBAL_COLOR_SCHEME_NIGHT:
3630 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3631 m_fog_color.Blue() * dim);
3635 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3636 SetBackgroundColour( wxColour(0,0,0) );
3638 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3641 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3643 SetBackgroundColour( wxNullColour );
3650 m_Piano->SetColorScheme(cs);
3652 m_Compass->SetColorScheme(cs);
3654 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3656 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3658 if (m_NotificationsList) m_NotificationsList->SetColorScheme();
3659 if (m_notification_button) {
3660 m_notification_button->SetColorScheme(cs);
3664 if (g_bopengl && m_glcc) {
3665 m_glcc->SetColorScheme(cs);
3666 g_glTextureManager->ClearAllRasterTextures();
3671 m_brepaint_piano =
true;
3678wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3679 wxImage img = Bitmap.ConvertToImage();
3680 int sx = img.GetWidth();
3681 int sy = img.GetHeight();
3683 wxImage new_img(img);
3685 for (
int i = 0; i < sx; i++) {
3686 for (
int j = 0; j < sy; j++) {
3687 if (!img.IsTransparent(i, j)) {
3688 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3689 (
unsigned char)(img.GetGreen(i, j) * factor),
3690 (
unsigned char)(img.GetBlue(i, j) * factor));
3695 wxBitmap ret = wxBitmap(new_img);
3700void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3703 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3705 if (!m_pBrightPopup) {
3708 GetTextExtent(
"MAX", &x, &y, NULL, NULL, pfont);
3712 m_pBrightPopup->SetSize(x, y);
3713 m_pBrightPopup->Move(120, 120);
3716 int bmpsx = m_pBrightPopup->GetSize().x;
3717 int bmpsy = m_pBrightPopup->GetSize().y;
3719 wxBitmap bmp(bmpsx, bmpsx);
3720 wxMemoryDC mdc(bmp);
3722 mdc.SetTextForeground(GetGlobalColor(
"GREEN4"));
3723 mdc.SetBackground(wxBrush(GetGlobalColor(
"UINFD")));
3724 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3725 mdc.SetBrush(wxBrush(GetGlobalColor(
"UINFD")));
3728 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3730 mdc.SetFont(*pfont);
3733 if (brightness == max)
3735 else if (brightness == min)
3738 val.Printf(
"%3d", brightness);
3740 mdc.DrawText(val, 0, 0);
3742 mdc.SelectObject(wxNullBitmap);
3744 m_pBrightPopup->SetBitmap(bmp);
3745 m_pBrightPopup->Show();
3746 m_pBrightPopup->Refresh();
3749void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3750 m_b_rot_hidef =
true;
3754void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3757 bool b_need_refresh =
false;
3759 wxSize win_size = GetSize() * m_displayScale;
3763 bool showAISRollover =
false;
3764 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3766 SelectItem *pFind = pSelectAIS->FindSelection(
3769 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3770 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3773 showAISRollover =
true;
3775 if (NULL == m_pAISRolloverWin) {
3777 m_pAISRolloverWin->IsActive(
false);
3778 b_need_refresh =
true;
3779 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3780 m_AISRollover_MMSI != FoundAIS_MMSI) {
3786 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3787 m_pAISRolloverWin->IsActive(
false);
3788 m_AISRollover_MMSI = 0;
3793 m_AISRollover_MMSI = FoundAIS_MMSI;
3795 if (!m_pAISRolloverWin->IsActive()) {
3796 wxString s = ptarget->GetRolloverString();
3797 m_pAISRolloverWin->SetString(s);
3799 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3800 AIS_ROLLOVER, win_size);
3801 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3802 m_pAISRolloverWin->IsActive(
true);
3803 b_need_refresh =
true;
3807 m_AISRollover_MMSI = 0;
3808 showAISRollover =
false;
3813 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3814 m_pAISRolloverWin->IsActive(
false);
3815 m_AISRollover_MMSI = 0;
3816 b_need_refresh =
true;
3821 bool showRouteRollover =
false;
3823 if (NULL == m_pRolloverRouteSeg) {
3828 SelectableItemList SelList = pSelect->FindSelectionList(
3830 wxSelectableItemListNode *node = SelList.GetFirst();
3836 if (pr && pr->IsVisible()) {
3837 m_pRolloverRouteSeg = pFindSel;
3838 showRouteRollover =
true;
3840 if (NULL == m_pRouteRolloverWin) {
3842 m_pRouteRolloverWin->IsActive(
false);
3845 if (!m_pRouteRolloverWin->IsActive()) {
3853 DistanceBearingMercator(
3854 segShow_point_b->m_lat, segShow_point_b->m_lon,
3855 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3857 if (!pr->m_bIsInLayer)
3858 s.Append(_(
"Route") +
": ");
3860 s.Append(_(
"Layer Route: "));
3862 if (pr->m_RouteNameString.IsEmpty())
3863 s.Append(_(
"(unnamed)"));
3865 s.Append(pr->m_RouteNameString);
3868 << _(
"Total Length: ") << FormatDistanceAdaptive(pr->m_route_length)
3870 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3871 << segShow_point_b->GetName() <<
"\n";
3874 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
3875 (
int)floor(brg + 0.5), 0x00B0);
3878 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3880 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3881 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3883 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
3884 (
int)floor(varBrg + 0.5), 0x00B0);
3887 s << FormatDistanceAdaptive(dist);
3892 double shiptoEndLeg = 0.;
3893 bool validActive =
false;
3894 if (pr->IsActive() &&
3895 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
3898 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
3899 wxRoutePointListNode *node =
3900 (pr->pRoutePointList)->GetFirst()->GetNext();
3902 float dist_to_endleg = 0;
3906 prp = node->GetData();
3912 if (prp->IsSame(segShow_point_a))
break;
3913 node = node->GetNext();
3915 s <<
" (+" << FormatDistanceAdaptive(dist_to_endleg) <<
")";
3921 << _(
"From Ship To") <<
" " << segShow_point_b->GetName() <<
"\n";
3924 ->GetCurrentRngToActivePoint();
3929 s << FormatDistanceAdaptive(shiptoEndLeg);
3933 if (!std::isnan(gCog) && !std::isnan(gSog))
3935 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
3938 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
3939 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
3941 << wxString(ttg_sec > SECONDS_PER_DAY
3942 ? ttg_span.Format(_(
"%Dd %H:%M"))
3943 : ttg_span.Format(_(
"%H:%M")));
3944 wxDateTime dtnow, eta;
3945 eta = dtnow.SetToCurrent().Add(ttg_span);
3946 s <<
" - " << eta.Format(
"%b").Mid(0, 4)
3947 << eta.Format(
" %d %H:%M");
3951 m_pRouteRolloverWin->SetString(s);
3953 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3954 LEG_ROLLOVER, win_size);
3955 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
3956 m_pRouteRolloverWin->IsActive(
true);
3957 b_need_refresh =
true;
3958 showRouteRollover =
true;
3962 node = node->GetNext();
3968 m_pRolloverRouteSeg))
3969 showRouteRollover =
false;
3970 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
3971 showRouteRollover =
false;
3973 showRouteRollover =
true;
3977 if (m_routeState) showRouteRollover =
false;
3980 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
3981 showRouteRollover =
false;
3983 if (m_pRouteRolloverWin &&
3984 !showRouteRollover) {
3985 m_pRouteRolloverWin->IsActive(
false);
3986 m_pRolloverRouteSeg = NULL;
3987 m_pRouteRolloverWin->Destroy();
3988 m_pRouteRolloverWin = NULL;
3989 b_need_refresh =
true;
3990 }
else if (m_pRouteRolloverWin && showRouteRollover) {
3991 m_pRouteRolloverWin->IsActive(
true);
3992 b_need_refresh =
true;
3997 bool showTrackRollover =
false;
3999 if (NULL == m_pRolloverTrackSeg) {
4004 SelectableItemList SelList = pSelect->FindSelectionList(
4006 wxSelectableItemListNode *node = SelList.GetFirst();
4012 if (pt && pt->IsVisible()) {
4013 m_pRolloverTrackSeg = pFindSel;
4014 showTrackRollover =
true;
4016 if (NULL == m_pTrackRolloverWin) {
4018 m_pTrackRolloverWin->IsActive(
false);
4021 if (!m_pTrackRolloverWin->IsActive()) {
4029 DistanceBearingMercator(
4030 segShow_point_b->m_lat, segShow_point_b->m_lon,
4031 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
4033 if (!pt->m_bIsInLayer)
4034 s.Append(_(
"Track") +
": ");
4036 s.Append(_(
"Layer Track: "));
4038 if (pt->GetName().IsEmpty())
4039 s.Append(_(
"(unnamed)"));
4041 s.Append(pt->GetName());
4042 double tlenght = pt->Length();
4043 s <<
"\n" << _(
"Total Track: ") << FormatDistanceAdaptive(tlenght);
4044 if (pt->GetLastPoint()->GetTimeString() &&
4045 pt->GetPoint(0)->GetTimeString()) {
4046 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
4047 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
4048 if (lastPointTime.IsValid() && zeroPointTime.IsValid()) {
4049 wxTimeSpan ttime = lastPointTime - zeroPointTime;
4050 double htime = ttime.GetSeconds().ToDouble() / 3600.;
4051 s << wxString::Format(
" %.1f ", (
float)(tlenght / htime))
4052 << getUsrSpeedUnit();
4053 s << wxString(htime > 24. ? ttime.Format(
" %Dd %H:%M")
4054 : ttime.Format(
" %H:%M"));
4058 if (g_bShowTrackPointTime &&
4059 strlen(segShow_point_b->GetTimeString())) {
4060 wxString stamp = segShow_point_b->GetTimeString();
4061 wxDateTime timestamp = segShow_point_b->GetCreateTime();
4062 if (timestamp.IsValid()) {
4066 stamp = ocpn::toUsrDateTimeFormat(timestamp.FromUTC(), opts);
4068 s <<
"\n" << _(
"Segment Created: ") << stamp;
4073 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
4078 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
4080 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
4081 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
4083 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4087 s << FormatDistanceAdaptive(dist);
4089 if (segShow_point_a->GetTimeString() &&
4090 segShow_point_b->GetTimeString()) {
4091 wxDateTime apoint = segShow_point_a->GetCreateTime();
4092 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4093 if (apoint.IsValid() && bpoint.IsValid()) {
4094 double segmentSpeed = toUsrSpeed(
4095 dist / ((bpoint - apoint).GetSeconds().ToDouble() / 3600.));
4096 s << wxString::Format(
" %.1f ", (
float)segmentSpeed)
4097 << getUsrSpeedUnit();
4101 m_pTrackRolloverWin->SetString(s);
4103 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4104 LEG_ROLLOVER, win_size);
4105 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4106 m_pTrackRolloverWin->IsActive(
true);
4107 b_need_refresh =
true;
4108 showTrackRollover =
true;
4112 node = node->GetNext();
4118 m_pRolloverTrackSeg))
4119 showTrackRollover =
false;
4120 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4121 showTrackRollover =
false;
4123 showTrackRollover =
true;
4127 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4128 showTrackRollover =
false;
4131 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4132 showTrackRollover =
false;
4138 if (m_pTrackRolloverWin &&
4139 !showTrackRollover) {
4140 m_pTrackRolloverWin->IsActive(
false);
4141 m_pRolloverTrackSeg = NULL;
4142 m_pTrackRolloverWin->Destroy();
4143 m_pTrackRolloverWin = NULL;
4144 b_need_refresh =
true;
4145 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4146 m_pTrackRolloverWin->IsActive(
true);
4147 b_need_refresh =
true;
4150 if (b_need_refresh) Refresh();
4153void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4154 if ((GetShowENCLights() || m_bsectors_shown) &&
4155 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4156 extendedSectorLegs)) {
4157 if (!m_bsectors_shown) {
4159 m_bsectors_shown =
true;
4162 if (m_bsectors_shown) {
4164 m_bsectors_shown =
false;
4172#if defined(__WXGTK__) || defined(__WXQT__)
4177 double cursor_lat, cursor_lon;
4180 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4181 while (cursor_lon < -180.) cursor_lon += 360.;
4183 while (cursor_lon > 180.) cursor_lon -= 360.;
4185 SetCursorStatus(cursor_lat, cursor_lon);
4191void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4192 if (!parent_frame->m_pStatusBar)
return;
4196 s1 += toSDMM(1, cursor_lat);
4198 s1 += toSDMM(2, cursor_lon);
4200 if (STAT_FIELD_CURSOR_LL >= 0)
4201 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4203 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4208 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4209 if (g_bShowMag) sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4210 if (g_bShowTrue) st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4212 wxString s = st + sm;
4213 s << FormatDistanceAdaptive(dist);
4225 if (g_bShowLiveETA) {
4228 float boatSpeedDefault = g_defaultBoatSpeed;
4233 if (!std::isnan(gSog)) {
4235 if (boatSpeed < 0.5) {
4238 realTimeETA = dist / boatSpeed * 60;
4247 s << minutesToHoursDays(realTimeETA);
4252 s << wxString::Format(
"%d", (
int)toUsrSpeed(boatSpeedDefault, -1));
4253 s << wxString::Format(
"%s", getUsrSpeedUnit(-1));
4255 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4260 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4268wxString minutesToHoursDays(
float timeInMinutes) {
4271 if (timeInMinutes == 0) {
4276 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4277 s << wxString::Format(
"%d", (
int)timeInMinutes);
4282 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4285 hours = (int)timeInMinutes / 60;
4286 min = (int)timeInMinutes % 60;
4289 s << wxString::Format(
"%d", hours);
4292 s << wxString::Format(
"%d", hours);
4294 s << wxString::Format(
"%d", min);
4301 else if (timeInMinutes > 24 * 60) {
4304 days = (int)(timeInMinutes / 60) / 24;
4305 hours = (int)(timeInMinutes / 60) % 24;
4308 s << wxString::Format(
"%d", days);
4311 s << wxString::Format(
"%d", days);
4313 s << wxString::Format(
"%d", hours);
4325void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4333 wxPoint2DDouble *r) {
4338 double rlon, wxPoint2DDouble *r) {
4349 if (!g_bopengl && m_singleChart &&
4350 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4351 (((fabs(vp.
rotation) < .0001) && (fabs(vp.
skew) < .0001)) ||
4352 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4353 (m_singleChart->GetChartProjectionType() !=
4354 PROJECTION_TRANSVERSE_MERCATOR) &&
4355 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4356 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4357 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4371 Cur_BSB_Ch->SetVPRasterParms(vp);
4372 double rpixxd, rpixyd;
4373 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4399 if (std::isnan(p.m_x)) {
4400 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4404 if ((abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6))
4405 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4407 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4426 if (!g_bopengl && m_singleChart &&
4427 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4428 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4429 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4430 (m_singleChart->GetChartProjectionType() !=
4431 PROJECTION_TRANSVERSE_MERCATOR) &&
4432 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4433 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4434 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4445 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4448 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4453 else if (slon > 180.)
4464 GetVP().
GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4470 DoZoomCanvas(factor,
false);
4471 extendedSectorLegs.clear();
4476 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4479 if (StartTimedMovement(stoptimer)) {
4481 m_zoom_factor = factor;
4486 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4488 DoZoomCanvas(factor, can_zoom_to_cursor);
4491 extendedSectorLegs.clear();
4494void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4497 if (!m_pCurrentStack)
return;
4503 if (m_bzooming)
return;
4512 double proposed_scale_onscreen =
4515 bool b_do_zoom =
false;
4524 if (!VPoint.b_quilt) {
4527 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4528 if (new_db_index >= 0)
4529 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4533 int current_ref_stack_index = -1;
4534 if (m_pCurrentStack->nEntry) {
4536 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4537 m_pQuilt->SetReferenceChart(trial_index);
4538 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4539 if (new_db_index >= 0)
4540 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4544 if (m_pCurrentStack)
4545 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4555 double min_allowed_scale =
4558 if (proposed_scale_onscreen < min_allowed_scale) {
4563 proposed_scale_onscreen = min_allowed_scale;
4567 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4570 }
else if (factor < 1) {
4575 bool b_smallest =
false;
4577 if (!VPoint.b_quilt) {
4582 LLBBox viewbox = VPoint.GetBBox();
4584 int current_index =
ChartData->FinddbIndex(pc->GetFullPath());
4585 double max_allowed_scale;
4599 if (proposed_scale_onscreen > max_allowed_scale) {
4601 proposed_scale_onscreen = max_allowed_scale;
4606 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4607 if (new_db_index >= 0)
4608 pc =
ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4610 if (m_pCurrentStack)
4611 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4614 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4616 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4617 proposed_scale_onscreen =
4618 wxMin(proposed_scale_onscreen,
4624 m_absolute_min_scale_ppm)
4625 proposed_scale_onscreen =
4634 bool b_allow_ztc =
true;
4635 if (m_bFollow && m_bLookAhead) b_allow_ztc =
false;
4636 if (can_zoom_to_cursor && g_bEnableZoomToCursor && b_allow_ztc) {
4638 double brg, distance;
4639 ll_gc_ll_reverse(gLat, gLon, GetVP().clat, GetVP().clon, &brg,
4642 meters_to_shift = distance * 1852;
4650 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4653 if (m_bFollow) DoCanvasUpdate();
4660void ChartCanvas::SetAbsoluteMinScale(
double min_scale) {
4662 m_absolute_min_scale_ppm = wxMax(m_absolute_min_scale_ppm, x_scale_ppm);
4666void ChartCanvas::RotateCanvas(
double dir) {
4670 if (StartTimedMovement()) {
4672 m_rotation_speed = dir * 60;
4675 double speed = dir * 10;
4676 if (m_modkeys == wxMOD_ALT) speed /= 20;
4677 DoRotateCanvas(VPoint.
rotation + PI / 180 * speed);
4681void ChartCanvas::DoRotateCanvas(
double rotation) {
4682 while (rotation < 0) rotation += 2 * PI;
4683 while (rotation > 2 * PI) rotation -= 2 * PI;
4685 if (rotation == VPoint.
rotation || std::isnan(rotation))
return;
4687 SetVPRotation(rotation);
4688 parent_frame->UpdateRotationState(VPoint.
rotation);
4691void ChartCanvas::DoTiltCanvas(
double tilt) {
4692 while (tilt < 0) tilt = 0;
4693 while (tilt > .95) tilt = .95;
4695 if (tilt == VPoint.
tilt || std::isnan(tilt))
return;
4701void ChartCanvas::TogglebFollow(
void) {
4708void ChartCanvas::ClearbFollow(
void) {
4711 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4713 UpdateFollowButtonState();
4717 parent_frame->SetChartUpdatePeriod();
4720void ChartCanvas::SetbFollow(
void) {
4723 if ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
4724 (fabs(m_OSoffsety) > VPoint.
pix_height / 2)) {
4732 p.m_x += m_OSoffsetx;
4733 p.m_y -= m_OSoffsety;
4742 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4743 UpdateFollowButtonState();
4745 if (!g_bSmoothRecenter) {
4749 parent_frame->SetChartUpdatePeriod();
4752void ChartCanvas::UpdateFollowButtonState(
void) {
4755 m_muiBar->SetFollowButtonState(0);
4758 m_muiBar->SetFollowButtonState(2);
4760 m_muiBar->SetFollowButtonState(1);
4766 androidSetFollowTool(0);
4769 androidSetFollowTool(2);
4771 androidSetFollowTool(1);
4778 for (
auto pic : *
PluginLoader::GetInstance()->GetPlugInArray()) {
4779 if (pic->m_enabled && pic->m_init_state) {
4780 switch (pic->m_api_version) {
4783 if (ppi) ppi->UpdateFollowState(m_canvasIndex, m_bFollow);
4794void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4795 if (g_bSmoothRecenter && !m_routeState) {
4796 if (StartSmoothJump(lat, lon, scale_ppm))
4800 double gcDist, gcBearingEnd;
4801 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL,
4803 gcBearingEnd += 180;
4804 double lat_offset = cos(gcBearingEnd * PI / 180.) * 0.5 *
4807 sin(gcBearingEnd * PI / 180.) * 0.5 * GetCanvasWidth() /
GetVPScale();
4808 double new_lat = lat + (lat_offset / (1852 * 60));
4809 double new_lon = lon + (lon_offset / (1852 * 60));
4812 StartSmoothJump(lat, lon, scale_ppm);
4817 if (lon > 180.0) lon -= 360.0;
4823 if (!GetQuiltMode()) {
4825 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4826 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4830 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
4831 AdjustQuiltRefChart();
4838 UpdateFollowButtonState();
4846bool ChartCanvas::StartSmoothJump(
double lat,
double lon,
double scale_ppm) {
4851 Geodesic::GreatCircleDistBear(m_vLon, m_vLat, lon, lat, &gcDist, NULL, NULL);
4852 double distance_pixels = gcDist *
GetVPScale();
4853 if (distance_pixels > 0.5 * GetCanvasWidth()) {
4859 m_startLat = m_vLat;
4860 m_startLon = m_vLon;
4865 m_endLon = (lon > 180.0) ? (lon - 360.0) : lon;
4866 m_endScale = scale_ppm;
4869 m_animationDuration = 600;
4870 m_animationStart = wxGetLocalTimeMillis();
4877 m_easeTimer.Start(16, wxTIMER_CONTINUOUS);
4878 m_animationActive =
true;
4883void ChartCanvas::OnJumpEaseTimer(wxTimerEvent &event) {
4885 wxLongLong now = wxGetLocalTimeMillis();
4886 double elapsed = (now - m_animationStart).ToDouble();
4887 double t = elapsed / m_animationDuration.ToDouble();
4888 if (t > 1.0) t = 1.0;
4891 double e = easeOutCubic(t);
4894 double curLat = m_startLat + (m_endLat - m_startLat) * e;
4895 double curLon = m_startLon + (m_endLon - m_startLon) * e;
4896 double curScale = m_startScale + (m_endScale - m_startScale) * e;
4901 SetViewPoint(curLat, curLon, curScale, 0.0, GetVPRotation());
4907 m_animationActive =
false;
4908 UpdateFollowButtonState();
4918 extendedSectorLegs.clear();
4927 if (iters++ > 5)
return false;
4928 if (!std::isnan(dlat))
break;
4931 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
4937 else if (dlat < -90)
4940 if (dlon > 360.) dlon -= 360.;
4941 if (dlon < -360.) dlon += 360.;
4956 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4960 if (VPoint.b_quilt) {
4961 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4962 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
4966 double tweak_scale_ppm =
4972 if (new_ref_dbIndex == -1) {
4973#pragma GCC diagnostic push
4974#pragma GCC diagnostic ignored "-Warray-bounds"
4981 int trial_index = -1;
4982 if (m_pCurrentStack->nEntry) {
4984 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4987 if (trial_index < 0) {
4988 auto full_screen_array = GetQuiltFullScreendbIndexArray();
4989 if (full_screen_array.size())
4990 trial_index = full_screen_array[full_screen_array.size() - 1];
4993 if (trial_index >= 0) {
4994 m_pQuilt->SetReferenceChart(trial_index);
4999#pragma GCC diagnostic pop
5006 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
5008 double offset_angle = atan2(offy, offx);
5009 double offset_distance = sqrt((offy * offy) + (offx * offx));
5010 double chart_angle = GetVPRotation();
5011 double target_angle = chart_angle - offset_angle;
5012 double d_east_mod = offset_distance * cos(target_angle);
5013 double d_north_mod = offset_distance * sin(target_angle);
5018 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.
pix_width / 2) ||
5019 (fabs(m_OSoffsety) > VPoint.
pix_height / 2))) {
5021 UpdateFollowButtonState();
5027 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
5032bool ChartCanvas::IsOwnshipOnScreen() {
5035 if (((r.x > 0) && r.x < GetCanvasWidth()) &&
5036 ((r.y > 0) && r.y < GetCanvasHeight()))
5042void ChartCanvas::ReloadVP(
bool b_adjust) {
5043 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
5045 LoadVP(VPoint, b_adjust);
5048void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
5050 if (g_bopengl && m_glcc) {
5051 m_glcc->Invalidate();
5052 if (m_glcc->GetSize() != GetSize()) {
5053 m_glcc->SetSize(GetSize());
5058 m_cache_vp.Invalidate();
5059 m_bm_cache_vp.Invalidate();
5062 VPoint.Invalidate();
5064 if (m_pQuilt) m_pQuilt->Invalidate();
5073 vp.m_projection_type, b_adjust);
5076void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
5077 m_pQuilt->SetReferenceChart(dbIndex);
5078 VPoint.Invalidate();
5079 m_pQuilt->Invalidate();
5082double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
5084 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
5091int ChartCanvas::AdjustQuiltRefChart() {
5096 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5098 double min_ref_scale =
5099 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
5100 double max_ref_scale =
5101 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
5104 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.
chart_scale);
5105 }
else if (VPoint.
chart_scale > max_ref_scale * 64) {
5106 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.
chart_scale);
5108 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
5111 int target_stack_index = wxNOT_FOUND;
5113 for (
auto index : m_pQuilt->GetExtendedStackIndexArray()) {
5114 if (index == m_pQuilt->GetRefChartdbIndex()) {
5115 target_stack_index = il;
5120 if (wxNOT_FOUND == target_stack_index)
5121 target_stack_index = 0;
5123 int ref_family = pc->GetChartFamily();
5124 int extended_array_count =
5125 m_pQuilt->GetExtendedStackIndexArray().size();
5126 while ((!brender_ok) &&
5127 ((
int)target_stack_index < (extended_array_count - 1))) {
5128 target_stack_index++;
5130 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5132 if ((ref_family ==
ChartData->GetDBChartFamily(test_db_index)) &&
5133 IsChartQuiltableRef(test_db_index)) {
5136 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
5138 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
5145 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
5146 if ((ref_family ==
ChartData->GetDBChartFamily(new_db_index)) &&
5147 IsChartQuiltableRef(new_db_index)) {
5148 m_pQuilt->SetReferenceChart(new_db_index);
5151 ret = m_pQuilt->GetRefChartdbIndex();
5153 ret = m_pQuilt->GetRefChartdbIndex();
5156 ret = m_pQuilt->GetRefChartdbIndex();
5165void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
5166 delete m_pCurrentStack;
5178bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
5179 double latNE,
double lonNE) {
5181 double latc = (latSW + latNE) / 2.0;
5182 double lonc = (lonSW + lonNE) / 2.0;
5185 double ne_easting, ne_northing;
5186 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
5188 double sw_easting, sw_northing;
5189 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
5191 double scale_ppm = VPoint.
pix_height / fabs(ne_northing - sw_northing);
5198 VPoint.
rotation, VPoint.m_projection_type,
true, refresh);
5201bool ChartCanvas::SetVPProjection(
int projection) {
5207 double prev_true_scale_ppm = m_true_scale_ppm;
5212 m_absolute_min_scale_ppm));
5220bool ChartCanvas::SetVPRotation(
double angle) {
5222 VPoint.
skew, angle);
5225 double skew,
double rotation,
int projection,
5226 bool b_adjust,
bool b_refresh) {
5231 if (VPoint.IsValid()) {
5232 if ((fabs(VPoint.
view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5233 (fabs(VPoint.
skew - skew) < 1e-9) &&
5234 (fabs(VPoint.
rotation - rotation) < 1e-9) &&
5235 (fabs(VPoint.
clat - lat) < 1e-9) && (fabs(VPoint.
clon - lon) < 1e-9) &&
5236 (VPoint.m_projection_type == projection ||
5237 projection == PROJECTION_UNKNOWN))
5240 if (VPoint.m_projection_type != projection)
5241 VPoint.InvalidateTransformCache();
5251 if (projection != PROJECTION_UNKNOWN)
5252 VPoint.SetProjectionType(projection);
5253 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5254 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5257 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5258 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5259 if (VPoint.
clat > 89.5)
5261 else if (VPoint.
clat < -89.5)
5262 VPoint.
clat = -89.5;
5267 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5268 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5280 bool bwasValid = VPoint.IsValid();
5285 m_cache_vp.Invalidate();
5290 VPoint.
chart_scale = m_canvas_scale_factor / (scale_ppm);
5294 int mouseX = mouse_x;
5295 int mouseY = mouse_y;
5296 if ((mouseX > 0) && (mouseX < VPoint.
pix_width) && (mouseY > 0) &&
5302 SendCursorLatLonToAllPlugIns(lat, lon);
5305 if (!VPoint.b_quilt && m_singleChart) {
5310 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5314 if ((!m_cache_vp.IsValid()) ||
5319 wxPoint cp_last, cp_this;
5323 if (cp_last != cp_this) {
5329 if (m_pCurrentStack) {
5331 int current_db_index;
5333 m_pCurrentStack->GetCurrentEntrydbIndex();
5335 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5337 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5340 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5344 if (VPoint.b_quilt) {
5346 m_pQuilt->InvalidateAllQuiltPatchs();
5350 if (!m_pCurrentStack)
return false;
5352 int current_db_index;
5354 m_pCurrentStack->GetCurrentEntrydbIndex();
5356 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5357 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5360 int current_ref_stack_index = -1;
5361 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5362 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5363 current_ref_stack_index = i;
5366 if (g_bFullScreenQuilt) {
5367 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5371 bool b_needNewRef =
false;
5374 if ((-1 == current_ref_stack_index) &&
5375 (m_pQuilt->GetRefChartdbIndex() >= 0))
5376 b_needNewRef =
true;
5383 bool renderable =
true;
5385 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5386 if (referenceChart) {
5387 double chartMaxScale = referenceChart->GetNormalScaleMax(
5389 renderable = chartMaxScale * 64 >= VPoint.
chart_scale;
5391 if (!renderable) b_needNewRef =
true;
5396 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5397 int target_scale = cte_ref.GetScale();
5398 int target_type = cte_ref.GetChartType();
5399 int candidate_stack_index;
5406 candidate_stack_index = 0;
5407 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5409 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5410 int candidate_scale = cte_candidate.GetScale();
5411 int candidate_type = cte_candidate.GetChartType();
5413 if ((candidate_scale >= target_scale) &&
5414 (candidate_type == target_type)) {
5415 bool renderable =
true;
5417 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5418 if (tentative_referenceChart) {
5419 double chartMaxScale =
5420 tentative_referenceChart->GetNormalScaleMax(
5422 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5425 if (renderable)
break;
5428 candidate_stack_index++;
5433 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5434 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5435 while (candidate_stack_index >= 0) {
5436 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5440 int candidate_scale = cte_candidate.GetScale();
5441 int candidate_type = cte_candidate.GetChartType();
5443 if ((candidate_scale <= target_scale) &&
5444 (candidate_type == target_type))
5447 candidate_stack_index--;
5452 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5453 (candidate_stack_index < 0))
5454 candidate_stack_index = 0;
5456 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5458 m_pQuilt->SetReferenceChart(new_ref_index);
5464 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5469 bool renderable =
true;
5471 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5472 if (referenceChart) {
5473 double chartMaxScale = referenceChart->GetNormalScaleMax(
5475 renderable = chartMaxScale * 1.5 > VPoint.
chart_scale;
5476 proj =
ChartData->GetDBChartProj(ref_db_index);
5478 proj = PROJECTION_MERCATOR;
5480 VPoint.b_MercatorProjectionOverride =
5481 (m_pQuilt->GetnCharts() == 0 || !renderable);
5483 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5485 VPoint.SetProjectionType(proj);
5492 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5497 m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5517 m_pQuilt->Invalidate();
5534 if (b_refresh) Refresh(
false);
5541 }
else if (!g_bopengl) {
5542 OcpnProjType projection = PROJECTION_UNKNOWN;
5545 projection = m_singleChart->GetChartProjectionType();
5546 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5547 VPoint.SetProjectionType(projection);
5551 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5552 m_cache_vp.Invalidate();
5556 UpdateCanvasControlBar();
5562 if (VPoint.GetBBox().GetValid()) {
5565 VPoint.
ref_scale = m_singleChart->GetNativeScale();
5574 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5577 VPoint.
ref_scale = m_pQuilt->GetRefNativeScale();
5584 wxPoint2DDouble r, r1;
5586 double delta_check =
5590 double check_point = wxMin(89., VPoint.
clat);
5592 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5595 DistanceBearingMercator(check_point, VPoint.
clon, check_point + delta_check,
5596 VPoint.
clon, 0, &rhumbDist);
5601 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5602 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5604 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5608 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5614 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5616 if (m_true_scale_ppm)
5617 VPoint.
chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5622 double round_factor = 1000.;
5626 round_factor = 100.;
5628 round_factor = 1000.;
5631 double retina_coef = 1;
5635 retina_coef = GetContentScaleFactor();
5646 double true_scale_display =
5647 wxRound(VPoint.
chart_scale / round_factor) * round_factor * retina_coef;
5652 if (m_displayed_scale_factor > 10.0)
5653 text.Printf(
"%s %4.0f (%1.0fx)", _(
"Scale"), true_scale_display,
5654 m_displayed_scale_factor);
5655 else if (m_displayed_scale_factor > 1.0)
5656 text.Printf(
"%s %4.0f (%1.1fx)", _(
"Scale"), true_scale_display,
5657 m_displayed_scale_factor);
5658 else if (m_displayed_scale_factor > 0.1) {
5659 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5660 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5661 }
else if (m_displayed_scale_factor > 0.01) {
5662 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5663 text.Printf(
"%s %4.0f (%1.2fx)", _(
"Scale"), true_scale_display, sfr);
5666 "%s %4.0f (---)", _(
"Scale"),
5667 true_scale_display);
5670 m_scaleValue = true_scale_display;
5672 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5674 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5675 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5677 bool b_noshow =
false;
5681 wxClientDC dc(parent_frame->GetStatusBar());
5683 wxFont *templateFont = FontMgr::Get().
GetFont(_(
"StatusBar"), 0);
5684 dc.SetFont(*templateFont);
5685 dc.GetTextExtent(text, &w, &h);
5690 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5691 if (w && w > rect.width) {
5692 text.Printf(
"%s (%1.1fx)", _(
"Scale"), m_displayed_scale_factor);
5696 dc.GetTextExtent(text, &w, &h);
5698 if (w && w > rect.width) {
5704 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5709 m_vLat = VPoint.
clat;
5710 m_vLon = VPoint.
clon;
5724static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5728static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5729 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5731wxColour ChartCanvas::PredColor() {
5734 if (SHIP_NORMAL == m_ownship_state)
5735 return GetGlobalColor(_T (
"URED" ));
5737 else if (SHIP_LOWACCURACY == m_ownship_state)
5738 return GetGlobalColor(_T (
"YELO1" ));
5740 return GetGlobalColor(_T (
"NODTA" ));
5743wxColour ChartCanvas::ShipColor() {
5747 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5749 if (SHIP_LOWACCURACY == m_ownship_state)
5750 return GetGlobalColor(_T (
"YELO1" ));
5752 return GetGlobalColor(_T (
"URED" ));
5755void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc,
5756 wxPoint2DDouble lShipMidPoint) {
5757 dc.SetPen(wxPen(PredColor(), 2));
5759 if (SHIP_NORMAL == m_ownship_state)
5760 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5762 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5764 dc.DrawEllipse(lShipMidPoint.m_x - 10, lShipMidPoint.m_y - 10, 20, 20);
5765 dc.DrawEllipse(lShipMidPoint.m_x - 6, lShipMidPoint.m_y - 6, 12, 12);
5767 dc.
DrawLine(lShipMidPoint.m_x - 12, lShipMidPoint.m_y, lShipMidPoint.m_x + 12,
5769 dc.
DrawLine(lShipMidPoint.m_x, lShipMidPoint.m_y - 12, lShipMidPoint.m_x,
5770 lShipMidPoint.m_y + 12);
5773void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5774 wxPoint GPSOffsetPixels,
5775 wxPoint2DDouble lGPSPoint) {
5780 float ref_dim = m_display_size_mm / 24;
5781 ref_dim = wxMin(ref_dim, 12);
5782 ref_dim = wxMax(ref_dim, 6);
5785 cPred.Set(g_cog_predictor_color);
5786 if (cPred == wxNullColour) cPred = PredColor();
5793 double nominal_line_width_pix = wxMax(
5795 floor(m_pix_per_mm / 2));
5799 if (nominal_line_width_pix > g_cog_predictor_width)
5800 g_cog_predictor_width = nominal_line_width_pix;
5803 wxPoint lPredPoint, lHeadPoint;
5805 float pCog = std::isnan(gCog) ? 0 : gCog;
5806 float pSog = std::isnan(gSog) ? 0 : gSog;
5808 double pred_lat, pred_lon;
5809 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5810 &pred_lat, &pred_lon);
5821 float ndelta_pix = 10.;
5822 double hdg_pred_lat, hdg_pred_lon;
5823 bool b_render_hdt =
false;
5824 if (!std::isnan(gHdt)) {
5826 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5829 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5830 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5831 if (dist > ndelta_pix ) {
5832 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5833 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5838 wxPoint lShipMidPoint;
5839 lShipMidPoint.x = lGPSPoint.m_x + GPSOffsetPixels.x;
5840 lShipMidPoint.y = lGPSPoint.m_y + GPSOffsetPixels.y;
5841 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5842 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5844 if (lpp >= img_height / 2) {
5845 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5846 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5847 !std::isnan(gSog)) {
5849 float dash_length = ref_dim;
5850 wxDash dash_long[2];
5852 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5853 g_cog_predictor_width);
5854 dash_long[1] = dash_long[0] / 2.0;
5858 if (dash_length > 250.) {
5859 dash_long[0] = 250. / g_cog_predictor_width;
5860 dash_long[1] = dash_long[0] / 2;
5863 wxPen ppPen2(cPred, g_cog_predictor_width,
5864 (wxPenStyle)g_cog_predictor_style);
5865 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5866 ppPen2.SetDashes(2, dash_long);
5869 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5870 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5872 if (g_cog_predictor_width > 1) {
5873 float line_width = g_cog_predictor_width / 3.;
5875 wxDash dash_long3[2];
5876 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5877 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5879 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
5880 (wxPenStyle)g_cog_predictor_style);
5881 if (g_cog_predictor_style == (wxPenStyle)wxUSER_DASH)
5882 ppPen3.SetDashes(2, dash_long3);
5884 dc.StrokeLine(lGPSPoint.m_x + GPSOffsetPixels.x,
5885 lGPSPoint.m_y + GPSOffsetPixels.y,
5886 lPredPoint.x + GPSOffsetPixels.x,
5887 lPredPoint.y + GPSOffsetPixels.y);
5890 if (g_cog_predictor_endmarker) {
5892 double png_pred_icon_scale_factor = .4;
5893 if (g_ShipScaleFactorExp > 1.0)
5894 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5895 if (g_scaler) png_pred_icon_scale_factor *= 1.0 / g_scaler;
5899 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
5900 (
float)(lPredPoint.x - lShipMidPoint.x));
5901 cog_rad += (float)PI;
5903 for (
int i = 0; i < 4; i++) {
5905 double pxa = (double)(s_png_pred_icon[j]);
5906 double pya = (double)(s_png_pred_icon[j + 1]);
5908 pya *= png_pred_icon_scale_factor;
5909 pxa *= png_pred_icon_scale_factor;
5911 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
5912 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
5914 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
5915 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
5919 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
5922 dc.SetBrush(wxBrush(cPred));
5924 dc.StrokePolygon(4, icon);
5931 float hdt_dash_length = ref_dim * 0.4;
5933 cPred.Set(g_ownship_HDTpredictor_color);
5934 if (cPred == wxNullColour) cPred = PredColor();
5936 (g_ownship_HDTpredictor_width > 0 ? g_ownship_HDTpredictor_width
5937 : g_cog_predictor_width * 0.8);
5938 wxDash dash_short[2];
5940 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
5943 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
5946 wxPen ppPen2(cPred, hdt_width, (wxPenStyle)g_ownship_HDTpredictor_style);
5947 if (g_ownship_HDTpredictor_style == (wxPenStyle)wxUSER_DASH)
5948 ppPen2.SetDashes(2, dash_short);
5952 lGPSPoint.m_x + GPSOffsetPixels.x, lGPSPoint.m_y + GPSOffsetPixels.y,
5953 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
5955 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
5957 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
5959 if (g_ownship_HDTpredictor_endmarker) {
5960 double nominal_circle_size_pixels = wxMax(
5961 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
5964 if (g_ShipScaleFactorExp > 1.0)
5965 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5967 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
5968 lHeadPoint.y + GPSOffsetPixels.y,
5969 nominal_circle_size_pixels / 2);
5974 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
5975 double factor = 1.00;
5976 if (g_pNavAidRadarRingsStepUnits == 1)
5978 else if (g_pNavAidRadarRingsStepUnits == 2) {
5979 if (std::isnan(gSog))
5984 factor *= g_fNavAidRadarRingsStep;
5988 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
5991 double lpp = sqrt(pow((
double)(lGPSPoint.m_x - r.x), 2) +
5992 pow((
double)(lGPSPoint.m_y - r.y), 2));
5993 int pix_radius = (int)lpp;
5995 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
5997 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
6000 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
6002 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
6003 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, i * pix_radius);
6007void ChartCanvas::ComputeShipScaleFactor(
6008 float icon_hdt,
int ownShipWidth,
int ownShipLength,
6009 wxPoint2DDouble &lShipMidPoint, wxPoint &GPSOffsetPixels,
6010 wxPoint2DDouble lGPSPoint,
float &scale_factor_x,
float &scale_factor_y) {
6011 float screenResolution = m_pix_per_mm;
6014 double ship_bow_lat, ship_bow_lon;
6015 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
6016 &ship_bow_lat, &ship_bow_lon);
6017 wxPoint lShipBowPoint;
6018 wxPoint2DDouble b_point =
6022 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
6023 powf((
float)(b_point.m_y - a_point.m_y), 2));
6026 float shipLength_mm = shipLength_px / screenResolution;
6029 float ownship_min_mm = g_n_ownship_min_mm;
6030 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
6033 float hdt_ant = icon_hdt + 180.;
6034 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
6035 float dx = g_n_gps_antenna_offset_x / 1852.;
6036 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
6044 if (shipLength_mm < ownship_min_mm) {
6045 dy /= shipLength_mm / ownship_min_mm;
6046 dx /= shipLength_mm / ownship_min_mm;
6049 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
6051 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
6052 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
6058 GPSOffsetPixels.x = lShipMidPoint.m_x - lGPSPoint.m_x;
6059 GPSOffsetPixels.y = lShipMidPoint.m_y - lGPSPoint.m_y;
6061 float scale_factor = shipLength_px / ownShipLength;
6064 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
6067 scale_factor = wxMax(scale_factor, scale_factor_min);
6069 scale_factor_y = scale_factor;
6070 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
6071 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
6074void ChartCanvas::ShipDraw(
ocpnDC &dc) {
6075 if (!GetVP().IsValid())
return;
6077 wxPoint GPSOffsetPixels(0, 0);
6078 wxPoint2DDouble lGPSPoint, lShipMidPoint;
6081 float pCog = std::isnan(gCog) ? 0 : gCog;
6082 float pSog = std::isnan(gSog) ? 0 : gSog;
6086 lShipMidPoint = lGPSPoint;
6090 float icon_hdt = pCog;
6091 if (!std::isnan(gHdt)) icon_hdt = gHdt;
6094 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
6098 double osd_head_lat, osd_head_lon;
6099 wxPoint osd_head_point;
6101 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
6106 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.m_y),
6107 (
float)(osd_head_point.x - lShipMidPoint.m_x));
6108 icon_rad += (float)PI;
6110 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().
rotation;
6114 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
6118 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
6119 if (GetVP().chart_scale >
6122 ShipDrawLargeScale(dc, lShipMidPoint);
6128 if (m_pos_image_user)
6129 pos_image = m_pos_image_user->Copy();
6130 else if (SHIP_NORMAL == m_ownship_state)
6131 pos_image = m_pos_image_red->Copy();
6132 if (SHIP_LOWACCURACY == m_ownship_state)
6133 pos_image = m_pos_image_yellow->Copy();
6134 else if (SHIP_NORMAL != m_ownship_state)
6135 pos_image = m_pos_image_grey->Copy();
6138 if (m_pos_image_user) {
6139 pos_image = m_pos_image_user->Copy();
6141 if (SHIP_LOWACCURACY == m_ownship_state)
6142 pos_image = m_pos_image_user_yellow->Copy();
6143 else if (SHIP_NORMAL != m_ownship_state)
6144 pos_image = m_pos_image_user_grey->Copy();
6147 img_height = pos_image.GetHeight();
6149 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
6150 g_OwnShipIconType > 0)
6152 int ownShipWidth = 22;
6153 int ownShipLength = 84;
6154 if (g_OwnShipIconType == 1) {
6155 ownShipWidth = pos_image.GetWidth();
6156 ownShipLength = pos_image.GetHeight();
6159 float scale_factor_x, scale_factor_y;
6160 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
6161 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
6162 scale_factor_x, scale_factor_y);
6164 if (g_OwnShipIconType == 1) {
6165 pos_image.Rescale(ownShipWidth * scale_factor_x,
6166 ownShipLength * scale_factor_y,
6167 wxIMAGE_QUALITY_HIGH);
6168 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6170 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6173 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6174 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6175 if (rot_image.GetAlpha(ip, jp) > 64)
6176 rot_image.SetAlpha(ip, jp, 255);
6178 wxBitmap os_bm(rot_image);
6180 int w = os_bm.GetWidth();
6181 int h = os_bm.GetHeight();
6184 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6185 lShipMidPoint.m_y - h / 2,
true);
6188 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6189 lShipMidPoint.m_y - h / 2);
6190 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6191 lShipMidPoint.m_y - h / 2 + h);
6194 else if (g_OwnShipIconType == 2) {
6195 wxPoint ownship_icon[10];
6197 for (
int i = 0; i < 10; i++) {
6199 float pxa = (float)(s_ownship_icon[j]);
6200 float pya = (float)(s_ownship_icon[j + 1]);
6201 pya *= scale_factor_y;
6202 pxa *= scale_factor_x;
6204 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
6205 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
6207 ownship_icon[i].x = (int)(px) + lShipMidPoint.m_x;
6208 ownship_icon[i].y = (int)(py) + lShipMidPoint.m_y;
6211 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
6213 dc.SetBrush(wxBrush(ShipColor()));
6215 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
6218 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
6220 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
6224 img_height = ownShipLength * scale_factor_y;
6228 if (m_pos_image_user) circle_rad = 1;
6230 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6231 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6232 dc.StrokeCircle(lGPSPoint.m_x, lGPSPoint.m_y, circle_rad);
6235 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
6237 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
6240 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
6241 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6242 if (rot_image.GetAlpha(ip, jp) > 64)
6243 rot_image.SetAlpha(ip, jp, 255);
6245 wxBitmap os_bm(rot_image);
6247 if (g_ShipScaleFactorExp > 1) {
6248 wxImage scaled_image = os_bm.ConvertToImage();
6249 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6251 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6252 scaled_image.GetHeight() * factor,
6253 wxIMAGE_QUALITY_HIGH));
6255 int w = os_bm.GetWidth();
6256 int h = os_bm.GetHeight();
6259 dc.DrawBitmap(os_bm, lShipMidPoint.m_x - w / 2,
6260 lShipMidPoint.m_y - h / 2,
true);
6264 if (m_pos_image_user) circle_rad = 1;
6266 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6267 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6268 dc.StrokeCircle(lShipMidPoint.m_x, lShipMidPoint.m_y, circle_rad);
6271 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2,
6272 lShipMidPoint.m_y - h / 2);
6273 dc.CalcBoundingBox(lShipMidPoint.m_x - w / 2 + w,
6274 lShipMidPoint.m_y - h / 2 + h);
6279 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6292void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6293 float &MinorSpacing) {
6298 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6299 {.000001f, 45.0f, 15.0f},
6300 {.0002f, 30.0f, 10.0f},
6301 {.0003f, 10.0f, 2.0f},
6302 {.0008f, 5.0f, 1.0f},
6303 {.001f, 2.0f, 30.0f / 60.0f},
6304 {.003f, 1.0f, 20.0f / 60.0f},
6305 {.006f, 0.5f, 10.0f / 60.0f},
6306 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6307 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6308 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6309 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6310 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6311 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6312 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6313 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6316 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6317 if (view_scale_ppm < lltab[tabi][0])
break;
6318 MajorSpacing = lltab[tabi][1];
6319 MinorSpacing = lltab[tabi][2];
6333wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6334 int deg = (int)fabs(latlon);
6335 float min = fabs((fabs(latlon) - deg) * 60.0);
6345 }
else if (latlon < 0.0) {
6357 if (spacing >= 1.0) {
6358 ret.Printf(
"%3d%c %c", deg, 0x00b0, postfix);
6359 }
else if (spacing >= (1.0 / 60.0)) {
6360 ret.Printf(
"%3d%c%02.0f %c", deg, 0x00b0, min, postfix);
6362 ret.Printf(
"%3d%c%02.2f %c", deg, 0x00b0, min, postfix);
6379void ChartCanvas::GridDraw(
ocpnDC &dc) {
6380 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6382 double nlat, elon, slat, wlon;
6385 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6387 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6389 if (!m_pgridFont) SetupGridFont();
6390 dc.SetFont(*m_pgridFont);
6391 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6394 h = m_canvas_height;
6405 dlon = dlon + 360.0;
6408 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6411 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6414 while (lat < nlat) {
6417 CalcGridText(lat, gridlatMajor,
true);
6419 dc.
DrawLine(0, r.y, w, r.y,
false);
6420 dc.DrawText(st, 0, r.y);
6421 lat = lat + gridlatMajor;
6423 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6427 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6430 while (lat < nlat) {
6433 dc.
DrawLine(0, r.y, 10, r.y,
false);
6434 dc.
DrawLine(w - 10, r.y, w, r.y,
false);
6435 lat = lat + gridlatMinor;
6439 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6442 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6445 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6447 wxString st = CalcGridText(lon, gridlonMajor,
false);
6449 dc.
DrawLine(r.x, 0, r.x, h,
false);
6450 dc.DrawText(st, r.x, 0);
6451 lon = lon + gridlonMajor;
6456 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6460 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6462 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6465 dc.
DrawLine(r.x, 0, r.x, 10,
false);
6466 dc.
DrawLine(r.x, h - 10, r.x, h,
false);
6467 lon = lon + gridlonMinor;
6474void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6476 double blat, blon, tlat, tlon;
6479 int x_origin = m_bDisplayGrid ? 60 : 20;
6480 int y_origin = m_canvas_height - 50;
6486 if (GetVP().chart_scale > 80000)
6490 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6491 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6496 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6497 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6501 double rotation = -VPoint.
rotation;
6503 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6505 int l1 = (y_origin - r.y) / count;
6507 for (
int i = 0; i < count; i++) {
6514 dc.
DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6517 double blat, blon, tlat, tlon;
6524 int y_origin = m_canvas_height - chartbar_height - 5;
6528 m_canvas_height / GetContentScaleFactor() - chartbar_height - 5;
6535 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6538 int unit = g_iDistanceFormat;
6540 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6541 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6544 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6545 float places = floor(logdist), rem = logdist - places;
6546 dist = pow(10, places);
6553 wxString s = wxString::Format(
"%g ", dist) + getUsrDistanceUnit(
unit);
6554 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6555 double rotation = -VPoint.
rotation;
6557 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6561 int l1 = r.x - x_origin;
6563 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6568 dc.
DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6569 dc.
DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6570 dc.
DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6572 if (!m_pgridFont) SetupGridFont();
6573 dc.SetFont(*m_pgridFont);
6574 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6576 dc.GetTextExtent(s, &w, &h);
6582 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6586void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6591 double ra_max = 40.;
6593 wxPen pen_save = dc.GetPen();
6595 wxDateTime now = wxDateTime::Now();
6601 x0 = x1 = x + radius;
6606 while (angle < 360.) {
6607 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6610 if (angle > 360.) angle = 360.;
6612 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6620 x1 = (int)(x + cos(angle * PI / 180.) * r);
6621 y1 = (int)(y + sin(angle * PI / 180.) * r);
6631 dc.
DrawLine(x + radius, y, x1, y1);
6633 dc.SetPen(pen_save);
6636static bool bAnchorSoundPlaying =
false;
6638static void onAnchorSoundFinished(
void *ptr) {
6639 g_anchorwatch_sound->UnLoad();
6640 bAnchorSoundPlaying =
false;
6643void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6645 bool play_sound =
false;
6646 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6647 if (AnchorAlertOn1) {
6648 wxPoint TargetPoint;
6651 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6652 TargetPoint.y, 100);
6656 AnchorAlertOn1 =
false;
6658 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6659 if (AnchorAlertOn2) {
6660 wxPoint TargetPoint;
6663 JaggyCircle(dc, wxPen(GetGlobalColor(
"URED"), 2), TargetPoint.x,
6664 TargetPoint.y, 100);
6668 AnchorAlertOn2 =
false;
6671 if (!bAnchorSoundPlaying) {
6672 auto cmd_sound =
dynamic_cast<SystemCmdSound *
>(g_anchorwatch_sound);
6673 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6674 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6675 if (g_anchorwatch_sound->IsOk()) {
6676 bAnchorSoundPlaying =
true;
6677 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6678 g_anchorwatch_sound->Play();
6684void ChartCanvas::UpdateShips() {
6687 wxClientDC dc(
this);
6688 if (!dc.IsOk())
return;
6690 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6691 if (!test_bitmap.IsOk())
return;
6693 wxMemoryDC temp_dc(test_bitmap);
6695 temp_dc.ResetBoundingBox();
6696 temp_dc.DestroyClippingRegion();
6697 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6703 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6704 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6708 ocpndc.CalcBoundingBox(px.x, px.y);
6713 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6714 temp_dc.MaxY() - temp_dc.MinY());
6716 wxRect own_ship_update_rect = ship_draw_rect;
6718 if (!own_ship_update_rect.IsEmpty()) {
6721 own_ship_update_rect.Union(ship_draw_last_rect);
6722 own_ship_update_rect.Inflate(2);
6725 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6727 ship_draw_last_rect = ship_draw_rect;
6729 temp_dc.SelectObject(wxNullBitmap);
6732void ChartCanvas::UpdateAlerts() {
6737 wxClientDC dc(
this);
6741 dc.GetSize(&sx, &sy);
6744 wxBitmap test_bitmap(sx, sy, -1);
6748 temp_dc.SelectObject(test_bitmap);
6750 temp_dc.ResetBoundingBox();
6751 temp_dc.DestroyClippingRegion();
6752 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6759 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6760 temp_dc.MaxX() - temp_dc.MinX(),
6761 temp_dc.MaxY() - temp_dc.MinY());
6763 if (!alert_rect.IsEmpty())
6764 alert_rect.Inflate(2);
6766 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6769 wxRect alert_update_rect = alert_draw_rect;
6770 alert_update_rect.Union(alert_rect);
6773 RefreshRect(alert_update_rect,
false);
6777 alert_draw_rect = alert_rect;
6779 temp_dc.SelectObject(wxNullBitmap);
6782void ChartCanvas::UpdateAIS() {
6783 if (!g_pAIS)
return;
6788 wxClientDC dc(
this);
6792 dc.GetSize(&sx, &sy);
6800 if (g_pAIS->GetTargetList().size() > 10) {
6801 ais_rect = wxRect(0, 0, sx, sy);
6804 wxBitmap test_bitmap(sx, sy, -1);
6808 temp_dc.SelectObject(test_bitmap);
6810 temp_dc.ResetBoundingBox();
6811 temp_dc.DestroyClippingRegion();
6812 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6816 AISDraw(ocpndc, GetVP(),
this);
6817 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6821 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6822 temp_dc.MaxY() - temp_dc.MinY());
6824 if (!ais_rect.IsEmpty())
6825 ais_rect.Inflate(2);
6827 temp_dc.SelectObject(wxNullBitmap);
6830 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6833 wxRect ais_update_rect = ais_draw_rect;
6834 ais_update_rect.Union(ais_rect);
6837 RefreshRect(ais_update_rect,
false);
6841 ais_draw_rect = ais_rect;
6844void ChartCanvas::ToggleCPAWarn() {
6845 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6851 g_bTCPA_Max =
false;
6855 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6856 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6858 if (!g_AisFirstTimeUse) {
6859 OCPNMessageBox(
this, _(
"CPA Alarm is switched") +
" " + mess.MakeLower(),
6860 _(
"CPA") +
" " + mess, 4, 4);
6865void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6867void ChartCanvas::OnSize(wxSizeEvent &event) {
6868 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
return;
6870 GetClientSize(&m_canvas_width, &m_canvas_height);
6874 m_displayScale = GetContentScaleFactor();
6878 m_canvas_width *= m_displayScale;
6879 m_canvas_height *= m_displayScale;
6892 m_absolute_min_scale_ppm =
6894 (1.2 * WGS84_semimajor_axis_meters * PI);
6897 gFrame->ProcessCanvasResize();
6907 SetMUIBarPosition();
6908 UpdateFollowButtonState();
6909 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6913 xr_margin = m_canvas_width * 95 / 100;
6914 xl_margin = m_canvas_width * 5 / 100;
6915 yt_margin = m_canvas_height * 5 / 100;
6916 yb_margin = m_canvas_height * 95 / 100;
6919 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
6924 m_brepaint_piano =
true;
6927 m_dc_route.SelectObject(wxNullBitmap);
6930 m_dc_route.SelectObject(*proute_bm);
6944 m_glcc->OnSize(event);
6953void ChartCanvas::ProcessNewGUIScale() {
6961void ChartCanvas::CreateMUIBar() {
6962 if (g_useMUI && !m_muiBar) {
6968 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6969 m_muiBar->SetColorScheme(m_cs);
6970 m_muiBarHOSize = m_muiBar->m_size;
6974 SetMUIBarPosition();
6975 UpdateFollowButtonState();
6976 m_muiBar->UpdateDynamicValues();
6977 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6981void ChartCanvas::SetMUIBarPosition() {
6985 int pianoWidth = GetClientSize().x * 0.6f;
6990 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
6991 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
6993 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
6994 m_muiBar->SetColorScheme(m_cs);
6998 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
6999 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
7001 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
7002 m_muiBar->SetColorScheme(m_cs);
7006 m_muiBar->SetBestPosition();
7010void ChartCanvas::DestroyMuiBar() {
7017void ChartCanvas::ShowCompositeInfoWindow(
7018 int x,
int n_charts,
int scale,
const std::vector<int> &index_vector) {
7020 if (NULL == m_pCIWin) {
7025 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
7028 s = _(
"Composite of ");
7031 s1.Printf(
"%d ", n_charts);
7039 s1.Printf(_(
"Chart scale"));
7042 s2.Printf(
"1:%d\n",
scale);
7046 s1 = _(
"Zoom in for more information");
7050 int char_width = s1.Length();
7051 int char_height = 3;
7053 if (g_bChartBarEx) {
7056 for (
int i : index_vector) {
7058 wxString path = cte.GetFullSystemPath();
7062 char_width = wxMax(char_width, path.Length());
7063 if (j++ >= 9)
break;
7066 s +=
" .\n .\n .\n";
7075 m_pCIWin->SetString(s);
7077 m_pCIWin->FitToChars(char_width, char_height);
7080 p.x = x / GetContentScaleFactor();
7081 if ((p.x + m_pCIWin->GetWinSize().x) >
7082 (m_canvas_width / GetContentScaleFactor()))
7083 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7084 m_pCIWin->GetWinSize().x) /
7087 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7088 4 - m_pCIWin->GetWinSize().y;
7090 m_pCIWin->dbIndex = 0;
7091 m_pCIWin->chart_scale = 0;
7092 m_pCIWin->SetPosition(p);
7093 m_pCIWin->SetBitmap();
7094 m_pCIWin->Refresh();
7098 HideChartInfoWindow();
7102void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
7104 if (NULL == m_pCIWin) {
7109 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
7118 dbIndex, FULL_INIT);
7120 int char_width, char_height;
7121 s =
ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
7122 if (pc)
ChartData->UnLockCacheChart(dbIndex);
7124 m_pCIWin->SetString(s);
7125 m_pCIWin->FitToChars(char_width, char_height);
7128 p.x = x / GetContentScaleFactor();
7129 if ((p.x + m_pCIWin->GetWinSize().x) >
7130 (m_canvas_width / GetContentScaleFactor()))
7131 p.x = ((m_canvas_width / GetContentScaleFactor()) -
7132 m_pCIWin->GetWinSize().x) /
7135 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
7136 4 - m_pCIWin->GetWinSize().y;
7138 m_pCIWin->dbIndex = dbIndex;
7139 m_pCIWin->SetPosition(p);
7140 m_pCIWin->SetBitmap();
7141 m_pCIWin->Refresh();
7145 HideChartInfoWindow();
7149void ChartCanvas::HideChartInfoWindow(
void) {
7152 m_pCIWin->Destroy();
7156 androidForceFullRepaint();
7161void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
7162 wxMouseEvent ev(wxEVT_MOTION);
7165 ev.m_leftDown = mouse_leftisdown;
7167 wxEvtHandler *evthp = GetEventHandler();
7169 ::wxPostEvent(evthp, ev);
7172void ChartCanvas::MovementTimerEvent(wxTimerEvent &) {
7173 if ((m_panx_target_final - m_panx_target_now) ||
7174 (m_pany_target_final - m_pany_target_now)) {
7175 DoTimedMovementTarget();
7180void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
7182bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
7184 if (m_disable_edge_pan)
return false;
7187 int pan_margin = m_canvas_width * margin / 100;
7188 int pan_timer_set = 200;
7189 double pan_delta = GetVP().
pix_width * delta / 100;
7193 if (x > m_canvas_width - pan_margin) {
7198 else if (x < pan_margin) {
7203 if (y < pan_margin) {
7208 else if (y > m_canvas_height - pan_margin) {
7217 wxMouseState state = ::wxGetMouseState();
7218#if wxCHECK_VERSION(3, 0, 0)
7219 if (!state.LeftIsDown())
7221 if (!state.LeftDown())
7226 if ((bft) && !pPanTimer->IsRunning()) {
7228 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
7234 if ((!bft) && pPanTimer->IsRunning()) {
7244void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
7245 bool setBeingEdited) {
7246 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
7247 m_pRoutePointEditTarget = NULL;
7248 m_pFoundPoint = NULL;
7252 SelectableItemList SelList = pSelect->FindSelectionList(
7254 wxSelectableItemListNode *node = SelList.GetFirst();
7256 pFind = node->GetData();
7265 bool brp_viz =
false;
7266 if (m_pEditRouteArray) {
7267 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7268 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7269 if (pr->IsVisible()) {
7275 brp_viz = frp->IsVisible();
7279 if (m_pEditRouteArray)
7281 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7282 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7285 m_bRouteEditing = setBeingEdited;
7288 frp->m_bRPIsBeingEdited = setBeingEdited;
7289 m_bMarkEditing = setBeingEdited;
7292 m_pRoutePointEditTarget = frp;
7293 m_pFoundPoint = pFind;
7297 node = node->GetNext();
7300std::shared_ptr<PI_PointContext> ChartCanvas::GetCanvasContextAtPoint(
int x,
7316 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7317 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7318 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7319 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7323 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7326 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7331 int FoundAIS_MMSI = 0;
7333 FoundAIS_MMSI = pFindAIS->GetUserData();
7336 if (g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI))
7337 seltype |= SELTYPE_AISTARGET;
7343 Route *SelectedRoute = NULL;
7349 Route *pSelectedActiveRoute = NULL;
7350 Route *pSelectedVizRoute = NULL;
7354 SelectableItemList SelList =
7355 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7356 wxSelectableItemListNode *node = SelList.GetFirst();
7366 bool brp_viz =
false;
7368 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7370 if (pr->IsVisible()) {
7375 if (!brp_viz && prp->IsShared())
7377 brp_viz = prp->IsVisible();
7380 brp_viz = prp->IsVisible();
7382 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7388 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7391 pSelectedActiveRoute = pr;
7392 pFoundActiveRoutePoint = prp;
7397 if (NULL == pSelectedVizRoute) {
7398 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7400 if (pr->IsVisible()) {
7401 pSelectedVizRoute = pr;
7402 pFoundVizRoutePoint = prp;
7408 delete proute_array;
7411 node = node->GetNext();
7415 if (pFoundActiveRoutePoint) {
7416 FoundRoutePoint = pFoundActiveRoutePoint;
7417 SelectedRoute = pSelectedActiveRoute;
7418 }
else if (pFoundVizRoutePoint) {
7419 FoundRoutePoint = pFoundVizRoutePoint;
7420 SelectedRoute = pSelectedVizRoute;
7423 FoundRoutePoint = pFirstVizPoint;
7425 if (SelectedRoute) {
7426 if (SelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7427 }
else if (FoundRoutePoint) {
7428 seltype |= SELTYPE_MARKPOINT;
7433 if (m_pFoundRoutePoint) {
7437 .CalculateDCRect(m_dc_route,
this, &wp_rect);
7438 RefreshRect(wp_rect,
true);
7448 SelectableItemList SelList =
7449 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7451 if (NULL == SelectedRoute)
7454 wxSelectableItemListNode *node = SelList.GetFirst();
7459 if (pr->IsVisible()) {
7463 node = node->GetNext();
7467 if (SelectedRoute) {
7468 if (NULL == FoundRoutePoint)
7469 FoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7472 seltype |= SELTYPE_ROUTESEGMENT;
7477 if (pFindTrackSeg) {
7478 m_pSelectedTrack = NULL;
7480 SelectableItemList SelList =
7481 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7484 wxSelectableItemListNode *node = SelList.GetFirst();
7489 if (pt->IsVisible()) {
7490 m_pSelectedTrack = pt;
7493 node = node->GetNext();
7496 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7501 bool bseltc =
false;
7515 SelectableItemList SelList = pSelectTC->FindSelectionList(
7519 wxSelectableItemListNode *node = SelList.GetFirst();
7520 pFind = node->GetData();
7521 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7523 if (SelList.GetCount() > 1) {
7524 node = node->GetNext();
7526 pFind = node->GetData();
7528 if (pIDX_candidate->
IDX_type ==
'c') {
7529 pIDX_best_candidate = pIDX_candidate;
7533 node = node->GetNext();
7536 wxSelectableItemListNode *node = SelList.GetFirst();
7537 pFind = node->GetData();
7538 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7541 m_pIDXCandidate = pIDX_best_candidate;
7548 seltype |= SELTYPE_CURRENTPOINT;
7551 else if (pFindTide) {
7552 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7559 seltype |= SELTYPE_TIDEPOINT;
7564 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7567 auto rstruct = std::make_shared<PI_PointContext>();
7568 rstruct->object_type = OBJECT_CHART;
7569 rstruct->object_ident =
"";
7571 if (seltype == SELTYPE_AISTARGET) {
7572 rstruct->object_type = OBJECT_AISTARGET;
7574 val.Printf(
"%d", FoundAIS_MMSI);
7575 rstruct->object_ident = val.ToStdString();
7576 }
else if (seltype & SELTYPE_MARKPOINT) {
7577 if (FoundRoutePoint) {
7578 rstruct->object_type = OBJECT_ROUTEPOINT;
7579 rstruct->object_ident = FoundRoutePoint->
m_GUID.ToStdString();
7581 }
else if (seltype & SELTYPE_ROUTESEGMENT) {
7582 if (SelectedRoute) {
7583 rstruct->object_type = OBJECT_ROUTESEGMENT;
7584 rstruct->object_ident = SelectedRoute->
m_GUID.ToStdString();
7591void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7592 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7593 singleClickEventIsValid =
false;
7594 m_DoubleClickTimer->Stop();
7599bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7600 if (!m_bChartDragging && !m_bDrawingRoute) {
7605 if (m_Compass && m_Compass->IsShown()) {
7607 bool isInCompass = logicalRect.Contains(event.GetPosition());
7609 if (m_Compass->MouseEvent(event)) {
7610 cursor_region = CENTER;
7611 if (!g_btouch) SetCanvasCursor(event);
7617 if (m_notification_button && m_notification_button->IsShown()) {
7619 bool isinButton = logicalRect.Contains(event.GetPosition());
7621 SetCursor(*pCursorArrow);
7622 if (event.LeftDown()) HandleNotificationMouseClick();
7627 if (MouseEventToolbar(event))
return true;
7629 if (MouseEventChartBar(event))
return true;
7631 if (MouseEventMUIBar(event))
return true;
7633 if (MouseEventIENCBar(event))
return true;
7638void ChartCanvas::HandleNotificationMouseClick() {
7639 if (!m_NotificationsList) {
7643 m_NotificationsList->RecalculateSize();
7644 m_NotificationsList->Hide();
7647 if (m_NotificationsList->IsShown()) {
7648 m_NotificationsList->Hide();
7650 m_NotificationsList->RecalculateSize();
7651 m_NotificationsList->ReloadNotificationList();
7652 m_NotificationsList->Show();
7655bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7656 if (!g_bShowChartBar)
return false;
7658 if (!m_Piano->MouseEvent(event))
return false;
7660 cursor_region = CENTER;
7661 if (!g_btouch) SetCanvasCursor(event);
7665bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7666 if (!IsPrimaryCanvas())
return false;
7668 if (g_MainToolbar) {
7669 if (!g_MainToolbar->MouseEvent(event))
7672 g_MainToolbar->RefreshToolbar();
7675 cursor_region = CENTER;
7676 if (!g_btouch) SetCanvasCursor(event);
7680bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7681 if (!IsPrimaryCanvas())
return false;
7683 if (g_iENCToolbar) {
7684 if (!g_iENCToolbar->MouseEvent(event))
7687 g_iENCToolbar->RefreshToolbar();
7694bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7696 if (!m_muiBar->MouseEvent(event))
return false;
7699 cursor_region = CENTER;
7700 if (!g_btouch) SetCanvasCursor(event);
7712 event.GetPosition(&x, &y);
7714 x *= m_displayScale;
7715 y *= m_displayScale;
7717 m_MouseDragging =
event.Dragging();
7723 if (event.Dragging()) {
7724 if ((x == mouse_x) && (y == mouse_y))
return true;
7730 mouse_leftisdown =
event.LeftDown();
7734 cursor_region = CENTER;
7738 if (m_Compass && m_Compass->IsShown() &&
7739 m_Compass->
GetRect().Contains(event.GetPosition())) {
7740 cursor_region = CENTER;
7741 }
else if (x > xr_margin) {
7742 cursor_region = MID_RIGHT;
7743 }
else if (x < xl_margin) {
7744 cursor_region = MID_LEFT;
7745 }
else if (y > yb_margin - chartbar_height &&
7746 y < m_canvas_height - chartbar_height) {
7747 cursor_region = MID_TOP;
7748 }
else if (y < yt_margin) {
7749 cursor_region = MID_BOT;
7751 cursor_region = CENTER;
7754 if (!g_btouch) SetCanvasCursor(event);
7758 leftIsDown =
event.LeftDown();
7761 if (event.LeftDown()) {
7762 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7765 g_bTempShowMenuBar =
false;
7766 parent_frame->ApplyGlobalSettings(
false);
7774 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7775 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7779 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7780 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7783 event.SetEventObject(
this);
7784 if (SendMouseEventToPlugins(event))
7791 if (g_btouch && m_bChartDragging && event.LeftUp()) {
7792 StartChartDragInertia();
7795 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7797 if (m_DoubleClickTimer->IsRunning()) {
7798 m_DoubleClickTimer->Stop();
7803 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7804 singleClickEvent = event;
7805 singleClickEventIsValid =
true;
7814 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7815 if (g_click_stop > 0) {
7823 if (GetUpMode() == COURSE_UP_MODE) {
7824 m_b_rot_hidef =
false;
7825 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7827 pRotDefTimer->Stop();
7830 bool bRoll = !g_btouch;
7835 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7836 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7837 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7838 m_RolloverPopupTimer.Start(
7842 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7846 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7855#if !defined(__WXGTK__) && !defined(__WXQT__)
7863 if ((x >= 0) && (y >= 0))
7868 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7869 wxPoint p = ClientToScreen(wxPoint(x, y));
7875 if (m_routeState >= 2) {
7878 m_bDrawingRoute =
true;
7880 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7885 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7888 m_bDrawingRoute =
true;
7890 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7903#if defined(__WXMAC__) || defined(__ANDROID__)
7907 wxClientDC cdc(GetParent());
7919 if (m_pSelectedRoute) {
7921 m_pSelectedRoute->DeSelectRoute();
7923 if (g_bopengl && m_glcc) {
7928 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7931 if (m_pFoundRoutePoint) {
7939 if (g_btouch && m_pRoutePointEditTarget) {
7942 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7947 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7948 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7949 pFindRouteSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7950 pFindTrackSeg = pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7954 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7957 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7963 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7966 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7967 seltype |= SELTYPE_AISTARGET;
7972 m_pFoundRoutePoint = NULL;
7977 Route *pSelectedActiveRoute = NULL;
7978 Route *pSelectedVizRoute = NULL;
7982 SelectableItemList SelList =
7983 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7984 wxSelectableItemListNode *node = SelList.GetFirst();
7994 bool brp_viz =
false;
7996 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7998 if (pr->IsVisible()) {
8003 if (!brp_viz && prp->IsShared())
8005 brp_viz = prp->IsVisible();
8008 brp_viz = prp->IsVisible();
8010 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
8015 m_pSelectedRoute = NULL;
8017 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8020 pSelectedActiveRoute = pr;
8021 pFoundActiveRoutePoint = prp;
8026 if (NULL == pSelectedVizRoute) {
8027 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8029 if (pr->IsVisible()) {
8030 pSelectedVizRoute = pr;
8031 pFoundVizRoutePoint = prp;
8037 delete proute_array;
8039 node = node->GetNext();
8043 if (pFoundActiveRoutePoint) {
8044 m_pFoundRoutePoint = pFoundActiveRoutePoint;
8045 m_pSelectedRoute = pSelectedActiveRoute;
8046 }
else if (pFoundVizRoutePoint) {
8047 m_pFoundRoutePoint = pFoundVizRoutePoint;
8048 m_pSelectedRoute = pSelectedVizRoute;
8051 m_pFoundRoutePoint = pFirstVizPoint;
8053 if (m_pSelectedRoute) {
8054 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
8055 }
else if (m_pFoundRoutePoint) {
8056 seltype |= SELTYPE_MARKPOINT;
8060 if (m_pFoundRoutePoint) {
8064 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8065 RefreshRect(wp_rect,
true);
8074 SelectableItemList SelList =
8075 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
8077 if (NULL == m_pSelectedRoute)
8080 wxSelectableItemListNode *node = SelList.GetFirst();
8085 if (pr->IsVisible()) {
8086 m_pSelectedRoute = pr;
8089 node = node->GetNext();
8093 if (m_pSelectedRoute) {
8094 if (NULL == m_pFoundRoutePoint)
8095 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
8100 if (g_bopengl && m_glcc) {
8105 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
8107 seltype |= SELTYPE_ROUTESEGMENT;
8111 if (pFindTrackSeg) {
8112 m_pSelectedTrack = NULL;
8114 SelectableItemList SelList =
8115 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
8118 wxSelectableItemListNode *node = SelList.GetFirst();
8123 if (pt->IsVisible()) {
8124 m_pSelectedTrack = pt;
8127 node = node->GetNext();
8129 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
8144 SelectableItemList SelList =
8145 pSelectTC->FindSelectionList(ctx, slat, slon, SELTYPE_CURRENTPOINT);
8148 wxSelectableItemListNode *node = SelList.GetFirst();
8149 pFind = node->GetData();
8150 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8152 if (SelList.GetCount() > 1) {
8153 node = node->GetNext();
8155 pFind = node->GetData();
8157 if (pIDX_candidate->
IDX_type ==
'c') {
8158 pIDX_best_candidate = pIDX_candidate;
8162 node = node->GetNext();
8165 wxSelectableItemListNode *node = SelList.GetFirst();
8166 pFind = node->GetData();
8167 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
8170 m_pIDXCandidate = pIDX_best_candidate;
8171 seltype |= SELTYPE_CURRENTPOINT;
8174 else if (pFindTide) {
8175 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
8176 seltype |= SELTYPE_TIDEPOINT;
8180 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
8185void ChartCanvas::CallPopupMenu(
int x,
int y) {
8189 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
8197 if (SELTYPE_CURRENTPOINT == seltype) {
8203 if (SELTYPE_TIDEPOINT == seltype) {
8209 InvokeCanvasMenu(x, y, seltype);
8212 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
8216 m_pSelectedRoute = NULL;
8218 if (m_pFoundRoutePoint) {
8219 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
8222 m_pFoundRoutePoint = NULL;
8228bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
8236 event.GetPosition(&x, &y);
8242 SelectRadius = g_Platform->GetSelectRadiusPix() /
8243 (m_true_scale_ppm * 1852 * 60);
8250 if (event.LeftDClick() && (cursor_region == CENTER)) {
8251 m_DoubleClickTimer->Start();
8252 singleClickEventIsValid =
false;
8256 y * g_current_monitor_dip_px_ratio, zlat, zlon);
8261 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
8264 m_FoundAIS_MMSI = pFindAIS->GetUserData();
8265 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
8266 ShowAISTargetQueryDialog(
this, m_FoundAIS_MMSI);
8272 SelectableItemList rpSelList =
8273 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
8274 wxSelectableItemListNode *node = rpSelList.GetFirst();
8275 bool b_onRPtarget =
false;
8279 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
8280 b_onRPtarget =
true;
8283 node = node->GetNext();
8288 if (m_pRoutePointEditTarget) {
8290 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
8296 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
8299 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8300 m_pRoutePointEditTarget = NULL;
8301 RefreshRect(wp_rect,
true);
8305 node = rpSelList.GetFirst();
8310 wxArrayPtrVoid *proute_array =
8315 bool brp_viz =
false;
8317 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8319 if (pr->IsVisible()) {
8324 delete proute_array;
8328 brp_viz = frp->IsVisible();
8330 brp_viz = frp->IsVisible();
8333 ShowMarkPropertiesDialog(frp);
8341 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
8345 if (pr->IsVisible()) {
8346 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
8351 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
8355 if (pt->IsVisible()) {
8356 ShowTrackPropertiesDialog(pt);
8363 ShowObjectQueryWindow(x, y, zlat, zlon);
8368 if (event.LeftDown()) {
8384 bool appending =
false;
8385 bool inserting =
false;
8388 SetCursor(*pCursorPencil);
8392 m_bRouteEditing =
true;
8394 if (m_routeState == 1) {
8395 m_pMouseRoute =
new Route();
8396 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
8397 pRouteList->Append(m_pMouseRoute);
8406 double nearby_radius_meters =
8407 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8410 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8411 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8412 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
8413 wxArrayPtrVoid *proute_array =
8418 bool brp_viz =
false;
8420 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
8422 if (pr->IsVisible()) {
8427 delete proute_array;
8429 pNearbyPoint->IsShared())
8432 pNearbyPoint->IsVisible();
8434 brp_viz = pNearbyPoint->IsVisible();
8437 wxString msg = _(
"Use nearby waypoint?");
8439 const bool noname(pNearbyPoint->GetName() ==
"");
8442 _(
"Use nearby nameless waypoint and name it M with"
8443 " a unique number?");
8446 m_FinishRouteOnKillFocus =
false;
8448 OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8449 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8450 m_FinishRouteOnKillFocus =
true;
8451 if (dlg_return == wxID_YES) {
8453 if (m_pMouseRoute) {
8454 int last_wp_num = m_pMouseRoute->GetnPoints();
8456 wxString guid_short = m_pMouseRoute->GetGUID().Left(2);
8457 wxString wp_name = wxString::Format(
8458 "M%002i-%s", last_wp_num + 1, guid_short);
8459 pNearbyPoint->SetName(wp_name);
8461 pNearbyPoint->SetName(
"WPXX");
8463 pMousePoint = pNearbyPoint;
8466 if (m_routeState > 1)
8467 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8468 Undo_HasParent, NULL);
8471 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8472 bool procede =
false;
8476 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8482 m_FinishRouteOnKillFocus =
false;
8488 _(
"Insert first part of this route in the new route?");
8489 if (tail->GetIndexOf(pMousePoint) ==
8492 dmsg = _(
"Insert this route in the new route?");
8494 if (tail->GetIndexOf(pMousePoint) != 1) {
8495 dlg_return = OCPNMessageBox(
8496 this, dmsg, _(
"OpenCPN Route Create"),
8497 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8498 m_FinishRouteOnKillFocus =
true;
8500 if (dlg_return == wxID_YES) {
8507 _(
"Append last part of this route to the new route?");
8508 if (tail->GetIndexOf(pMousePoint) == 1)
8510 "Append this route to the new route?");
8515 if (tail->GetLastPoint() != pMousePoint) {
8516 dlg_return = OCPNMessageBox(
8517 this, dmsg, _(
"OpenCPN Route Create"),
8518 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8519 m_FinishRouteOnKillFocus =
true;
8521 if (dlg_return == wxID_YES) {
8532 if (!FindRouteContainingWaypoint(pMousePoint))
8533 pMousePoint->SetShared(
true);
8538 if (NULL == pMousePoint) {
8539 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8541 pMousePoint->SetNameShown(
false);
8545 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8547 if (m_routeState > 1)
8548 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8549 Undo_IsOrphanded, NULL);
8552 if (m_pMouseRoute) {
8553 if (m_routeState == 1) {
8555 m_pMouseRoute->AddPoint(pMousePoint);
8559 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8560 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8561 &rhumbBearing, &rhumbDist);
8562 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
8563 rlat, &gcDist, &gcBearing, NULL);
8564 double gcDistNM = gcDist / 1852.0;
8567 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8568 pow(rhumbDist - gcDistNM - 1, 0.5);
8571 msg << _(
"For this leg the Great Circle route is ")
8572 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8573 << _(
" shorter than rhumbline.\n\n")
8574 << _(
"Would you like include the Great Circle routing points "
8577 m_FinishRouteOnKillFocus =
false;
8578 m_disable_edge_pan =
true;
8581 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8582 wxYES_NO | wxNO_DEFAULT);
8584 m_disable_edge_pan =
false;
8585 m_FinishRouteOnKillFocus =
true;
8587 if (answer == wxID_YES) {
8589 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8590 wxRealPoint gcCoord;
8592 for (
int i = 1; i <= segmentCount; i++) {
8593 double fraction = (double)i * (1.0 / (
double)segmentCount);
8594 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8595 gcDist * fraction, gcBearing,
8596 &gcCoord.x, &gcCoord.y, NULL);
8598 if (i < segmentCount) {
8599 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
8601 gcPoint->SetNameShown(
false);
8603 NavObj_dB::GetInstance().InsertRoutePoint(gcPoint);
8605 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8608 gcPoint = pMousePoint;
8611 m_pMouseRoute->AddPoint(gcPoint);
8612 pSelect->AddSelectableRouteSegment(
8613 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8614 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8615 prevGcPoint = gcPoint;
8618 undo->CancelUndoableAction(
true);
8621 m_pMouseRoute->AddPoint(pMousePoint);
8622 pSelect->AddSelectableRouteSegment(
8623 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8624 pMousePoint, m_pMouseRoute);
8625 undo->AfterUndoableAction(m_pMouseRoute);
8629 m_pMouseRoute->AddPoint(pMousePoint);
8630 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8631 rlon, m_prev_pMousePoint,
8632 pMousePoint, m_pMouseRoute);
8633 undo->AfterUndoableAction(m_pMouseRoute);
8639 m_prev_pMousePoint = pMousePoint;
8647 int connect = tail->GetIndexOf(pMousePoint);
8652 int length = tail->GetnPoints();
8657 start = connect + 1;
8662 m_pMouseRoute->RemovePoint(
8666 for (i = start; i <= stop; i++) {
8667 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8670 m_pMouseRoute->GetnPoints();
8672 gFrame->RefreshAllCanvas();
8676 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8678 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8679 m_pMouseRoute->FinalizeForRendering();
8681 gFrame->RefreshAllCanvas();
8685 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8687 SetCursor(*pCursorPencil);
8689 if (!m_pMeasureRoute) {
8690 m_pMeasureRoute =
new Route();
8691 pRouteList->Append(m_pMeasureRoute);
8694 if (m_nMeasureState == 1) {
8700 wxString(_T (
"circle" )),
8701 wxEmptyString, wxEmptyString);
8703 pMousePoint->SetShowWaypointRangeRings(
false);
8705 m_pMeasureRoute->AddPoint(pMousePoint);
8709 m_prev_pMousePoint = pMousePoint;
8713 gFrame->RefreshAllCanvas();
8718 FindRoutePointsAtCursor(SelectRadius,
true);
8723 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8731 if (ret)
return true;
8734 if (event.Dragging()) {
8739 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8741 SelectableItemList SelList = pSelect->FindSelectionList(
8743 wxSelectableItemListNode *node = SelList.GetFirst();
8745 pFind = node->GetData();
8747 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8748 node = node->GetNext();
8753 if (m_pRoutePointEditTarget &&
8754 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8756 SelectableItemList SelList = pSelect->FindSelectionList(
8758 wxSelectableItemListNode *node = SelList.GetFirst();
8760 pFind = node->GetData();
8762 if (m_pRoutePointEditTarget == frp) {
8763 m_bIsInRadius =
true;
8766 node = node->GetNext();
8769 if (!m_dragoffsetSet) {
8771 .PresetDragOffset(
this, mouse_x, mouse_y);
8772 m_dragoffsetSet =
true;
8777 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8778 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8780 if (NULL == g_pMarkInfoDialog) {
8781 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8782 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8783 DraggingAllowed =
false;
8785 if (m_pRoutePointEditTarget &&
8786 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8787 DraggingAllowed =
false;
8789 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8791 if (DraggingAllowed) {
8792 if (!undo->InUndoableAction()) {
8793 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8794 Undo_NeedsCopy, m_pFoundPoint);
8800 if (!g_bopengl && m_pEditRouteArray) {
8801 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8802 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8807 if (g_pRouteMan->IsRouteValid(pr)) {
8809 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8810 pre_rect.Union(route_rect);
8818 if (CheckEdgePan(x, y,
true, 5, 2))
8826 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8828 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8829 m_pRoutePointEditTarget,
8830 SELTYPE_DRAGHANDLE);
8831 m_pFoundPoint->m_slat =
8832 m_pRoutePointEditTarget->m_lat;
8833 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8835 m_pRoutePointEditTarget->m_lat =
8837 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8838 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8839 m_pFoundPoint->m_slat =
8841 m_pFoundPoint->m_slon = new_cursor_lon;
8845 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8846 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8847 g_pMarkInfoDialog->UpdateProperties(
true);
8857 if (m_pEditRouteArray) {
8858 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8860 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8861 if (g_pRouteMan->IsRouteValid(pr)) {
8863 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8864 post_rect.Union(route_rect);
8870 pre_rect.Union(post_rect);
8871 RefreshRect(pre_rect,
false);
8873 gFrame->RefreshCanvasOther(
this);
8874 m_bRoutePoinDragging =
true;
8879 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8880 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8882 if (NULL == g_pMarkInfoDialog) {
8883 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8884 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8885 DraggingAllowed =
false;
8887 if (m_pRoutePointEditTarget &&
8888 (m_pRoutePointEditTarget->GetIconName() ==
"mob"))
8889 DraggingAllowed =
false;
8891 if (m_pRoutePointEditTarget->
m_bIsInLayer) DraggingAllowed =
false;
8893 if (DraggingAllowed) {
8894 if (!undo->InUndoableAction()) {
8895 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8896 Undo_NeedsCopy, m_pFoundPoint);
8904 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8905 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8907 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8908 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8910 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8916 .CalculateDCRect(m_dc_route,
this, &pre_rect);
8917 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8918 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8919 (
int)(lppmax - (pre_rect.height / 2)));
8927 .SetPointFromDraghandlePoint(
this, mouse_x, mouse_y);
8930 m_pRoutePointEditTarget,
8931 SELTYPE_DRAGHANDLE);
8932 m_pFoundPoint->m_slat =
8933 m_pRoutePointEditTarget->m_lat;
8934 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8936 m_pRoutePointEditTarget->m_lat =
8939 m_pRoutePointEditTarget->
m_wpBBox.Invalidate();
8945 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8946 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8947 g_pMarkInfoDialog->UpdateProperties(
true);
8952 if (!g_btouch) InvalidateGL();
8958 .CalculateDCRect(m_dc_route,
this, &post_rect);
8959 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8960 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8961 (
int)(lppmax - (post_rect.height / 2)));
8964 pre_rect.Union(post_rect);
8965 RefreshRect(pre_rect,
false);
8967 gFrame->RefreshCanvasOther(
this);
8968 m_bRoutePoinDragging =
true;
8973 if (ret)
return true;
8976 if (event.LeftUp()) {
8977 bool b_startedit_route =
false;
8978 m_dragoffsetSet =
false;
8981 m_bChartDragging =
false;
8982 m_bIsInRadius =
false;
8987 m_bedge_pan =
false;
8992 bool appending =
false;
8993 bool inserting =
false;
8999 if (m_pRoutePointEditTarget) {
9005 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9006 RefreshRect(wp_rect,
true);
9008 m_pRoutePointEditTarget = NULL;
9010 m_bRouteEditing =
true;
9012 if (m_routeState == 1) {
9013 m_pMouseRoute =
new Route();
9014 m_pMouseRoute->SetHiLite(50);
9015 pRouteList->Append(m_pMouseRoute);
9018 NavObj_dB::GetInstance().InsertRoute(m_pMouseRoute);
9025 double nearby_radius_meters =
9026 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9029 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
9030 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
9031 !pNearbyPoint->
m_bIsInLayer && pNearbyPoint->IsVisible()) {
9034 m_FinishRouteOnKillFocus =
9036 dlg_return = OCPNMessageBox(
9037 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
9038 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9039 m_FinishRouteOnKillFocus =
true;
9041 dlg_return = wxID_YES;
9043 if (dlg_return == wxID_YES) {
9044 pMousePoint = pNearbyPoint;
9047 if (m_routeState > 1)
9048 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9049 Undo_HasParent, NULL);
9050 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
9052 bool procede =
false;
9056 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
9062 m_FinishRouteOnKillFocus =
false;
9063 if (m_routeState == 1) {
9067 _(
"Insert first part of this route in the new route?");
9068 if (tail->GetIndexOf(pMousePoint) ==
9071 dmsg = _(
"Insert this route in the new route?");
9073 if (tail->GetIndexOf(pMousePoint) != 1) {
9075 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9076 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9077 m_FinishRouteOnKillFocus =
true;
9079 if (dlg_return == wxID_YES) {
9086 _(
"Append last part of this route to the new route?");
9087 if (tail->GetIndexOf(pMousePoint) == 1)
9089 "Append this route to the new route?");
9093 if (tail->GetLastPoint() != pMousePoint) {
9095 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
9096 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9097 m_FinishRouteOnKillFocus =
true;
9099 if (dlg_return == wxID_YES) {
9110 if (!FindRouteContainingWaypoint(pMousePoint))
9111 pMousePoint->SetShared(
true);
9115 if (NULL == pMousePoint) {
9116 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
9118 pMousePoint->SetNameShown(
false);
9120 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
9122 if (m_routeState > 1)
9123 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
9124 Undo_IsOrphanded, NULL);
9127 if (m_routeState == 1) {
9129 m_pMouseRoute->AddPoint(pMousePoint);
9130 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9134 double rhumbBearing, rhumbDist, gcBearing, gcDist;
9135 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
9136 &rhumbBearing, &rhumbDist);
9137 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
9138 &gcDist, &gcBearing, NULL);
9139 double gcDistNM = gcDist / 1852.0;
9142 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
9143 pow(rhumbDist - gcDistNM - 1, 0.5);
9146 msg << _(
"For this leg the Great Circle route is ")
9147 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
9148 << _(
" shorter than rhumbline.\n\n")
9149 << _(
"Would you like include the Great Circle routing points "
9153 m_FinishRouteOnKillFocus =
false;
9154 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
9155 wxYES_NO | wxNO_DEFAULT);
9156 m_FinishRouteOnKillFocus =
true;
9158 int answer = wxID_NO;
9161 if (answer == wxID_YES) {
9163 RoutePoint *prevGcPoint = m_prev_pMousePoint;
9164 wxRealPoint gcCoord;
9166 for (
int i = 1; i <= segmentCount; i++) {
9167 double fraction = (double)i * (1.0 / (
double)segmentCount);
9168 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
9169 gcDist * fraction, gcBearing,
9170 &gcCoord.x, &gcCoord.y, NULL);
9172 if (i < segmentCount) {
9173 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x,
"xmblue",
"",
9175 gcPoint->SetNameShown(
false);
9176 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
9179 gcPoint = pMousePoint;
9182 m_pMouseRoute->AddPoint(gcPoint);
9183 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9185 pSelect->AddSelectableRouteSegment(
9186 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
9187 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
9188 prevGcPoint = gcPoint;
9191 undo->CancelUndoableAction(
true);
9194 m_pMouseRoute->AddPoint(pMousePoint);
9195 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9196 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9197 rlon, m_prev_pMousePoint,
9198 pMousePoint, m_pMouseRoute);
9199 undo->AfterUndoableAction(m_pMouseRoute);
9203 m_pMouseRoute->AddPoint(pMousePoint);
9204 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
9206 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
9207 rlon, m_prev_pMousePoint,
9208 pMousePoint, m_pMouseRoute);
9209 undo->AfterUndoableAction(m_pMouseRoute);
9215 m_prev_pMousePoint = pMousePoint;
9222 int connect = tail->GetIndexOf(pMousePoint);
9227 int length = tail->GetnPoints();
9232 start = connect + 1;
9237 m_pMouseRoute->RemovePoint(
9241 for (i = start; i <= stop; i++) {
9242 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
9245 m_pMouseRoute->GetnPoints();
9247 gFrame->RefreshAllCanvas();
9251 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
9253 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
9254 m_pMouseRoute->FinalizeForRendering();
9259 }
else if (m_bMeasure_Active && m_nMeasureState)
9262 m_bedge_pan =
false;
9266 if (m_nMeasureState == 1) {
9267 m_pMeasureRoute =
new Route();
9268 pRouteList->Append(m_pMeasureRoute);
9273 if (m_pMeasureRoute) {
9276 wxEmptyString, wxEmptyString);
9279 m_pMeasureRoute->AddPoint(pMousePoint);
9283 m_prev_pMousePoint = pMousePoint;
9285 m_pMeasureRoute->GetnPoints();
9289 CancelMeasureRoute();
9295 bool bSelectAllowed =
true;
9296 if (NULL == g_pMarkInfoDialog) {
9297 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
9298 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
9299 bSelectAllowed =
false;
9306 if (m_bRoutePoinDragging) bSelectAllowed =
false;
9308 if (bSelectAllowed) {
9309 bool b_was_editing_mark = m_bMarkEditing;
9310 bool b_was_editing_route = m_bRouteEditing;
9311 FindRoutePointsAtCursor(SelectRadius,
9317 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->
m_bIsInLayer)
9318 m_pRoutePointEditTarget = NULL;
9320 if (!b_was_editing_route) {
9321 if (m_pEditRouteArray) {
9322 b_startedit_route =
true;
9326 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
9327 m_pTrackRolloverWin->IsActive(
false);
9329 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
9330 m_pRouteRolloverWin->IsActive(
false);
9334 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9336 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9341 if (g_pRouteMan->IsRouteValid(pr)) {
9344 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
9345 pre_rect.Union(route_rect);
9348 RefreshRect(pre_rect,
true);
9351 b_startedit_route =
false;
9355 if (m_pRoutePointEditTarget) {
9356 if (b_was_editing_mark ||
9357 b_was_editing_route) {
9358 if (m_lastRoutePointEditTarget) {
9362 .EnableDragHandle(
false);
9363 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9364 SELTYPE_DRAGHANDLE);
9368 if (m_pRoutePointEditTarget) {
9371 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
9372 wxPoint2DDouble dragHandlePoint =
9374 .GetDragHandlePoint(
this);
9375 pSelect->AddSelectablePoint(
9376 dragHandlePoint.m_y, dragHandlePoint.m_x,
9377 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
9380 if (m_lastRoutePointEditTarget) {
9384 .EnableDragHandle(
false);
9385 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
9386 SELTYPE_DRAGHANDLE);
9389 wxArrayPtrVoid *lastEditRouteArray =
9391 m_lastRoutePointEditTarget);
9392 if (lastEditRouteArray) {
9393 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
9395 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
9396 if (g_pRouteMan->IsRouteValid(pr)) {
9400 delete lastEditRouteArray;
9411 if (m_lastRoutePointEditTarget) {
9414 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9415 RefreshRect(wp_rect,
true);
9418 if (m_pRoutePointEditTarget) {
9421 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9422 RefreshRect(wp_rect,
true);
9431 bool b_start_rollover =
false;
9432 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
9433 SelectItem *pFind = pSelectAIS->FindSelection(
9435 if (pFind) b_start_rollover =
true;
9438 if (!b_start_rollover && !b_startedit_route) {
9439 SelectableItemList SelList = pSelect->FindSelectionList(
9441 wxSelectableItemListNode *node = SelList.GetFirst();
9447 if (pr && pr->IsVisible()) {
9448 b_start_rollover =
true;
9451 node = node->GetNext();
9455 if (!b_start_rollover && !b_startedit_route) {
9456 SelectableItemList SelList = pSelect->FindSelectionList(
9458 wxSelectableItemListNode *node = SelList.GetFirst();
9464 if (tr && tr->IsVisible()) {
9465 b_start_rollover =
true;
9468 node = node->GetNext();
9472 if (b_start_rollover)
9473 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
9477 bool appending =
false;
9478 bool inserting =
false;
9480 if (m_bRouteEditing ) {
9482 if (m_pRoutePointEditTarget) {
9488 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9489 double nearby_radius_meters =
9490 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9491 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9492 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9493 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9495 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9499 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9501 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9516 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9521 OCPNMessageBox(
this,
9522 _(
"Replace this RoutePoint by the nearby "
9524 _(
"OpenCPN RoutePoint change"),
9525 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9526 if (dlg_return == wxID_YES) {
9531 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9534 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9536 if (tail && current && (tail != current)) {
9538 connect = tail->GetIndexOf(pNearbyPoint);
9539 int index_current_route =
9540 current->GetIndexOf(m_pRoutePointEditTarget);
9541 index_last = current->GetIndexOf(current->GetLastPoint());
9542 dlg_return1 = wxID_NO;
9544 index_current_route) {
9546 if (connect != tail->GetnPoints()) {
9549 _(
"Last part of route to be appended to dragged "
9553 _(
"Full route to be appended to dragged route?");
9555 dlg_return1 = OCPNMessageBox(
9556 this, dmsg, _(
"OpenCPN Route Create"),
9557 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9558 if (dlg_return1 == wxID_YES) {
9562 }
else if (index_current_route ==
9567 _(
"First part of route to be inserted into dragged "
9569 if (connect == tail->GetnPoints())
9571 "Full route to be inserted into dragged route?");
9573 dlg_return1 = OCPNMessageBox(
9574 this, dmsg, _(
"OpenCPN Route Create"),
9575 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9576 if (dlg_return1 == wxID_YES) {
9583 if (m_pRoutePointEditTarget->IsShared()) {
9585 dlg_return = OCPNMessageBox(
9587 _(
"Do you really want to delete and replace this "
9589 "\n" + _(
"which has been created manually?"),
9590 (
"OpenCPN RoutePoint warning"),
9591 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9594 if (dlg_return == wxID_YES) {
9595 pMousePoint = pNearbyPoint;
9597 pMousePoint->SetShared(
true);
9607 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9609 if (m_pEditRouteArray) {
9610 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9612 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9613 if (g_pRouteMan->IsRouteValid(pr)) {
9619 pSelect->DeleteAllSelectableRoutePoints(pr);
9620 pSelect->DeleteAllSelectableRouteSegments(pr);
9625 pSelect->AddAllSelectableRouteSegments(pr);
9626 pSelect->AddAllSelectableRoutePoints(pr);
9628 pr->FinalizeForRendering();
9629 pr->UpdateSegmentDistances();
9630 if (m_bRoutePoinDragging) {
9632 NavObj_dB::GetInstance().UpdateRoute(pr);
9639 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9640 if (m_pEditRouteArray) {
9641 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9643 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9644 if (g_pRouteMan->IsRouteValid(pr)) {
9645 if (pRoutePropDialog->GetRoute() == pr) {
9646 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9662 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9665 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9666 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9667 g_pMarkInfoDialog->Hide();
9669 delete m_pRoutePointEditTarget;
9670 m_lastRoutePointEditTarget = NULL;
9671 m_pRoutePointEditTarget = NULL;
9672 undo->AfterUndoableAction(pMousePoint);
9673 undo->InvalidateUndo();
9678 else if (m_bMarkEditing) {
9679 if (m_pRoutePointEditTarget)
9680 if (m_bRoutePoinDragging) {
9682 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9686 if (m_pRoutePointEditTarget)
9687 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9689 if (!m_pRoutePointEditTarget) {
9690 delete m_pEditRouteArray;
9691 m_pEditRouteArray = NULL;
9692 m_bRouteEditing =
false;
9694 m_bRoutePoinDragging =
false;
9701 int length = tail->GetnPoints();
9702 for (
int i = connect + 1; i <= length; i++) {
9703 current->AddPointAndSegment(tail->GetPoint(i),
false);
9706 gFrame->RefreshAllCanvas();
9709 current->FinalizeForRendering();
9715 pSelect->DeleteAllSelectableRoutePoints(current);
9716 pSelect->DeleteAllSelectableRouteSegments(current);
9717 for (
int i = 1; i < connect; i++) {
9718 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9720 pSelect->AddAllSelectableRouteSegments(current);
9721 pSelect->AddAllSelectableRoutePoints(current);
9722 current->FinalizeForRendering();
9728 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9729 if (m_pEditRouteArray) {
9730 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9731 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9732 if (g_pRouteMan->IsRouteValid(pr)) {
9733 if (pRoutePropDialog->GetRoute() == pr) {
9734 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9744 if (m_bRouteEditing) {
9747 bool appending =
false;
9748 bool inserting =
false;
9751 if (m_pRoutePointEditTarget) {
9752 m_pRoutePointEditTarget->
m_bBlink =
false;
9756 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->
m_bIsActive) {
9757 double nearby_radius_meters =
9758 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9759 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9760 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9761 nearby_radius_meters, m_pRoutePointEditTarget->
m_GUID);
9763 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9764 bool duplicate =
false;
9766 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9768 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9783 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9788 OCPNMessageBox(
this,
9789 _(
"Replace this RoutePoint by the nearby "
9791 _(
"OpenCPN RoutePoint change"),
9792 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9793 if (dlg_return == wxID_YES) {
9797 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9800 FindRouteContainingWaypoint(m_pRoutePointEditTarget);
9802 if (tail && current && (tail != current)) {
9804 connect = tail->GetIndexOf(pNearbyPoint);
9805 int index_current_route =
9806 current->GetIndexOf(m_pRoutePointEditTarget);
9807 index_last = current->GetIndexOf(current->GetLastPoint());
9808 dlg_return1 = wxID_NO;
9810 index_current_route) {
9812 if (connect != tail->GetnPoints()) {
9815 _(
"Last part of route to be appended to dragged "
9819 _(
"Full route to be appended to dragged route?");
9821 dlg_return1 = OCPNMessageBox(
9822 this, dmsg, _(
"OpenCPN Route Create"),
9823 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9824 if (dlg_return1 == wxID_YES) {
9828 }
else if (index_current_route ==
9833 _(
"First part of route to be inserted into dragged "
9835 if (connect == tail->GetnPoints())
9837 "Full route to be inserted into dragged route?");
9839 dlg_return1 = OCPNMessageBox(
9840 this, dmsg, _(
"OpenCPN Route Create"),
9841 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9842 if (dlg_return1 == wxID_YES) {
9849 if (m_pRoutePointEditTarget->IsShared()) {
9850 dlg_return = wxID_NO;
9851 dlg_return = OCPNMessageBox(
9853 _(
"Do you really want to delete and replace this "
9855 "\n" + _(
"which has been created manually?"),
9856 (
"OpenCPN RoutePoint warning"),
9857 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9860 if (dlg_return == wxID_YES) {
9861 pMousePoint = pNearbyPoint;
9863 pMousePoint->SetShared(
true);
9873 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9875 if (m_pEditRouteArray) {
9876 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9878 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9879 if (g_pRouteMan->IsRouteValid(pr)) {
9884 pSelect->DeleteAllSelectableRoutePoints(pr);
9885 pSelect->DeleteAllSelectableRouteSegments(pr);
9890 pSelect->AddAllSelectableRouteSegments(pr);
9891 pSelect->AddAllSelectableRoutePoints(pr);
9893 pr->FinalizeForRendering();
9894 pr->UpdateSegmentDistances();
9897 if (m_bRoutePoinDragging) {
9902 NavObj_dB::GetInstance().UpdateRoutePoint(
9903 m_pRoutePointEditTarget);
9905 NavObj_dB::GetInstance().UpdateRoute(pr);
9917 int length = tail->GetnPoints();
9918 for (
int i = connect + 1; i <= length; i++) {
9919 current->AddPointAndSegment(tail->GetPoint(i),
false);
9923 gFrame->RefreshAllCanvas();
9926 current->FinalizeForRendering();
9932 pSelect->DeleteAllSelectableRoutePoints(current);
9933 pSelect->DeleteAllSelectableRouteSegments(current);
9934 for (
int i = 1; i < connect; i++) {
9935 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9937 pSelect->AddAllSelectableRouteSegments(current);
9938 pSelect->AddAllSelectableRoutePoints(current);
9939 current->FinalizeForRendering();
9945 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9946 if (m_pEditRouteArray) {
9947 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9949 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9950 if (g_pRouteMan->IsRouteValid(pr)) {
9951 if (pRoutePropDialog->GetRoute() == pr) {
9952 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9961 NavObj_dB::GetInstance().DeleteRoutePoint(m_pRoutePointEditTarget);
9964 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9965 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9966 g_pMarkInfoDialog->Hide();
9968 delete m_pRoutePointEditTarget;
9969 m_lastRoutePointEditTarget = NULL;
9970 undo->AfterUndoableAction(pMousePoint);
9971 undo->InvalidateUndo();
9976 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9979 delete m_pEditRouteArray;
9980 m_pEditRouteArray = NULL;
9984 m_bRouteEditing =
false;
9985 m_pRoutePointEditTarget = NULL;
9991 else if (m_bMarkEditing) {
9992 if (m_pRoutePointEditTarget) {
9993 if (m_bRoutePoinDragging) {
9995 NavObj_dB::GetInstance().UpdateRoutePoint(m_pRoutePointEditTarget);
9997 undo->AfterUndoableAction(m_pRoutePointEditTarget);
10002 .CalculateDCRect(m_dc_route,
this, &wp_rect);
10004 RefreshRect(wp_rect,
true);
10007 m_pRoutePointEditTarget = NULL;
10008 m_bMarkEditing =
false;
10013 else if (leftIsDown) {
10014 leftIsDown =
false;
10018 if (!m_bChartDragging && !m_bMeasure_Active) {
10020 m_bChartDragging =
false;
10024 m_bRoutePoinDragging =
false;
10027 if (ret)
return true;
10030 if (event.RightDown()) {
10041 m_FinishRouteOnKillFocus =
false;
10042 CallPopupMenu(mx, my);
10043 m_FinishRouteOnKillFocus =
true;
10054 if (event.ShiftDown()) {
10058 event.GetPosition(&x, &y);
10060 x *= m_displayScale;
10061 y *= m_displayScale;
10067 int wheel_dir =
event.GetWheelRotation();
10070 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
10071 wheel_dir = wheel_dir > 0 ? 1 : -1;
10073 double factor = g_mouse_zoom_sensitivity;
10074 if (wheel_dir < 0) factor = 1 / factor;
10077 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
10078 if (wheel_dir == m_last_wheel_dir) {
10079 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
10084 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
10085 m_wheelstopwatch.Start(0);
10090 m_last_wheel_dir = wheel_dir;
10095 if (event.LeftDown()) {
10102 last_drag.x = x, last_drag.y = y;
10103 panleftIsDown =
true;
10106 if (event.LeftUp()) {
10107 if (panleftIsDown) {
10109 panleftIsDown =
false;
10112 if (!m_bChartDragging && !m_bMeasure_Active) {
10113 switch (cursor_region) {
10135 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
10140 m_bChartDragging =
false;
10146 if (event.Dragging() && event.LeftIsDown()) {
10164 struct timespec now;
10165 clock_gettime(CLOCK_MONOTONIC, &now);
10166 uint64_t tnow = (1e9 * now.tv_sec) + now.tv_nsec;
10168 if (
false == m_bChartDragging) {
10170 last_drag.x = x, last_drag.y = y;
10171 m_bChartDragging =
true;
10172 m_chart_drag_total_time = 0;
10173 m_chart_drag_total_x = 0;
10174 m_chart_drag_total_y = 0;
10175 m_inertia_last_drag_x = x;
10176 m_inertia_last_drag_y = y;
10177 m_drag_vec_x.clear();
10178 m_drag_vec_y.clear();
10179 m_drag_vec_t.clear();
10180 m_last_drag_time = tnow;
10184 uint64_t delta_t = tnow - m_last_drag_time;
10185 double delta_tf = delta_t / 1e9;
10187 m_chart_drag_total_time += delta_tf;
10188 m_chart_drag_total_x += m_inertia_last_drag_x - x;
10189 m_chart_drag_total_y += m_inertia_last_drag_y - y;
10191 m_drag_vec_x.push_back(m_inertia_last_drag_x - x);
10192 m_drag_vec_y.push_back(m_inertia_last_drag_y - y);
10193 m_drag_vec_t.push_back(delta_tf);
10195 m_inertia_last_drag_x = x;
10196 m_inertia_last_drag_y = y;
10197 m_last_drag_time = tnow;
10199 if ((last_drag.x != x) || (last_drag.y != y)) {
10200 if (!m_routeState) {
10203 m_bChartDragging =
true;
10204 StartTimedMovement();
10205 m_pan_drag.x += last_drag.x - x;
10206 m_pan_drag.y += last_drag.y - y;
10207 last_drag.x = x, last_drag.y = y;
10211 if ((last_drag.x != x) || (last_drag.y != y)) {
10212 if (!m_routeState) {
10215 m_bChartDragging =
true;
10216 StartTimedMovement();
10217 m_pan_drag.x += last_drag.x - x;
10218 m_pan_drag.y += last_drag.y - y;
10219 last_drag.x = x, last_drag.y = y;
10226 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
10228 m_DoubleClickTimer->Start();
10229 singleClickEventIsValid =
false;
10237void ChartCanvas::MouseEvent(wxMouseEvent &event) {
10238 if (MouseEventOverlayWindows(event))
return;
10245void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
10248 wxCursor *ptarget_cursor = pCursorArrow;
10249 if (!pPlugIn_Cursor) {
10250 ptarget_cursor = pCursorArrow;
10251 if ((!m_routeState) &&
10252 (!m_bMeasure_Active) ) {
10253 if (cursor_region == MID_RIGHT) {
10254 ptarget_cursor = pCursorRight;
10255 }
else if (cursor_region == MID_LEFT) {
10256 ptarget_cursor = pCursorLeft;
10257 }
else if (cursor_region == MID_TOP) {
10258 ptarget_cursor = pCursorDown;
10259 }
else if (cursor_region == MID_BOT) {
10260 ptarget_cursor = pCursorUp;
10262 ptarget_cursor = pCursorArrow;
10264 }
else if (m_bMeasure_Active ||
10266 ptarget_cursor = pCursorPencil;
10268 ptarget_cursor = pPlugIn_Cursor;
10271 SetCursor(*ptarget_cursor);
10274void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
10275 SetCursor(*pCursorArrow);
10278void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
10282 wxArrayString files;
10284 ChartBase *target_chart = GetChartAtCursor();
10285 if (target_chart) {
10286 file.Assign(target_chart->GetFullPath());
10287 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
10288 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
10291 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
10293 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
10294 unsigned int im = stackIndexArray.size();
10295 int scale = 2147483647;
10296 if (VPoint.b_quilt && im > 0) {
10297 for (
unsigned int is = 0; is < im; is++) {
10298 if (
ChartData->GetDBChartType(stackIndexArray[is]) ==
10299 CHART_TYPE_MBTILES) {
10300 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
10302 VPoint.
GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
10303 if (
ChartData->GetChartTableEntry(stackIndexArray[is])
10305 .Contains(lat, lon)) {
10306 if (
ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
10309 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
10310 file.Assign(
ChartData->GetDBChartFileName(stackIndexArray[is]));
10318 std::vector<Ais8_001_22 *> area_notices;
10320 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
10323 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
10324 auto target_data = target.second;
10325 if (!target_data->area_notices.empty()) {
10326 for (
auto &ani : target_data->area_notices) {
10331 for (Ais8_001_22_SubAreaList::iterator sa =
10332 area_notice.sub_areas.begin();
10333 sa != area_notice.sub_areas.end(); ++sa) {
10334 switch (sa->shape) {
10335 case AIS8_001_22_SHAPE_CIRCLE: {
10336 wxPoint target_point;
10338 bbox.Expand(target_point);
10339 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
10342 case AIS8_001_22_SHAPE_RECT: {
10343 wxPoint target_point;
10345 bbox.Expand(target_point);
10346 if (sa->e_dim_m > sa->n_dim_m)
10347 bbox.EnLarge(sa->e_dim_m * vp_scale);
10349 bbox.EnLarge(sa->n_dim_m * vp_scale);
10352 case AIS8_001_22_SHAPE_POLYGON:
10353 case AIS8_001_22_SHAPE_POLYLINE: {
10354 for (
int i = 0; i < 4; ++i) {
10355 double lat = sa->latitude;
10356 double lon = sa->longitude;
10357 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
10359 wxPoint target_point;
10361 bbox.Expand(target_point);
10365 case AIS8_001_22_SHAPE_SECTOR: {
10366 double lat1 = sa->latitude;
10367 double lon1 = sa->longitude;
10369 wxPoint target_point;
10371 bbox.Expand(target_point);
10372 for (
int i = 0; i < 18; ++i) {
10375 sa->left_bound_deg +
10376 i * (sa->right_bound_deg - sa->left_bound_deg) / 18,
10377 sa->radius_m / 1852.0, &lat, &lon);
10379 bbox.Expand(target_point);
10381 ll_gc_ll(lat1, lon1, sa->right_bound_deg, sa->radius_m / 1852.0,
10384 bbox.Expand(target_point);
10390 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
10391 area_notices.push_back(&area_notice);
10398 if (target_chart || !area_notices.empty() || file.HasName()) {
10400 int sel_rad_pix = 5;
10401 float SelectRadius = sel_rad_pix / (GetVP().
view_scale_ppm * 1852 * 60);
10406 SetCursor(wxCURSOR_WAIT);
10407 bool lightsVis = m_encShowLights;
10408 if (!lightsVis) SetShowENCLights(
true);
10411 ListOfObjRazRules *rule_list = NULL;
10412 ListOfPI_S57Obj *pi_rule_list = NULL;
10415 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
10416 else if (target_plugin_chart)
10417 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
10418 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
10420 ListOfObjRazRules *overlay_rule_list = NULL;
10421 ChartBase *overlay_chart = GetOverlayChartAtCursor();
10424 if (CHs57_Overlay) {
10425 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
10426 zlat, zlon, SelectRadius, &GetVP());
10429 if (!lightsVis) SetShowENCLights(
false);
10432 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ObjectQuery"));
10433 wxString face = dFont->GetFaceName();
10435 if (NULL == g_pObjectQueryDialog) {
10436 g_pObjectQueryDialog =
10437 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
10438 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
10441 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
10442 wxColor fg = FontMgr::Get().
GetFontColor(_(
"ObjectQuery"));
10446 fg = g_pObjectQueryDialog->GetForegroundColour();
10450 "<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>",
10451 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
10454 int points = dFont->GetPointSize();
10456 int points = dFont->GetPointSize() + 1;
10460 for (
int i = -2; i < 5; i++) {
10461 sizes[i + 2] = points + i + (i > 0 ? i : 0);
10463 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
10465 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText +=
"<i>";
10467 if (overlay_rule_list && CHs57_Overlay) {
10468 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
10469 objText <<
"<hr noshade>";
10472 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
10473 an != area_notices.end(); ++an) {
10474 objText << _T(
"<b>AIS Area Notice:</b> " );
10475 objText << ais8_001_22_notice_names[(*an)->notice_type];
10476 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
10477 (*an)->sub_areas.begin();
10478 sa != (*an)->sub_areas.end(); ++sa)
10479 if (!sa->text.empty()) objText << sa->text;
10480 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
10481 objText << _T(
"<hr noshade>" );
10485 objText << Chs57->CreateObjDescriptions(rule_list);
10486 else if (target_plugin_chart)
10487 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
10490 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText <<
"</i>";
10493 wxString AddFiles, filenameOK;
10495 if (!target_plugin_chart) {
10498 AddFiles = wxString::Format(
10499 "<hr noshade><br><b>Additional info files attached to: </b> "
10501 "size=-2>%s</font><br><table border=0 cellspacing=0 "
10503 file.GetFullName());
10505 file.Assign(file.GetPath(),
"");
10506 wxDir dir(file.GetFullPath());
10508 bool cont = dir.GetFirst(&filename,
"", wxDIR_FILES);
10510 file.Assign(dir.GetNameWithSep().append(filename));
10511 wxString FormatString =
10512 "<td valign=top><font size=-2><a "
10513 "href=\"%s\">%s</a></font></td>";
10514 if (g_ObjQFileExt.Find(file.GetExt().Lower()) != wxNOT_FOUND) {
10515 filenameOK = file.GetFullPath();
10517 if (3 * ((
int)filecount / 3) == filecount)
10518 FormatString.Prepend(
"<tr>");
10520 FormatString.Prepend(
10521 "<td>  </td>");
10524 AddFiles << wxString::Format(FormatString, file.GetFullPath(),
10525 file.GetFullName());
10528 cont = dir.GetNext(&filename);
10530 objText << AddFiles <<
"</table>";
10532 objText <<
"</font>";
10533 objText <<
"</body></html>";
10535 if (Chs57 || target_plugin_chart || (filecount > 1)) {
10536 g_pObjectQueryDialog->SetHTMLPage(objText);
10537 g_pObjectQueryDialog->Show();
10539 if ((!Chs57 && filecount == 1)) {
10541 wxHtmlLinkInfo hli(filenameOK);
10542 wxHtmlLinkEvent hle(1, hli);
10543 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
10546 if (rule_list) rule_list->Clear();
10549 if (overlay_rule_list) overlay_rule_list->Clear();
10550 delete overlay_rule_list;
10552 if (pi_rule_list) pi_rule_list->Clear();
10553 delete pi_rule_list;
10555 SetCursor(wxCURSOR_ARROW);
10559void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
10561 if (!g_pMarkInfoDialog) {
10568 wxSize canvas_size = GetSize();
10571 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
10573 g_pMarkInfoDialog->Layout();
10575 wxPoint canvas_pos = GetPosition();
10576 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
10578 bool newFit =
false;
10579 if (canvas_size.x < fitted_size.x) {
10580 fitted_size.x = canvas_size.x - 40;
10581 if (canvas_size.y < fitted_size.y)
10582 fitted_size.y -= 40;
10584 if (canvas_size.y < fitted_size.y) {
10585 fitted_size.y = canvas_size.y - 40;
10586 if (canvas_size.x < fitted_size.x)
10587 fitted_size.x -= 40;
10591 g_pMarkInfoDialog->SetSize(fitted_size);
10592 g_pMarkInfoDialog->Centre();
10598 wxString title_base = _(
"Mark Properties");
10600 title_base = _(
"Waypoint Properties");
10602 g_pMarkInfoDialog->SetRoutePoint(markPoint);
10603 g_pMarkInfoDialog->UpdateProperties();
10605 wxString caption(wxString::Format(
"%s, %s: %s", title_base, _(
"Layer"),
10607 g_pMarkInfoDialog->SetDialogTitle(caption);
10609 g_pMarkInfoDialog->SetDialogTitle(title_base);
10611 g_pMarkInfoDialog->Show();
10612 g_pMarkInfoDialog->Raise();
10613 g_pMarkInfoDialog->InitialFocus();
10614 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
10617void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
10618 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
10619 pRoutePropDialog->SetRouteAndUpdate(selected);
10621 pRoutePropDialog->Show();
10622 pRoutePropDialog->Raise();
10624 pRoutePropDialog = RoutePropDlgImpl::getInstance(
10627 if (g_bresponsive) {
10628 wxSize canvas_size = GetSize();
10629 wxPoint canvas_pos = GetPosition();
10630 wxSize fitted_size = pRoutePropDialog->GetSize();
10633 if (canvas_size.x < fitted_size.x) {
10634 fitted_size.x = canvas_size.x;
10635 if (canvas_size.y < fitted_size.y)
10636 fitted_size.y -= 20;
10638 if (canvas_size.y < fitted_size.y) {
10639 fitted_size.y = canvas_size.y;
10640 if (canvas_size.x < fitted_size.x)
10641 fitted_size.x -= 20;
10644 pRoutePropDialog->SetSize(fitted_size);
10645 pRoutePropDialog->Centre();
10650 wxPoint xxp = ClientToScreen(canvas_pos);
10654 pRoutePropDialog->SetRouteAndUpdate(selected);
10656 pRoutePropDialog->Show();
10661void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
10662 pTrackPropDialog = TrackPropDlg::getInstance(
10665 pTrackPropDialog->SetTrackAndUpdate(selected);
10668 pTrackPropDialog->Show();
10673void pupHandler_PasteWaypoint() {
10676 int pasteBuffer = kml.ParsePasteBuffer();
10677 RoutePoint *pasted = kml.GetParsedRoutePoint();
10678 if (!pasted)
return;
10680 double nearby_radius_meters =
10681 g_Platform->GetSelectRadiusPix() /
10682 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10684 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
10685 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
10687 int answer = wxID_NO;
10691 "There is an existing waypoint at the same location as the one you are "
10692 "pasting. Would you like to merge the pasted data with it?\n\n");
10693 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10694 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10695 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10698 if (answer == wxID_YES) {
10699 nearPoint->SetName(pasted->GetName());
10701 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10702 pRouteManagerDialog->UpdateWptListCtrl();
10705 if (answer == wxID_NO) {
10708 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10711 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10714 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10715 pRouteManagerDialog->UpdateWptListCtrl();
10720 gFrame->InvalidateAllGL();
10721 gFrame->RefreshAllCanvas(
false);
10724void pupHandler_PasteRoute() {
10727 int pasteBuffer = kml.ParsePasteBuffer();
10728 Route *pasted = kml.GetParsedRoute();
10729 if (!pasted)
return;
10731 double nearby_radius_meters =
10732 g_Platform->GetSelectRadiusPix() /
10733 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10739 bool mergepoints =
false;
10740 bool createNewRoute =
true;
10741 int existingWaypointCounter = 0;
10743 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10744 curPoint = pasted->GetPoint(i);
10745 nearPoint = pWayPointMan->GetNearbyWaypoint(
10746 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10748 mergepoints =
true;
10749 existingWaypointCounter++;
10757 int answer = wxID_NO;
10761 "There are existing waypoints at the same location as some of the ones "
10762 "you are pasting. Would you like to just merge the pasted data into "
10764 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10765 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10766 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10768 if (answer == wxID_CANCEL) {
10775 if (mergepoints && answer == wxID_YES &&
10776 existingWaypointCounter == pasted->GetnPoints()) {
10777 wxRouteListNode *route_node = pRouteList->GetFirst();
10778 while (route_node) {
10779 Route *proute = route_node->GetData();
10782 createNewRoute =
false;
10785 route_node = route_node->GetNext();
10789 Route *newRoute = 0;
10792 if (createNewRoute) {
10793 newRoute =
new Route();
10797 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10798 curPoint = pasted->GetPoint(i);
10801 newPoint = pWayPointMan->GetNearbyWaypoint(
10802 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10803 newPoint->SetName(curPoint->GetName());
10806 if (createNewRoute) newRoute->AddPoint(newPoint);
10812 newPoint->SetIconName(
"circle");
10815 newPoint->SetShared(
false);
10817 newRoute->AddPoint(newPoint);
10818 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10821 NavObj_dB::GetInstance().InsertRoutePoint(newPoint);
10824 if (i > 1 && createNewRoute)
10825 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10826 curPoint->m_lat, curPoint->m_lon,
10827 prevPoint, newPoint, newRoute);
10828 prevPoint = newPoint;
10831 if (createNewRoute) {
10832 pRouteList->Append(newRoute);
10834 NavObj_dB::GetInstance().InsertRoute(newRoute);
10836 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10837 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10840 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10841 pRouteManagerDialog->UpdateRouteListCtrl();
10842 pRouteManagerDialog->UpdateWptListCtrl();
10844 gFrame->InvalidateAllGL();
10845 gFrame->RefreshAllCanvas(
false);
10851void pupHandler_PasteTrack() {
10854 int pasteBuffer = kml.ParsePasteBuffer();
10855 Track *pasted = kml.GetParsedTrack();
10856 if (!pasted)
return;
10864 newTrack->SetName(pasted->GetName());
10866 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10867 curPoint = pasted->GetPoint(i);
10871 wxDateTime now = wxDateTime::Now();
10874 newTrack->AddPoint(newPoint);
10877 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10878 newPoint->m_lat, newPoint->m_lon,
10879 prevPoint, newPoint, newTrack);
10881 prevPoint = newPoint;
10884 g_TrackList.push_back(newTrack);
10886 NavObj_dB::GetInstance().InsertTrack(newTrack);
10888 gFrame->InvalidateAllGL();
10889 gFrame->RefreshAllCanvas(
false);
10892bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10895 v[
"CursorPosition_x"] = x;
10896 v[
"CursorPosition_y"] = y;
10899 if (seltype & SELTYPE_UNKNOWN) v[
"SelectionType"] =
"Canvas";
10900 if (seltype & SELTYPE_ROUTEPOINT) v[
"SelectionType"] =
"RoutePoint";
10901 if (seltype & SELTYPE_AISTARGET) v[
"SelectionType"] =
"AISTarget";
10906 SendMessageToAllPlugins(
"OCPN_CONTEXT_CLICK", out);
10908 json_msg.
Notify(std::make_shared<wxJSONValue>(v),
"OCPN_CONTEXT_CLICK");
10911#define SELTYPE_UNKNOWN 0x0001
10912#define SELTYPE_ROUTEPOINT 0x0002
10913#define SELTYPE_ROUTESEGMENT 0x0004
10914#define SELTYPE_TIDEPOINT 0x0008
10915#define SELTYPE_CURRENTPOINT 0x0010
10916#define SELTYPE_ROUTECREATE 0x0020
10917#define SELTYPE_AISTARGET 0x0040
10918#define SELTYPE_MARKPOINT 0x0080
10919#define SELTYPE_TRACKSEGMENT 0x0100
10920#define SELTYPE_DRAGHANDLE 0x0200
10923 if (g_bhide_context_menus)
return true;
10925 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10926 m_pIDXCandidate, m_nmea_log);
10929 wxEVT_COMMAND_MENU_SELECTED,
10930 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10932 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10935 wxEVT_COMMAND_MENU_SELECTED,
10936 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10938 delete m_canvasMenu;
10939 m_canvasMenu = NULL;
10949void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10952 if (m_canvasMenu) {
10953 m_canvasMenu->PopupMenuHandler(event);
10958void ChartCanvas::StartRoute(
void) {
10960 if (g_brouteCreating)
return;
10962 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10964 g_brouteCreating =
true;
10966 m_bDrawingRoute =
false;
10967 SetCursor(*pCursorPencil);
10969 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10971 HideGlobalToolbar();
10974 androidSetRouteAnnunciator(
true);
10978wxString ChartCanvas::FinishRoute(
void) {
10980 m_prev_pMousePoint = NULL;
10981 m_bDrawingRoute =
false;
10983 if (m_pMouseRoute) rv = m_pMouseRoute->
m_GUID;
10986 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10988 androidSetRouteAnnunciator(
false);
10991 SetCursor(*pCursorArrow);
10993 if (m_pMouseRoute) {
10994 if (m_bAppendingRoute) {
10996 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
10998 if (m_pMouseRoute->GetnPoints() > 1) {
11000 NavObj_dB::GetInstance().UpdateRoute(m_pMouseRoute);
11003 m_pMouseRoute = NULL;
11006 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
11008 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
11009 (pRoutePropDialog->IsShown())) {
11010 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
11013 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
11014 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
11015 pRouteManagerDialog->UpdateRouteListCtrl();
11018 m_bAppendingRoute =
false;
11019 m_pMouseRoute = NULL;
11021 m_pSelectedRoute = NULL;
11023 undo->InvalidateUndo();
11024 gFrame->RefreshAllCanvas(
true);
11026 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
11028 ShowGlobalToolbar();
11030 g_brouteCreating =
false;
11035void ChartCanvas::HideGlobalToolbar() {
11036 if (m_canvasIndex == 0) {
11037 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
11041void ChartCanvas::ShowGlobalToolbar() {
11042 if (m_canvasIndex == 0) {
11043 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
11047void ChartCanvas::ShowAISTargetList(
void) {
11048 if (NULL == g_pAISTargetList) {
11052 g_pAISTargetList->UpdateAISTargetList();
11055void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
11056 if (!m_bShowOutlines)
return;
11060 int nEntry =
ChartData->GetChartTableEntries();
11062 for (
int i = 0; i < nEntry; i++) {
11066 bool b_group_draw =
false;
11067 if (m_groupIndex > 0) {
11068 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
11069 int index = pt->GetGroupArray()[ig];
11070 if (m_groupIndex == index) {
11071 b_group_draw =
true;
11076 b_group_draw =
true;
11078 if (b_group_draw) RenderChartOutline(dc, i, vp);
11084 if (VPoint.b_quilt) {
11085 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
11086 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
11090 }
else if (m_singleChart &&
11091 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
11095 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
11098 if (zoom_factor > 8.0) {
11099 wxPen mPen(GetGlobalColor(
"UINFM"), 2, wxPENSTYLE_SHORT_DASH);
11102 wxPen mPen(GetGlobalColor(
"UINFM"), 1, wxPENSTYLE_SOLID);
11106 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
11110void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
11112 if (g_bopengl && m_glcc) {
11114 m_glcc->RenderChartOutline(dc, dbIndex, vp);
11119 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
11120 if (!
ChartData->IsChartAvailable(dbIndex))
return;
11123 float plylat, plylon;
11124 float plylat1, plylon1;
11126 int pixx, pixy, pixx1, pixy1;
11129 ChartData->GetDBBoundingBox(dbIndex, box);
11133 if (box.GetLonRange() == 360)
return;
11135 double lon_bias = 0;
11137 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
11139 int nPly =
ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11141 if (
ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
11142 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
11144 else if (
ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
11145 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
11148 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
11151 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11152 if (0 == nAuxPlyEntries)
11156 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
11157 plylon += lon_bias;
11163 for (
int i = 0; i < nPly - 1; i++) {
11164 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
11165 plylon1 += lon_bias;
11171 int pixxs1 = pixx1;
11172 int pixys1 = pixy1;
11174 bool b_skip =
false;
11178 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
11179 pow((
double)(pixy1 - pixy), 2)) /
11185 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11190 if (fabs(dist - distgc) > 10000. * 1852.)
11196 ClipResult res = cohen_sutherland_line_clip_i(
11198 if (res != Invisible && !b_skip)
11199 dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11207 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
11208 plylon1 += lon_bias;
11214 ClipResult res = cohen_sutherland_line_clip_i(
11216 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11223 int nAuxPlyEntries =
ChartData->GetnAuxPlyEntries(dbIndex);
11224 for (
int j = 0; j < nAuxPlyEntries; j++) {
11226 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
11231 for (
int i = 0; i < nAuxPly - 1; i++) {
11232 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
11238 int pixxs1 = pixx1;
11239 int pixys1 = pixy1;
11241 bool b_skip =
false;
11245 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
11246 ((pixy1 - pixy) * (pixy1 - pixy))) /
11251 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
11256 if (fabs(dist - distgc) > 10000. * 1852.)
11262 ClipResult res = cohen_sutherland_line_clip_i(
11264 if (res != Invisible && !b_skip) dc.
DrawLine(pixx, pixy, pixx1, pixy1);
11272 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
11277 ClipResult res = cohen_sutherland_line_clip_i(
11279 if (res != Invisible) dc.
DrawLine(pixx, pixy, pixx1, pixy1,
false);
11284static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
11285 const wxString &second) {
11286 wxFont *dFont = FontMgr::Get().
GetFont(_(
"RouteLegInfoRollover"));
11288 int pointsize = dFont->GetPointSize();
11292 pointsize, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
11293 false, dFont->GetFaceName());
11295 dc.SetFont(*psRLI_font);
11303 int hilite_offset = 3;
11306 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
11307 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
11309 dc.GetTextExtent(first, &w1, &h1);
11310 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
11316 w = wxMax(w1, w2) + (h1 / 2);
11321 xp = ref_point.x - w;
11323 yp += hilite_offset;
11325 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
11327 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
11328 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
11330 dc.DrawText(first, xp, yp);
11331 if (second.Len()) dc.DrawText(second, xp, yp + h1);
11334void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
11335 if (!g_bAllowShipToActive)
return;
11337 Route *rt = g_pRouteMan->GetpActiveRoute();
11340 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
11341 wxPoint2DDouble pa, pb;
11347 g_pRouteMan->GetRoutePen()->GetWidth();
11348 if (rt->
m_width != wxPENSTYLE_INVALID)
11350 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
11351 g_shipToActiveStyle, 5)];
11352 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
11354 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
11356 g_pRouteMan->GetActiveRoutePen()->GetColour();
11357 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
11360 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
11363 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
11364 (
int)pb.m_y, GetVP(),
true);
11368#ifdef USE_ANDROID_GLES2
11369 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11371 if (style != wxPENSTYLE_SOLID) {
11372 if (glChartCanvas::dash_map.find(style) !=
11373 glChartCanvas::dash_map.end()) {
11374 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
11378 dc.
DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
11381 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y,
11382 (
int)pb.m_x, (
int)pb.m_y, GetVP());
11388void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
11390 if (m_routeState >= 2) route = m_pMouseRoute;
11391 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
11392 route = m_pMeasureRoute;
11394 if (!route)
return;
11397 if (!g_pRouteMan->IsRouteValid(route))
return;
11402 int np = route->GetnPoints();
11404 if (g_btouch && (np > 1)) np--;
11406 render_lat = rp.m_lat;
11407 render_lon = rp.m_lon;
11410 double rhumbBearing, rhumbDist;
11412 &rhumbBearing, &rhumbDist);
11413 double brg = rhumbBearing;
11414 double dist = rhumbDist;
11418 double gcBearing, gcBearing2, gcDist;
11419 Geodesic::GreatCircleDistBear(render_lon, render_lat,
m_cursor_lon,
11422 double gcDistm = gcDist / 1852.0;
11425 rhumbBearing = 90.;
11427 wxPoint destPoint, lastPoint;
11430 int milesDiff = rhumbDist - gcDistm;
11431 if (milesDiff > 1) {
11442 for (
int i = 1; i <= milesDiff; i++) {
11443 double p = (double)i * (1.0 / (
double)milesDiff);
11445 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
11446 &pLon, &pLat, &gcBearing2);
11448 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
11450 lastPoint = destPoint;
11453 if (r_rband.x && r_rband.y) {
11454 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
11456 if (m_bMeasure_DistCircle) {
11457 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
11458 powf((
float)(r_rband.y - lastPoint.y), 2));
11460 dc.SetPen(*g_pRouteMan->GetRoutePen());
11461 dc.SetBrush(*wxTRANSPARENT_BRUSH);
11462 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
11468 wxString routeInfo;
11471 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
11477 varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
11479 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11480 (
int)varBrg, 0x00B0);
11482 routeInfo <<
" " << FormatDistanceAdaptive(dist);
11487 routeInfo <<
"\nReverse: ";
11489 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8),
11490 (
int)(brg + 180.) % 360, 0x00B0);
11492 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8),
11493 (
int)(varBrg + 180.) % 360, 0x00B0);
11498 s0.Append(_(
"Route") +
": ");
11500 s0.Append(_(
"Layer Route: "));
11503 if (!g_btouch) disp_length += dist;
11504 s0 += FormatDistanceAdaptive(disp_length);
11506 RouteLegInfo(dc, r_rband, routeInfo, s0);
11508 m_brepaint_piano =
true;
11511void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
11512 if (!m_bShowVisibleSectors)
return;
11514 if (g_bDeferredInitDone) {
11516 double rhumbBearing, rhumbDist;
11517 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
11518 &rhumbBearing, &rhumbDist);
11520 if (rhumbDist > 0.05)
11522 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
11523 m_sectorlegsVisible);
11524 m_sector_glat = gLat;
11525 m_sector_glon = gLon;
11527 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
11531void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
11539void ChartCanvas::UpdateCanvasS52PLIBConfig() {
11540 if (!ps52plib)
return;
11542 if (VPoint.b_quilt) {
11543 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11545 if (m_pQuilt->IsQuiltVector()) {
11546 if (ps52plib->GetStateHash() != m_s52StateHash) {
11548 m_s52StateHash = ps52plib->GetStateHash();
11552 if (ps52plib->GetStateHash() != m_s52StateHash) {
11554 m_s52StateHash = ps52plib->GetStateHash();
11559 bool bSendPlibState =
true;
11560 if (VPoint.b_quilt) {
11561 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
11564 if (bSendPlibState) {
11566 v[
"OpenCPN Version Major"] = VERSION_MAJOR;
11567 v[
"OpenCPN Version Minor"] = VERSION_MINOR;
11568 v[
"OpenCPN Version Patch"] = VERSION_PATCH;
11569 v[
"OpenCPN Version Date"] = VERSION_DATE;
11570 v[
"OpenCPN Version Full"] = VERSION_FULL;
11573 v[
"OpenCPN S52PLIB ShowText"] = GetShowENCText();
11574 v[
"OpenCPN S52PLIB ShowSoundings"] = GetShowENCDepth();
11575 v[
"OpenCPN S52PLIB ShowLights"] = GetShowENCLights();
11576 v[
"OpenCPN S52PLIB ShowAnchorConditions"] = m_encShowAnchor;
11577 v[
"OpenCPN S52PLIB ShowQualityOfData"] = GetShowENCDataQual();
11578 v[
"OpenCPN S52PLIB ShowATONLabel"] = GetShowENCBuoyLabels();
11579 v[
"OpenCPN S52PLIB ShowLightDescription"] = GetShowENCLightDesc();
11583 v[
"OpenCPN S52PLIB SoundingsFactor"] = g_ENCSoundingScaleFactor;
11584 v[
"OpenCPN S52PLIB TextFactor"] = g_ENCTextScaleFactor;
11588 v[
"OpenCPN S52PLIB MetaDisplay"] = ps52plib->m_bShowMeta;
11589 v[
"OpenCPN S52PLIB DeclutterText"] = ps52plib->m_bDeClutterText;
11590 v[
"OpenCPN S52PLIB ShowNationalText"] = ps52plib->m_bShowNationalTexts;
11591 v[
"OpenCPN S52PLIB ShowImportantTextOnly"] =
11592 ps52plib->m_bShowS57ImportantTextOnly;
11593 v[
"OpenCPN S52PLIB UseSCAMIN"] = ps52plib->m_bUseSCAMIN;
11594 v[
"OpenCPN S52PLIB UseSUPER_SCAMIN"] = ps52plib->m_bUseSUPER_SCAMIN;
11595 v[
"OpenCPN S52PLIB SymbolStyle"] = ps52plib->m_nSymbolStyle;
11596 v[
"OpenCPN S52PLIB BoundaryStyle"] = ps52plib->m_nBoundaryStyle;
11597 v[
"OpenCPN S52PLIB ColorShades"] = S52_getMarinerParam(S52_MAR_TWO_SHADES);
11600 v[
"OpenCPN Zoom Mod Vector"] = g_chart_zoom_modifier_vector;
11601 v[
"OpenCPN Zoom Mod Other"] = g_chart_zoom_modifier_raster;
11602 v[
"OpenCPN Scale Factor Exp"] =
11603 g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
11610 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
11611 SendMessageToAllPlugins(wxString(
"OpenCPN Config"), out);
11612 g_lastS52PLIBPluginMessage = out;
11618void ChartCanvas::OnPaint(wxPaintEvent &event) {
11619 wxPaintDC dc(
this);
11629 if (!m_b_paint_enable) {
11634 UpdateCanvasS52PLIBConfig();
11637 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
11639 if (m_glcc && g_bopengl) {
11640 if (!s_in_update) {
11650 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
11652 wxRegion ru = GetUpdateRegion();
11654 int rx, ry, rwidth, rheight;
11655 ru.GetBox(rx, ry, rwidth, rheight);
11659#ifdef ocpnUSE_DIBSECTION
11662 wxMemoryDC temp_dc;
11670 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
11671 height += m_Piano->GetHeight();
11673 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
11677 int thumbx, thumby, thumbsx, thumbsy;
11678 pthumbwin->GetPosition(&thumbx, &thumby);
11679 pthumbwin->GetSize(&thumbsx, &thumbsy);
11680 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
11682 if (pthumbwin->IsShown()) {
11683 rgn_chart.Subtract(rgn_thumbwin);
11684 ru.Subtract(rgn_thumbwin);
11690 wxRegion rgn_blit = ru;
11691 if (g_bShowChartBar) {
11692 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
11693 GetClientSize().x, m_Piano->GetHeight());
11696 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
11697 if (style->chartStatusWindowTransparent)
11698 m_brepaint_piano =
true;
11700 ru.Subtract(chart_bar_rect);
11704 if (m_Compass && m_Compass->IsShown()) {
11705 wxRect compassRect = m_Compass->
GetRect();
11706 if (ru.Contains(compassRect) != wxOutRegion) {
11707 ru.Subtract(compassRect);
11711 wxRect noteRect = m_notification_button->
GetRect();
11712 if (ru.Contains(noteRect) != wxOutRegion) {
11713 ru.Subtract(noteRect);
11717 bool b_newview =
true;
11722 m_cache_vp.IsValid()) {
11728 bool b_rcache_ok =
false;
11729 if (fabs(VPoint.
skew) > 0.01 || fabs(VPoint.
rotation) > 0.01)
11730 b_rcache_ok = !b_newview;
11733 if (VPoint.b_MercatorProjectionOverride)
11734 VPoint.SetProjectionType(PROJECTION_MERCATOR);
11748 if (b_rcache_ok) chart_get_region.Clear();
11751 if (VPoint.b_quilt)
11753 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11755 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11760 AbstractPlatform::ShowBusySpinner();
11764 if ((m_working_bm.GetWidth() != svp.
pix_width) ||
11765 (m_working_bm.GetHeight() != svp.
pix_height))
11769 if (fabs(VPoint.
rotation) < 0.01) {
11770 bool b_save =
true;
11772 if (g_SencThreadManager) {
11773 if (g_SencThreadManager->GetJobCount()) {
11775 m_cache_vp.Invalidate();
11789 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11794 int dy = c_new.y - c_old.y;
11795 int dx = c_new.x - c_old.x;
11800 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11804 temp_dc.SelectObject(m_working_bm);
11806 wxMemoryDC cache_dc;
11807 cache_dc.SelectObject(m_cached_chart_bm);
11811 temp_dc.Blit(0, 0, VPoint.
pix_width - dx,
11814 temp_dc.Blit(-dx, 0, VPoint.
pix_width + dx,
11820 temp_dc.Blit(0, -dy, VPoint.
pix_width - dx,
11823 temp_dc.Blit(-dx, -dy, VPoint.
pix_width + dx,
11831 update_region.Union(
11834 update_region.Union(wxRect(0, 0, VPoint.
pix_width, -dy));
11839 update_region.Union(
11842 update_region.Union(wxRect(0, 0, -dx, VPoint.
pix_height));
11846 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11848 cache_dc.SelectObject(wxNullBitmap);
11852 temp_dc.SelectObject(m_cached_chart_bm);
11855 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11859 temp_dc.SelectObject(m_working_bm);
11860 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11865 temp_dc.SelectObject(m_cached_chart_bm);
11870 temp_dc.SelectObject(m_working_bm);
11871 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11884 wxMemoryDC scratch_dc_0;
11885 scratch_dc_0.SelectObject(m_cached_chart_bm);
11888 scratch_dc_0.SelectObject(wxNullBitmap);
11897 temp_dc.SelectObject(m_working_bm);
11900 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11901 chart_get_all_region);
11904 AbstractPlatform::HideBusySpinner();
11910 if (!m_singleChart) {
11911 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11916 if (!chart_get_region.IsEmpty()) {
11917 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11921 if (temp_dc.IsOk()) {
11926 if (!VPoint.b_quilt) {
11929 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11930 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11937 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11938 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11941 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11943 temp_dc.DestroyClippingRegion();
11948 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11950 if (!backgroundRegion.IsEmpty()) {
11956 wxColour water = pWorldBackgroundChart->water;
11957 if (water.IsOk()) {
11958 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11959 temp_dc.SetBrush(wxBrush(water));
11961 while (upd.HaveRects()) {
11962 wxRect rect = upd.GetRect();
11963 temp_dc.DrawRectangle(rect);
11968 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11969 temp_dc.SetDeviceClippingRegion(*clip_region);
11970 delete clip_region;
11974 SetVPRotation(VPoint.
skew);
11977 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11983 wxMemoryDC *pChartDC = &temp_dc;
11984 wxMemoryDC rotd_dc;
11986 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11988 if (!b_rcache_ok) {
11990 wxMemoryDC tbase_dc;
11992 tbase_dc.SelectObject(bm_base);
11994 tbase_dc.SelectObject(wxNullBitmap);
11996 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11999 wxImage base_image;
12000 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
12008 bool b_rot_ok =
false;
12009 if (base_image.IsOk()) {
12012 m_b_rot_hidef =
false;
12016 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
12017 m_b_rot_hidef, &m_roffset);
12022 rot_vp.IsValid() && (ri.IsOk())) {
12029 m_prot_bm =
new wxBitmap(ri);
12032 m_roffset.x += VPoint.rv_rect.x;
12033 m_roffset.y += VPoint.rv_rect.y;
12036 if (m_prot_bm && m_prot_bm->IsOk()) {
12037 rotd_dc.SelectObject(*m_prot_bm);
12038 pChartDC = &rotd_dc;
12040 pChartDC = &temp_dc;
12041 m_roffset = wxPoint(0, 0);
12044 pChartDC = &temp_dc;
12045 m_roffset = wxPoint(0, 0);
12048 wxPoint offset = m_roffset;
12051 m_cache_vp = VPoint;
12054 wxMemoryDC mscratch_dc;
12055 mscratch_dc.SelectObject(*pscratch_bm);
12057 mscratch_dc.ResetBoundingBox();
12058 mscratch_dc.DestroyClippingRegion();
12059 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
12062 wxRegionIterator upd(rgn_blit);
12064 wxRect rect = upd.GetRect();
12066 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
12067 rect.x - offset.x, rect.y - offset.y);
12073 if (m_show_focus_bar && (g_canvasConfig != 0)) {
12074 if (
this == wxWindow::FindFocus()) {
12077 wxColour colour = GetGlobalColor(
"BLUE4");
12078 mscratch_dc.SetPen(wxPen(colour));
12079 mscratch_dc.SetBrush(wxBrush(colour));
12081 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
12082 mscratch_dc.DrawRectangle(activeRect);
12087 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
12088 unsigned int im = stackIndexArray.size();
12089 if (VPoint.b_quilt && im > 0) {
12090 std::vector<int> tiles_to_show;
12091 for (
unsigned int is = 0; is < im; is++) {
12093 ChartData->GetChartTableEntry(stackIndexArray[is]);
12094 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
12097 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
12098 tiles_to_show.push_back(stackIndexArray[is]);
12102 if (tiles_to_show.size())
12103 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
12109 ocpnDC scratch_dc(mscratch_dc);
12110 RenderAlertMessage(mscratch_dc, GetVP());
12116#ifdef ocpnUSE_DIBSECTION
12121 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
12122 q_dc.SelectObject(qbm);
12125 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
12128 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
12129 q_dc.SetBrush(qbr);
12130 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
12133 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
12136 q_dc.SelectObject(wxNullBitmap);
12145 if( VPoint.b_quilt ) {
12146 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
12147 ChartBase *chart = m_pQuilt->GetRefChart();
12148 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
12153 ChPI->ClearPLIBTextList();
12156 ps52plib->ClearTextList();
12160 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
12162 wxColor maskBackground = wxColour(1,0,0);
12163 t_dc.SelectObject( qbm );
12164 t_dc.SetBackground(wxBrush(maskBackground));
12168 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
12171 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
12172 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
12175 wxRegionIterator upd_final( ru );
12176 while( upd_final ) {
12177 wxRect rect = upd_final.GetRect();
12178 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
12182 t_dc.SelectObject( wxNullBitmap );
12188 if (VPoint.b_quilt) {
12189 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
12190 ChartBase *chart = m_pQuilt->GetRefChart();
12191 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
12195 ChPI->ClearPLIBTextList();
12197 if (ps52plib) ps52plib->ClearTextList();
12202 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
12204 if (g_bShowChartBar && m_Piano) {
12205 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
12206 GetVP().pix_width, m_Piano->GetHeight());
12209 if (!style->chartStatusWindowTransparent)
12210 chart_all_text_region.Subtract(chart_bar_rect);
12213 if (m_Compass && m_Compass->IsShown()) {
12214 wxRect compassRect = m_Compass->
GetRect();
12215 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
12216 chart_all_text_region.Subtract(compassRect);
12220 mscratch_dc.DestroyClippingRegion();
12222 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
12223 chart_all_text_region);
12229 ocpnDC scratch_dc(mscratch_dc);
12230 DrawOverlayObjects(scratch_dc, ru);
12233 wxRegionIterator upd_final(rgn_blit);
12234 while (upd_final) {
12235 wxRect rect = upd_final.GetRect();
12236 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
12243 temp_dc.SelectObject(wxNullBitmap);
12245 mscratch_dc.SelectObject(wxNullBitmap);
12247 dc.DestroyClippingRegion();
12252void ChartCanvas::PaintCleanup() {
12264 m_bTCupdate =
false;
12268 WarpPointer(warp_x, warp_y);
12275 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
12276 m_VPMovementTimer.Start(1, wxTIMER_ONE_SHOT);
12280wxColour GetErrorGraphicColor(
double val)
12299 if((val > 0) && (val < 1)) c.Set(
"#002ad9");
12300 else if((val >= 1) && (val < 2)) c.Set(
"#006ed9");
12301 else if((val >= 2) && (val < 3)) c.Set(
"#00b2d9");
12302 else if((val >= 3) && (val < 4)) c.Set(
"#00d4d4");
12303 else if((val >= 4) && (val < 5)) c.Set(
"#00d9a6");
12304 else if((val >= 5) && (val < 7)) c.Set(
"#00d900");
12305 else if((val >= 7) && (val < 9)) c.Set(
"#95d900");
12306 else if((val >= 9) && (val < 12)) c.Set(
"#d9d900");
12307 else if((val >= 12) && (val < 15)) c.Set(
"#d9ae00");
12308 else if((val >= 15) && (val < 18)) c.Set(
"#d98300");
12309 else if((val >= 18) && (val < 21)) c.Set(
"#d95700");
12310 else if((val >= 21) && (val < 24)) c.Set(
"#d90000");
12311 else if((val >= 24) && (val < 27)) c.Set(
"#ae0000");
12312 else if((val >= 27) && (val < 30)) c.Set(
"#8c0000");
12313 else if((val >= 30) && (val < 36)) c.Set(
"#870000");
12314 else if((val >= 36) && (val < 42)) c.Set(
"#690000");
12315 else if((val >= 42) && (val < 48)) c.Set(
"#550000");
12316 else if( val >= 48) c.Set(
"#410000");
12321void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
12324 gr_image.InitAlpha();
12326 double maxval = -10000;
12327 double minval = 10000;
12344 maxval = wxMax(maxval, (glat - rlat));
12345 minval = wxMin(minval, (glat - rlat));
12362 double f = ((glat - rlat)-minval)/(maxval - minval);
12364 double dy = (f * 40);
12366 wxColour c = GetErrorGraphicColor(dy);
12367 unsigned char r = c.Red();
12368 unsigned char g = c.Green();
12369 unsigned char b = c.Blue();
12371 gr_image.SetRGB(j, i, r,g,b);
12372 if((glat - rlat )!= 0)
12373 gr_image.SetAlpha(j, i, 128);
12375 gr_image.SetAlpha(j, i, 255);
12382 wxBitmap *pbm =
new wxBitmap(gr_image);
12383 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
12384 pbm->SetMask(gr_mask);
12386 pmdc->DrawBitmap(*pbm, 0,0);
12394void ChartCanvas::CancelMouseRoute() {
12396 m_pMouseRoute = NULL;
12397 m_bDrawingRoute =
false;
12400int ChartCanvas::GetNextContextMenuId() {
12401 return CanvasMenuHandler::GetNextContextMenuId();
12404bool ChartCanvas::SetCursor(
const wxCursor &c) {
12406 if (g_bopengl && m_glcc)
12407 return m_glcc->SetCursor(c);
12410 return wxWindow::SetCursor(c);
12413void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
12414 if (g_bquiting)
return;
12424 if (!m_RolloverPopupTimer.IsRunning() &&
12425 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
12426 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
12427 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
12428 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
12431 if (m_glcc && g_bopengl) {
12434 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
12436 m_glcc->Refresh(eraseBackground,
12447 if (pthumbwin && pthumbwin->IsShown()) {
12448 pthumbwin->Raise();
12449 pthumbwin->Refresh(
false);
12453 if (m_pCIWin && m_pCIWin->IsShown()) {
12455 m_pCIWin->Refresh(
false);
12463 wxWindow::Refresh(eraseBackground, rect);
12466void ChartCanvas::Update() {
12467 if (m_glcc && g_bopengl) {
12472 wxWindow::Update();
12476 if (!pemboss)
return;
12477 int x = pemboss->x, y = pemboss->y;
12478 const double factor = 200;
12480 wxASSERT_MSG(dc.GetDC(),
"DrawEmboss has no dc (opengl?)");
12481 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
12482 wxASSERT_MSG(pmdc,
"dc to EmbossCanvas not a memory dc");
12485 wxMemoryDC snip_dc;
12486 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
12487 snip_dc.SelectObject(snip_bmp);
12489 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
12490 snip_dc.SelectObject(wxNullBitmap);
12492 wxImage snip_img = snip_bmp.ConvertToImage();
12495 unsigned char *pdata = snip_img.GetData();
12497 for (
int y = 0; y < pemboss->height; y++) {
12498 int map_index = (y * pemboss->width);
12499 for (
int x = 0; x < pemboss->width; x++) {
12500 double val = (pemboss->pmap[map_index] * factor) / 256.;
12502 int nred = (int)((*pdata) + val);
12503 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
12504 *pdata++ = (
unsigned char)nred;
12506 int ngreen = (int)((*pdata) + val);
12507 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
12508 *pdata++ = (
unsigned char)ngreen;
12510 int nblue = (int)((*pdata) + val);
12511 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
12512 *pdata++ = (
unsigned char)nblue;
12520 wxBitmap emb_bmp(snip_img);
12523 wxMemoryDC result_dc;
12524 result_dc.SelectObject(emb_bmp);
12527 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
12529 result_dc.SelectObject(wxNullBitmap);
12535 if (GetQuiltMode()) {
12537 int refIndex = GetQuiltRefChartdbIndex();
12538 if (refIndex >= 0) {
12540 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
12541 if (current_type == CHART_TYPE_MBTILES) {
12542 ChartBase *pChart = m_pQuilt->GetRefChart();
12545 zoom_factor = ptc->GetZoomFactor();
12550 if (zoom_factor <= 3.9)
return NULL;
12552 if (m_singleChart) {
12553 if (zoom_factor <= 3.9)
return NULL;
12558 if (m_pEM_OverZoom) {
12559 m_pEM_OverZoom->x = 4;
12560 m_pEM_OverZoom->y = 0;
12561 if (g_MainToolbar && IsPrimaryCanvas()) {
12562 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
12563 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
12566 return m_pEM_OverZoom;
12569void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
12581 if (g_pi_manager) {
12582 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
12583 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12587 AISDrawAreaNotices(dc, GetVP(),
this);
12589 wxDC *pdc = dc.GetDC();
12591 pdc->DestroyClippingRegion();
12592 wxDCClipper(*pdc, ru);
12595 if (m_bShowNavobjects) {
12596 DrawAllTracksInBBox(dc, GetVP().GetBBox());
12597 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
12598 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
12599 DrawAnchorWatchPoints(dc);
12601 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
12602 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
12605 AISDraw(dc, GetVP(),
this);
12609 RenderVisibleSectorLights(dc);
12611 RenderAllChartOutlines(dc, GetVP());
12612 RenderRouteLegs(dc);
12613 RenderShipToActive(dc,
false);
12615 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
12616 if (g_pi_manager) {
12617 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12621 if (!g_bhide_depth_units) DrawEmboss(dc, EmbossDepthScale());
12622 if (!g_bhide_overzoom_flag) DrawEmboss(dc, EmbossOverzoomIndicator(dc));
12624 if (g_pi_manager) {
12625 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12630 RebuildTideSelectList(GetVP().GetBBox());
12631 DrawAllTidesInBBox(dc, GetVP().GetBBox());
12634 if (m_bShowCurrent) {
12635 RebuildCurrentSelectList(GetVP().GetBBox());
12636 DrawAllCurrentsInBBox(dc, GetVP().GetBBox());
12639 if (!g_PrintingInProgress) {
12640 if (IsPrimaryCanvas()) {
12641 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
12644 if (IsPrimaryCanvas()) {
12645 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
12648 if (m_muiBar) m_muiBar->DrawDC(dc, 1.0);
12650 if (m_pTrackRolloverWin) {
12651 m_pTrackRolloverWin->Draw(dc);
12652 m_brepaint_piano =
true;
12655 if (m_pRouteRolloverWin) {
12656 m_pRouteRolloverWin->Draw(dc);
12657 m_brepaint_piano =
true;
12660 if (m_pAISRolloverWin) {
12661 m_pAISRolloverWin->Draw(dc);
12662 m_brepaint_piano =
true;
12664 if (m_brepaint_piano && g_bShowChartBar) {
12665 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), dc);
12668 if (m_Compass) m_Compass->Paint(dc);
12670 if (!g_CanvasHideNotificationIcon) {
12671 auto ¬eman = NotificationManager::GetInstance();
12672 if (noteman.GetNotificationCount()) {
12673 m_notification_button->SetIconSeverity(noteman.GetMaxSeverity());
12674 if (m_notification_button->UpdateStatus()) Refresh();
12675 m_notification_button->Show(
true);
12676 m_notification_button->Paint(dc);
12678 m_notification_button->Show(
false);
12682 if (g_pi_manager) {
12683 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex,
12689 if (!m_bShowDepthUnits)
return NULL;
12691 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
12693 if (GetQuiltMode()) {
12694 wxString s = m_pQuilt->GetQuiltDepthUnit();
12697 depth_unit_type = DEPTH_UNIT_FEET;
12698 else if (s.StartsWith(
"FATHOMS"))
12699 depth_unit_type = DEPTH_UNIT_FATHOMS;
12700 else if (s.StartsWith(
"METERS"))
12701 depth_unit_type = DEPTH_UNIT_METERS;
12702 else if (s.StartsWith(
"METRES"))
12703 depth_unit_type = DEPTH_UNIT_METERS;
12704 else if (s.StartsWith(
"METRIC"))
12705 depth_unit_type = DEPTH_UNIT_METERS;
12706 else if (s.StartsWith(
"METER"))
12707 depth_unit_type = DEPTH_UNIT_METERS;
12710 if (m_singleChart) {
12711 depth_unit_type = m_singleChart->GetDepthUnitType();
12712 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
12713 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
12718 switch (depth_unit_type) {
12719 case DEPTH_UNIT_FEET:
12722 case DEPTH_UNIT_METERS:
12723 ped = m_pEM_Meters;
12725 case DEPTH_UNIT_FATHOMS:
12726 ped = m_pEM_Fathoms;
12732 ped->x = (GetVP().
pix_width - ped->width);
12734 if (m_Compass && m_bShowCompassWin && g_bShowCompassWin) {
12735 wxRect r = m_Compass->
GetRect();
12736 ped->y = r.y + r.height;
12743void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
12746 if (style->embossFont == wxEmptyString) {
12747 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12749 font.SetPointSize(60);
12750 font.SetWeight(wxFONTWEIGHT_BOLD);
12752 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12753 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12755 int emboss_width = 500;
12756 int emboss_height = 200;
12760 delete m_pEM_Meters;
12761 delete m_pEM_Fathoms;
12765 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12767 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12769 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12772#define OVERZOOM_TEXT _("OverZoom")
12774void ChartCanvas::SetOverzoomFont() {
12779 if (style->embossFont == wxEmptyString) {
12780 wxFont *dFont = FontMgr::Get().
GetFont(_(
"Dialog"), 0);
12782 font.SetPointSize(40);
12783 font.SetWeight(wxFONTWEIGHT_BOLD);
12785 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12786 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12788 wxClientDC dc(
this);
12790 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12792 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12793 font.SetPointSize(font.GetPointSize() - 1);
12795 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12797 m_overzoomFont = font;
12798 m_overzoomTextWidth = w;
12799 m_overzoomTextHeight = h;
12802void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12803 delete m_pEM_OverZoom;
12805 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12807 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12808 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12811emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12812 int height,
const wxString &str,
12817 wxBitmap bmp(width, height, -1);
12820 wxMemoryDC temp_dc;
12821 temp_dc.SelectObject(bmp);
12824 temp_dc.SetBackground(*wxWHITE_BRUSH);
12825 temp_dc.SetTextBackground(*wxWHITE);
12826 temp_dc.SetTextForeground(*wxBLACK);
12830 temp_dc.SetFont(font);
12833 temp_dc.GetTextExtent(str, &str_w, &str_h);
12835 temp_dc.DrawText(str, 1, 1);
12838 temp_dc.SelectObject(wxNullBitmap);
12841 wxImage img = bmp.ConvertToImage();
12843 int image_width = str_w * 105 / 100;
12844 int image_height = str_h * 105 / 100;
12845 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12846 wxMin(image_height, img.GetHeight()));
12847 wxImage imgs = img.GetSubImage(r);
12851 case GLOBAL_COLOR_SCHEME_DAY:
12855 case GLOBAL_COLOR_SCHEME_DUSK:
12858 case GLOBAL_COLOR_SCHEME_NIGHT:
12865 const int w = imgs.GetWidth();
12866 const int h = imgs.GetHeight();
12867 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12872 for (
int y = 1; y < h - 1; y++) {
12873 for (
int x = 1; x < w - 1; x++) {
12875 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12876 val = (int)(val * val_factor);
12877 index = (y * w) + x;
12890void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12891 Track *active_track = NULL;
12892 for (
Track *pTrackDraw : g_TrackList) {
12893 if (g_pActiveTrack == pTrackDraw) {
12894 active_track = pTrackDraw;
12898 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12901 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12904void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12905 Track *active_track = NULL;
12906 for (
Track *pTrackDraw : g_TrackList) {
12907 if (g_pActiveTrack == pTrackDraw) {
12908 active_track = pTrackDraw;
12912 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12915void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12916 Route *active_route = NULL;
12918 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12919 node = node->GetNext()) {
12920 Route *pRouteDraw = node->GetData();
12921 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12922 active_route = pRouteDraw;
12927 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12932 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12935void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12936 Route *active_route = NULL;
12938 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12939 node = node->GetNext()) {
12940 Route *pRouteDraw = node->GetData();
12941 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12942 active_route = pRouteDraw;
12946 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12949void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12950 if (!pWayPointMan)
return;
12952 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12958 node = node->GetNext();
12963 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12967 if (pWP->GetShowWaypointRangeRings() &&
12968 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12969 double factor = 1.00;
12970 if (pWP->GetWaypointRangeRingsStepUnits() ==
12972 factor = 1 / 1.852;
12974 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12975 pWP->GetWaypointRangeRingsStep() / 60.;
12979 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12980 pWP->m_lat + radius, pWP->m_lon + radius);
12981 if (!BltBBox.IntersectOut(radar_box)) {
12988 node = node->GetNext();
12992void ChartCanvas::DrawBlinkObjects(
void) {
12994 wxRect update_rect;
12996 if (!pWayPointMan)
return;
12998 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
13008 node = node->GetNext();
13010 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
13013void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
13016 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
13018 wxPoint lAnchorPoint1, lAnchorPoint2;
13021 if (pAnchorWatchPoint1) {
13022 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
13026 if (pAnchorWatchPoint2) {
13027 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
13032 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
13033 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
13035 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
13036 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
13037 dc.SetBrush(*ppBrush);
13041 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13046 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13051 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
13056 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
13061double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
13064 wxPoint lAnchorPoint;
13067 double tlat1, tlon1;
13069 if (pAnchorWatchPoint) {
13070 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
13071 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
13072 dabs = fabs(d1 / 1852.);
13073 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
13078 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
13079 pow((
double)(lAnchorPoint.y - r1.y), 2));
13082 if (d1 < 0) lpp = -lpp;
13090void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
13091 if (!ptcmgr)
return;
13093 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
13095 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13096 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13101 if ((type ==
't') || (type ==
'T')) {
13102 if (BBox.Contains(lat, lon)) {
13104 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
13110void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
13111 if (!ptcmgr)
return;
13113 wxDateTime this_now = gTimeSource;
13114 bool cur_time = !gTimeSource.IsValid();
13115 if (cur_time) this_now = wxDateTime::Now();
13116 time_t t_this_now = this_now.GetTicks();
13118 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13119 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13120 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
13121 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
13123 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
13124 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
13127 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
13128 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
13129 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
13130 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
13131 wxBRUSHSTYLE_SOLID);
13132 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
13133 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
13134 wxBRUSHSTYLE_SOLID);
13136 wxFont *dFont = FontMgr::Get().
GetFont(_(
"ExtendedTideIcon"));
13137 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
13138 int font_size = wxMax(10, dFont->GetPointSize());
13141 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13142 false, dFont->GetFaceName());
13144 dc.SetPen(*pblack_pen);
13145 dc.SetBrush(*pgreen_brush);
13149 case GLOBAL_COLOR_SCHEME_DAY:
13152 case GLOBAL_COLOR_SCHEME_DUSK:
13155 case GLOBAL_COLOR_SCHEME_NIGHT:
13156 bm = m_bmTideNight;
13163 int bmw = bm.GetWidth();
13164 int bmh = bm.GetHeight();
13166 float scale_factor = 1.0;
13170 float icon_pixelRefDim = 45;
13175 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
13177 float pix_factor = (1.5 * height) / icon_pixelRefDim;
13179 scale_factor *= pix_factor;
13181 float user_scale_factor = g_ChartScaleFactorExp;
13182 if (g_ChartScaleFactorExp > 1.0)
13183 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13186 scale_factor *= user_scale_factor;
13187 scale_factor *= GetContentScaleFactor();
13190 double marge = 0.05;
13191 std::vector<LLBBox> drawn_boxes;
13192 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13193 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13196 if ((type ==
't') || (type ==
'T'))
13201 if (BBox.ContainsMarge(lat, lon, marge)) {
13203 if (GetVP().chart_scale < 500000) {
13204 bool bdrawn =
false;
13205 for (
size_t i = 0; i < drawn_boxes.size(); i++) {
13206 if (drawn_boxes[i].Contains(lat, lon)) {
13211 if (bdrawn)
continue;
13214 this_box.Set(lat, lon, lat, lon);
13215 this_box.EnLarge(.005);
13216 drawn_boxes.push_back(this_box);
13222 if (GetVP().chart_scale > 500000) {
13223 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
13227 dc.SetFont(*plabelFont);
13239 if (ptcmgr->GetTideFlowSens(
13240 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13244 ptcmgr->GetHightOrLowTide(
13245 t_this_now + BACKWARD_TEN_MINUTES_STEP,
13246 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
13258 if (tctime > t_this_now)
13259 ptcmgr->GetHightOrLowTide(
13260 t_this_now, BACKWARD_TEN_MINUTES_STEP,
13261 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
13265 ptcmgr->GetHightOrLowTide(
13266 t_this_now, FORWARD_TEN_MINUTES_STEP,
13267 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->
IDX_rec_num,
13281 int width = (int)(12 * scale_factor + 0.5);
13282 int height = (int)(45 * scale_factor + 0.5);
13283 int linew = wxMax(1, (
int)(scale_factor));
13284 int xDraw = r.x - (width / 2);
13285 int yDraw = r.y - (height / 2);
13288 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
13289 int hs = (httime > lttime) ? -4 : 4;
13290 hs *= (int)(scale_factor + 0.5);
13291 if (ts > 0.995 || ts < 0.005) hs = 0;
13292 int ht_y = (int)(height * ts);
13295 pblack_pen->SetWidth(linew);
13296 dc.SetPen(*pblack_pen);
13297 dc.SetBrush(*pyelo_brush);
13298 dc.DrawRectangle(xDraw, yDraw, width, height);
13302 dc.SetPen(*pblue_pen);
13303 dc.SetBrush(*pblue_brush);
13304 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
13305 (width - (4 * linew)), height - ht_y);
13311 arrow[0].x = xDraw + 2 * linew;
13312 arrow[1].x = xDraw + width / 2;
13313 arrow[2].x = xDraw + width - 2 * linew;
13314 pyelo_pen->SetWidth(linew);
13315 pblue_pen->SetWidth(linew);
13316 if (ts > 0.35 || ts < 0.15)
13318 hl = (int)(height * 0.25) + yDraw;
13320 arrow[1].y = hl + hs;
13323 dc.SetPen(*pyelo_pen);
13325 dc.SetPen(*pblue_pen);
13326 dc.DrawLines(3, arrow);
13328 if (ts > 0.60 || ts < 0.40)
13330 hl = (int)(height * 0.5) + yDraw;
13332 arrow[1].y = hl + hs;
13335 dc.SetPen(*pyelo_pen);
13337 dc.SetPen(*pblue_pen);
13338 dc.DrawLines(3, arrow);
13340 if (ts < 0.65 || ts > 0.85)
13342 hl = (int)(height * 0.75) + yDraw;
13344 arrow[1].y = hl + hs;
13347 dc.SetPen(*pyelo_pen);
13349 dc.SetPen(*pblue_pen);
13350 dc.DrawLines(3, arrow);
13354 s.Printf(
"%3.1f", nowlev);
13356 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
13358 dc.GetTextExtent(s, &wx1, NULL);
13360 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
13375void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
13376 if (!ptcmgr)
return;
13378 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
13380 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13381 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13386 if (((type ==
'c') || (type ==
'C')) && (!pIDX->
b_skipTooDeep)) {
13387 if ((BBox.Contains(lat, lon))) {
13389 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
13395void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
13396 if (!ptcmgr)
return;
13398 float tcvalue, dir;
13402 double lon_last = 0.;
13403 double lat_last = 0.;
13405 double marge = 0.2;
13406 bool cur_time = !gTimeSource.IsValid();
13408 double true_scale_display = floor(VPoint.
chart_scale / 100.) * 100.;
13409 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
13411 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
13412 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
13413 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
13414 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
13416 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
13417 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
13418 wxBRUSHSTYLE_SOLID);
13419 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
13420 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
13421 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
13422 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
13424 double skew_angle = GetVPRotation();
13426 wxFont *dFont = FontMgr::Get().
GetFont(_(
"CurrentValue"));
13427 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
13428 int font_size = wxMax(10, dFont->GetPointSize());
13431 font_size, dFont->GetFamily(), dFont->GetStyle(), dFont->GetWeight(),
13432 false, dFont->GetFaceName());
13434 float scale_factor = 1.0;
13440 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
13442 float nominal_icon_size_pixels = 15;
13443 float pix_factor = (1 * height) / nominal_icon_size_pixels;
13445 scale_factor *= pix_factor;
13447 float user_scale_factor = g_ChartScaleFactorExp;
13448 if (g_ChartScaleFactorExp > 1.0)
13449 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
13452 scale_factor *= user_scale_factor;
13454 scale_factor *= GetContentScaleFactor();
13457 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
13458 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
13463 if (((type ==
'c') || (type ==
'C')) && (1 )) {
13464 if (!pIDX->
b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
13469 int dd = (int)(5.0 * scale_factor + 0.5);
13480 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13481 dc.SetPen(*pblack_pen);
13482 dc.SetBrush(*porange_brush);
13483 dc.DrawPolygon(4, d);
13486 dc.SetBrush(*pblack_brush);
13487 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
13491 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
13505 double a1 = fabs(tcvalue) * 10.;
13507 a1 = wxMax(1.0, a1);
13508 double a2 = log10(a1);
13510 float cscale = scale_factor * a2 * 0.3;
13512 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
13513 dc.SetPen(*porange_pen);
13514 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
13518 if (bDrawCurrentValues) {
13519 dc.SetFont(*pTCFont);
13520 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
13521 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
13547 if (!pvIDX)
return;
13552 if (pCwin && pCwin->IsShown()) {
13560 pCwin->RequestUserAttention(wxUSER_ATTENTION_INFO);
13575 pCwin =
new TCWin(
this, x, y, pvIDX);
13593#define NUM_CURRENT_ARROW_POINTS 9
13594static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
13595 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
13596 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
13597 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
13599void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
13601 if (
scale > 1e-2) {
13602 float sin_rot = sin(rot_angle * PI / 180.);
13603 float cos_rot = cos(rot_angle * PI / 180.);
13607 float xt = CurrentArrowArray[0].x;
13608 float yt = CurrentArrowArray[0].y;
13610 float xp = (xt * cos_rot) - (yt * sin_rot);
13611 float yp = (xt * sin_rot) + (yt * cos_rot);
13612 int x1 = (int)(xp *
scale);
13613 int y1 = (int)(yp *
scale);
13616 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
13617 xt = CurrentArrowArray[ip].x;
13618 yt = CurrentArrowArray[ip].y;
13620 float xp = (xt * cos_rot) - (yt * sin_rot);
13621 float yp = (xt * sin_rot) + (yt * cos_rot);
13622 int x2 = (int)(xp *
scale);
13623 int y2 = (int)(yp *
scale);
13625 dc.
DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
13633wxString ChartCanvas::FindValidUploadPort() {
13636 if (!g_uploadConnection.IsEmpty() &&
13637 g_uploadConnection.StartsWith(
"Serial")) {
13638 port = g_uploadConnection;
13644 for (
auto *cp : TheConnectionParams()) {
13645 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
13646 port <<
"Serial:" << cp->Port;
13652void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
13655 if (NULL == g_pais_query_dialog_active) {
13656 int pos_x = g_ais_query_dialog_x;
13657 int pos_y = g_ais_query_dialog_y;
13659 if (g_pais_query_dialog_active) {
13660 g_pais_query_dialog_active->Destroy();
13666 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
13667 wxPoint(pos_x, pos_y));
13669 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
13670 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
13671 g_pais_query_dialog_active->SetMMSI(mmsi);
13672 g_pais_query_dialog_active->UpdateText();
13673 wxSize sz = g_pais_query_dialog_active->GetSize();
13675 bool b_reset_pos =
false;
13680 RECT frame_title_rect;
13681 frame_title_rect.left = pos_x;
13682 frame_title_rect.top = pos_y;
13683 frame_title_rect.right = pos_x + sz.x;
13684 frame_title_rect.bottom = pos_y + 30;
13686 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
13687 b_reset_pos =
true;
13692 wxRect window_title_rect;
13693 window_title_rect.x = pos_x;
13694 window_title_rect.y = pos_y;
13695 window_title_rect.width = sz.x;
13696 window_title_rect.height = 30;
13698 wxRect ClientRect = wxGetClientDisplayRect();
13699 ClientRect.Deflate(
13701 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
13705 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
13708 g_pais_query_dialog_active->SetMMSI(mmsi);
13709 g_pais_query_dialog_active->UpdateText();
13712 g_pais_query_dialog_active->Show();
13715void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13716 bool cur_mode = GetQuiltMode();
13718 if (!GetQuiltMode())
13719 SetQuiltMode(
true);
13720 else if (GetQuiltMode()) {
13721 SetQuiltMode(
false);
13722 g_sticky_chart = GetQuiltReferenceChartIndex();
13725 if (cur_mode != GetQuiltMode()) {
13726 SetupCanvasQuiltMode();
13735 if (ps52plib) ps52plib->GenerateStateHash();
13737 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13738 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13741void ChartCanvas::DoCanvasStackDelta(
int direction) {
13742 if (!GetQuiltMode()) {
13743 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13744 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13745 if ((current_stack_index + direction) < 0)
return;
13747 if (m_bpersistent_quilt ) {
13749 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13751 if (IsChartQuiltableRef(new_dbIndex)) {
13752 ToggleCanvasQuiltMode();
13753 SelectQuiltRefdbChart(new_dbIndex);
13754 m_bpersistent_quilt =
false;
13757 SelectChartFromStack(current_stack_index + direction);
13760 std::vector<int> piano_chart_index_array =
13761 GetQuiltExtendedStackdbIndexArray();
13762 int refdb = GetQuiltRefChartdbIndex();
13765 int current_index = -1;
13766 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13767 if (refdb == piano_chart_index_array[i]) {
13772 if (current_index == -1)
return;
13775 int target_family = ctet.GetChartFamily();
13777 int new_index = -1;
13778 int check_index = current_index + direction;
13779 bool found =
false;
13780 int check_dbIndex = -1;
13781 int new_dbIndex = -1;
13785 (
unsigned int)check_index < piano_chart_index_array.size() &&
13786 (check_index >= 0)) {
13787 check_dbIndex = piano_chart_index_array[check_index];
13789 if (target_family == cte.GetChartFamily()) {
13791 new_index = check_index;
13792 new_dbIndex = check_dbIndex;
13796 check_index += direction;
13799 if (!found)
return;
13801 if (!IsChartQuiltableRef(new_dbIndex)) {
13802 ToggleCanvasQuiltMode();
13803 SelectdbChart(new_dbIndex);
13804 m_bpersistent_quilt =
true;
13806 SelectQuiltRefChart(new_index);
13810 gFrame->UpdateGlobalMenuItems();
13812 SetQuiltChartHiLiteIndex(-1);
13823void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13826 switch (event.GetId()) {
13838 DoCanvasStackDelta(1);
13843 DoCanvasStackDelta(-1);
13853 ShowCurrents(!GetbShowCurrent());
13860 ShowTides(!GetbShowTide());
13867 if (0 == m_routeState) {
13874 androidSetRouteAnnunciator(m_routeState == 1);
13880 SetAISCanvasDisplayStyle(-1);
13892void ChartCanvas::SetShowAIS(
bool show) {
13894 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13895 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13898void ChartCanvas::SetAttenAIS(
bool show) {
13899 m_bShowAISScaled = show;
13900 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13901 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13904void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13907 bool bShowAIS_Array[3] = {
true,
true,
false};
13908 bool bShowScaled_Array[3] = {
false,
true,
true};
13909 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13910 _(
"Attenuate less critical AIS targets"),
13911 _(
"Hide AIS Targets")};
13912 wxString iconName_Array[3] = {
"AIS",
"AIS_Suppressed",
"AIS_Disabled"};
13914 int AIS_Toolbar_Switch = 0;
13915 if (StyleIndx == -1) {
13917 for (
int i = 1; i < ArraySize; i++) {
13918 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13919 (bShowScaled_Array[i] == m_bShowAISScaled))
13920 AIS_Toolbar_Switch = i;
13922 AIS_Toolbar_Switch++;
13923 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13924 AIS_Toolbar_Switch++;
13927 AIS_Toolbar_Switch = StyleIndx;
13930 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13932 int AIS_Toolbar_Switch_Next =
13933 AIS_Toolbar_Switch + 1;
13934 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13935 AIS_Toolbar_Switch_Next++;
13936 if (AIS_Toolbar_Switch_Next >= ArraySize)
13937 AIS_Toolbar_Switch_Next = 0;
13940 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13941 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13944void ChartCanvas::TouchAISToolActive(
void) {}
13946void ChartCanvas::UpdateAISTBTool(
void) {}
13954void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13956 bool b_update =
false;
13957 int cc1_edge_comp = 2;
13958 wxRect rect = m_Compass->
GetRect();
13959 wxSize parent_size = GetSize();
13961 parent_size *= m_displayScale;
13965 wxPoint compass_pt(parent_size.x - rect.width - cc1_edge_comp,
13966 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13967 wxRect compass_rect(compass_pt, rect.GetSize());
13969 m_Compass->Move(compass_pt);
13971 if (m_Compass && m_Compass->IsShown())
13972 m_Compass->UpdateStatus(b_force_new | b_update);
13974 double scaler = g_Platform->GetCompassScaleFactor(g_GUIScaleFactor);
13975 scaler = wxMax(scaler, 1.0);
13976 wxPoint note_point = wxPoint(
13977 parent_size.x - (scaler * 20 * wxWindow::GetCharWidth()), compass_rect.y);
13978 m_notification_button->Move(note_point);
13979 m_notification_button->UpdateStatus();
13981 if (b_force_new | b_update) Refresh();
13984void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13985 ChartTypeEnum New_Type,
13986 ChartFamilyEnum New_Family) {
13987 if (!GetpCurrentStack())
return;
13990 if (index < GetpCurrentStack()->nEntry) {
13993 pTentative_Chart =
ChartData->OpenStackChartConditional(
13994 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13996 if (pTentative_Chart) {
13997 if (m_singleChart) m_singleChart->Deactivate();
13999 m_singleChart = pTentative_Chart;
14000 m_singleChart->Activate();
14002 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14003 GetpCurrentStack(), m_singleChart->GetFullPath());
14016 double best_scale_ppm = GetBestVPScale(m_singleChart);
14017 double rotation = GetVPRotation();
14018 double oldskew = GetVPSkew();
14019 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
14021 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
14022 if (fabs(oldskew) > 0.0001) rotation = 0.0;
14023 if (fabs(newskew) > 0.0001) rotation = newskew;
14026 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
14028 UpdateGPSCompassStatusBox(
true);
14032 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
14033 if (idx < 0)
return;
14035 std::vector<int> piano_active_chart_index_array;
14036 piano_active_chart_index_array.push_back(
14037 GetpCurrentStack()->GetCurrentEntrydbIndex());
14038 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14041void ChartCanvas::SelectdbChart(
int dbindex) {
14042 if (!GetpCurrentStack())
return;
14045 if (dbindex >= 0) {
14048 pTentative_Chart =
ChartData->OpenChartFromDB(dbindex, FULL_INIT);
14050 if (pTentative_Chart) {
14051 if (m_singleChart) m_singleChart->Deactivate();
14053 m_singleChart = pTentative_Chart;
14054 m_singleChart->Activate();
14056 GetpCurrentStack()->CurrentStackEntry =
ChartData->GetStackEntry(
14057 GetpCurrentStack(), m_singleChart->GetFullPath());
14070 double best_scale_ppm = GetBestVPScale(m_singleChart);
14074 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
14084void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
14087 if (!GetQuiltMode()) {
14088 if (GetpCurrentStack()) {
14089 int stack_index = -1;
14090 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
14091 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
14092 if (check_dbIndex < 0)
continue;
14094 ChartData->GetChartTableEntry(check_dbIndex);
14095 if (type == cte.GetChartType()) {
14098 }
else if (family == cte.GetChartFamily()) {
14104 if (stack_index >= 0) {
14105 SelectChartFromStack(stack_index);
14109 int sel_dbIndex = -1;
14110 std::vector<int> piano_chart_index_array =
14111 GetQuiltExtendedStackdbIndexArray();
14112 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
14113 int check_dbIndex = piano_chart_index_array[i];
14115 if (type == cte.GetChartType()) {
14116 if (IsChartQuiltableRef(check_dbIndex)) {
14117 sel_dbIndex = check_dbIndex;
14120 }
else if (family == cte.GetChartFamily()) {
14121 if (IsChartQuiltableRef(check_dbIndex)) {
14122 sel_dbIndex = check_dbIndex;
14128 if (sel_dbIndex >= 0) {
14129 SelectQuiltRefdbChart(sel_dbIndex,
false);
14131 AdjustQuiltRefChart();
14138 SetQuiltChartHiLiteIndex(-1);
14143bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
14144 return std::find(m_tile_yesshow_index_array.begin(),
14145 m_tile_yesshow_index_array.end(),
14146 index) != m_tile_yesshow_index_array.end();
14149bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
14150 return std::find(m_tile_noshow_index_array.begin(),
14151 m_tile_noshow_index_array.end(),
14152 index) != m_tile_noshow_index_array.end();
14155void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
14156 if (std::find(m_tile_noshow_index_array.begin(),
14157 m_tile_noshow_index_array.end(),
14158 index) == m_tile_noshow_index_array.end()) {
14159 m_tile_noshow_index_array.push_back(index);
14169void ChartCanvas::HandlePianoClick(
14170 int selected_index,
const std::vector<int> &selected_dbIndex_array) {
14171 if (g_options && g_options->IsShown())
14173 if (!m_pCurrentStack)
return;
14189 double distance = 25000;
14190 int closest_index = -1;
14191 for (
int chart_index : selected_dbIndex_array) {
14193 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
14194 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
14197 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
14198 if (test_distance < distance) {
14199 distance = test_distance;
14200 closest_index = chart_index;
14204 int selected_dbIndex = selected_dbIndex_array[0];
14205 if (closest_index >= 0) selected_dbIndex = closest_index;
14207 if (!GetQuiltMode()) {
14208 if (m_bpersistent_quilt ) {
14209 if (IsChartQuiltableRef(selected_dbIndex)) {
14210 ToggleCanvasQuiltMode();
14211 SelectQuiltRefdbChart(selected_dbIndex);
14212 m_bpersistent_quilt =
false;
14214 SelectChartFromStack(selected_index);
14217 SelectChartFromStack(selected_index);
14218 g_sticky_chart = selected_dbIndex;
14222 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
14226 if (CHART_TYPE_MBTILES ==
ChartData->GetDBChartType(selected_dbIndex)) {
14227 bool bfound =
false;
14228 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
14229 if (m_tile_noshow_index_array[i] ==
14230 selected_dbIndex) {
14231 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
14238 m_tile_noshow_index_array.push_back(selected_dbIndex);
14242 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
14243 m_tile_yesshow_index_array.push_back(selected_dbIndex);
14247 if (IsChartQuiltableRef(selected_dbIndex)) {
14253 bool set_scale =
false;
14254 if (CHART_TYPE_S57 ==
ChartData->GetDBChartType(selected_dbIndex)) {
14255 if (
ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
14261 SelectQuiltRefdbChart(selected_dbIndex,
true);
14263 SelectQuiltRefdbChart(selected_dbIndex,
false);
14268 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
14270 double proposed_scale_onscreen =
14273 if (g_bPreserveScaleOnX) {
14274 proposed_scale_onscreen =
14275 wxMin(proposed_scale_onscreen,
14277 GetCanvasWidth()));
14279 proposed_scale_onscreen =
14280 wxMin(proposed_scale_onscreen,
14282 GetCanvasWidth()));
14284 proposed_scale_onscreen =
14285 wxMax(proposed_scale_onscreen,
14294 ToggleCanvasQuiltMode();
14295 SelectdbChart(selected_dbIndex);
14296 m_bpersistent_quilt =
true;
14301 SetQuiltChartHiLiteIndex(-1);
14302 gFrame->UpdateGlobalMenuItems();
14304 HideChartInfoWindow();
14309void ChartCanvas::HandlePianoRClick(
14310 int x,
int y,
int selected_index,
14311 const std::vector<int> &selected_dbIndex_array) {
14312 if (g_options && g_options->IsShown())
14314 if (!GetpCurrentStack())
return;
14316 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
14317 UpdateCanvasControlBar();
14319 SetQuiltChartHiLiteIndex(-1);
14322void ChartCanvas::HandlePianoRollover(
14323 int selected_index,
const std::vector<int> &selected_dbIndex_array,
14324 int n_charts,
int scale) {
14325 if (g_options && g_options->IsShown())
14327 if (!GetpCurrentStack())
return;
14332 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
14334 if (!GetQuiltMode()) {
14335 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14338 std::vector<int> piano_chart_index_array;
14339 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
14340 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
14341 if ((GetpCurrentStack()->nEntry > 1) ||
14342 (piano_chart_index_array.size() >= 1)) {
14343 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14345 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14347 }
else if (GetpCurrentStack()->nEntry == 1) {
14349 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
14350 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
14351 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14353 }
else if ((-1 == selected_index) &&
14354 (0 == selected_dbIndex_array.size())) {
14355 ShowChartInfoWindow(key_location.x, -1);
14359 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
14361 if ((GetpCurrentStack()->nEntry > 1) ||
14362 (piano_chart_index_array.size() >= 1)) {
14364 ShowCompositeInfoWindow(key_location.x, n_charts,
scale,
14365 selected_dbIndex_array);
14366 else if (n_charts == 1)
14367 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
14369 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
14376void ChartCanvas::ClearPianoRollover() {
14377 ClearQuiltChartHiLiteIndexArray();
14378 ShowChartInfoWindow(0, -1);
14379 std::vector<int> vec;
14380 ShowCompositeInfoWindow(0, 0, 0, vec);
14384void ChartCanvas::UpdateCanvasControlBar(
void) {
14385 if (m_pianoFrozen)
return;
14387 if (!GetpCurrentStack())
return;
14389 if (!g_bShowChartBar)
return;
14392 int sel_family = -1;
14394 std::vector<int> piano_chart_index_array;
14395 std::vector<int> empty_piano_chart_index_array;
14397 wxString old_hash = m_Piano->GetStoredHash();
14399 if (GetQuiltMode()) {
14400 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
14401 GetQuiltFullScreendbIndexArray());
14403 std::vector<int> piano_active_chart_index_array =
14404 GetQuiltCandidatedbIndexArray();
14405 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
14407 std::vector<int> piano_eclipsed_chart_index_array =
14408 GetQuiltEclipsedStackdbIndexArray();
14409 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
14411 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
14412 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
14414 sel_type =
ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
14415 sel_family =
ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
14417 piano_chart_index_array =
ChartData->GetCSArray(GetpCurrentStack());
14418 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
14421 if (m_singleChart) {
14422 sel_type = m_singleChart->GetChartType();
14423 sel_family = m_singleChart->GetChartFamily();
14428 std::vector<int> piano_skew_chart_index_array;
14429 std::vector<int> piano_tmerc_chart_index_array;
14430 std::vector<int> piano_poly_chart_index_array;
14432 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14434 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14435 double skew_norm = ctei.GetChartSkew();
14436 if (skew_norm > 180.) skew_norm -= 360.;
14438 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
14439 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
14442 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
14443 if (fabs(skew_norm) > 1.)
14444 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14446 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
14447 }
else if (fabs(skew_norm) > 1.)
14448 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
14450 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
14451 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
14452 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
14454 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
14455 if (new_hash != old_hash) {
14456 m_Piano->FormatKeys();
14457 HideChartInfoWindow();
14458 m_Piano->ResetRollover();
14459 SetQuiltChartHiLiteIndex(-1);
14460 m_brepaint_piano =
true;
14466 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
14468 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
14469 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
14470 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
14471 if (e == CHART_FAMILY_RASTER) mask |= 1;
14472 if (e == CHART_FAMILY_VECTOR) {
14473 if (t == CHART_TYPE_CM93COMP)
14480 wxString s_indicated;
14481 if (sel_type == CHART_TYPE_CM93COMP)
14482 s_indicated =
"cm93";
14484 if (sel_family == CHART_FAMILY_RASTER)
14485 s_indicated =
"raster";
14486 else if (sel_family == CHART_FAMILY_VECTOR)
14487 s_indicated =
"vector";
14490 g_Platform->setChartTypeMaskSel(mask, s_indicated);
14493void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
14495void ChartCanvas::PianoPopupMenu(
14496 int x,
int y,
int selected_index,
14497 const std::vector<int> &selected_dbIndex_array) {
14498 if (!GetpCurrentStack())
return;
14501 if (!GetQuiltMode())
return;
14503 m_piano_ctx_menu =
new wxMenu();
14505 if (m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
14515 menu_selected_dbIndex = selected_dbIndex_array[0];
14516 menu_selected_index = selected_index;
14519 bool b_is_in_noshow =
false;
14520 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14521 if (m_quilt_noshow_index_array[i] ==
14522 menu_selected_dbIndex)
14524 b_is_in_noshow =
true;
14529 if (b_is_in_noshow) {
14530 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
14531 _(
"Show This Chart"));
14532 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14533 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
14534 }
else if (GetpCurrentStack()->nEntry > 1) {
14535 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
14536 _(
"Hide This Chart"));
14537 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
14538 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
14542 wxPoint pos = wxPoint(x, y - 30);
14545 if (m_piano_ctx_menu->GetMenuItems().GetCount())
14546 PopupMenu(m_piano_ctx_menu, pos);
14548 delete m_piano_ctx_menu;
14549 m_piano_ctx_menu = NULL;
14551 HideChartInfoWindow();
14552 m_Piano->ResetRollover();
14554 SetQuiltChartHiLiteIndex(-1);
14555 ClearQuiltChartHiLiteIndexArray();
14560void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
14561 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14562 if (m_quilt_noshow_index_array[i] ==
14563 menu_selected_dbIndex)
14565 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14571void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
14572 if (!GetpCurrentStack())
return;
14575 RemoveChartFromQuilt(menu_selected_dbIndex);
14579 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
14580 int type =
ChartData->GetDBChartType(menu_selected_dbIndex);
14582 int i = menu_selected_index + 1;
14583 bool b_success =
false;
14584 while (i < GetpCurrentStack()->nEntry - 1) {
14585 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14586 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14587 SelectQuiltRefChart(i);
14597 i = menu_selected_index - 1;
14599 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
14600 if (type ==
ChartData->GetDBChartType(dbIndex)) {
14601 SelectQuiltRefChart(i);
14611void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
14613 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
14614 if (m_quilt_noshow_index_array[i] ==
14617 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
14622 m_quilt_noshow_index_array.push_back(dbIndex);
14625bool ChartCanvas::UpdateS52State() {
14626 bool retval =
false;
14630 ps52plib->SetShowS57Text(m_encShowText);
14631 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
14632 ps52plib->m_bShowSoundg = m_encShowDepth;
14633 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
14634 ps52plib->m_bShowLdisText = m_encShowLightDesc;
14637 if (!m_encShowLights)
14638 ps52plib->AddObjNoshow(
"LIGHTS");
14640 ps52plib->RemoveObjNoshow(
"LIGHTS");
14641 ps52plib->SetLightsOff(!m_encShowLights);
14642 ps52plib->m_bExtendLightSectors =
true;
14645 ps52plib->SetAnchorOn(m_encShowAnchor);
14646 ps52plib->SetQualityOfData(m_encShowDataQual);
14652void ChartCanvas::SetShowENCDataQual(
bool show) {
14653 m_encShowDataQual = show;
14654 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14655 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14657 m_s52StateHash = 0;
14660void ChartCanvas::SetShowENCText(
bool show) {
14661 m_encShowText = show;
14662 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14663 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14665 m_s52StateHash = 0;
14668void ChartCanvas::SetENCDisplayCategory(
int category) {
14669 m_encDisplayCategory = category;
14670 m_s52StateHash = 0;
14673void ChartCanvas::SetShowENCDepth(
bool show) {
14674 m_encShowDepth = show;
14675 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14676 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14678 m_s52StateHash = 0;
14681void ChartCanvas::SetShowENCLightDesc(
bool show) {
14682 m_encShowLightDesc = show;
14683 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14684 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14686 m_s52StateHash = 0;
14689void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
14690 m_encShowBuoyLabels = show;
14691 m_s52StateHash = 0;
14694void ChartCanvas::SetShowENCLights(
bool show) {
14695 m_encShowLights = show;
14696 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14697 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14699 m_s52StateHash = 0;
14702void ChartCanvas::SetShowENCAnchor(
bool show) {
14703 m_encShowAnchor = show;
14704 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
14705 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
14707 m_s52StateHash = 0;
14710wxRect ChartCanvas::GetMUIBarRect() {
14713 rv = m_muiBar->GetRect();
14719void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14720 if (!GetAlertString().IsEmpty()) {
14721 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14722 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14724 dc.SetFont(*pfont);
14725 dc.SetPen(*wxTRANSPARENT_PEN);
14727 dc.SetBrush(wxColour(243, 229, 47));
14729 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14733 wxRect sbr = GetScaleBarRect();
14734 int xp = sbr.x + sbr.width + 10;
14735 int yp = (sbr.y + sbr.height) - h;
14737 int wdraw = w + 10;
14738 dc.DrawRectangle(xp, yp, wdraw, h);
14739 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14740 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14750#define BRIGHT_XCALIB
14751#define __OPCPN_USEICC__
14754#ifdef __OPCPN_USEICC__
14755int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14756 double co_green,
double co_blue);
14758wxString temp_file_name;
14762class ocpnCurtain:
public wxDialog
14764 DECLARE_CLASS( ocpnCurtain )
14765 DECLARE_EVENT_TABLE()
14768 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14770 bool ProcessEvent(wxEvent& event);
14774IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14776BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14779ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14781 wxDialog::Create( parent, -1,
"ocpnCurtain", position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14784ocpnCurtain::~ocpnCurtain()
14788bool ocpnCurtain::ProcessEvent(wxEvent& event)
14790 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14791 return GetParent()->GetEventHandler()->ProcessEvent(event);
14796#include <windows.h>
14799typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14800typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14801SetDeviceGammaRamp_ptr_type
14802 g_pSetDeviceGammaRamp;
14803GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14805WORD *g_pSavedGammaMap;
14809int InitScreenBrightness(
void) {
14812 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14816 if (NULL == hGDI32DLL) {
14817 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14819 if (NULL != hGDI32DLL) {
14821 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14822 hGDI32DLL,
"SetDeviceGammaRamp");
14823 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14824 hGDI32DLL,
"GetDeviceGammaRamp");
14827 if ((NULL == g_pSetDeviceGammaRamp) ||
14828 (NULL == g_pGetDeviceGammaRamp)) {
14829 FreeLibrary(hGDI32DLL);
14838 if (!g_pSavedGammaMap) {
14839 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14842 bbr = g_pGetDeviceGammaRamp(
14843 hDC, g_pSavedGammaMap);
14844 ReleaseDC(NULL, hDC);
14849 wxRegKey *pRegKey =
new wxRegKey(
14850 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows "
14851 "NT\\CurrentVersion\\ICM");
14852 if (!pRegKey->Exists()) pRegKey->Create();
14853 pRegKey->SetValue(
"GdiIcmGammaRange", 256);
14855 g_brightness_init =
true;
14861 if (NULL == g_pcurtain) {
14862 if (gFrame->CanSetTransparent()) {
14864 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1,
"",
14865 wxPoint(0, 0), ::wxGetDisplaySize(),
14866 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14867 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14874 g_pcurtain->Hide();
14876 HWND hWnd = GetHwndOf(g_pcurtain);
14877 SetWindowLong(hWnd, GWL_EXSTYLE,
14878 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14879 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14880 g_pcurtain->SetTransparent(0);
14882 g_pcurtain->Maximize();
14883 g_pcurtain->Show();
14886 g_pcurtain->Enable();
14887 g_pcurtain->Disable();
14894 g_brightness_init =
true;
14900 wxString cmd(_T (
"xcalib -version" ));
14902 wxArrayString output;
14903 long r = wxExecute(cmd, output);
14906 " External application \"xcalib\" not found. Screen brightness "
14909 g_brightness_init =
true;
14914int RestoreScreenBrightness(
void) {
14917 if (g_pSavedGammaMap) {
14918 HDC hDC = GetDC(NULL);
14919 g_pSetDeviceGammaRamp(hDC,
14921 ReleaseDC(NULL, hDC);
14923 free(g_pSavedGammaMap);
14924 g_pSavedGammaMap = NULL;
14928 g_pcurtain->Close();
14929 g_pcurtain->Destroy();
14933 g_brightness_init =
false;
14938#ifdef BRIGHT_XCALIB
14939 if (g_brightness_init) {
14941 cmd =
"xcalib -clear";
14942 wxExecute(cmd, wxEXEC_ASYNC);
14943 g_brightness_init =
false;
14953int SetScreenBrightness(
int brightness) {
14960 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14962 g_pcurtain->Close();
14963 g_pcurtain->Destroy();
14967 InitScreenBrightness();
14969 if (NULL == hGDI32DLL) {
14971 wchar_t wdll_name[80];
14972 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14973 LPCWSTR cstr = wdll_name;
14975 hGDI32DLL = LoadLibrary(cstr);
14977 if (NULL != hGDI32DLL) {
14979 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14980 hGDI32DLL,
"SetDeviceGammaRamp");
14981 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14982 hGDI32DLL,
"GetDeviceGammaRamp");
14985 if ((NULL == g_pSetDeviceGammaRamp) ||
14986 (NULL == g_pGetDeviceGammaRamp)) {
14987 FreeLibrary(hGDI32DLL);
14994 HDC hDC = GetDC(NULL);
15005 int increment = brightness * 256 / 100;
15008 WORD GammaTable[3][256];
15011 for (
int i = 0; i < 256; i++) {
15012 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
15013 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
15014 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
15016 table_val += increment;
15018 if (table_val > 65535) table_val = 65535;
15021 g_pSetDeviceGammaRamp(hDC, GammaTable);
15022 ReleaseDC(NULL, hDC);
15029 if (g_pSavedGammaMap) {
15030 HDC hDC = GetDC(NULL);
15031 g_pSetDeviceGammaRamp(hDC,
15033 ReleaseDC(NULL, hDC);
15036 if (brightness < 100) {
15037 if (NULL == g_pcurtain) InitScreenBrightness();
15040 int sbrite = wxMax(1, brightness);
15041 sbrite = wxMin(100, sbrite);
15043 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
15047 g_pcurtain->Close();
15048 g_pcurtain->Destroy();
15058#ifdef BRIGHT_XCALIB
15060 if (!g_brightness_init) {
15061 last_brightness = 100;
15062 g_brightness_init =
true;
15063 temp_file_name = wxFileName::CreateTempFileName(
"");
15064 InitScreenBrightness();
15067#ifdef __OPCPN_USEICC__
15070 if (!CreateSimpleICCProfileFile(
15071 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
15072 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
15073 wxString cmd(_T (
"xcalib " ));
15074 cmd += temp_file_name;
15076 wxExecute(cmd, wxEXEC_ASYNC);
15085 if (brightness > last_brightness) {
15087 cmd =
"xcalib -clear";
15088 wxExecute(cmd, wxEXEC_ASYNC);
15090 ::wxMilliSleep(10);
15092 int brite_adj = wxMax(1, brightness);
15093 cmd.Printf(
"xcalib -co %2d -a", brite_adj);
15094 wxExecute(cmd, wxEXEC_ASYNC);
15096 int brite_adj = wxMax(1, brightness);
15097 int factor = (brite_adj * 100) / last_brightness;
15098 factor = wxMax(1, factor);
15100 cmd.Printf(
"xcalib -co %2d -a", factor);
15101 wxExecute(cmd, wxEXEC_ASYNC);
15106 last_brightness = brightness;
15113#ifdef __OPCPN_USEICC__
15115#define MLUT_TAG 0x6d4c5554L
15116#define VCGT_TAG 0x76636774L
15118int GetIntEndian(
unsigned char *s) {
15123 p = (
unsigned char *)&ret;
15126 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
15128 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
15133unsigned short GetShortEndian(
unsigned char *s) {
15134 unsigned short ret;
15138 p = (
unsigned char *)&ret;
15141 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
15143 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
15149int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
15150 double co_green,
double co_blue) {
15154 fp = fopen(file_name,
"wb");
15155 if (!fp)
return -1;
15161 for (
int i = 0; i < 128; i++) header[i] = 0;
15163 fwrite(header, 128, 1, fp);
15167 int numTags = GetIntEndian((
unsigned char *)&numTags0);
15168 fwrite(&numTags, 1, 4, fp);
15170 int tagName0 = VCGT_TAG;
15171 int tagName = GetIntEndian((
unsigned char *)&tagName0);
15172 fwrite(&tagName, 1, 4, fp);
15174 int tagOffset0 = 128 + 4 *
sizeof(int);
15175 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
15176 fwrite(&tagOffset, 1, 4, fp);
15179 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
15180 fwrite(&tagSize, 1, 4, fp);
15182 fwrite(&tagName, 1, 4, fp);
15184 fwrite(&tagName, 1, 4, fp);
15189 int gammatype0 = 0;
15190 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
15191 fwrite(&gammatype, 1, 4, fp);
15193 int numChannels0 = 3;
15194 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
15195 fwrite(&numChannels, 1, 2, fp);
15197 int numEntries0 = 256;
15198 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
15199 fwrite(&numEntries, 1, 2, fp);
15201 int entrySize0 = 1;
15202 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
15203 fwrite(&entrySize, 1, 2, fp);
15205 unsigned char ramp[256];
15208 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
15209 fwrite(ramp, 256, 1, fp);
15212 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
15213 fwrite(ramp, 256, 1, fp);
15216 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
15217 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)
Gets 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)
Hooks into gui available in model.
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.