27 #include <wx/wxprec.h>
33 #include <wx/graphics.h>
34 #include <wx/clipbrd.h>
35 #include <wx/aui/aui.h>
39 #include <wx/listimpl.cpp>
41 #include "model/ais_decoder.h"
43 #include "model/ais_target_data.h"
45 #include "model/conn_params.h"
46 #include "model/cutil.h"
47 #include "model/geodesic.h"
48 #include "model/idents.h"
49 #include "model/multiplexer.h"
50 #include "model/nav_object_database.h"
51 #include "model/navutil_base.h"
52 #include "model/own_ship.h"
53 #include "model/route.h"
54 #include "model/routeman.h"
55 #include "model/select.h"
56 #include "model/select_item.h"
57 #include "model/track.h"
58 #include "model/wx28compat.h"
61 #include "AISTargetAlertDialog.h"
62 #include "CanvasConfig.h"
63 #include "canvasMenu.h"
64 #include "CanvasOptions.h"
68 #include "ChInfoWin.h"
74 #include "glTextureDescriptor.h"
76 #include "iENCToolbar.h"
78 #include "line_clip.h"
83 #include "OCPN_AUIManager.h"
85 #include "ocpn_frame.h"
86 #include "ocpn_pixel.h"
87 #include "OCPNRegion.h"
89 #include "pluginmanager.h"
91 #include "route_gui.h"
92 #include "routemanagerdialog.h"
93 #include "route_point_gui.h"
94 #include "RoutePropDlgImpl.h"
98 #include "SendToGpsDlg.h"
99 #include "shapefile_basemap.h"
101 #include "SystemCmdSound.h"
104 #include "thumbwin.h"
105 #include "tide_time.h"
108 #include "track_gui.h"
109 #include "TrackPropDlg.h"
113 #include "androidUTIL.h"
117 #include "glChartCanvas.h"
121 #define _CRTDBG_MAP_ALLOC
124 #define DEBUG_NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)
125 #define new DEBUG_NEW
134 extern float g_ShipScaleFactorExp;
135 extern double g_mouse_zoom_sensitivity;
139 #if defined(__MSVC__) && (_MSC_VER < 1700)
140 #define trunc(d) ((d > 0) ? floor(d) : ceil(d))
146 #define OCPN_ALT_MENUBAR 1
154 extern bool G_FloatPtInPolygon(
MyFlPoint *rgpts,
int wnumpts,
float x,
float y);
155 extern void catch_signals(
int signo);
157 extern void AlphaBlending(
ocpnDC &dc,
int x,
int y,
int size_x,
int size_y,
158 float radius, wxColour color,
159 unsigned char transparency);
161 extern double g_ChartNotRenderScaleFactor;
163 extern bool bDBUpdateInProgress;
164 extern ColorScheme global_color_scheme;
165 extern int g_nbrightness;
170 extern RouteList *pRouteList;
171 extern std::vector<Track*> g_TrackList;
175 extern TCMgr *ptcmgr;
182 extern double AnchorPointMinDist;
183 extern bool AnchorAlertOn1;
184 extern bool AnchorAlertOn2;
189 extern wxString GetLayerName(
int id);
190 extern wxString g_uploadConnection;
191 extern bool g_bsimplifiedScalebar;
193 extern bool bDrawCurrentValues;
195 extern s52plib *ps52plib;
197 extern bool g_bTempShowMenuBar;
198 extern bool g_bShowMenuBar;
199 extern bool g_bShowCompassWin;
203 extern int g_iNavAidRadarRingsNumberVisible;
204 extern bool g_bNavAidRadarRingsShown;
205 extern float g_fNavAidRadarRingsStep;
206 extern int g_pNavAidRadarRingsStepUnits;
207 extern bool g_bWayPointPreventDragging;
208 extern bool g_bEnableZoomToCursor;
209 extern bool g_bShowChartBar;
210 extern int g_ENCSoundingScaleFactor;
211 extern int g_ENCTextScaleFactor;
212 extern int g_maxzoomin;
214 bool g_bShowShipToActive;
215 int g_shipToActiveStyle;
216 int g_shipToActiveColor;
220 extern int g_S57_dialog_sx, g_S57_dialog_sy;
223 extern int g_detailslider_dialog_x, g_detailslider_dialog_y;
225 extern bool g_b_overzoom_x;
226 extern double g_plus_minus_zoom_factor;
228 extern int g_OwnShipIconType;
229 extern double g_n_ownship_length_meters;
230 extern double g_n_ownship_beam_meters;
231 extern double g_n_gps_antenna_offset_y;
232 extern double g_n_gps_antenna_offset_x;
233 extern int g_n_ownship_min_mm;
235 extern double g_COGAvg;
237 extern int g_click_stop;
239 extern double g_ownship_predictor_minutes;
240 extern int g_cog_predictor_style;
241 extern wxString g_cog_predictor_color;
242 extern int g_cog_predictor_endmarker;
243 extern int g_ownship_HDTpredictor_style;
244 extern wxString g_ownship_HDTpredictor_color;
245 extern int g_ownship_HDTpredictor_endmarker;
246 extern int g_ownship_HDTpredictor_width;
247 extern double g_ownship_HDTpredictor_miles;
249 extern bool g_bquiting;
256 extern bool g_bopengl;
258 extern bool g_bFullScreenQuilt;
260 extern bool g_bsmoothpanzoom;
264 extern bool g_b_assume_azerty;
266 extern ChartGroupArray *g_pGroupArray;
271 extern OcpnSound *g_anchorwatch_sound;
273 extern bool g_bresponsive;
274 extern int g_chart_zoom_modifier_raster;
275 extern int g_chart_zoom_modifier_vector;
276 extern int g_ChartScaleFactor;
282 extern double g_gl_ms_per_frame;
283 extern bool g_benable_rotate;
284 extern bool g_bRollover;
286 extern bool g_bSpaceDropMark;
287 extern bool g_bAutoHideToolbar;
288 extern int g_nAutoHideToolbar;
289 extern bool g_bDeferredInitDone;
291 extern wxString g_CmdSoundString;
292 extern bool g_boptionsactive;
299 static bool mouse_leftisdown;
301 bool g_brouteCreating;
303 bool g_bShowTrackPointTime;
309 bool g_brightness_init;
312 int g_cog_predictor_width;
313 extern double g_display_size_mm;
317 extern wxColour g_colourOwnshipRangeRingsColour;
321 extern double g_defaultBoatSpeed;
322 double g_defaultBoatSpeedUserUnit;
324 extern int g_nAIS_activity_timer;
325 extern bool g_bskew_comp;
326 extern float g_compass_scalefactor;
327 extern int g_COGAvgSec;
329 wxGLContext *g_pGLcontext;
331 extern bool g_useMUI;
332 extern unsigned int g_canvasConfig;
333 extern wxString g_lastPluginMessage;
338 extern float g_toolbar_scalefactor;
341 wxString g_ObjQFileExt;
344 wxDialog *g_pcurtain;
346 extern int g_GUIScaleFactor;
349 wxString g_lastS52PLIBPluginMessage;
350 extern bool g_bChartBarEx;
351 bool g_PrintingInProgress;
353 #define MIN_BRIGHT 10
354 #define MAX_BRIGHT 100
360 EVT_PAINT(ChartCanvas::OnPaint)
361 EVT_ACTIVATE(ChartCanvas::OnActivate)
362 EVT_SIZE(ChartCanvas::OnSize)
363 #ifndef HAVE_WX_GESTURE_EVENTS
364 EVT_MOUSE_EVENTS(ChartCanvas::MouseEvent)
366 EVT_TIMER(DBLCLICK_TIMER, ChartCanvas::MouseTimedEvent)
367 EVT_TIMER(PAN_TIMER, ChartCanvas::PanTimerEvent)
368 EVT_TIMER(MOVEMENT_TIMER, ChartCanvas::MovementTimerEvent)
369 EVT_TIMER(MOVEMENT_STOP_TIMER, ChartCanvas::MovementStopTimerEvent)
370 EVT_TIMER(CURTRACK_TIMER, ChartCanvas::OnCursorTrackTimerEvent)
371 EVT_TIMER(ROT_TIMER, ChartCanvas::RotateTimerEvent)
372 EVT_TIMER(ROPOPUP_TIMER, ChartCanvas::OnRolloverPopupTimerEvent)
373 EVT_TIMER(ROUTEFINISH_TIMER, ChartCanvas::OnRouteFinishTimerEvent)
374 EVT_KEY_DOWN(ChartCanvas::OnKeyDown)
375 EVT_KEY_UP(ChartCanvas::OnKeyUp)
376 EVT_CHAR(ChartCanvas::OnKeyChar)
377 EVT_MOUSE_CAPTURE_LOST(ChartCanvas::LostMouseCapture)
378 EVT_KILL_FOCUS(ChartCanvas::OnKillFocus)
379 EVT_SET_FOCUS(ChartCanvas::OnSetFocus)
380 EVT_MENU(-1, ChartCanvas::OnToolLeftClick)
381 EVT_TIMER(DEFERRED_FOCUS_TIMER, ChartCanvas::OnDeferredFocusTimerEvent)
387 : wxWindow(frame, wxID_ANY, wxPoint(20, 20), wxSize(5, 5), wxNO_BORDER) {
388 parent_frame = (
MyFrame *)frame;
389 m_canvasIndex = canvasIndex;
393 SetBackgroundColour(wxColour(0, 0, 0));
394 SetBackgroundStyle(wxBG_STYLE_CUSTOM);
398 m_bDrawingRoute =
false;
399 m_bRouteEditing =
false;
400 m_bMarkEditing =
false;
401 m_bRoutePoinDragging =
false;
402 m_bIsInRadius =
false;
403 m_bMayToggleMenuBar =
true;
406 m_bShowNavobjects =
true;
408 m_bAppendingRoute =
false;
409 pThumbDIBShow = NULL;
410 m_bShowCurrent =
false;
412 bShowingCurrent =
false;
416 m_b_paint_enable =
true;
419 pss_overlay_bmp = NULL;
420 pss_overlay_mask = NULL;
421 m_bChartDragging =
false;
422 m_bMeasure_Active =
false;
423 m_bMeasure_DistCircle =
false;
424 m_pMeasureRoute = NULL;
425 m_pTrackRolloverWin = NULL;
426 m_pRouteRolloverWin = NULL;
427 m_pAISRolloverWin = NULL;
429 m_disable_edge_pan =
false;
430 m_dragoffsetSet =
false;
434 m_singleChart = NULL;
435 m_upMode = NORTH_UP_MODE;
437 m_bShowAISScaled =
false;
444 m_pSelectedRoute = NULL;
445 m_pSelectedTrack = NULL;
446 m_pRoutePointEditTarget = NULL;
447 m_pFoundPoint = NULL;
448 m_pMouseRoute = NULL;
449 m_prev_pMousePoint = NULL;
450 m_pEditRouteArray = NULL;
451 m_pFoundRoutePoint = NULL;
452 m_FinishRouteOnKillFocus =
true;
454 m_pRolloverRouteSeg = NULL;
455 m_pRolloverTrackSeg = NULL;
456 m_bsectors_shown =
false;
458 m_bbrightdir =
false;
463 m_pos_image_user_day = NULL;
464 m_pos_image_user_dusk = NULL;
465 m_pos_image_user_night = NULL;
466 m_pos_image_user_grey_day = NULL;
467 m_pos_image_user_grey_dusk = NULL;
468 m_pos_image_user_grey_night = NULL;
471 m_rotation_speed = 0;
477 m_pos_image_user_yellow_day = NULL;
478 m_pos_image_user_yellow_dusk = NULL;
479 m_pos_image_user_yellow_night = NULL;
481 SetOwnShipState(SHIP_INVALID);
483 undo =
new Undo(
this);
489 m_focus_indicator_pix = 1;
491 m_pCurrentStack = NULL;
492 m_bpersistent_quilt =
false;
493 m_piano_ctx_menu = NULL;
496 g_ChartNotRenderScaleFactor = 2.0;
497 m_bShowScaleInStatusBar =
true;
500 m_bShowScaleInStatusBar =
false;
502 m_bShowOutlines =
false;
503 m_bDisplayGrid =
false;
504 m_bShowDepthUnits =
true;
505 m_encDisplayCategory = (int)STANDARD;
507 m_encShowLights =
true;
508 m_encShowAnchor =
true;
509 m_encShowDataQual =
false;
511 m_pQuilt =
new Quilt(
this);
513 SetAlertString(_T(
""));
516 g_PrintingInProgress =
false;
518 #ifdef HAVE_WX_GESTURE_EVENTS
519 m_oldVPSScale = -1.0;
520 m_popupWanted =
false;
526 singleClickEventIsValid =
false;
535 pCursorPencil = NULL;
540 SetCursor(*pCursorArrow);
542 pPanTimer =
new wxTimer(
this, m_MouseDragging);
545 pMovementTimer =
new wxTimer(
this, MOVEMENT_TIMER);
546 pMovementTimer->Stop();
548 pMovementStopTimer =
new wxTimer(
this, MOVEMENT_STOP_TIMER);
549 pMovementStopTimer->Stop();
551 pRotDefTimer =
new wxTimer(
this, ROT_TIMER);
552 pRotDefTimer->Stop();
554 m_DoubleClickTimer =
new wxTimer(
this, DBLCLICK_TIMER);
555 m_DoubleClickTimer->Stop();
560 pCurTrackTimer =
new wxTimer(
this, CURTRACK_TIMER);
561 pCurTrackTimer->Stop();
562 m_curtrack_timer_msec = 10;
564 m_wheelzoom_stop_oneshot = 0;
565 m_last_wheel_dir = 0;
567 m_RolloverPopupTimer.SetOwner(
this, ROPOPUP_TIMER);
569 m_deferredFocusTimer.SetOwner(
this, DEFERRED_FOCUS_TIMER);
571 m_rollover_popup_timer_msec = 20;
573 m_routeFinishTimer.SetOwner(
this, ROUTEFINISH_TIMER);
575 m_b_rot_hidef =
true;
580 m_upMode = NORTH_UP_MODE;
581 m_bLookAhead =
false;
586 m_cs = GLOBAL_COLOR_SCHEME_DAY;
589 VPoint.view_scale_ppm = 1;
593 m_canvas_scale_factor = 1.;
595 m_canvas_width = 1000;
597 m_overzoomTextWidth = 0;
598 m_overzoomTextHeight = 0;
602 gShapeBasemap.Reset();
607 m_pEM_Fathoms = NULL;
609 CreateDepthUnitEmbossMaps(GLOBAL_COLOR_SCHEME_DAY);
611 m_pEM_OverZoom = NULL;
613 CreateOZEmbossMapData(GLOBAL_COLOR_SCHEME_DAY);
617 m_bmTideDay = style->GetIconScaled(_T(
"tidesml"), 1. / g_Platform->GetDisplayDIPMult(
this));
620 m_bmTideDusk = CreateDimBitmap(m_bmTideDay, .50);
623 m_bmTideNight = CreateDimBitmap(m_bmTideDay, .20);
626 double factor_dusk = 0.5;
627 double factor_night = 0.25;
630 m_os_image_red_day = style->GetIcon(_T(
"ship-red")).ConvertToImage();
632 int rimg_width = m_os_image_red_day.GetWidth();
633 int rimg_height = m_os_image_red_day.GetHeight();
635 m_os_image_red_dusk = m_os_image_red_day.Copy();
636 m_os_image_red_night = m_os_image_red_day.Copy();
638 for (
int iy = 0; iy < rimg_height; iy++) {
639 for (
int ix = 0; ix < rimg_width; ix++) {
640 if (!m_os_image_red_day.IsTransparent(ix, iy)) {
641 wxImage::RGBValue rgb(m_os_image_red_day.GetRed(ix, iy),
642 m_os_image_red_day.GetGreen(ix, iy),
643 m_os_image_red_day.GetBlue(ix, iy));
644 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
645 hsv.value = hsv.value * factor_dusk;
646 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
647 m_os_image_red_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
649 hsv = wxImage::RGBtoHSV(rgb);
650 hsv.value = hsv.value * factor_night;
651 nrgb = wxImage::HSVtoRGB(hsv);
652 m_os_image_red_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
658 m_os_image_grey_day =
659 style->GetIcon(_T(
"ship-red")).ConvertToImage().ConvertToGreyscale();
661 int gimg_width = m_os_image_grey_day.GetWidth();
662 int gimg_height = m_os_image_grey_day.GetHeight();
664 m_os_image_grey_dusk = m_os_image_grey_day.Copy();
665 m_os_image_grey_night = m_os_image_grey_day.Copy();
667 for (
int iy = 0; iy < gimg_height; iy++) {
668 for (
int ix = 0; ix < gimg_width; ix++) {
669 if (!m_os_image_grey_day.IsTransparent(ix, iy)) {
670 wxImage::RGBValue rgb(m_os_image_grey_day.GetRed(ix, iy),
671 m_os_image_grey_day.GetGreen(ix, iy),
672 m_os_image_grey_day.GetBlue(ix, iy));
673 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
674 hsv.value = hsv.value * factor_dusk;
675 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
676 m_os_image_grey_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
678 hsv = wxImage::RGBtoHSV(rgb);
679 hsv.value = hsv.value * factor_night;
680 nrgb = wxImage::HSVtoRGB(hsv);
681 m_os_image_grey_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
687 m_os_image_yellow_day = m_os_image_red_day.Copy();
689 gimg_width = m_os_image_yellow_day.GetWidth();
690 gimg_height = m_os_image_yellow_day.GetHeight();
692 m_os_image_yellow_dusk = m_os_image_red_day.Copy();
693 m_os_image_yellow_night = m_os_image_red_day.Copy();
695 for (
int iy = 0; iy < gimg_height; iy++) {
696 for (
int ix = 0; ix < gimg_width; ix++) {
697 if (!m_os_image_yellow_day.IsTransparent(ix, iy)) {
698 wxImage::RGBValue rgb(m_os_image_yellow_day.GetRed(ix, iy),
699 m_os_image_yellow_day.GetGreen(ix, iy),
700 m_os_image_yellow_day.GetBlue(ix, iy));
701 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
702 hsv.hue += 60. / 360.;
703 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
704 m_os_image_yellow_day.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
706 hsv = wxImage::RGBtoHSV(rgb);
707 hsv.value = hsv.value * factor_dusk;
708 hsv.hue += 60. / 360.;
709 nrgb = wxImage::HSVtoRGB(hsv);
710 m_os_image_yellow_dusk.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
712 hsv = wxImage::RGBtoHSV(rgb);
713 hsv.hue += 60. / 360.;
714 hsv.value = hsv.value * factor_night;
715 nrgb = wxImage::HSVtoRGB(hsv);
716 m_os_image_yellow_night.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
722 m_pos_image_red = &m_os_image_red_day;
723 m_pos_image_yellow = &m_os_image_yellow_day;
724 m_pos_image_grey = &m_os_image_grey_day;
728 m_pBrightPopup = NULL;
731 if (!g_bdisable_opengl) m_pQuilt->EnableHighDefinitionZoom(
true);
734 int gridFontSize = 8;
735 #if defined(__WXOSX__) || defined(__WXGTK3__)
737 gridFontSize *= GetContentScaleFactor();
740 m_pgridFont = FontMgr::Get().FindOrCreateFont(
741 gridFontSize, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, FALSE,
742 wxString(_T (
"Arial" )));
744 m_Piano =
new Piano(
this);
746 m_bShowCompassWin = g_bShowCompassWin;
749 m_Compass->SetScaleFactor(g_compass_scalefactor);
750 m_Compass->Show(m_bShowCompassWin);
752 m_pianoFrozen =
false;
754 SetMinSize(wxSize(200, 200));
756 m_displayScale = 1.0;
757 #if defined(__WXOSX__) || defined(__WXGTK3__)
759 m_displayScale = GetContentScaleFactor();
763 #ifdef HAVE_WX_GESTURE_EVENTS
764 if (!EnableTouchEvents(wxTOUCH_ZOOM_GESTURE |
765 wxTOUCH_PRESS_GESTURES)) {
766 wxLogError(
"Failed to enable touch events");
769 Bind(wxEVT_GESTURE_ZOOM, &ChartCanvas::OnZoom,
this);
771 Bind(wxEVT_LONG_PRESS, &ChartCanvas::OnLongPress,
this);
772 Bind(wxEVT_PRESS_AND_TAP, &ChartCanvas::OnPressAndTap,
this);
774 Bind(wxEVT_RIGHT_UP, &ChartCanvas::OnRightUp,
this);
775 Bind(wxEVT_RIGHT_DOWN, &ChartCanvas::OnRightDown,
this);
777 Bind(wxEVT_LEFT_UP, &ChartCanvas::OnLeftUp,
this);
778 Bind(wxEVT_LEFT_DOWN, &ChartCanvas::OnLeftDown,
this);
780 Bind(wxEVT_MOUSEWHEEL, &ChartCanvas::OnWheel,
this);
781 Bind(wxEVT_MOTION, &ChartCanvas::OnMotion,
this);
785 ChartCanvas::~ChartCanvas() {
786 delete pThumbDIBShow;
794 delete pCursorPencil;
798 delete pMovementTimer;
799 delete pMovementStopTimer;
800 delete pCurTrackTimer;
802 delete m_DoubleClickTimer;
804 delete m_pTrackRolloverWin;
805 delete m_pRouteRolloverWin;
806 delete m_pAISRolloverWin;
807 delete m_pBrightPopup;
813 m_dc_route.SelectObject(wxNullBitmap);
816 delete pWorldBackgroundChart;
817 delete pss_overlay_bmp;
821 delete m_pEM_Fathoms;
823 delete m_pEM_OverZoom;
828 delete m_pos_image_user_day;
829 delete m_pos_image_user_dusk;
830 delete m_pos_image_user_night;
831 delete m_pos_image_user_grey_day;
832 delete m_pos_image_user_grey_dusk;
833 delete m_pos_image_user_grey_night;
834 delete m_pos_image_user_yellow_day;
835 delete m_pos_image_user_yellow_dusk;
836 delete m_pos_image_user_yellow_night;
840 if (!g_bdisable_opengl) {
843 #if wxCHECK_VERSION(2, 9, 0)
844 if (IsPrimaryCanvas() && g_bopengl)
delete g_pGLcontext;
851 MUIBar *muiBar = m_muiBar;
855 delete m_pCurrentStack;
860 void ChartCanvas::RebuildCursors() {
866 delete pCursorPencil;
870 double cursorScale = exp(g_GUIScaleFactor * (0.693 / 5.0));
872 double pencilScale = 1.0 / g_Platform->GetDisplayDIPMult(gFrame);
874 wxImage ICursorLeft = style->GetIcon(_T(
"left")).ConvertToImage();
875 wxImage ICursorRight = style->GetIcon(_T(
"right")).ConvertToImage();
876 wxImage ICursorUp = style->GetIcon(_T(
"up")).ConvertToImage();
877 wxImage ICursorDown = style->GetIcon(_T(
"down")).ConvertToImage();
878 wxImage ICursorPencil = style->GetIconScaled(_T(
"pencil"), pencilScale).ConvertToImage();
879 wxImage ICursorCross = style->GetIcon(_T(
"cross")).ConvertToImage();
881 #if !defined(__WXMSW__) && !defined(__WXQT__)
882 ICursorLeft.ConvertAlphaToMask(128);
883 ICursorRight.ConvertAlphaToMask(128);
884 ICursorUp.ConvertAlphaToMask(128);
885 ICursorDown.ConvertAlphaToMask(128);
886 ICursorPencil.ConvertAlphaToMask(10);
887 ICursorCross.ConvertAlphaToMask(10);
890 if (ICursorLeft.Ok()) {
891 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0);
892 ICursorLeft.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
893 pCursorLeft =
new wxCursor(ICursorLeft);
895 pCursorLeft =
new wxCursor(wxCURSOR_ARROW);
897 if (ICursorRight.Ok()) {
898 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 31);
899 ICursorRight.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15);
900 pCursorRight =
new wxCursor(ICursorRight);
902 pCursorRight =
new wxCursor(wxCURSOR_ARROW);
904 if (ICursorUp.Ok()) {
905 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
906 ICursorUp.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 0);
907 pCursorUp =
new wxCursor(ICursorUp);
909 pCursorUp =
new wxCursor(wxCURSOR_ARROW);
911 if (ICursorDown.Ok()) {
912 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 15);
913 ICursorDown.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 31);
914 pCursorDown =
new wxCursor(ICursorDown);
916 pCursorDown =
new wxCursor(wxCURSOR_ARROW);
918 if (ICursorPencil.Ok()) {
919 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0 * pencilScale);
920 ICursorPencil.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 16 * pencilScale);
921 pCursorPencil =
new wxCursor(ICursorPencil);
923 pCursorPencil =
new wxCursor(wxCURSOR_ARROW);
925 if (ICursorCross.Ok()) {
926 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 13);
927 ICursorCross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 12);
928 pCursorCross =
new wxCursor(ICursorCross);
930 pCursorCross =
new wxCursor(wxCURSOR_ARROW);
932 pCursorArrow =
new wxCursor(wxCURSOR_ARROW);
933 pPlugIn_Cursor = NULL;
936 void ChartCanvas::CanvasApplyLocale() {
937 CreateDepthUnitEmbossMaps(m_cs);
938 CreateOZEmbossMapData(m_cs);
941 void ChartCanvas::SetupGlCanvas() {
944 if (!g_bdisable_opengl) {
946 wxLogMessage(_T(
"Creating glChartCanvas"));
951 if (IsPrimaryCanvas()) {
958 wxGLContext *pctx =
new wxGLContext(m_glcc);
959 m_glcc->SetContext(pctx);
963 m_glcc->SetContext(
new wxGLContext(m_glcc, g_pGLcontext));
965 m_glcc->SetContext(g_pGLcontext);
975 if (!g_bdisable_opengl) {
978 wxLogMessage(_T(
"Creating glChartCanvas"));
982 if (IsPrimaryCanvas()) {
983 qDebug() <<
"Creating Primary glChartCanvas";
991 wxGLContext *pctx =
new wxGLContext(m_glcc);
992 m_glcc->SetContext(pctx);
994 m_glcc->m_pParentCanvas =
this;
997 qDebug() <<
"Creating Secondary glChartCanvas";
1003 gFrame, gFrame->GetPrimaryCanvas()->GetglCanvas());
1006 wxGLContext *pwxctx =
new wxGLContext(m_glcc);
1007 m_glcc->SetContext(pwxctx);
1008 m_glcc->m_pParentCanvas =
this;
1016 void ChartCanvas::OnKillFocus(wxFocusEvent &WXUNUSED(event)) {
1017 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1032 if (m_routeState && m_FinishRouteOnKillFocus)
1033 m_routeFinishTimer.Start(20, wxTIMER_ONE_SHOT);
1035 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1039 void ChartCanvas::OnSetFocus(wxFocusEvent &WXUNUSED(event)) {
1040 m_routeFinishTimer.Stop();
1044 gFrame->UpdateGlobalMenuItems(
this);
1046 RefreshRect(wxRect(0, 0, GetClientSize().x, m_focus_indicator_pix),
false);
1049 void ChartCanvas::OnRouteFinishTimerEvent(wxTimerEvent &event) {
1050 if (m_routeState && m_FinishRouteOnKillFocus) FinishRoute();
1053 #ifdef HAVE_WX_GESTURE_EVENTS
1054 void ChartCanvas::OnLongPress(wxLongPressEvent &event) {
1060 m_popupWanted =
true;
1063 void ChartCanvas::OnPressAndTap(wxPressAndTapEvent &event) {
1067 void ChartCanvas::OnRightUp(wxMouseEvent &event) { MouseEvent(event); }
1069 void ChartCanvas::OnRightDown(wxMouseEvent &event) { MouseEvent(event); }
1071 void ChartCanvas::OnLeftUp(wxMouseEvent &event) {
1072 wxPoint pos =
event.GetPosition();
1076 if (!m_popupWanted) {
1077 wxMouseEvent ev(wxEVT_LEFT_UP);
1084 m_popupWanted =
false;
1086 wxMouseEvent ev(wxEVT_RIGHT_DOWN);
1093 void ChartCanvas::OnLeftDown(wxMouseEvent &event) {
1096 wxPoint pos =
event.GetPosition();
1100 void ChartCanvas::OnMotion(wxMouseEvent &event) {
1105 event.m_leftDown = m_leftdown;
1109 void ChartCanvas::OnZoom(wxZoomGestureEvent &event) {
1111 if (event.IsGestureEnd())
return;
1113 double factor =
event.GetZoomFactor();
1115 if (event.IsGestureStart() || m_oldVPSScale < 0) {
1116 m_oldVPSScale = GetVPScale();
1119 double current_vps = GetVPScale();
1120 double wanted_factor = m_oldVPSScale / current_vps * factor;
1122 ZoomCanvas(wanted_factor,
true,
false);
1125 if (event.IsGestureStart()) {
1126 m_zoomStartPoint =
event.GetPosition();
1128 wxPoint delta =
event.GetPosition() - m_zoomStartPoint;
1129 PanCanvas(-delta.x, -delta.y);
1130 m_zoomStartPoint =
event.GetPosition();
1134 void ChartCanvas::OnWheel(wxMouseEvent &event) { MouseEvent(event); }
1136 void ChartCanvas::OnDoubleLeftClick(wxMouseEvent &event) {
1137 DoRotateCanvas(0.0);
1141 void ChartCanvas::ApplyCanvasConfig(
canvasConfig *pcc) {
1142 SetViewPoint(pcc->iLat, pcc->iLon, pcc->iScale, 0., pcc->iRotation);
1146 m_restore_dbindex = pcc->DBindex;
1147 m_bFollow = pcc->bFollow;
1148 if (pcc->GroupID < 0) pcc->GroupID = 0;
1150 if (pcc->GroupID > (
int)g_pGroupArray->GetCount())
1153 m_groupIndex = pcc->GroupID;
1155 if (pcc->bQuilt != GetQuiltMode()) ToggleCanvasQuiltMode();
1157 ShowTides(pcc->bShowTides);
1158 ShowCurrents(pcc->bShowCurrents);
1160 SetShowDepthUnits(pcc->bShowDepthUnits);
1161 SetShowGrid(pcc->bShowGrid);
1162 SetShowOutlines(pcc->bShowOutlines);
1164 SetShowAIS(pcc->bShowAIS);
1165 SetAttenAIS(pcc->bAttenAIS);
1168 SetShowENCText(pcc->bShowENCText);
1169 m_encDisplayCategory = pcc->nENCDisplayCategory;
1170 m_encShowDepth = pcc->bShowENCDepths;
1171 m_encShowLightDesc = pcc->bShowENCLightDescriptions;
1172 m_encShowBuoyLabels = pcc->bShowENCBuoyLabels;
1173 m_encShowLights = pcc->bShowENCLights;
1174 m_bShowVisibleSectors = pcc->bShowENCVisibleSectorLights;
1175 m_encShowAnchor = pcc->bShowENCAnchorInfo;
1176 m_encShowDataQual = pcc->bShowENCDataQuality;
1178 bool courseUp = pcc->bCourseUp;
1179 bool headUp = pcc->bHeadUp;
1180 m_upMode = NORTH_UP_MODE;
1182 m_upMode = COURSE_UP_MODE;
1184 m_upMode = HEAD_UP_MODE;
1186 m_bLookAhead = pcc->bLookahead;
1188 m_singleChart = NULL;
1191 void ChartCanvas::ApplyGlobalSettings() {
1193 m_bShowCompassWin = g_bShowCompassWin;
1195 m_Compass->Show(m_bShowCompassWin);
1196 if (m_bShowCompassWin) m_Compass->UpdateStatus();
1200 void ChartCanvas::CheckGroupValid(
bool showMessage,
bool switchGroup0) {
1201 bool groupOK = CheckGroup(m_groupIndex);
1204 SetGroupIndex(m_groupIndex,
true);
1208 void ChartCanvas::SetShowGPS(
bool bshow) {
1209 if (m_bShowGPS != bshow) {
1212 m_Compass->SetScaleFactor(g_compass_scalefactor);
1213 m_Compass->Show(m_bShowCompassWin);
1218 void ChartCanvas::SetShowGPSCompassWindow(
bool bshow) {
1220 m_Compass->Show(m_bShowCompassWin);
1221 if (m_bShowCompassWin) m_Compass->UpdateStatus();
1225 int ChartCanvas::GetPianoHeight() {
1227 if (g_bShowChartBar && GetPiano()) height = m_Piano->GetHeight();
1232 void ChartCanvas::ConfigureChartBar() {
1235 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
1236 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
1238 if (GetQuiltMode()) {
1239 m_Piano->SetRoundedRectangles(
true);
1241 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
1242 m_Piano->SetPolyIcon(
new wxBitmap(style->GetIcon(_T(
"polyprj"))));
1243 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
1246 void ChartCanvas::ShowTides(
bool bShow) {
1247 gFrame->LoadHarmonics();
1249 if (ptcmgr->IsReady()) {
1250 SetbShowTide(bShow);
1252 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES, bShow);
1254 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1255 SetbShowTide(
false);
1256 parent_frame->SetMenubarItemState(ID_MENU_SHOW_TIDES,
false);
1259 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1260 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1271 void ChartCanvas::ShowCurrents(
bool bShow) {
1272 gFrame->LoadHarmonics();
1274 if (ptcmgr->IsReady()) {
1275 SetbShowCurrent(bShow);
1276 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS, bShow);
1278 wxLogMessage(_T(
"Chart1::Event...TCMgr Not Available"));
1279 SetbShowCurrent(
false);
1280 parent_frame->SetMenubarItemState(ID_MENU_SHOW_CURRENTS,
false);
1283 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
1284 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
1296 extern bool g_bPreserveScaleOnX;
1298 extern int g_sticky_chart;
1300 void ChartCanvas::canvasRefreshGroupIndex(
void) { SetGroupIndex(m_groupIndex); }
1302 void ChartCanvas::SetGroupIndex(
int index,
bool autoSwitch) {
1303 SetAlertString(_T(
""));
1305 int new_index = index;
1306 if (index > (
int)g_pGroupArray->GetCount()) new_index = 0;
1308 bool bgroup_override =
false;
1309 int old_group_index = new_index;
1311 if (!CheckGroup(new_index)) {
1313 bgroup_override =
true;
1316 if (!autoSwitch && (index <= (
int)g_pGroupArray->GetCount()))
1320 int current_chart_native_scale = GetCanvasChartNativeScale();
1323 m_groupIndex = new_index;
1326 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
1329 if (m_muiBar) m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
1333 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1337 g_sticky_chart = -1;
1341 UpdateCanvasOnGroupChange();
1344 if (GetQuiltMode()) dbi_now = GetQuiltReferenceChartIndex();
1346 int dbi_hint = FindClosestCanvasChartdbIndex(current_chart_native_scale);
1349 if ((dbi_now != dbi_hint) || !GetQuiltMode()) {
1350 double best_scale = GetBestStartScale(dbi_hint, vp);
1351 SetVPScale(best_scale);
1354 if (GetQuiltMode()) dbi_hint = GetQuiltReferenceChartIndex();
1358 canvasChartsRefresh(dbi_hint);
1360 UpdateCanvasControlBar();
1362 if (!autoSwitch && bgroup_override) {
1364 wxString msg(_(
"Group \""));
1366 ChartGroup *pGroup = g_pGroupArray->Item(new_index - 1);
1367 msg += pGroup->m_group_name;
1369 msg += _(
"\" is empty.");
1371 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxICON_INFORMATION, 2);
1378 if (bgroup_override) {
1379 wxString msg(_(
"Group \""));
1381 ChartGroup *pGroup = g_pGroupArray->Item(old_group_index - 1);
1382 msg += pGroup->m_group_name;
1384 msg += _(
"\" is empty, switching to \"All Active Charts\" group.");
1386 OCPNMessageBox(
this, msg, _(
"OpenCPN Group Notice"), wxOK, 5);
1390 bool ChartCanvas::CheckGroup(
int igroup) {
1391 if (!ChartData)
return true;
1393 if (igroup == 0)
return true;
1398 ChartGroup *pGroup = g_pGroupArray->Item(igroup - 1);
1400 if (pGroup->m_element_array.empty())
1404 for (
const auto &elem : pGroup->m_element_array) {
1405 for (
unsigned int ic = 0;
1406 ic < (
unsigned int)ChartData->GetChartTableEntries(); ic++) {
1408 wxString chart_full_path(pcte->GetpFullPath(), wxConvUTF8);
1410 if (chart_full_path.StartsWith(elem.m_element_name))
return true;
1415 for (
const auto &elem : pGroup->m_element_array) {
1416 const wxString &element_root = elem.m_element_name;
1417 wxString test_string = _T(
"GSHH");
1418 if (element_root.Upper().Contains(test_string))
return true;
1424 void ChartCanvas::canvasChartsRefresh(
int dbi_hint) {
1425 if (!ChartData)
return;
1427 AbstractPlatform::ShowBusySpinner();
1429 double old_scale = GetVPScale();
1431 SetQuiltRefChart(-1);
1433 m_singleChart = NULL;
1439 if (!m_pCurrentStack) {
1441 ChartData->BuildChartStack(m_pCurrentStack, m_vLat, m_vLon, m_groupIndex);
1444 if (-1 != dbi_hint) {
1445 if (GetQuiltMode()) {
1446 GetpCurrentStack()->SetCurrentEntryFromdbIndex(dbi_hint);
1447 SetQuiltRefChart(dbi_hint);
1451 pTentative_Chart = ChartData->OpenChartFromDB(dbi_hint, FULL_INIT);
1453 if (pTentative_Chart) {
1456 if (m_singleChart) m_singleChart->Deactivate();
1458 m_singleChart = pTentative_Chart;
1459 m_singleChart->Activate();
1461 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
1462 GetpCurrentStack(), m_singleChart->GetFullPath());
1470 GetpCurrentStack()->CurrentStackEntry = GetpCurrentStack()->nEntry - 1;
1471 int selected_index = GetpCurrentStack()->GetCurrentEntrydbIndex();
1472 SetQuiltRefChart(selected_index);
1476 SetupCanvasQuiltMode();
1477 if (!GetQuiltMode() && m_singleChart == 0) {
1479 if (NULL == pDummyChart) pDummyChart =
new ChartDummy;
1480 m_singleChart = pDummyChart;
1481 SetVPScale(old_scale);
1486 UpdateCanvasControlBar();
1487 UpdateGPSCompassStatusBox(
true);
1489 SetCursor(wxCURSOR_ARROW);
1491 AbstractPlatform::HideBusySpinner();
1494 bool ChartCanvas::DoCanvasUpdate(
void) {
1496 double vpLat, vpLon;
1498 bool bNewChart =
false;
1499 bool bNewView =
false;
1500 bool bCanvasChartAutoOpen =
true;
1502 bool bNewPiano =
false;
1503 bool bOpenSpecified;
1509 if (bDBUpdateInProgress)
return false;
1510 if (!ChartData)
return false;
1512 if (ChartData->IsBusy())
return false;
1538 double dx = m_OSoffsetx;
1539 double dy = m_OSoffsety;
1540 double d_east = dx / GetVP().view_scale_ppm;
1541 double d_north = dy / GetVP().view_scale_ppm;
1543 if (GetUpMode() == NORTH_UP_MODE) {
1544 fromSM(d_east, d_north, gLat, gLon, &vpLat, &vpLon);
1546 double offset_angle = atan2(d_north, d_east);
1547 double offset_distance = sqrt((d_north * d_north) + (d_east * d_east));
1548 double chart_angle = GetVPRotation();
1549 double target_angle = chart_angle + offset_angle;
1550 double d_east_mod = offset_distance * cos(target_angle);
1551 double d_north_mod = offset_distance * sin(target_angle);
1552 fromSM(d_east_mod, d_north_mod, gLat, gLon, &vpLat, &vpLon);
1556 if (m_bLookAhead && bGPSValid && !m_MouseDragging) {
1557 double angle = g_COGAvg + (GetVPRotation() * 180. / PI);
1559 double pixel_deltay =
1560 fabs(cos(angle * PI / 180.)) * GetCanvasHeight() / 4;
1561 double pixel_deltax = fabs(sin(angle * PI / 180.)) * GetCanvasWidth() / 4;
1563 double pixel_delta_tent =
1564 sqrt((pixel_deltay * pixel_deltay) + (pixel_deltax * pixel_deltax));
1566 double pixel_delta = 0;
1571 if (!std::isnan(gSog)) {
1574 else if (gSog >= 3.0)
1575 pixel_delta = pixel_delta_tent;
1577 pixel_delta = pixel_delta_tent * (gSog - 1.0) / 2.0;
1580 double meters_to_shift =
1581 cos(gLat * PI / 180.) * pixel_delta / GetVPScale();
1583 double dir_to_shift = g_COGAvg;
1585 ll_gc_ll(gLat, gLon, dir_to_shift, meters_to_shift / 1852., &vpLat,
1587 }
else if (m_bLookAhead && !bGPSValid) {
1601 if (GetQuiltMode()) {
1602 int current_db_index = -1;
1603 if (m_pCurrentStack)
1606 ->GetCurrentEntrydbIndex();
1614 if (m_bautofind && (-1 == GetQuiltReferenceChartIndex()) &&
1616 if (m_pCurrentStack->nEntry) {
1617 int new_dbIndex = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry -
1619 SelectQuiltRefdbChart(new_dbIndex,
true);
1620 m_bautofind =
false;
1624 ChartData->BuildChartStack(m_pCurrentStack, tLat, tLon, m_groupIndex);
1625 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
1630 ChartData->CheckExclusiveTileGroup(m_canvasIndex);
1632 double proposed_scale_onscreen =
1633 GetCanvasScaleFactor() / GetVPScale();
1635 int initial_db_index = m_restore_dbindex;
1636 if (initial_db_index < 0) {
1637 if (m_pCurrentStack->nEntry) {
1639 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
1644 if (m_pCurrentStack->nEntry) {
1645 int initial_type = ChartData->GetDBChartType(initial_db_index);
1650 if (!IsChartQuiltableRef(initial_db_index)) {
1654 int stack_index = 0;
1656 if (stack_index >= 0) {
1657 while ((stack_index < m_pCurrentStack->nEntry - 1)) {
1658 int test_db_index = m_pCurrentStack->GetDBIndex(stack_index);
1659 if (IsChartQuiltableRef(test_db_index) &&
1661 ChartData->GetDBChartType(initial_db_index))) {
1662 initial_db_index = test_db_index;
1670 ChartBase *pc = ChartData->OpenChartFromDB(initial_db_index, FULL_INIT);
1672 SetQuiltRefChart(initial_db_index);
1673 m_pCurrentStack->SetCurrentEntryFromdbIndex(initial_db_index);
1677 bNewView |= SetViewPoint(vpLat, vpLon,
1678 GetCanvasScaleFactor() / proposed_scale_onscreen,
1679 0, GetVPRotation());
1682 bNewView |= SetViewPoint(vpLat, vpLon, GetVPScale(), 0, GetVPRotation());
1688 pLast_Ch = m_singleChart;
1689 ChartTypeEnum new_open_type;
1690 ChartFamilyEnum new_open_family;
1692 new_open_type = pLast_Ch->GetChartType();
1693 new_open_family = pLast_Ch->GetChartFamily();
1695 new_open_type = CHART_TYPE_KAP;
1696 new_open_family = CHART_FAMILY_RASTER;
1699 bOpenSpecified = m_bFirstAuto;
1702 if (NULL == m_pCurrentStack) m_pCurrentStack =
new ChartStack;
1705 if (0 == ChartData->BuildChartStack(&WorkStack, tLat, tLon, g_sticky_chart,
1707 if (NULL == pDummyChart) {
1713 if (m_singleChart->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1715 m_singleChart = pDummyChart;
1719 double set_scale = GetVPScale();
1720 if (!GetVP().IsValid()) set_scale = 1. / 20000.;
1722 bNewView |= SetViewPoint(tLat, tLon, set_scale, 0, GetVPRotation());
1725 if (WorkStack.nEntry && m_pCurrentStack->nEntry) {
1726 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1733 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1739 if (!ChartData->EqualStacks(&WorkStack, m_pCurrentStack)) {
1744 ChartData->CopyStack(&LastStack, m_pCurrentStack);
1747 ChartData->CopyStack(m_pCurrentStack, &WorkStack);
1752 if (NULL != m_singleChart)
1753 tEntry = ChartData->GetStackEntry(m_pCurrentStack,
1754 m_singleChart->GetFullPath());
1757 m_pCurrentStack->CurrentStackEntry = tEntry;
1767 if (bCanvasChartAutoOpen) {
1768 bool search_direction =
1770 int start_index = 0;
1774 if ((LastStack.CurrentStackEntry == LastStack.nEntry - 1) ||
1775 (LastStack.nEntry == 0)) {
1776 search_direction =
true;
1777 start_index = m_pCurrentStack->nEntry - 1;
1781 if (bOpenSpecified) {
1782 search_direction =
false;
1784 if ((start_index < 0) | (start_index >= m_pCurrentStack->nEntry))
1787 new_open_type = CHART_TYPE_DONTCARE;
1790 pProposed = ChartData->OpenStackChartConditional(
1791 m_pCurrentStack, start_index, search_direction, new_open_type,
1795 if (NULL == pProposed)
1796 pProposed = ChartData->OpenStackChartConditional(
1797 m_pCurrentStack, start_index, search_direction,
1798 CHART_TYPE_CM93COMP, CHART_FAMILY_VECTOR);
1800 if (NULL == pProposed)
1801 pProposed = ChartData->OpenStackChartConditional(
1802 m_pCurrentStack, start_index, search_direction,
1803 CHART_TYPE_CM93COMP, CHART_FAMILY_RASTER);
1814 if (NULL == pProposed) {
1815 if (NULL == pDummyChart) {
1821 if (pLast_Ch->GetChartType() != CHART_TYPE_DUMMY) bNewChart =
true;
1823 pProposed = pDummyChart;
1827 if (m_singleChart) m_singleChart->Deactivate();
1828 m_singleChart = pProposed;
1830 if (m_singleChart) {
1831 m_singleChart->Activate();
1832 m_pCurrentStack->CurrentStackEntry = ChartData->GetStackEntry(
1833 m_pCurrentStack, m_singleChart->GetFullPath());
1838 if (NULL != m_singleChart) {
1840 double set_scale = GetVPScale();
1844 if (!GetVP().IsValid())
1845 set_scale = 1. / 20000.;
1847 double proposed_scale_onscreen;
1850 double new_scale_ppm =
1851 m_singleChart->GetNearestPreferredScalePPM(GetVPScale());
1852 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
1854 proposed_scale_onscreen = GetCanvasScaleFactor() / set_scale;
1859 if (bNewChart && !g_bPreserveScaleOnX && !bOpenSpecified) {
1860 proposed_scale_onscreen = m_singleChart->GetNativeScale() / 2;
1861 double equivalent_vp_scale =
1862 GetCanvasScaleFactor() / proposed_scale_onscreen;
1863 double new_scale_ppm =
1864 m_singleChart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1865 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
1869 proposed_scale_onscreen =
1870 wxMin(proposed_scale_onscreen,
1871 m_singleChart->GetNormalScaleMax(GetCanvasScaleFactor(),
1873 proposed_scale_onscreen =
1874 wxMax(proposed_scale_onscreen,
1875 m_singleChart->GetNormalScaleMin(GetCanvasScaleFactor(),
1879 set_scale = GetCanvasScaleFactor() / proposed_scale_onscreen;
1882 bNewView |= SetViewPoint(vpLat, vpLon, set_scale,
1883 m_singleChart->GetChartSkew() * PI / 180.,
1890 if ((m_bFollow) && m_singleChart)
1891 bNewView |= SetViewPoint(vpLat, vpLon, GetVPScale(),
1892 m_singleChart->GetChartSkew() * PI / 180.,
1902 if (pthumbwin && pthumbwin->IsShown()) {
1903 if (pthumbwin->pThumbChart) {
1904 if (pthumbwin->pThumbChart->UpdateThumbData(gLat, gLon))
1905 pthumbwin->Refresh(TRUE);
1909 m_bFirstAuto =
false;
1913 if (bNewChart && !bNewView) Refresh(
false);
1918 if (m_glcc && g_bopengl && bNewChart) GetglCanvas()->Invalidate();
1921 return bNewChart | bNewView;
1924 void ChartCanvas::SelectQuiltRefdbChart(
int db_index,
bool b_autoscale) {
1925 if (m_pCurrentStack) m_pCurrentStack->SetCurrentEntryFromdbIndex(db_index);
1927 SetQuiltRefChart(db_index);
1929 ChartBase *pc = ChartData->OpenChartFromDB(db_index, FULL_INIT);
1932 double best_scale_ppm = GetBestVPScale(pc);
1933 SetVPScale(best_scale_ppm);
1936 SetQuiltRefChart(-1);
1938 SetQuiltRefChart(-1);
1941 void ChartCanvas::SelectQuiltRefChart(
int selected_index) {
1942 std::vector<int> piano_chart_index_array =
1943 GetQuiltExtendedStackdbIndexArray();
1944 int current_db_index = piano_chart_index_array[selected_index];
1946 SelectQuiltRefdbChart(current_db_index);
1949 double ChartCanvas::GetBestVPScale(
ChartBase *pchart) {
1951 double proposed_scale_onscreen = GetCanvasScaleFactor() / GetVPScale();
1953 if ((g_bPreserveScaleOnX) ||
1954 (CHART_TYPE_CM93COMP == pchart->GetChartType())) {
1955 double new_scale_ppm = GetVPScale();
1956 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
1960 proposed_scale_onscreen = pchart->GetNativeScale() / 2;
1961 double equivalent_vp_scale =
1962 GetCanvasScaleFactor() / proposed_scale_onscreen;
1963 double new_scale_ppm =
1964 pchart->GetNearestPreferredScalePPM(equivalent_vp_scale);
1965 proposed_scale_onscreen = GetCanvasScaleFactor() / new_scale_ppm;
1971 double max_underzoom_multiplier = 2.0;
1972 if (GetVP().b_quilt) {
1973 double scale_max = m_pQuilt->GetNomScaleMin(pchart->GetNativeScale(),
1974 pchart->GetChartType(),
1975 pchart->GetChartFamily());
1976 max_underzoom_multiplier = scale_max / pchart->GetNativeScale();
1979 proposed_scale_onscreen = wxMin(
1980 proposed_scale_onscreen,
1981 pchart->GetNormalScaleMax(GetCanvasScaleFactor(), GetCanvasWidth()) *
1982 max_underzoom_multiplier);
1985 proposed_scale_onscreen =
1986 wxMax(proposed_scale_onscreen,
1987 pchart->GetNormalScaleMin(GetCanvasScaleFactor(),
false));
1989 return GetCanvasScaleFactor() / proposed_scale_onscreen;
1994 void ChartCanvas::SetupCanvasQuiltMode(
void) {
1997 ChartData->LockCache();
1999 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
2003 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2004 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2005 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2006 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2008 m_Piano->SetRoundedRectangles(
true);
2011 int target_new_dbindex = -1;
2012 if (m_pCurrentStack) {
2013 target_new_dbindex =
2014 GetQuiltReferenceChartIndex();
2016 if (-1 != target_new_dbindex) {
2017 if (!IsChartQuiltableRef(target_new_dbindex)) {
2018 int proj = ChartData->GetDBChartProj(target_new_dbindex);
2019 int type = ChartData->GetDBChartType(target_new_dbindex);
2022 int stack_index = m_pCurrentStack->CurrentStackEntry;
2024 while ((stack_index < m_pCurrentStack->nEntry - 1) &&
2025 (stack_index >= 0)) {
2026 int proj_tent = ChartData->GetDBChartProj(
2027 m_pCurrentStack->GetDBIndex(stack_index));
2028 int type_tent = ChartData->GetDBChartType(
2029 m_pCurrentStack->GetDBIndex(stack_index));
2031 if (IsChartQuiltableRef(m_pCurrentStack->GetDBIndex(stack_index))) {
2032 if ((proj == proj_tent) && (type_tent == type)) {
2033 target_new_dbindex = m_pCurrentStack->GetDBIndex(stack_index);
2043 if (IsChartQuiltableRef(target_new_dbindex))
2044 SelectQuiltRefdbChart(target_new_dbindex,
2047 SelectQuiltRefdbChart(-1,
false);
2049 m_singleChart = NULL;
2052 AdjustQuiltRefChart();
2060 GetVP().SetProjectionType(PROJECTION_UNKNOWN);
2064 std::vector<int> empty_array;
2065 m_Piano->SetActiveKeyArray(empty_array);
2066 m_Piano->SetNoshowIndexArray(empty_array);
2067 m_Piano->SetEclipsedIndexArray(empty_array);
2070 m_Piano->SetVizIcon(
new wxBitmap(style->GetIcon(_T(
"viz"))));
2071 m_Piano->SetInVizIcon(
new wxBitmap(style->GetIcon(_T(
"redX"))));
2072 m_Piano->SetTMercIcon(
new wxBitmap(style->GetIcon(_T(
"tmercprj"))));
2073 m_Piano->SetSkewIcon(
new wxBitmap(style->GetIcon(_T(
"skewprj"))));
2075 m_Piano->SetRoundedRectangles(
false);
2081 if (!GetQuiltMode()) {
2082 if (ChartData && ChartData->IsValid()) {
2086 if (m_bFollow ==
true) {
2094 if (!m_singleChart) {
2097 ChartData->BuildChartStack(&TempStack, tLat, tLon, g_sticky_chart,
2105 int cur_max_scale = (int)1e8;
2107 ChartBase *pChart = GetFirstQuiltChart();
2111 ChartData->GetStackEntry(&TempStack, pChart->GetFullPath());
2113 if (pChart->GetNativeScale() < cur_max_scale) {
2114 Candidate_Chart = pChart;
2115 cur_max_scale = pChart->GetNativeScale();
2118 pChart = GetNextQuiltChart();
2121 m_singleChart = Candidate_Chart;
2125 if (NULL == m_singleChart) {
2126 m_singleChart = ChartData->OpenStackChartConditional(
2127 &TempStack, TempStack.nEntry - 1,
true, CHART_TYPE_DONTCARE,
2128 CHART_FAMILY_DONTCARE);
2134 InvalidateAllQuiltPatchs();
2136 if (m_singleChart) {
2137 int dbi = ChartData->FinddbIndex(m_singleChart->GetFullPath());
2138 std::vector<int> one_array;
2139 one_array.push_back(dbi);
2140 m_Piano->SetActiveKeyArray(one_array);
2143 if (m_singleChart) {
2144 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
2148 if (m_pCurrentStack) m_pCurrentStack->b_valid =
false;
2152 bool ChartCanvas::IsTempMenuBarEnabled() {
2155 wxGetOsVersion(&major);
2163 double ChartCanvas::GetCanvasRangeMeters() {
2165 GetSize(&width, &height);
2166 int minDimension = wxMin(width, height);
2168 double range = (minDimension / GetVP().view_scale_ppm) / 2;
2169 range *= cos(GetVP().clat * PI / 180.);
2173 void ChartCanvas::SetCanvasRangeMeters(
double range) {
2175 GetSize(&width, &height);
2176 int minDimension = wxMin(width, height);
2178 double scale_ppm = minDimension / (range / cos(GetVP().clat * PI / 180.));
2179 SetVPScale(scale_ppm / 2);
2182 bool ChartCanvas::SetUserOwnship() {
2186 if (pWayPointMan && pWayPointMan->DoesIconExist(_T(
"ownship"))) {
2187 double factor_dusk = 0.5;
2188 double factor_night = 0.25;
2190 wxBitmap *pbmp = pWayPointMan->GetIconBitmap(_T(
"ownship"));
2191 m_pos_image_user_day =
new wxImage;
2192 *m_pos_image_user_day = pbmp->ConvertToImage();
2193 if (!m_pos_image_user_day->HasAlpha()) m_pos_image_user_day->InitAlpha();
2195 int gimg_width = m_pos_image_user_day->GetWidth();
2196 int gimg_height = m_pos_image_user_day->GetHeight();
2199 m_pos_image_user_dusk =
new wxImage;
2200 m_pos_image_user_night =
new wxImage;
2202 *m_pos_image_user_dusk = m_pos_image_user_day->Copy();
2203 *m_pos_image_user_night = m_pos_image_user_day->Copy();
2205 for (
int iy = 0; iy < gimg_height; iy++) {
2206 for (
int ix = 0; ix < gimg_width; ix++) {
2207 if (!m_pos_image_user_day->IsTransparent(ix, iy)) {
2208 wxImage::RGBValue rgb(m_pos_image_user_day->GetRed(ix, iy),
2209 m_pos_image_user_day->GetGreen(ix, iy),
2210 m_pos_image_user_day->GetBlue(ix, iy));
2211 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2212 hsv.value = hsv.value * factor_dusk;
2213 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2214 m_pos_image_user_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2217 hsv = wxImage::RGBtoHSV(rgb);
2218 hsv.value = hsv.value * factor_night;
2219 nrgb = wxImage::HSVtoRGB(hsv);
2220 m_pos_image_user_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2227 m_pos_image_user_grey_day =
new wxImage;
2228 *m_pos_image_user_grey_day = m_pos_image_user_day->ConvertToGreyscale();
2230 m_pos_image_user_grey_dusk =
new wxImage;
2231 m_pos_image_user_grey_night =
new wxImage;
2233 *m_pos_image_user_grey_dusk = m_pos_image_user_grey_day->Copy();
2234 *m_pos_image_user_grey_night = m_pos_image_user_grey_day->Copy();
2236 for (
int iy = 0; iy < gimg_height; iy++) {
2237 for (
int ix = 0; ix < gimg_width; ix++) {
2238 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2239 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2240 m_pos_image_user_grey_day->GetGreen(ix, iy),
2241 m_pos_image_user_grey_day->GetBlue(ix, iy));
2242 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2243 hsv.value = hsv.value * factor_dusk;
2244 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2245 m_pos_image_user_grey_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green,
2248 hsv = wxImage::RGBtoHSV(rgb);
2249 hsv.value = hsv.value * factor_night;
2250 nrgb = wxImage::HSVtoRGB(hsv);
2251 m_pos_image_user_grey_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2258 m_pos_image_user_yellow_day =
new wxImage;
2259 m_pos_image_user_yellow_dusk =
new wxImage;
2260 m_pos_image_user_yellow_night =
new wxImage;
2262 *m_pos_image_user_yellow_day = m_pos_image_user_grey_day->Copy();
2263 *m_pos_image_user_yellow_dusk = m_pos_image_user_grey_day->Copy();
2264 *m_pos_image_user_yellow_night = m_pos_image_user_grey_day->Copy();
2266 for (
int iy = 0; iy < gimg_height; iy++) {
2267 for (
int ix = 0; ix < gimg_width; ix++) {
2268 if (!m_pos_image_user_grey_day->IsTransparent(ix, iy)) {
2269 wxImage::RGBValue rgb(m_pos_image_user_grey_day->GetRed(ix, iy),
2270 m_pos_image_user_grey_day->GetGreen(ix, iy),
2271 m_pos_image_user_grey_day->GetBlue(ix, iy));
2275 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
2276 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
2277 m_pos_image_user_yellow_day->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2279 hsv = wxImage::RGBtoHSV(rgb);
2280 hsv.value = hsv.value * factor_dusk;
2281 nrgb = wxImage::HSVtoRGB(hsv);
2282 m_pos_image_user_yellow_dusk->SetRGB(ix, iy, nrgb.red, nrgb.green, 0);
2284 hsv = wxImage::RGBtoHSV(rgb);
2285 hsv.value = hsv.value * factor_night;
2286 nrgb = wxImage::HSVtoRGB(hsv);
2287 m_pos_image_user_yellow_night->SetRGB(ix, iy, nrgb.red, nrgb.green,
2298 void ChartCanvas::SetDisplaySizeMM(
double size) {
2299 m_display_size_mm = size;
2305 wxSize sd = g_Platform->getDisplaySize();
2306 double horizontal = sd.x;
2308 g_scaler = g_Platform->GetDisplayDIPMult(
this);
2310 m_pix_per_mm = (horizontal) / ((
double)m_display_size_mm);
2311 m_canvas_scale_factor = (horizontal) / (m_display_size_mm / 1000.);
2314 ps52plib->SetDisplayWidth(g_monitor_info[g_current_monitor].width);
2315 ps52plib->SetPPMM(m_pix_per_mm);
2320 _T(
"Metrics: m_display_size_mm: %g g_Platform->getDisplaySize(): ")
2322 m_display_size_mm, sd.x, sd.y);
2326 ssx = g_monitor_info[g_current_monitor].width;
2327 ssy = g_monitor_info[g_current_monitor].height;
2328 msg.Printf(_T(
"monitor size: %d %d"), ssx, ssy);
2331 m_focus_indicator_pix = wxRound(1 * GetPixPerMM());
2334 void ChartCanvas::OnEvtCompressProgress( OCPN_CompressProgressEvent & event )
2336 wxString msg(event.m_string.c_str(), wxConvUTF8);
2338 if(pprog_threads > 0 && compress_msg_array.GetCount() > (
unsigned int)pprog_threads) {
2339 compress_msg_array.RemoveAt(pprog_threads, compress_msg_array.GetCount() - pprog_threads);
2342 if(compress_msg_array.GetCount() > (
unsigned int)event.thread )
2344 compress_msg_array.RemoveAt(event.thread);
2345 compress_msg_array.Insert( msg, event.thread);
2348 compress_msg_array.Add(msg);
2351 wxString combined_msg;
2352 for(
unsigned int i=0 ; i < compress_msg_array.GetCount() ; i++) {
2353 combined_msg += compress_msg_array[i];
2354 combined_msg += _T(
"\n");
2358 pprog->Update(pprog_count, combined_msg, &skip );
2359 pprog->SetSize(pprog_size);
2364 void ChartCanvas::InvalidateGL() {
2365 if (!m_glcc)
return;
2367 if (g_bopengl) m_glcc->Invalidate();
2369 if (m_Compass) m_Compass->UpdateStatus(
true);
2372 int ChartCanvas::GetCanvasChartNativeScale() {
2374 if (!VPoint.b_quilt) {
2375 if (m_singleChart) ret = m_singleChart->GetNativeScale();
2377 ret = (int)m_pQuilt->GetRefNativeScale();
2382 ChartBase *ChartCanvas::GetChartAtCursor() {
2384 if (m_singleChart && (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR))
2385 target_chart = m_singleChart;
2386 else if (VPoint.b_quilt)
2387 target_chart = m_pQuilt->GetChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2389 target_chart = NULL;
2390 return target_chart;
2393 ChartBase *ChartCanvas::GetOverlayChartAtCursor() {
2397 m_pQuilt->GetOverlayChartAtPix(VPoint, wxPoint(mouse_x, mouse_y));
2399 target_chart = NULL;
2400 return target_chart;
2403 int ChartCanvas::FindClosestCanvasChartdbIndex(
int scale) {
2404 int new_dbIndex = -1;
2405 if (!VPoint.b_quilt) {
2406 if (m_pCurrentStack) {
2407 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
2408 int sc = ChartData->GetStackChartScale(m_pCurrentStack, i, NULL, 0);
2410 new_dbIndex = m_pCurrentStack->GetDBIndex(i);
2420 unsigned int im = m_pQuilt->GetExtendedStackIndexArray().size();
2422 for (
unsigned int is = 0; is < im; is++) {
2424 m_pQuilt->GetExtendedStackIndexArray()[is]);
2427 new_dbIndex = m_pQuilt->GetExtendedStackIndexArray()[is];
2437 void ChartCanvas::EnablePaint(
bool b_enable) {
2438 m_b_paint_enable = b_enable;
2440 if (m_glcc) m_glcc->EnablePaint(b_enable);
2444 bool ChartCanvas::IsQuiltDelta() {
return m_pQuilt->IsQuiltDelta(VPoint); }
2446 void ChartCanvas::UnlockQuilt() { m_pQuilt->UnlockQuilt(); }
2448 std::vector<int> ChartCanvas::GetQuiltIndexArray(
void) {
2449 return m_pQuilt->GetQuiltIndexArray();
2453 void ChartCanvas::SetQuiltMode(
bool b_quilt) {
2454 VPoint.b_quilt = b_quilt;
2455 VPoint.b_FullScreenQuilt = g_bFullScreenQuilt;
2458 bool ChartCanvas::GetQuiltMode(
void) {
return VPoint.b_quilt; }
2460 int ChartCanvas::GetQuiltReferenceChartIndex(
void) {
2461 return m_pQuilt->GetRefChartdbIndex();
2464 void ChartCanvas::InvalidateAllQuiltPatchs(
void) {
2465 m_pQuilt->InvalidateAllQuiltPatchs();
2468 ChartBase *ChartCanvas::GetLargestScaleQuiltChart() {
2469 return m_pQuilt->GetLargestScaleChart();
2472 ChartBase *ChartCanvas::GetFirstQuiltChart() {
2473 return m_pQuilt->GetFirstChart();
2476 ChartBase *ChartCanvas::GetNextQuiltChart() {
return m_pQuilt->GetNextChart(); }
2478 int ChartCanvas::GetQuiltChartCount() {
return m_pQuilt->GetnCharts(); }
2480 void ChartCanvas::SetQuiltChartHiLiteIndex(
int dbIndex) {
2481 m_pQuilt->SetHiliteIndex(dbIndex);
2484 void ChartCanvas::SetQuiltChartHiLiteIndexArray(std::vector<int> hilite_array) {
2485 m_pQuilt->SetHiliteIndexArray(hilite_array);
2488 void ChartCanvas::ClearQuiltChartHiLiteIndexArray() {
2489 m_pQuilt->ClearHiliteIndexArray();
2492 std::vector<int> ChartCanvas::GetQuiltCandidatedbIndexArray(
bool flag1,
2494 return m_pQuilt->GetCandidatedbIndexArray(flag1, flag2);
2497 int ChartCanvas::GetQuiltRefChartdbIndex(
void) {
2498 return m_pQuilt->GetRefChartdbIndex();
2501 std::vector<int> &ChartCanvas::GetQuiltExtendedStackdbIndexArray() {
2502 return m_pQuilt->GetExtendedStackIndexArray();
2505 std::vector<int> &ChartCanvas::GetQuiltFullScreendbIndexArray() {
2506 return m_pQuilt->GetFullscreenIndexArray();
2509 std::vector<int> ChartCanvas::GetQuiltEclipsedStackdbIndexArray() {
2510 return m_pQuilt->GetEclipsedStackIndexArray();
2513 void ChartCanvas::InvalidateQuilt(
void) {
return m_pQuilt->Invalidate(); }
2515 double ChartCanvas::GetQuiltMaxErrorFactor() {
2516 return m_pQuilt->GetMaxErrorFactor();
2519 bool ChartCanvas::IsChartQuiltableRef(
int db_index) {
2520 return m_pQuilt->IsChartQuiltableRef(db_index);
2524 double chartMaxScale =
2525 chart->GetNormalScaleMax(GetCanvasScaleFactor(), GetCanvasWidth());
2526 return (chartMaxScale * g_ChartNotRenderScaleFactor > vp.chart_scale);
2529 void ChartCanvas::StartMeasureRoute() {
2530 if (!m_routeState) {
2531 if (m_bMeasure_Active) {
2533 NavObjectChanges::getInstance());
2534 m_pMeasureRoute = NULL;
2537 m_bMeasure_Active =
true;
2538 m_nMeasureState = 1;
2539 m_bDrawingRoute =
false;
2541 SetCursor(*pCursorPencil);
2546 void ChartCanvas::CancelMeasureRoute() {
2547 m_bMeasure_Active =
false;
2548 m_nMeasureState = 0;
2549 m_bDrawingRoute =
false;
2551 g_pRouteMan->
DeleteRoute(m_pMeasureRoute, NavObjectChanges::getInstance());
2552 m_pMeasureRoute = NULL;
2554 SetCursor(*pCursorArrow);
2557 ViewPort &ChartCanvas::GetVP() {
return VPoint; }
2559 void ChartCanvas::SetVP(
ViewPort &vp) { VPoint = vp; }
2567 void ChartCanvas::TriggerDeferredFocus() {
2570 m_deferredFocusTimer.Start(20,
true);
2572 #if defined(__WXGTK__) || defined(__WXOSX__)
2583 void ChartCanvas::OnDeferredFocusTimerEvent(wxTimerEvent &event) {
2588 void ChartCanvas::OnKeyChar(wxKeyEvent &event) {
2590 if (g_pi_manager->SendKeyEventToPlugins(event))
2594 int key_char =
event.GetKeyCode();
2596 if (g_benable_rotate) {
2617 void ChartCanvas::OnKeyDown(wxKeyEvent &event) {
2619 if (g_pi_manager->SendKeyEventToPlugins(event))
2623 bool b_handled =
false;
2625 m_modkeys =
event.GetModifiers();
2627 int panspeed = m_modkeys == wxMOD_ALT ? 1 : 100;
2629 #ifdef OCPN_ALT_MENUBAR
2635 if (IsTempMenuBarEnabled() && event.AltDown() && !g_bShowMenuBar) {
2637 if (event.GetKeyCode() >=
'A' && event.GetKeyCode() <=
'Z') {
2638 if (!g_bTempShowMenuBar) {
2639 g_bTempShowMenuBar =
true;
2640 parent_frame->ApplyGlobalSettings(
false);
2642 m_bMayToggleMenuBar =
false;
2648 if (event.GetKeyCode() != WXK_ALT) {
2649 m_bMayToggleMenuBar =
false;
2656 switch (event.GetKeyCode()) {
2663 event.GetPosition(&x, &y);
2664 m_FinishRouteOnKillFocus =
false;
2665 CallPopupMenu(x, y);
2666 m_FinishRouteOnKillFocus =
true;
2670 m_modkeys |= wxMOD_ALT;
2674 m_modkeys |= wxMOD_CONTROL;
2679 case WXK_RAW_CONTROL:
2680 m_modkeys |= wxMOD_RAW_CONTROL;
2685 if (m_modkeys == wxMOD_CONTROL)
2686 parent_frame->DoStackDown(
this);
2687 else if (g_bsmoothpanzoom) {
2688 StartTimedMovement();
2691 PanCanvas(-panspeed, 0);
2697 if (g_bsmoothpanzoom) {
2698 StartTimedMovement();
2701 PanCanvas(0, -panspeed);
2706 if (m_modkeys == wxMOD_CONTROL)
2707 parent_frame->DoStackUp(
this);
2708 else if (g_bsmoothpanzoom) {
2709 StartTimedMovement();
2712 PanCanvas(panspeed, 0);
2718 if (g_bsmoothpanzoom) {
2719 StartTimedMovement();
2722 PanCanvas(0, panspeed);
2731 SetShowENCText(!GetShowENCText());
2737 if (!m_bMeasure_Active) {
2738 if (event.ShiftDown())
2739 m_bMeasure_DistCircle =
true;
2741 m_bMeasure_DistCircle =
false;
2743 StartMeasureRoute();
2745 CancelMeasureRoute();
2747 SetCursor(*pCursorArrow);
2757 parent_frame->ToggleColorScheme();
2759 TriggerDeferredFocus();
2763 int mod = m_modkeys & wxMOD_SHIFT;
2764 if (mod != m_brightmod) {
2766 m_bbrightdir = !m_bbrightdir;
2769 if (!m_bbrightdir) {
2770 g_nbrightness -= 10;
2771 if (g_nbrightness <= MIN_BRIGHT) {
2772 g_nbrightness = MIN_BRIGHT;
2773 m_bbrightdir =
true;
2776 g_nbrightness += 10;
2777 if (g_nbrightness >= MAX_BRIGHT) {
2778 g_nbrightness = MAX_BRIGHT;
2779 m_bbrightdir =
false;
2783 SetScreenBrightness(g_nbrightness);
2784 ShowBrightnessLevelTimedPopup(g_nbrightness / 10, 1, 10);
2793 parent_frame->DoStackDown(
this);
2797 parent_frame->DoStackUp(
this);
2802 ToggleCanvasQuiltMode();
2807 parent_frame->ToggleFullScreen();
2812 if (m_modkeys == wxMOD_ALT)
2813 m_nMeasureState = *(
volatile int *)(0);
2815 ToggleChartOutlines();
2820 parent_frame->ActivateMOB();
2824 case WXK_NUMPAD_ADD:
2826 ZoomCanvas(g_plus_minus_zoom_factor,
false);
2829 case WXK_NUMPAD_SUBTRACT:
2830 case WXK_PAGEDOWN: {
2831 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2836 if (m_bMeasure_Active) {
2837 if (m_nMeasureState > 2) {
2838 m_pMeasureRoute->DeletePoint(m_pMeasureRoute->GetLastPoint());
2839 m_pMeasureRoute->m_lastMousePointIndex =
2840 m_pMeasureRoute->GetnPoints();
2842 gFrame->RefreshAllCanvas();
2844 CancelMeasureRoute();
2845 StartMeasureRoute();
2853 if (event.GetKeyCode() < 128)
2855 int key_char =
event.GetKeyCode();
2859 if (!g_b_assume_azerty) {
2863 ZoomCanvas(g_plus_minus_zoom_factor,
false);
2868 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2873 if (g_benable_rotate) {
2897 ZoomCanvas(g_plus_minus_zoom_factor,
false);
2902 ZoomCanvas(1.0 / g_plus_minus_zoom_factor,
false);
2909 if (key_char ==
'F' && m_modkeys & wxMOD_CONTROL && m_modkeys & wxMOD_RAW_CONTROL) {
2910 parent_frame->ToggleFullScreen();
2915 if (event.ControlDown()) key_char -= 64;
2917 if (key_char >=
'0' && key_char <=
'9')
2918 SetGroupIndex(key_char -
'0');
2923 SetShowENCAnchor(!GetShowENCAnchor());
2929 parent_frame->ToggleColorScheme();
2934 event.GetPosition(&x, &y);
2935 ChartTypeEnum ChartType = CHART_TYPE_UNKNOWN;
2936 ChartFamilyEnum ChartFam = CHART_FAMILY_UNKNOWN;
2938 if (!pPopupDetailSlider) {
2939 if (VPoint.b_quilt) {
2941 if (m_pQuilt->GetChartAtPix(
2946 ChartType = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2948 ChartFam = m_pQuilt->GetChartAtPix(VPoint, wxPoint(x, y))
2953 if (m_singleChart) {
2954 ChartType = m_singleChart->GetChartType();
2955 ChartFam = m_singleChart->GetChartFamily();
2959 if ((ChartType != CHART_TYPE_UNKNOWN) ||
2960 (ChartFam != CHART_FAMILY_UNKNOWN)) {
2962 this, -1, ChartType, ChartFam,
2963 wxPoint(g_detailslider_dialog_x, g_detailslider_dialog_y),
2964 wxDefaultSize, wxSIMPLE_BORDER, _T(
""));
2965 if (pPopupDetailSlider) pPopupDetailSlider->Show();
2969 if (pPopupDetailSlider) pPopupDetailSlider->Close();
2970 pPopupDetailSlider = NULL;
2976 SetShowENCLights(!GetShowENCLights());
2982 if (event.ShiftDown())
2983 m_bMeasure_DistCircle =
true;
2985 m_bMeasure_DistCircle =
false;
2987 StartMeasureRoute();
2991 if (g_bInlandEcdis && ps52plib) {
2992 SetENCDisplayCategory((_DisCat)STANDARD);
2997 ToggleChartOutlines();
3001 ToggleCanvasQuiltMode();
3005 parent_frame->ToggleTestPause();
3008 g_bNavAidRadarRingsShown = !g_bNavAidRadarRingsShown;
3009 if (g_bNavAidRadarRingsShown &&
3010 g_iNavAidRadarRingsNumberVisible == 0)
3011 g_iNavAidRadarRingsNumberVisible = 1;
3012 else if (!g_bNavAidRadarRingsShown &&
3013 g_iNavAidRadarRingsNumberVisible == 1)
3014 g_iNavAidRadarRingsNumberVisible = 0;
3017 SetShowENCDepth(!m_encShowDepth);
3022 SetShowENCText(!GetShowENCText());
3027 SetShowENCDataQual(!GetShowENCDataQual());
3032 m_bShowNavobjects = !m_bShowNavobjects;
3047 if (g_bShowMenuBar ==
false) parent_frame->ToggleChartBar(
this);
3052 if (event.ControlDown()) gFrame->DropMarker(
false);
3058 if (
Route *r = g_pRouteMan->GetpActiveRoute()) {
3059 int indexActive = r->GetIndexOf(r->m_pRouteActivePoint);
3060 if ((indexActive + 1) <= r->GetnPoints()) {
3071 if (!g_bShowMenuBar) gFrame->DropMarker(
true);
3077 if (g_bSpaceDropMark) gFrame->DropMarker(
true);
3083 if (m_modkeys == wxMOD_CONTROL) parent_frame->ActivateMOB();
3090 parent_frame->DoSettings();
3094 parent_frame->Close();
3102 if (NULL == pGoToPositionDialog)
3105 pGoToPositionDialog->SetCanvas(
this);
3106 pGoToPositionDialog->Show();
3110 if (undo->AnythingToRedo()) {
3111 undo->RedoNextAction();
3118 if (event.ShiftDown()) {
3119 if (undo->AnythingToRedo()) {
3120 undo->RedoNextAction();
3125 if (undo->AnythingToUndo()) {
3126 undo->UndoLastAction();
3135 if (m_bMeasure_Active) {
3136 CancelMeasureRoute();
3138 SetCursor(*pCursorArrow);
3141 gFrame->RefreshAllCanvas();
3155 switch (gamma_state) {
3175 SetScreenBrightness(g_nbrightness);
3180 if (event.ControlDown()) {
3181 m_bShowCompassWin = !m_bShowCompassWin;
3182 SetShowGPSCompassWindow(m_bShowCompassWin);
3196 if (!b_handled)
event.Skip();
3200 void ChartCanvas::OnKeyUp(wxKeyEvent &event) {
3202 if (g_pi_manager->SendKeyEventToPlugins(event))
3206 switch (event.GetKeyCode()) {
3208 parent_frame->SwitchKBFocus(
this);
3214 if (!m_pany) m_panspeed = 0;
3220 if (!m_panx) m_panspeed = 0;
3223 case WXK_NUMPAD_ADD:
3224 case WXK_NUMPAD_SUBTRACT:
3227 if (m_mustmove) DoMovement(m_mustmove);
3233 m_modkeys &= ~wxMOD_ALT;
3234 #ifdef OCPN_ALT_MENUBAR
3239 if (IsTempMenuBarEnabled() && !g_bShowMenuBar && m_bMayToggleMenuBar) {
3240 g_bTempShowMenuBar = !g_bTempShowMenuBar;
3241 parent_frame->ApplyGlobalSettings(
false);
3243 m_bMayToggleMenuBar =
true;
3249 m_modkeys &= ~wxMOD_CONTROL;
3253 if (event.GetKeyCode() < 128)
3255 int key_char =
event.GetKeyCode();
3259 if (!g_b_assume_azerty) {
3267 DoMovement(m_mustmove);
3273 DoMovement(m_mustmove);
3274 m_rotation_speed = 0;
3282 DoMovement(m_mustmove);
3292 void ChartCanvas::ToggleChartOutlines(
void) {
3293 m_bShowOutlines = !m_bShowOutlines;
3299 if (g_bopengl) InvalidateGL();
3303 void ChartCanvas::ToggleLookahead() {
3304 m_bLookAhead = !m_bLookAhead;
3309 void ChartCanvas::SetUpMode(
int mode) {
3312 if (mode != NORTH_UP_MODE) {
3315 if (!std::isnan(gCog)) stuff = gCog;
3317 if (g_COGAvgSec > 0) {
3318 for (
int i = 0; i < g_COGAvgSec; i++) gFrame->COGTable[i] = stuff;
3321 gFrame->FrameCOGTimer.Start(100, wxTIMER_CONTINUOUS);
3323 if (!g_bskew_comp && (fabs(GetVPSkew()) > 0.0001))
3324 SetVPRotation(GetVPSkew());
3329 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
3330 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
3332 UpdateGPSCompassStatusBox(
true);
3333 gFrame->DoChartUpdate();
3336 bool ChartCanvas::DoCanvasCOGSet(
void) {
3337 if (GetUpMode() == NORTH_UP_MODE)
return false;
3339 if (std::isnan(g_COGAvg))
return true;
3341 double old_VPRotate = m_VPRotate;
3343 if ((GetUpMode() == HEAD_UP_MODE) && !std::isnan(gHdt)) {
3344 m_VPRotate = -gHdt * PI / 180.;
3345 }
else if (GetUpMode() == COURSE_UP_MODE)
3346 m_VPRotate = -g_COGAvg * PI / 180.;
3348 SetVPRotation(m_VPRotate);
3349 bool bnew_chart = DoCanvasUpdate();
3351 if ((bnew_chart) || (old_VPRotate != m_VPRotate)) ReloadVP();
3356 void ChartCanvas::StopMovement() {
3357 m_panx = m_pany = 0;
3360 m_rotation_speed = 0;
3363 #if !defined(__WXGTK__) && !defined(__WXQT__)
3374 bool ChartCanvas::StartTimedMovement(
bool stoptimer) {
3376 if (stoptimer) pMovementStopTimer->Start(800, wxTIMER_ONE_SHOT);
3378 if (!pMovementTimer->IsRunning()) {
3380 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
3383 if (m_panx || m_pany || m_zoom_factor != 1 || m_rotation_speed) {
3388 m_last_movement_time = wxDateTime::UNow();
3399 void ChartCanvas::DoTimedMovement() {
3400 if (m_pan_drag == wxPoint(0, 0) && !m_panx && !m_pany && m_zoom_factor == 1 &&
3404 wxDateTime now = wxDateTime::UNow();
3406 if (m_last_movement_time.IsValid())
3407 dt = (now - m_last_movement_time).GetMilliseconds().ToLong();
3409 m_last_movement_time = now;
3417 void ChartCanvas::DoMovement(
long dt) {
3419 if (dt == 0) dt = 1;
3422 if (m_mustmove < 0) m_mustmove = 0;
3424 if (m_pan_drag.x || m_pan_drag.y) {
3425 PanCanvas(m_pan_drag.x, m_pan_drag.y);
3426 m_pan_drag.x = m_pan_drag.y = 0;
3429 if (m_panx || m_pany) {
3430 const double slowpan = .1, maxpan = 2;
3431 if (m_modkeys == wxMOD_ALT)
3432 m_panspeed = slowpan;
3434 m_panspeed += (double)dt / 500;
3435 m_panspeed = wxMin(maxpan, m_panspeed);
3437 PanCanvas(m_panspeed * m_panx * dt, m_panspeed * m_pany * dt);
3440 if (m_zoom_factor != 1) {
3441 double alpha = 400, beta = 1.5;
3442 double zoom_factor = (exp(dt / alpha) - 1) / beta + 1;
3444 if (m_modkeys == wxMOD_ALT) zoom_factor = pow(zoom_factor, .15);
3446 if (m_zoom_factor < 1) zoom_factor = 1 / zoom_factor;
3451 if (zoom_factor > 1) {
3452 if (VPoint.chart_scale / zoom_factor <= m_zoom_target)
3453 zoom_factor = VPoint.chart_scale / m_zoom_target;
3456 else if (zoom_factor < 1) {
3457 if (VPoint.chart_scale / zoom_factor >= m_zoom_target)
3458 zoom_factor = VPoint.chart_scale / m_zoom_target;
3462 if (fabs(zoom_factor - 1) > 1e-4)
3463 DoZoomCanvas(zoom_factor, m_bzooming_to_cursor);
3465 if (m_wheelzoom_stop_oneshot > 0) {
3466 if (m_wheelstopwatch.Time() > m_wheelzoom_stop_oneshot) {
3467 m_wheelzoom_stop_oneshot = 0;
3472 if (zoom_factor > 1) {
3473 if (VPoint.chart_scale <= m_zoom_target) {
3474 m_wheelzoom_stop_oneshot = 0;
3477 }
else if (zoom_factor < 1) {
3478 if (VPoint.chart_scale >= m_zoom_target) {
3479 m_wheelzoom_stop_oneshot = 0;
3486 if (m_rotation_speed) {
3487 double speed = m_rotation_speed;
3488 if (m_modkeys == wxMOD_ALT) speed /= 10;
3489 DoRotateCanvas(VPoint.rotation + speed * PI / 180 * dt / 1000.0);
3493 void ChartCanvas::SetColorScheme(ColorScheme cs) {
3494 SetAlertString(_T(
""));
3498 case GLOBAL_COLOR_SCHEME_DAY:
3499 m_pos_image_red = &m_os_image_red_day;
3500 m_pos_image_grey = &m_os_image_grey_day;
3501 m_pos_image_yellow = &m_os_image_yellow_day;
3502 m_pos_image_user = m_pos_image_user_day;
3503 m_pos_image_user_grey = m_pos_image_user_grey_day;
3504 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3505 m_cTideBitmap = m_bmTideDay;
3506 m_cCurrentBitmap = m_bmCurrentDay;
3509 case GLOBAL_COLOR_SCHEME_DUSK:
3510 m_pos_image_red = &m_os_image_red_dusk;
3511 m_pos_image_grey = &m_os_image_grey_dusk;
3512 m_pos_image_yellow = &m_os_image_yellow_dusk;
3513 m_pos_image_user = m_pos_image_user_dusk;
3514 m_pos_image_user_grey = m_pos_image_user_grey_dusk;
3515 m_pos_image_user_yellow = m_pos_image_user_yellow_dusk;
3516 m_cTideBitmap = m_bmTideDusk;
3517 m_cCurrentBitmap = m_bmCurrentDusk;
3519 case GLOBAL_COLOR_SCHEME_NIGHT:
3520 m_pos_image_red = &m_os_image_red_night;
3521 m_pos_image_grey = &m_os_image_grey_night;
3522 m_pos_image_yellow = &m_os_image_yellow_night;
3523 m_pos_image_user = m_pos_image_user_night;
3524 m_pos_image_user_grey = m_pos_image_user_grey_night;
3525 m_pos_image_user_yellow = m_pos_image_user_yellow_night;
3526 m_cTideBitmap = m_bmTideNight;
3527 m_cCurrentBitmap = m_bmCurrentNight;
3530 m_pos_image_red = &m_os_image_red_day;
3531 m_pos_image_grey = &m_os_image_grey_day;
3532 m_pos_image_yellow = &m_os_image_yellow_day;
3533 m_pos_image_user = m_pos_image_user_day;
3534 m_pos_image_user_grey = m_pos_image_user_grey_day;
3535 m_pos_image_user_yellow = m_pos_image_user_yellow_day;
3536 m_cTideBitmap = m_bmTideDay;
3537 m_cCurrentBitmap = m_bmCurrentDay;
3541 CreateDepthUnitEmbossMaps(cs);
3542 CreateOZEmbossMapData(cs);
3545 m_fog_color = wxColor(
3549 case GLOBAL_COLOR_SCHEME_DUSK:
3552 case GLOBAL_COLOR_SCHEME_NIGHT:
3558 m_fog_color.Set(m_fog_color.Red() * dim, m_fog_color.Green() * dim,
3559 m_fog_color.Blue() * dim);
3563 if( cs == GLOBAL_COLOR_SCHEME_DUSK || cs == GLOBAL_COLOR_SCHEME_NIGHT ) {
3564 SetBackgroundColour( wxColour(0,0,0) );
3566 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxSIMPLE_BORDER) | wxNO_BORDER);
3569 SetWindowStyleFlag( (GetWindowStyleFlag() & ~wxNO_BORDER) | wxSIMPLE_BORDER);
3571 SetBackgroundColour( wxNullColour );
3578 m_Piano->SetColorScheme(cs);
3580 m_Compass->SetColorScheme(cs);
3582 if (m_muiBar) m_muiBar->SetColorScheme(cs);
3584 if (pWorldBackgroundChart) pWorldBackgroundChart->SetColorScheme(cs);
3586 if (g_bopengl && m_glcc) {
3587 m_glcc->SetColorScheme(cs);
3588 g_glTextureManager->ClearAllRasterTextures();
3593 m_brepaint_piano =
true;
3600 wxBitmap ChartCanvas::CreateDimBitmap(wxBitmap &Bitmap,
double factor) {
3601 wxImage img = Bitmap.ConvertToImage();
3602 int sx = img.GetWidth();
3603 int sy = img.GetHeight();
3605 wxImage new_img(img);
3607 for (
int i = 0; i < sx; i++) {
3608 for (
int j = 0; j < sy; j++) {
3609 if (!img.IsTransparent(i, j)) {
3610 new_img.SetRGB(i, j, (
unsigned char)(img.GetRed(i, j) * factor),
3611 (
unsigned char)(img.GetGreen(i, j) * factor),
3612 (
unsigned char)(img.GetBlue(i, j) * factor));
3617 wxBitmap ret = wxBitmap(new_img);
3622 void ChartCanvas::ShowBrightnessLevelTimedPopup(
int brightness,
int min,
3624 wxFont *pfont = FontMgr::Get().FindOrCreateFont(
3625 40, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
3627 if (!m_pBrightPopup) {
3630 GetTextExtent(_T(
"MAX"), &x, &y, NULL, NULL, pfont);
3634 m_pBrightPopup->SetSize(x, y);
3635 m_pBrightPopup->Move(120, 120);
3638 int bmpsx = m_pBrightPopup->GetSize().x;
3639 int bmpsy = m_pBrightPopup->GetSize().y;
3641 wxBitmap bmp(bmpsx, bmpsx);
3642 wxMemoryDC mdc(bmp);
3644 mdc.SetTextForeground(GetGlobalColor(_T(
"GREEN4")));
3645 mdc.SetBackground(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3646 mdc.SetPen(wxPen(wxColour(0, 0, 0)));
3647 mdc.SetBrush(wxBrush(GetGlobalColor(_T(
"UINFD"))));
3650 mdc.DrawRectangle(0, 0, bmpsx, bmpsy);
3652 mdc.SetFont(*pfont);
3655 if (brightness == max)
3657 else if (brightness == min)
3660 val.Printf(_T(
"%3d"), brightness);
3662 mdc.DrawText(val, 0, 0);
3664 mdc.SelectObject(wxNullBitmap);
3666 m_pBrightPopup->SetBitmap(bmp);
3667 m_pBrightPopup->Show();
3668 m_pBrightPopup->Refresh();
3671 void ChartCanvas::RotateTimerEvent(wxTimerEvent &event) {
3672 m_b_rot_hidef =
true;
3676 void ChartCanvas::OnRolloverPopupTimerEvent(wxTimerEvent &event) {
3677 if (!g_bRollover)
return;
3679 bool b_need_refresh =
false;
3681 wxSize win_size = GetSize() * m_displayScale;
3682 if (console && console->IsShown()) win_size.x -= console->GetSize().x;
3685 bool showAISRollover =
false;
3686 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
3687 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3688 SelectItem *pFind = pSelectAIS->FindSelection(
3689 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_AISTARGET);
3691 int FoundAIS_MMSI = (wxIntPtr)pFind->m_pData1;
3692 auto ptarget = g_pAIS->Get_Target_Data_From_MMSI(FoundAIS_MMSI);
3695 showAISRollover =
true;
3697 if (NULL == m_pAISRolloverWin) {
3699 m_pAISRolloverWin->IsActive(
false);
3700 b_need_refresh =
true;
3701 }
else if (m_pAISRolloverWin->IsActive() && m_AISRollover_MMSI &&
3702 m_AISRollover_MMSI != FoundAIS_MMSI) {
3708 m_RolloverPopupTimer.Start(50, wxTIMER_ONE_SHOT);
3709 m_pAISRolloverWin->IsActive(
false);
3710 m_AISRollover_MMSI = 0;
3715 m_AISRollover_MMSI = FoundAIS_MMSI;
3717 if (!m_pAISRolloverWin->IsActive()) {
3718 wxString s = ptarget->GetRolloverString();
3719 m_pAISRolloverWin->SetString(s);
3721 m_pAISRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3722 AIS_ROLLOVER, win_size);
3723 m_pAISRolloverWin->SetBitmap(AIS_ROLLOVER);
3724 m_pAISRolloverWin->IsActive(
true);
3725 b_need_refresh =
true;
3729 m_AISRollover_MMSI = 0;
3730 showAISRollover =
false;
3735 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive() && !showAISRollover) {
3736 m_pAISRolloverWin->IsActive(
false);
3737 m_AISRollover_MMSI = 0;
3738 b_need_refresh =
true;
3743 bool showRouteRollover =
false;
3745 if (NULL == m_pRolloverRouteSeg) {
3749 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3750 SelectableItemList SelList = pSelect->FindSelectionList(
3751 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTESEGMENT);
3752 wxSelectableItemListNode *node = SelList.GetFirst();
3758 if (pr && pr->IsVisible()) {
3759 m_pRolloverRouteSeg = pFindSel;
3760 showRouteRollover =
true;
3762 if (NULL == m_pRouteRolloverWin) {
3764 m_pRouteRolloverWin->IsActive(
false);
3767 if (!m_pRouteRolloverWin->IsActive()) {
3775 DistanceBearingMercator(
3776 segShow_point_b->m_lat, segShow_point_b->m_lon,
3777 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3779 if (!pr->m_bIsInLayer)
3780 s.Append(_(
"Route") + _T(
": "));
3782 s.Append(_(
"Layer Route: "));
3784 if (pr->m_RouteNameString.IsEmpty())
3785 s.Append(_(
"(unnamed)"));
3787 s.Append(pr->m_RouteNameString);
3789 s << _T(
"\n") << _(
"Total Length: ")
3790 << FormatDistanceAdaptive(pr->m_route_length) << _T(
"\n")
3791 << _(
"Leg: from ") << segShow_point_a->GetName() << _(
" to ")
3792 << segShow_point_b->GetName() << _T(
"\n");
3795 s << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)floor(brg+0.5),
3799 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3801 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3802 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3804 s << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8), (
int)floor(varBrg+0.5),
3808 s << FormatDistanceAdaptive(dist);
3813 double shiptoEndLeg = 0.;
3814 bool validActive =
false;
3815 if (pr->IsActive() &&
3816 pr->pRoutePointList->GetFirst()->GetData()->m_bIsActive)
3819 if (segShow_point_a != pr->pRoutePointList->GetFirst()->GetData()) {
3820 wxRoutePointListNode *node =
3821 (pr->pRoutePointList)->GetFirst()->GetNext();
3823 float dist_to_endleg = 0;
3827 prp = node->GetData();
3829 shiptoEndLeg += prp->m_seg_len;
3830 else if (prp->m_bIsActive)
3832 dist_to_endleg += prp->m_seg_len;
3833 if (prp->IsSame(segShow_point_a))
break;
3834 node = node->GetNext();
3836 s << _T(
" (+") << FormatDistanceAdaptive(dist_to_endleg) << _T(
")");
3841 s << _T(
"\n") << _(
"From Ship To") << _T(
" ")
3842 << segShow_point_b->GetName() << _T(
"\n");
3845 ->GetCurrentRngToActivePoint();
3850 s << FormatDistanceAdaptive(shiptoEndLeg);
3854 if (!std::isnan(gCog) && !std::isnan(gSog))
3856 cos((g_pRouteMan->GetCurrentBrgToActivePoint() - gCog) *
3859 float ttg_sec = (shiptoEndLeg / gSog) * 3600.;
3860 wxTimeSpan ttg_span = wxTimeSpan::Seconds((
long)ttg_sec);
3862 << wxString(ttg_sec > SECONDS_PER_DAY
3863 ? ttg_span.Format(_(
"%Dd %H:%M"))
3864 : ttg_span.Format(_(
"%H:%M")));
3865 wxDateTime dtnow, eta;
3866 eta = dtnow.SetToCurrent().Add(ttg_span);
3867 s << _T(
" - ") << eta.Format(_T(
"%b")).Mid(0, 4)
3868 << eta.Format(_T(
" %d %H:%M"));
3870 s << _T(
" ---- ----");
3872 m_pRouteRolloverWin->SetString(s);
3874 m_pRouteRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
3875 LEG_ROLLOVER, win_size);
3876 m_pRouteRolloverWin->SetBitmap(LEG_ROLLOVER);
3877 m_pRouteRolloverWin->IsActive(
true);
3878 b_need_refresh =
true;
3879 showRouteRollover =
true;
3883 node = node->GetNext();
3887 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3888 if (!pSelect->IsSelectableSegmentSelected(ctx, m_cursor_lat, m_cursor_lon,
3889 m_pRolloverRouteSeg))
3890 showRouteRollover =
false;
3891 else if (m_pRouteRolloverWin && !m_pRouteRolloverWin->IsActive())
3892 showRouteRollover =
false;
3894 showRouteRollover =
true;
3898 if (m_routeState) showRouteRollover =
false;
3901 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
3902 showRouteRollover =
false;
3904 if (m_pRouteRolloverWin &&
3905 !showRouteRollover) {
3906 m_pRouteRolloverWin->IsActive(
false);
3907 m_pRolloverRouteSeg = NULL;
3908 m_pRouteRolloverWin->Destroy();
3909 m_pRouteRolloverWin = NULL;
3910 b_need_refresh =
true;
3911 }
else if (m_pRouteRolloverWin && showRouteRollover) {
3912 m_pRouteRolloverWin->IsActive(
true);
3913 b_need_refresh =
true;
3918 bool showTrackRollover =
false;
3920 if (NULL == m_pRolloverTrackSeg) {
3924 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
3925 SelectableItemList SelList = pSelect->FindSelectionList(
3926 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_TRACKSEGMENT);
3927 wxSelectableItemListNode *node = SelList.GetFirst();
3933 if (pt && pt->IsVisible()) {
3934 m_pRolloverTrackSeg = pFindSel;
3935 showTrackRollover =
true;
3937 if (NULL == m_pTrackRolloverWin) {
3939 m_pTrackRolloverWin->IsActive(
false);
3942 if (!m_pTrackRolloverWin->IsActive()) {
3950 DistanceBearingMercator(
3951 segShow_point_b->m_lat, segShow_point_b->m_lon,
3952 segShow_point_a->m_lat, segShow_point_a->m_lon, &brg, &dist);
3954 if (!pt->m_bIsInLayer)
3955 s.Append(_(
"Track") + _T(
": "));
3957 s.Append(_(
"Layer Track: "));
3959 if (pt->GetName().IsEmpty())
3960 s.Append(_(
"(unnamed)"));
3962 s.Append(pt->GetName());
3963 double tlenght = pt->Length();
3964 s << _T(
"\n") << _(
"Total Track: ")
3965 << FormatDistanceAdaptive(tlenght);
3966 if (pt->GetLastPoint()->GetTimeString() &&
3967 pt->GetPoint(0)->GetTimeString()) {
3968 wxDateTime lastPointTime = pt->GetLastPoint()->GetCreateTime();
3969 wxDateTime zeroPointTime = pt->GetPoint(0)->GetCreateTime();
3970 if (lastPointTime.IsValid() && zeroPointTime.IsValid()){
3971 wxTimeSpan ttime = lastPointTime - zeroPointTime;
3972 double htime = ttime.GetSeconds().ToDouble() / 3600.;
3973 s << wxString::Format(_T(
" %.1f "), (
float)(tlenght / htime))
3974 << getUsrSpeedUnit();
3975 s << wxString(htime > 24. ? ttime.Format(_T(
" %Dd %H:%M"))
3976 : ttime.Format(_T(
" %H:%M")));
3980 if (g_bShowTrackPointTime && strlen(segShow_point_b->GetTimeString()))
3981 s << _T(
"\n") << _(
"Segment Created: ")
3982 << segShow_point_b->GetTimeString();
3986 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)brg,
3991 (segShow_point_b->m_lat + segShow_point_a->m_lat) / 2;
3993 (segShow_point_b->m_lon + segShow_point_a->m_lon) / 2;
3994 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
3996 s << wxString::Format(wxString(
"%03d%c ", wxConvUTF8), (
int)varBrg,
4000 s << FormatDistanceAdaptive(dist);
4002 if (segShow_point_a->GetTimeString() &&
4003 segShow_point_b->GetTimeString()) {
4004 wxDateTime apoint = segShow_point_a->GetCreateTime();
4005 wxDateTime bpoint = segShow_point_b->GetCreateTime();
4006 if (apoint.IsValid() && bpoint.IsValid()){
4007 double segmentSpeed =
4008 toUsrSpeed(dist / ((bpoint - apoint).GetSeconds()
4011 s << wxString::Format(_T(
" %.1f "), (
float)segmentSpeed)
4012 << getUsrSpeedUnit();
4016 m_pTrackRolloverWin->SetString(s);
4018 m_pTrackRolloverWin->SetBestPosition(mouse_x, mouse_y, 16, 16,
4019 LEG_ROLLOVER, win_size);
4020 m_pTrackRolloverWin->SetBitmap(LEG_ROLLOVER);
4021 m_pTrackRolloverWin->IsActive(
true);
4022 b_need_refresh =
true;
4023 showTrackRollover =
true;
4027 node = node->GetNext();
4031 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
4032 if (!pSelect->IsSelectableSegmentSelected(ctx, m_cursor_lat, m_cursor_lon,
4033 m_pRolloverTrackSeg))
4034 showTrackRollover =
false;
4035 else if (m_pTrackRolloverWin && !m_pTrackRolloverWin->IsActive())
4036 showTrackRollover =
false;
4038 showTrackRollover =
true;
4042 if (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())
4043 showTrackRollover =
false;
4046 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive())
4047 showTrackRollover =
false;
4053 if (m_pTrackRolloverWin &&
4054 !showTrackRollover) {
4055 m_pTrackRolloverWin->IsActive(
false);
4056 m_pRolloverTrackSeg = NULL;
4057 m_pTrackRolloverWin->Destroy();
4058 m_pTrackRolloverWin = NULL;
4059 b_need_refresh =
true;
4060 }
else if (m_pTrackRolloverWin && showTrackRollover) {
4061 m_pTrackRolloverWin->IsActive(
true);
4062 b_need_refresh =
true;
4065 if (b_need_refresh) Refresh();
4068 void ChartCanvas::OnCursorTrackTimerEvent(wxTimerEvent &event) {
4069 if ((GetShowENCLights() || m_bsectors_shown ) &&
4070 s57_CheckExtendedLightSectors(
this, mouse_x, mouse_y, VPoint,
4071 extendedSectorLegs)) {
4072 if (!m_bsectors_shown) {
4074 m_bsectors_shown =
true;
4077 if (m_bsectors_shown) {
4079 m_bsectors_shown =
false;
4087 #if defined(__WXGTK__) || defined(__WXQT__)
4092 double cursor_lat, cursor_lon;
4093 GetCanvasPixPoint(mouse_x, mouse_y, cursor_lat, cursor_lon);
4095 if ((fabs(cursor_lat) < 90.) && (fabs(cursor_lon) < 360.)) {
4096 while (cursor_lon < -180.) cursor_lon += 360.;
4098 while (cursor_lon > 180.) cursor_lon -= 360.;
4100 SetCursorStatus(cursor_lat, cursor_lon);
4106 void ChartCanvas::SetCursorStatus(
double cursor_lat,
double cursor_lon) {
4107 if (!parent_frame->m_pStatusBar)
return;
4111 s1 += toSDMM(1, cursor_lat);
4113 s1 += toSDMM(2, cursor_lon);
4115 if (STAT_FIELD_CURSOR_LL >= 0)
4116 parent_frame->SetStatusText(s1, STAT_FIELD_CURSOR_LL);
4118 if (STAT_FIELD_CURSOR_BRGRNG < 0)
return;
4123 DistanceBearingMercator(cursor_lat, cursor_lon, gLat, gLon, &brg, &dist);
4125 sm.Printf(
"%03d%c(M) ", (
int)toMagnetic(brg), 0x00B0);
4127 st.Printf(
"%03d%c(T) ", (
int)brg, 0x00B0);
4129 wxString s = st + sm;
4130 s << FormatDistanceAdaptive(dist);
4142 if (g_bShowLiveETA) {
4145 float boatSpeedDefault = g_defaultBoatSpeed;
4150 if (!std::isnan(gSog)) {
4152 if (boatSpeed < 0.5) {
4155 realTimeETA = dist / boatSpeed * 60;
4164 s << minutesToHoursDays(realTimeETA);
4169 s << wxString::Format(_T(
"%d"), (
int)toUsrSpeed(boatSpeedDefault, -1));
4170 s << wxString::Format(_T(
"%s"), getUsrSpeedUnit(-1));
4172 s << minutesToHoursDays(dist / boatSpeedDefault * 60);
4177 parent_frame->SetStatusText(s, STAT_FIELD_CURSOR_BRGRNG);
4185 wxString minutesToHoursDays(
float timeInMinutes) {
4188 if (timeInMinutes == 0) {
4193 else if (timeInMinutes < 60 && timeInMinutes != 0) {
4194 s << wxString::Format(_T(
"%d"), (
int)timeInMinutes);
4199 else if (timeInMinutes >= 60 && timeInMinutes < 24 * 60) {
4202 hours = (int)timeInMinutes / 60;
4203 min = (int)timeInMinutes % 60;
4206 s << wxString::Format(_T(
"%d"), hours);
4209 s << wxString::Format(_T(
"%d"), hours);
4211 s << wxString::Format(_T(
"%d"), min);
4218 else if (timeInMinutes > 24 * 60) {
4221 days = (int)(timeInMinutes / 60) / 24;
4222 hours = (int)(timeInMinutes / 60) % 24;
4225 s << wxString::Format(_T(
"%d"), days);
4228 s << wxString::Format(_T(
"%d"), days);
4230 s << wxString::Format(_T(
"%d"), hours);
4242 void ChartCanvas::GetCursorLatLon(
double *lat,
double *lon) {
4244 GetCanvasPixPoint(mouse_x, mouse_y, clat, clon);
4249 void ChartCanvas::GetDoubleCanvasPointPix(
double rlat,
double rlon,
4250 wxPoint2DDouble *r) {
4251 return GetDoubleCanvasPointPixVP(GetVP(), rlat, rlon, r);
4254 void ChartCanvas::GetDoubleCanvasPointPixVP(
ViewPort &vp,
double rlat,
4255 double rlon, wxPoint2DDouble *r) {
4266 if (!g_bopengl && m_singleChart &&
4267 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4268 (((fabs(vp.rotation) < .0001) && (fabs(vp.skew) < .0001)) ||
4269 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4270 (m_singleChart->GetChartProjectionType() !=
4271 PROJECTION_TRANSVERSE_MERCATOR) &&
4272 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4273 (m_singleChart->GetChartProjectionType() == vp.m_projection_type) &&
4274 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4288 Cur_BSB_Ch->SetVPRasterParms(vp);
4289 double rpixxd, rpixyd;
4290 if (0 == Cur_BSB_Ch->latlong_to_pix_vp(rlat, rlon, rpixxd, rpixyd, vp)) {
4299 *r = vp.GetDoublePixFromLL(rlat, rlon);
4304 bool ChartCanvas::GetCanvasPointPix(
double rlat,
double rlon, wxPoint *r) {
4305 return GetCanvasPointPixVP(GetVP(), rlat, rlon, r);
4308 bool ChartCanvas::GetCanvasPointPixVP(
ViewPort &vp,
double rlat,
double rlon,
4311 GetDoubleCanvasPointPixVP(vp, rlat, rlon, &p);
4316 if (std::isnan(p.m_x)) {
4317 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4321 if( (abs(p.m_x) < 1e6) && (abs(p.m_y) < 1e6) )
4322 *r = wxPoint(wxRound(p.m_x), wxRound(p.m_y));
4324 *r = wxPoint(INVALID_COORD, INVALID_COORD);
4329 void ChartCanvas::GetCanvasPixPoint(
double x,
double y,
double &lat,
4343 if (!g_bopengl && m_singleChart &&
4344 (m_singleChart->GetChartFamily() == CHART_FAMILY_RASTER) &&
4345 (((fabs(GetVP().rotation) < .0001) && (fabs(GetVP().skew) < .0001)) ||
4346 ((m_singleChart->GetChartProjectionType() != PROJECTION_MERCATOR) &&
4347 (m_singleChart->GetChartProjectionType() !=
4348 PROJECTION_TRANSVERSE_MERCATOR) &&
4349 (m_singleChart->GetChartProjectionType() != PROJECTION_POLYCONIC))) &&
4350 (m_singleChart->GetChartProjectionType() == GetVP().m_projection_type) &&
4351 (m_singleChart->GetChartType() != CHART_TYPE_PLUGIN)) {
4362 Cur_BSB_Ch->SetVPRasterParms(GetVP());
4365 if (0 == Cur_BSB_Ch->vp_pix_to_latlong(GetVP(), x, y, &slat, &slon)) {
4370 else if (slon > 180.)
4381 GetVP().GetLLFromPix(wxPoint2DDouble(x, y), &lat, &lon);
4385 void ChartCanvas::ZoomCanvasSimple(
double factor) {
4386 DoZoomCanvas(factor,
false);
4387 extendedSectorLegs.clear();
4390 void ChartCanvas::ZoomCanvas(
double factor,
bool can_zoom_to_cursor,
4392 m_bzooming_to_cursor = can_zoom_to_cursor && g_bEnableZoomToCursor;
4394 if (g_bsmoothpanzoom) {
4395 if (StartTimedMovement(stoptimer)) {
4397 m_zoom_factor = factor;
4400 m_zoom_target = VPoint.chart_scale / factor;
4402 if (m_modkeys == wxMOD_ALT) factor = pow(factor, .15);
4404 DoZoomCanvas(factor, can_zoom_to_cursor);
4407 extendedSectorLegs.clear();
4410 void ChartCanvas::DoZoomCanvas(
double factor,
bool can_zoom_to_cursor) {
4412 if (!ChartData)
return;
4413 if (!m_pCurrentStack)
return;
4415 if (g_bShowCompassWin) {
4416 m_bShowCompassWin =
true;
4417 SetShowGPSCompassWindow(
true);
4424 if (m_bzooming)
return;
4427 double old_ppm = GetVP().view_scale_ppm;
4430 double zlat = m_cursor_lat;
4431 double zlon = m_cursor_lon;
4433 double proposed_scale_onscreen =
4434 GetVP().chart_scale /
4436 bool b_do_zoom =
false;
4445 if (!VPoint.b_quilt) {
4448 int new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4449 if (new_db_index >= 0)
4450 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4454 int current_ref_stack_index = -1;
4455 if (m_pCurrentStack->nEntry) {
4456 int trial_index = m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4457 m_pQuilt->SetReferenceChart(trial_index);
4458 new_db_index = m_pQuilt->AdjustRefOnZoomIn(proposed_scale_onscreen);
4459 if (new_db_index >= 0)
4460 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4464 if (m_pCurrentStack)
4465 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4475 double min_allowed_scale =
4478 if (proposed_scale_onscreen < min_allowed_scale) {
4479 if (min_allowed_scale == GetCanvasScaleFactor() / (GetVPScale())) {
4483 proposed_scale_onscreen = min_allowed_scale;
4487 proposed_scale_onscreen = wxMax(proposed_scale_onscreen, g_maxzoomin);
4490 }
else if (factor < 1) {
4495 bool b_smallest =
false;
4497 if (!VPoint.b_quilt) {
4502 LLBBox viewbox = VPoint.GetBBox();
4504 int current_index = ChartData->FinddbIndex(pc->GetFullPath());
4505 double max_allowed_scale;
4507 max_allowed_scale = GetCanvasScaleFactor() / m_absolute_min_scale_ppm;
4519 if (proposed_scale_onscreen > max_allowed_scale) {
4521 proposed_scale_onscreen = max_allowed_scale;
4526 int new_db_index = m_pQuilt->AdjustRefOnZoomOut(proposed_scale_onscreen);
4527 if (new_db_index >= 0)
4528 pc = ChartData->OpenChartFromDB(new_db_index, FULL_INIT);
4530 if (m_pCurrentStack)
4531 m_pCurrentStack->SetCurrentEntryFromdbIndex(
4534 b_smallest = m_pQuilt->IsChartSmallestScale(new_db_index);
4536 if (b_smallest || (0 == m_pQuilt->GetExtendedStackCount()))
4537 proposed_scale_onscreen =
4538 wxMin(proposed_scale_onscreen,
4539 GetCanvasScaleFactor() / m_absolute_min_scale_ppm);
4543 if ((GetCanvasScaleFactor() / proposed_scale_onscreen) <
4544 m_absolute_min_scale_ppm)
4549 GetVPScale() * (GetVP().chart_scale / proposed_scale_onscreen);
4552 if (can_zoom_to_cursor && g_bEnableZoomToCursor) {
4555 SetVPScale(new_scale,
false);
4558 GetCanvasPointPix(zlat, zlon, &r);
4559 PanCanvas(r.x - mouse_x, r.y - mouse_y);
4561 SetVPScale(new_scale);
4563 if (m_bFollow) DoCanvasUpdate();
4570 void ChartCanvas::RotateCanvas(
double dir) {
4573 if (g_bsmoothpanzoom) {
4574 if (StartTimedMovement()) {
4576 m_rotation_speed = dir * 60;
4579 double speed = dir * 10;
4580 if (m_modkeys == wxMOD_ALT) speed /= 20;
4581 DoRotateCanvas(VPoint.rotation + PI / 180 * speed);
4585 void ChartCanvas::DoRotateCanvas(
double rotation) {
4586 while (rotation < 0) rotation += 2 * PI;
4587 while (rotation > 2 * PI) rotation -= 2 * PI;
4589 if (rotation == VPoint.rotation || std::isnan(rotation))
return;
4591 SetVPRotation(rotation);
4592 parent_frame->UpdateRotationState(VPoint.rotation);
4595 void ChartCanvas::DoTiltCanvas(
double tilt) {
4596 while (tilt < 0) tilt = 0;
4597 while (tilt > .95) tilt = .95;
4599 if (tilt == VPoint.tilt || std::isnan(tilt))
return;
4605 void ChartCanvas::TogglebFollow(
void) {
4612 void ChartCanvas::ClearbFollow(
void) {
4615 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
false);
4617 UpdateFollowButtonState();
4621 parent_frame->SetChartUpdatePeriod();
4624 void ChartCanvas::SetbFollow(
void) {
4625 JumpToPosition(gLat, gLon, GetVPScale());
4628 parent_frame->SetMenubarItemState(ID_MENU_NAV_FOLLOW,
true);
4630 UpdateFollowButtonState();
4634 if ((fabs(m_OSoffsetx) > VPoint.pix_width / 2) ||
4635 (fabs(m_OSoffsety) > VPoint.pix_height / 2)) {
4642 parent_frame->SetChartUpdatePeriod();
4645 void ChartCanvas::UpdateFollowButtonState(
void) {
4648 m_muiBar->SetFollowButtonState(0);
4651 m_muiBar->SetFollowButtonState(2);
4653 m_muiBar->SetFollowButtonState(1);
4659 androidSetFollowTool(0);
4662 androidSetFollowTool(2);
4664 androidSetFollowTool(1);
4669 void ChartCanvas::JumpToPosition(
double lat,
double lon,
double scale_ppm) {
4670 if (lon > 180.0) lon -= 360.0;
4676 if (!GetQuiltMode()) {
4678 if (m_singleChart) skew = m_singleChart->GetChartSkew() * PI / 180.;
4679 SetViewPoint(lat, lon, scale_ppm, skew, GetVPRotation());
4681 if (scale_ppm != GetVPScale()) {
4683 VPoint.chart_scale = m_canvas_scale_factor / (scale_ppm);
4684 AdjustQuiltRefChart();
4686 SetViewPoint(lat, lon, scale_ppm, 0, GetVPRotation());
4691 UpdateFollowButtonState();
4699 bool ChartCanvas::PanCanvas(
double dx,
double dy) {
4700 if (!ChartData)
return false;
4702 extendedSectorLegs.clear();
4706 wxPoint2DDouble p(VPoint.pix_width / 2.0, VPoint.pix_height / 2.0);
4710 GetCanvasPixPoint(p.m_x + trunc(dx), p.m_y + trunc(dy), dlat, dlon);
4712 if (iters++ > 5)
return false;
4713 if (!std::isnan(dlat))
break;
4716 if (fabs(dx) < 1 && fabs(dy) < 1)
return false;
4722 else if (dlat < -90)
4725 if (dlon > 360.) dlon -= 360.;
4726 if (dlon < -360.) dlon += 360.;
4741 int cur_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4743 SetViewPoint(dlat, dlon, VPoint.view_scale_ppm, VPoint.skew, VPoint.rotation);
4745 if (VPoint.b_quilt) {
4746 int new_ref_dbIndex = m_pQuilt->GetRefChartdbIndex();
4747 if ((new_ref_dbIndex != cur_ref_dbIndex) && (new_ref_dbIndex != -1)) {
4749 ChartBase *pc = ChartData->OpenChartFromDB(new_ref_dbIndex, FULL_INIT);
4751 double tweak_scale_ppm =
4752 pc->GetNearestPreferredScalePPM(VPoint.view_scale_ppm);
4753 SetVPScale(tweak_scale_ppm);
4757 if(new_ref_dbIndex == -1) {
4762 int trial_index = -1;
4763 if (m_pCurrentStack->nEntry) {
4765 m_pCurrentStack->GetDBIndex(m_pCurrentStack->nEntry - 1);
4768 if (trial_index < 0) {
4769 auto full_screen_array = GetQuiltFullScreendbIndexArray();
4770 if (full_screen_array.size())
4771 trial_index = full_screen_array[full_screen_array.size()-1];
4774 if (trial_index >= 0){
4775 m_pQuilt->SetReferenceChart(trial_index);
4776 SetViewPoint(dlat, dlon, VPoint.view_scale_ppm, VPoint.skew, VPoint.rotation);
4784 toSM(dlat, dlon, gLat, gLon, &offx, &offy);
4786 double offset_angle = atan2(offy, offx);
4787 double offset_distance = sqrt((offy * offy) + (offx * offx));
4788 double chart_angle = GetVPRotation();
4789 double target_angle = chart_angle - offset_angle;
4790 double d_east_mod = offset_distance * cos(target_angle);
4791 double d_north_mod = offset_distance * sin(target_angle);
4793 m_OSoffsetx = d_east_mod * VPoint.view_scale_ppm;
4794 m_OSoffsety = -d_north_mod * VPoint.view_scale_ppm;
4799 if (m_bFollow && ((fabs(m_OSoffsetx) > VPoint.pix_width / 2) ||
4800 (fabs(m_OSoffsety) > VPoint.pix_height / 2))) {
4803 UpdateFollowButtonState();
4808 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
4813 void ChartCanvas::ReloadVP(
bool b_adjust) {
4814 if (g_brightness_init) SetScreenBrightness(g_nbrightness);
4816 LoadVP(VPoint, b_adjust);
4819 void ChartCanvas::LoadVP(
ViewPort &vp,
bool b_adjust) {
4821 if (g_bopengl && m_glcc) {
4822 m_glcc->Invalidate();
4823 if (m_glcc->GetSize() != GetSize()) {
4824 m_glcc->SetSize(GetSize());
4829 m_cache_vp.Invalidate();
4830 m_bm_cache_vp.Invalidate();
4833 VPoint.Invalidate();
4835 if (m_pQuilt) m_pQuilt->Invalidate();
4843 SetViewPoint(vp.clat, vp.clon, vp.view_scale_ppm, vp.skew, vp.rotation,
4844 vp.m_projection_type, b_adjust);
4848 void ChartCanvas::SetQuiltRefChart(
int dbIndex) {
4849 m_pQuilt->SetReferenceChart(dbIndex);
4850 VPoint.Invalidate();
4851 m_pQuilt->Invalidate();
4854 double ChartCanvas::GetBestStartScale(
int dbi_hint,
const ViewPort &vp) {
4856 return m_pQuilt->GetBestStartScale(dbi_hint, vp);
4858 return vp.view_scale_ppm;
4863 int ChartCanvas::AdjustQuiltRefChart() {
4866 wxASSERT(ChartData);
4868 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
4870 double min_ref_scale =
4871 pc->GetNormalScaleMin(m_canvas_scale_factor,
false);
4872 double max_ref_scale =
4873 pc->GetNormalScaleMax(m_canvas_scale_factor, m_canvas_width);
4875 if (VPoint.chart_scale < min_ref_scale) {
4876 ret = m_pQuilt->AdjustRefOnZoomIn(VPoint.chart_scale);
4877 }
else if (VPoint.chart_scale > max_ref_scale) {
4878 ret = m_pQuilt->AdjustRefOnZoomOut(VPoint.chart_scale);
4880 bool brender_ok = IsChartLargeEnoughToRender(pc, VPoint);
4882 int ref_family = pc->GetChartFamily();
4885 unsigned int target_stack_index = 0;
4886 int target_stack_index_check =
4887 m_pQuilt->GetExtendedStackIndexArray()
4888 [m_pQuilt->GetRefChartdbIndex()];
4890 if (wxNOT_FOUND != target_stack_index_check)
4891 target_stack_index = target_stack_index_check;
4893 int extended_array_count =
4894 m_pQuilt->GetExtendedStackIndexArray().size();
4895 while ((!brender_ok) &&
4896 ((
int)target_stack_index < (extended_array_count - 1))) {
4897 target_stack_index++;
4899 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
4901 if ((ref_family == ChartData->GetDBChartFamily(test_db_index)) &&
4902 IsChartQuiltableRef(test_db_index)) {
4905 ChartData->OpenChartFromDB(test_db_index, FULL_INIT);
4907 brender_ok = IsChartLargeEnoughToRender(ptest_chart, VPoint);
4914 m_pQuilt->GetExtendedStackIndexArray()[target_stack_index];
4915 if ((ref_family == ChartData->GetDBChartFamily(new_db_index)) &&
4916 IsChartQuiltableRef(new_db_index)) {
4917 m_pQuilt->SetReferenceChart(new_db_index);
4920 ret = m_pQuilt->GetRefChartdbIndex();
4922 ret = m_pQuilt->GetRefChartdbIndex();
4925 ret = m_pQuilt->GetRefChartdbIndex();
4934 void ChartCanvas::UpdateCanvasOnGroupChange(
void) {
4935 delete m_pCurrentStack;
4937 wxASSERT(ChartData);
4938 ChartData->BuildChartStack(m_pCurrentStack, VPoint.clat, VPoint.clon,
4947 bool ChartCanvas::SetViewPointByCorners(
double latSW,
double lonSW,
4948 double latNE,
double lonNE) {
4950 double latc = (latSW + latNE) / 2.0;
4951 double lonc = (lonSW + lonNE) / 2.0;
4954 double ne_easting, ne_northing;
4955 toSM(latNE, lonNE, latc, lonc, &ne_easting, &ne_northing);
4957 double sw_easting, sw_northing;
4958 toSM(latSW, lonSW, latc, lonc, &sw_easting, &sw_northing);
4960 double scale_ppm = VPoint.pix_height / fabs(ne_northing - sw_northing);
4962 return SetViewPoint(latc, lonc, scale_ppm, VPoint.skew, VPoint.rotation);
4965 bool ChartCanvas::SetVPScale(
double scale,
bool refresh) {
4966 return SetViewPoint(VPoint.clat, VPoint.clon,
scale, VPoint.skew,
4967 VPoint.rotation, VPoint.m_projection_type,
true, refresh);
4970 bool ChartCanvas::SetVPProjection(
int projection) {
4976 double prev_true_scale_ppm = m_true_scale_ppm;
4977 return SetViewPoint(VPoint.clat, VPoint.clon, VPoint.view_scale_ppm,
4978 VPoint.skew, VPoint.rotation, projection) &&
4980 VPoint.view_scale_ppm * prev_true_scale_ppm / m_true_scale_ppm,
4981 m_absolute_min_scale_ppm));
4984 bool ChartCanvas::SetViewPoint(
double lat,
double lon) {
4985 return SetViewPoint(lat, lon, VPoint.view_scale_ppm, VPoint.skew,
4989 bool ChartCanvas::SetVPRotation(
double angle) {
4990 return SetViewPoint(VPoint.clat, VPoint.clon, VPoint.view_scale_ppm, VPoint.skew,
4994 bool ChartCanvas::SetViewPoint(
double lat,
double lon,
double scale_ppm,
4995 double skew,
double rotation,
int projection,
4996 bool b_adjust,
bool b_refresh) {
5003 if (VPoint.IsValid()) {
5004 if ((fabs(VPoint.view_scale_ppm - scale_ppm) / scale_ppm < 1e-5) &&
5005 (fabs(VPoint.skew - skew) < 1e-9) &&
5006 (fabs(VPoint.rotation - rotation) < 1e-9) &&
5007 (fabs(VPoint.clat - lat) < 1e-9) && (fabs(VPoint.clon - lon) < 1e-9) &&
5008 (VPoint.m_projection_type == projection ||
5009 projection == PROJECTION_UNKNOWN))
5013 if (VPoint.m_projection_type != projection)
5014 VPoint.InvalidateTransformCache();
5022 VPoint.rotation = rotation;
5023 VPoint.view_scale_ppm = scale_ppm;
5024 if (projection != PROJECTION_UNKNOWN)
5025 VPoint.SetProjectionType(projection);
5026 else if (VPoint.m_projection_type == PROJECTION_UNKNOWN)
5027 VPoint.SetProjectionType(PROJECTION_MERCATOR);
5030 if (VPoint.m_projection_type == PROJECTION_MERCATOR ||
5031 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR) {
5032 if (VPoint.clat > 89.5)
5034 else if (VPoint.clat < -89.5)
5035 VPoint.clat = -89.5;
5040 if (VPoint.m_projection_type == PROJECTION_POLYCONIC ||
5041 VPoint.m_projection_type == PROJECTION_TRANSVERSE_MERCATOR)
5042 VPoint.view_scale_ppm = wxMax(VPoint.view_scale_ppm, 2e-4);
5049 if ((VPoint.pix_width <= 0) ||
5050 (VPoint.pix_height <= 0))
5053 bool bwasValid = VPoint.IsValid();
5057 if (last_vp.view_scale_ppm != scale_ppm) {
5058 m_cache_vp.Invalidate();
5063 VPoint.chart_scale = m_canvas_scale_factor / (scale_ppm);
5068 const wxPoint pt = wxGetMousePosition();
5069 int mouseX = pt.x - GetScreenPosition().x;
5070 int mouseY = pt.y - GetScreenPosition().y;
5071 if ((mouseX > 0) && (mouseX < VPoint.pix_width) && (mouseY > 0) &&
5072 (mouseY < VPoint.pix_height)) {
5074 GetCanvasPixPoint(mouseX, mouseY, lat, lon);
5077 if (g_pi_manager) g_pi_manager->SendCursorLatLonToAllPlugIns(lat, lon);
5080 if (!VPoint.b_quilt && m_singleChart) {
5085 if (b_adjust) m_singleChart->AdjustVP(last_vp, VPoint);
5089 if ((!m_cache_vp.IsValid()) ||
5090 (m_cache_vp.view_scale_ppm != VPoint.view_scale_ppm)) {
5094 wxPoint cp_last, cp_this;
5095 GetCanvasPointPix(m_cache_vp.clat, m_cache_vp.clon, &cp_last);
5096 GetCanvasPointPix(VPoint.clat, VPoint.clon, &cp_this);
5098 if (cp_last != cp_this) {
5104 if (m_pCurrentStack) {
5105 assert(ChartData != 0);
5106 int current_db_index;
5108 m_pCurrentStack->GetCurrentEntrydbIndex();
5110 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, current_db_index,
5112 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5115 if (!g_bopengl) VPoint.b_MercatorProjectionOverride =
false;
5119 if (VPoint.b_quilt) {
5120 if (last_vp.view_scale_ppm != scale_ppm)
5121 m_pQuilt->InvalidateAllQuiltPatchs();
5125 if (!m_pCurrentStack)
return false;
5127 int current_db_index;
5129 m_pCurrentStack->GetCurrentEntrydbIndex();
5131 ChartData->BuildChartStack(m_pCurrentStack, lat, lon, m_groupIndex);
5132 m_pCurrentStack->SetCurrentEntryFromdbIndex(current_db_index);
5135 int current_ref_stack_index = -1;
5136 for (
int i = 0; i < m_pCurrentStack->nEntry; i++) {
5137 if (m_pQuilt->GetRefChartdbIndex() == m_pCurrentStack->GetDBIndex(i))
5138 current_ref_stack_index = i;
5141 if (g_bFullScreenQuilt) {
5142 current_ref_stack_index = m_pQuilt->GetRefChartdbIndex();
5146 bool b_needNewRef =
false;
5149 if ((-1 == current_ref_stack_index) &&
5150 (m_pQuilt->GetRefChartdbIndex() >= 0))
5151 b_needNewRef =
true;
5158 bool renderable =
true;
5160 ChartData->OpenChartFromDB(m_pQuilt->GetRefChartdbIndex(), FULL_INIT);
5161 if (referenceChart) {
5162 double chartMaxScale = referenceChart->GetNormalScaleMax(
5163 GetCanvasScaleFactor(), GetCanvasWidth());
5164 renderable = chartMaxScale * 64 >= VPoint.chart_scale;
5166 if (!renderable) b_needNewRef =
true;
5171 ChartData->GetChartTableEntry(m_pQuilt->GetRefChartdbIndex());
5172 int target_scale = cte_ref.GetScale();
5173 int target_type = cte_ref.GetChartType();
5174 int candidate_stack_index;
5181 candidate_stack_index = 0;
5182 while (candidate_stack_index <= m_pCurrentStack->nEntry - 1) {
5184 m_pCurrentStack->GetDBIndex(candidate_stack_index));
5185 int candidate_scale = cte_candidate.GetScale();
5186 int candidate_type = cte_candidate.GetChartType();
5188 if ((candidate_scale >= target_scale) &&
5189 (candidate_type == target_type)) {
5190 bool renderable =
true;
5191 ChartBase *tentative_referenceChart = ChartData->OpenChartFromDB(
5192 m_pCurrentStack->GetDBIndex(candidate_stack_index), FULL_INIT);
5193 if (tentative_referenceChart) {
5194 double chartMaxScale =
5195 tentative_referenceChart->GetNormalScaleMax(
5196 GetCanvasScaleFactor(), GetCanvasWidth());
5197 renderable = chartMaxScale * 1.5 > VPoint.chart_scale;
5200 if (renderable)
break;
5203 candidate_stack_index++;
5208 if (candidate_stack_index >= m_pCurrentStack->nEntry) {
5209 candidate_stack_index = m_pCurrentStack->nEntry - 1;
5210 while (candidate_stack_index >= 0) {
5211 int idx = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5214 ChartData->GetChartTableEntry(idx);
5215 int candidate_scale = cte_candidate.GetScale();
5216 int candidate_type = cte_candidate.GetChartType();
5218 if ((candidate_scale <= target_scale) &&
5219 (candidate_type == target_type))
5222 candidate_stack_index--;
5227 if ((candidate_stack_index >= m_pCurrentStack->nEntry) ||
5228 (candidate_stack_index < 0))
5229 candidate_stack_index = 0;
5231 int new_ref_index = m_pCurrentStack->GetDBIndex(candidate_stack_index);
5233 m_pQuilt->SetReferenceChart(new_ref_index);
5239 int ref_db_index = m_pQuilt->GetRefChartdbIndex(), proj;
5244 bool renderable =
true;
5246 ChartData->OpenChartFromDB(ref_db_index, FULL_INIT);
5247 if (referenceChart) {
5248 double chartMaxScale = referenceChart->GetNormalScaleMax(
5249 GetCanvasScaleFactor(), GetCanvasWidth());
5250 renderable = chartMaxScale * 1.5 > VPoint.chart_scale;
5251 proj = ChartData->GetDBChartProj(ref_db_index);
5253 proj = PROJECTION_MERCATOR;
5255 VPoint.b_MercatorProjectionOverride =
5256 (m_pQuilt->GetnCharts() == 0 || !renderable);
5258 if (VPoint.b_MercatorProjectionOverride) proj = PROJECTION_MERCATOR;
5260 VPoint.SetProjectionType(proj);
5267 if (m_pQuilt->IsQuiltDelta(VPoint)) {
5271 if (b_adjust) m_pQuilt->AdjustQuiltVP(last_vp, VPoint);
5286 if ((last_vp.view_scale_ppm != scale_ppm) || !bwasValid) {
5290 m_pQuilt->Invalidate();
5305 ChartData->PurgeCacheUnusedCharts(0.7);
5307 if (b_refresh) Refresh(
false);
5314 }
else if (!g_bopengl) {
5315 OcpnProjType projection = PROJECTION_UNKNOWN;
5318 projection = m_singleChart->GetChartProjectionType();
5319 if (projection == PROJECTION_UNKNOWN) projection = PROJECTION_MERCATOR;
5320 VPoint.SetProjectionType(projection);
5324 if (last_vp.m_projection_type != VPoint.m_projection_type) {
5325 m_cache_vp.Invalidate();
5329 UpdateCanvasControlBar();
5331 VPoint.chart_scale = 1.0;
5335 if (VPoint.GetBBox().GetValid()) {
5338 VPoint.ref_scale = m_singleChart->GetNativeScale();
5346 if ((last_vp.view_scale_ppm != scale_ppm) || !bwasValid) {
5347 VPoint.ref_scale = m_pQuilt->GetRefNativeScale();
5350 VPoint.ref_scale = m_pQuilt->GetRefNativeScale();
5357 wxPoint2DDouble r, r1;
5359 double delta_check =
5360 (VPoint.pix_height / VPoint.view_scale_ppm) / (1852. * 60);
5363 double check_point = wxMin(89., VPoint.clat);
5365 while ((delta_check + check_point) > 90.) delta_check /= 2.;
5368 DistanceBearingMercator(check_point, VPoint.clon, check_point + delta_check,
5369 VPoint.clon, 0, &rhumbDist);
5371 GetDoubleCanvasPointPix(check_point, VPoint.clon, &r1);
5372 GetDoubleCanvasPointPix(check_point + delta_check, VPoint.clon, &r);
5373 double delta_p = sqrt(((r1.m_y - r.m_y) * (r1.m_y - r.m_y)) +
5374 ((r1.m_x - r.m_x) * (r1.m_x - r.m_x)));
5376 m_true_scale_ppm = delta_p / (rhumbDist * 1852);
5380 if (0.0 == m_true_scale_ppm) m_true_scale_ppm = scale_ppm;
5386 if (scale_ppm < 1e-4) m_true_scale_ppm = scale_ppm;
5388 if (m_true_scale_ppm)
5389 VPoint.chart_scale = m_canvas_scale_factor / (m_true_scale_ppm);
5391 VPoint.chart_scale = 1.0;
5394 double round_factor = 1000.;
5395 if (VPoint.chart_scale <= 1000.)
5397 else if (VPoint.chart_scale <= 10000.)
5398 round_factor = 100.;
5399 else if (VPoint.chart_scale <= 100000.)
5400 round_factor = 1000.;
5403 double retina_coef = 1;
5407 retina_coef = GetContentScaleFactor();;
5412 double true_scale_display =
5413 wxRound(VPoint.chart_scale / round_factor) * round_factor * retina_coef;
5416 m_displayed_scale_factor = VPoint.ref_scale / VPoint.chart_scale;
5418 if (m_displayed_scale_factor > 10.0)
5419 text.Printf(_T(
"%s %4.0f (%1.0fx)"), _(
"Scale"), true_scale_display,
5420 m_displayed_scale_factor);
5421 else if (m_displayed_scale_factor > 1.0)
5422 text.Printf(_T(
"%s %4.0f (%1.1fx)"), _(
"Scale"), true_scale_display,
5423 m_displayed_scale_factor);
5424 else if (m_displayed_scale_factor > 0.1) {
5425 double sfr = wxRound(m_displayed_scale_factor * 10.) / 10.;
5426 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5427 }
else if (m_displayed_scale_factor > 0.01) {
5428 double sfr = wxRound(m_displayed_scale_factor * 100.) / 100.;
5429 text.Printf(_T(
"%s %4.0f (%1.2fx)"), _(
"Scale"), true_scale_display, sfr);
5432 _T(
"%s %4.0f (---)"), _(
"Scale"),
5433 true_scale_display);
5436 m_scaleValue = true_scale_display;
5438 if (m_muiBar) m_muiBar->UpdateDynamicValues();
5440 if (m_bShowScaleInStatusBar && parent_frame->GetStatusBar() &&
5441 (parent_frame->GetStatusBar()->GetFieldsCount() > STAT_FIELD_SCALE)) {
5443 bool b_noshow =
false;
5447 wxClientDC dc(parent_frame->GetStatusBar());
5449 wxFont *templateFont = FontMgr::Get().GetFont(_(
"StatusBar"), 0);
5450 dc.SetFont(*templateFont);
5451 dc.GetTextExtent(text, &w, &h);
5456 parent_frame->GetStatusBar()->GetFieldRect(STAT_FIELD_SCALE, rect);
5457 if (w && w > rect.width) {
5458 text.Printf(_T(
"%s (%1.1fx)"), _(
"Scale"),
5459 m_displayed_scale_factor);
5463 dc.GetTextExtent(text, &w, &h);
5465 if (w && w > rect.width) {
5471 if (!b_noshow) parent_frame->SetStatusText(text, STAT_FIELD_SCALE);
5476 m_vLat = VPoint.clat;
5477 m_vLon = VPoint.clon;
5491 static int s_png_pred_icon[] = {-10, -10, -10, 10, 10, 10, 10, -10};
5495 static int s_ownship_icon[] = {5, -42, 11, -28, 11, 42, -11, 42, -11, -28,
5496 -5, -42, -11, 0, 11, 0, 0, 42, 0, -42};
5498 wxColour ChartCanvas::PredColor() {
5501 if (SHIP_NORMAL == m_ownship_state)
5502 return GetGlobalColor(_T (
"URED" ));
5504 else if (SHIP_LOWACCURACY == m_ownship_state)
5505 return GetGlobalColor(_T (
"YELO1" ));
5507 return GetGlobalColor(_T (
"NODTA" ));
5510 wxColour ChartCanvas::ShipColor() {
5514 if (SHIP_NORMAL != m_ownship_state)
return GetGlobalColor(_T (
"GREY1" ));
5516 if (SHIP_LOWACCURACY == m_ownship_state)
5517 return GetGlobalColor(_T (
"YELO1" ));
5519 return GetGlobalColor(_T (
"URED" ));
5522 void ChartCanvas::ShipDrawLargeScale(
ocpnDC &dc, wxPoint lShipMidPoint) {
5523 dc.SetPen(wxPen(PredColor(), 2));
5525 if (SHIP_NORMAL == m_ownship_state)
5526 dc.SetBrush(wxBrush(ShipColor(), wxBRUSHSTYLE_TRANSPARENT));
5528 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"YELO1" ))));
5530 dc.DrawEllipse(lShipMidPoint.x - 10, lShipMidPoint.y - 10, 20, 20);
5531 dc.DrawEllipse(lShipMidPoint.x - 6, lShipMidPoint.y - 6, 12, 12);
5533 dc.DrawLine(lShipMidPoint.x - 12, lShipMidPoint.y, lShipMidPoint.x + 12,
5535 dc.DrawLine(lShipMidPoint.x, lShipMidPoint.y - 12, lShipMidPoint.x,
5536 lShipMidPoint.y + 12);
5539 void ChartCanvas::ShipIndicatorsDraw(
ocpnDC &dc,
int img_height,
5540 wxPoint GPSOffsetPixels,
5541 wxPoint lGPSPoint) {
5545 float ref_dim = m_display_size_mm / 24;
5546 ref_dim = wxMin(ref_dim, 12);
5547 ref_dim = wxMax(ref_dim, 6);
5550 cPred.Set(g_cog_predictor_color);
5551 if(cPred == wxNullColour) cPred = PredColor();
5558 double nominal_line_width_pix = wxMax(
5560 floor(m_pix_per_mm / 2));
5564 if (nominal_line_width_pix > g_cog_predictor_width)
5565 g_cog_predictor_width = nominal_line_width_pix;
5568 wxPoint lPredPoint, lHeadPoint;
5570 float pCog = std::isnan(gCog) ? 0 : gCog;
5571 float pSog = std::isnan(gSog) ? 0 : gSog;
5573 double pred_lat, pred_lon;
5574 ll_gc_ll(gLat, gLon, pCog, pSog * g_ownship_predictor_minutes / 60.,
5575 &pred_lat, &pred_lon);
5576 GetCanvasPointPix(pred_lat, pred_lon, &lPredPoint);
5586 float ndelta_pix = 10.;
5587 double hdg_pred_lat, hdg_pred_lon;
5588 bool b_render_hdt =
false;
5589 if (!std::isnan(gHdt)) {
5591 ll_gc_ll(gLat, gLon, gHdt, g_ownship_HDTpredictor_miles, &hdg_pred_lat,
5593 GetCanvasPointPix(hdg_pred_lat, hdg_pred_lon, &lHeadPoint);
5594 float dist = sqrtf(powf((
float)(lHeadPoint.x - lPredPoint.x), 2) +
5595 powf((
float)(lHeadPoint.y - lPredPoint.y), 2));
5596 if (dist > ndelta_pix ) {
5597 box.SetFromSegment(gLat, gLon, hdg_pred_lat, hdg_pred_lon);
5598 if (!GetVP().GetBBox().IntersectOut(box)) b_render_hdt =
true;
5603 wxPoint lShipMidPoint;
5604 lShipMidPoint.x = lGPSPoint.x + GPSOffsetPixels.x;
5605 lShipMidPoint.y = lGPSPoint.y + GPSOffsetPixels.y;
5606 float lpp = sqrtf(powf((
float)(lPredPoint.x - lShipMidPoint.x), 2) +
5607 powf((
float)(lPredPoint.y - lShipMidPoint.y), 2));
5609 if (lpp >= img_height / 2) {
5610 box.SetFromSegment(gLat, gLon, pred_lat, pred_lon);
5611 if (!GetVP().GetBBox().IntersectOut(box) && !std::isnan(gCog) &&
5612 !std::isnan(gSog)) {
5614 float dash_length = ref_dim;
5615 wxDash dash_long[2];
5617 (int)(floor(g_Platform->GetDisplayDPmm() * dash_length) /
5618 g_cog_predictor_width);
5619 dash_long[1] = dash_long[0] / 2.0;
5623 if (dash_length > 250.) {
5624 dash_long[0] = 250. / g_cog_predictor_width;
5625 dash_long[1] = dash_long[0] / 2;
5628 wxPen ppPen2(cPred, g_cog_predictor_width, (wxPenStyle)g_cog_predictor_style);
5629 if(g_cog_predictor_style==(wxPenStyle)wxUSER_DASH)
5630 ppPen2.SetDashes(2, dash_long);
5633 lGPSPoint.x + GPSOffsetPixels.x, lGPSPoint.y + GPSOffsetPixels.y,
5634 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5636 if (g_cog_predictor_width > 1) {
5637 float line_width = g_cog_predictor_width / 3.;
5639 wxDash dash_long3[2];
5640 dash_long3[0] = g_cog_predictor_width / line_width * dash_long[0];
5641 dash_long3[1] = g_cog_predictor_width / line_width * dash_long[1];
5643 wxPen ppPen3(GetGlobalColor(_T (
"UBLCK" )), wxMax(1, line_width),
5644 (wxPenStyle)g_cog_predictor_style);
5645 if(g_cog_predictor_style==(wxPenStyle)wxUSER_DASH)
5646 ppPen3.SetDashes(2, dash_long3);
5649 lGPSPoint.x + GPSOffsetPixels.x, lGPSPoint.y + GPSOffsetPixels.y,
5650 lPredPoint.x + GPSOffsetPixels.x, lPredPoint.y + GPSOffsetPixels.y);
5653 if (g_cog_predictor_endmarker) {
5655 double png_pred_icon_scale_factor = .4;
5656 if (g_ShipScaleFactorExp > 1.0)
5657 png_pred_icon_scale_factor *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5659 png_pred_icon_scale_factor *= 1.0 / g_scaler;
5663 float cog_rad = atan2f((
float)(lPredPoint.y - lShipMidPoint.y),
5664 (
float)(lPredPoint.x - lShipMidPoint.x));
5665 cog_rad += (float)PI;
5667 for (
int i = 0; i < 4; i++) {
5669 double pxa = (double)(s_png_pred_icon[j]);
5670 double pya = (double)(s_png_pred_icon[j + 1]);
5672 pya *= png_pred_icon_scale_factor;
5673 pxa *= png_pred_icon_scale_factor;
5675 double px = (pxa * sin(cog_rad)) + (pya * cos(cog_rad));
5676 double py = (pya * sin(cog_rad)) - (pxa * cos(cog_rad));
5678 icon[i].x = (int)wxRound(px) + lPredPoint.x + GPSOffsetPixels.x;
5679 icon[i].y = (int)wxRound(py) + lPredPoint.y + GPSOffsetPixels.y;
5683 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), g_cog_predictor_width / 2,
5686 dc.SetBrush(wxBrush(cPred));
5688 dc.StrokePolygon(4, icon);
5695 float hdt_dash_length = ref_dim * 0.4;
5697 cPred.Set(g_ownship_HDTpredictor_color);
5698 if(cPred == wxNullColour) cPred = PredColor();
5699 float hdt_width = (g_ownship_HDTpredictor_width>0?g_ownship_HDTpredictor_width:g_cog_predictor_width * 0.8);
5700 wxDash dash_short[2];
5702 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length) /
5705 (int)(floor(g_Platform->GetDisplayDPmm() * hdt_dash_length * 0.9) /
5708 wxPen ppPen2(cPred, hdt_width,(wxPenStyle)g_ownship_HDTpredictor_style);
5709 if(g_ownship_HDTpredictor_style==(wxPenStyle)wxUSER_DASH)
5710 ppPen2.SetDashes(2, dash_short);
5714 lGPSPoint.x + GPSOffsetPixels.x, lGPSPoint.y + GPSOffsetPixels.y,
5715 lHeadPoint.x + GPSOffsetPixels.x, lHeadPoint.y + GPSOffsetPixels.y);
5717 wxPen ppPen1(cPred, g_cog_predictor_width / 3, wxPENSTYLE_SOLID);
5719 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"GREY2" ))));
5721 if (g_ownship_HDTpredictor_endmarker) {
5722 double nominal_circle_size_pixels = wxMax(
5723 4.0, floor(m_pix_per_mm * (ref_dim / 5.0)));
5726 if (g_ShipScaleFactorExp > 1.0)
5727 nominal_circle_size_pixels *= (log(g_ShipScaleFactorExp) + 1.0) * 1.1;
5729 dc.StrokeCircle(lHeadPoint.x + GPSOffsetPixels.x,
5730 lHeadPoint.y + GPSOffsetPixels.y,
5731 nominal_circle_size_pixels / 2);
5736 if (g_bNavAidRadarRingsShown && g_iNavAidRadarRingsNumberVisible > 0) {
5737 double factor = 1.00;
5738 if (g_pNavAidRadarRingsStepUnits == 1)
5740 else if (g_pNavAidRadarRingsStepUnits == 2){
5741 if (std::isnan(gSog))
5746 factor *= g_fNavAidRadarRingsStep;
5750 ll_gc_ll(gLat, gLon, 0, factor, &tlat, &tlon);
5751 GetCanvasPointPix(tlat, tlon, &r);
5753 double lpp = sqrt(pow((
double)(lGPSPoint.x - r.x), 2) +
5754 pow((
double)(lGPSPoint.y - r.y), 2));
5755 int pix_radius = (int)lpp;
5757 extern wxColor GetDimColor(wxColor c);
5758 wxColor rangeringcolour = GetDimColor(g_colourOwnshipRangeRingsColour);
5760 wxPen ppPen1(rangeringcolour, g_cog_predictor_width);
5763 dc.SetBrush(wxBrush(rangeringcolour, wxBRUSHSTYLE_TRANSPARENT));
5765 for (
int i = 1; i <= g_iNavAidRadarRingsNumberVisible; i++)
5766 dc.StrokeCircle(lGPSPoint.x, lGPSPoint.y, i * pix_radius);
5770 void ChartCanvas::ComputeShipScaleFactor(
5771 float icon_hdt,
int ownShipWidth,
int ownShipLength, wxPoint &lShipMidPoint,
5772 wxPoint &GPSOffsetPixels, wxPoint lGPSPoint,
float &scale_factor_x,
5773 float &scale_factor_y) {
5774 float screenResolution = m_pix_per_mm;
5777 double ship_bow_lat, ship_bow_lon;
5778 ll_gc_ll(gLat, gLon, icon_hdt, g_n_ownship_length_meters / 1852.,
5779 &ship_bow_lat, &ship_bow_lon);
5780 wxPoint lShipBowPoint;
5781 wxPoint2DDouble b_point =
5782 GetVP().GetDoublePixFromLL(ship_bow_lat, ship_bow_lon);
5783 wxPoint2DDouble a_point = GetVP().GetDoublePixFromLL(gLat, gLon);
5785 float shipLength_px = sqrtf(powf((
float)(b_point.m_x - a_point.m_x), 2) +
5786 powf((
float)(b_point.m_y - a_point.m_y), 2));
5789 float shipLength_mm = shipLength_px / screenResolution;
5792 float ownship_min_mm = g_n_ownship_min_mm;
5793 ownship_min_mm = wxMax(ownship_min_mm, 1.0);
5796 float hdt_ant = icon_hdt + 180.;
5797 float dy = (g_n_ownship_length_meters / 2 - g_n_gps_antenna_offset_y) / 1852.;
5798 float dx = g_n_gps_antenna_offset_x / 1852.;
5799 if (g_n_gps_antenna_offset_y > g_n_ownship_length_meters / 2)
5807 if (shipLength_mm < ownship_min_mm) {
5808 dy /= shipLength_mm / ownship_min_mm;
5809 dx /= shipLength_mm / ownship_min_mm;
5812 double ship_mid_lat, ship_mid_lon, ship_mid_lat1, ship_mid_lon1;
5814 ll_gc_ll(gLat, gLon, hdt_ant, dy, &ship_mid_lat, &ship_mid_lon);
5815 ll_gc_ll(ship_mid_lat, ship_mid_lon, icon_hdt - 90., dx, &ship_mid_lat1,
5818 GetCanvasPointPix(ship_mid_lat1, ship_mid_lon1, &lShipMidPoint);
5819 GPSOffsetPixels.x = lShipMidPoint.x - lGPSPoint.x;
5820 GPSOffsetPixels.y = lShipMidPoint.y - lGPSPoint.y;
5822 float scale_factor = shipLength_px / ownShipLength;
5825 float scale_factor_min = ownship_min_mm / (ownShipLength / screenResolution);
5828 scale_factor = wxMax(scale_factor, scale_factor_min);
5830 scale_factor_y = scale_factor;
5831 scale_factor_x = scale_factor_y * ((float)ownShipLength / ownShipWidth) /
5832 ((float)g_n_ownship_length_meters / g_n_ownship_beam_meters);
5835 void ChartCanvas::ShipDraw(
ocpnDC &dc) {
5836 if (!GetVP().IsValid())
return;
5838 wxPoint lGPSPoint, lShipMidPoint, GPSOffsetPixels(0, 0);
5841 float pCog = std::isnan(gCog) ? 0 : gCog;
5842 float pSog = std::isnan(gSog) ? 0 : gSog;
5844 GetCanvasPointPix(gLat, gLon, &lGPSPoint);
5845 lShipMidPoint = lGPSPoint;
5849 float icon_hdt = pCog;
5850 if (!std::isnan(gHdt)) icon_hdt = gHdt;
5853 if (std::isnan(icon_hdt)) icon_hdt = 0.0;
5857 double osd_head_lat, osd_head_lon;
5858 wxPoint osd_head_point;
5860 ll_gc_ll(gLat, gLon, icon_hdt, pSog * 10. / 60., &osd_head_lat,
5863 GetCanvasPointPix(osd_head_lat, osd_head_lon, &osd_head_point);
5865 float icon_rad = atan2f((
float)(osd_head_point.y - lShipMidPoint.y),
5866 (
float)(osd_head_point.x - lShipMidPoint.x));
5867 icon_rad += (float)PI;
5869 if (pSog < 0.2) icon_rad = ((icon_hdt + 90.) * PI / 180) + GetVP().rotation;
5873 BoundingBox bb_screen(0, 0, GetVP().pix_width, GetVP().pix_height);
5877 if (bb_screen.PointInBox(lShipMidPoint, 20)) {
5878 if (GetVP().chart_scale >
5881 ShipDrawLargeScale(dc, lShipMidPoint);
5887 if (m_pos_image_user)
5888 pos_image = m_pos_image_user->Copy();
5889 else if (SHIP_NORMAL == m_ownship_state)
5890 pos_image = m_pos_image_red->Copy();
5891 if (SHIP_LOWACCURACY == m_ownship_state)
5892 pos_image = m_pos_image_yellow->Copy();
5893 else if (SHIP_NORMAL != m_ownship_state)
5894 pos_image = m_pos_image_grey->Copy();
5897 if (m_pos_image_user) {
5898 pos_image = m_pos_image_user->Copy();
5900 if (SHIP_LOWACCURACY == m_ownship_state)
5901 pos_image = m_pos_image_user_yellow->Copy();
5902 else if (SHIP_NORMAL != m_ownship_state)
5903 pos_image = m_pos_image_user_grey->Copy();
5906 img_height = pos_image.GetHeight();
5908 if (g_n_ownship_beam_meters > 0.0 && g_n_ownship_length_meters > 0.0 &&
5909 g_OwnShipIconType > 0)
5911 int ownShipWidth = 22;
5912 int ownShipLength = 84;
5913 if (g_OwnShipIconType == 1) {
5914 ownShipWidth = pos_image.GetWidth();
5915 ownShipLength = pos_image.GetHeight();
5918 float scale_factor_x, scale_factor_y;
5919 ComputeShipScaleFactor(icon_hdt, ownShipWidth, ownShipLength,
5920 lShipMidPoint, GPSOffsetPixels, lGPSPoint,
5921 scale_factor_x, scale_factor_y);
5923 if (g_OwnShipIconType == 1) {
5924 pos_image.Rescale(ownShipWidth * scale_factor_x,
5925 ownShipLength * scale_factor_y,
5926 wxIMAGE_QUALITY_HIGH);
5927 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
5929 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
5932 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
5933 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
5934 if (rot_image.GetAlpha(ip, jp) > 64)
5935 rot_image.SetAlpha(ip, jp, 255);
5937 wxBitmap os_bm(rot_image);
5939 int w = os_bm.GetWidth();
5940 int h = os_bm.GetHeight();
5943 dc.DrawBitmap(os_bm, lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2,
5947 dc.CalcBoundingBox(lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2);
5948 dc.CalcBoundingBox(lShipMidPoint.x - w / 2 + w,
5949 lShipMidPoint.y - h / 2 + h);
5952 else if (g_OwnShipIconType == 2) {
5953 wxPoint ownship_icon[10];
5955 for (
int i = 0; i < 10; i++) {
5957 float pxa = (float)(s_ownship_icon[j]);
5958 float pya = (float)(s_ownship_icon[j + 1]);
5959 pya *= scale_factor_y;
5960 pxa *= scale_factor_x;
5962 float px = (pxa * sinf(icon_rad)) + (pya * cosf(icon_rad));
5963 float py = (pya * sinf(icon_rad)) - (pxa * cosf(icon_rad));
5965 ownship_icon[i].x = (int)(px) + lShipMidPoint.x;
5966 ownship_icon[i].y = (int)(py) + lShipMidPoint.y;
5969 wxPen ppPen1(GetGlobalColor(_T (
"UBLCK" )), 1, wxPENSTYLE_SOLID);
5971 dc.SetBrush(wxBrush(ShipColor()));
5973 dc.StrokePolygon(6, &ownship_icon[0], 0, 0);
5976 dc.StrokeLine(ownship_icon[6].x, ownship_icon[6].y, ownship_icon[7].x,
5978 dc.StrokeLine(ownship_icon[8].x, ownship_icon[8].y, ownship_icon[9].x,
5982 img_height = ownShipLength * scale_factor_y;
5986 if (m_pos_image_user) circle_rad = 1;
5988 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
5989 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
5990 dc.StrokeCircle(lGPSPoint.x, lGPSPoint.y, circle_rad);
5993 wxPoint rot_ctr(pos_image.GetWidth() / 2, pos_image.GetHeight() / 2);
5995 pos_image.Rotate(-(icon_rad - (PI / 2.)), rot_ctr,
true);
5998 for (
int ip = 0; ip < rot_image.GetWidth(); ip++)
5999 for (
int jp = 0; jp < rot_image.GetHeight(); jp++)
6000 if (rot_image.GetAlpha(ip, jp) > 64)
6001 rot_image.SetAlpha(ip, jp, 255);
6003 wxBitmap os_bm(rot_image);
6005 if (g_ShipScaleFactorExp > 1) {
6006 wxImage scaled_image = os_bm.ConvertToImage();
6007 double factor = (log(g_ShipScaleFactorExp) + 1.0) *
6009 os_bm = wxBitmap(scaled_image.Scale(scaled_image.GetWidth() * factor,
6010 scaled_image.GetHeight() * factor,
6011 wxIMAGE_QUALITY_HIGH));
6013 int w = os_bm.GetWidth();
6014 int h = os_bm.GetHeight();
6017 dc.DrawBitmap(os_bm, lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2,
6022 if (m_pos_image_user) circle_rad = 1;
6024 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" )), 1));
6025 dc.SetBrush(wxBrush(GetGlobalColor(_T (
"UIBCK" ))));
6026 dc.StrokeCircle(lShipMidPoint.x, lShipMidPoint.y, circle_rad);
6029 dc.CalcBoundingBox(lShipMidPoint.x - w / 2, lShipMidPoint.y - h / 2);
6030 dc.CalcBoundingBox(lShipMidPoint.x - w / 2 + w,
6031 lShipMidPoint.y - h / 2 + h);
6036 ShipIndicatorsDraw(dc, img_height, GPSOffsetPixels, lGPSPoint);
6049 void CalcGridSpacing(
float view_scale_ppm,
float &MajorSpacing,
6050 float &MinorSpacing) {
6055 const float lltab[][3] = {{0.0f, 90.0f, 30.0f},
6056 {.000001f, 45.0f, 15.0f},
6057 {.0002f, 30.0f, 10.0f},
6058 {.0003f, 10.0f, 2.0f},
6059 {.0008f, 5.0f, 1.0f},
6060 {.001f, 2.0f, 30.0f / 60.0f},
6061 {.003f, 1.0f, 20.0f / 60.0f},
6062 {.006f, 0.5f, 10.0f / 60.0f},
6063 {.03f, 15.0f / 60.0f, 5.0f / 60.0f},
6064 {.01f, 10.0f / 60.0f, 2.0f / 60.0f},
6065 {.06f, 5.0f / 60.0f, 1.0f / 60.0f},
6066 {.1f, 2.0f / 60.0f, 1.0f / 60.0f},
6067 {.4f, 1.0f / 60.0f, 0.5f / 60.0f},
6068 {.6f, 0.5f / 60.0f, 0.1f / 60.0f},
6069 {1.0f, 0.2f / 60.0f, 0.1f / 60.0f},
6070 {1e10f, 0.1f / 60.0f, 0.05f / 60.0f}};
6073 for (tabi = 0; tabi < ((
sizeof lltab) / (
sizeof *lltab)) - 1; tabi++)
6074 if (view_scale_ppm < lltab[tabi][0])
break;
6075 MajorSpacing = lltab[tabi][1];
6076 MinorSpacing = lltab[tabi][2];
6090 wxString CalcGridText(
float latlon,
float spacing,
bool bPostfix) {
6091 int deg = (int)fabs(latlon);
6092 float min = fabs((fabs(latlon) - deg) * 60.0);
6102 }
else if (latlon < 0.0) {
6114 if (spacing >= 1.0) {
6115 ret.Printf(_T(
"%3d%c %c"), deg, 0x00b0, postfix);
6116 }
else if (spacing >= (1.0 / 60.0)) {
6117 ret.Printf(_T(
"%3d%c%02.0f %c"), deg, 0x00b0, min, postfix);
6119 ret.Printf(_T(
"%3d%c%02.2f %c"), deg, 0x00b0, min, postfix);
6136 void ChartCanvas::GridDraw(
ocpnDC &dc) {
6137 if (!(m_bDisplayGrid && (fabs(GetVP().rotation) < 1e-5)))
return;
6139 double nlat, elon, slat, wlon;
6142 float gridlatMajor, gridlatMinor, gridlonMajor, gridlonMinor;
6144 wxPen GridPen(GetGlobalColor(_T (
"SNDG1" )), 1, wxPENSTYLE_SOLID);
6146 dc.SetFont(*m_pgridFont);
6147 dc.SetTextForeground(GetGlobalColor(_T (
"SNDG1" )));
6150 h = m_canvas_height;
6152 GetCanvasPixPoint(0, 0, nlat,
6154 GetCanvasPixPoint(w, h, slat,
6161 dlon = dlon + 360.0;
6164 CalcGridSpacing(GetVP().view_scale_ppm, gridlatMajor, gridlatMinor);
6167 lat = ceil(slat / gridlatMajor) * gridlatMajor;
6170 while (lat < nlat) {
6173 CalcGridText(lat, gridlatMajor,
true);
6174 GetCanvasPointPix(lat, (elon + wlon) / 2, &r);
6175 dc.DrawLine(0, r.y, w, r.y,
false);
6176 dc.DrawText(st, 0, r.y);
6177 lat = lat + gridlatMajor;
6179 if (fabs(lat - wxRound(lat)) < 1e-5) lat = wxRound(lat);
6183 lat = ceil(slat / gridlatMinor) * gridlatMinor;
6186 while (lat < nlat) {
6188 GetCanvasPointPix(lat, (elon + wlon) / 2, &r);
6189 dc.DrawLine(0, r.y, 10, r.y,
false);
6190 dc.DrawLine(w - 10, r.y, w, r.y,
false);
6191 lat = lat + gridlatMinor;
6195 CalcGridSpacing(GetVP().view_scale_ppm, gridlonMajor, gridlonMinor);
6198 lon = ceil(wlon / gridlonMajor) * gridlonMajor;
6201 for (
int i = 0, itermax = (
int)(dlon / gridlonMajor); i <= itermax; i++) {
6203 wxString st = CalcGridText(lon, gridlonMajor,
false);
6204 GetCanvasPointPix((nlat + slat) / 2, lon, &r);
6205 dc.DrawLine(r.x, 0, r.x, h,
false);
6206 dc.DrawText(st, r.x, 0);
6207 lon = lon + gridlonMajor;
6212 if (fabs(lon - wxRound(lon)) < 1e-5) lon = wxRound(lon);
6216 lon = ceil(wlon / gridlonMinor) * gridlonMinor;
6218 for (
int i = 0, itermax = (
int)(dlon / gridlonMinor); i <= itermax; i++) {
6220 GetCanvasPointPix((nlat + slat) / 2, lon, &r);
6221 dc.DrawLine(r.x, 0, r.x, 10,
false);
6222 dc.DrawLine(r.x, h - 10, r.x, h,
false);
6223 lon = lon + gridlonMinor;
6230 void ChartCanvas::ScaleBarDraw(
ocpnDC &dc) {
6232 double blat, blon, tlat, tlon;
6235 int x_origin = m_bDisplayGrid ? 60 : 20;
6236 int y_origin = m_canvas_height - 50;
6242 if (GetVP().chart_scale > 80000)
6246 pen1 = wxPen(GetGlobalColor(_T (
"SNDG2" )), 3, wxPENSTYLE_SOLID);
6247 pen2 = wxPen(GetGlobalColor(_T (
"SNDG1" )), 3, wxPENSTYLE_SOLID);
6252 pen1 = wxPen(GetGlobalColor(_T (
"SCLBR" )), 3, wxPENSTYLE_SOLID);
6253 pen2 = wxPen(GetGlobalColor(_T (
"CHGRD" )), 3, wxPENSTYLE_SOLID);
6256 GetCanvasPixPoint(x_origin, y_origin, blat, blon);
6257 double rotation = -VPoint.rotation;
6259 ll_gc_ll(blat, blon, rotation * 180 / PI, dist, &tlat, &tlon);
6260 GetCanvasPointPix(tlat, tlon, &r);
6261 int l1 = (y_origin - r.y) / count;
6263 for (
int i = 0; i < count; i++) {
6270 dc.DrawLine(x_origin, y_origin - y, x_origin, y_origin - (y + l1));
6273 double blat, blon, tlat, tlon;
6275 int x_origin = 5.0 * GetPixPerMM();
6276 int chartbar_height = GetChartbarHeight();
6280 int y_origin = m_canvas_height - chartbar_height - 5;
6283 y_origin = m_canvas_height/GetContentScaleFactor() - chartbar_height - 5;
6286 GetCanvasPixPoint(x_origin, y_origin, blat, blon);
6287 GetCanvasPixPoint(x_origin + m_canvas_width, y_origin, tlat, tlon);
6290 ll_gc_ll_reverse(blat, blon, tlat, tlon, 0, &d);
6293 int unit = g_iDistanceFormat;
6295 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI))
6296 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
6299 float dist = toUsrDistance(d,
unit), logdist = log(dist) / log(10.F);
6300 float places = floor(logdist), rem = logdist - places;
6301 dist = pow(10, places);
6308 wxString s = wxString::Format(_T(
"%g "), dist) + getUsrDistanceUnit(
unit);
6309 wxPen pen1 = wxPen(GetGlobalColor(_T (
"UBLCK" )), 3, wxPENSTYLE_SOLID);
6310 double rotation = -VPoint.rotation;
6312 ll_gc_ll(blat, blon, rotation * 180 / PI + 90, fromUsrDistance(dist,
unit),
6315 GetCanvasPointPix(tlat, tlon, &r);
6316 int l1 = r.x - x_origin;
6318 m_scaleBarRect = wxRect(x_origin, y_origin - 12, l1,
6323 dc.DrawLine(x_origin, y_origin, x_origin, y_origin - 12);
6324 dc.DrawLine(x_origin, y_origin, x_origin + l1, y_origin);
6325 dc.DrawLine(x_origin + l1, y_origin, x_origin + l1, y_origin - 12);
6327 dc.SetFont(*m_pgridFont);
6328 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
6330 dc.GetTextExtent(s, &w, &h);
6331 dc.DrawText(s, x_origin + l1 / 2 - w / 2, y_origin - h - 1);
6335 void ChartCanvas::JaggyCircle(
ocpnDC &dc, wxPen pen,
int x,
int y,
int radius) {
6340 double ra_max = 40.;
6342 wxPen pen_save = dc.GetPen();
6344 wxDateTime now = wxDateTime::Now();
6350 x0 = x1 = x + radius;
6355 while (angle < 360.) {
6356 double da = da_min + (((double)rand() / RAND_MAX) * (da_max - da_min));
6359 if (angle > 360.) angle = 360.;
6361 double ra = ra_min + (((double)rand() / RAND_MAX) * (ra_max - ra_min));
6369 x1 = (int)(x + cos(angle * PI / 180.) * r);
6370 y1 = (int)(y + sin(angle * PI / 180.) * r);
6372 dc.DrawLine(x0, y0, x1, y1);
6380 dc.DrawLine(x + radius, y, x1, y1);
6382 dc.SetPen(pen_save);
6385 static bool bAnchorSoundPlaying =
false;
6387 static void onAnchorSoundFinished(
void *ptr) {
6388 g_anchorwatch_sound->UnLoad();
6389 bAnchorSoundPlaying =
false;
6392 void ChartCanvas::AlertDraw(
ocpnDC &dc) {
6394 bool play_sound =
false;
6395 if (pAnchorWatchPoint1 && AnchorAlertOn1) {
6396 if (AnchorAlertOn1) {
6397 wxPoint TargetPoint;
6398 GetCanvasPointPix(pAnchorWatchPoint1->m_lat, pAnchorWatchPoint1->m_lon,
6400 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6401 TargetPoint.y, 100);
6405 AnchorAlertOn1 =
false;
6407 if (pAnchorWatchPoint2 && AnchorAlertOn2) {
6408 if (AnchorAlertOn2) {
6409 wxPoint TargetPoint;
6410 GetCanvasPointPix(pAnchorWatchPoint2->m_lat, pAnchorWatchPoint2->m_lon,
6412 JaggyCircle(dc, wxPen(GetGlobalColor(_T(
"URED")), 2), TargetPoint.x,
6413 TargetPoint.y, 100);
6417 AnchorAlertOn2 =
false;
6420 if(!bAnchorSoundPlaying) {
6421 auto cmd_sound =
dynamic_cast<SystemCmdSound*
>(g_anchorwatch_sound);
6422 if (cmd_sound) cmd_sound->SetCmd(g_CmdSoundString.mb_str(wxConvUTF8));
6423 g_anchorwatch_sound->Load(g_anchorwatch_sound_file);
6424 if (g_anchorwatch_sound->IsOk()) {
6425 bAnchorSoundPlaying =
true;
6426 g_anchorwatch_sound->SetFinishedCallback(onAnchorSoundFinished, NULL);
6427 g_anchorwatch_sound->Play();
6433 void ChartCanvas::UpdateShips() {
6436 wxClientDC dc(
this);
6437 if (!dc.IsOk())
return;
6439 wxBitmap test_bitmap(dc.GetSize().x, dc.GetSize().y);
6440 if (!test_bitmap.IsOk())
6443 wxMemoryDC temp_dc(test_bitmap);
6445 temp_dc.ResetBoundingBox();
6446 temp_dc.DestroyClippingRegion();
6447 temp_dc.SetClippingRegion(0, 0, dc.GetSize().x, dc.GetSize().y);
6453 if (g_pActiveTrack && g_pActiveTrack->IsRunning()) {
6454 TrackPoint *p = g_pActiveTrack->GetLastPoint();
6457 GetCanvasPointPix(p->m_lat, p->m_lon, &px);
6458 ocpndc.CalcBoundingBox(px.x, px.y);
6463 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6464 temp_dc.MaxY() - temp_dc.MinY());
6466 wxRect own_ship_update_rect = ship_draw_rect;
6468 if (!own_ship_update_rect.IsEmpty()) {
6471 own_ship_update_rect.Union(ship_draw_last_rect);
6472 own_ship_update_rect.Inflate(2);
6475 if (!own_ship_update_rect.IsEmpty()) RefreshRect(own_ship_update_rect,
false);
6477 ship_draw_last_rect = ship_draw_rect;
6479 temp_dc.SelectObject(wxNullBitmap);
6482 void ChartCanvas::UpdateAlerts() {
6487 wxClientDC dc(
this);
6491 dc.GetSize(&sx, &sy);
6494 wxBitmap test_bitmap(sx, sy, -1);
6498 temp_dc.SelectObject(test_bitmap);
6500 temp_dc.ResetBoundingBox();
6501 temp_dc.DestroyClippingRegion();
6502 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6509 wxRect alert_rect(temp_dc.MinX(), temp_dc.MinY(),
6510 temp_dc.MaxX() - temp_dc.MinX(),
6511 temp_dc.MaxY() - temp_dc.MinY());
6513 if (!alert_rect.IsEmpty())
6514 alert_rect.Inflate(2);
6516 if (!alert_rect.IsEmpty() || !alert_draw_rect.IsEmpty()) {
6519 wxRect alert_update_rect = alert_draw_rect;
6520 alert_update_rect.Union(alert_rect);
6523 RefreshRect(alert_update_rect,
false);
6527 alert_draw_rect = alert_rect;
6529 temp_dc.SelectObject(wxNullBitmap);
6532 void ChartCanvas::UpdateAIS() {
6533 if (!g_pAIS)
return;
6538 wxClientDC dc(
this);
6542 dc.GetSize(&sx, &sy);
6550 if (g_pAIS->GetTargetList().size() > 10) {
6551 ais_rect = wxRect(0, 0, sx, sy);
6554 wxBitmap test_bitmap(sx, sy, -1);
6558 temp_dc.SelectObject(test_bitmap);
6560 temp_dc.ResetBoundingBox();
6561 temp_dc.DestroyClippingRegion();
6562 temp_dc.SetClippingRegion(wxRect(0, 0, sx, sy));
6566 AISDraw(ocpndc, GetVP(),
this);
6567 AISDrawAreaNotices(ocpndc, GetVP(),
this);
6571 wxRect(temp_dc.MinX(), temp_dc.MinY(), temp_dc.MaxX() - temp_dc.MinX(),
6572 temp_dc.MaxY() - temp_dc.MinY());
6574 if (!ais_rect.IsEmpty())
6575 ais_rect.Inflate(2);
6577 temp_dc.SelectObject(wxNullBitmap);
6580 if (!ais_rect.IsEmpty() || !ais_draw_rect.IsEmpty()) {
6583 wxRect ais_update_rect = ais_draw_rect;
6584 ais_update_rect.Union(ais_rect);
6587 RefreshRect(ais_update_rect,
false);
6591 ais_draw_rect = ais_rect;
6594 void ChartCanvas::ToggleCPAWarn() {
6595 if (!g_AisFirstTimeUse) g_bCPAWarn = !g_bCPAWarn;
6601 g_bTCPA_Max =
false;
6605 if (STAT_FIELD_SCALE >= 4 && parent_frame->GetStatusBar()) {
6606 parent_frame->SetStatusText(_(
"CPA alarm ") + mess, STAT_FIELD_SCALE);
6608 if (!g_AisFirstTimeUse) {
6609 OCPNMessageBox(
this,
6610 _(
"CPA Alarm is switched") + _T(
" ") + mess.MakeLower(),
6611 _(
"CPA") + _T(
" ") + mess, 4, 4);
6616 void ChartCanvas::OnActivate(wxActivateEvent &event) { ReloadVP(); }
6618 void ChartCanvas::OnSize(wxSizeEvent &event) {
6619 if ((event.m_size.GetWidth() < 1) || (event.m_size.GetHeight() < 1))
6621 GetClientSize(&m_canvas_width, &m_canvas_height);
6625 m_displayScale = GetContentScaleFactor();
6629 m_canvas_width *= m_displayScale;
6630 m_canvas_height *= m_displayScale;
6633 VPoint.pix_width = m_canvas_width;
6634 VPoint.pix_height = m_canvas_height;
6640 SetVPScale(GetVPScale());
6642 m_absolute_min_scale_ppm =
6644 (1.2 * WGS84_semimajor_axis_meters * PI);
6647 gFrame->ProcessCanvasResize();
6657 SetMUIBarPosition();
6658 UpdateFollowButtonState();
6659 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6663 xr_margin = m_canvas_width * 95 / 100;
6664 xl_margin = m_canvas_width * 5 / 100;
6665 yt_margin = m_canvas_height * 5 / 100;
6666 yb_margin = m_canvas_height * 95 / 100;
6669 m_pQuilt->SetQuiltParameters(m_canvas_scale_factor, m_canvas_width);
6673 pscratch_bm =
new wxBitmap(VPoint.pix_width, VPoint.pix_height, -1);
6674 m_brepaint_piano =
true;
6677 m_dc_route.SelectObject(wxNullBitmap);
6679 proute_bm =
new wxBitmap(VPoint.pix_width, VPoint.pix_height, -1);
6680 m_dc_route.SelectObject(*proute_bm);
6683 m_cached_chart_bm.Create(VPoint.pix_width, VPoint.pix_height, -1);
6686 m_working_bm.Create(VPoint.pix_width, VPoint.pix_height, -1);
6689 SetVPScale(GetVPScale());
6694 m_glcc->OnSize(event);
6703 void ChartCanvas::ProcessNewGUIScale() {
6711 void ChartCanvas::CreateMUIBar() {
6712 if (g_useMUI && !m_muiBar) {
6716 if (ChartData) m_bENCGroup = ChartData->IsENCInGroup(m_groupIndex);
6718 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6719 m_muiBar->SetColorScheme(m_cs);
6720 m_muiBarHOSize = m_muiBar->m_size;
6724 SetMUIBarPosition();
6725 UpdateFollowButtonState();
6726 m_muiBar->UpdateDynamicValues();
6727 m_muiBar->SetCanvasENCAvailable(m_bENCGroup);
6731 void ChartCanvas::SetMUIBarPosition() {
6735 int pianoWidth = GetClientSize().x * 0.6f;
6740 if ((m_muiBar->GetOrientation() == wxHORIZONTAL)) {
6741 if (m_muiBarHOSize.x > (GetClientSize().x - pianoWidth)) {
6743 m_muiBar =
new MUIBar(
this, wxVERTICAL, g_toolbar_scalefactor);
6744 m_muiBar->SetColorScheme(m_cs);
6748 if ((m_muiBar->GetOrientation() == wxVERTICAL)) {
6749 if (m_muiBarHOSize.x < (GetClientSize().x - pianoWidth)) {
6751 m_muiBar =
new MUIBar(
this, wxHORIZONTAL, g_toolbar_scalefactor);
6752 m_muiBar->SetColorScheme(m_cs);
6756 m_muiBar->SetBestPosition();
6760 void ChartCanvas::DestroyMuiBar() {
6767 void ChartCanvas::ShowCompositeInfoWindow(
int x,
int n_charts,
int scale,
6768 const std::vector<int> &index_vector) {
6770 if (NULL == m_pCIWin) {
6775 if (!m_pCIWin->IsShown() || (m_pCIWin->chart_scale !=
scale)) {
6778 s = _(
"Composite of ");
6781 s1.Printf(
"%d ", n_charts);
6789 s1.Printf(_(
"Chart scale"));
6792 s2.Printf(
"1:%d\n",
scale);
6796 s1 = _(
"Zoom in for more information");
6800 int char_width = s1.Length();
6801 int char_height = 3;
6803 if (g_bChartBarEx) {
6806 for (
int i : index_vector ) {
6808 wxString path = cte.GetFullSystemPath();
6812 char_width = wxMax(char_width, path.Length());
6813 if (j++ >= 9)
break;
6816 s +=
" .\n .\n .\n";
6825 m_pCIWin->SetString(s);
6827 m_pCIWin->FitToChars(char_width, char_height);
6830 p.x = x / GetContentScaleFactor();
6831 if ((p.x + m_pCIWin->GetWinSize().x) >
6832 (m_canvas_width / GetContentScaleFactor()))
6833 p.x = ((m_canvas_width / GetContentScaleFactor()) -
6834 m_pCIWin->GetWinSize().x) /
6837 p.y = (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor() -
6838 4 - m_pCIWin->GetWinSize().y;
6840 m_pCIWin->dbIndex = 0;
6841 m_pCIWin->chart_scale = 0;
6842 m_pCIWin->SetPosition(p);
6843 m_pCIWin->SetBitmap();
6844 m_pCIWin->Refresh();
6848 HideChartInfoWindow();
6852 void ChartCanvas::ShowChartInfoWindow(
int x,
int dbIndex) {
6854 if (NULL == m_pCIWin) {
6859 if (!m_pCIWin->IsShown() || (m_pCIWin->dbIndex != dbIndex)) {
6866 if ((ChartData->IsChartInCache(dbIndex)) && ChartData->IsValid())
6867 pc = ChartData->OpenChartFromDBAndLock(
6868 dbIndex, FULL_INIT);
6870 int char_width, char_height;
6871 s = ChartData->GetFullChartInfo(pc, dbIndex, &char_width, &char_height);
6872 if (pc) ChartData->UnLockCacheChart(dbIndex);
6874 m_pCIWin->SetString(s);
6875 m_pCIWin->FitToChars(char_width, char_height);
6878 p.x = x / GetContentScaleFactor();
6879 if ((p.x + m_pCIWin->GetWinSize().x) > (m_canvas_width / GetContentScaleFactor()))
6880 p.x = ((m_canvas_width / GetContentScaleFactor())
6881 - m_pCIWin->GetWinSize().x) / 2;
6884 (m_canvas_height - m_Piano->GetHeight()) / GetContentScaleFactor()
6885 - 4 - m_pCIWin->GetWinSize().y;
6887 m_pCIWin->dbIndex = dbIndex;
6888 m_pCIWin->SetPosition(p);
6889 m_pCIWin->SetBitmap();
6890 m_pCIWin->Refresh();
6894 HideChartInfoWindow();
6898 void ChartCanvas::HideChartInfoWindow(
void) {
6901 m_pCIWin->Destroy();
6905 androidForceFullRepaint();
6910 void ChartCanvas::PanTimerEvent(wxTimerEvent &event) {
6911 wxMouseEvent ev(wxEVT_MOTION);
6914 ev.m_leftDown = mouse_leftisdown;
6916 wxEvtHandler *evthp = GetEventHandler();
6918 ::wxPostEvent(evthp, ev);
6921 void ChartCanvas::MovementTimerEvent(wxTimerEvent &) { DoTimedMovement(); }
6923 void ChartCanvas::MovementStopTimerEvent(wxTimerEvent &) { StopMovement(); }
6925 bool ChartCanvas::CheckEdgePan(
int x,
int y,
bool bdragging,
int margin,
6927 if (m_disable_edge_pan)
return false;
6930 int pan_margin = m_canvas_width * margin / 100;
6931 int pan_timer_set = 200;
6932 double pan_delta = GetVP().pix_width * delta / 100;
6936 if (x > m_canvas_width - pan_margin) {
6941 else if (x < pan_margin) {
6946 if (y < pan_margin) {
6951 else if (y > m_canvas_height - pan_margin) {
6960 wxMouseState state = ::wxGetMouseState();
6961 #if wxCHECK_VERSION(3, 0, 0)
6962 if (!state.LeftIsDown())
6964 if (!state.LeftDown())
6969 if ((bft) && !pPanTimer->IsRunning()) {
6970 PanCanvas(pan_x, pan_y);
6971 pPanTimer->Start(pan_timer_set, wxTIMER_ONE_SHOT);
6977 if ((!bft) && pPanTimer->IsRunning()) {
6987 void ChartCanvas::FindRoutePointsAtCursor(
float selectRadius,
6988 bool setBeingEdited) {
6989 m_lastRoutePointEditTarget = m_pRoutePointEditTarget;
6990 m_pRoutePointEditTarget = NULL;
6991 m_pFoundPoint = NULL;
6994 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
6995 SelectableItemList SelList = pSelect->FindSelectionList(
6996 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTEPOINT);
6997 wxSelectableItemListNode *node = SelList.GetFirst();
6999 pFind = node->GetData();
7004 m_pEditRouteArray = g_pRouteMan->GetRouteArrayContaining(frp);
7007 bool brp_viz =
false;
7008 if (m_pEditRouteArray) {
7009 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7010 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7011 if (pr->IsVisible()) {
7017 brp_viz = frp->IsVisible();
7021 if (m_pEditRouteArray)
7023 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
7024 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
7025 pr->m_bIsBeingEdited = setBeingEdited;
7027 m_bRouteEditing = setBeingEdited;
7030 frp->m_bRPIsBeingEdited = setBeingEdited;
7031 m_bMarkEditing = setBeingEdited;
7034 m_pRoutePointEditTarget = frp;
7035 m_pFoundPoint = pFind;
7039 node = node->GetNext();
7043 void ChartCanvas::MouseTimedEvent(wxTimerEvent &event) {
7044 if (singleClickEventIsValid) MouseEvent(singleClickEvent);
7045 singleClickEventIsValid =
false;
7046 m_DoubleClickTimer->Stop();
7051 bool ChartCanvas::MouseEventOverlayWindows(wxMouseEvent &event) {
7052 if (!m_bChartDragging && !m_bDrawingRoute) {
7053 if (m_Compass && m_Compass->IsShown() &&
7054 m_Compass->GetRect().Contains(event.GetPosition())) {
7055 if (m_Compass->MouseEvent(event)) {
7056 cursor_region = CENTER;
7057 if (!g_btouch) SetCanvasCursor(event);
7062 if (MouseEventToolbar(event))
7065 if (MouseEventChartBar(event))
7068 if (MouseEventMUIBar(event))
7071 if (MouseEventIENCBar(event))
7078 bool ChartCanvas::MouseEventChartBar(wxMouseEvent &event) {
7079 if (!g_bShowChartBar)
return false;
7081 if (!m_Piano->MouseEvent(event))
return false;
7083 cursor_region = CENTER;
7084 if (!g_btouch) SetCanvasCursor(event);
7088 bool ChartCanvas::MouseEventToolbar(wxMouseEvent &event) {
7089 if (!IsPrimaryCanvas())
7092 if (g_MainToolbar) {
7093 if (!g_MainToolbar->MouseEvent(event))
7096 g_MainToolbar->RefreshToolbar();
7099 cursor_region = CENTER;
7100 if (!g_btouch) SetCanvasCursor(event);
7104 bool ChartCanvas::MouseEventIENCBar(wxMouseEvent &event) {
7105 if (!IsPrimaryCanvas())
7108 if (g_iENCToolbar) {
7109 if (!g_iENCToolbar->MouseEvent(event))
7112 g_iENCToolbar->RefreshToolbar();
7119 bool ChartCanvas::MouseEventMUIBar(wxMouseEvent &event) {
7121 if (!m_muiBar->MouseEvent(event))
return false;
7124 cursor_region = CENTER;
7125 if (!g_btouch) SetCanvasCursor(event);
7134 event.GetPosition(&x, &y);
7136 x *= m_displayScale;
7137 y *= m_displayScale;
7139 m_MouseDragging =
event.Dragging();
7145 if (event.Dragging()) {
7146 if ((x == mouse_x) && (y == mouse_y))
return true;
7152 mouse_leftisdown =
event.LeftDown();
7153 GetCanvasPixPoint(x, y, m_cursor_lat, m_cursor_lon);
7156 cursor_region = CENTER;
7158 int chartbar_height = GetChartbarHeight();
7160 if (m_Compass && m_Compass->IsShown() &&
7161 m_Compass->GetRect().Contains(event.GetPosition())) {
7162 cursor_region = CENTER;
7163 }
else if (x > xr_margin) {
7164 cursor_region = MID_RIGHT;
7165 }
else if (x < xl_margin) {
7166 cursor_region = MID_LEFT;
7167 }
else if (y > yb_margin - chartbar_height &&
7168 y < m_canvas_height - chartbar_height) {
7169 cursor_region = MID_TOP;
7170 }
else if (y < yt_margin) {
7171 cursor_region = MID_BOT;
7173 cursor_region = CENTER;
7176 if (!g_btouch) SetCanvasCursor(event);
7180 leftIsDown =
event.LeftDown();
7183 if (event.LeftDown()) {
7184 if (g_bShowMenuBar ==
false && g_bTempShowMenuBar ==
true) {
7187 g_bTempShowMenuBar =
false;
7188 parent_frame->ApplyGlobalSettings(
false);
7196 if (event.ControlDown()) m_modkeys |= wxMOD_CONTROL;
7197 if (event.AltDown()) m_modkeys |= wxMOD_ALT;
7201 if (event.ButtonDown() && !HasCapture()) CaptureMouse();
7202 if (event.ButtonUp() && HasCapture()) ReleaseMouse();
7206 if (g_pi_manager->SendMouseEventToPlugins(event))
7212 if (b_handle_dclick && event.LeftUp() && !singleClickEventIsValid) {
7214 if (m_DoubleClickTimer->IsRunning()) {
7215 m_DoubleClickTimer->Stop();
7220 m_DoubleClickTimer->Start(350, wxTIMER_ONE_SHOT);
7221 singleClickEvent = event;
7222 singleClickEventIsValid =
true;
7231 if (event.LeftDown() || event.LeftUp() || event.Dragging()) {
7232 if (g_click_stop > 0) {
7240 if (GetUpMode() == COURSE_UP_MODE) {
7241 m_b_rot_hidef =
false;
7242 pRotDefTimer->Start(500, wxTIMER_ONE_SHOT);
7244 pRotDefTimer->Stop();
7247 bool bRoll = !g_btouch;
7249 bRoll = g_bRollover;
7252 if ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
7253 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
7254 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive()))
7255 m_RolloverPopupTimer.Start(
7259 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec, wxTIMER_ONE_SHOT);
7263 pCurTrackTimer->Start(m_curtrack_timer_msec, wxTIMER_ONE_SHOT);
7272 #if !defined(__WXGTK__) && !defined(__WXQT__)
7273 SetCursorStatus(m_cursor_lat, m_cursor_lon);
7280 if ((x >= 0) && (y >= 0))
7281 g_pi_manager->SendCursorLatLonToAllPlugIns(m_cursor_lat, m_cursor_lon);
7285 if ((m_bMeasure_Active && (m_nMeasureState >= 2)) || (m_routeState > 1)) {
7286 wxPoint p = ClientToScreen(wxPoint(x, y));
7292 if (m_routeState >= 2) {
7295 m_bDrawingRoute =
true;
7297 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7302 if (m_bMeasure_Active && (m_nMeasureState >= 2)) {
7305 m_bDrawingRoute =
true;
7307 if (!g_btouch) CheckEdgePan(x, y, event.Dragging(), 5, 2);
7314 void ChartCanvas::CallPopupMenu(
int x,
int y) {
7322 InvokeCanvasMenu(x, y, SELTYPE_ROUTECREATE);
7328 slat = m_cursor_lat;
7329 slon = m_cursor_lon;
7331 #if defined(__WXMAC__) || defined(__ANDROID__)
7335 wxClientDC cdc(GetParent());
7347 if (m_pSelectedRoute) {
7348 m_pSelectedRoute->m_bRtIsSelected =
false;
7349 m_pSelectedRoute->DeSelectRoute();
7351 if (g_bopengl && m_glcc) {
7356 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7359 if (m_pFoundRoutePoint) {
7360 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7362 RefreshRect(m_pFoundRoutePoint->CurrentRect_in_DC);
7367 if (g_btouch && m_pRoutePointEditTarget) {
7368 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7369 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7370 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7374 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7375 pFindAIS = pSelectAIS->FindSelection(ctx, slat, slon, SELTYPE_AISTARGET);
7376 pFindRP = pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7378 pSelect->FindSelection(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7380 pSelect->FindSelection(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7384 pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_CURRENTPOINT);
7387 pFindTide = pSelectTC->FindSelection(ctx, slat, slon, SELTYPE_TIDEPOINT);
7393 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7396 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI))
7397 seltype |= SELTYPE_AISTARGET;
7402 m_pFoundRoutePoint = NULL;
7407 Route *pSelectedActiveRoute = NULL;
7408 Route *pSelectedVizRoute = NULL;
7411 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7412 SelectableItemList SelList =
7413 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTEPOINT);
7414 wxSelectableItemListNode *node = SelList.GetFirst();
7421 wxArrayPtrVoid *proute_array = g_pRouteMan->GetRouteArrayContaining(prp);
7424 bool brp_viz =
false;
7426 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7428 if (pr->IsVisible()) {
7433 if (!brp_viz && prp->IsShared())
7435 brp_viz = prp->IsVisible();
7438 brp_viz = prp->IsVisible();
7440 if ((NULL == pFirstVizPoint) && brp_viz) pFirstVizPoint = prp;
7445 m_pSelectedRoute = NULL;
7447 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7449 if (pr->m_bRtIsActive) {
7450 pSelectedActiveRoute = pr;
7451 pFoundActiveRoutePoint = prp;
7456 if (NULL == pSelectedVizRoute) {
7457 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7459 if (pr->IsVisible()) {
7460 pSelectedVizRoute = pr;
7461 pFoundVizRoutePoint = prp;
7467 delete proute_array;
7470 node = node->GetNext();
7474 if (pFoundActiveRoutePoint) {
7475 m_pFoundRoutePoint = pFoundActiveRoutePoint;
7476 m_pSelectedRoute = pSelectedActiveRoute;
7477 }
else if (pFoundVizRoutePoint) {
7478 m_pFoundRoutePoint = pFoundVizRoutePoint;
7479 m_pSelectedRoute = pSelectedVizRoute;
7482 m_pFoundRoutePoint = pFirstVizPoint;
7484 if (m_pSelectedRoute) {
7485 if (m_pSelectedRoute->IsVisible()) seltype |= SELTYPE_ROUTEPOINT;
7486 }
else if (m_pFoundRoutePoint)
7487 seltype |= SELTYPE_MARKPOINT;
7491 if (m_pFoundRoutePoint) {
7492 m_pFoundRoutePoint->m_bPtIsSelected =
true;
7494 RoutePointGui(*m_pFoundRoutePoint).CalculateDCRect(m_dc_route,
this, &wp_rect);
7495 RefreshRect(wp_rect,
true);
7503 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7504 SelectableItemList SelList =
7505 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_ROUTESEGMENT);
7507 if (NULL == m_pSelectedRoute)
7510 wxSelectableItemListNode *node = SelList.GetFirst();
7515 if (pr->IsVisible()) {
7516 m_pSelectedRoute = pr;
7519 node = node->GetNext();
7523 if (m_pSelectedRoute) {
7524 if (NULL == m_pFoundRoutePoint)
7525 m_pFoundRoutePoint = (
RoutePoint *)pFindRouteSeg->m_pData1;
7527 m_pSelectedRoute->m_bRtIsSelected = !(seltype & SELTYPE_ROUTEPOINT);
7528 if (m_pSelectedRoute->m_bRtIsSelected) {
7530 if (g_bopengl && m_glcc) {
7535 RouteGui(*m_pSelectedRoute).Draw(dc,
this, GetVP().GetBBox());
7538 seltype |= SELTYPE_ROUTESEGMENT;
7542 if (pFindTrackSeg) {
7543 m_pSelectedTrack = NULL;
7544 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7545 SelectableItemList SelList =
7546 pSelect->FindSelectionList(ctx, slat, slon, SELTYPE_TRACKSEGMENT);
7549 wxSelectableItemListNode *node = SelList.GetFirst();
7554 if (pt->IsVisible()) {
7555 m_pSelectedTrack = pt;
7558 node = node->GetNext();
7561 if (m_pSelectedTrack) seltype |= SELTYPE_TRACKSEGMENT;
7564 bool bseltc =
false;
7577 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7578 SelectableItemList SelList = pSelectTC->FindSelectionList(
7579 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_CURRENTPOINT);
7582 wxSelectableItemListNode *node = SelList.GetFirst();
7583 pFind = node->GetData();
7584 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7586 if (SelList.GetCount() > 1) {
7587 node = node->GetNext();
7589 pFind = node->GetData();
7591 if (pIDX_candidate->IDX_type ==
'c') {
7592 pIDX_best_candidate = pIDX_candidate;
7596 node = node->GetNext();
7599 wxSelectableItemListNode *node = SelList.GetFirst();
7600 pFind = node->GetData();
7601 pIDX_best_candidate = (
IDX_entry *)(pFind->m_pData1);
7604 m_pIDXCandidate = pIDX_best_candidate;
7607 DrawTCWindow(x, y, (
void *)pIDX_best_candidate);
7611 seltype |= SELTYPE_CURRENTPOINT;
7614 else if (pFindTide) {
7615 m_pIDXCandidate = (
IDX_entry *)pFindTide->m_pData1;
7618 DrawTCWindow(x, y, (
void *)pFindTide->m_pData1);
7622 seltype |= SELTYPE_TIDEPOINT;
7626 if (0 == seltype) seltype |= SELTYPE_UNKNOWN;
7629 InvokeCanvasMenu(x, y, seltype);
7632 if (m_pSelectedRoute && g_pRouteMan->IsRouteValid(m_pSelectedRoute)) {
7633 m_pSelectedRoute->m_bRtIsSelected =
false;
7636 m_pSelectedRoute = NULL;
7638 if (m_pFoundRoutePoint) {
7639 if (pSelect->IsSelectableRoutePointValid(m_pFoundRoutePoint))
7640 m_pFoundRoutePoint->m_bPtIsSelected =
false;
7642 m_pFoundRoutePoint = NULL;
7650 bool ChartCanvas::MouseEventProcessObjects(wxMouseEvent &event) {
7652 if (std::isnan(m_cursor_lat))
return false;
7658 event.GetPosition(&x, &y);
7664 SelectRadius = g_Platform->GetSelectRadiusPix() /
7665 (m_true_scale_ppm * 1852 * 60);
7672 if (event.LeftDClick() && (cursor_region == CENTER)) {
7673 m_DoubleClickTimer->Start();
7674 singleClickEventIsValid =
false;
7677 GetCanvasPixPoint(x * g_current_monitor_dip_px_ratio, y * g_current_monitor_dip_px_ratio, zlat, zlon);
7679 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
7682 pFindAIS = pSelectAIS->FindSelection(ctx, zlat, zlon, SELTYPE_AISTARGET);
7685 m_FoundAIS_MMSI = pFindAIS->GetUserData();
7686 if (g_pAIS->Get_Target_Data_From_MMSI(m_FoundAIS_MMSI)) {
7687 wxWindow *pwin = wxDynamicCast(
this, wxWindow);
7688 ShowAISTargetQueryDialog(pwin, m_FoundAIS_MMSI);
7694 SelectableItemList rpSelList =
7695 pSelect->FindSelectionList(ctx, zlat, zlon, SELTYPE_ROUTEPOINT);
7696 wxSelectableItemListNode *node = rpSelList.GetFirst();
7697 bool b_onRPtarget =
false;
7701 if (m_pRoutePointEditTarget && (frp == m_pRoutePointEditTarget)) {
7702 b_onRPtarget =
true;
7705 node = node->GetNext();
7710 if (m_pRoutePointEditTarget) {
7712 ShowMarkPropertiesDialog(m_pRoutePointEditTarget);
7715 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
7716 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
7717 if (g_btouch)
RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
false);
7719 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this, &wp_rect);
7720 m_pRoutePointEditTarget = NULL;
7721 RefreshRect(wp_rect,
true);
7725 node = rpSelList.GetFirst();
7730 wxArrayPtrVoid *proute_array =
7731 g_pRouteMan->GetRouteArrayContaining(frp);
7735 bool brp_viz =
false;
7737 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7739 if (pr->IsVisible()) {
7747 brp_viz = frp->IsVisible();
7749 brp_viz = frp->IsVisible();
7752 ShowMarkPropertiesDialog(frp);
7760 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_ROUTESEGMENT);
7764 if (pr->IsVisible()) {
7765 ShowRoutePropertiesDialog(_(
"Route Properties"), pr);
7770 cursorItem = pSelect->FindSelection(ctx, zlat, zlon, SELTYPE_TRACKSEGMENT);
7774 if (pt->IsVisible()) {
7775 ShowTrackPropertiesDialog(pt);
7782 ShowObjectQueryWindow(x, y, zlat, zlon);
7787 if (event.LeftDown()) {
7803 bool appending =
false;
7804 bool inserting =
false;
7807 SetCursor(*pCursorPencil);
7808 rlat = m_cursor_lat;
7809 rlon = m_cursor_lon;
7811 m_bRouteEditing =
true;
7813 if (m_routeState == 1) {
7814 m_pMouseRoute =
new Route();
7815 pRouteList->Append(m_pMouseRoute);
7824 double nearby_radius_meters =
7825 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
7828 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
7829 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
7830 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
7831 wxArrayPtrVoid *proute_array =
7832 g_pRouteMan->GetRouteArrayContaining(pNearbyPoint);
7836 bool brp_viz =
false;
7838 for (
unsigned int ir = 0; ir < proute_array->GetCount(); ir++) {
7840 if (pr->IsVisible()) {
7846 pNearbyPoint->IsShared())
7849 pNearbyPoint->IsVisible();
7851 brp_viz = pNearbyPoint->IsVisible();
7854 m_FinishRouteOnKillFocus =
7856 int dlg_return = OCPNMessageBox(
7857 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
7858 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
7859 m_FinishRouteOnKillFocus =
true;
7861 if (dlg_return == wxID_YES) {
7862 pMousePoint = pNearbyPoint;
7865 if (m_routeState > 1)
7866 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
7867 Undo_HasParent, NULL);
7870 g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
7871 bool procede =
false;
7875 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
7881 m_FinishRouteOnKillFocus =
false;
7887 _(
"Insert first part of this route in the new route?");
7888 if (tail->GetIndexOf(pMousePoint) ==
7891 dmsg = _(
"Insert this route in the new route?");
7893 if (tail->GetIndexOf(pMousePoint) != 1) {
7894 dlg_return = OCPNMessageBox(
7895 this, dmsg, _(
"OpenCPN Route Create"),
7896 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
7897 m_FinishRouteOnKillFocus =
true;
7899 if (dlg_return == wxID_YES) {
7906 _(
"Append last part of this route to the new route?");
7907 if (tail->GetIndexOf(pMousePoint) == 1)
7909 "Append this route to the new route?");
7914 if (tail->GetLastPoint() != pMousePoint) {
7915 dlg_return = OCPNMessageBox(
7916 this, dmsg, _(
"OpenCPN Route Create"),
7917 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
7918 m_FinishRouteOnKillFocus =
true;
7920 if (dlg_return == wxID_YES) {
7931 if (!FindRouteContainingWaypoint(pMousePoint))
7932 pMousePoint->SetShared(
true);
7937 if (NULL == pMousePoint) {
7938 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
7939 _T(
""), wxEmptyString);
7940 pMousePoint->SetNameShown(
false);
7942 pConfig->AddNewWayPoint(pMousePoint, -1);
7943 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
7945 if (m_routeState > 1)
7946 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
7947 Undo_IsOrphanded, NULL);
7950 if (m_pMouseRoute) {
7951 if (m_routeState == 1) {
7953 m_pMouseRoute->AddPoint(pMousePoint);
7955 if (m_pMouseRoute->m_NextLegGreatCircle) {
7956 double rhumbBearing, rhumbDist, gcBearing, gcDist;
7957 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
7958 &rhumbBearing, &rhumbDist);
7959 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon,
7960 rlat, &gcDist, &gcBearing, NULL);
7961 double gcDistNM = gcDist / 1852.0;
7964 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
7965 pow(rhumbDist - gcDistNM - 1, 0.5);
7968 msg << _(
"For this leg the Great Circle route is ")
7969 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
7970 << _(
" shorter than rhumbline.\n\n")
7971 << _(
"Would you like include the Great Circle routing points "
7974 m_FinishRouteOnKillFocus =
false;
7975 m_disable_edge_pan =
true;
7978 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
7979 wxYES_NO | wxNO_DEFAULT);
7981 m_disable_edge_pan =
false;
7982 m_FinishRouteOnKillFocus =
true;
7984 if (answer == wxID_YES) {
7986 RoutePoint *prevGcPoint = m_prev_pMousePoint;
7987 wxRealPoint gcCoord;
7989 for (
int i = 1; i <= segmentCount; i++) {
7990 double fraction = (double)i * (1.0 / (
double)segmentCount);
7991 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
7992 gcDist * fraction, gcBearing,
7993 &gcCoord.x, &gcCoord.y, NULL);
7995 if (i < segmentCount) {
7996 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
7997 _T(
""), wxEmptyString);
7998 gcPoint->SetNameShown(
false);
7999 pConfig->AddNewWayPoint(gcPoint, -1);
8000 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8003 gcPoint = pMousePoint;
8006 m_pMouseRoute->AddPoint(gcPoint);
8007 pSelect->AddSelectableRouteSegment(
8008 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8009 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8010 prevGcPoint = gcPoint;
8013 undo->CancelUndoableAction(
true);
8016 m_pMouseRoute->AddPoint(pMousePoint);
8017 pSelect->AddSelectableRouteSegment(
8018 m_prev_rlat, m_prev_rlon, rlat, rlon, m_prev_pMousePoint,
8019 pMousePoint, m_pMouseRoute);
8020 undo->AfterUndoableAction(m_pMouseRoute);
8024 m_pMouseRoute->AddPoint(pMousePoint);
8025 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8026 rlon, m_prev_pMousePoint,
8027 pMousePoint, m_pMouseRoute);
8028 undo->AfterUndoableAction(m_pMouseRoute);
8034 m_prev_pMousePoint = pMousePoint;
8036 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8042 int connect = tail->GetIndexOf(pMousePoint);
8047 int length = tail->GetnPoints();
8052 start = connect + 1;
8057 m_pMouseRoute->RemovePoint(
8061 for (i = start; i <= stop; i++) {
8062 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8064 m_pMouseRoute->m_lastMousePointIndex =
8065 m_pMouseRoute->GetnPoints();
8067 gFrame->RefreshAllCanvas();
8071 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8073 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8074 m_pMouseRoute->FinalizeForRendering();
8076 gFrame->RefreshAllCanvas();
8080 else if (m_bMeasure_Active && (m_nMeasureState >= 1))
8082 SetCursor(*pCursorPencil);
8084 if (!m_pMeasureRoute) {
8085 m_pMeasureRoute =
new Route();
8086 pRouteList->Append(m_pMeasureRoute);
8089 if (m_nMeasureState == 1) {
8095 m_cursor_lat, m_cursor_lon, wxString(_T (
"circle" )),
8096 wxEmptyString, wxEmptyString);
8097 pMousePoint->m_bShowName =
false;
8098 pMousePoint->SetShowWaypointRangeRings(
false);
8100 m_pMeasureRoute->AddPoint(pMousePoint);
8102 m_prev_rlat = m_cursor_lat;
8103 m_prev_rlon = m_cursor_lon;
8104 m_prev_pMousePoint = pMousePoint;
8105 m_pMeasureRoute->m_lastMousePointIndex =
8106 m_pMeasureRoute->GetnPoints();
8109 gFrame->RefreshAllCanvas();
8114 FindRoutePointsAtCursor(SelectRadius,
true);
8119 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
8127 if (ret)
return true;
8130 if (event.Dragging()) {
8133 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8135 if (m_pRoutePointEditTarget && !m_bIsInRadius) {
8137 SelectableItemList SelList = pSelect->FindSelectionList(
8138 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTEPOINT);
8139 wxSelectableItemListNode *node = SelList.GetFirst();
8141 pFind = node->GetData();
8143 if (m_pRoutePointEditTarget == frp) m_bIsInRadius =
true;
8144 node = node->GetNext();
8149 if (m_pRoutePointEditTarget &&
8150 m_pRoutePointEditTarget->IsDragHandleEnabled()) {
8152 SelectableItemList SelList = pSelect->FindSelectionList(
8153 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_DRAGHANDLE);
8154 wxSelectableItemListNode *node = SelList.GetFirst();
8156 pFind = node->GetData();
8158 if (m_pRoutePointEditTarget == frp) {
8159 m_bIsInRadius =
true;
8162 node = node->GetNext();
8165 if (!m_dragoffsetSet) {
8166 RoutePointGui(*m_pRoutePointEditTarget).PresetDragOffset(
this, mouse_x, mouse_y);
8167 m_dragoffsetSet =
true;
8172 if (m_bRouteEditing && m_pRoutePointEditTarget) {
8173 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8175 if (NULL == g_pMarkInfoDialog) {
8176 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8177 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8178 DraggingAllowed =
false;
8180 if (m_pRoutePointEditTarget &&
8181 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8182 DraggingAllowed =
false;
8184 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8186 if (DraggingAllowed) {
8187 if (!undo->InUndoableAction()) {
8188 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8189 Undo_NeedsCopy, m_pFoundPoint);
8195 if (!g_bopengl && m_pEditRouteArray) {
8196 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
8197 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8202 if (g_pRouteMan->IsRouteValid(pr)) {
8204 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8205 pre_rect.Union(route_rect);
8210 double new_cursor_lat = m_cursor_lat;
8211 double new_cursor_lon = m_cursor_lon;
8213 if (CheckEdgePan(x, y,
true, 5, 2))
8214 GetCanvasPixPoint(x, y, new_cursor_lat, new_cursor_lon);
8220 RoutePointGui(*m_pRoutePointEditTarget).SetPointFromDraghandlePoint(
this, mouse_x,
8223 pSelect->ModifySelectablePoint(new_cursor_lat, new_cursor_lon,
8224 m_pRoutePointEditTarget,
8225 SELTYPE_DRAGHANDLE);
8226 m_pFoundPoint->m_slat =
8227 m_pRoutePointEditTarget->m_lat;
8228 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8230 m_pRoutePointEditTarget->m_lat =
8232 m_pRoutePointEditTarget->m_lon = new_cursor_lon;
8233 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8234 m_pFoundPoint->m_slat =
8236 m_pFoundPoint->m_slon = new_cursor_lon;
8240 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8241 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8242 g_pMarkInfoDialog->UpdateProperties(
true);
8252 if (m_pEditRouteArray) {
8253 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8255 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8256 if (g_pRouteMan->IsRouteValid(pr)) {
8258 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8259 post_rect.Union(route_rect);
8265 pre_rect.Union(post_rect);
8266 RefreshRect(pre_rect,
false);
8268 gFrame->RefreshCanvasOther(
this);
8269 m_bRoutePoinDragging =
true;
8274 else if (m_bMarkEditing && m_pRoutePointEditTarget) {
8275 bool DraggingAllowed = g_btouch ? m_bIsInRadius :
true;
8277 if (NULL == g_pMarkInfoDialog) {
8278 if (g_bWayPointPreventDragging) DraggingAllowed =
false;
8279 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8280 DraggingAllowed =
false;
8282 if (m_pRoutePointEditTarget &&
8283 (m_pRoutePointEditTarget->GetIconName() == _T(
"mob")))
8284 DraggingAllowed =
false;
8286 if (m_pRoutePointEditTarget->m_bIsInLayer) DraggingAllowed =
false;
8288 if (DraggingAllowed) {
8289 if (!undo->InUndoableAction()) {
8290 undo->BeforeUndoableAction(Undo_MoveWaypoint, m_pRoutePointEditTarget,
8291 Undo_NeedsCopy, m_pFoundPoint);
8299 if (pAnchorWatchPoint1 == m_pRoutePointEditTarget) {
8300 lpp1 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint1));
8302 if (pAnchorWatchPoint2 == m_pRoutePointEditTarget) {
8303 lpp2 = fabs(GetAnchorWatchRadiusPixels(pAnchorWatchPoint2));
8305 lppmax = wxMax(lpp1 + 10, lpp2 + 10);
8310 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this, &pre_rect);
8311 if ((lppmax > pre_rect.width / 2) || (lppmax > pre_rect.height / 2))
8312 pre_rect.Inflate((
int)(lppmax - (pre_rect.width / 2)),
8313 (
int)(lppmax - (pre_rect.height / 2)));
8320 RoutePointGui(*m_pRoutePointEditTarget).SetPointFromDraghandlePoint(
this, mouse_x,
8323 pSelect->ModifySelectablePoint(m_cursor_lat, m_cursor_lon,
8324 m_pRoutePointEditTarget,
8325 SELTYPE_DRAGHANDLE);
8326 m_pFoundPoint->m_slat =
8327 m_pRoutePointEditTarget->m_lat;
8328 m_pFoundPoint->m_slon = m_pRoutePointEditTarget->m_lon;
8330 m_pRoutePointEditTarget->m_lat =
8332 m_pRoutePointEditTarget->m_lon = m_cursor_lon;
8333 m_pRoutePointEditTarget->m_wpBBox.Invalidate();
8334 m_pFoundPoint->m_slat = m_cursor_lat;
8335 m_pFoundPoint->m_slon = m_cursor_lon;
8339 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown())) {
8340 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
8341 g_pMarkInfoDialog->UpdateProperties(
true);
8346 if (!g_btouch) InvalidateGL();
8351 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this,
8353 if ((lppmax > post_rect.width / 2) || (lppmax > post_rect.height / 2))
8354 post_rect.Inflate((
int)(lppmax - (post_rect.width / 2)),
8355 (
int)(lppmax - (post_rect.height / 2)));
8358 pre_rect.Union(post_rect);
8359 RefreshRect(pre_rect,
false);
8361 gFrame->RefreshCanvasOther(
this);
8362 m_bRoutePoinDragging =
true;
8367 if (ret)
return true;
8370 if (event.LeftUp()) {
8371 bool b_startedit_route =
false;
8372 m_dragoffsetSet =
false;
8375 m_bChartDragging =
false;
8376 m_bIsInRadius =
false;
8381 m_bedge_pan =
false;
8386 bool appending =
false;
8387 bool inserting =
false;
8390 rlat = m_cursor_lat;
8391 rlon = m_cursor_lon;
8393 if (m_pRoutePointEditTarget) {
8394 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8395 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
8399 .CalculateDCRect(m_dc_route,
this, &wp_rect);
8400 RefreshRect(wp_rect,
true);
8402 m_pRoutePointEditTarget = NULL;
8404 m_bRouteEditing =
true;
8406 if (m_routeState == 1) {
8407 m_pMouseRoute =
new Route();
8408 m_pMouseRoute->SetHiLite(50);
8409 pRouteList->Append(m_pMouseRoute);
8418 double nearby_radius_meters =
8419 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8422 pWayPointMan->GetNearbyWaypoint(rlat, rlon, nearby_radius_meters);
8423 if (pNearbyPoint && (pNearbyPoint != m_prev_pMousePoint) &&
8424 !pNearbyPoint->m_bIsInLayer && pNearbyPoint->IsVisible()) {
8427 m_FinishRouteOnKillFocus =
8429 dlg_return = OCPNMessageBox(
8430 this, _(
"Use nearby waypoint?"), _(
"OpenCPN Route Create"),
8431 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8432 m_FinishRouteOnKillFocus =
true;
8434 dlg_return = wxID_YES;
8436 if (dlg_return == wxID_YES) {
8437 pMousePoint = pNearbyPoint;
8440 if (m_routeState > 1)
8441 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8442 Undo_HasParent, NULL);
8443 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(pMousePoint);
8445 bool procede =
false;
8449 if (m_routeState > 1 && m_pMouseRoute && tail == m_pMouseRoute)
8455 m_FinishRouteOnKillFocus =
false;
8456 if (m_routeState == 1) {
8460 _(
"Insert first part of this route in the new route?");
8461 if (tail->GetIndexOf(pMousePoint) ==
8464 dmsg = _(
"Insert this route in the new route?");
8466 if (tail->GetIndexOf(pMousePoint) != 1) {
8468 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8469 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8470 m_FinishRouteOnKillFocus =
true;
8472 if (dlg_return == wxID_YES) {
8479 _(
"Append last part of this route to the new route?");
8480 if (tail->GetIndexOf(pMousePoint) == 1)
8482 "Append this route to the new route?");
8486 if (tail->GetLastPoint() != pMousePoint) {
8488 OCPNMessageBox(
this, dmsg, _(
"OpenCPN Route Create"),
8489 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8490 m_FinishRouteOnKillFocus =
true;
8492 if (dlg_return == wxID_YES) {
8503 if (!FindRouteContainingWaypoint(pMousePoint))
8504 pMousePoint->SetShared(
true);
8508 if (NULL == pMousePoint) {
8509 pMousePoint =
new RoutePoint(rlat, rlon, g_default_routepoint_icon,
8510 _T(
""), wxEmptyString);
8511 pMousePoint->SetNameShown(
false);
8513 pConfig->AddNewWayPoint(pMousePoint, -1);
8514 pSelect->AddSelectableRoutePoint(rlat, rlon, pMousePoint);
8516 if (m_routeState > 1)
8517 undo->BeforeUndoableAction(Undo_AppendWaypoint, pMousePoint,
8518 Undo_IsOrphanded, NULL);
8521 if (m_routeState == 1) {
8523 m_pMouseRoute->AddPoint(pMousePoint);
8525 if (m_pMouseRoute->m_NextLegGreatCircle) {
8526 double rhumbBearing, rhumbDist, gcBearing, gcDist;
8527 DistanceBearingMercator(rlat, rlon, m_prev_rlat, m_prev_rlon,
8528 &rhumbBearing, &rhumbDist);
8529 Geodesic::GreatCircleDistBear(m_prev_rlon, m_prev_rlat, rlon, rlat,
8530 &gcDist, &gcBearing, NULL);
8531 double gcDistNM = gcDist / 1852.0;
8534 int segmentCount = (3.0 + (rhumbDist - gcDistNM)) /
8535 pow(rhumbDist - gcDistNM - 1, 0.5);
8538 msg << _(
"For this leg the Great Circle route is ")
8539 << FormatDistanceAdaptive(rhumbDist - gcDistNM)
8540 << _(
" shorter than rhumbline.\n\n")
8541 << _(
"Would you like include the Great Circle routing points "
8545 m_FinishRouteOnKillFocus =
false;
8546 int answer = OCPNMessageBox(
this, msg, _(
"OpenCPN Route Create"),
8547 wxYES_NO | wxNO_DEFAULT);
8548 m_FinishRouteOnKillFocus =
true;
8550 int answer = wxID_NO;
8553 if (answer == wxID_YES) {
8555 RoutePoint *prevGcPoint = m_prev_pMousePoint;
8556 wxRealPoint gcCoord;
8558 for (
int i = 1; i <= segmentCount; i++) {
8559 double fraction = (double)i * (1.0 / (
double)segmentCount);
8560 Geodesic::GreatCircleTravel(m_prev_rlon, m_prev_rlat,
8561 gcDist * fraction, gcBearing,
8562 &gcCoord.x, &gcCoord.y, NULL);
8564 if (i < segmentCount) {
8565 gcPoint =
new RoutePoint(gcCoord.y, gcCoord.x, _T(
"xmblue"),
8566 _T(
""), wxEmptyString);
8567 gcPoint->SetNameShown(
false);
8568 pConfig->AddNewWayPoint(gcPoint, -1);
8569 pSelect->AddSelectableRoutePoint(gcCoord.y, gcCoord.x,
8572 gcPoint = pMousePoint;
8575 m_pMouseRoute->AddPoint(gcPoint);
8576 pSelect->AddSelectableRouteSegment(
8577 prevGcPoint->m_lat, prevGcPoint->m_lon, gcPoint->m_lat,
8578 gcPoint->m_lon, prevGcPoint, gcPoint, m_pMouseRoute);
8579 prevGcPoint = gcPoint;
8582 undo->CancelUndoableAction(
true);
8585 m_pMouseRoute->AddPoint(pMousePoint);
8586 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8587 rlon, m_prev_pMousePoint,
8588 pMousePoint, m_pMouseRoute);
8589 undo->AfterUndoableAction(m_pMouseRoute);
8593 m_pMouseRoute->AddPoint(pMousePoint);
8594 pSelect->AddSelectableRouteSegment(m_prev_rlat, m_prev_rlon, rlat,
8595 rlon, m_prev_pMousePoint,
8596 pMousePoint, m_pMouseRoute);
8597 undo->AfterUndoableAction(m_pMouseRoute);
8603 m_prev_pMousePoint = pMousePoint;
8604 m_pMouseRoute->m_lastMousePointIndex = m_pMouseRoute->GetnPoints();
8610 int connect = tail->GetIndexOf(pMousePoint);
8615 int length = tail->GetnPoints();
8620 start = connect + 1;
8625 m_pMouseRoute->RemovePoint(
8629 for (i = start; i <= stop; i++) {
8630 m_pMouseRoute->AddPointAndSegment(tail->GetPoint(i),
false);
8632 m_pMouseRoute->m_lastMousePointIndex =
8633 m_pMouseRoute->GetnPoints();
8635 gFrame->RefreshAllCanvas();
8639 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lat;
8641 m_pMouseRoute->GetPoint(m_pMouseRoute->GetnPoints())->m_lon;
8642 m_pMouseRoute->FinalizeForRendering();
8647 }
else if (m_bMeasure_Active && m_nMeasureState)
8650 m_bedge_pan =
false;
8654 if (m_nMeasureState == 1) {
8655 m_pMeasureRoute =
new Route();
8656 pRouteList->Append(m_pMeasureRoute);
8661 if (m_pMeasureRoute){
8663 wxString(_T (
"circle" )),
8664 wxEmptyString, wxEmptyString);
8665 pMousePoint->m_bShowName =
false;
8667 m_pMeasureRoute->AddPoint(pMousePoint);
8669 m_prev_rlat = m_cursor_lat;
8670 m_prev_rlon = m_cursor_lon;
8671 m_prev_pMousePoint = pMousePoint;
8672 m_pMeasureRoute->m_lastMousePointIndex = m_pMeasureRoute->GetnPoints();
8677 CancelMeasureRoute();
8683 bool bSelectAllowed =
true;
8684 if (NULL == g_pMarkInfoDialog) {
8685 if (g_bWayPointPreventDragging) bSelectAllowed =
false;
8686 }
else if (!g_pMarkInfoDialog->IsShown() && g_bWayPointPreventDragging)
8687 bSelectAllowed =
false;
8694 if (m_bRoutePoinDragging) bSelectAllowed =
false;
8696 if (bSelectAllowed) {
8697 bool b_was_editing_mark = m_bMarkEditing;
8698 bool b_was_editing_route = m_bRouteEditing;
8699 FindRoutePointsAtCursor(SelectRadius,
8705 if (m_pRoutePointEditTarget && m_pRoutePointEditTarget->m_bIsInLayer)
8706 m_pRoutePointEditTarget = NULL;
8708 if (!b_was_editing_route) {
8709 if (m_pEditRouteArray) {
8710 b_startedit_route =
true;
8714 if (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) {
8715 m_pTrackRolloverWin->IsActive(
false);
8717 if (m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) {
8718 m_pRouteRolloverWin->IsActive(
false);
8722 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8724 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8729 if (g_pRouteMan->IsRouteValid(pr)) {
8732 RouteGui(*pr).CalculateDCRect(m_dc_route,
this, &route_rect);
8733 pre_rect.Union(route_rect);
8736 RefreshRect(pre_rect,
true);
8739 b_startedit_route =
false;
8743 if (m_pRoutePointEditTarget) {
8744 if (b_was_editing_mark ||
8745 b_was_editing_route) {
8746 if (m_lastRoutePointEditTarget) {
8747 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8748 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
8749 RoutePointGui(*m_lastRoutePointEditTarget).EnableDragHandle(
false);
8750 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
8751 SELTYPE_DRAGHANDLE);
8755 if (m_pRoutePointEditTarget) {
8756 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
true;
8757 m_pRoutePointEditTarget->m_bPtIsSelected =
true;
8758 RoutePointGui(*m_pRoutePointEditTarget).EnableDragHandle(
true);
8759 wxPoint2DDouble dragHandlePoint =
8760 RoutePointGui(*m_pRoutePointEditTarget).GetDragHandlePoint(
this);
8761 pSelect->AddSelectablePoint(
8762 dragHandlePoint.m_y, dragHandlePoint.m_x,
8763 m_pRoutePointEditTarget, SELTYPE_DRAGHANDLE);
8766 if (m_lastRoutePointEditTarget) {
8767 m_lastRoutePointEditTarget->m_bRPIsBeingEdited =
false;
8768 m_lastRoutePointEditTarget->m_bPtIsSelected =
false;
8769 RoutePointGui(*m_lastRoutePointEditTarget).EnableDragHandle(
false);
8770 pSelect->DeleteSelectablePoint(m_lastRoutePointEditTarget,
8771 SELTYPE_DRAGHANDLE);
8774 wxArrayPtrVoid *lastEditRouteArray =
8775 g_pRouteMan->GetRouteArrayContaining(
8776 m_lastRoutePointEditTarget);
8777 if (lastEditRouteArray) {
8778 for (
unsigned int ir = 0; ir < lastEditRouteArray->GetCount();
8780 Route *pr = (
Route *)lastEditRouteArray->Item(ir);
8781 if (g_pRouteMan->IsRouteValid(pr)) {
8782 pr->m_bIsBeingEdited =
false;
8795 if (m_lastRoutePointEditTarget) {
8797 RoutePointGui(*m_lastRoutePointEditTarget).CalculateDCRect(m_dc_route,
this,
8799 RefreshRect(wp_rect,
true);
8802 if (m_pRoutePointEditTarget) {
8804 RoutePointGui(*m_pRoutePointEditTarget).CalculateDCRect(m_dc_route,
this,
8806 RefreshRect(wp_rect,
true);
8814 SelectCtx ctx(m_bShowNavobjects, GetCanvasTrueScale(), GetScaleValue());
8815 bool b_start_rollover =
false;
8816 if (g_pAIS && g_pAIS->GetNumTargets() && m_bShowAIS) {
8817 SelectItem *pFind = pSelectAIS->FindSelection(
8818 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_AISTARGET);
8819 if (pFind) b_start_rollover =
true;
8822 if (!b_start_rollover && !b_startedit_route) {
8823 SelectableItemList SelList = pSelect->FindSelectionList(
8824 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_ROUTESEGMENT);
8825 wxSelectableItemListNode *node = SelList.GetFirst();
8831 if (pr && pr->IsVisible()) {
8832 b_start_rollover =
true;
8835 node = node->GetNext();
8839 if (!b_start_rollover && !b_startedit_route) {
8840 SelectableItemList SelList = pSelect->FindSelectionList(
8841 ctx, m_cursor_lat, m_cursor_lon, SELTYPE_TRACKSEGMENT);
8842 wxSelectableItemListNode *node = SelList.GetFirst();
8848 if (tr && tr->IsVisible()) {
8849 b_start_rollover =
true;
8852 node = node->GetNext();
8856 if (b_start_rollover)
8857 m_RolloverPopupTimer.Start(m_rollover_popup_timer_msec,
8861 bool appending =
false;
8862 bool inserting =
false;
8864 if (m_bRouteEditing ) {
8866 if (m_pRoutePointEditTarget) {
8872 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
8873 double nearby_radius_meters =
8874 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
8875 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
8876 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
8877 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
8878 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
8879 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
8882 if (m_pEditRouteArray && !pNearbyPoint->m_bIsolatedMark) {
8883 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8885 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8886 if (pr && pr->pRoutePointList) {
8887 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
8900 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
8905 OCPNMessageBox(
this,
8906 _(
"Replace this RoutePoint by the nearby "
8908 _(
"OpenCPN RoutePoint change"),
8909 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8910 if (dlg_return == wxID_YES) {
8915 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
8917 current = FindRouteContainingWaypoint(
8918 m_pRoutePointEditTarget);
8920 if (tail && current && (tail != current)) {
8922 connect = tail->GetIndexOf(pNearbyPoint);
8923 int index_current_route =
8924 current->GetIndexOf(m_pRoutePointEditTarget);
8925 index_last = current->GetIndexOf(current->GetLastPoint());
8926 dlg_return1 = wxID_NO;
8928 index_current_route) {
8930 if (connect != tail->GetnPoints()) {
8933 _(
"Last part of route to be appended to dragged "
8937 _(
"Full route to be appended to dragged route?");
8939 dlg_return1 = OCPNMessageBox(
8940 this, dmsg, _(
"OpenCPN Route Create"),
8941 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8942 if (dlg_return1 == wxID_YES) {
8946 }
else if (index_current_route ==
8951 _(
"First part of route to be inserted into dragged "
8953 if (connect == tail->GetnPoints())
8955 "Full route to be inserted into dragged route?");
8957 dlg_return1 = OCPNMessageBox(
8958 this, dmsg, _(
"OpenCPN Route Create"),
8959 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8960 if (dlg_return1 == wxID_YES) {
8967 if (m_pRoutePointEditTarget->IsShared()) {
8969 dlg_return = OCPNMessageBox(
8971 _(
"Do you really want to delete and replace this "
8973 _T(
"\n") + _(
"which has been created manually?"),
8974 (
"OpenCPN RoutePoint warning"),
8975 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
8978 if (dlg_return == wxID_YES) {
8979 pMousePoint = pNearbyPoint;
8980 if (pMousePoint->m_bIsolatedMark) {
8981 pMousePoint->SetShared(
true);
8983 pMousePoint->m_bIsolatedMark =
8985 pMousePoint->m_bIsInRoute =
true;
8991 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
8993 if (m_pEditRouteArray) {
8994 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
8996 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
8997 if (g_pRouteMan->IsRouteValid(pr)) {
9001 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9003 pSelect->DeleteAllSelectableRoutePoints(pr);
9004 pSelect->DeleteAllSelectableRouteSegments(pr);
9006 pr->pRoutePointList->Insert(nRP, pMousePoint);
9007 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9009 pSelect->AddAllSelectableRouteSegments(pr);
9010 pSelect->AddAllSelectableRoutePoints(pr);
9012 pr->FinalizeForRendering();
9013 pr->UpdateSegmentDistances();
9014 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9020 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9021 if (m_pEditRouteArray) {
9022 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9024 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9025 if (g_pRouteMan->IsRouteValid(pr)) {
9026 if (pRoutePropDialog->GetRoute() == pr) {
9027 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9042 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9043 pWayPointMan->RemoveRoutePoint(m_pRoutePointEditTarget);
9045 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9046 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9047 g_pMarkInfoDialog->Hide();
9049 delete m_pRoutePointEditTarget;
9050 m_lastRoutePointEditTarget = NULL;
9051 m_pRoutePointEditTarget = NULL;
9052 undo->AfterUndoableAction(pMousePoint);
9053 undo->InvalidateUndo();
9058 else if (m_bMarkEditing) {
9059 if (m_pRoutePointEditTarget)
9060 if (m_bRoutePoinDragging)
9061 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9064 if (m_pRoutePointEditTarget)
9065 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9067 if (!m_pRoutePointEditTarget) {
9068 delete m_pEditRouteArray;
9069 m_pEditRouteArray = NULL;
9070 m_bRouteEditing =
false;
9072 m_bRoutePoinDragging =
false;
9079 int length = tail->GetnPoints();
9080 for (
int i = connect + 1; i <= length; i++) {
9081 current->AddPointAndSegment(tail->GetPoint(i),
false);
9082 if (current) current->m_lastMousePointIndex = current->GetnPoints();
9084 gFrame->RefreshAllCanvas();
9087 current->FinalizeForRendering();
9088 current->m_bIsBeingEdited =
false;
9090 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9093 pSelect->DeleteAllSelectableRoutePoints(current);
9094 pSelect->DeleteAllSelectableRouteSegments(current);
9095 for (
int i = 1; i < connect; i++) {
9096 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9098 pSelect->AddAllSelectableRouteSegments(current);
9099 pSelect->AddAllSelectableRoutePoints(current);
9100 current->FinalizeForRendering();
9101 current->m_bIsBeingEdited =
false;
9102 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9106 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9107 if (m_pEditRouteArray) {
9108 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount(); ir++) {
9109 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9110 if (g_pRouteMan->IsRouteValid(pr)) {
9111 if (pRoutePropDialog->GetRoute() == pr) {
9112 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9122 if (m_bRouteEditing) {
9125 bool appending =
false;
9126 bool inserting =
false;
9129 if (m_pRoutePointEditTarget) {
9130 m_pRoutePointEditTarget->m_bBlink =
false;
9134 if (m_bRoutePoinDragging && !m_pRoutePointEditTarget->m_bIsActive) {
9135 double nearby_radius_meters =
9136 g_Platform->GetSelectRadiusPix() / m_true_scale_ppm;
9137 RoutePoint *pNearbyPoint = pWayPointMan->GetOtherNearbyWaypoint(
9138 m_pRoutePointEditTarget->m_lat, m_pRoutePointEditTarget->m_lon,
9139 nearby_radius_meters, m_pRoutePointEditTarget->m_GUID);
9140 if (pNearbyPoint && !pNearbyPoint->m_bIsInLayer &&
9141 pWayPointMan->IsReallyVisible(pNearbyPoint)) {
9142 bool duplicate =
false;
9143 if (m_pEditRouteArray && !pNearbyPoint->m_bIsolatedMark) {
9144 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9146 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9147 if (pr && pr->pRoutePointList) {
9148 if (pr->pRoutePointList->IndexOf(pNearbyPoint) !=
9161 if (m_pEditRouteArray->GetCount() == 1) duplicate =
false;
9166 OCPNMessageBox(
this,
9167 _(
"Replace this RoutePoint by the nearby "
9169 _(
"OpenCPN RoutePoint change"),
9170 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9171 if (dlg_return == wxID_YES) {
9175 tail = g_pRouteMan->FindVisibleRouteContainingWaypoint(
9177 current = FindRouteContainingWaypoint(
9178 m_pRoutePointEditTarget);
9180 if (tail && current && (tail != current)) {
9182 connect = tail->GetIndexOf(pNearbyPoint);
9183 int index_current_route =
9184 current->GetIndexOf(m_pRoutePointEditTarget);
9185 index_last = current->GetIndexOf(current->GetLastPoint());
9186 dlg_return1 = wxID_NO;
9188 index_current_route) {
9190 if (connect != tail->GetnPoints()) {
9193 _(
"Last part of route to be appended to dragged "
9197 _(
"Full route to be appended to dragged route?");
9199 dlg_return1 = OCPNMessageBox(
9200 this, dmsg, _(
"OpenCPN Route Create"),
9201 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9202 if (dlg_return1 == wxID_YES) {
9206 }
else if (index_current_route ==
9211 _(
"First part of route to be inserted into dragged "
9213 if (connect == tail->GetnPoints())
9215 "Full route to be inserted into dragged route?");
9217 dlg_return1 = OCPNMessageBox(
9218 this, dmsg, _(
"OpenCPN Route Create"),
9219 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9220 if (dlg_return1 == wxID_YES) {
9227 if (m_pRoutePointEditTarget->IsShared()) {
9228 dlg_return = wxID_NO;
9229 dlg_return = OCPNMessageBox(
9231 _(
"Do you really want to delete and replace this "
9233 _T(
"\n") + _(
"which has been created manually?"),
9234 (
"OpenCPN RoutePoint warning"),
9235 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
9238 if (dlg_return == wxID_YES) {
9239 pMousePoint = pNearbyPoint;
9240 if (pMousePoint->m_bIsolatedMark) {
9241 pMousePoint->SetShared(
true);
9243 pMousePoint->m_bIsolatedMark =
9245 pMousePoint->m_bIsInRoute =
true;
9251 pSelect->UpdateSelectableRouteSegments(m_pRoutePointEditTarget);
9253 if (m_pEditRouteArray) {
9254 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9256 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9257 if (g_pRouteMan->IsRouteValid(pr)) {
9260 pr->pRoutePointList->IndexOf(m_pRoutePointEditTarget);
9262 pSelect->DeleteAllSelectableRoutePoints(pr);
9263 pSelect->DeleteAllSelectableRouteSegments(pr);
9265 pr->pRoutePointList->Insert(nRP, pMousePoint);
9266 pr->pRoutePointList->DeleteObject(m_pRoutePointEditTarget);
9268 pSelect->AddAllSelectableRouteSegments(pr);
9269 pSelect->AddAllSelectableRoutePoints(pr);
9271 pr->FinalizeForRendering();
9272 pr->UpdateSegmentDistances();
9273 pr->m_bIsBeingEdited =
false;
9275 if (m_bRoutePoinDragging) pConfig->UpdateRoute(pr);
9287 int length = tail->GetnPoints();
9288 for (
int i = connect + 1; i <= length; i++) {
9289 current->AddPointAndSegment(tail->GetPoint(i),
false);
9291 current->m_lastMousePointIndex = current->GetnPoints();
9293 gFrame->RefreshAllCanvas();
9296 current->FinalizeForRendering();
9297 current->m_bIsBeingEdited =
false;
9299 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9302 pSelect->DeleteAllSelectableRoutePoints(current);
9303 pSelect->DeleteAllSelectableRouteSegments(current);
9304 for (
int i = 1; i < connect; i++) {
9305 current->InsertPointAndSegment(tail->GetPoint(i), i - 1,
false);
9307 pSelect->AddAllSelectableRouteSegments(current);
9308 pSelect->AddAllSelectableRoutePoints(current);
9309 current->FinalizeForRendering();
9310 current->m_bIsBeingEdited =
false;
9311 g_pRouteMan->
DeleteRoute(tail, NavObjectChanges::getInstance());
9315 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
9316 if (m_pEditRouteArray) {
9317 for (
unsigned int ir = 0; ir < m_pEditRouteArray->GetCount();
9319 Route *pr = (
Route *)m_pEditRouteArray->Item(ir);
9320 if (g_pRouteMan->IsRouteValid(pr)) {
9321 if (pRoutePropDialog->GetRoute() == pr) {
9322 pRoutePropDialog->SetRouteAndUpdate(pr,
true);
9330 pConfig->DeleteWayPoint(m_pRoutePointEditTarget);
9331 pWayPointMan->RemoveRoutePoint(m_pRoutePointEditTarget);
9333 if ((NULL != g_pMarkInfoDialog) && (g_pMarkInfoDialog->IsShown()))
9334 if (m_pRoutePointEditTarget == g_pMarkInfoDialog->GetRoutePoint())
9335 g_pMarkInfoDialog->Hide();
9337 delete m_pRoutePointEditTarget;
9338 m_lastRoutePointEditTarget = NULL;
9339 undo->AfterUndoableAction(pMousePoint);
9340 undo->InvalidateUndo();
9342 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9343 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9345 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9348 delete m_pEditRouteArray;
9349 m_pEditRouteArray = NULL;
9353 m_bRouteEditing =
false;
9354 m_pRoutePointEditTarget = NULL;
9360 else if (m_bMarkEditing) {
9361 if (m_pRoutePointEditTarget) {
9362 if (m_bRoutePoinDragging)
9363 pConfig->UpdateWayPoint(m_pRoutePointEditTarget);
9364 undo->AfterUndoableAction(m_pRoutePointEditTarget);
9365 m_pRoutePointEditTarget->m_bRPIsBeingEdited =
false;
9369 .CalculateDCRect(m_dc_route,
this, &wp_rect);
9370 m_pRoutePointEditTarget->m_bPtIsSelected =
false;
9371 RefreshRect(wp_rect,
true);
9374 m_pRoutePointEditTarget = NULL;
9375 m_bMarkEditing =
false;
9380 else if (leftIsDown) {
9385 if (!m_bChartDragging && !m_bMeasure_Active) {
9387 m_bChartDragging =
false;
9391 m_bRoutePoinDragging =
false;
9394 if (ret)
return true;
9397 if (event.RightDown()) {
9408 m_FinishRouteOnKillFocus =
false;
9409 CallPopupMenu(mx, my);
9410 m_FinishRouteOnKillFocus =
true;
9418 bool ChartCanvas::MouseEventProcessCanvas(wxMouseEvent &event) {
9420 event.GetPosition(&x, &y);
9422 x *= m_displayScale;
9423 y *= m_displayScale;
9429 int wheel_dir =
event.GetWheelRotation();
9432 int mouse_wheel_oneshot = abs(wheel_dir) * 4;
9433 wheel_dir = wheel_dir > 0 ? 1 : -1;
9435 double factor = g_mouse_zoom_sensitivity;
9436 if (wheel_dir < 0) factor = 1 / factor;
9438 if (g_bsmoothpanzoom) {
9439 if ((m_wheelstopwatch.Time() < m_wheelzoom_stop_oneshot)) {
9440 if (wheel_dir == m_last_wheel_dir) {
9441 m_wheelzoom_stop_oneshot += mouse_wheel_oneshot;
9446 m_wheelzoom_stop_oneshot = mouse_wheel_oneshot;
9447 m_wheelstopwatch.Start(0);
9452 m_last_wheel_dir = wheel_dir;
9454 ZoomCanvas(factor,
true,
false);
9457 if (event.LeftDown()) {
9459 if ((GetCanvasCount() > 1) && (
this != g_focusCanvas)) {
9464 last_drag.x = x, last_drag.y = y;
9465 panleftIsDown =
true;
9468 if (event.LeftUp()) {
9469 if (panleftIsDown) {
9471 panleftIsDown =
false;
9474 if (!m_bChartDragging && !m_bMeasure_Active) {
9475 switch (cursor_region) {
9497 PanCanvas(x - GetVP().pix_width / 2, y - GetVP().pix_height / 2);
9502 m_bChartDragging =
false;
9508 if (event.Dragging() && event.LeftIsDown()) {
9525 if (
false == m_bChartDragging) {
9526 last_drag.x = x, last_drag.y = y;
9527 m_bChartDragging =
true;
9531 if ((last_drag.x != x) || (last_drag.y != y)) {
9534 m_bChartDragging =
true;
9535 StartTimedMovement();
9536 m_pan_drag.x += last_drag.x - x;
9537 m_pan_drag.y += last_drag.y - y;
9539 last_drag.x = x, last_drag.y = y;
9543 if ((m_bMeasure_Active && m_nMeasureState) || (m_routeState)) {
9545 m_DoubleClickTimer->Start();
9546 singleClickEventIsValid =
false;
9555 void ChartCanvas::MouseEvent(wxMouseEvent &event) {
9556 if (MouseEventOverlayWindows(event))
return;
9560 if (!MouseEventProcessObjects(event)) MouseEventProcessCanvas(event);
9563 void ChartCanvas::SetCanvasCursor(wxMouseEvent &event) {
9566 wxCursor *ptarget_cursor = pCursorArrow;
9567 if (!pPlugIn_Cursor) {
9568 ptarget_cursor = pCursorArrow;
9569 if ((!m_routeState) &&
9570 (!m_bMeasure_Active) ) {
9571 if (cursor_region == MID_RIGHT) {
9572 ptarget_cursor = pCursorRight;
9573 }
else if (cursor_region == MID_LEFT) {
9574 ptarget_cursor = pCursorLeft;
9575 }
else if (cursor_region == MID_TOP) {
9576 ptarget_cursor = pCursorDown;
9577 }
else if (cursor_region == MID_BOT) {
9578 ptarget_cursor = pCursorUp;
9580 ptarget_cursor = pCursorArrow;
9582 }
else if (m_bMeasure_Active ||
9584 ptarget_cursor = pCursorPencil;
9586 ptarget_cursor = pPlugIn_Cursor;
9589 SetCursor(*ptarget_cursor);
9592 void ChartCanvas::LostMouseCapture(wxMouseCaptureLostEvent &event) {
9593 SetCursor(*pCursorArrow);
9596 void ChartCanvas::ShowObjectQueryWindow(
int x,
int y,
float zlat,
float zlon) {
9600 wxArrayString files;
9602 ChartBase *target_chart = GetChartAtCursor();
9604 file.Assign(target_chart->GetFullPath());
9605 if ((target_chart->GetChartType() == CHART_TYPE_PLUGIN) &&
9606 (target_chart->GetChartFamily() == CHART_FAMILY_VECTOR))
9609 Chs57 =
dynamic_cast<s57chart *
>(target_chart);
9611 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
9612 unsigned int im = stackIndexArray.size();
9613 int scale = 2147483647;
9614 if (VPoint.b_quilt && im > 0) {
9615 for (
unsigned int is = 0; is < im; is++) {
9616 if (ChartData->GetDBChartType(stackIndexArray[is]) ==
9617 CHART_TYPE_MBTILES) {
9618 if (IsTileOverlayIndexInNoShow(stackIndexArray[is]))
continue;
9620 VPoint.GetLLFromPix(wxPoint(mouse_x, mouse_y), &lat, &lon);
9621 if (ChartData->GetChartTableEntry(stackIndexArray[is])
9623 .Contains(lat, lon)) {
9624 if (ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale() <
9627 ChartData->GetChartTableEntry(stackIndexArray[is]).GetScale();
9628 file.Assign(ChartData->GetDBChartFileName(stackIndexArray[is]));
9636 std::vector<Ais8_001_22 *> area_notices;
9638 if (g_pAIS && m_bShowAIS && g_bShowAreaNotices) {
9639 float vp_scale = GetVPScale();
9641 for (
const auto &target : g_pAIS->GetAreaNoticeSourcesList()) {
9642 auto target_data = target.second;
9643 if (!target_data->area_notices.empty()) {
9644 for (
auto &ani : target_data->area_notices) {
9649 for (Ais8_001_22_SubAreaList::iterator sa =
9650 area_notice.sub_areas.begin();
9651 sa != area_notice.sub_areas.end(); ++sa) {
9652 switch (sa->shape) {
9653 case AIS8_001_22_SHAPE_CIRCLE: {
9654 wxPoint target_point;
9655 GetCanvasPointPix(sa->latitude, sa->longitude, &target_point);
9656 bbox.Expand(target_point);
9657 if (sa->radius_m > 0.0) bbox.EnLarge(sa->radius_m * vp_scale);
9660 case AIS8_001_22_SHAPE_RECT: {
9661 wxPoint target_point;
9662 GetCanvasPointPix(sa->latitude, sa->longitude, &target_point);
9663 bbox.Expand(target_point);
9664 if (sa->e_dim_m > sa->n_dim_m) bbox.EnLarge(sa->e_dim_m * vp_scale);
9665 else bbox.EnLarge(sa->n_dim_m * vp_scale);
9668 case AIS8_001_22_SHAPE_POLYGON:
9669 case AIS8_001_22_SHAPE_POLYLINE: {
9670 for (
int i = 0; i < 4; ++i) {
9671 double lat = sa->latitude;
9672 double lon = sa->longitude;
9673 ll_gc_ll(lat, lon, sa->angles[i], sa->dists_m[i] / 1852.0,
9675 wxPoint target_point;
9676 GetCanvasPointPix(lat, lon, &target_point);
9677 bbox.Expand(target_point);
9681 case AIS8_001_22_SHAPE_SECTOR: {
9682 double lat1 = sa->latitude;
9683 double lon1 = sa->longitude;
9685 wxPoint target_point;
9686 GetCanvasPointPix(lat1, lon1, &target_point);
9687 bbox.Expand(target_point);
9688 for (
int i = 0; i < 18; ++i) {
9689 ll_gc_ll(lat1, lon1, sa->left_bound_deg + i * (sa->right_bound_deg - sa->left_bound_deg) / 18 , sa->radius_m / 1852.0,
9691 GetCanvasPointPix(lat, lon, &target_point);
9692 bbox.Expand(target_point);
9694 ll_gc_ll(lat1, lon1, sa->right_bound_deg , sa->radius_m / 1852.0,
9696 GetCanvasPointPix(lat, lon, &target_point);
9697 bbox.Expand(target_point);
9703 if (bbox.GetValid() && bbox.PointInBox(x, y)) {
9704 area_notices.push_back(&area_notice);
9711 if (target_chart || !area_notices.empty() || file.HasName()) {
9713 int sel_rad_pix = 5;
9714 float SelectRadius = sel_rad_pix / (GetVP().view_scale_ppm * 1852 * 60);
9719 SetCursor(wxCURSOR_WAIT);
9720 bool lightsVis = m_encShowLights;
9721 if (!lightsVis) SetShowENCLights(
true);
9724 ListOfObjRazRules *rule_list = NULL;
9725 ListOfPI_S57Obj *pi_rule_list = NULL;
9728 Chs57->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &GetVP());
9729 else if (target_plugin_chart)
9730 pi_rule_list = g_pi_manager->GetPlugInObjRuleListAtLatLon(
9731 target_plugin_chart, zlat, zlon, SelectRadius, GetVP());
9733 ListOfObjRazRules *overlay_rule_list = NULL;
9734 ChartBase *overlay_chart = GetOverlayChartAtCursor();
9737 if (CHs57_Overlay) {
9738 overlay_rule_list = CHs57_Overlay->GetObjRuleListAtLatLon(
9739 zlat, zlon, SelectRadius, &GetVP());
9742 if (!lightsVis) SetShowENCLights(
false);
9745 wxFont *dFont = FontMgr::Get().GetFont(_(
"ObjectQuery"));
9746 wxString face = dFont->GetFaceName();
9748 if (NULL == g_pObjectQueryDialog) {
9749 g_pObjectQueryDialog =
9750 new S57QueryDialog(
this, -1, _(
"Object Query"), wxDefaultPosition,
9751 wxSize(g_S57_dialog_sx, g_S57_dialog_sy));
9754 wxColor bg = g_pObjectQueryDialog->GetBackgroundColour();
9755 wxColor fg = FontMgr::Get().GetFontColor(_(
"ObjectQuery"));
9759 fg = g_pObjectQueryDialog->GetForegroundColour();
9763 _T(
"<html><body bgcolor=#%02x%02x%02x><font color=#%02x%02x%02x>"),
9764 bg.Red(), bg.Green(), bg.Blue(), fg.Red(), fg.Green(), fg.Blue());
9767 int points = dFont->GetPointSize();
9769 int points = dFont->GetPointSize() + 1;
9773 for (
int i = -2; i < 5; i++) {
9774 sizes[i + 2] = points + i + (i > 0 ? i : 0);
9776 g_pObjectQueryDialog->m_phtml->SetFonts(face, face, sizes);
9778 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText += _T(
"<i>");
9780 if (overlay_rule_list && CHs57_Overlay) {
9781 objText << CHs57_Overlay->CreateObjDescriptions(overlay_rule_list);
9782 objText << _T(
"<hr noshade>");
9785 for (std::vector<Ais8_001_22 *>::iterator an = area_notices.begin();
9786 an != area_notices.end(); ++an) {
9787 objText << _T(
"<b>AIS Area Notice:</b> " );
9788 objText << ais8_001_22_notice_names[(*an)->notice_type];
9789 for (std::vector<Ais8_001_22_SubArea>::iterator sa =
9790 (*an)->sub_areas.begin();
9791 sa != (*an)->sub_areas.end(); ++sa)
9792 if (!sa->text.empty()) objText << sa->text;
9793 objText << _T(
"<br>expires: " ) << (*an)->expiry_time.Format();
9794 objText << _T(
"<hr noshade>" );
9798 objText << Chs57->CreateObjDescriptions(rule_list);
9799 else if (target_plugin_chart)
9800 objText << g_pi_manager->CreateObjDescriptions(target_plugin_chart,
9803 if (wxFONTSTYLE_ITALIC == dFont->GetStyle()) objText << _T(
"</i>");
9806 wxString AddFiles, filenameOK;
9808 if (!target_plugin_chart) {
9811 AddFiles = wxString::Format(
9812 _T(
"<hr noshade><br><b>Additional info files attached to: </b> ")
9814 _T(
"size=-2>%s</font><br><table border=0 cellspacing=0 ")
9815 _T(
"cellpadding=3>"),
9816 file.GetFullName());
9818 file.Assign(file.GetPath(), wxT(
""));
9819 wxDir dir( file.GetFullPath() );
9821 bool cont = dir.GetFirst( &filename,
"", wxDIR_FILES );
9824 file.Assign( dir.GetNameWithSep().append( filename) );
9825 wxString FormatString = _T(
"<td valign=top><font size=-2><a href=\"%s\">%s</a></font></td>");
9826 if( g_ObjQFileExt.Find( file.GetExt().Lower() ) != wxNOT_FOUND )
9828 filenameOK=file.GetFullPath();
9830 if ( 3*((
int)filecount/3) == filecount )
9831 FormatString.Prepend(_T(
"<tr>"));
9833 FormatString.Prepend(_T(
"<td>  </td>"));
9835 AddFiles << wxString::Format(FormatString, file.GetFullPath(), file.GetFullName());
9838 cont = dir.GetNext(&filename);
9840 objText << AddFiles << _T(
"</table>");
9842 objText << _T(
"</font>");
9843 objText << _T(
"</body></html>");
9845 if (Chs57 || target_plugin_chart || (filecount > 1)) {
9846 g_pObjectQueryDialog->SetHTMLPage(objText);
9847 g_pObjectQueryDialog->Show();
9849 if ((!Chs57 && filecount == 1)){
9851 wxHtmlLinkInfo hli(filenameOK);
9852 wxHtmlLinkEvent hle(1, hli);
9853 g_pObjectQueryDialog->OnHtmlLinkClicked(hle);
9856 if (rule_list) rule_list->Clear();
9859 if (overlay_rule_list) overlay_rule_list->Clear();
9860 delete overlay_rule_list;
9862 if (pi_rule_list) pi_rule_list->Clear();
9863 delete pi_rule_list;
9865 SetCursor(wxCURSOR_ARROW);
9869 void ChartCanvas::ShowMarkPropertiesDialog(
RoutePoint *markPoint) {
9871 if (!g_pMarkInfoDialog) {
9878 wxSize canvas_size = GetSize();
9880 int best_size_y = wxMin(400 / OCPN_GetWinDIPScaleFactor(), canvas_size.y);
9881 g_pMarkInfoDialog->SetMinSize(wxSize(-1, best_size_y));
9883 g_pMarkInfoDialog->Layout();
9885 wxPoint canvas_pos = GetPosition();
9886 wxSize fitted_size = g_pMarkInfoDialog->GetSize();
9888 bool newFit =
false;
9889 if (canvas_size.x < fitted_size.x) {
9890 fitted_size.x = canvas_size.x - 40;
9891 if (canvas_size.y < fitted_size.y)
9892 fitted_size.y -= 40;
9894 if (canvas_size.y < fitted_size.y) {
9895 fitted_size.y = canvas_size.y - 40;
9896 if (canvas_size.x < fitted_size.x)
9897 fitted_size.x -= 40;
9901 g_pMarkInfoDialog->SetSize(fitted_size);
9902 g_pMarkInfoDialog->Centre();
9906 markPoint->m_bRPIsBeingEdited =
false;
9908 wxString title_base = _(
"Waypoint Properties");
9909 if (!markPoint->m_bIsInRoute)
9910 title_base = _(
"Mark Properties");
9912 g_pMarkInfoDialog->SetRoutePoints(std::vector<RoutePoint*> {markPoint});
9913 g_pMarkInfoDialog->UpdateProperties();
9914 if (markPoint->m_bIsInLayer) {
9915 wxString caption(wxString::Format(_T(
"%s, %s: %s"),
9916 title_base, _(
"Layer"),
9917 GetLayerName(markPoint->m_LayerID)));
9918 g_pMarkInfoDialog->SetDialogTitle(caption);
9920 g_pMarkInfoDialog->SetDialogTitle(title_base);
9922 g_pMarkInfoDialog->Show();
9923 g_pMarkInfoDialog->Raise();
9924 g_pMarkInfoDialog->InitialFocus();
9925 if (bNew) g_pMarkInfoDialog->CenterOnScreen();
9928 void ChartCanvas::ShowRoutePropertiesDialog(wxString title,
Route *selected) {
9929 pRoutePropDialog = RoutePropDlgImpl::getInstance(
this);
9930 pRoutePropDialog->SetRouteAndUpdate(selected);
9932 pRoutePropDialog->Show();
9933 pRoutePropDialog->Raise();
9935 pRoutePropDialog = RoutePropDlgImpl::getInstance(
9938 if (g_bresponsive) {
9939 wxSize canvas_size = GetSize();
9940 wxPoint canvas_pos = GetPosition();
9941 wxSize fitted_size = pRoutePropDialog->GetSize();
9944 if (canvas_size.x < fitted_size.x) {
9945 fitted_size.x = canvas_size.x;
9946 if (canvas_size.y < fitted_size.y)
9947 fitted_size.y -= 20;
9949 if (canvas_size.y < fitted_size.y) {
9950 fitted_size.y = canvas_size.y;
9951 if (canvas_size.x < fitted_size.x)
9952 fitted_size.x -= 20;
9955 pRoutePropDialog->SetSize(fitted_size);
9956 pRoutePropDialog->Centre();
9961 wxPoint xxp = ClientToScreen(canvas_pos);
9965 pRoutePropDialog->SetRouteAndUpdate(selected);
9967 pRoutePropDialog->Show();
9972 void ChartCanvas::ShowTrackPropertiesDialog(
Track *selected) {
9973 pTrackPropDialog = TrackPropDlg::getInstance(
9976 pTrackPropDialog->SetTrackAndUpdate(selected);
9979 pTrackPropDialog->Show();
9984 void pupHandler_PasteWaypoint() {
9987 int pasteBuffer = kml.ParsePasteBuffer();
9988 RoutePoint *pasted = kml.GetParsedRoutePoint();
9989 if (!pasted)
return;
9991 double nearby_radius_meters =
9992 g_Platform->GetSelectRadiusPix() /
9993 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
9995 RoutePoint *nearPoint = pWayPointMan->GetNearbyWaypoint(
9996 pasted->m_lat, pasted->m_lon, nearby_radius_meters);
9998 int answer = wxID_NO;
9999 if (nearPoint && !nearPoint->m_bIsInLayer) {
10002 "There is an existing waypoint at the same location as the one you are "
10003 "pasting. Would you like to merge the pasted data with it?\n\n");
10004 msg << _(
"Answering 'No' will create a new waypoint at the same location.");
10005 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoint?"),
10006 (
long)wxYES_NO | wxCANCEL | wxNO_DEFAULT);
10009 if (answer == wxID_YES) {
10010 nearPoint->SetName(pasted->GetName());
10011 nearPoint->m_MarkDescription = pasted->m_MarkDescription;
10012 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10013 pRouteManagerDialog->UpdateWptListCtrl();
10016 if (answer == wxID_NO) {
10018 newPoint->m_bIsolatedMark =
true;
10019 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10021 pConfig->AddNewWayPoint(newPoint, -1);
10022 pWayPointMan->AddRoutePoint(newPoint);
10023 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10024 pRouteManagerDialog->UpdateWptListCtrl();
10025 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10026 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10029 gFrame->InvalidateAllGL();
10030 gFrame->RefreshAllCanvas(
false);
10033 void pupHandler_PasteRoute() {
10036 int pasteBuffer = kml.ParsePasteBuffer();
10037 Route *pasted = kml.GetParsedRoute();
10038 if (!pasted)
return;
10040 double nearby_radius_meters =
10041 g_Platform->GetSelectRadiusPix() /
10042 gFrame->GetPrimaryCanvas()->GetCanvasTrueScale();
10048 bool mergepoints =
false;
10049 bool createNewRoute =
true;
10050 int existingWaypointCounter = 0;
10052 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10053 curPoint = pasted->GetPoint(i);
10054 nearPoint = pWayPointMan->GetNearbyWaypoint(
10055 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10057 mergepoints =
true;
10058 existingWaypointCounter++;
10062 curPoint->m_bPtIsSelected =
true;
10066 int answer = wxID_NO;
10070 "There are existing waypoints at the same location as some of the ones "
10071 "you are pasting. Would you like to just merge the pasted data into "
10073 msg << _(
"Answering 'No' will create all new waypoints for this route.");
10074 answer = OCPNMessageBox(NULL, msg, _(
"Merge waypoints?"),
10075 (
long)wxYES_NO | wxCANCEL | wxYES_DEFAULT);
10077 if (answer == wxID_CANCEL) {
10084 if (mergepoints && answer == wxID_YES &&
10085 existingWaypointCounter == pasted->GetnPoints()) {
10086 wxRouteListNode *route_node = pRouteList->GetFirst();
10087 while (route_node) {
10088 Route *proute = route_node->GetData();
10090 if (pasted->m_RouteNameString == proute->m_RouteNameString) {
10091 createNewRoute =
false;
10094 route_node = route_node->GetNext();
10098 Route *newRoute = 0;
10101 if (createNewRoute) {
10102 newRoute =
new Route();
10103 newRoute->m_RouteNameString = pasted->m_RouteNameString;
10106 for (
int i = 1; i <= pasted->GetnPoints(); i++) {
10107 curPoint = pasted->GetPoint(i);
10108 if (answer == wxID_YES && curPoint->m_bPtIsSelected) {
10109 curPoint->m_bPtIsSelected =
false;
10110 newPoint = pWayPointMan->GetNearbyWaypoint(
10111 curPoint->m_lat, curPoint->m_lon, nearby_radius_meters);
10112 newPoint->SetName(curPoint->GetName());
10113 newPoint->m_MarkDescription = curPoint->m_MarkDescription;
10115 if (createNewRoute) newRoute->AddPoint(newPoint);
10117 curPoint->m_bPtIsSelected =
false;
10120 newPoint->m_bIsolatedMark =
false;
10121 newPoint->SetIconName(_T(
"circle"));
10122 newPoint->m_bIsVisible =
true;
10123 newPoint->m_bShowName =
false;
10124 newPoint->SetShared(
false);
10126 newRoute->AddPoint(newPoint);
10127 pSelect->AddSelectableRoutePoint(newPoint->m_lat, newPoint->m_lon,
10129 pConfig->AddNewWayPoint(newPoint, -1);
10130 pWayPointMan->AddRoutePoint(newPoint);
10132 if (i > 1 && createNewRoute)
10133 pSelect->AddSelectableRouteSegment(prevPoint->m_lat, prevPoint->m_lon,
10134 curPoint->m_lat, curPoint->m_lon,
10135 prevPoint, newPoint, newRoute);
10136 prevPoint = newPoint;
10139 if (createNewRoute) {
10140 pRouteList->Append(newRoute);
10141 pConfig->AddNewRoute(newRoute);
10143 if (pRoutePropDialog && pRoutePropDialog->IsShown()) {
10144 pRoutePropDialog->SetRouteAndUpdate(newRoute);
10147 if (pRouteManagerDialog && pRouteManagerDialog->IsShown()) {
10148 pRouteManagerDialog->UpdateRouteListCtrl();
10149 pRouteManagerDialog->UpdateWptListCtrl();
10151 gFrame->InvalidateAllGL();
10152 gFrame->RefreshAllCanvas(
false);
10154 if (
RoutePointGui(*newPoint).IsVisibleSelectable(g_focusCanvas))
10155 RoutePointGui(*newPoint).ShowScaleWarningMessage(g_focusCanvas);
10158 void pupHandler_PasteTrack() {
10161 int pasteBuffer = kml.ParsePasteBuffer();
10162 Track *pasted = kml.GetParsedTrack();
10163 if (!pasted)
return;
10171 newTrack->SetName(pasted->GetName());
10173 for (
int i = 0; i < pasted->GetnPoints(); i++) {
10174 curPoint = pasted->GetPoint(i);
10178 wxDateTime now = wxDateTime::Now();
10179 newPoint->SetCreateTime(curPoint->GetCreateTime());
10181 newTrack->AddPoint(newPoint);
10184 pSelect->AddSelectableTrackSegment(prevPoint->m_lat, prevPoint->m_lon,
10185 newPoint->m_lat, newPoint->m_lon,
10186 prevPoint, newPoint, newTrack);
10188 prevPoint = newPoint;
10191 g_TrackList.push_back(newTrack);
10192 pConfig->AddNewTrack(newTrack);
10194 gFrame->InvalidateAllGL();
10195 gFrame->RefreshAllCanvas(
false);
10198 bool ChartCanvas::InvokeCanvasMenu(
int x,
int y,
int seltype) {
10200 m_pFoundRoutePoint, m_FoundAIS_MMSI,
10204 wxEVT_COMMAND_MENU_SELECTED,
10205 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10207 m_canvasMenu->CanvasPopupMenu(x, y, seltype);
10210 wxEVT_COMMAND_MENU_SELECTED,
10211 (wxObjectEventFunction)(wxEventFunction)&ChartCanvas::PopupMenuHandler);
10213 delete m_canvasMenu;
10214 m_canvasMenu = NULL;
10224 void ChartCanvas::PopupMenuHandler(wxCommandEvent &event) {
10227 if (m_canvasMenu) {
10228 m_canvasMenu->PopupMenuHandler(event);
10233 void ChartCanvas::StartRoute(
void) {
10235 if (g_brouteCreating)
return;
10237 if (g_MainToolbar) g_MainToolbar->DisableTooltips();
10239 g_brouteCreating =
true;
10241 m_bDrawingRoute =
false;
10242 SetCursor(*pCursorPencil);
10244 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
true);
10246 HideGlobalToolbar();
10249 androidSetRouteAnnunciator(
true);
10253 void ChartCanvas::FinishRoute(
void) {
10255 m_prev_pMousePoint = NULL;
10256 m_bDrawingRoute =
false;
10259 gFrame->SetMasterToolbarItemState(ID_MENU_ROUTE_NEW,
false);
10261 androidSetRouteAnnunciator(
false);
10264 SetCursor(*pCursorArrow);
10266 if (m_pMouseRoute) {
10267 if (m_bAppendingRoute)
10268 pConfig->UpdateRoute(m_pMouseRoute);
10270 if (m_pMouseRoute->GetnPoints() > 1) {
10271 pConfig->AddNewRoute(m_pMouseRoute);
10274 NavObjectChanges::getInstance());
10275 m_pMouseRoute = NULL;
10278 if (m_pMouseRoute) m_pMouseRoute->SetHiLite(0);
10280 if (RoutePropDlgImpl::getInstanceFlag() && pRoutePropDialog &&
10281 (pRoutePropDialog->IsShown())) {
10282 pRoutePropDialog->SetRouteAndUpdate(m_pMouseRoute,
true);
10285 if (RouteManagerDialog::getInstanceFlag() && pRouteManagerDialog) {
10286 if (pRouteManagerDialog && pRouteManagerDialog->IsShown())
10287 pRouteManagerDialog->UpdateRouteListCtrl();
10290 m_bAppendingRoute =
false;
10291 m_pMouseRoute = NULL;
10293 m_pSelectedRoute = NULL;
10295 undo->InvalidateUndo();
10296 gFrame->RefreshAllCanvas(
true);
10298 if (g_MainToolbar) g_MainToolbar->EnableTooltips();
10300 ShowGlobalToolbar();
10302 g_brouteCreating =
false;
10305 void ChartCanvas::HideGlobalToolbar() {
10306 if (m_canvasIndex == 0) {
10307 m_last_TBviz = gFrame->SetGlobalToolbarViz(
false);
10311 void ChartCanvas::ShowGlobalToolbar() {
10312 if (m_canvasIndex == 0) {
10313 if (m_last_TBviz) gFrame->SetGlobalToolbarViz(
true);
10317 void ChartCanvas::ShowAISTargetList(
void) {
10318 if (NULL == g_pAISTargetList) {
10322 g_pAISTargetList->UpdateAISTargetList();
10325 void ChartCanvas::RenderAllChartOutlines(
ocpnDC &dc,
ViewPort &vp) {
10326 if (!m_bShowOutlines)
return;
10328 if (!ChartData)
return;
10330 int nEntry = ChartData->GetChartTableEntries();
10332 for (
int i = 0; i < nEntry; i++) {
10336 bool b_group_draw =
false;
10337 if (m_groupIndex > 0) {
10338 for (
unsigned int ig = 0; ig < pt->GetGroupArray().size(); ig++) {
10339 int index = pt->GetGroupArray()[ig];
10340 if (m_groupIndex == index) {
10341 b_group_draw =
true;
10346 b_group_draw =
true;
10348 if (b_group_draw) RenderChartOutline(dc, i, vp);
10354 if (VPoint.b_quilt) {
10355 for (
ChartBase *pch = GetFirstQuiltChart(); pch; pch = GetNextQuiltChart())
10356 if (pch->GetChartType() == CHART_TYPE_CM93COMP) {
10360 }
else if (m_singleChart &&
10361 (m_singleChart->GetChartType() == CHART_TYPE_CM93COMP))
10365 double chart_native_ppm = m_canvas_scale_factor / pcm93->GetNativeScale();
10366 double zoom_factor = GetVP().view_scale_ppm / chart_native_ppm;
10368 if (zoom_factor > 8.0) {
10369 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 2, wxPENSTYLE_SHORT_DASH);
10372 wxPen mPen(GetGlobalColor(_T(
"UINFM")), 1, wxPENSTYLE_SOLID);
10376 pcm93->RenderNextSmallerCellOutlines(dc, vp,
this);
10380 void ChartCanvas::RenderChartOutline(
ocpnDC &dc,
int dbIndex,
ViewPort &vp) {
10382 if (g_bopengl && m_glcc) {
10384 m_glcc->RenderChartOutline(dc, dbIndex, vp);
10389 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_PLUGIN) {
10390 if (!ChartData->IsChartAvailable(dbIndex))
return;
10393 float plylat, plylon;
10394 float plylat1, plylon1;
10396 int pixx, pixy, pixx1, pixy1;
10399 ChartData->GetDBBoundingBox(dbIndex, box);
10403 if (box.GetLonRange() == 360)
return;
10405 double lon_bias = 0;
10407 if (box.IntersectOutGetBias(vp.GetBBox(), lon_bias))
return;
10409 int nPly = ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10411 if (ChartData->GetDBChartType(dbIndex) == CHART_TYPE_CM93)
10412 dc.SetPen(wxPen(GetGlobalColor(_T (
"YELO1" )), 1, wxPENSTYLE_SOLID));
10414 else if (ChartData->GetDBChartFamily(dbIndex) == CHART_FAMILY_VECTOR)
10415 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFG" )), 1, wxPENSTYLE_SOLID));
10418 dc.SetPen(wxPen(GetGlobalColor(_T (
"UINFR" )), 1, wxPENSTYLE_SOLID));
10421 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10422 if (0 == nAuxPlyEntries)
10426 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat, &plylon);
10427 plylon += lon_bias;
10429 GetCanvasPointPix(plylat, plylon, &r);
10433 for (
int i = 0; i < nPly - 1; i++) {
10434 ChartData->GetDBPlyPoint(dbIndex, i + 1, &plylat1, &plylon1);
10435 plylon1 += lon_bias;
10437 GetCanvasPointPix(plylat1, plylon1, &r1);
10441 int pixxs1 = pixx1;
10442 int pixys1 = pixy1;
10444 bool b_skip =
false;
10446 if (vp.chart_scale > 5e7) {
10448 double dist = sqrt(pow((
double)(pixx1 - pixx), 2) +
10449 pow((
double)(pixy1 - pixy), 2)) /
10455 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10460 if (fabs(dist - distgc) > 10000. * 1852.)
10466 ClipResult res = cohen_sutherland_line_clip_i(
10467 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10468 if (res != Invisible && !b_skip)
10469 dc.DrawLine(pixx, pixy, pixx1, pixy1,
false);
10477 ChartData->GetDBPlyPoint(dbIndex, 0, &plylat1, &plylon1);
10478 plylon1 += lon_bias;
10480 GetCanvasPointPix(plylat1, plylon1, &r1);
10484 ClipResult res = cohen_sutherland_line_clip_i(
10485 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10486 if (res != Invisible) dc.DrawLine(pixx, pixy, pixx1, pixy1,
false);
10493 int nAuxPlyEntries = ChartData->GetnAuxPlyEntries(dbIndex);
10494 for (
int j = 0; j < nAuxPlyEntries; j++) {
10496 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat, &plylon);
10497 GetCanvasPointPix(plylat, plylon, &r);
10501 for (
int i = 0; i < nAuxPly - 1; i++) {
10502 ChartData->GetDBAuxPlyPoint(dbIndex, i + 1, j, &plylat1, &plylon1);
10504 GetCanvasPointPix(plylat1, plylon1, &r1);
10508 int pixxs1 = pixx1;
10509 int pixys1 = pixy1;
10511 bool b_skip =
false;
10513 if (vp.chart_scale > 5e7) {
10515 double dist = sqrt((
double)((pixx1 - pixx) * (pixx1 - pixx)) +
10516 ((pixy1 - pixy) * (pixy1 - pixy))) /
10521 DistGreatCircle(plylat, plylon, plylat1, plylon1) * 1852.;
10526 if (fabs(dist - distgc) > 10000. * 1852.)
10532 ClipResult res = cohen_sutherland_line_clip_i(
10533 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10534 if (res != Invisible && !b_skip) dc.DrawLine(pixx, pixy, pixx1, pixy1);
10542 ChartData->GetDBAuxPlyPoint(dbIndex, 0, j, &plylat1, &plylon1);
10543 GetCanvasPointPix(plylat1, plylon1, &r1);
10547 ClipResult res = cohen_sutherland_line_clip_i(
10548 &pixx, &pixy, &pixx1, &pixy1, 0, vp.pix_width, 0, vp.pix_height);
10549 if (res != Invisible) dc.DrawLine(pixx, pixy, pixx1, pixy1,
false);
10554 static void RouteLegInfo(
ocpnDC &dc, wxPoint ref_point,
const wxString &first,
10555 const wxString &second) {
10556 wxFont *dFont = FontMgr::Get().GetFont(_(
"RouteLegInfoRollover"));
10558 int pointsize = dFont->GetPointSize();
10559 pointsize /= OCPN_GetWinDIPScaleFactor();
10561 wxFont *psRLI_font = FontMgr::Get().FindOrCreateFont(
10562 pointsize, dFont->GetFamily(), dFont->GetStyle(),
10563 dFont->GetWeight(),
false, dFont->GetFaceName());
10566 dc.SetFont(*psRLI_font);
10574 int hilite_offset = 3;
10577 sdc.GetTextExtent(first, &w1, &h1, NULL, NULL, psRLI_font);
10578 if (second.Len()) sdc.GetTextExtent(second, &w2, &h2, NULL, NULL, psRLI_font);
10580 dc.GetTextExtent(first, &w1, &h1);
10581 if (second.Len()) dc.GetTextExtent(second, &w2, &h2);
10584 h1 *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
10585 h2 *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
10587 w = wxMax(w1, w2) + (h1 / 2);
10588 w *= (OCPN_GetWinDIPScaleFactor() * 100.) / 100;
10592 xp = ref_point.x - w;
10594 yp += hilite_offset;
10596 AlphaBlending(dc, xp, yp, w, h, 0.0, GetGlobalColor(_T (
"YELO1" )), 172);
10598 dc.SetPen(wxPen(GetGlobalColor(_T (
"UBLCK" ))));
10599 dc.SetTextForeground(GetGlobalColor(_T (
"UBLCK" )));
10601 dc.DrawText(first, xp, yp);
10602 if (second.Len()) dc.DrawText(second, xp, yp + h1);
10605 void ChartCanvas::RenderShipToActive(
ocpnDC &dc,
bool Use_Opengl) {
10606 if (!g_bAllowShipToActive)
return;
10608 Route *rt = g_pRouteMan->GetpActiveRoute();
10611 if (
RoutePoint *rp = g_pRouteMan->GetpActivePoint()) {
10612 wxPoint2DDouble pa, pb;
10613 GetDoubleCanvasPointPix(gLat, gLon, &pa);
10614 GetDoubleCanvasPointPix(rp->m_lat, rp->m_lon, &pb);
10618 g_pRouteMan->GetRoutePen()->GetWidth();
10619 if (rt->m_width != wxPENSTYLE_INVALID)
10620 width = rt->m_width;
10621 wxPenStyle style = (wxPenStyle)::StyleValues[wxMin(
10622 g_shipToActiveStyle, 5)];
10623 if (style == wxPENSTYLE_INVALID) style = wxPENSTYLE_SOLID;
10625 g_shipToActiveColor > 0 ? GpxxColors[wxMin(g_shipToActiveColor - 1, 15)]
10627 g_pRouteMan->GetActiveRoutePen()->GetColour();
10628 wxPen *mypen = wxThePenList->FindOrCreatePen(color, width, style);
10631 dc.SetBrush(wxBrush(color, wxBRUSHSTYLE_SOLID));
10634 RouteGui(*rt).RenderSegment(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x, (
int)pb.m_y,
10640 #ifdef USE_ANDROID_GLES2
10641 dc.DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
10643 if (style != wxPENSTYLE_SOLID) {
10644 if (glChartCanvas::dash_map.find(style) !=
10645 glChartCanvas::dash_map.end()) {
10646 mypen->SetDashes(2, &glChartCanvas::dash_map[style][0]);
10650 dc.DrawLine(pa.m_x, pa.m_y, pb.m_x, pb.m_y);
10653 RouteGui(*rt).RenderSegmentArrowsGL(dc, (
int)pa.m_x, (
int)pa.m_y, (
int)pb.m_x,
10654 (
int)pb.m_y, GetVP());
10660 void ChartCanvas::RenderRouteLegs(
ocpnDC &dc) {
10662 if (m_routeState >= 2) route = m_pMouseRoute;
10663 if (m_pMeasureRoute && m_bMeasure_Active && (m_nMeasureState >= 2))
10664 route = m_pMeasureRoute;
10666 if (!route)
return;
10669 if( !g_pRouteMan->IsRouteValid(route) )
10672 double render_lat = m_cursor_lat;
10673 double render_lon = m_cursor_lon;
10675 int np = route->GetnPoints();
10677 if (g_btouch && (np > 1)) np--;
10679 render_lat = rp.m_lat;
10680 render_lon = rp.m_lon;
10683 double rhumbBearing, rhumbDist;
10684 DistanceBearingMercator(m_cursor_lat, m_cursor_lon, render_lat, render_lon,
10685 &rhumbBearing, &rhumbDist);
10686 double brg = rhumbBearing;
10687 double dist = rhumbDist;
10691 double gcBearing, gcBearing2, gcDist;
10692 Geodesic::GreatCircleDistBear(render_lon, render_lat, m_cursor_lon,
10693 m_cursor_lat, &gcDist, &gcBearing,
10695 double gcDistm = gcDist / 1852.0;
10697 if ((render_lat == m_cursor_lat) && (render_lon == m_cursor_lon))
10698 rhumbBearing = 90.;
10700 wxPoint destPoint, lastPoint;
10702 route->m_NextLegGreatCircle =
false;
10703 int milesDiff = rhumbDist - gcDistm;
10704 if (milesDiff > 1) {
10707 route->m_NextLegGreatCircle =
true;
10711 RouteGui(*route).DrawPointWhich(dc,
this, route->m_lastMousePointIndex, &lastPoint);
10713 if (route->m_NextLegGreatCircle) {
10714 for (
int i = 1; i <= milesDiff; i++) {
10715 double p = (double)i * (1.0 / (
double)milesDiff);
10717 Geodesic::GreatCircleTravel(render_lon, render_lat, gcDist * p, brg,
10718 &pLon, &pLat, &gcBearing2);
10719 destPoint = VPoint.GetPixFromLL(pLat, pLon);
10720 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &destPoint, GetVP(),
false);
10721 lastPoint = destPoint;
10724 if (r_rband.x && r_rband.y) {
10725 RouteGui(*route).DrawSegment(dc,
this, &lastPoint, &r_rband, GetVP(),
false);
10726 if (m_bMeasure_DistCircle) {
10727 double distanceRad = sqrtf(powf((
float)(r_rband.x - lastPoint.x), 2) +
10728 powf((
float)(r_rband.y - lastPoint.y), 2));
10730 dc.SetPen(*g_pRouteMan->GetRoutePen());
10731 dc.SetBrush(*wxTRANSPARENT_BRUSH);
10732 dc.StrokeCircle(lastPoint.x, lastPoint.y, distanceRad);
10738 wxString routeInfo;
10740 routeInfo << wxString::Format(wxString(
"%03d%c(T) ", wxConvUTF8), (
int)brg,
10744 double latAverage = (m_cursor_lat + render_lat) / 2;
10745 double lonAverage = (m_cursor_lon + render_lon) / 2;
10746 double varBrg = gFrame->GetMag(brg, latAverage, lonAverage);
10748 routeInfo << wxString::Format(wxString(
"%03d%c(M) ", wxConvUTF8), (
int)varBrg,
10752 routeInfo << _T(
" ") << FormatDistanceAdaptive(dist);
10755 if (!route->m_bIsInLayer)
10756 s0.Append(_(
"Route") + _T(
": "));
10758 s0.Append(_(
"Layer Route: "));
10760 double disp_length = route->m_route_length;
10761 if (!g_btouch) disp_length += dist;
10762 s0 += FormatDistanceAdaptive(disp_length);
10764 RouteLegInfo(dc, r_rband, routeInfo, s0);
10766 m_brepaint_piano =
true;
10769 void ChartCanvas::RenderVisibleSectorLights(
ocpnDC &dc) {
10770 if (!m_bShowVisibleSectors)
return;
10772 if (g_bDeferredInitDone) {
10774 double rhumbBearing, rhumbDist;
10775 DistanceBearingMercator(gLat, gLon, m_sector_glat, m_sector_glon,
10776 &rhumbBearing, &rhumbDist);
10778 if (rhumbDist > 0.05)
10780 s57_GetVisibleLightSectors(
this, gLat, gLon, GetVP(),
10781 m_sectorlegsVisible);
10782 m_sector_glat = gLat;
10783 m_sector_glon = gLon;
10785 s57_DrawExtendedLightSectors(dc, VPoint, m_sectorlegsVisible);
10789 void ChartCanvas::WarpPointerDeferred(
int x,
int y) {
10797 void ChartCanvas::UpdateCanvasS52PLIBConfig() {
10798 if (!ps52plib)
return;
10800 if (VPoint.b_quilt) {
10801 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
10803 if (m_pQuilt->IsQuiltVector()) {
10804 if (ps52plib->GetStateHash() != m_s52StateHash) {
10806 m_s52StateHash = ps52plib->GetStateHash();
10810 if (ps52plib->GetStateHash() != m_s52StateHash) {
10812 m_s52StateHash = ps52plib->GetStateHash();
10817 bool bSendPlibState =
true;
10818 if (VPoint.b_quilt) {
10819 if (!m_pQuilt->DoesQuiltContainPlugins()) bSendPlibState =
false;
10822 if (bSendPlibState) {
10824 v[_T(
"OpenCPN Version Major")] = VERSION_MAJOR;
10825 v[_T(
"OpenCPN Version Minor")] = VERSION_MINOR;
10826 v[_T(
"OpenCPN Version Patch")] = VERSION_PATCH;
10827 v[_T(
"OpenCPN Version Date")] = VERSION_DATE;
10828 v[_T(
"OpenCPN Version Full")] = VERSION_FULL;
10831 v[_T(
"OpenCPN S52PLIB ShowText")] = GetShowENCText();
10832 v[_T(
"OpenCPN S52PLIB ShowSoundings")] = GetShowENCDepth();
10833 v[_T(
"OpenCPN S52PLIB ShowLights")] = GetShowENCLights();
10834 v[_T(
"OpenCPN S52PLIB ShowAnchorConditions")] =
10836 v[_T(
"OpenCPN S52PLIB ShowQualityOfData")] =
10837 GetShowENCDataQual();
10838 v[_T(
"OpenCPN S52PLIB ShowATONLabel")] = GetShowENCBuoyLabels();
10839 v[_T(
"OpenCPN S52PLIB ShowLightDescription")] = GetShowENCLightDesc();
10841 v[_T(
"OpenCPN S52PLIB DisplayCategory")] = GetENCDisplayCategory();
10843 v[_T(
"OpenCPN S52PLIB SoundingsFactor")] = g_ENCSoundingScaleFactor;
10844 v[_T(
"OpenCPN S52PLIB TextFactor")] = g_ENCTextScaleFactor;
10848 v[_T(
"OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
10849 v[_T(
"OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
10850 v[_T(
"OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
10851 v[_T(
"OpenCPN S52PLIB ShowImportantTextOnly")] = ps52plib->m_bShowS57ImportantTextOnly;
10852 v[_T(
"OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
10853 v[_T(
"OpenCPN S52PLIB UseSUPER_SCAMIN")] = ps52plib->m_bUseSUPER_SCAMIN;
10854 v[_T(
"OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
10855 v[_T(
"OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
10856 v[_T(
"OpenCPN S52PLIB ColorShades")] = S52_getMarinerParam( S52_MAR_TWO_SHADES );
10859 v[_T(
"OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
10860 v[_T(
"OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier_raster;
10861 v[_T(
"OpenCPN Scale Factor Exp")] = g_Platform->GetChartScaleFactorExp(g_ChartScaleFactor);
10862 v[_T(
"OpenCPN Display Width")] = (int)g_display_size_mm;
10868 if (!g_lastS52PLIBPluginMessage.IsSameAs(out)) {
10869 g_pi_manager->SendMessageToAllPlugins(wxString(_T(
"OpenCPN Config")),
10871 g_lastS52PLIBPluginMessage = out;
10877 void ChartCanvas::OnPaint(wxPaintEvent &event) {
10878 wxPaintDC dc(
this);
10888 if (!m_b_paint_enable) {
10893 UpdateCanvasS52PLIBConfig();
10896 if (!g_bdisable_opengl && m_glcc) m_glcc->Show(g_bopengl);
10898 if (m_glcc && g_bopengl) {
10899 if (!s_in_update) {
10909 if ((GetVP().pix_width == 0) || (GetVP().pix_height == 0))
return;
10911 wxRegion ru = GetUpdateRegion();
10913 int rx, ry, rwidth, rheight;
10914 ru.GetBox(rx, ry, rwidth, rheight);
10918 #ifdef ocpnUSE_DIBSECTION
10921 wxMemoryDC temp_dc;
10924 long height = GetVP().pix_height;
10929 if (!style->chartStatusWindowTransparent && g_bShowChartBar)
10930 height += m_Piano->GetHeight();
10932 wxRegion rgn_chart(0, 0, GetVP().pix_width, height);
10936 int thumbx, thumby, thumbsx, thumbsy;
10937 pthumbwin->GetPosition(&thumbx, &thumby);
10938 pthumbwin->GetSize(&thumbsx, &thumbsy);
10939 wxRegion rgn_thumbwin(thumbx, thumby, thumbsx - 1, thumbsy - 1);
10941 if (pthumbwin->IsShown()) {
10942 rgn_chart.Subtract(rgn_thumbwin);
10943 ru.Subtract(rgn_thumbwin);
10949 wxRegion rgn_blit = ru;
10950 if (g_bShowChartBar) {
10951 wxRect chart_bar_rect(0, GetClientSize().y - m_Piano->GetHeight(),
10952 GetClientSize().x, m_Piano->GetHeight());
10955 if (ru.Contains(chart_bar_rect) != wxOutRegion) {
10956 if (style->chartStatusWindowTransparent)
10957 m_brepaint_piano =
true;
10959 ru.Subtract(chart_bar_rect);
10963 if (m_Compass && m_Compass->IsShown()) {
10964 wxRect compassRect = m_Compass->GetRect();
10965 if (ru.Contains(compassRect) != wxOutRegion) {
10966 ru.Subtract(compassRect);
10971 bool b_newview =
true;
10973 if ((m_cache_vp.view_scale_ppm == VPoint.view_scale_ppm) &&
10974 (m_cache_vp.rotation == VPoint.rotation) &&
10975 (m_cache_vp.clat == VPoint.clat) && (m_cache_vp.clon == VPoint.clon) &&
10976 m_cache_vp.IsValid()) {
10982 bool b_rcache_ok =
false;
10983 if (fabs(VPoint.skew) > 0.01 || fabs(VPoint.rotation) > 0.01)
10984 b_rcache_ok = !b_newview;
10987 if (VPoint.b_MercatorProjectionOverride)
10988 VPoint.SetProjectionType(PROJECTION_MERCATOR);
10991 svp.pix_width = svp.rv_rect.width;
10992 svp.pix_height = svp.rv_rect.height;
10998 OCPNRegion chart_get_region(wxRect(0, 0, svp.pix_width, svp.pix_height));
11002 if (b_rcache_ok) chart_get_region.Clear();
11005 if (VPoint.b_quilt)
11007 if (!m_pQuilt || !m_pQuilt->IsComposed())
return;
11009 bool bvectorQuilt = m_pQuilt->IsQuiltVector();
11012 if (bvectorQuilt && (m_cache_vp.view_scale_ppm != VPoint.view_scale_ppm ||
11013 m_cache_vp.rotation != VPoint.rotation)) {
11014 AbstractPlatform::ShowBusySpinner();
11018 if ((m_working_bm.GetWidth() != svp.pix_width) ||
11019 (m_working_bm.GetHeight() != svp.pix_height))
11020 m_working_bm.Create(svp.pix_width, svp.pix_height,
11023 if (fabs(VPoint.rotation) < 0.01) {
11024 bool b_save =
true;
11026 if (g_SencThreadManager) {
11027 if (g_SencThreadManager->GetJobCount()) {
11029 m_cache_vp.Invalidate();
11043 if (m_bm_cache_vp.IsValid() && m_cache_vp.IsValid() ) {
11045 wxPoint c_old = VPoint.GetPixFromLL(VPoint.clat, VPoint.clon);
11046 wxPoint c_new = m_bm_cache_vp.GetPixFromLL(VPoint.clat, VPoint.clon);
11048 int dy = c_new.y - c_old.y;
11049 int dx = c_new.x - c_old.x;
11054 if (m_pQuilt->IsVPBlittable(VPoint, dx, dy,
true)) {
11058 temp_dc.SelectObject(m_working_bm);
11060 wxMemoryDC cache_dc;
11061 cache_dc.SelectObject(m_cached_chart_bm);
11065 temp_dc.Blit(0, 0, VPoint.pix_width - dx,
11066 VPoint.pix_height - dy, &cache_dc, dx, dy);
11068 temp_dc.Blit(-dx, 0, VPoint.pix_width + dx,
11069 VPoint.pix_height - dy, &cache_dc, 0, dy);
11074 temp_dc.Blit(0, -dy, VPoint.pix_width - dx,
11075 VPoint.pix_height + dy, &cache_dc, dx, 0);
11077 temp_dc.Blit(-dx, -dy, VPoint.pix_width + dx,
11078 VPoint.pix_height + dy, &cache_dc, 0, 0);
11085 update_region.Union(
11086 wxRect(0, VPoint.pix_height - dy, VPoint.pix_width, dy));
11088 update_region.Union(wxRect(0, 0, VPoint.pix_width, -dy));
11093 update_region.Union(
11094 wxRect(VPoint.pix_width - dx, 0, dx, VPoint.pix_height));
11096 update_region.Union(wxRect(0, 0, -dx, VPoint.pix_height));
11100 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11102 cache_dc.SelectObject(wxNullBitmap);
11106 temp_dc.SelectObject(m_cached_chart_bm);
11109 m_pQuilt->ComputeRenderRegion(svp, chart_get_region);
11113 temp_dc.SelectObject(m_working_bm);
11114 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11119 temp_dc.SelectObject(m_cached_chart_bm);
11124 temp_dc.SelectObject(m_working_bm);
11125 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11138 wxMemoryDC scratch_dc_0;
11139 scratch_dc_0.SelectObject(m_cached_chart_bm);
11140 scratch_dc_0.Blit(0, 0, svp.pix_width, svp.pix_height, &temp_dc, 0, 0);
11142 scratch_dc_0.SelectObject(wxNullBitmap);
11151 temp_dc.SelectObject(m_working_bm);
11153 wxRect(0, 0, svp.pix_width, svp.pix_height));
11154 m_pQuilt->RenderQuiltRegionViewOnDCNoText(temp_dc, svp,
11155 chart_get_all_region);
11158 AbstractPlatform::HideBusySpinner();
11164 if (!m_singleChart) {
11165 dc.SetBackground(wxBrush(*wxLIGHT_GREY));
11170 if (!chart_get_region.IsEmpty()) {
11171 m_singleChart->RenderRegionViewOnDC(temp_dc, svp, chart_get_region);
11175 if (temp_dc.IsOk()) {
11180 if (!VPoint.b_quilt) {
11183 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11184 m_singleChart->GetValidCanvasRegion(svp, &chartValidRegion);
11191 m_singleChart->GetValidCanvasRegion(VPoint, &chartValidRegion);
11192 chartValidRegion.Offset(-VPoint.rv_rect.x, -VPoint.rv_rect.y);
11195 chartValidRegion = m_pQuilt->GetFullQuiltRenderedRegion();
11197 temp_dc.DestroyClippingRegion();
11200 OCPNRegion backgroundRegion(wxRect(0, 0, svp.pix_width, svp.pix_height));
11202 if (chartValidRegion.IsOk()) backgroundRegion.Subtract(chartValidRegion);
11204 if (!backgroundRegion.IsEmpty()) {
11210 wxColour water = pWorldBackgroundChart->water;
11211 if (water.IsOk()) {
11212 temp_dc.SetPen(*wxTRANSPARENT_PEN);
11213 temp_dc.SetBrush(wxBrush(water));
11215 while (upd.HaveRects()) {
11216 wxRect rect = upd.GetRect();
11217 temp_dc.DrawRectangle(rect);
11222 wxRegion *clip_region = backgroundRegion.GetNew_wxRegion();
11223 temp_dc.SetDeviceClippingRegion(*clip_region);
11224 delete clip_region;
11227 double r = VPoint.rotation;
11228 SetVPRotation(VPoint.skew);
11231 gShapeBasemap.RenderViewOnDC(bgdc, VPoint);
11237 wxMemoryDC *pChartDC = &temp_dc;
11238 wxMemoryDC rotd_dc;
11240 if (((fabs(GetVP().rotation) > 0.01)) || (fabs(GetVP().skew) > 0.01)) {
11242 if (!b_rcache_ok) {
11244 wxMemoryDC tbase_dc;
11245 wxBitmap bm_base(svp.pix_width, svp.pix_height, -1);
11246 tbase_dc.SelectObject(bm_base);
11247 tbase_dc.Blit(0, 0, svp.pix_width, svp.pix_height, &temp_dc, 0, 0);
11248 tbase_dc.SelectObject(wxNullBitmap);
11250 const wxBitmap &bm_base = temp_dc.GetSelectedBitmap();
11253 wxImage base_image;
11254 if (bm_base.IsOk()) base_image = bm_base.ConvertToImage();
11260 double angle = GetVP().skew - GetVP().rotation;
11262 bool b_rot_ok =
false;
11263 if (base_image.IsOk()) {
11266 m_b_rot_hidef =
false;
11270 wxPoint(GetVP().rv_rect.width / 2, GetVP().rv_rect.height / 2),
11271 m_b_rot_hidef, &m_roffset);
11273 if ((rot_vp.view_scale_ppm == VPoint.view_scale_ppm) &&
11274 (rot_vp.rotation == VPoint.rotation) &&
11275 (rot_vp.clat == VPoint.clat) && (rot_vp.clon == VPoint.clon) &&
11276 rot_vp.IsValid() && (ri.IsOk())) {
11283 m_prot_bm =
new wxBitmap(ri);
11286 m_roffset.x += VPoint.rv_rect.x;
11287 m_roffset.y += VPoint.rv_rect.y;
11290 if (m_prot_bm && m_prot_bm->IsOk()) {
11291 rotd_dc.SelectObject(*m_prot_bm);
11292 pChartDC = &rotd_dc;
11294 pChartDC = &temp_dc;
11295 m_roffset = wxPoint(0, 0);
11298 pChartDC = &temp_dc;
11299 m_roffset = wxPoint(0, 0);
11302 wxPoint offset = m_roffset;
11305 m_cache_vp = VPoint;
11308 wxMemoryDC mscratch_dc;
11309 mscratch_dc.SelectObject(*pscratch_bm);
11311 mscratch_dc.ResetBoundingBox();
11312 mscratch_dc.DestroyClippingRegion();
11313 mscratch_dc.SetDeviceClippingRegion(rgn_chart);
11316 wxRegionIterator upd(rgn_blit);
11318 wxRect rect = upd.GetRect();
11320 mscratch_dc.Blit(rect.x, rect.y, rect.width, rect.height, pChartDC,
11321 rect.x - offset.x, rect.y - offset.y);
11327 if (g_canvasConfig != 0) {
11328 if (
this == wxWindow::FindFocus()) {
11329 g_focusCanvas =
this;
11331 wxColour colour = GetGlobalColor(_T(
"BLUE4"));
11332 mscratch_dc.SetPen(wxPen(colour));
11333 mscratch_dc.SetBrush(wxBrush(colour));
11335 wxRect activeRect(0, 0, GetClientSize().x, m_focus_indicator_pix);
11336 mscratch_dc.DrawRectangle(activeRect);
11341 std::vector<int> stackIndexArray = m_pQuilt->GetExtendedStackIndexArray();
11342 unsigned int im = stackIndexArray.size();
11343 if (VPoint.b_quilt && im > 0) {
11344 std::vector<int> tiles_to_show;
11345 for (
unsigned int is = 0; is < im; is++) {
11347 ChartData->GetChartTableEntry(stackIndexArray[is]);
11348 if (IsTileOverlayIndexInNoShow(stackIndexArray[is])) {
11351 if (cte.GetChartType() == CHART_TYPE_MBTILES) {
11352 tiles_to_show.push_back(stackIndexArray[is]);
11356 if (tiles_to_show.size())
11357 SetAlertString(_(
"MBTile requires OpenGL to be enabled"));
11364 ocpnDC scratch_dc(mscratch_dc);
11365 DrawOverlayObjects(scratch_dc, ru);
11368 RebuildTideSelectList(GetVP().GetBBox());
11369 DrawAllTidesInBBox(scratch_dc, GetVP().GetBBox());
11372 if (m_bShowCurrent) {
11373 RebuildCurrentSelectList(GetVP().GetBBox());
11374 DrawAllCurrentsInBBox(scratch_dc, GetVP().GetBBox());
11377 if (m_brepaint_piano && g_bShowChartBar) {
11378 m_Piano->Paint(GetClientSize().y - m_Piano->GetHeight(), mscratch_dc);
11381 if (m_Compass) m_Compass->Paint(scratch_dc);
11383 RenderAlertMessage(mscratch_dc, GetVP());
11388 #ifdef ocpnUSE_DIBSECTION
11393 wxBitmap qbm(GetVP().pix_width, GetVP().pix_height);
11394 q_dc.SelectObject(qbm);
11397 q_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &mscratch_dc, 0, 0);
11400 wxBrush qbr(*wxBLACK, wxBRUSHSTYLE_FDIAGONAL_HATCH);
11401 q_dc.SetBrush(qbr);
11402 q_dc.DrawRectangle(0, 0, GetVP().pix_width, GetVP().pix_height);
11405 mscratch_dc.Blit(0, 0, GetVP().pix_width, GetVP().pix_height, &q_dc, 0, 0,
11408 q_dc.SelectObject(wxNullBitmap);
11415 if( VPoint.b_quilt ) {
11416 if(m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()){
11417 ChartBase *chart = m_pQuilt->GetRefChart();
11418 if( chart && chart->GetChartType() != CHART_TYPE_CM93COMP){
11423 ChPI->ClearPLIBTextList();
11426 ps52plib->ClearTextList();
11430 wxBitmap qbm( GetVP().pix_width, GetVP().pix_height );
11432 wxColor maskBackground = wxColour(1,0,0);
11433 t_dc.SelectObject( qbm );
11434 t_dc.SetBackground(wxBrush(maskBackground));
11438 t_dc.Blit( 0, 0, GetVP().pix_width, GetVP().pix_height, scratch_dc.GetDC(), 0, 0, wxCOPY );
11441 OCPNRegion chart_all_text_region( wxRect( 0, 0, GetVP().pix_width, GetVP().pix_height ) );
11442 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly( t_dc, svp, chart_all_text_region );
11445 wxRegionIterator upd_final( ru );
11446 while( upd_final ) {
11447 wxRect rect = upd_final.GetRect();
11448 scratch_dc.GetDC()->Blit( rect.x, rect.y, rect.width, rect.height, &t_dc, rect.x, rect.y, wxCOPY,
true );
11452 t_dc.SelectObject( wxNullBitmap );
11458 if (VPoint.b_quilt) {
11459 if (m_pQuilt->IsQuiltVector() && ps52plib && ps52plib->GetShowS57Text()) {
11460 ChartBase *chart = m_pQuilt->GetRefChart();
11461 if (chart && chart->GetChartType() != CHART_TYPE_CM93COMP) {
11465 ChPI->ClearPLIBTextList();
11467 if (ps52plib) ps52plib->ClearTextList();
11472 wxRect(0, 0, GetVP().pix_width, GetVP().pix_height));
11474 if (g_bShowChartBar && m_Piano) {
11475 wxRect chart_bar_rect(0, GetVP().pix_height - m_Piano->GetHeight(),
11476 GetVP().pix_width, m_Piano->GetHeight());
11479 if (!style->chartStatusWindowTransparent)
11480 chart_all_text_region.Subtract(chart_bar_rect);
11483 if (m_Compass && m_Compass->IsShown()) {
11484 wxRect compassRect = m_Compass->GetRect();
11485 if (chart_all_text_region.Contains(compassRect) != wxOutRegion) {
11486 chart_all_text_region.Subtract(compassRect);
11490 mscratch_dc.DestroyClippingRegion();
11492 m_pQuilt->RenderQuiltRegionViewOnDCTextOnly(mscratch_dc, svp,
11493 chart_all_text_region);
11499 wxRegionIterator upd_final(rgn_blit);
11500 while (upd_final) {
11501 wxRect rect = upd_final.GetRect();
11502 dc.Blit(rect.x, rect.y, rect.width, rect.height, &mscratch_dc, rect.x,
11523 temp_dc.SelectObject(wxNullBitmap);
11525 mscratch_dc.SelectObject(wxNullBitmap);
11527 dc.DestroyClippingRegion();
11532 void ChartCanvas::PaintCleanup() {
11544 m_bTCupdate =
false;
11548 WarpPointer(warp_x, warp_y);
11555 pMovementTimer->Start(1, wxTIMER_ONE_SHOT);
11559 wxColour GetErrorGraphicColor(
double val)
11578 if((val > 0) && (val < 1)) c.Set(_T(
"#002ad9"));
11579 else if((val >= 1) && (val < 2)) c.Set(_T(
"#006ed9"));
11580 else if((val >= 2) && (val < 3)) c.Set(_T(
"#00b2d9"));
11581 else if((val >= 3) && (val < 4)) c.Set(_T(
"#00d4d4"));
11582 else if((val >= 4) && (val < 5)) c.Set(_T(
"#00d9a6"));
11583 else if((val >= 5) && (val < 7)) c.Set(_T(
"#00d900"));
11584 else if((val >= 7) && (val < 9)) c.Set(_T(
"#95d900"));
11585 else if((val >= 9) && (val < 12)) c.Set(_T(
"#d9d900"));
11586 else if((val >= 12) && (val < 15)) c.Set(_T(
"#d9ae00"));
11587 else if((val >= 15) && (val < 18)) c.Set(_T(
"#d98300"));
11588 else if((val >= 18) && (val < 21)) c.Set(_T(
"#d95700"));
11589 else if((val >= 21) && (val < 24)) c.Set(_T(
"#d90000"));
11590 else if((val >= 24) && (val < 27)) c.Set(_T(
"#ae0000"));
11591 else if((val >= 27) && (val < 30)) c.Set(_T(
"#8c0000"));
11592 else if((val >= 30) && (val < 36)) c.Set(_T(
"#870000"));
11593 else if((val >= 36) && (val < 42)) c.Set(_T(
"#690000"));
11594 else if((val >= 42) && (val < 48)) c.Set(_T(
"#550000"));
11595 else if( val >= 48) c.Set(_T(
"#410000"));
11600 void ChartCanvas::RenderGeorefErrorMap( wxMemoryDC *pmdc,
ViewPort *vp)
11602 wxImage gr_image(vp->pix_width, vp->pix_height);
11603 gr_image.InitAlpha();
11605 double maxval = -10000;
11606 double minval = 10000;
11611 GetCanvasPixPoint(0, 0, rlat, rlon);
11613 for(
int i=1; i < vp->pix_height-1; i++)
11615 for(
int j=0; j < vp->pix_width; j++)
11621 GetCanvasPixPoint(j, i, glat, glon);
11623 maxval = wxMax(maxval, (glat - rlat));
11624 minval = wxMin(minval, (glat - rlat));
11630 GetCanvasPixPoint(0, 0, rlat, rlon);
11631 for(
int i=1; i < vp->pix_height-1; i++)
11633 for(
int j=0; j < vp->pix_width; j++)
11639 GetCanvasPixPoint(j, i, glat, glon);
11641 double f = ((glat - rlat)-minval)/(maxval - minval);
11643 double dy = (f * 40);
11645 wxColour c = GetErrorGraphicColor(dy);
11646 unsigned char r = c.Red();
11647 unsigned char g = c.Green();
11648 unsigned char b = c.Blue();
11650 gr_image.SetRGB(j, i, r,g,b);
11651 if((glat - rlat )!= 0)
11652 gr_image.SetAlpha(j, i, 128);
11654 gr_image.SetAlpha(j, i, 255);
11661 wxBitmap *pbm =
new wxBitmap(gr_image);
11662 wxMask *gr_mask =
new wxMask(*pbm, wxColour(0,0,0));
11663 pbm->SetMask(gr_mask);
11665 pmdc->DrawBitmap(*pbm, 0,0);
11673 void ChartCanvas::CancelMouseRoute() {
11675 m_pMouseRoute = NULL;
11676 m_bDrawingRoute =
false;
11679 int ChartCanvas::GetNextContextMenuId() {
11680 return CanvasMenuHandler::GetNextContextMenuId();
11683 bool ChartCanvas::SetCursor(
const wxCursor &c) {
11685 if (g_bopengl && m_glcc)
11686 return m_glcc->SetCursor(c);
11689 return wxWindow::SetCursor(c);
11692 void ChartCanvas::Refresh(
bool eraseBackground,
const wxRect *rect) {
11693 if (g_bquiting)
return;
11695 GetCanvasPixPoint(mouse_x, mouse_y, m_cursor_lat, m_cursor_lon);
11703 if (!m_RolloverPopupTimer.IsRunning() &&
11704 ((m_pRouteRolloverWin && m_pRouteRolloverWin->IsActive()) ||
11705 (m_pTrackRolloverWin && m_pTrackRolloverWin->IsActive()) ||
11706 (m_pAISRolloverWin && m_pAISRolloverWin->IsActive())))
11707 m_RolloverPopupTimer.Start(500, wxTIMER_ONE_SHOT);
11710 if (m_glcc && g_bopengl) {
11713 if (eraseBackground && m_glcc->UsingFBO()) m_glcc->Invalidate();
11715 m_glcc->Refresh(eraseBackground,
11726 if (pthumbwin && pthumbwin->IsShown()) {
11727 pthumbwin->Raise();
11728 pthumbwin->Refresh(
false);
11732 if (m_pCIWin && m_pCIWin->IsShown()) {
11734 m_pCIWin->Refresh(
false);
11742 wxWindow::Refresh(eraseBackground, rect);
11745 void ChartCanvas::Update() {
11746 if (m_glcc && g_bopengl) {
11751 wxWindow::Update();
11755 if (!pemboss)
return;
11756 int x = pemboss->x, y = pemboss->y;
11757 const double factor = 200;
11759 wxASSERT_MSG(dc.GetDC(), wxT(
"DrawEmboss has no dc (opengl?)"));
11760 wxMemoryDC *pmdc =
dynamic_cast<wxMemoryDC *
>(dc.GetDC());
11761 wxASSERT_MSG(pmdc, wxT(
"dc to EmbossCanvas not a memory dc"));
11764 wxMemoryDC snip_dc;
11765 wxBitmap snip_bmp(pemboss->width, pemboss->height, -1);
11766 snip_dc.SelectObject(snip_bmp);
11768 snip_dc.Blit(0, 0, pemboss->width, pemboss->height, pmdc, x, y);
11769 snip_dc.SelectObject(wxNullBitmap);
11771 wxImage snip_img = snip_bmp.ConvertToImage();
11774 unsigned char *pdata = snip_img.GetData();
11776 for (
int y = 0; y < pemboss->height; y++) {
11777 int map_index = (y * pemboss->width);
11778 for (
int x = 0; x < pemboss->width; x++) {
11779 double val = (pemboss->pmap[map_index] * factor) / 256.;
11781 int nred = (int)((*pdata) + val);
11782 nred = nred > 255 ? 255 : (nred < 0 ? 0 : nred);
11783 *pdata++ = (
unsigned char)nred;
11785 int ngreen = (int)((*pdata) + val);
11786 ngreen = ngreen > 255 ? 255 : (ngreen < 0 ? 0 : ngreen);
11787 *pdata++ = (
unsigned char)ngreen;
11789 int nblue = (int)((*pdata) + val);
11790 nblue = nblue > 255 ? 255 : (nblue < 0 ? 0 : nblue);
11791 *pdata++ = (
unsigned char)nblue;
11799 wxBitmap emb_bmp(snip_img);
11802 wxMemoryDC result_dc;
11803 result_dc.SelectObject(emb_bmp);
11806 pmdc->Blit(x, y, pemboss->width, pemboss->height, &result_dc, 0, 0);
11808 result_dc.SelectObject(wxNullBitmap);
11812 double zoom_factor = GetVP().ref_scale / GetVP().chart_scale;
11814 if (GetQuiltMode()) {
11816 int refIndex = GetQuiltRefChartdbIndex();
11817 if (refIndex >= 0) {
11818 const ChartTableEntry &cte = ChartData->GetChartTableEntry(refIndex);
11819 ChartTypeEnum current_type = (ChartTypeEnum)cte.GetChartType();
11820 if (current_type == CHART_TYPE_MBTILES) {
11821 ChartBase *pChart = m_pQuilt->GetRefChart();
11824 zoom_factor = ptc->GetZoomFactor();
11829 if (zoom_factor <= 3.9)
return NULL;
11831 if (m_singleChart) {
11832 if (zoom_factor <= 3.9)
return NULL;
11837 if (m_pEM_OverZoom) {
11838 m_pEM_OverZoom->x = 4;
11839 m_pEM_OverZoom->y = 0;
11840 if (g_MainToolbar && IsPrimaryCanvas()) {
11841 wxRect masterToolbarRect = g_MainToolbar->GetToolbarRect();
11842 m_pEM_OverZoom->x = masterToolbarRect.width + 4;
11845 return m_pEM_OverZoom;
11848 void ChartCanvas::DrawOverlayObjects(
ocpnDC &dc,
const wxRegion &ru) {
11858 g_overlayCanvas =
this;
11860 if (g_pi_manager) {
11861 g_pi_manager->SendViewPortToRequestingPlugIns(GetVP());
11862 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_LEGACY);
11865 AISDrawAreaNotices(dc, GetVP(),
this);
11867 wxDC *pdc = dc.GetDC();
11869 pdc->DestroyClippingRegion();
11870 wxDCClipper(*pdc, ru);
11873 if (m_bShowNavobjects) {
11874 DrawAllTracksInBBox(dc, GetVP().GetBBox());
11875 DrawAllRoutesInBBox(dc, GetVP().GetBBox());
11876 DrawAllWaypointsInBBox(dc, GetVP().GetBBox());
11877 DrawAnchorWatchPoints(dc);
11879 DrawActiveTrackInBBox(dc, GetVP().GetBBox());
11880 DrawActiveRouteInBBox(dc, GetVP().GetBBox());
11883 AISDraw(dc, GetVP(),
this);
11887 RenderVisibleSectorLights(dc);
11889 RenderAllChartOutlines(dc, GetVP());
11890 RenderRouteLegs(dc);
11891 RenderShipToActive(dc,
false);
11893 s57_DrawExtendedLightSectors(dc, VPoint, extendedSectorLegs);
11894 if (g_pi_manager) {
11895 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_OVER_SHIPS);
11898 DrawEmboss(dc, EmbossDepthScale());
11899 DrawEmboss(dc, EmbossOverzoomIndicator(dc));
11900 if (g_pi_manager) {
11901 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_OVER_EMBOSS);
11903 if(!g_PrintingInProgress){
11904 if (IsPrimaryCanvas()) {
11905 if (g_MainToolbar) g_MainToolbar->DrawDC(dc, 1.0);
11908 if (IsPrimaryCanvas()) {
11909 if (g_iENCToolbar) g_iENCToolbar->DrawDC(dc, 1.0);
11913 m_muiBar->DrawDC( dc, 1.0);
11915 if (m_pTrackRolloverWin) {
11916 m_pTrackRolloverWin->Draw(dc);
11917 m_brepaint_piano =
true;
11920 if (m_pRouteRolloverWin) {
11921 m_pRouteRolloverWin->Draw(dc);
11922 m_brepaint_piano =
true;
11925 if (m_pAISRolloverWin) {
11926 m_pAISRolloverWin->Draw(dc);
11927 m_brepaint_piano =
true;
11930 if (g_pi_manager) {
11931 g_pi_manager->RenderAllCanvasOverlayPlugIns(dc, GetVP(), m_canvasIndex, OVERLAY_OVER_UI);
11936 if (!m_bShowDepthUnits)
return NULL;
11938 int depth_unit_type = DEPTH_UNIT_UNKNOWN;
11940 if (GetQuiltMode()) {
11941 wxString s = m_pQuilt->GetQuiltDepthUnit();
11943 if (s == _T(
"FEET"))
11944 depth_unit_type = DEPTH_UNIT_FEET;
11945 else if (s.StartsWith(_T(
"FATHOMS")))
11946 depth_unit_type = DEPTH_UNIT_FATHOMS;
11947 else if (s.StartsWith(_T(
"METERS")))
11948 depth_unit_type = DEPTH_UNIT_METERS;
11949 else if (s.StartsWith(_T(
"METRES")))
11950 depth_unit_type = DEPTH_UNIT_METERS;
11951 else if (s.StartsWith(_T(
"METRIC")))
11952 depth_unit_type = DEPTH_UNIT_METERS;
11953 else if (s.StartsWith(_T(
"METER")))
11954 depth_unit_type = DEPTH_UNIT_METERS;
11957 if (m_singleChart) {
11958 depth_unit_type = m_singleChart->GetDepthUnitType();
11959 if (m_singleChart->GetChartFamily() == CHART_FAMILY_VECTOR)
11960 depth_unit_type = ps52plib->m_nDepthUnitDisplay + 1;
11965 switch (depth_unit_type) {
11966 case DEPTH_UNIT_FEET:
11969 case DEPTH_UNIT_METERS:
11970 ped = m_pEM_Meters;
11972 case DEPTH_UNIT_FATHOMS:
11973 ped = m_pEM_Fathoms;
11979 ped->x = (GetVP().pix_width - ped->width);
11981 if (m_Compass && m_bShowCompassWin) {
11982 wxRect r = m_Compass->GetRect();
11983 ped->y = r.y + r.height;
11990 void ChartCanvas::CreateDepthUnitEmbossMaps(ColorScheme cs) {
11993 if (style->embossFont == wxEmptyString) {
11994 wxFont *dFont = FontMgr::Get().GetFont(_(
"Dialog"), 0);
11996 font.SetPointSize(60);
11997 font.SetWeight(wxFONTWEIGHT_BOLD);
11999 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12000 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12002 int emboss_width = 500;
12003 int emboss_height = 200;
12007 delete m_pEM_Meters;
12008 delete m_pEM_Fathoms;
12012 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Feet"), cs);
12014 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Meters"), cs);
12016 CreateEmbossMapData(font, emboss_width, emboss_height, _(
"Fathoms"), cs);
12019 #define OVERZOOM_TEXT _("OverZoom")
12021 void ChartCanvas::SetOverzoomFont() {
12026 if (style->embossFont == wxEmptyString) {
12027 wxFont *dFont = FontMgr::Get().GetFont(_(
"Dialog"), 0);
12029 font.SetPointSize(40);
12030 font.SetWeight(wxFONTWEIGHT_BOLD);
12032 font = wxFont(style->embossHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL,
12033 wxFONTWEIGHT_BOLD,
false, style->embossFont);
12035 wxClientDC dc(
this);
12037 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12039 while (font.GetPointSize() > 10 && (w > 500 || h > 100)) {
12040 font.SetPointSize(font.GetPointSize() - 1);
12042 dc.GetTextExtent(OVERZOOM_TEXT, &w, &h);
12044 m_overzoomFont = font;
12045 m_overzoomTextWidth = w;
12046 m_overzoomTextHeight = h;
12049 void ChartCanvas::CreateOZEmbossMapData(ColorScheme cs) {
12050 delete m_pEM_OverZoom;
12052 if (m_overzoomTextWidth > 0 && m_overzoomTextHeight > 0)
12054 CreateEmbossMapData(m_overzoomFont, m_overzoomTextWidth + 10,
12055 m_overzoomTextHeight + 10, OVERZOOM_TEXT, cs);
12058 emboss_data *ChartCanvas::CreateEmbossMapData(wxFont &font,
int width,
12059 int height,
const wxString &str,
12064 wxBitmap bmp(width, height, -1);
12067 wxMemoryDC temp_dc;
12068 temp_dc.SelectObject(bmp);
12071 temp_dc.SetBackground(*wxWHITE_BRUSH);
12072 temp_dc.SetTextBackground(*wxWHITE);
12073 temp_dc.SetTextForeground(*wxBLACK);
12077 temp_dc.SetFont(font);
12080 temp_dc.GetTextExtent(str, &str_w, &str_h);
12082 temp_dc.DrawText(str, 1, 1);
12085 temp_dc.SelectObject(wxNullBitmap);
12088 wxImage img = bmp.ConvertToImage();
12090 int image_width = str_w * 105 / 100;
12091 int image_height = str_h * 105 / 100;
12092 wxRect r(0, 0, wxMin(image_width, img.GetWidth()),
12093 wxMin(image_height, img.GetHeight()));
12094 wxImage imgs = img.GetSubImage(r);
12098 case GLOBAL_COLOR_SCHEME_DAY:
12102 case GLOBAL_COLOR_SCHEME_DUSK:
12105 case GLOBAL_COLOR_SCHEME_NIGHT:
12112 const int w = imgs.GetWidth();
12113 const int h = imgs.GetHeight();
12114 pmap = (
int *)calloc(w * h *
sizeof(
int), 1);
12119 for (
int y = 1; y < h - 1; y++) {
12120 for (
int x = 1; x < w - 1; x++) {
12122 img.GetRed(x + 1, y + 1) - img.GetRed(x - 1, y - 1);
12123 val = (int)(val * val_factor);
12124 index = (y * w) + x;
12137 void ChartCanvas::DrawAllTracksInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12138 Track *active_track = NULL;
12139 for (
Track* pTrackDraw : g_TrackList) {
12140 if (g_pActiveTrack == pTrackDraw) {
12141 active_track = pTrackDraw;
12145 TrackGui(*pTrackDraw).Draw(
this, dc, GetVP(), BltBBox);
12148 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12151 void ChartCanvas::DrawActiveTrackInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12152 Track *active_track = NULL;
12153 for (
Track* pTrackDraw : g_TrackList) {
12154 if (g_pActiveTrack == pTrackDraw) {
12155 active_track = pTrackDraw;
12159 if (active_track)
TrackGui(*active_track).Draw(
this, dc, GetVP(), BltBBox);
12162 void ChartCanvas::DrawAllRoutesInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12163 Route *active_route = NULL;
12165 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12166 node = node->GetNext()) {
12167 Route *pRouteDraw = node->GetData();
12168 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12169 active_route = pRouteDraw;
12174 RouteGui(*pRouteDraw).Draw(dc,
this, BltBBox);
12179 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12182 void ChartCanvas::DrawActiveRouteInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12183 Route *active_route = NULL;
12185 for (wxRouteListNode *node = pRouteList->GetFirst(); node;
12186 node = node->GetNext()) {
12187 Route *pRouteDraw = node->GetData();
12188 if (pRouteDraw->IsActive() || pRouteDraw->IsSelected()) {
12189 active_route = pRouteDraw;
12193 if (active_route)
RouteGui(*active_route).Draw(dc,
this, BltBBox);
12196 void ChartCanvas::DrawAllWaypointsInBBox(
ocpnDC &dc, LLBBox &BltBBox) {
12197 if (!pWayPointMan)
return;
12199 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12204 if (pWP->m_bIsInRoute) {
12205 node = node->GetNext();
12210 if (BltBBox.Contains(pWP->m_lat, pWP->m_lon))
12214 if (pWP->GetShowWaypointRangeRings() &&
12215 (pWP->GetWaypointRangeRingsNumber() > 0)) {
12216 double factor = 1.00;
12217 if (pWP->GetWaypointRangeRingsStepUnits() ==
12219 factor = 1 / 1.852;
12221 double radius = factor * pWP->GetWaypointRangeRingsNumber() *
12222 pWP->GetWaypointRangeRingsStep() / 60.;
12226 radar_box.Set(pWP->m_lat - radius, pWP->m_lon - radius,
12227 pWP->m_lat + radius, pWP->m_lon + radius);
12228 if (!BltBBox.IntersectOut(radar_box)) {
12235 node = node->GetNext();
12239 void ChartCanvas::DrawBlinkObjects(
void) {
12241 wxRect update_rect;
12243 if (!pWayPointMan)
return;
12245 wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst();
12250 if (pWP->m_bBlink) {
12251 update_rect.Union(pWP->CurrentRect_in_DC);
12255 node = node->GetNext();
12257 if (!update_rect.IsEmpty()) RefreshRect(update_rect);
12260 void ChartCanvas::DrawAnchorWatchPoints(
ocpnDC &dc) {
12263 if (pAnchorWatchPoint1 || pAnchorWatchPoint2) {
12265 wxPoint lAnchorPoint1, lAnchorPoint2;
12268 if (pAnchorWatchPoint1) {
12269 lpp1 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint1);
12270 GetCanvasPointPix(pAnchorWatchPoint1->m_lat, pAnchorWatchPoint1->m_lon,
12273 if (pAnchorWatchPoint2) {
12274 lpp2 = GetAnchorWatchRadiusPixels(pAnchorWatchPoint2);
12275 GetCanvasPointPix(pAnchorWatchPoint2->m_lat, pAnchorWatchPoint2->m_lon,
12279 wxPen ppPeng(GetGlobalColor(_T (
"UGREN" )), 2);
12280 wxPen ppPenr(GetGlobalColor(_T (
"URED" )), 2);
12282 wxBrush *ppBrush = wxTheBrushList->FindOrCreateBrush(
12283 wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT);
12284 dc.SetBrush(*ppBrush);
12288 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12293 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12298 dc.StrokeCircle(lAnchorPoint1.x, lAnchorPoint1.y, fabs(lpp1));
12303 dc.StrokeCircle(lAnchorPoint2.x, lAnchorPoint2.y, fabs(lpp2));
12308 double ChartCanvas::GetAnchorWatchRadiusPixels(
RoutePoint *pAnchorWatchPoint) {
12311 wxPoint lAnchorPoint;
12314 double tlat1, tlon1;
12316 if (pAnchorWatchPoint) {
12317 (pAnchorWatchPoint->GetName()).ToDouble(&d1);
12318 d1 = AnchorDistFix(d1, AnchorPointMinDist, g_nAWMax);
12319 dabs = fabs(d1 / 1852.);
12320 ll_gc_ll(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon, 0, dabs,
12322 GetCanvasPointPix(tlat1, tlon1, &r1);
12323 GetCanvasPointPix(pAnchorWatchPoint->m_lat, pAnchorWatchPoint->m_lon,
12325 lpp = sqrt(pow((
double)(lAnchorPoint.x - r1.x), 2) +
12326 pow((
double)(lAnchorPoint.y - r1.y), 2));
12329 if (d1 < 0) lpp = -lpp;
12337 void ChartCanvas::RebuildTideSelectList(LLBBox &BBox) {
12338 if (!ptcmgr)
return;
12340 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_TIDEPOINT);
12342 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12343 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12344 double lon = pIDX->IDX_lon;
12345 double lat = pIDX->IDX_lat;
12347 char type = pIDX->IDX_type;
12348 if ((type ==
't') || (type ==
'T')) {
12349 if (BBox.Contains(lat, lon)) {
12351 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_TIDEPOINT);
12357 extern wxDateTime gTimeSource;
12359 void ChartCanvas::DrawAllTidesInBBox(
ocpnDC &dc, LLBBox &BBox) {
12360 if (!ptcmgr)
return;
12362 wxDateTime this_now = gTimeSource;
12363 bool cur_time = !gTimeSource.IsValid();
12364 if (cur_time) this_now = wxDateTime::Now();
12365 time_t t_this_now = this_now.GetTicks();
12367 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12368 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12369 wxPen *pyelo_pen = wxThePenList->FindOrCreatePen(
12370 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )), 1,
12372 wxPen *pblue_pen = wxThePenList->FindOrCreatePen(
12373 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )), 1,
12376 wxBrush *pgreen_brush = wxTheBrushList->FindOrCreateBrush(
12377 GetGlobalColor(_T (
"GREEN1" )), wxBRUSHSTYLE_SOLID);
12380 wxBrush *pblue_brush = wxTheBrushList->FindOrCreateBrush(
12381 GetGlobalColor(cur_time ? _T (
"BLUE2" ) : _T (
"BLUE3" )),
12382 wxBRUSHSTYLE_SOLID);
12383 wxBrush *pyelo_brush = wxTheBrushList->FindOrCreateBrush(
12384 GetGlobalColor(cur_time ? _T (
"YELO1" ) : _T (
"YELO2" )),
12385 wxBRUSHSTYLE_SOLID);
12387 wxFont *dFont = FontMgr::Get().GetFont(_(
"ExtendedTideIcon"));
12388 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"ExtendedTideIcon")));
12389 int font_size = wxMax(10, dFont->GetPointSize());
12390 font_size /= g_Platform->GetDisplayDIPMult(
this);
12391 wxFont *plabelFont =
12392 FontMgr::Get().FindOrCreateFont(font_size,
12393 dFont->GetFamily(), dFont->GetStyle(),
12394 dFont->GetWeight(),
false,
12395 dFont->GetFaceName());
12397 dc.SetPen(*pblack_pen);
12398 dc.SetBrush(*pgreen_brush);
12402 case GLOBAL_COLOR_SCHEME_DAY:
12405 case GLOBAL_COLOR_SCHEME_DUSK:
12408 case GLOBAL_COLOR_SCHEME_NIGHT:
12409 bm = m_bmTideNight;
12416 int bmw = bm.GetWidth();
12417 int bmh = bm.GetHeight();
12419 float scale_factor = 1.0;
12423 float icon_pixelRefDim = 45;
12426 float nominal_icon_size_mm = g_Platform->GetDisplaySizeMM() *25 / 1000;
12427 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 8);
12428 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 15);
12429 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12432 #ifndef __ANDROID__
12443 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, plabelFont);
12444 height *= g_Platform->GetDisplayDIPMult(
this);
12445 float nominal_icon_size_pixels = 48;
12446 float pix_factor = (2 * height) / nominal_icon_size_pixels;
12457 double targetHeight0 = 16.0;
12460 double displaySize = m_display_size_mm;
12461 displaySize = wxMax(displaySize, 100);
12463 float targetHeight = wxMin(targetHeight0, displaySize / 15);
12465 double pix_factor = targetHeight / symHeight;
12468 scale_factor *= pix_factor;
12470 float user_scale_factor = g_ChartScaleFactorExp;
12471 if (g_ChartScaleFactorExp > 1.0)
12472 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
12475 scale_factor *= user_scale_factor;
12476 scale_factor *= GetContentScaleFactor();
12480 double marge = 0.05;
12481 std::vector<LLBBox> drawn_boxes;
12482 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12483 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12485 char type = pIDX->IDX_type;
12486 if ((type ==
't') || (type ==
'T'))
12488 double lon = pIDX->IDX_lon;
12489 double lat = pIDX->IDX_lat;
12491 if (BBox.ContainsMarge(lat, lon, marge)) {
12494 if (GetVP().chart_scale < 500000){
12495 bool bdrawn =
false;
12496 for (
size_t i = 0; i < drawn_boxes.size(); i++){
12497 if (drawn_boxes[i].Contains(lat, lon)){
12506 this_box.Set(lat, lon, lat, lon);
12507 this_box.EnLarge(.005);
12508 drawn_boxes.push_back(this_box);
12512 GetCanvasPointPix(lat, lon, &r);
12514 if (GetVP().chart_scale > 500000) {
12515 dc.DrawBitmap(bm, r.x - bmw / 2, r.y - bmh / 2,
true);
12519 dc.SetFont(*plabelFont);
12531 if (ptcmgr->GetTideFlowSens(
12532 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12533 pIDX->IDX_rec_num, nowlev, val, wt)) {
12536 ptcmgr->GetHightOrLowTide(
12537 t_this_now + BACKWARD_TEN_MINUTES_STEP,
12538 FORWARD_TEN_MINUTES_STEP, FORWARD_ONE_MINUTES_STEP, val,
12539 wt, pIDX->IDX_rec_num, val, tctime);
12550 if (tctime > t_this_now)
12551 ptcmgr->GetHightOrLowTide(
12552 t_this_now, BACKWARD_TEN_MINUTES_STEP,
12553 BACKWARD_ONE_MINUTES_STEP, nowlev, wt,
12554 pIDX->IDX_rec_num, val, tctime);
12557 ptcmgr->GetHightOrLowTide(
12558 t_this_now, FORWARD_TEN_MINUTES_STEP,
12559 FORWARD_ONE_MINUTES_STEP, nowlev, wt, pIDX->IDX_rec_num,
12573 int width = (int)(12 * scale_factor + 0.5);
12574 int height = (int)(45 * scale_factor + 0.5);
12575 int linew = wxMax(1, (
int)(scale_factor));
12576 int xDraw = r.x - (width / 2);
12577 int yDraw = r.y - (height / 2);
12580 float ts = 1 - ((nowlev - ltleve) / (htleve - ltleve));
12581 int hs = (httime > lttime) ? -4 : 4;
12582 hs *= (int)(scale_factor + 0.5);
12583 if (ts > 0.995 || ts < 0.005) hs = 0;
12584 int ht_y = (int)(height * ts);
12587 pblack_pen->SetWidth(linew);
12588 dc.SetPen(*pblack_pen);
12589 dc.SetBrush(*pyelo_brush);
12590 dc.DrawRectangle(xDraw, yDraw, width, height);
12594 dc.SetPen(*pblue_pen);
12595 dc.SetBrush(*pblue_brush);
12596 dc.DrawRectangle((xDraw + 2 * linew), yDraw + ht_y,
12597 (width - (4 * linew)), height - ht_y);
12603 arrow[0].x = xDraw + 2 * linew;
12604 arrow[1].x = xDraw + width / 2;
12605 arrow[2].x = xDraw + width - 2 * linew;
12606 pyelo_pen->SetWidth(linew);
12607 pblue_pen->SetWidth(linew);
12608 if (ts > 0.35 || ts < 0.15)
12610 hl = (int)(height * 0.25) + yDraw;
12612 arrow[1].y = hl + hs;
12615 dc.SetPen(*pyelo_pen);
12617 dc.SetPen(*pblue_pen);
12618 dc.DrawLines(3, arrow);
12620 if (ts > 0.60 || ts < 0.40)
12622 hl = (int)(height * 0.5) + yDraw;
12624 arrow[1].y = hl + hs;
12627 dc.SetPen(*pyelo_pen);
12629 dc.SetPen(*pblue_pen);
12630 dc.DrawLines(3, arrow);
12632 if (ts < 0.65 || ts > 0.85)
12634 hl = (int)(height * 0.75) + yDraw;
12636 arrow[1].y = hl + hs;
12639 dc.SetPen(*pyelo_pen);
12641 dc.SetPen(*pblue_pen);
12642 dc.DrawLines(3, arrow);
12646 s.Printf(_T(
"%3.1f"), nowlev);
12648 if (pmsd) s.Append(wxString(pmsd->units_abbrv, wxConvUTF8));
12650 dc.GetTextExtent(s, &wx1, NULL);
12651 wx1 *= g_Platform->GetDisplayDIPMult(
this);
12652 dc.DrawText(s, r.x - (wx1 / 2), yDraw + height);
12667 void ChartCanvas::RebuildCurrentSelectList(LLBBox &BBox) {
12668 if (!ptcmgr)
return;
12670 pSelectTC->DeleteAllSelectableTypePoints(SELTYPE_CURRENTPOINT);
12672 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12673 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12674 double lon = pIDX->IDX_lon;
12675 double lat = pIDX->IDX_lat;
12677 char type = pIDX->IDX_type;
12678 if (((type ==
'c') || (type ==
'C')) && (!pIDX->b_skipTooDeep)) {
12679 if ((BBox.Contains(lat, lon))) {
12681 pSelectTC->AddSelectablePoint(lat, lon, pIDX, SELTYPE_CURRENTPOINT);
12687 void ChartCanvas::DrawAllCurrentsInBBox(
ocpnDC &dc, LLBBox &BBox) {
12688 if (!ptcmgr)
return;
12690 float tcvalue, dir;
12694 double lon_last = 0.;
12695 double lat_last = 0.;
12697 double marge = 0.2;
12698 bool cur_time = !gTimeSource.IsValid();
12700 double true_scale_display = floor(VPoint.chart_scale / 100.) * 100.;
12701 bDrawCurrentValues = true_scale_display < g_Show_Target_Name_Scale;
12703 wxPen *pblack_pen = wxThePenList->FindOrCreatePen(
12704 GetGlobalColor(_T (
"UINFD" )), 1, wxPENSTYLE_SOLID);
12705 wxPen *porange_pen = wxThePenList->FindOrCreatePen(
12706 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )), 1,
12708 wxBrush *porange_brush = wxTheBrushList->FindOrCreateBrush(
12709 GetGlobalColor(cur_time ? _T (
"UINFO" ) : _T (
"UINFB" )),
12710 wxBRUSHSTYLE_SOLID);
12711 wxBrush *pgray_brush = wxTheBrushList->FindOrCreateBrush(
12712 GetGlobalColor(_T (
"UIBDR" )), wxBRUSHSTYLE_SOLID);
12713 wxBrush *pblack_brush = wxTheBrushList->FindOrCreateBrush(
12714 GetGlobalColor(_T (
"UINFD" )), wxBRUSHSTYLE_SOLID);
12717 double skew_angle = GetVPRotation();
12719 wxFont *dFont = FontMgr::Get().GetFont(_(
"CurrentValue"));
12720 dc.SetTextForeground(FontMgr::Get().GetFontColor(_(
"CurrentValue")));
12721 int font_size = wxMax(10, dFont->GetPointSize());
12722 font_size /= g_Platform->GetDisplayDIPMult(
this);
12724 FontMgr::Get().FindOrCreateFont(font_size,
12725 dFont->GetFamily(), dFont->GetStyle(),
12726 dFont->GetWeight(),
false,
12727 dFont->GetFaceName());
12730 float scale_factor = 1.0;
12736 float nominal_icon_size_mm = g_Platform->GetDisplaySizeMM() *3 / 1000;
12737 nominal_icon_size_mm = wxMax(nominal_icon_size_mm, 2);
12738 nominal_icon_size_mm = wxMin(nominal_icon_size_mm, 4);
12739 float nominal_icon_size_pixels = wxMax(4.0, floor(g_Platform->GetDisplayDPmm() * nominal_icon_size_mm));
12745 float nominal_icon_size_pixels = 6;
12746 float pix_factor = nominal_icon_size_pixels / icon_pixelRefDim;
12749 #ifndef __ANDROID__
12753 sdc.GetTextExtent(
"M", NULL, &height, NULL, NULL, pTCFont);
12754 height *= g_Platform->GetDisplayDIPMult(
this);
12755 float nominal_icon_size_pixels = 15;
12756 float pix_factor = (1 * height) / nominal_icon_size_pixels;
12763 float icon_pixelRefDim = 5;
12768 double targetHeight0 = 2.0;
12771 double displaySize = m_display_size_mm;
12772 displaySize = wxMax(displaySize, 100);
12774 float targetHeight = wxMin(targetHeight0, displaySize / 50);
12775 double pix_factor = targetHeight / symHeight;
12778 scale_factor *= pix_factor;
12780 float user_scale_factor = g_ChartScaleFactorExp;
12781 if (g_ChartScaleFactorExp > 1.0)
12782 user_scale_factor = (log(g_ChartScaleFactorExp) + 1.0) *
12785 scale_factor *= user_scale_factor;
12787 scale_factor *= GetContentScaleFactor();
12790 for (
int i = 1; i < ptcmgr->Get_max_IDX() + 1; i++) {
12791 const IDX_entry *pIDX = ptcmgr->GetIDX_entry(i);
12792 double lon = pIDX->IDX_lon;
12793 double lat = pIDX->IDX_lat;
12795 char type = pIDX->IDX_type;
12796 if (((type ==
'c') || (type ==
'C')) && (1 )) {
12797 if (!pIDX->b_skipTooDeep && (BBox.ContainsMarge(lat, lon, marge))) {
12799 GetCanvasPointPix(lat, lon, &r);
12802 int dd = (int)(5.0 * scale_factor + 0.5);
12813 pblack_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
12814 dc.SetPen(*pblack_pen);
12815 dc.SetBrush(*porange_brush);
12816 dc.DrawPolygon(4, d);
12819 dc.SetBrush(*pblack_brush);
12820 dc.DrawCircle(r.x, r.y, (
int)(2 * scale_factor));
12823 if (GetVP().chart_scale < 1000000) {
12824 if (!ptcmgr->GetTideOrCurrent15(0, i, tcvalue, dir, bnew_val))
12838 double a1 = fabs(tcvalue) * 10.;
12840 a1 = wxMax(1.0, a1);
12841 double a2 = log10(a1);
12843 float cscale = scale_factor * a2 * 0.4;
12845 porange_pen->SetWidth(wxMax(2, (
int)(scale_factor + 0.5)));
12846 dc.SetPen(*porange_pen);
12847 DrawArrow(dc, pixxc, pixyc, dir - 90 + (skew_angle * 180. / PI),
12851 if (bDrawCurrentValues) {
12852 dc.SetFont(*pTCFont);
12853 snprintf(sbuf, 19,
"%3.1f", fabs(tcvalue));
12854 dc.DrawText(wxString(sbuf, wxConvUTF8), pixxc, pixyc);
12875 void ChartCanvas::DrawTCWindow(
int x,
int y,
void *pvIDX) {
12876 pCwin =
new TCWin(
this, x, y, pvIDX);
12879 #define NUM_CURRENT_ARROW_POINTS 9
12880 static wxPoint CurrentArrowArray[NUM_CURRENT_ARROW_POINTS] = {
12881 wxPoint(0, 0), wxPoint(0, -10), wxPoint(55, -10),
12882 wxPoint(55, -25), wxPoint(100, 0), wxPoint(55, 25),
12883 wxPoint(55, 10), wxPoint(0, 10), wxPoint(0, 0)};
12885 void ChartCanvas::DrawArrow(
ocpnDC &dc,
int x,
int y,
double rot_angle,
12887 if (
scale > 1e-2) {
12888 float sin_rot = sin(rot_angle * PI / 180.);
12889 float cos_rot = cos(rot_angle * PI / 180.);
12893 float xt = CurrentArrowArray[0].x;
12894 float yt = CurrentArrowArray[0].y;
12896 float xp = (xt * cos_rot) - (yt * sin_rot);
12897 float yp = (xt * sin_rot) + (yt * cos_rot);
12898 int x1 = (int)(xp *
scale);
12899 int y1 = (int)(yp *
scale);
12902 for (
int ip = 1; ip < NUM_CURRENT_ARROW_POINTS; ip++) {
12903 xt = CurrentArrowArray[ip].x;
12904 yt = CurrentArrowArray[ip].y;
12906 float xp = (xt * cos_rot) - (yt * sin_rot);
12907 float yp = (xt * sin_rot) + (yt * cos_rot);
12908 int x2 = (int)(xp *
scale);
12909 int y2 = (int)(yp *
scale);
12911 dc.DrawLine(x1 + x, y1 + y, x2 + x, y2 + y);
12919 wxString ChartCanvas::FindValidUploadPort() {
12922 if (!g_uploadConnection.IsEmpty() &&
12923 g_uploadConnection.StartsWith(_T(
"Serial"))) {
12924 port = g_uploadConnection;
12927 else if (TheConnectionParams()) {
12930 for (
size_t i = 0; i < TheConnectionParams()->Count(); i++) {
12932 if ((cp->IOSelect != DS_TYPE_INPUT) && cp->Type == SERIAL)
12933 port << _T(
"Serial:") << cp->Port;
12939 void ShowAISTargetQueryDialog(wxWindow *win,
int mmsi) {
12942 if (NULL == g_pais_query_dialog_active) {
12943 int pos_x = g_ais_query_dialog_x;
12944 int pos_y = g_ais_query_dialog_y;
12946 if (g_pais_query_dialog_active) {
12947 g_pais_query_dialog_active->Destroy();
12953 g_pais_query_dialog_active->
Create(win, -1, _(
"AIS Target Query"),
12954 wxPoint(pos_x, pos_y));
12956 g_pais_query_dialog_active->SetAutoCentre(g_btouch);
12957 g_pais_query_dialog_active->SetAutoSize(g_bresponsive);
12958 g_pais_query_dialog_active->SetMMSI(mmsi);
12959 g_pais_query_dialog_active->UpdateText();
12960 wxSize sz = g_pais_query_dialog_active->GetSize();
12962 bool b_reset_pos =
false;
12967 RECT frame_title_rect;
12968 frame_title_rect.left = pos_x;
12969 frame_title_rect.top = pos_y;
12970 frame_title_rect.right = pos_x + sz.x;
12971 frame_title_rect.bottom = pos_y + 30;
12973 if (NULL == MonitorFromRect(&frame_title_rect, MONITOR_DEFAULTTONULL))
12974 b_reset_pos =
true;
12979 wxRect window_title_rect;
12980 window_title_rect.x = pos_x;
12981 window_title_rect.y = pos_y;
12982 window_title_rect.width = sz.x;
12983 window_title_rect.height = 30;
12985 wxRect ClientRect = wxGetClientDisplayRect();
12986 ClientRect.Deflate(
12988 if (!ClientRect.Intersects(window_title_rect)) b_reset_pos =
true;
12992 if (b_reset_pos) g_pais_query_dialog_active->Move(50, 200);
12995 g_pais_query_dialog_active->SetMMSI(mmsi);
12996 g_pais_query_dialog_active->UpdateText();
12999 g_pais_query_dialog_active->Show();
13002 void ChartCanvas::ToggleCanvasQuiltMode(
void) {
13003 bool cur_mode = GetQuiltMode();
13005 if (!GetQuiltMode())
13006 SetQuiltMode(
true);
13007 else if (GetQuiltMode()) {
13008 SetQuiltMode(
false);
13009 g_sticky_chart = GetQuiltReferenceChartIndex();
13012 if (cur_mode != GetQuiltMode()) {
13013 SetupCanvasQuiltMode();
13022 if (ps52plib) ps52plib->GenerateStateHash();
13024 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13025 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13028 void ChartCanvas::DoCanvasStackDelta(
int direction) {
13029 if (!GetQuiltMode()) {
13030 int current_stack_index = GetpCurrentStack()->CurrentStackEntry;
13031 if ((current_stack_index + direction) >= GetpCurrentStack()->nEntry)
return;
13032 if ((current_stack_index + direction) < 0)
return;
13034 if (m_bpersistent_quilt ) {
13036 GetpCurrentStack()->GetDBIndex(current_stack_index + direction);
13038 if (IsChartQuiltableRef(new_dbIndex)) {
13039 ToggleCanvasQuiltMode();
13040 SelectQuiltRefdbChart(new_dbIndex);
13041 m_bpersistent_quilt =
false;
13044 SelectChartFromStack(current_stack_index + direction);
13047 std::vector<int> piano_chart_index_array =
13048 GetQuiltExtendedStackdbIndexArray();
13049 int refdb = GetQuiltRefChartdbIndex();
13052 int current_index = -1;
13053 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13054 if (refdb == piano_chart_index_array[i]) {
13059 if (current_index == -1)
return;
13062 int target_family = ctet.GetChartFamily();
13064 int new_index = -1;
13065 int check_index = current_index + direction;
13066 bool found =
false;
13067 int check_dbIndex = -1;
13068 int new_dbIndex = -1;
13072 (
unsigned int)check_index < piano_chart_index_array.size() &&
13073 (check_index >= 0)) {
13074 check_dbIndex = piano_chart_index_array[check_index];
13075 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13076 if (target_family == cte.GetChartFamily()) {
13078 new_index = check_index;
13079 new_dbIndex = check_dbIndex;
13083 check_index += direction;
13086 if (!found)
return;
13088 if (!IsChartQuiltableRef(new_dbIndex)) {
13089 ToggleCanvasQuiltMode();
13090 SelectdbChart(new_dbIndex);
13091 m_bpersistent_quilt =
true;
13093 SelectQuiltRefChart(new_index);
13097 gFrame->UpdateGlobalMenuItems();
13099 SetQuiltChartHiLiteIndex(-1);
13110 void ChartCanvas::OnToolLeftClick(wxCommandEvent &event) {
13113 switch (event.GetId()) {
13116 ZoomCanvasSimple(g_plus_minus_zoom_factor);
13122 ZoomCanvasSimple(1.0 / g_plus_minus_zoom_factor);
13127 DoCanvasStackDelta(1);
13132 DoCanvasStackDelta(-1);
13142 ShowCurrents(!GetbShowCurrent());
13149 ShowTides(!GetbShowTide());
13156 if (0 == m_routeState) {
13163 androidSetRouteAnnunciator(m_routeState == 1);
13169 SetAISCanvasDisplayStyle(-1);
13184 void ChartCanvas::SetShowAIS(
bool show) {
13186 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13187 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13190 void ChartCanvas::SetAttenAIS(
bool show) {
13191 m_bShowAISScaled = show;
13192 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13193 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13196 void ChartCanvas::SetAISCanvasDisplayStyle(
int StyleIndx) {
13199 bool bShowAIS_Array[3] = {
true,
true,
false};
13200 bool bShowScaled_Array[3] = {
false,
true,
true};
13201 wxString ToolShortHelp_Array[3] = {_(
"Show all AIS Targets"),
13202 _(
"Attenuate less critical AIS targets"),
13203 _(
"Hide AIS Targets")};
13204 wxString iconName_Array[3] = {_T(
"AIS"), _T(
"AIS_Suppressed"),
13205 _T(
"AIS_Disabled")};
13207 int AIS_Toolbar_Switch = 0;
13208 if (StyleIndx == -1) {
13210 for (
int i = 1; i < ArraySize; i++) {
13211 if ((bShowAIS_Array[i] == m_bShowAIS) &&
13212 (bShowScaled_Array[i] == m_bShowAISScaled))
13213 AIS_Toolbar_Switch = i;
13215 AIS_Toolbar_Switch++;
13216 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch == 1))
13217 AIS_Toolbar_Switch++;
13220 AIS_Toolbar_Switch = StyleIndx;
13223 if (AIS_Toolbar_Switch >= ArraySize) AIS_Toolbar_Switch = 0;
13225 int AIS_Toolbar_Switch_Next =
13226 AIS_Toolbar_Switch + 1;
13227 if ((!g_bAllowShowScaled) && (AIS_Toolbar_Switch_Next == 1))
13228 AIS_Toolbar_Switch_Next++;
13229 if (AIS_Toolbar_Switch_Next >= ArraySize)
13230 AIS_Toolbar_Switch_Next = 0;
13233 m_bShowAIS = bShowAIS_Array[AIS_Toolbar_Switch];
13234 m_bShowAISScaled = bShowScaled_Array[AIS_Toolbar_Switch];
13237 void ChartCanvas::TouchAISToolActive(
void) {
13240 void ChartCanvas::UpdateAISTBTool(
void) {
13249 void ChartCanvas::UpdateGPSCompassStatusBox(
bool b_force_new) {
13251 bool b_update =
false;
13252 int cc1_edge_comp = 2;
13253 wxRect rect = m_Compass->GetRect();
13254 wxSize parent_size = GetSize();
13256 parent_size *= m_displayScale;
13260 wxPoint tentative_pt(parent_size.x - rect.width - cc1_edge_comp,
13261 g_StyleManager->GetCurrentStyle()->GetCompassYOffset());
13262 wxRect tentative_rect(tentative_pt, rect.GetSize());
13264 m_Compass->Move(tentative_pt);
13266 if (m_Compass && m_Compass->IsShown())
13267 m_Compass->UpdateStatus(b_force_new | b_update);
13269 if (b_force_new | b_update) Refresh();
13272 void ChartCanvas::SelectChartFromStack(
int index,
bool bDir,
13273 ChartTypeEnum New_Type,
13274 ChartFamilyEnum New_Family) {
13275 if (!GetpCurrentStack())
return;
13276 if (!ChartData)
return;
13278 if (index < GetpCurrentStack()->nEntry) {
13281 pTentative_Chart = ChartData->OpenStackChartConditional(
13282 GetpCurrentStack(), index, bDir, New_Type, New_Family);
13284 if (pTentative_Chart) {
13285 if (m_singleChart) m_singleChart->Deactivate();
13287 m_singleChart = pTentative_Chart;
13288 m_singleChart->Activate();
13290 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13291 GetpCurrentStack(), m_singleChart->GetFullPath());
13304 double best_scale_ppm = GetBestVPScale(m_singleChart);
13305 double rotation = GetVPRotation();
13306 double oldskew = GetVPSkew();
13307 double newskew = m_singleChart->GetChartSkew() * PI / 180.0;
13309 if (!g_bskew_comp && (GetUpMode() == NORTH_UP_MODE)) {
13310 if (fabs(oldskew) > 0.0001) rotation = 0.0;
13311 if (fabs(newskew) > 0.0001) rotation = newskew;
13314 SetViewPoint(zLat, zLon, best_scale_ppm, newskew, rotation);
13316 UpdateGPSCompassStatusBox(
true);
13320 int idx = GetpCurrentStack()->GetCurrentEntrydbIndex();
13321 if (idx < 0)
return;
13323 std::vector<int> piano_active_chart_index_array;
13324 piano_active_chart_index_array.push_back(
13325 GetpCurrentStack()->GetCurrentEntrydbIndex());
13326 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13329 void ChartCanvas::SelectdbChart(
int dbindex) {
13330 if (!GetpCurrentStack())
return;
13331 if (!ChartData)
return;
13333 if (dbindex >= 0) {
13336 pTentative_Chart = ChartData->OpenChartFromDB(dbindex, FULL_INIT);
13338 if (pTentative_Chart) {
13339 if (m_singleChart) m_singleChart->Deactivate();
13341 m_singleChart = pTentative_Chart;
13342 m_singleChart->Activate();
13344 GetpCurrentStack()->CurrentStackEntry = ChartData->GetStackEntry(
13345 GetpCurrentStack(), m_singleChart->GetFullPath());
13358 double best_scale_ppm = GetBestVPScale(m_singleChart);
13361 SetViewPoint(zLat, zLon, best_scale_ppm,
13362 m_singleChart->GetChartSkew() * PI / 180., GetVPRotation());
13372 void ChartCanvas::selectCanvasChartDisplay(
int type,
int family) {
13373 double target_scale = GetVP().view_scale_ppm;
13375 if (!GetQuiltMode()) {
13376 if (GetpCurrentStack()) {
13377 int stack_index = -1;
13378 for (
int i = 0; i < GetpCurrentStack()->nEntry; i++) {
13379 int check_dbIndex = GetpCurrentStack()->GetDBIndex(i);
13380 if (check_dbIndex < 0)
continue;
13382 ChartData->GetChartTableEntry(check_dbIndex);
13383 if (type == cte.GetChartType()) {
13386 }
else if (family == cte.GetChartFamily()) {
13392 if (stack_index >= 0) {
13393 SelectChartFromStack(stack_index);
13397 int sel_dbIndex = -1;
13398 std::vector<int> piano_chart_index_array =
13399 GetQuiltExtendedStackdbIndexArray();
13400 for (
unsigned int i = 0; i < piano_chart_index_array.size(); i++) {
13401 int check_dbIndex = piano_chart_index_array[i];
13402 const ChartTableEntry &cte = ChartData->GetChartTableEntry(check_dbIndex);
13403 if (type == cte.GetChartType()) {
13404 if (IsChartQuiltableRef(check_dbIndex)) {
13405 sel_dbIndex = check_dbIndex;
13408 }
else if (family == cte.GetChartFamily()) {
13409 if (IsChartQuiltableRef(check_dbIndex)) {
13410 sel_dbIndex = check_dbIndex;
13416 if (sel_dbIndex >= 0) {
13417 SelectQuiltRefdbChart(sel_dbIndex,
false);
13419 AdjustQuiltRefChart();
13423 SetVPScale(target_scale);
13426 SetQuiltChartHiLiteIndex(-1);
13431 bool ChartCanvas::IsTileOverlayIndexInYesShow(
int index) {
13432 return std::find(m_tile_yesshow_index_array.begin(),
13433 m_tile_yesshow_index_array.end(),
13434 index) != m_tile_yesshow_index_array.end();
13437 bool ChartCanvas::IsTileOverlayIndexInNoShow(
int index) {
13438 return std::find(m_tile_noshow_index_array.begin(),
13439 m_tile_noshow_index_array.end(),
13440 index) != m_tile_noshow_index_array.end();
13443 void ChartCanvas::AddTileOverlayIndexToNoShow(
int index) {
13444 if (std::find(m_tile_noshow_index_array.begin(),
13445 m_tile_noshow_index_array.end(),
13446 index) == m_tile_noshow_index_array.end()) {
13447 m_tile_noshow_index_array.push_back(index);
13457 void ChartCanvas::HandlePianoClick(
int selected_index,
13458 const std::vector<int> &selected_dbIndex_array)
13460 if (g_boptionsactive)
13462 if (!m_pCurrentStack)
return;
13463 if (!ChartData)
return;
13476 double distance = 25000;
13477 int closest_index = -1;
13478 for (
int chart_index : selected_dbIndex_array) {
13479 const ChartTableEntry &cte = ChartData->GetChartTableEntry(chart_index);
13480 double chart_lat = (cte.GetLatMax() + cte.GetLatMin()) / 2;
13481 double chart_lon = (cte.GetLonMax() + cte.GetLonMin()) / 2;
13484 double test_distance = abs(m_vLat - chart_lat) + abs(m_vLon - chart_lon);
13485 if (test_distance < distance){
13486 distance = test_distance;
13487 closest_index = chart_index;
13491 int selected_dbIndex = selected_dbIndex_array[0];
13492 if (closest_index >= 0)
13493 selected_dbIndex = closest_index;
13495 if (!GetQuiltMode()) {
13496 if (m_bpersistent_quilt ) {
13497 if (IsChartQuiltableRef(selected_dbIndex)) {
13498 ToggleCanvasQuiltMode();
13499 SelectQuiltRefdbChart(selected_dbIndex);
13500 m_bpersistent_quilt =
false;
13502 SelectChartFromStack(selected_index);
13505 SelectChartFromStack(selected_index);
13506 g_sticky_chart = selected_dbIndex;
13510 GetVP().SetProjectionType(m_singleChart->GetChartProjectionType());
13514 if (CHART_TYPE_MBTILES == ChartData->GetDBChartType(selected_dbIndex)) {
13515 bool bfound =
false;
13516 for (
unsigned int i = 0; i < m_tile_noshow_index_array.size(); i++) {
13517 if (m_tile_noshow_index_array[i] ==
13518 selected_dbIndex) {
13519 m_tile_noshow_index_array.erase(m_tile_noshow_index_array.begin() +
13526 m_tile_noshow_index_array.push_back(selected_dbIndex);
13530 if (!IsTileOverlayIndexInYesShow(selected_dbIndex))
13531 m_tile_yesshow_index_array.push_back(selected_dbIndex);
13535 if (IsChartQuiltableRef(selected_dbIndex)) {
13541 bool set_scale =
false;
13542 if (CHART_TYPE_S57 == ChartData->GetDBChartType(selected_dbIndex)) {
13543 if (ChartData->GetDBChartScale(selected_dbIndex) < 5000) {
13549 SelectQuiltRefdbChart(selected_dbIndex,
true);
13551 SelectQuiltRefdbChart(selected_dbIndex,
false);
13556 ChartData->OpenChartFromDB(selected_dbIndex, FULL_INIT);
13558 double proposed_scale_onscreen =
13559 GetCanvasScaleFactor() / GetVPScale();
13561 if (g_bPreserveScaleOnX) {
13562 proposed_scale_onscreen =
13563 wxMin(proposed_scale_onscreen,
13564 100 * pc->GetNormalScaleMax(GetCanvasScaleFactor(),
13565 GetCanvasWidth()));
13567 proposed_scale_onscreen =
13568 wxMin(proposed_scale_onscreen,
13569 20 * pc->GetNormalScaleMax(GetCanvasScaleFactor(),
13570 GetCanvasWidth()));
13572 proposed_scale_onscreen =
13573 wxMax(proposed_scale_onscreen,
13574 pc->GetNormalScaleMin(GetCanvasScaleFactor(),
13578 SetVPScale(GetCanvasScaleFactor() / proposed_scale_onscreen);
13582 ToggleCanvasQuiltMode();
13583 SelectdbChart(selected_dbIndex);
13584 m_bpersistent_quilt =
true;
13589 SetQuiltChartHiLiteIndex(-1);
13590 gFrame->UpdateGlobalMenuItems();
13592 HideChartInfoWindow();
13597 void ChartCanvas::HandlePianoRClick(
int x,
int y,
int selected_index,
13598 const std::vector<int> &selected_dbIndex_array)
13600 if (g_boptionsactive)
13602 if (!GetpCurrentStack())
return;
13604 PianoPopupMenu(x, y, selected_index, selected_dbIndex_array);
13605 UpdateCanvasControlBar();
13607 SetQuiltChartHiLiteIndex(-1);
13610 void ChartCanvas::HandlePianoRollover(
int selected_index,
13611 const std::vector<int> &selected_dbIndex_array,
13612 int n_charts,
int scale) {
13613 if (g_boptionsactive)
13615 if (!GetpCurrentStack())
return;
13616 if (!ChartData)
return;
13618 if (ChartData->IsBusy())
return;
13620 wxPoint key_location = m_Piano->GetKeyOrigin(selected_index);
13622 if (!GetQuiltMode()) {
13623 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
13626 std::vector<int> piano_chart_index_array;
13627 if (m_Piano->GetPianoMode() == PIANO_MODE_LEGACY) {
13628 piano_chart_index_array = GetQuiltExtendedStackdbIndexArray();
13629 if ((GetpCurrentStack()->nEntry > 1) ||
13630 (piano_chart_index_array.size() >= 1)) {
13631 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
13633 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
13635 }
else if (GetpCurrentStack()->nEntry == 1) {
13637 ChartData->GetChartTableEntry(GetpCurrentStack()->GetDBIndex(0));
13638 if (CHART_TYPE_CM93COMP != cte.GetChartType()) {
13639 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
13641 }
else if ((-1 == selected_index) &&
13642 (0 == selected_dbIndex_array.size())) {
13643 ShowChartInfoWindow(key_location.x, -1);
13648 piano_chart_index_array = GetQuiltFullScreendbIndexArray();
13650 if ((GetpCurrentStack()->nEntry > 1) ||
13651 (piano_chart_index_array.size() >= 1)) {
13654 ShowCompositeInfoWindow(key_location.x, n_charts,
scale, selected_dbIndex_array);
13655 else if(n_charts == 1)
13656 ShowChartInfoWindow(key_location.x, selected_dbIndex_array[0]);
13658 SetQuiltChartHiLiteIndexArray(selected_dbIndex_array);
13665 void ChartCanvas::ClearPianoRollover() {
13666 ClearQuiltChartHiLiteIndexArray();
13667 ShowChartInfoWindow(0, -1);
13668 std::vector<int> vec;
13669 ShowCompositeInfoWindow(0, 0, 0, vec);
13673 void ChartCanvas::UpdateCanvasControlBar(
void) {
13674 if (m_pianoFrozen)
return;
13676 if (!GetpCurrentStack())
return;
13677 if (!ChartData)
return;
13678 if (!g_bShowChartBar)
return;
13681 int sel_family = -1;
13683 std::vector<int> piano_chart_index_array;
13684 std::vector<int> empty_piano_chart_index_array;
13686 wxString old_hash = m_Piano->GetStoredHash();
13688 if (GetQuiltMode()) {
13689 m_Piano->SetKeyArray(GetQuiltExtendedStackdbIndexArray(),
13690 GetQuiltFullScreendbIndexArray());
13692 std::vector<int> piano_active_chart_index_array =
13693 GetQuiltCandidatedbIndexArray();
13694 m_Piano->SetActiveKeyArray(piano_active_chart_index_array);
13696 std::vector<int> piano_eclipsed_chart_index_array =
13697 GetQuiltEclipsedStackdbIndexArray();
13698 m_Piano->SetEclipsedIndexArray(piano_eclipsed_chart_index_array);
13700 m_Piano->SetNoshowIndexArray(m_quilt_noshow_index_array);
13701 m_Piano->AddNoshowIndexArray(m_tile_noshow_index_array);
13703 sel_type = ChartData->GetDBChartType(GetQuiltReferenceChartIndex());
13704 sel_family = ChartData->GetDBChartFamily(GetQuiltReferenceChartIndex());
13706 piano_chart_index_array = ChartData->GetCSArray(GetpCurrentStack());
13707 m_Piano->SetKeyArray(piano_chart_index_array, piano_chart_index_array);
13710 if (m_singleChart) {
13711 sel_type = m_singleChart->GetChartType();
13712 sel_family = m_singleChart->GetChartFamily();
13717 std::vector<int> piano_skew_chart_index_array;
13718 std::vector<int> piano_tmerc_chart_index_array;
13719 std::vector<int> piano_poly_chart_index_array;
13721 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
13723 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
13724 double skew_norm = ctei.GetChartSkew();
13725 if (skew_norm > 180.) skew_norm -= 360.;
13727 if (ctei.GetChartProjectionType() == PROJECTION_TRANSVERSE_MERCATOR)
13728 piano_tmerc_chart_index_array.push_back(piano_chart_index_array[ino]);
13731 else if (ctei.GetChartProjectionType() == PROJECTION_POLYCONIC) {
13732 if (fabs(skew_norm) > 1.)
13733 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
13735 piano_poly_chart_index_array.push_back(piano_chart_index_array[ino]);
13736 }
else if (fabs(skew_norm) > 1.)
13737 piano_skew_chart_index_array.push_back(piano_chart_index_array[ino]);
13739 m_Piano->SetSkewIndexArray(piano_skew_chart_index_array);
13740 m_Piano->SetTmercIndexArray(piano_tmerc_chart_index_array);
13741 m_Piano->SetPolyIndexArray(piano_poly_chart_index_array);
13743 wxString new_hash = m_Piano->GenerateAndStoreNewHash();
13744 if (new_hash != old_hash) {
13745 m_Piano->FormatKeys();
13746 HideChartInfoWindow();
13747 m_Piano->ResetRollover();
13748 SetQuiltChartHiLiteIndex(-1);
13749 m_brepaint_piano =
true;
13755 for (
unsigned int ino = 0; ino < piano_chart_index_array.size(); ino++) {
13757 ChartData->GetChartTableEntry(piano_chart_index_array[ino]);
13758 ChartFamilyEnum e = (ChartFamilyEnum)ctei.GetChartFamily();
13759 ChartTypeEnum t = (ChartTypeEnum)ctei.GetChartType();
13760 if (e == CHART_FAMILY_RASTER) mask |= 1;
13761 if (e == CHART_FAMILY_VECTOR) {
13762 if (t == CHART_TYPE_CM93COMP)
13769 wxString s_indicated;
13770 if (sel_type == CHART_TYPE_CM93COMP)
13771 s_indicated = _T(
"cm93");
13773 if (sel_family == CHART_FAMILY_RASTER)
13774 s_indicated = _T(
"raster");
13775 else if (sel_family == CHART_FAMILY_VECTOR)
13776 s_indicated = _T(
"vector");
13779 g_Platform->setChartTypeMaskSel(mask, s_indicated);
13782 void ChartCanvas::FormatPianoKeys(
void) { m_Piano->FormatKeys(); }
13784 void ChartCanvas::PianoPopupMenu(
int x,
int y,
int selected_index,
13785 const std::vector<int> &selected_dbIndex_array) {
13786 if (!GetpCurrentStack())
return;
13789 if (!GetQuiltMode())
return;
13791 m_piano_ctx_menu =
new wxMenu();
13793 if(m_Piano->GetPianoMode() == PIANO_MODE_COMPOSITE) {
13803 menu_selected_dbIndex = selected_dbIndex_array[0];
13804 menu_selected_index = selected_index;
13807 bool b_is_in_noshow =
false;
13808 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
13809 if (m_quilt_noshow_index_array[i] ==
13810 menu_selected_dbIndex)
13812 b_is_in_noshow =
true;
13817 if (b_is_in_noshow) {
13818 m_piano_ctx_menu->Append(ID_PIANO_ENABLE_QUILT_CHART,
13819 _(
"Show This Chart"));
13820 Connect(ID_PIANO_ENABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
13821 wxCommandEventHandler(ChartCanvas::OnPianoMenuEnableChart));
13822 }
else if (GetpCurrentStack()->nEntry > 1) {
13823 m_piano_ctx_menu->Append(ID_PIANO_DISABLE_QUILT_CHART,
13824 _(
"Hide This Chart"));
13825 Connect(ID_PIANO_DISABLE_QUILT_CHART, wxEVT_COMMAND_MENU_SELECTED,
13826 wxCommandEventHandler(ChartCanvas::OnPianoMenuDisableChart));
13830 wxPoint pos = wxPoint(x, y - 30);
13833 if (m_piano_ctx_menu->GetMenuItems().GetCount())
13834 PopupMenu(m_piano_ctx_menu, pos);
13836 delete m_piano_ctx_menu;
13837 m_piano_ctx_menu = NULL;
13839 HideChartInfoWindow();
13840 m_Piano->ResetRollover();
13842 SetQuiltChartHiLiteIndex(-1);
13843 ClearQuiltChartHiLiteIndexArray();
13848 void ChartCanvas::OnPianoMenuEnableChart(wxCommandEvent &event) {
13849 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
13850 if (m_quilt_noshow_index_array[i] ==
13851 menu_selected_dbIndex)
13853 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
13859 void ChartCanvas::OnPianoMenuDisableChart(wxCommandEvent &event) {
13860 if (!GetpCurrentStack())
return;
13861 if (!ChartData)
return;
13863 RemoveChartFromQuilt(menu_selected_dbIndex);
13867 if (menu_selected_dbIndex == GetQuiltRefChartdbIndex()) {
13868 int type = ChartData->GetDBChartType(menu_selected_dbIndex);
13870 int i = menu_selected_index + 1;
13871 bool b_success =
false;
13872 while (i < GetpCurrentStack()->nEntry - 1) {
13873 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
13874 if (type == ChartData->GetDBChartType(dbIndex)) {
13875 SelectQuiltRefChart(i);
13885 i = menu_selected_index - 1;
13887 int dbIndex = GetpCurrentStack()->GetDBIndex(i);
13888 if (type == ChartData->GetDBChartType(dbIndex)) {
13889 SelectQuiltRefChart(i);
13899 void ChartCanvas::RemoveChartFromQuilt(
int dbIndex) {
13901 for (
unsigned int i = 0; i < m_quilt_noshow_index_array.size(); i++) {
13902 if (m_quilt_noshow_index_array[i] ==
13905 m_quilt_noshow_index_array.erase(m_quilt_noshow_index_array.begin() + i);
13910 m_quilt_noshow_index_array.push_back(dbIndex);
13913 bool ChartCanvas::UpdateS52State() {
13914 bool retval =
false;
13918 ps52plib->SetShowS57Text(m_encShowText);
13919 ps52plib->SetDisplayCategory((DisCat)m_encDisplayCategory);
13920 ps52plib->m_bShowSoundg = m_encShowDepth;
13921 ps52plib->m_bShowAtonText = m_encShowBuoyLabels;
13922 ps52plib->m_bShowLdisText = m_encShowLightDesc;
13925 if (!m_encShowLights)
13926 ps52plib->AddObjNoshow(
"LIGHTS");
13928 ps52plib->RemoveObjNoshow(
"LIGHTS");
13929 ps52plib->SetLightsOff(!m_encShowLights);
13930 ps52plib->m_bExtendLightSectors =
true;
13933 ps52plib->SetAnchorOn(m_encShowAnchor);
13934 ps52plib->SetQualityOfData(m_encShowDataQual);
13940 void ChartCanvas::SetShowENCDataQual(
bool show) {
13941 m_encShowDataQual = show;
13942 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13943 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13945 m_s52StateHash = 0;
13948 void ChartCanvas::SetShowENCText(
bool show) {
13949 m_encShowText = show;
13950 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13951 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13953 m_s52StateHash = 0;
13956 void ChartCanvas::SetENCDisplayCategory(
int category) {
13957 m_encDisplayCategory = category;
13958 m_s52StateHash = 0;
13961 void ChartCanvas::SetShowENCDepth(
bool show) {
13962 m_encShowDepth = show;
13963 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13964 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13966 m_s52StateHash = 0;
13969 void ChartCanvas::SetShowENCLightDesc(
bool show) {
13970 m_encShowLightDesc = show;
13971 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13972 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13974 m_s52StateHash = 0;
13977 void ChartCanvas::SetShowENCBuoyLabels(
bool show) {
13978 m_encShowBuoyLabels = show;
13979 m_s52StateHash = 0;
13982 void ChartCanvas::SetShowENCLights(
bool show) {
13983 m_encShowLights = show;
13984 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13985 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13987 m_s52StateHash = 0;
13990 void ChartCanvas::SetShowENCAnchor(
bool show) {
13991 m_encShowAnchor = show;
13992 if (GetMUIBar() && GetMUIBar()->GetCanvasOptions())
13993 GetMUIBar()->GetCanvasOptions()->RefreshControlValues();
13995 m_s52StateHash = 0;
13998 wxRect ChartCanvas::GetMUIBarRect() {
14001 rv = m_muiBar->GetRect();
14007 void ChartCanvas::RenderAlertMessage(wxDC &dc,
const ViewPort &vp) {
14008 if (!GetAlertString().IsEmpty()) {
14009 wxFont *pfont = wxTheFontList->FindOrCreateFont(
14010 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
14012 dc.SetFont(*pfont);
14013 dc.SetPen(*wxTRANSPARENT_PEN);
14015 dc.SetBrush(wxColour(243, 229, 47));
14017 dc.GetMultiLineTextExtent(GetAlertString(), &w, &h);
14021 wxRect sbr = GetScaleBarRect();
14022 int xp = sbr.x + sbr.width + 10;
14023 int yp = (sbr.y + sbr.height) - h;
14025 int wdraw = w + 10;
14026 dc.DrawRectangle(xp, yp, wdraw, h);
14027 dc.DrawLabel(GetAlertString(), wxRect(xp, yp, wdraw, h),
14028 wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL);
14038 #define BRIGHT_XCALIB
14039 #define __OPCPN_USEICC__
14042 #ifdef __OPCPN_USEICC__
14043 int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14044 double co_green,
double co_blue);
14046 wxString temp_file_name;
14050 class ocpnCurtain:
public wxDialog
14052 DECLARE_CLASS( ocpnCurtain )
14053 DECLARE_EVENT_TABLE()
14056 ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle );
14058 bool ProcessEvent(wxEvent& event);
14062 IMPLEMENT_CLASS ( ocpnCurtain, wxDialog )
14064 BEGIN_EVENT_TABLE(ocpnCurtain, wxDialog)
14067 ocpnCurtain::ocpnCurtain( wxWindow *parent, wxPoint position, wxSize size,
long wstyle )
14069 wxDialog::Create( parent, -1, _T(
"ocpnCurtain"), position, size, wxNO_BORDER | wxSTAY_ON_TOP );
14072 ocpnCurtain::~ocpnCurtain()
14076 bool ocpnCurtain::ProcessEvent(wxEvent& event)
14078 GetParent()->GetEventHandler()->SetEvtHandlerEnabled(
true);
14079 return GetParent()->GetEventHandler()->ProcessEvent(event);
14084 #include <windows.h>
14087 typedef BOOL(WINAPI *SetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14088 typedef BOOL(WINAPI *GetDeviceGammaRamp_ptr_type)(HDC hDC, LPVOID lpRampTable);
14089 SetDeviceGammaRamp_ptr_type
14090 g_pSetDeviceGammaRamp;
14091 GetDeviceGammaRamp_ptr_type g_pGetDeviceGammaRamp;
14093 WORD *g_pSavedGammaMap;
14097 int InitScreenBrightness(
void) {
14100 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14104 if (NULL == hGDI32DLL) {
14105 hGDI32DLL = LoadLibrary(TEXT(
"gdi32.dll"));
14107 if (NULL != hGDI32DLL) {
14109 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14110 hGDI32DLL,
"SetDeviceGammaRamp");
14111 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14112 hGDI32DLL,
"GetDeviceGammaRamp");
14115 if ((NULL == g_pSetDeviceGammaRamp) ||
14116 (NULL == g_pGetDeviceGammaRamp)) {
14117 FreeLibrary(hGDI32DLL);
14126 if (!g_pSavedGammaMap) {
14127 g_pSavedGammaMap = (WORD *)malloc(3 * 256 *
sizeof(WORD));
14130 bbr = g_pGetDeviceGammaRamp(
14131 hDC, g_pSavedGammaMap);
14132 ReleaseDC(NULL, hDC);
14137 wxRegKey *pRegKey =
new wxRegKey(
14138 _T(
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows ")
14139 _T(
"NT\\CurrentVersion\\ICM"));
14140 if (!pRegKey->Exists()) pRegKey->Create();
14141 pRegKey->SetValue(_T(
"GdiIcmGammaRange"), 256);
14143 g_brightness_init =
true;
14149 if (NULL == g_pcurtain) {
14150 if (gFrame->CanSetTransparent()) {
14152 g_pcurtain =
new wxDialog(gFrame->GetPrimaryCanvas(), -1, _T(
""),
14153 wxPoint(0, 0), ::wxGetDisplaySize(),
14154 wxNO_BORDER | wxTRANSPARENT_WINDOW |
14155 wxSTAY_ON_TOP | wxDIALOG_NO_PARENT);
14162 g_pcurtain->Hide();
14164 HWND hWnd = GetHwndOf(g_pcurtain);
14165 SetWindowLong(hWnd, GWL_EXSTYLE,
14166 GetWindowLong(hWnd, GWL_EXSTYLE) | ~WS_EX_APPWINDOW);
14167 g_pcurtain->SetBackgroundColour(wxColour(0, 0, 0));
14168 g_pcurtain->SetTransparent(0);
14170 g_pcurtain->Maximize();
14171 g_pcurtain->Show();
14174 g_pcurtain->Enable();
14175 g_pcurtain->Disable();
14182 g_brightness_init =
true;
14188 wxString cmd(_T (
"xcalib -version" ));
14190 wxArrayString output;
14191 long r = wxExecute(cmd, output);
14194 _T(
" External application \"xcalib\" not found. Screen brightness ")
14195 _T(
"not changed."));
14197 g_brightness_init =
true;
14202 int RestoreScreenBrightness(
void) {
14205 if (g_pSavedGammaMap) {
14206 HDC hDC = GetDC(NULL);
14207 g_pSetDeviceGammaRamp(hDC,
14209 ReleaseDC(NULL, hDC);
14211 free(g_pSavedGammaMap);
14212 g_pSavedGammaMap = NULL;
14216 g_pcurtain->Close();
14217 g_pcurtain->Destroy();
14221 g_brightness_init =
false;
14226 #ifdef BRIGHT_XCALIB
14227 if (g_brightness_init) {
14229 cmd = _T(
"xcalib -clear");
14230 wxExecute(cmd, wxEXEC_ASYNC);
14231 g_brightness_init =
false;
14241 int SetScreenBrightness(
int brightness) {
14248 if (gFrame->GetPrimaryCanvas()->GetglCanvas() && g_bopengl) {
14250 g_pcurtain->Close();
14251 g_pcurtain->Destroy();
14255 InitScreenBrightness();
14257 if (NULL == hGDI32DLL) {
14259 wchar_t wdll_name[80];
14260 MultiByteToWideChar(0, 0,
"gdi32.dll", -1, wdll_name, 80);
14261 LPCWSTR cstr = wdll_name;
14263 hGDI32DLL = LoadLibrary(cstr);
14265 if (NULL != hGDI32DLL) {
14267 g_pSetDeviceGammaRamp = (SetDeviceGammaRamp_ptr_type)GetProcAddress(
14268 hGDI32DLL,
"SetDeviceGammaRamp");
14269 g_pGetDeviceGammaRamp = (GetDeviceGammaRamp_ptr_type)GetProcAddress(
14270 hGDI32DLL,
"GetDeviceGammaRamp");
14273 if ((NULL == g_pSetDeviceGammaRamp) ||
14274 (NULL == g_pGetDeviceGammaRamp)) {
14275 FreeLibrary(hGDI32DLL);
14282 HDC hDC = GetDC(NULL);
14293 int increment = brightness * 256 / 100;
14296 WORD GammaTable[3][256];
14299 for (
int i = 0; i < 256; i++) {
14300 GammaTable[0][i] = r_gamma_mult * (WORD)table_val;
14301 GammaTable[1][i] = g_gamma_mult * (WORD)table_val;
14302 GammaTable[2][i] = b_gamma_mult * (WORD)table_val;
14304 table_val += increment;
14306 if (table_val > 65535) table_val = 65535;
14309 g_pSetDeviceGammaRamp(hDC, GammaTable);
14310 ReleaseDC(NULL, hDC);
14317 if (g_pSavedGammaMap) {
14318 HDC hDC = GetDC(NULL);
14319 g_pSetDeviceGammaRamp(hDC,
14321 ReleaseDC(NULL, hDC);
14324 if (brightness < 100) {
14325 if (NULL == g_pcurtain) InitScreenBrightness();
14328 int sbrite = wxMax(1, brightness);
14329 sbrite = wxMin(100, sbrite);
14331 g_pcurtain->SetTransparent((100 - sbrite) * 256 / 100);
14335 g_pcurtain->Close();
14336 g_pcurtain->Destroy();
14346 #ifdef BRIGHT_XCALIB
14348 if (!g_brightness_init) {
14349 last_brightness = 100;
14350 g_brightness_init =
true;
14351 temp_file_name = wxFileName::CreateTempFileName(_T(
""));
14352 InitScreenBrightness();
14355 #ifdef __OPCPN_USEICC__
14358 if (!CreateSimpleICCProfileFile(
14359 (
const char *)temp_file_name.fn_str(), brightness * r_gamma_mult,
14360 brightness * g_gamma_mult, brightness * b_gamma_mult)) {
14361 wxString cmd(_T (
"xcalib " ));
14362 cmd += temp_file_name;
14364 wxExecute(cmd, wxEXEC_ASYNC);
14373 if (brightness > last_brightness) {
14375 cmd = _T(
"xcalib -clear");
14376 wxExecute(cmd, wxEXEC_ASYNC);
14378 ::wxMilliSleep(10);
14380 int brite_adj = wxMax(1, brightness);
14381 cmd.Printf(_T(
"xcalib -co %2d -a"), brite_adj);
14382 wxExecute(cmd, wxEXEC_ASYNC);
14384 int brite_adj = wxMax(1, brightness);
14385 int factor = (brite_adj * 100) / last_brightness;
14386 factor = wxMax(1, factor);
14388 cmd.Printf(_T(
"xcalib -co %2d -a"), factor);
14389 wxExecute(cmd, wxEXEC_ASYNC);
14394 last_brightness = brightness;
14401 #ifdef __OPCPN_USEICC__
14403 #define MLUT_TAG 0x6d4c5554L
14404 #define VCGT_TAG 0x76636774L
14406 int GetIntEndian(
unsigned char *s) {
14411 p = (
unsigned char *)&ret;
14414 for (i =
sizeof(
int) - 1; i > -1; --i) *p++ = s[i];
14416 for (i = 0; i < (int)
sizeof(
int); ++i) *p++ = s[i];
14421 unsigned short GetShortEndian(
unsigned char *s) {
14422 unsigned short ret;
14426 p = (
unsigned char *)&ret;
14429 for (i =
sizeof(
unsigned short) - 1; i > -1; --i) *p++ = s[i];
14431 for (i = 0; i < (int)
sizeof(
unsigned short); ++i) *p++ = s[i];
14437 int CreateSimpleICCProfileFile(
const char *file_name,
double co_red,
14438 double co_green,
double co_blue) {
14442 fp = fopen(file_name,
"wb");
14443 if (!fp)
return -1;
14449 for (
int i = 0; i < 128; i++) header[i] = 0;
14451 fwrite(header, 128, 1, fp);
14455 int numTags = GetIntEndian((
unsigned char *)&numTags0);
14456 fwrite(&numTags, 1, 4, fp);
14458 int tagName0 = VCGT_TAG;
14459 int tagName = GetIntEndian((
unsigned char *)&tagName0);
14460 fwrite(&tagName, 1, 4, fp);
14462 int tagOffset0 = 128 + 4 *
sizeof(int);
14463 int tagOffset = GetIntEndian((
unsigned char *)&tagOffset0);
14464 fwrite(&tagOffset, 1, 4, fp);
14467 int tagSize = GetIntEndian((
unsigned char *)&tagSize0);
14468 fwrite(&tagSize, 1, 4, fp);
14470 fwrite(&tagName, 1, 4, fp);
14472 fwrite(&tagName, 1, 4, fp);
14477 int gammatype0 = 0;
14478 int gammatype = GetIntEndian((
unsigned char *)&gammatype0);
14479 fwrite(&gammatype, 1, 4, fp);
14481 int numChannels0 = 3;
14482 unsigned short numChannels = GetShortEndian((
unsigned char *)&numChannels0);
14483 fwrite(&numChannels, 1, 2, fp);
14485 int numEntries0 = 256;
14486 unsigned short numEntries = GetShortEndian((
unsigned char *)&numEntries0);
14487 fwrite(&numEntries, 1, 2, fp);
14489 int entrySize0 = 1;
14490 unsigned short entrySize = GetShortEndian((
unsigned char *)&entrySize0);
14491 fwrite(&entrySize, 1, 2, fp);
14493 unsigned char ramp[256];
14496 for (
int i = 0; i < 256; i++) ramp[i] = i * co_red / 100.;
14497 fwrite(ramp, 256, 1, fp);
14500 for (
int i = 0; i < 256; i++) ramp[i] = i * co_green / 100.;
14501 fwrite(ramp, 256, 1, fp);
14504 for (
int i = 0; i < 256; i++) ramp[i] = i * co_blue / 100.;
14505 fwrite(ramp, 256, 1, fp);
Global state for AIS decoder.
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.
bool MouseEventSetup(wxMouseEvent &event, bool b_handle_dclick=true)
bool Compose(const ViewPort &vp)
bool ActivateNextPoint(Route *pr, bool skipped)
bool DeleteRoute(Route *pRoute, NavObjectChanges *nav_obj_changes)
Set of basemaps at different resolutions.
Global variables reflecting command line options and arguments.