24#include "wx/tokenzr.h"
25#include "wx/datetime.h"
27#include <wx/wfstream.h>
29#include <wx/filename.h>
31#include <wx/graphics.h>
34#include <wx/stdpaths.h>
47#include <wx/arrimpl.cpp>
50#include "android_jvm.h"
54double m_cursor_lat, m_cursor_lon;
90 return ((x - i) >= 0.5) ? (i + 1) : (i);
92 return (-x + i >= 0.5) ? (i - 1) : (i);
102#if wxCHECK_VERSION(2, 9, 4)
103#define SetBitmapLabelLabel SetBitmap
106#define DEFAULT_STYLE \
107 = wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL
109WX_DEFINE_OBJARRAY(ArrayOfGribRecordSets);
112static int CompareFileStringTime(
const wxString &first,
113 const wxString &second) {
115 wxFileName s(second);
116 wxTimeSpan sp = s.GetModificationTime() - f.GetModificationTime();
117 return sp.GetMinutes();
123wxWindow *GetGRIBCanvas() {
146GribTimelineRecordSet::~GribTimelineRecordSet() {
151void GribTimelineRecordSet::ClearCachedData() {
155 for (
unsigned int j = 0; j <
m_IsobarArray[i]->GetCount(); j++) {
169GRIBUICtrlBar::GRIBUICtrlBar(wxWindow *parent, wxWindowID
id,
170 const wxString &title,
const wxPoint &pos,
171 const wxSize &size,
long style,
grib_pi *ppi,
179 pReq_Dialog =
nullptr;
180 m_bGRIBActiveFile =
nullptr;
181 m_pTimelineSet =
nullptr;
182 m_gCursorData =
nullptr;
183 m_gGRIBUICData =
nullptr;
184 m_gtk_started =
false;
189 m_fgCtrlGrabberSize->Add(m_gGrabber, 0, wxALL, 0);
191 this->SetSizer(m_fgCtrlBarSizer);
193 m_fgCtrlBarSizer->Fit(
this);
196 pConf->SetPath(_T (
"/Settings/GRIB" ));
197 pConf->Read(_T (
"WindPlot" ), &m_bDataPlot[GribOverlaySettings::WIND],
199 pConf->Read(_T (
"WindGustPlot" ),
200 &m_bDataPlot[GribOverlaySettings::WIND_GUST],
false);
201 pConf->Read(_T (
"PressurePlot" ),
202 &m_bDataPlot[GribOverlaySettings::PRESSURE],
false);
203 pConf->Read(_T (
"WavePlot" ), &m_bDataPlot[GribOverlaySettings::WAVE],
205 pConf->Read(_T (
"CurrentPlot" ),
206 &m_bDataPlot[GribOverlaySettings::CURRENT],
false);
207 pConf->Read(_T (
"PrecipitationPlot" ),
208 &m_bDataPlot[GribOverlaySettings::PRECIPITATION],
false);
209 pConf->Read(_T (
"CloudPlot" ), &m_bDataPlot[GribOverlaySettings::CLOUD],
211 pConf->Read(_T (
"AirTemperaturePlot" ),
212 &m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE],
false);
213 pConf->Read(_T (
"SeaTemperaturePlot" ),
214 &m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE],
false);
215 pConf->Read(_T (
"CAPEPlot" ), &m_bDataPlot[GribOverlaySettings::CAPE],
217 pConf->Read(_T (
"CompReflectivityPlot" ),
218 &m_bDataPlot[GribOverlaySettings::COMP_REFL],
false);
220 pConf->Read(_T (
"CursorDataShown" ), &m_CDataIsShown,
true);
222 pConf->Read(_T (
"lastdatatype" ), &m_lastdatatype, 0);
224 pConf->SetPath(_T (
"/Settings/GRIB/FileNames" ));
225 m_file_names.Clear();
226 if (pConf->GetNumberOfEntries()) {
229 bool bCont = pConf->GetFirstEntry(str, dummy);
231 pConf->Read(str, &val);
232 m_file_names.Add(val);
233 bCont = pConf->GetNextEntry(str, dummy);
237 wxStandardPathsBase &spath = wxStandardPaths::Get();
239 pConf->SetPath(_T (
"/Directories" ));
240 pConf->Read(_T (
"GRIBDirectory" ), &m_grib_dir);
242 pConf->SetPath(_T(
"/PlugIns/GRIB" ));
246 pConf->SetPath(_T (
"/Settings/GRIB/XyGrib" ));
247 pConf->Read(_T(
"AtmModelIndex" ), &xyGribConfig.atmModelIndex, 0);
248 pConf->Read(_T(
"WaveModelIndex" ), &xyGribConfig.waveModelIndex, 0);
249 pConf->Read(_T(
"ResolutionIndex" ), &xyGribConfig.resolutionIndex, 0);
250 pConf->Read(_T(
"DurationIndex" ), &xyGribConfig.durationIndex, 0);
251 pConf->Read(_T(
"RunIndex" ), &xyGribConfig.runIndex, 0);
252 pConf->Read(_T(
"IntervalIndex" ), &xyGribConfig.intervalIndex, 0);
253 pConf->Read(_T(
"Wind" ), &xyGribConfig.wind,
true);
254 pConf->Read(_T(
"Gust" ), &xyGribConfig.gust,
true);
255 pConf->Read(_T(
"Pressure" ), &xyGribConfig.pressure,
false);
256 pConf->Read(_T(
"Temperature" ), &xyGribConfig.temperature,
true);
257 pConf->Read(_T(
"Cape" ), &xyGribConfig.cape,
false);
258 pConf->Read(_T(
"Reflectivity" ), &xyGribConfig.reflectivity,
false);
259 pConf->Read(_T(
"CloudCover" ), &xyGribConfig.cloudCover,
true);
260 pConf->Read(_T(
"Precipitation" ), &xyGribConfig.precipitation,
true);
261 pConf->Read(_T(
"WaveHeight" ), &xyGribConfig.waveHeight,
true);
262 pConf->Read(_T(
"WindWaves" ), &xyGribConfig.windWaves,
true);
268 m_tPlayStop.Connect(wxEVT_TIMER,
269 wxTimerEventHandler(GRIBUICtrlBar::OnPlayStopTimer),
272 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICtrlBar::OnMove));
274 m_OverlaySettings.Read();
279 SetMinSize(GetBestSize());
280 if (m_ProjectBoatPanel) {
281 m_ProjectBoatPanel->SetSpeed(pPlugIn->m_boat_sog);
282 m_ProjectBoatPanel->SetCourse(pPlugIn->m_boat_cog);
284 m_highlight_latmax = 0;
285 m_highlight_lonmax = 0;
286 m_highlight_latmin = 0;
287 m_highlight_lonmin = 0;
292 createRequestDialog();
295GRIBUICtrlBar::~GRIBUICtrlBar() {
300 pConf->SetPath(_T (
"/Settings/GRIB" ));
301 pConf->Write(_T (
"WindPlot" ), m_bDataPlot[GribOverlaySettings::WIND]);
302 pConf->Write(_T (
"WindGustPlot" ),
303 m_bDataPlot[GribOverlaySettings::WIND_GUST]);
304 pConf->Write(_T (
"PressurePlot" ),
305 m_bDataPlot[GribOverlaySettings::PRESSURE]);
306 pConf->Write(_T (
"WavePlot" ), m_bDataPlot[GribOverlaySettings::WAVE]);
307 pConf->Write(_T (
"CurrentPlot" ),
308 m_bDataPlot[GribOverlaySettings::CURRENT]);
309 pConf->Write(_T (
"PrecipitationPlot" ),
310 m_bDataPlot[GribOverlaySettings::PRECIPITATION]);
311 pConf->Write(_T (
"CloudPlot" ), m_bDataPlot[GribOverlaySettings::CLOUD]);
312 pConf->Write(_T (
"AirTemperaturePlot" ),
313 m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE]);
314 pConf->Write(_T (
"SeaTemperaturePlot" ),
315 m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE]);
316 pConf->Write(_T (
"CAPEPlot" ), m_bDataPlot[GribOverlaySettings::CAPE]);
317 pConf->Write(_T (
"CompReflectivityPlot" ),
318 m_bDataPlot[GribOverlaySettings::COMP_REFL]);
320 pConf->Write(_T (
"CursorDataShown" ), m_CDataIsShown);
322 pConf->Write(_T (
"lastdatatype" ), m_lastdatatype);
324 pConf->SetPath(_T (
"/Settings/GRIB/FileNames" ));
325 int iFileMax = pConf->GetNumberOfEntries();
329 for (
int i = 0; i < iFileMax; i++) {
330 if (pConf->GetFirstEntry(key, dummy)) pConf->DeleteEntry(key,
false);
334 for (
unsigned int i = 0; i <
m_file_names.GetCount(); i++) {
336 key.Printf(_T(
"Filename%d"), i);
340 pConf->SetPath(_T (
"/Directories" ));
341 pConf->Write(_T (
"GRIBDirectory" ),
m_grib_dir);
344 pConf->SetPath(_T (
"/Settings/GRIB/XyGrib" ));
345 pConf->Write(_T(
"AtmModelIndex" ), xyGribConfig.atmModelIndex);
346 pConf->Write(_T(
"WaveModelIndex" ), xyGribConfig.waveModelIndex);
347 pConf->Write(_T(
"ResolutionIndex" ), xyGribConfig.resolutionIndex);
348 pConf->Write(_T(
"DurationIndex" ), xyGribConfig.durationIndex);
349 pConf->Write(_T(
"RunIndex" ), xyGribConfig.runIndex);
350 pConf->Write(_T(
"IntervalIndex" ), xyGribConfig.intervalIndex);
351 pConf->Write(_T(
"Wind" ), xyGribConfig.wind);
352 pConf->Write(_T(
"Gust" ), xyGribConfig.gust);
353 pConf->Write(_T(
"Pressure" ), xyGribConfig.pressure);
354 pConf->Write(_T(
"Temperature" ), xyGribConfig.temperature);
355 pConf->Write(_T(
"Cape" ), xyGribConfig.cape);
356 pConf->Write(_T(
"Reflectivity" ), xyGribConfig.reflectivity);
357 pConf->Write(_T(
"CloudCover" ), xyGribConfig.cloudCover);
358 pConf->Write(_T(
"Precipitation" ), xyGribConfig.precipitation);
359 pConf->Write(_T(
"WaveHeight" ), xyGribConfig.waveHeight);
360 pConf->Write(_T(
"WindWaves" ), xyGribConfig.windWaves);
366void GRIBUICtrlBar::SetScaledBitmap(
double factor) {
368 m_ScaledFactor = wxRound(factor * 4.0) / 4.0;
370 m_bpPrev->SetBitmapLabel(
371 GetScaledBitmap(wxBitmap(prev), _T(
"prev"), m_ScaledFactor));
372 m_bpNext->SetBitmapLabel(
373 GetScaledBitmap(wxBitmap(next), _T(
"next"), m_ScaledFactor));
374 m_bpAltitude->SetBitmapLabel(
375 GetScaledBitmap(wxBitmap(altitude), _T(
"altitude"), m_ScaledFactor));
376 m_bpNow->SetBitmapLabel(
377 GetScaledBitmap(wxBitmap(now), _T(
"now"), m_ScaledFactor));
378 m_bpZoomToCenter->SetBitmapLabel(
379 GetScaledBitmap(wxBitmap(zoomto), _T(
"zoomto"), m_ScaledFactor));
380 m_bpPlay->SetBitmapLabel(
381 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
382 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(
383 wxBitmap(m_CDataIsShown ? curdata : ncurdata),
384 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"), m_ScaledFactor));
386 m_bpOpenFile->SetBitmapLabel(
387 GetScaledBitmap(wxBitmap(openfile), _T(
"openfile"), m_ScaledFactor));
388 m_bpSettings->SetBitmapLabel(
389 GetScaledBitmap(wxBitmap(setting), _T(
"setting"), m_ScaledFactor));
395#ifdef __OCPN__ANDROID__
396 m_sTimeline->SetSize(wxSize(20 * m_ScaledFactor, -1));
397 m_sTimeline->SetMinSize(wxSize(20 * m_ScaledFactor, -1));
399 m_sTimeline->SetSize(wxSize(90 * m_ScaledFactor, -1));
400 m_sTimeline->SetMinSize(wxSize(90 * m_ScaledFactor, -1));
405 if (
nullptr == m_bpRequest)
return;
406 m_bpRequest->SetBitmapLabel(
407 GetScaledBitmap(wxBitmap(request), _T(
"request"), m_ScaledFactor));
408 m_bpRequest->SetToolTip(_(
"Start a download request"));
411void GRIBUICtrlBar::OpenFile(
bool newestFile) {
412 m_bpPlay->SetBitmapLabel(
413 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
414 m_cRecordForecast->Clear();
415 pPlugIn->GetGRIBOverlayFactory()->ClearParticles();
421 m_sTimeline->SetValue(0);
423 m_InterpolateMode =
false;
425 m_SelectionIsSaved =
false;
426 m_HasAltitude =
false;
447 title = (_(
"File: "));
448 title.Append(fn.GetFullName());
449 if (rsa->GetCount() == 0) {
452 title.Prepend(_(
"Error! ")).Append(_(
" contains no valid data!"));
454 PopulateComboDataList();
458 toUsrDateTimeFormat_Plugin(
462 if (rsa->GetCount() > 1) {
464 &last = rsa->Item(rsa->GetCount() - 1);
467 wxTimeSpan span = wxDateTime(last.m_Reference_Time) -
469 m_TimeLineHours = span.GetHours();
472 int halfintermin(wxTimeSpan(wxDateTime(second.m_Reference_Time) -
476 for (m_FileIntervalIndex = 0;; m_FileIntervalIndex++) {
481 if (m_FileIntervalIndex > 0) m_FileIntervalIndex--;
489 title = _(
"No valid GRIB file");
491 pPlugIn->GetGRIBOverlayFactory()->SetMessage(title);
493 SetTimeLineMax(
false);
495 if (
pPlugIn->GetStartOptions() &&
496 m_TimeLineHours != 0)
497 ComputeBestForecastForNow();
503 for (
int i = 1; i < 5; i++) {
508 m_HasAltitude =
true;
513#ifdef __OCPN__ANDROID__
514 m_bpSettings->Enable(
true);
520 m_sTimeline->Enable(
m_pTimelineSet !=
nullptr && m_TimeLineHours);
539 bool bconfigOK =
false;
540 if (m_bDataPlot[GribOverlaySettings::WIND] &&
543 if (m_bDataPlot[GribOverlaySettings::WIND_GUST] &&
546 if (m_bDataPlot[GribOverlaySettings::PRESSURE] &&
549 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
552 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
555 if (m_bDataPlot[GribOverlaySettings::CURRENT] &&
559 if (m_bDataPlot[GribOverlaySettings::PRECIPITATION] &&
562 if (m_bDataPlot[GribOverlaySettings::CLOUD] &&
565 if (m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE] &&
568 if (m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE] &&
571 if (m_bDataPlot[GribOverlaySettings::CAPE] &&
574 if (m_bDataPlot[GribOverlaySettings::COMP_REFL] &&
581 for (
int i = 0; i < (int)GribOverlaySettings::GEO_ALTITUDE; i++) {
583 m_bDataPlot[i] =
true;
590 double *latmin,
double *latmax,
591 double *lonmin,
double *lonmax) {
594 double ltmi = -GRIB_NOTDEF, ltma = GRIB_NOTDEF, lnmi = -GRIB_NOTDEF,
596 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
599 if (pGRA->getLatMin() < ltmi) ltmi = pGRA->getLatMin();
600 if (pGRA->getLatMax() > ltma) ltma = pGRA->getLatMax();
601 if (pGRA->getLonMin() < lnmi) lnmi = pGRA->getLonMin();
602 if (pGRA->getLonMax() > lnma) lnma = pGRA->getLonMax();
604 if (ltmi == -GRIB_NOTDEF || lnmi == -GRIB_NOTDEF || ltma == GRIB_NOTDEF ||
608 if (latmin) *latmin = ltmi;
609 if (latmax) *latmax = ltma;
610 if (lonmin) *lonmin = lnmi;
611 if (lonmax) *lonmax = lnma;
618 : m_files(files), m_pattern(pattern) {}
619 virtual wxDirTraverseResult OnFile(
const wxString &filename) {
620 if (m_pattern.Matches(filename)) m_files.Add(filename);
621 return wxDIR_CONTINUE;
623 virtual wxDirTraverseResult OnDir(
const wxString &WXUNUSED(dirname)) {
628 wxArrayString &m_files;
629 const wxRegEx &m_pattern;
632wxArrayString GRIBUICtrlBar::GetFilesInDirectory() {
633 wxArrayString file_array;
634 if (!wxDir::Exists(
m_grib_dir))
return file_array;
638 wxRegEx pattern(_T(
".+\\.gri?b2?(\\.(bz2|gz))?$"),
639 wxRE_EXTENDED | wxRE_ICASE | wxRE_NOSUB);
642 dir.Traverse(collector);
644 CompareFileStringTime);
648void GRIBUICtrlBar::SetCursorLatLon(
double lat,
double lon) {
652 if (m_vpMouse && ((lat > m_vpMouse->
lat_min) && (lat < m_vpMouse->lat_max)) &&
653 ((lon > m_vpMouse->
lon_min) && (lon < m_vpMouse->lon_max)))
658 if (!m_CDataIsShown)
return;
660 if (m_DialogStyle >> 1 == SEPARATED) {
661 if (m_gGRIBUICData) {
662 if (!m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.IsRunning())
663 m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.Start(
664 50, wxTIMER_ONE_SHOT);
668 if (!m_gCursorData->m_tCursorTrackTimer.IsRunning())
669 m_gCursorData->m_tCursorTrackTimer.Start(50, wxTIMER_ONE_SHOT);
674void GRIBUICtrlBar::OnShowCursorData(wxCommandEvent &event) {
675 m_CDataIsShown = !m_CDataIsShown;
676 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(
677 wxBitmap(m_CDataIsShown ? curdata : ncurdata),
678 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"), m_ScaledFactor));
679 SetDialogsStyleSizePosition(
true);
682void GRIBUICtrlBar::SetDialogsStyleSizePosition(
bool force_recompute) {
687 if (!force_recompute &&
688 (m_old_DialogStyle == m_DialogStyle
690 (m_old_DialogStyle >> 1 == ATTACHED && m_DialogStyle >> 1 == ATTACHED)))
693 bool m_HasCaption = GetWindowStyleFlag() == (wxCAPTION | wxCLOSE_BOX |
694 wxSYSTEM_MENU | wxTAB_TRAVERSAL);
699 int state = (m_DialogStyle >> 1 == ATTACHED && m_CDataIsShown) ? 0 : 1;
702 bool vis = i > 0 ? true : m_HasAltitude ? true :
false;
703 if (FindWindow(i + ID_CTRLALTITUDE))
704 FindWindow(i + ID_CTRLALTITUDE)
710 m_bpShowCursorData->SetToolTip(m_CDataIsShown ? _(
"Hide data at cursor")
711 : _(
"Show data at cursor"));
712 m_bpPlay->SetToolTip(_(
"Start play back"));
717 m_gCursorData->Hide();
718 m_fgCDataSizer->Detach(m_gCursorData);
721 SetMinSize(wxSize(0, 0));
725 if (m_gGRIBUICData) {
726 m_gGRIBUICData->Destroy();
727 m_gGRIBUICData =
nullptr;
730 if ((m_DialogStyle >> 1 == SEPARATED || !m_CDataIsShown) &&
737 if (m_CDataIsShown) {
738 if (m_DialogStyle >> 1 == ATTACHED) {
740 if (!m_gCursorData) m_gCursorData =
new CursorData(
this, *
this);
741 pPlugIn->SetDialogFont(m_gCursorData);
742 m_gCursorData->PopulateTrackingControls(
false);
744 if (m_fgCDataSizer->GetItem(m_gCursorData) ==
nullptr)
745 m_fgCDataSizer->Add(m_gCursorData, 0);
746 m_gCursorData->Show();
748 }
else if (m_DialogStyle >> 1 == SEPARATED) {
751 m_gGRIBUICData->m_gCursorData->PopulateTrackingControls(
752 m_DialogStyle == SEPARATED_VERTICAL);
753 pPlugIn->SetDialogFont(m_gGRIBUICData->m_gCursorData);
754 m_gGRIBUICData->Fit();
755 m_gGRIBUICData->Update();
756 m_gGRIBUICData->Show();
758 m_gGRIBUICData->Layout();
759 m_gGRIBUICData->Fit();
764 wxSize sd = GetSize();
766 if (!m_gtk_started && m_HasCaption ) {
768 m_gtk_started =
true;
771 SetSize(wxSize(sd.x, sd.y));
772 SetMinSize(wxSize(sd.x, sd.y));
773#ifdef __OCPN__ANDROID__
779 wxPoint pNew =
pPlugIn->GetCtrlBarXY();
780 pNew.x = tbRect.x + tbRect.width + 4;
788 if (sd.x > widthAvail) {
791 int target_char_width = (float)widthAvail / 28;
800 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
802 dc.GetTextExtent(_T(
"W"), &width, &height,
nullptr,
nullptr, sFont);
803 if (width <= target_char_width) bOK =
true;
805 if (pointSize <= 10) bOK =
true;
808 m_cRecordForecast->SetFont(*sFont);
813 SetSize(wxSize(widthAvail, sd.y));
814 SetMinSize(wxSize(widthAvail, sd.y));
818 wxPoint pNow =
pPlugIn->GetCtrlBarXY();
825 m_old_DialogStyle = m_DialogStyle;
828void GRIBUICtrlBar::OnAltitude(wxCommandEvent &event) {
829 if (!m_HasAltitude)
return;
831 wxMenu *amenu =
new wxMenu();
832 amenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
833 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
this);
835 for (
int i = 0; i < 5; i++) {
843 amenu, ID_CTRLALTITUDE + 1000 + i,
852 amenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
859void GRIBUICtrlBar::OnMove(wxMoveEvent &event) {
861 GetScreenPosition(&w, &h);
862 pPlugIn->SetCtrlBarXY(wxPoint(w, h));
865void GRIBUICtrlBar::OnMenuEvent(wxMenuEvent &event) {
866 int id =
event.GetId();
869 int alt = m_Altitude;
872 case ID_CTRLALTITUDE + 1000:
875 case ID_CTRLALTITUDE + 1001:
878 case ID_CTRLALTITUDE + 1002:
881 case ID_CTRLALTITUDE + 1003:
884 case ID_CTRLALTITUDE + 1004:
892 OnZoomToCenterClick(evt);
894 case ID_BTNSHOWCDATA:
895 OnShowCursorData(evt);
907 OnRequestForecastData(evt);
909 if (alt != m_Altitude) {
910 SetDialogsStyleSizePosition(
true);
915void GRIBUICtrlBar::MenuAppend(wxMenu *menu,
int id, wxString label,
916 wxItemKind kind, wxBitmap bitmap,
918 wxMenuItem *item =
new wxMenuItem(menu,
id, label, _T(
""), kind);
921 item->SetSubMenu(submenu);
931#if defined(__WXMSW__) || defined(__WXGTK__)
932 if (!bitmap.IsSameAs(wxNullBitmap)) item->SetBitmap(bitmap);
938void GRIBUICtrlBar::OnMouseEvent(wxMouseEvent &event) {
939 if (event.RightDown()) {
941 wxMenu *xmenu =
new wxMenu();
942 xmenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
943 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
947 wxMenu *smenu =
new wxMenu();
948 smenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
949 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
952 for (
int i = 0; i < 5; i++) {
960 smenu, ID_CTRLALTITUDE + 1000 + i,
967 smenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
969 xmenu, wxID_ANY, _(
"Select geopotential altitude"), wxITEM_NORMAL,
970 GetScaledBitmap(wxBitmap(altitude), _T(
"altitude"), m_ScaledFactor),
973 MenuAppend(xmenu, ID_BTNNOW, _(
"Now"), wxITEM_NORMAL,
974 GetScaledBitmap(wxBitmap(now), _T(
"now"), m_ScaledFactor));
975 MenuAppend(xmenu, ID_BTNZOOMTC, _(
"Zoom To Center"), wxITEM_NORMAL,
976 GetScaledBitmap(wxBitmap(zoomto), _T(
"zoomto"), m_ScaledFactor));
978 xmenu, ID_BTNSHOWCDATA,
979 m_CDataIsShown ? _(
"Hide data at cursor") : _(
"Show data at cursor"),
981 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
982 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"),
986 m_tPlayStop.IsRunning() ? _(
"Stop play back") : _(
"Start play back"),
988 GetScaledBitmap(wxBitmap(
m_tPlayStop.IsRunning() ? stop : play),
992 xmenu, ID_BTNOPENFILE, _(
"Open a new file"), wxITEM_NORMAL,
993 GetScaledBitmap(wxBitmap(openfile), _T(
"openfile"), m_ScaledFactor));
995 xmenu, ID_BTNSETTING, _(
"Settings"), wxITEM_NORMAL,
996 GetScaledBitmap(wxBitmap(setting), _T(
"setting"), m_ScaledFactor));
1002 requeststate1 ? _(
"Request forecast data")
1004 ? _(
"Draw requested Area or Click here to stop request")
1005 : _(
"Valid Area and Continue"),
1007 GetScaledBitmap(wxBitmap(requeststate1 ? request
1008 : requeststate3 ? selzone
1010 requeststate1 ? _T(
"request")
1011 : requeststate3 ? _T(
"selzone")
1012 : _T(
"request_end"),
1022 if (m_DialogStyle >> 1 == SEPARATED)
return;
1023 wxMouseEvent evt(event);
1026#ifndef __OCPN__ANDROID__
1027 if (m_gCursorData && m_CDataIsShown) {
1028 m_gCursorData->OnMouseEvent(evt);
1033void GRIBUICtrlBar::ContextMenuItemCallback(
int id) {
1035 bool dataisshown = m_CDataIsShown;
1036 m_CDataIsShown =
false;
1044 GetNearestIndex(GetNow(), 0));
1050 m_CDataIsShown = dataisshown;
1055 if (m_vpMouse == vp)
return;
1067void GRIBUICtrlBar::OnClose(wxCloseEvent &event) {
1069 if (m_gGRIBUICData) m_gGRIBUICData->Hide();
1072 pReq_Dialog->StopGraphicalZoneSelection();
1076 pPlugIn->SendTimelineMessage(wxInvalidDateTime);
1078 pPlugIn->OnGribCtrlBarClose();
1081void GRIBUICtrlBar::OnSize(wxSizeEvent &event) {
1083 wxSize p =
event.GetSize();
1089void GRIBUICtrlBar::OnPaint(wxPaintEvent &event) {
1090 wxWindowListNode *node = this->GetChildren().GetFirst();
1093 wxWindow *win = node->GetData();
1094 if (
dynamic_cast<wxBitmapButton *
>(win))
1095 dc.DrawBitmap(
dynamic_cast<wxBitmapButton *
>(win)->GetBitmap(), 5, 5,
1097 node = node->GetNext();
1101void GRIBUICtrlBar::createRequestDialog() {
1102 ::wxBeginBusyCursor();
1107 pPlugIn->SetDialogFont(pReq_Dialog);
1108 pPlugIn->SetDialogFont(pReq_Dialog->m_sScrolledDialog);
1110 pReq_Dialog->SetRequestDialogSize();
1111 if (::wxIsBusy()) ::wxEndBusyCursor();
1114void GRIBUICtrlBar::OnRequestForecastData(wxCommandEvent &event) {
1119 if (pReq_Dialog && pReq_Dialog->IsShown())
return;
1122 createRequestDialog();
1125 ::wxDisplaySize(&w,
nullptr);
1126 pReq_Dialog->Move((w - pReq_Dialog->GetSize().GetX()) / 2, 30);
1127 pReq_Dialog->Show();
1132void GRIBUICtrlBar::OnSettings(wxCommandEvent &event) {
1136 ::wxBeginBusyCursor();
1142 pPlugIn->SetDialogFont(dialog);
1143 for (
size_t i = 0; i < dialog->m_nSettingsBook->GetPageCount(); i++) {
1144 wxScrolledWindow *sc =
1145 ((wxScrolledWindow *)dialog->m_nSettingsBook->GetPage(i));
1149 dialog->m_nSettingsBook->ChangeSelection(dialog->GetPageIndex());
1150 dialog->SetSettingsDialogSize();
1153 ::wxDisplaySize(&w,
nullptr);
1154 dialog->Move((w - dialog->GetSize().GetX()) / 2, 30);
1157 ::wxEndBusyCursor();
1159 if (dialog->ShowModal() == wxID_OK) {
1160 dialog->WriteSettings();
1163 initSettings.Settings[GribOverlaySettings::WIND].m_Units &&
1165 GribOverlaySettings::BFS ||
1166 initSettings.Settings[GribOverlaySettings::WIND].m_Units ==
1167 GribOverlaySettings::BFS))
1169 STARTING_STATE_STYLE;
1173 m_DialogStyle = initSettings.m_iCtrlandDataStyle;
1175 ::wxBeginBusyCursor();
1177 dialog->SaveLastPage();
1179 m_InterpolateMode =
false;
1180 SetTimeLineMax(
true);
1181 SetFactoryOptions();
1183 SetDialogsStyleSizePosition(
true);
1189#ifdef __OCPN__ANDROID__
1190wxString callActivityMethod_ss(
const char *method, wxString parm);
1193void GRIBUICtrlBar::OnCompositeDialog(wxCommandEvent &event) {
1196 initSettings.Read();
1199 wxString json_begin = initSettings.SettingsToJSON(json);
1200 wxLogMessage(json_begin);
1209 double lon_min = wxRound(current_vp.
lon_min) - 1;
1210 double lon_max = wxRound(current_vp.
lon_max) + 1;
1211 double lat_min = wxRound(current_vp.
lat_min) - 1;
1212 double lat_max = wxRound(current_vp.
lat_max) + 1;
1216 int numErrors = reader.
Parse(json_begin, &v);
1217 if (numErrors > 0) {
1221 v[_T(
"latMin")] = lat_min;
1222 v[_T(
"latMax")] = lat_max;
1223 v[_T(
"lonMin")] = lon_min;
1224 v[_T(
"lonMax")] = lon_max;
1228 v[_T(
"grib_file")] = _T(
"");
1231 wxString json_final;
1232 w.
Write(v, json_final);
1233 wxLogMessage(json_final);
1235#ifdef __OCPN__ANDROID__
1236 wxString ret = callActivityMethod_ss(
"doGRIBActivity", json_final);
1243void GRIBUICtrlBar::OpenFileFromJSON(wxString json) {
1249 int numErrors = reader.
Parse(json, &root);
1250 if (numErrors > 0) {
1254 wxString file = root[(_T(
"grib_file"))].AsString();
1256 if (file.Length() && wxFileExists(file)) {
1257 wxFileName fn(file);
1265void GRIBUICtrlBar::OnPlayStop(wxCommandEvent &event) {
1269 m_bpPlay->SetBitmapLabel(
1270 GetScaledBitmap(wxBitmap(stop), _T(
"stop"), m_ScaledFactor));
1271 m_bpPlay->SetToolTip(_(
"Stop play back"));
1273 wxTIMER_CONTINUOUS);
1278void GRIBUICtrlBar::OnPlayStopTimer(wxTimerEvent &event) {
1279 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax()) {
1282 ComputeBestForecastForNow();
1283 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax())
1287 m_sTimeline->SetValue(0);
1294 ? GetNearestValue(GetNow(), 1)
1295 : GetNearestIndex(GetNow(), 2)
1296 : m_sTimeline->GetValue();
1297 m_sTimeline->SetValue(value + 1);
1301 if (!m_InterpolateMode)
1302 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1306void GRIBUICtrlBar::StopPlayBack() {
1309 m_bpPlay->SetBitmapLabel(
1310 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
1311 m_bpPlay->SetToolTip(_(
"Start play back"));
1315void GRIBUICtrlBar::TimelineChanged() {
1317 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1321 RestaureSelectionString();
1327 if (!m_InterpolateMode) {
1330 GribRecordSet &sel = rsa->Item(m_cRecordForecast->GetCurrentSelection());
1333 ? wxTimeSpan(t - MinTime()).GetMinutes() /
1336 : m_cRecordForecast->GetCurrentSelection());
1338 m_cRecordForecast->SetSelection(GetNearestIndex(time, 2));
1339 SaveSelectionString();
1342 wxString formattedTime = toUsrDateTimeFormat_Plugin(time, opts);
1343 m_cRecordForecast->SetString(m_Selection_index,
1346 m_cRecordForecast->SetStringSelection(
1352 pPlugIn->SendTimelineMessage(time);
1356void GRIBUICtrlBar::RestaureSelectionString() {
1357 if (!m_SelectionIsSaved)
return;
1359 int sel = m_cRecordForecast->GetSelection();
1360 m_cRecordForecast->SetString(m_Selection_index, m_Selection_label);
1361 m_cRecordForecast->SetSelection(sel);
1362 m_SelectionIsSaved =
false;
1365int GRIBUICtrlBar::GetNearestIndex(wxDateTime time,
int model) {
1370 wxDateTime itime, ip1time;
1371 for (i = 0; i < rsa->GetCount() - 1; i++) {
1372 itime = rsa->Item(i).m_Reference_Time;
1373 ip1time = rsa->Item(i + 1).m_Reference_Time;
1374 if (ip1time >= time)
break;
1376 if (!model)
return (time - itime > (ip1time - time) * 3) ? i + 1 : i;
1378 return model == 1 ? time == ip1time ? i : i + 1 : time == ip1time ? i + 1 : i;
1381int GRIBUICtrlBar::GetNearestValue(wxDateTime time,
int model) {
1383 if (m_TimeLineHours == 0)
return 0;
1384 wxDateTime itime, ip1time;
1387 wxTimeSpan span = time - MinTime();
1388 int t = span.GetMinutes() / stepmin;
1390 wxTimeSpan(t * stepmin / 60, (t * stepmin) % 60);
1391 ip1time = itime + wxTimeSpan(stepmin / 60, stepmin % 60);
1393 if (model == 1)
return time == ip1time ? t + 1 : t;
1395 return (time - itime > (ip1time - time) * 3) ? t + 1 : t;
1398wxDateTime GRIBUICtrlBar::GetNow() {
1399 wxDateTime now = wxDateTime::Now();
1405 now = (now > rsa->Item(rsa->GetCount() - 1).m_Reference_Time)
1406 ? rsa->Item(rsa->GetCount() - 1).m_Reference_Time
1407 : (now < rsa->Item(0).m_Reference_Time) ? rsa->Item(0).m_Reference_Time
1413 if (m_InterpolateMode) {
1414 int tl = (m_TimeLineHours == 0) ? 0 : m_sTimeline->GetValue();
1417 return MinTime() + wxTimeSpan(tl * stepmin / 60, (tl * stepmin) % 60);
1421 unsigned int index = m_cRecordForecast->GetCurrentSelection() < 1
1423 : m_cRecordForecast->GetCurrentSelection();
1424 if (rsa && index < rsa->GetCount())
return rsa->Item(index).m_Reference_Time;
1426 return wxDateTime::Now();
1429wxDateTime GRIBUICtrlBar::MinTime() {
1431 if (rsa && rsa->GetCount()) {
1435 return wxDateTime::Now();
1442 if (rsa->GetCount() == 0)
return nullptr;
1449 wxDateTime GR1time, GR2time;
1455 for (j = 0; j < rsa->GetCount(); j++) {
1461 if (curtime <= time) GR1time = curtime, GRS1 = GRS, GR1 = GR;
1463 if (curtime >= time) {
1464 GR2time = curtime, GRS2 = GRS, GR2 = GR;
1469 if (!GR1 || !GR2)
continue;
1471 wxDateTime mintime = MinTime();
1472 double minute2 = (GR2time - mintime).GetMinutes();
1473 double minute1 = (GR1time - mintime).GetMinutes();
1474 double nminute = (time - mintime).GetMinutes();
1476 if (minute2 < minute1 || nminute < minute1 || nminute > minute2)
continue;
1478 double interp_const;
1479 if (minute1 == minute2) {
1484 interp_const = (nminute - minute1) / (minute2 - minute1);
1515 *GR1, *GR2, interp_const, i ==
Idx_WVDIR));
1526 auto sog = m_ProjectBoatPanel->GetSpeed();
1527 auto cog = m_ProjectBoatPanel->GetCourse();
1529 static_cast<double>(now.GetTicks() -
pPlugIn->m_boat_time) * sog / 3600.0;
1531 pPlugIn->m_boat_lon, cog, dist,
1532 &m_projected_lat, &m_projected_lon);
1540double GRIBUICtrlBar::getTimeInterpolatedValue(
int idx,
double lon,
double lat,
1545 if (rsa->GetCount() == 0)
return GRIB_NOTDEF;
1547 GribRecord *before =
nullptr, *after =
nullptr;
1550 time_t t = time.GetTicks();
1551 for (j = 0; j < rsa->GetCount(); j++) {
1556 time_t curtime = GR->getRecordCurrentDate();
1559 if (curtime < t) before = GR;
1567 if (!before || !after)
return GRIB_NOTDEF;
1569 time_t t1 = before->getRecordCurrentDate();
1570 time_t t2 = after->getRecordCurrentDate();
1574 double v2 = after->getInterpolatedValue(lon, lat);
1575 if (v1 != GRIB_NOTDEF && v2 != GRIB_NOTDEF) {
1576 double k = fabs((
double)(t - t1) / (t2 - t1));
1577 return (1.0 - k) * v1 + k * v2;
1583bool GRIBUICtrlBar::getTimeInterpolatedValues(
double &M,
double &A,
int idx1,
1584 int idx2,
double lon,
double lat,
1592 if (rsa->GetCount() == 0)
return false;
1594 GribRecord *beforeX =
nullptr, *afterX =
nullptr;
1595 GribRecord *beforeY =
nullptr, *afterY =
nullptr;
1598 time_t t = time.GetTicks();
1599 for (j = 0; j < rsa->GetCount(); j++) {
1603 if (!GX || !GY)
continue;
1605 time_t curtime = GX->getRecordCurrentDate();
1620 if (!beforeX || !afterX)
return false;
1622 time_t t1 = beforeX->getRecordCurrentDate();
1623 time_t t2 = afterX->getRecordCurrentDate();
1628 double v1m, v2m, v1a, v2a;
1637 if (v1m == GRIB_NOTDEF || v2m == GRIB_NOTDEF || v1a == GRIB_NOTDEF ||
1641 double k = fabs((
double)(t - t1) / (t2 - t1));
1642 M = (1.0 - k) * v1m + k * v2m;
1643 A = (1.0 - k) * v1a + k * v2a;
1647void GRIBUICtrlBar::OnTimeline(wxScrollEvent &event) {
1650 if (!m_InterpolateMode)
1651 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1656void GRIBUICtrlBar::OnOpenFile(wxCommandEvent &event) {
1660#ifndef __OCPN__ANDROID__
1662 wxStandardPathsBase &path = wxStandardPaths::Get();
1663 wxString l_grib_dir = path.GetDocumentsDir();
1667 wxFileDialog *dialog =
1668 new wxFileDialog(
nullptr, _(
"Select a GRIB file"), l_grib_dir, _T(
""),
1670 "(*.grb;*.bz2;*.gz;*.grib2;*.grb2)|*.grb;*.bz2;*.gz;"
1671 "*.grib2;*.grb2|All files (*)|*.*"),
1672 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE,
1673 wxDefaultPosition, wxDefaultSize, _T(
"File Dialog"));
1675 if (dialog->ShowModal() == wxID_OK) {
1676 ::wxBeginBusyCursor();
1682 if (g_pi->m_bZoomToCenterAtInit) DoZoomToCenter();
1684 SetDialogsStyleSizePosition(
true);
1689 wxStandardPathsBase &path = wxStandardPaths::Get();
1695 nullptr, &file, _(
"Select a GRIB file"),
m_grib_dir, _T(
""), _T(
"*.*"));
1697 if (response == wxID_OK) {
1698 wxFileName fn(file);
1703 SetDialogsStyleSizePosition(
true);
1708void GRIBUICtrlBar::CreateActiveFileFromNames(
const wxArrayString &filenames) {
1709 if (filenames.GetCount() != 0) {
1716void GRIBUICtrlBar::PopulateComboDataList() {
1718 if (m_cRecordForecast->GetCount()) {
1719 index = m_cRecordForecast->GetCurrentSelection();
1720 m_cRecordForecast->Clear();
1726 for (
size_t i = 0; i < rsa->GetCount(); i++) {
1727 wxDateTime t(rsa->Item(i).m_Reference_Time);
1728 m_cRecordForecast->Append(toUsrDateTimeFormat_Plugin(t, opts));
1730 m_cRecordForecast->SetSelection(index);
1733void GRIBUICtrlBar::OnZoomToCenterClick(wxCommandEvent &event) {
1738 double latmin,latmax,lonmin,lonmax;
1739 if(!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax ))
1745 double width = lonmax - lonmin;
1746 double height = latmax - latmin;
1749 double clat = latmin + height / 2;
1750 double clon = lonmin + width / 2;
1754 lonmin = clon - 60.;
1755 lonmax = clon + 60.;
1758 latmin = clat - 60.;
1759 latmax = clat + 60.;
1769 int w =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetWidth();
1770 int h =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetHeight();
1774 ppm = wxMin(w/(ow*1852), h/(oh*1852)) * ( 100 - fabs( clat ) ) / 90;
1776 ppm = wxMin(ppm, 1.0);
1784void GRIBUICtrlBar::DoZoomToCenter() {
1787 double latmin, latmax, lonmin, lonmax;
1788 if (!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax))
1794 double width = lonmax - lonmin;
1795 double height = latmax - latmin;
1798 double clat = latmin + height / 2;
1799 double clon = lonmin + width / 2;
1803 lonmin = clon - 60.;
1804 lonmax = clon + 60.;
1806 if (height > 120.) {
1807 latmin = clat - 60.;
1808 latmax = clat + 60.;
1816 wxWindow *wx = GetGRIBCanvas();
1818 int w = wx->GetSize().x;
1819 int h = wx->GetSize().y;
1823 ppm = wxMin(w / (ow * 1852), h / (oh * 1852)) * (100 - fabs(clat)) / 90;
1825 ppm = wxMin(ppm, 1.0);
1830void GRIBUICtrlBar::OnPrev(wxCommandEvent &event) {
1834 RestaureSelectionString();
1838 selection = GetNearestIndex(GetNow(), 1);
1839 else if (m_InterpolateMode)
1843 selection = m_cRecordForecast->GetCurrentSelection();
1846 m_InterpolateMode =
false;
1848 m_cRecordForecast->SetSelection(selection < 1 ? 0 : selection - 1);
1853void GRIBUICtrlBar::OnNext(wxCommandEvent &event) {
1857 RestaureSelectionString();
1861 selection = GetNearestIndex(GetNow(), 2);
1862 else if (m_InterpolateMode)
1866 selection = m_cRecordForecast->GetCurrentSelection();
1868 m_cRecordForecast->SetSelection(selection);
1871 m_InterpolateMode =
false;
1873 if (selection == (
int)m_cRecordForecast->GetCount() - 1)
1876 m_cRecordForecast->SetSelection(selection + 1);
1881void GRIBUICtrlBar::ComputeBestForecastForNow() {
1883 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1887 wxDateTime now = GetNow();
1890 m_sTimeline->SetValue(GetNearestValue(now, 0));
1892 m_cRecordForecast->SetSelection(GetNearestIndex(now, 0));
1893 m_sTimeline->SetValue(m_cRecordForecast->GetCurrentSelection());
1896 if (
pPlugIn->GetStartOptions() !=
1903 m_InterpolateMode =
true;
1905 SetGribTimelineRecordSet(
1908 RestaureSelectionString();
1910 m_cRecordForecast->SetSelection(GetNearestIndex(now, 2));
1911 SaveSelectionString();
1914 wxString nowTime = toUsrDateTimeFormat_Plugin(now, opts);
1915 m_cRecordForecast->SetString(m_Selection_index,
1918 m_cRecordForecast->SetStringSelection(nowTime);
1922 pPlugIn->SendTimelineMessage(now);
1926void GRIBUICtrlBar::SetGribTimelineRecordSet(
1931 if (!
pPlugIn->GetGRIBOverlayFactory())
return;
1936void GRIBUICtrlBar::SetTimeLineMax(
bool SetValue) {
1937 int oldmax = wxMax(m_sTimeline->GetMax(), 1),
1938 oldval = m_sTimeline->GetValue();
1943 m_sTimeline->SetMax(m_TimeLineHours * 60 / stepmin);
1947 m_sTimeline->SetMax(rsa->GetCount() - 1);
1952 if (SetValue && m_sTimeline->GetMax() != 0) {
1954 ComputeBestForecastForNow();
1956 m_sTimeline->SetValue(m_sTimeline->GetMax() * oldval / oldmax);
1960void GRIBUICtrlBar::SetFactoryOptions() {
1963 pPlugIn->GetGRIBOverlayFactory()->ClearCachedData();
1972unsigned int GRIBFile::ID = 0;
1978 m_pGribReader =
nullptr;
1979 m_last_message = wxEmptyString;
1980 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
1981 wxString file_name = file_names[i];
1982 if (::wxFileExists(file_name)) m_bOK =
true;
1985 if (m_bOK ==
false) {
1986 m_last_message = _(
" files don't exist!");
1995 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
1996 file_name = file_names[i];
1997 m_pGribReader->openFile(file_name);
1999 if (m_pGribReader->isOk()) {
2006 if (m_bOK ==
false) {
2007 m_last_message = _(
" can't be read!");
2012 m_FileNames.Clear();
2013 m_FileNames.Add(file_name);
2015 m_FileNames = file_names;
2019 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_TOT, LV_GND_SURF, 0);
2020 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_RATE, LV_GND_SURF, 0);
2021 m_pGribReader->computeAccumulationRecords(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
2029 m_nGribRecords = m_pGribReader->getTotalNumberOfGribRecords();
2033 std::set<time_t>::iterator iter;
2034 std::set<time_t> date_list = m_pGribReader->getListDates();
2035 for (iter = date_list.begin(); iter != date_list.end(); iter++) {
2037 time_t reftime = *iter;
2039 m_GribRecordSetArray.Add(t);
2047 bool polarWind(
false);
2048 bool polarCurrent(
false);
2049 bool sigWave(
false);
2052 std::map<std::string, std::vector<GribRecord *> *> *p_map =
2053 m_pGribReader->getGribMap();
2056 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
2057 for (it = p_map->begin(); it != p_map->end(); it++) {
2058 std::vector<GribRecord *> *ls = (*it).second;
2059 for (zuint i = 0; i < ls->size(); i++) {
2062 time_t thistime = pRec->getRecordCurrentDate();
2065 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2066 if (m_GribRecordSetArray.Item(j).m_Reference_Time == thistime) {
2067 int idx = -1, mdx = -1;
2091 case GRB_WIND_SPEED:
2114 polarCurrent =
true;
2120 polarCurrent =
true;
2152 case GRB_PRECIP_RATE:
2153 case GRB_PRECIP_TOT:
2178 mdx = 1000 + NORWAY_METNO;
2208 case GRB_GEOPOT_HGT:
2234 if (m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx]) {
2237 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2259 if (oRec->
getDataType() == GRB_HTSGW) skip =
true;
2269 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx] = pRec;
2270 if (m_GribIdxArray.Index(idx) == wxNOT_FOUND)
2271 m_GribIdxArray.Add(idx, 1);
2272 if (mdx != -1 && m_GribIdxArray.Index(mdx) == wxNOT_FOUND)
2273 m_GribIdxArray.Add(mdx, 1);
2281 if (polarWind || polarCurrent) {
2282 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2283 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
2287 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2289 if (pRec !=
nullptr && pRec->
getDataType() == GRB_WIND_DIR) {
2311 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2312 if (pRec1 !=
nullptr && pRec1->
getDataType() == GRB_WIND_SPEED)
2320 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2322 if (pRec !=
nullptr && pRec->
getDataType() == GRB_CUR_DIR) {
2332 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2333 if (pRec1 !=
nullptr && pRec1->
getDataType() == GRB_CUR_SPEED)
2344 pRec->getRecordRefDate();
2347GRIBFile::~GRIBFile() {
delete m_pGribReader; }
2354 :
GRIBUICDataBase(parent.pParent, CURSOR_DATA, _(
"GRIB Display Control"),
2355 wxDefaultPosition, wxDefaultSize,
2356 wxSYSTEM_MENU | wxNO_BORDER | wxSTAY_ON_TOP)
2359 wxDefaultPosition, wxDefaultSize,
2360 wxSYSTEM_MENU | wxNO_BORDER)
2363 m_gpparent(parent) {
2367 m_gCursorData =
new CursorData(
this, m_gpparent);
2368 m_fgCdataSizer->Add(m_gCursorData, 0, wxALL, 0);
2370 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICData::OnMove));
2373void GRIBUICData::OnMove(wxMoveEvent &event) {
2375 GetScreenPosition(&w, &h);
2376 m_gpparent.
pPlugIn->SetCursorDataXY(wxPoint(w, h));
2382#ifdef __OCPN__ANDROID__
2384#include <QtAndroidExtras/QAndroidJniObject>
2386bool CheckPendingJNIException() {
2393 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2398 if ((jenv)->ExceptionCheck() == JNI_TRUE) {
2406wxString callActivityMethod_ss(
const char *method, wxString parm) {
2412 if (CheckPendingJNIException())
return _T(
"NOK");
2414 wxString return_string;
2415 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2416 "org/qtproject/qt5/android/QtNative",
"activity",
2417 "()Landroid/app/Activity;");
2418 if (CheckPendingJNIException())
return _T(
"NOK");
2420 if (!activity.isValid()) {
2422 return return_string;
2427 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2429 return "jenv Error";
2432 jstring p = (jenv)->NewStringUTF(parm.c_str());
2438 QAndroidJniObject data = activity.callObjectMethod(
2439 method,
"(Ljava/lang/String;)Ljava/lang/String;", p);
2440 if (CheckPendingJNIException())
return _T(
"NOK");
2444 jstring s = data.object<jstring>();
2446 if ((jenv)->GetStringLength(s)) {
2447 const char *ret_string = (jenv)->GetStringUTFChars(s,
nullptr);
2448 return_string = wxString(ret_string, wxConvUTF8);
2451 return return_string;
@ Idx_AIR_TEMP850
Air temperature at 850 hPa.
@ Idx_COMP_REFL
Composite radar reflectivity.
@ Idx_PRECIP_TOT
Total precipitation.
@ Idx_AIR_TEMP
Air temperature at 2m.
@ Idx_PRESSURE
Surface pressure.
@ Idx_WVDIR
Wave direction.
@ Idx_HUMID_RE850
Relative humidity at 850 hPa.
@ Idx_CLOUD_TOT
Total cloud cover.
@ Idx_WIND_GUST
Wind gust speed at surface.
@ Idx_WIND_VX
Surface wind velocity X component.
@ Idx_AIR_TEMP300
Air temperature at 300 hPa.
@ Idx_COUNT
Number of supported GRIB record types.
@ Idx_WIND_VY850
Wind velocity Y component at 850 hPa.
@ Idx_HUMID_RE500
Relative humidity at 500 hPa.
@ Idx_WIND_VX300
Wind velocity X component at 300 hPa.
@ Idx_HUMID_RE300
Relative humidity at 300 hPa.
@ Idx_WIND_VX850
Wind velocity X component at 850 hPa.
@ Idx_WIND_VY300
Wind velocity Y component at 300 hPa.
@ Idx_WIND_VX700
Wind velocity X component at 700 hPa.
@ Idx_HTSIGW
Significant wave height.
@ Idx_AIR_TEMP700
Air temperature at 700 hPa.
@ Idx_WIND_VY500
Wind velocity Y component at 500 hPa.
@ Idx_GEOP_HGT500
Geopotential height at 500 hPa.
@ Idx_SEACURRENT_VY
Sea current velocity Y component.
@ Idx_WIND_VX500
Wind velocity X component at 500 hPa.
@ Idx_GEOP_HGT300
Geopotential height at 300 hPa.
@ Idx_GEOP_HGT700
Geopotential height at 700 hPa.
@ Idx_WIND_VY700
Wind velocity Y component at 700 hPa.
@ Idx_SEA_TEMP
Sea surface temperature.
@ Idx_WIND_VY
Surface wind velocity Y component.
@ Idx_GEOP_HGT850
Geopotential height at 850 hPa.
@ Idx_SEACURRENT_VX
Sea current velocity X component.
@ Idx_AIR_TEMP500
Air temperature at 500 hPa.
@ Idx_HUMID_RE700
Relative humidity at 700 hPa.
@ Idx_CAPE
Convective Available Potential Energy.
int m_SavedZoneSelMode
Persisted version of the GRIB area selection mode.
int m_ZoneSelMode
Tracks the current state of GRIB area selection for zone coordinates.
GRIB Data Table View and Export Interface.
#define ID_BTNREQUEST
ID of button for requesting/downloading GRIB data./*#end#*/.
int m_SavedZoneSelMode
Persisted version of the GRIB area selection mode.
int m_ZoneSelMode
Tracks the current state of GRIB area selection for zone coordinates.
GRIB Weather Data Control Interface.
@ AUTO_SELECTION
Area automatically set from current viewport bounds.
@ DRAW_SELECTION
Manual mode has been selected.
@ START_SELECTION
User has clicked Shift + Left click and is drawing the bounding box by dragging the mouse.
@ SAVED_SELECTION
Area loaded from previously saved coordinates.
Tracks and displays GRIB meteorological data at cursor position.
Manages multiple GRIB record sets from one or more GRIB files.
GRIBFile(const wxArrayString &file_names, bool CumRec, bool WaveRec, bool newestFile=false)
Creates a new GRIBFile by parsing one or more GRIB files.
time_t GetRefDateTime(void)
Returns the reference datetime of the GRIB data, as the number of seconds since the epoch.
ArrayOfGribRecordSets * GetRecordSetArrayPtr(void)
Gets pointer to array of record sets organized by timestamp.
wxArrayString & GetFileNames(void)
Gets the list of source filenames being used.
bool IsOK(void)
Checks if file loading and parsing was successful.
Dialog showing GRIB data in a table format.
void SetTableSizePosition(int vpWidth, int vpHeight)
Set the table size and position relative to viewport.
void InitGribTable(const wxString zone, ArrayOfGribRecordSets *rsa)
Initialize the GRIB data table.
void SetViewPortWithFocus(PlugIn_ViewPort *vp)
Set the ViewPort that has the focus.
void GetProjectedLatLon(int &x, int &y, PlugIn_ViewPort *vp)
Gets the projected position of vessel based on current course, speed and forecast time.
GribOverlaySettings m_OverlaySettings
Settings that control how GRIB data is displayed and overlaid.
void SetRequestButtonBitmap(int type)
Set the icon and tooltip for the download request button.
wxTimer m_tPlayStop
Timer for controlling GRIB animation playback.
void SetViewPortUnderMouse(PlugIn_ViewPort *vp)
Set the ViewPort under the mouse.
wxString m_grib_dir
Directory containing GRIB files.
grib_pi * pPlugIn
Plugin instance that owns this control bar.
GRIBFile * m_bGRIBActiveFile
Currently active GRIB file being displayed.
wxDateTime TimelineTime()
Returns the selected time in the GRIB timeline widget.
void UpdateTrackingControl()
Schedules an update of the GRIB data values display at current cursor position.
GribTimelineRecordSet * m_pTimelineSet
Current set of GRIB records for timeline playback.
wxArrayString m_file_names
List of GRIB filenames being displayed.
GribTimelineRecordSet * GetTimeLineRecordSet(wxDateTime time)
Retrieves or creates a temporally interpolated GRIB record set for a specific timestamp.
void copyMissingWaveRecords()
Fills gaps in wave-related data fields by propagating known values across missing time periods.
void copyFirstCumulativeRecord()
Initializes cumulative meteorological parameters by copying their first record values.
Manages a collection of GribRecord objects representing multiple meteorological parameters at a singl...
void SetUnRefGribRecord(int i, GribRecord *pGR)
Sets a GRIB record that this set owns and will be responsible for deleting.
GribRecord * m_GribRecordPtrArray[Idx_COUNT]
Array of pointers to GRIB records representing different meteorological parameters.
time_t m_Reference_Time
Reference time for this set of records, as the number of seconds since the epoch.
Represents a meteorological data grid from a GRIB (Gridded Binary) file.
zuchar getTimeRange() const
Returns the time range indicator that defines how P1 and P2 should be interpreted.
static void Polar2UV(GribRecord *pDIR, GribRecord *pSPEED)
Converts wind or current values from polar (direction/speed) to cartesian (U/V) components.
static GribRecord * Interpolated2DRecord(GribRecord *&rety, const GribRecord &rec1x, const GribRecord &rec1y, const GribRecord &rec2x, const GribRecord &rec2y, double d)
Creates temporally interpolated records for vector fields (wind, currents).
zuint getDataCenterModel() const
Returns the numerical weather prediction model/center that produced this data.
double getInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
static GribRecord * InterpolatedRecord(const GribRecord &rec1, const GribRecord &rec2, double d, bool dir=false)
Creates a new GribRecord by temporally interpolating between two time points.
static bool getInterpolatedValues(double &M, double &A, const GribRecord *GRX, const GribRecord *GRY, double px, double py, bool numericalInterpolation=true)
Gets spatially interpolated wind or current vector values at a specific latitude/longitude point.
zuint getLevelValue() const
Returns the numeric value associated with the level type.
zuchar getLevelType() const
Returns the type of vertical level for this grid's data.
zuchar getDataType() const
Returns the type of meteorological parameter stored in this grid.
Manages GRIB file request configuration and downloads.
void OnVpUnderMouseChange(PlugIn_ViewPort *vp)
Callback invoked when the view port under mouse has changed.
void OnVpWithFocusChange(PlugIn_ViewPort *vp)
Callback invoked when the focused view port has changed, such as in multi-chart mode when user switch...
A specialized GribRecordSet that represents temporally interpolated weather data with isobar renderin...
wxArrayPtrVoid * m_IsobarArray[Idx_COUNT]
Array of cached isobar calculations for each data type (wind, pressure, etc).
GribTimelineRecordSet(unsigned int cnt)
Creates a timeline record set containing temporally interpolated GRIB records.
Contains view parameters and status information for a chart display viewport.
int pix_width
Viewport width in pixels.
double lon_max
Maximum longitude of the viewport.
double lat_max
Maximum latitude of the viewport.
int pix_height
Viewport height in pixels.
double lon_min
Minimum longitude of the viewport.
double lat_min
Minimum latitude of the viewport.
bool GetCopyFirstCumRec()
Returns true if cumulative parameters like precipitation and cloud cover should initialize their star...
bool GetCopyMissWaveRec()
Returns true if wave data should be propagated across time periods where wave records are missing.
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
The JSON document writer.
void Write(const wxJSONValue &value, wxString &str)
Write the JSONvalue object to a JSON text.
Email Request System for GRIB Data.
GRIB Weather Data Plugin for OpenCPN.
PlugIn Object Definition/API.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
void SetCanvasContextMenuItemViz(int item, bool viz)
Temporarily changes context menu item visibility.
int GetCanvasCount()
Gets total number of chart canvases.
wxFont * FindOrCreateFont_PlugIn(int point_size, wxFontFamily family, wxFontStyle style, wxFontWeight weight, bool underline, const wxString &facename, wxFontEncoding encoding)
Creates or finds a font in the font cache.
void PositionBearingDistanceMercator_Plugin(double lat, double lon, double brg, double dist, double *dlat, double *dlon)
Calculates destination point given start point, bearing and distance.
void JumpToPosition(double lat, double lon, double scale)
Centers chart display on specified position at given scale.
int PlatformFileSelectorDialog(wxWindow *parent, wxString *file_spec, wxString Title, wxString initDir, wxString suggestedName, wxString wildcard)
Shows platform-optimized file selector dialog.
wxRect GetMasterToolbarRect()
Gets bounding rectangle of master toolbar.
void CanvasJumpToPosition(wxWindow *canvas, double lat, double lon, double scale)
Centers specified canvas on given position at given scale.
void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
Converts lat/lon to canvas physical pixel coordinates.
void DimeWindow(wxWindow *win)
Applies system color scheme to window.
wxWindow * GetCanvasByIndex(int canvasIndex)
Gets chart canvas window by index.
void RequestRefresh(wxWindow *win)
Requests window refresh.
wxFileConfig * GetOCPNConfigObject(void)
Gets OpenCPN's configuration object.
void DistanceBearingMercator_Plugin(double lat0, double lon0, double lat1, double lon1, double *brg, double *dist)
Calculates bearing and distance between two points.
OpenGL Platform Abstraction Layer.