27#include "wx/tokenzr.h"
28#include "wx/datetime.h"
30#include <wx/wfstream.h>
32#include <wx/filename.h>
34#include <wx/graphics.h>
37#include <wx/stdpaths.h>
49#include <wx/arrimpl.cpp>
52#include "android_jvm.h"
56double m_cursor_lat, m_cursor_lon;
92 return ((x - i) >= 0.5) ? (i + 1) : (i);
94 return (-x + i >= 0.5) ? (i - 1) : (i);
104#if wxCHECK_VERSION(2, 9, 4)
105#define SetBitmapLabelLabel SetBitmap
108#define DEFAULT_STYLE \
109 = wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL
111WX_DEFINE_OBJARRAY(ArrayOfGribRecordSets);
114static int CompareFileStringTime(
const wxString &first,
115 const wxString &second) {
117 wxFileName s(second);
118 wxTimeSpan sp = s.GetModificationTime() - f.GetModificationTime();
119 return sp.GetMinutes();
125wxWindow *GetGRIBCanvas() {
148GribTimelineRecordSet::~GribTimelineRecordSet() {
153void GribTimelineRecordSet::ClearCachedData() {
157 for (
unsigned int j = 0; j <
m_IsobarArray[i]->GetCount(); j++) {
171GRIBUICtrlBar::GRIBUICtrlBar(wxWindow *parent, wxWindowID
id,
172 const wxString &title,
const wxPoint &pos,
173 const wxSize &size,
long style,
grib_pi *ppi,
181 pReq_Dialog =
nullptr;
182 m_bGRIBActiveFile =
nullptr;
183 m_pTimelineSet =
nullptr;
184 m_gCursorData =
nullptr;
185 m_gGRIBUICData =
nullptr;
186 m_gtk_started =
false;
191 m_fgCtrlGrabberSize->Add(m_gGrabber, 0, wxALL, 0);
193 this->SetSizer(m_fgCtrlBarSizer);
195 m_fgCtrlBarSizer->Fit(
this);
198 m_tFormatRefresh.Connect(
199 wxEVT_TIMER, wxTimerEventHandler(GRIBUICtrlBar::OnFormatRefreshTimer),
204 wxDateTime referenceDate(1, wxDateTime::Jan, 2021, 12, 0, 0);
208 m_tFormatRefresh.Start(5000);
211 pConf->SetPath(_T (
"/Settings/GRIB" ));
212 pConf->Read(_T (
"WindPlot" ), &m_bDataPlot[GribOverlaySettings::WIND],
214 pConf->Read(_T (
"WindGustPlot" ),
215 &m_bDataPlot[GribOverlaySettings::WIND_GUST],
false);
216 pConf->Read(_T (
"PressurePlot" ),
217 &m_bDataPlot[GribOverlaySettings::PRESSURE],
false);
218 pConf->Read(_T (
"WavePlot" ), &m_bDataPlot[GribOverlaySettings::WAVE],
220 pConf->Read(_T (
"CurrentPlot" ),
221 &m_bDataPlot[GribOverlaySettings::CURRENT],
false);
222 pConf->Read(_T (
"PrecipitationPlot" ),
223 &m_bDataPlot[GribOverlaySettings::PRECIPITATION],
false);
224 pConf->Read(_T (
"CloudPlot" ), &m_bDataPlot[GribOverlaySettings::CLOUD],
226 pConf->Read(_T (
"AirTemperaturePlot" ),
227 &m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE],
false);
228 pConf->Read(_T (
"SeaTemperaturePlot" ),
229 &m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE],
false);
230 pConf->Read(_T (
"CAPEPlot" ), &m_bDataPlot[GribOverlaySettings::CAPE],
232 pConf->Read(_T (
"CompReflectivityPlot" ),
233 &m_bDataPlot[GribOverlaySettings::COMP_REFL],
false);
235 pConf->Read(_T (
"CursorDataShown" ), &m_CDataIsShown,
true);
237 pConf->Read(_T (
"lastdatatype" ), &m_lastdatatype, 0);
239 pConf->SetPath(_T (
"/Settings/GRIB/FileNames" ));
240 m_file_names.Clear();
241 if (pConf->GetNumberOfEntries()) {
244 bool bCont = pConf->GetFirstEntry(str, dummy);
246 pConf->Read(str, &val);
247 m_file_names.Add(val);
248 bCont = pConf->GetNextEntry(str, dummy);
252 wxStandardPathsBase &spath = wxStandardPaths::Get();
254 pConf->SetPath(_T (
"/Directories" ));
255 pConf->Read(_T (
"GRIBDirectory" ), &m_grib_dir);
257 pConf->SetPath(_T(
"/PlugIns/GRIB" ));
261 pConf->SetPath(_T (
"/Settings/GRIB/XyGrib" ));
262 pConf->Read(_T(
"AtmModelIndex" ), &xyGribConfig.atmModelIndex, 0);
263 pConf->Read(_T(
"WaveModelIndex" ), &xyGribConfig.waveModelIndex, 0);
264 pConf->Read(_T(
"ResolutionIndex" ), &xyGribConfig.resolutionIndex, 0);
265 pConf->Read(_T(
"DurationIndex" ), &xyGribConfig.durationIndex, 0);
266 pConf->Read(_T(
"RunIndex" ), &xyGribConfig.runIndex, 0);
267 pConf->Read(_T(
"IntervalIndex" ), &xyGribConfig.intervalIndex, 0);
268 pConf->Read(_T(
"Wind" ), &xyGribConfig.wind,
true);
269 pConf->Read(_T(
"Gust" ), &xyGribConfig.gust,
true);
270 pConf->Read(_T(
"Pressure" ), &xyGribConfig.pressure,
false);
271 pConf->Read(_T(
"Temperature" ), &xyGribConfig.temperature,
true);
272 pConf->Read(_T(
"Cape" ), &xyGribConfig.cape,
false);
273 pConf->Read(_T(
"Reflectivity" ), &xyGribConfig.reflectivity,
false);
274 pConf->Read(_T(
"CloudCover" ), &xyGribConfig.cloudCover,
true);
275 pConf->Read(_T(
"Precipitation" ), &xyGribConfig.precipitation,
true);
276 pConf->Read(_T(
"WaveHeight" ), &xyGribConfig.waveHeight,
true);
277 pConf->Read(_T(
"WindWaves" ), &xyGribConfig.windWaves,
true);
283 m_tPlayStop.Connect(wxEVT_TIMER,
284 wxTimerEventHandler(GRIBUICtrlBar::OnPlayStopTimer),
287 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICtrlBar::OnMove));
289 m_OverlaySettings.Read();
294 SetMinSize(GetBestSize());
295 if (m_ProjectBoatPanel) {
296 m_ProjectBoatPanel->SetSpeed(pPlugIn->m_boat_sog);
297 m_ProjectBoatPanel->SetCourse(pPlugIn->m_boat_cog);
299 m_highlight_latmax = 0;
300 m_highlight_lonmax = 0;
301 m_highlight_latmin = 0;
302 m_highlight_lonmin = 0;
304#ifndef __OCPN__ANDROID__
310 createRequestDialog();
314GRIBUICtrlBar::~GRIBUICtrlBar() {
319 pConf->SetPath(_T (
"/Settings/GRIB" ));
320 pConf->Write(_T (
"WindPlot" ), m_bDataPlot[GribOverlaySettings::WIND]);
321 pConf->Write(_T (
"WindGustPlot" ),
322 m_bDataPlot[GribOverlaySettings::WIND_GUST]);
323 pConf->Write(_T (
"PressurePlot" ),
324 m_bDataPlot[GribOverlaySettings::PRESSURE]);
325 pConf->Write(_T (
"WavePlot" ), m_bDataPlot[GribOverlaySettings::WAVE]);
326 pConf->Write(_T (
"CurrentPlot" ),
327 m_bDataPlot[GribOverlaySettings::CURRENT]);
328 pConf->Write(_T (
"PrecipitationPlot" ),
329 m_bDataPlot[GribOverlaySettings::PRECIPITATION]);
330 pConf->Write(_T (
"CloudPlot" ), m_bDataPlot[GribOverlaySettings::CLOUD]);
331 pConf->Write(_T (
"AirTemperaturePlot" ),
332 m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE]);
333 pConf->Write(_T (
"SeaTemperaturePlot" ),
334 m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE]);
335 pConf->Write(_T (
"CAPEPlot" ), m_bDataPlot[GribOverlaySettings::CAPE]);
336 pConf->Write(_T (
"CompReflectivityPlot" ),
337 m_bDataPlot[GribOverlaySettings::COMP_REFL]);
339 pConf->Write(_T (
"CursorDataShown" ), m_CDataIsShown);
341 pConf->Write(_T (
"lastdatatype" ), m_lastdatatype);
343 pConf->SetPath(_T (
"/Settings/GRIB/FileNames" ));
344 int iFileMax = pConf->GetNumberOfEntries();
348 for (
int i = 0; i < iFileMax; i++) {
349 if (pConf->GetFirstEntry(key, dummy)) pConf->DeleteEntry(key,
false);
353 for (
unsigned int i = 0; i <
m_file_names.GetCount(); i++) {
355 key.Printf(_T(
"Filename%d"), i);
359 pConf->SetPath(_T (
"/Directories" ));
360 pConf->Write(_T (
"GRIBDirectory" ),
m_grib_dir);
363 pConf->SetPath(_T (
"/Settings/GRIB/XyGrib" ));
364 pConf->Write(_T(
"AtmModelIndex" ), xyGribConfig.atmModelIndex);
365 pConf->Write(_T(
"WaveModelIndex" ), xyGribConfig.waveModelIndex);
366 pConf->Write(_T(
"ResolutionIndex" ), xyGribConfig.resolutionIndex);
367 pConf->Write(_T(
"DurationIndex" ), xyGribConfig.durationIndex);
368 pConf->Write(_T(
"RunIndex" ), xyGribConfig.runIndex);
369 pConf->Write(_T(
"IntervalIndex" ), xyGribConfig.intervalIndex);
370 pConf->Write(_T(
"Wind" ), xyGribConfig.wind);
371 pConf->Write(_T(
"Gust" ), xyGribConfig.gust);
372 pConf->Write(_T(
"Pressure" ), xyGribConfig.pressure);
373 pConf->Write(_T(
"Temperature" ), xyGribConfig.temperature);
374 pConf->Write(_T(
"Cape" ), xyGribConfig.cape);
375 pConf->Write(_T(
"Reflectivity" ), xyGribConfig.reflectivity);
376 pConf->Write(_T(
"CloudCover" ), xyGribConfig.cloudCover);
377 pConf->Write(_T(
"Precipitation" ), xyGribConfig.precipitation);
378 pConf->Write(_T(
"WaveHeight" ), xyGribConfig.waveHeight);
379 pConf->Write(_T(
"WindWaves" ), xyGribConfig.windWaves);
385void GRIBUICtrlBar::SetScaledBitmap(
double factor) {
387 m_ScaledFactor = wxRound(factor * 4.0) / 4.0;
389 m_bpPrev->SetBitmapLabel(
390 GetScaledBitmap(wxBitmap(prev), _T(
"prev"), m_ScaledFactor));
391 m_bpNext->SetBitmapLabel(
392 GetScaledBitmap(wxBitmap(next), _T(
"next"), m_ScaledFactor));
393 m_bpAltitude->SetBitmapLabel(
394 GetScaledBitmap(wxBitmap(altitude), _T(
"altitude"), m_ScaledFactor));
395 m_bpNow->SetBitmapLabel(
396 GetScaledBitmap(wxBitmap(now), _T(
"now"), m_ScaledFactor));
397 m_bpZoomToCenter->SetBitmapLabel(
398 GetScaledBitmap(wxBitmap(zoomto), _T(
"zoomto"), m_ScaledFactor));
399 m_bpPlay->SetBitmapLabel(
400 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
401 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(
402 wxBitmap(m_CDataIsShown ? curdata : ncurdata),
403 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"), m_ScaledFactor));
405 m_bpOpenFile->SetBitmapLabel(
406 GetScaledBitmap(wxBitmap(openfile), _T(
"openfile"), m_ScaledFactor));
407 m_bpSettings->SetBitmapLabel(
408 GetScaledBitmap(wxBitmap(setting), _T(
"setting"), m_ScaledFactor));
414#ifdef __OCPN__ANDROID__
415 m_sTimeline->SetSize(wxSize(20 * m_ScaledFactor, -1));
416 m_sTimeline->SetMinSize(wxSize(20 * m_ScaledFactor, -1));
418 m_sTimeline->SetSize(wxSize(90 * m_ScaledFactor, -1));
419 m_sTimeline->SetMinSize(wxSize(90 * m_ScaledFactor, -1));
424 if (
nullptr == m_bpRequest)
return;
425 m_bpRequest->SetBitmapLabel(
426 GetScaledBitmap(wxBitmap(request), _T(
"request"), m_ScaledFactor));
427 m_bpRequest->SetToolTip(_(
"Start a download request"));
430void GRIBUICtrlBar::OpenFile(
bool newestFile) {
431 m_bpPlay->SetBitmapLabel(
432 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
433 m_cRecordForecast->Clear();
434 pPlugIn->GetGRIBOverlayFactory()->ClearParticles();
440 m_sTimeline->SetValue(0);
442 m_InterpolateMode =
false;
444 m_SelectionIsSaved =
false;
445 m_HasAltitude =
false;
466 title = (_(
"File: "));
467 title.Append(fn.GetFullName());
468 if (rsa->GetCount() == 0) {
471 title.Prepend(_(
"Error! ")).Append(_(
" contains no valid data!"));
473 PopulateComboDataList();
479 if (rsa->GetCount() > 1) {
481 &last = rsa->Item(rsa->GetCount() - 1);
484 wxTimeSpan span = wxDateTime(last.m_Reference_Time) -
486 m_TimeLineHours = span.GetHours();
489 int halfintermin(wxTimeSpan(wxDateTime(second.m_Reference_Time) -
493 for (m_FileIntervalIndex = 0;; m_FileIntervalIndex++) {
498 if (m_FileIntervalIndex > 0) m_FileIntervalIndex--;
506 title = _(
"No valid GRIB file");
508 pPlugIn->GetGRIBOverlayFactory()->SetMessage(title);
510 SetTimeLineMax(
false);
512 if (
pPlugIn->GetStartOptions() &&
513 m_TimeLineHours != 0)
514 ComputeBestForecastForNow();
520 for (
int i = 1; i < 5; i++) {
525 m_HasAltitude =
true;
530#ifdef __OCPN__ANDROID__
531 m_bpSettings->Enable(
true);
537 m_sTimeline->Enable(
m_pTimelineSet !=
nullptr && m_TimeLineHours);
556 bool bconfigOK =
false;
557 if (m_bDataPlot[GribOverlaySettings::WIND] &&
560 if (m_bDataPlot[GribOverlaySettings::WIND_GUST] &&
563 if (m_bDataPlot[GribOverlaySettings::PRESSURE] &&
566 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
569 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
572 if (m_bDataPlot[GribOverlaySettings::CURRENT] &&
576 if (m_bDataPlot[GribOverlaySettings::PRECIPITATION] &&
579 if (m_bDataPlot[GribOverlaySettings::CLOUD] &&
582 if (m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE] &&
585 if (m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE] &&
588 if (m_bDataPlot[GribOverlaySettings::CAPE] &&
591 if (m_bDataPlot[GribOverlaySettings::COMP_REFL] &&
598 for (
int i = 0; i < (int)GribOverlaySettings::GEO_ALTITUDE; i++) {
600 m_bDataPlot[i] =
true;
607 double *latmin,
double *latmax,
608 double *lonmin,
double *lonmax) {
611 double ltmi = -GRIB_NOTDEF, ltma = GRIB_NOTDEF, lnmi = -GRIB_NOTDEF,
613 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
616 if (pGRA->getLatMin() < ltmi) ltmi = pGRA->getLatMin();
617 if (pGRA->getLatMax() > ltma) ltma = pGRA->getLatMax();
618 if (pGRA->getLonMin() < lnmi) lnmi = pGRA->getLonMin();
619 if (pGRA->getLonMax() > lnma) lnma = pGRA->getLonMax();
621 if (ltmi == -GRIB_NOTDEF || lnmi == -GRIB_NOTDEF || ltma == GRIB_NOTDEF ||
625 if (latmin) *latmin = ltmi;
626 if (latmax) *latmax = ltma;
627 if (lonmin) *lonmin = lnmi;
628 if (lonmax) *lonmax = lnma;
635 : m_files(files), m_pattern(pattern) {}
636 virtual wxDirTraverseResult OnFile(
const wxString &filename) {
637 if (m_pattern.Matches(filename)) m_files.Add(filename);
638 return wxDIR_CONTINUE;
640 virtual wxDirTraverseResult OnDir(
const wxString &WXUNUSED(dirname)) {
645 wxArrayString &m_files;
646 const wxRegEx &m_pattern;
649wxArrayString GRIBUICtrlBar::GetFilesInDirectory() {
650 wxArrayString file_array;
651 if (!wxDir::Exists(
m_grib_dir))
return file_array;
655 wxRegEx pattern(_T(
".+\\.gri?b2?(\\.(bz2|gz))?$"),
656 wxRE_EXTENDED | wxRE_ICASE | wxRE_NOSUB);
659 dir.Traverse(collector);
661 CompareFileStringTime);
665void GRIBUICtrlBar::SetCursorLatLon(
double lat,
double lon) {
669 if (m_vpMouse && ((lat > m_vpMouse->
lat_min) && (lat < m_vpMouse->lat_max)) &&
670 ((lon > m_vpMouse->
lon_min) && (lon < m_vpMouse->lon_max)))
675 if (!m_CDataIsShown)
return;
677 if (m_DialogStyle >> 1 == SEPARATED) {
678 if (m_gGRIBUICData) {
679 if (!m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.IsRunning())
680 m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.Start(
681 50, wxTIMER_ONE_SHOT);
685 if (!m_gCursorData->m_tCursorTrackTimer.IsRunning())
686 m_gCursorData->m_tCursorTrackTimer.Start(50, wxTIMER_ONE_SHOT);
691void GRIBUICtrlBar::OnShowCursorData(wxCommandEvent &event) {
692 m_CDataIsShown = !m_CDataIsShown;
693 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(
694 wxBitmap(m_CDataIsShown ? curdata : ncurdata),
695 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"), m_ScaledFactor));
696 SetDialogsStyleSizePosition(
true);
699void GRIBUICtrlBar::SetDialogsStyleSizePosition(
bool force_recompute) {
704 if (!force_recompute &&
705 (m_old_DialogStyle == m_DialogStyle
707 (m_old_DialogStyle >> 1 == ATTACHED && m_DialogStyle >> 1 == ATTACHED)))
710 bool m_HasCaption = GetWindowStyleFlag() == (wxCAPTION |
wxCLOSE_BOX |
711 wxSYSTEM_MENU | wxTAB_TRAVERSAL);
716 int state = (m_DialogStyle >> 1 == ATTACHED && m_CDataIsShown) ? 0 : 1;
719 bool vis = i > 0 ? true : m_HasAltitude ? true :
false;
720 if (FindWindow(i + ID_CTRLALTITUDE))
721 FindWindow(i + ID_CTRLALTITUDE)
727 m_bpShowCursorData->SetToolTip(m_CDataIsShown ? _(
"Hide data at cursor")
728 : _(
"Show data at cursor"));
729 m_bpPlay->SetToolTip(_(
"Start play back"));
734 m_gCursorData->Hide();
735 m_fgCDataSizer->Detach(m_gCursorData);
738 SetMinSize(wxSize(0, 0));
742 if (m_gGRIBUICData) {
743 m_gGRIBUICData->Destroy();
744 m_gGRIBUICData =
nullptr;
747 if ((m_DialogStyle >> 1 == SEPARATED || !m_CDataIsShown) &&
754 if (m_CDataIsShown) {
755 if (m_DialogStyle >> 1 == ATTACHED) {
757 if (!m_gCursorData) m_gCursorData =
new CursorData(
this, *
this);
758 pPlugIn->SetDialogFont(m_gCursorData);
759 m_gCursorData->PopulateTrackingControls(
false);
761 if (m_fgCDataSizer->GetItem(m_gCursorData) ==
nullptr)
762 m_fgCDataSizer->Add(m_gCursorData, 0);
763 m_gCursorData->Show();
765 }
else if (m_DialogStyle >> 1 == SEPARATED) {
768 m_gGRIBUICData->m_gCursorData->PopulateTrackingControls(
769 m_DialogStyle == SEPARATED_VERTICAL);
770 pPlugIn->SetDialogFont(m_gGRIBUICData->m_gCursorData);
771 m_gGRIBUICData->Fit();
772 m_gGRIBUICData->Update();
773 m_gGRIBUICData->Show();
775 m_gGRIBUICData->Layout();
776 m_gGRIBUICData->Fit();
781 wxSize sd = GetSize();
783 if (!m_gtk_started && m_HasCaption ) {
785 m_gtk_started =
true;
788 SetSize(wxSize(sd.x, sd.y));
789 SetMinSize(wxSize(sd.x, sd.y));
790#ifdef __OCPN__ANDROID__
796 wxPoint pNew =
pPlugIn->GetCtrlBarXY();
797 pNew.x = tbRect.x + tbRect.width + 4;
805 if (sd.x > widthAvail) {
808 int target_char_width = (float)widthAvail / 28;
817 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
819 dc.GetTextExtent(_T(
"W"), &width, &height,
nullptr,
nullptr, sFont);
820 if (width <= target_char_width) bOK =
true;
822 if (pointSize <= 10) bOK =
true;
825 m_cRecordForecast->SetFont(*sFont);
830 SetSize(wxSize(widthAvail, sd.y));
831 SetMinSize(wxSize(widthAvail, sd.y));
835 wxPoint pNow =
pPlugIn->GetCtrlBarXY();
842 m_old_DialogStyle = m_DialogStyle;
845void GRIBUICtrlBar::OnAltitude(wxCommandEvent &event) {
846 if (!m_HasAltitude)
return;
848 wxMenu *amenu =
new wxMenu();
849 amenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
850 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
this);
852 for (
int i = 0; i < 5; i++) {
860 amenu, ID_CTRLALTITUDE + 1000 + i,
869 amenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
876void GRIBUICtrlBar::OnMove(wxMoveEvent &event) {
878 GetScreenPosition(&w, &h);
879 pPlugIn->SetCtrlBarXY(wxPoint(w, h));
882void GRIBUICtrlBar::OnMenuEvent(wxMenuEvent &event) {
883 int id =
event.GetId();
886 int alt = m_Altitude;
889 case ID_CTRLALTITUDE + 1000:
892 case ID_CTRLALTITUDE + 1001:
895 case ID_CTRLALTITUDE + 1002:
898 case ID_CTRLALTITUDE + 1003:
901 case ID_CTRLALTITUDE + 1004:
909 OnZoomToCenterClick(evt);
911 case ID_BTNSHOWCDATA:
912 OnShowCursorData(evt);
924 OnRequestForecastData(evt);
926 if (alt != m_Altitude) {
927 SetDialogsStyleSizePosition(
true);
932void GRIBUICtrlBar::MenuAppend(wxMenu *menu,
int id, wxString label,
933 wxItemKind kind, wxBitmap bitmap,
935 wxMenuItem *item =
new wxMenuItem(menu,
id, label, _T(
""), kind);
938 item->SetSubMenu(submenu);
948#if defined(__WXMSW__) || defined(__WXGTK__)
949 if (!bitmap.IsSameAs(wxNullBitmap)) item->SetBitmap(bitmap);
955void GRIBUICtrlBar::OnMouseEvent(wxMouseEvent &event) {
956 if (event.RightDown()) {
958 wxMenu *xmenu =
new wxMenu();
959 xmenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
960 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
964 wxMenu *smenu =
new wxMenu();
965 smenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
966 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
969 for (
int i = 0; i < 5; i++) {
977 smenu, ID_CTRLALTITUDE + 1000 + i,
984 smenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
986 xmenu, wxID_ANY, _(
"Select geopotential altitude"), wxITEM_NORMAL,
987 GetScaledBitmap(wxBitmap(altitude), _T(
"altitude"), m_ScaledFactor),
990 MenuAppend(xmenu, ID_BTNNOW, _(
"Now"), wxITEM_NORMAL,
991 GetScaledBitmap(wxBitmap(now), _T(
"now"), m_ScaledFactor));
992 MenuAppend(xmenu, ID_BTNZOOMTC, _(
"Zoom To Center"), wxITEM_NORMAL,
993 GetScaledBitmap(wxBitmap(zoomto), _T(
"zoomto"), m_ScaledFactor));
995 xmenu, ID_BTNSHOWCDATA,
996 m_CDataIsShown ? _(
"Hide data at cursor") : _(
"Show data at cursor"),
998 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
999 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"),
1003 m_tPlayStop.IsRunning() ? _(
"Stop play back") : _(
"Start play back"),
1005 GetScaledBitmap(wxBitmap(
m_tPlayStop.IsRunning() ? stop : play),
1006 m_tPlayStop.IsRunning() ? _T(
"stop") : _T(
"play"),
1009 xmenu, ID_BTNOPENFILE, _(
"Open a new file"), wxITEM_NORMAL,
1010 GetScaledBitmap(wxBitmap(openfile), _T(
"openfile"), m_ScaledFactor));
1012 xmenu, ID_BTNSETTING, _(
"Settings"), wxITEM_NORMAL,
1013 GetScaledBitmap(wxBitmap(setting), _T(
"setting"), m_ScaledFactor));
1019 requeststate1 ? _(
"Request forecast data")
1021 ? _(
"Draw requested Area or Click here to stop request")
1022 : _(
"Valid Area and Continue"),
1024 GetScaledBitmap(wxBitmap(requeststate1 ? request
1025 : requeststate3 ? selzone
1027 requeststate1 ? _T(
"request")
1028 : requeststate3 ? _T(
"selzone")
1029 : _T(
"request_end"),
1039 if (m_DialogStyle >> 1 == SEPARATED)
return;
1040 wxMouseEvent evt(event);
1043#ifndef __OCPN__ANDROID__
1044 if (m_gCursorData && m_CDataIsShown) {
1045 m_gCursorData->OnMouseEvent(evt);
1050void GRIBUICtrlBar::ContextMenuItemCallback(
int id) {
1052 bool dataisshown = m_CDataIsShown;
1053 m_CDataIsShown =
false;
1066 m_CDataIsShown = dataisshown;
1071 if (m_vpMouse == vp)
return;
1083void GRIBUICtrlBar::OnClose(wxCloseEvent &event) {
1085 if (m_gGRIBUICData) m_gGRIBUICData->Hide();
1088 pReq_Dialog->StopGraphicalZoneSelection();
1092 pPlugIn->SendTimelineMessage(wxInvalidDateTime);
1094 pPlugIn->OnGribCtrlBarClose();
1097void GRIBUICtrlBar::OnSize(wxSizeEvent &event) {
1099 wxSize p =
event.GetSize();
1105void GRIBUICtrlBar::OnPaint(wxPaintEvent &event) {
1106 wxWindowListNode *node = this->GetChildren().GetFirst();
1109 wxWindow *win = node->GetData();
1110 if (
dynamic_cast<wxBitmapButton *
>(win))
1111 dc.DrawBitmap(
dynamic_cast<wxBitmapButton *
>(win)->GetBitmap(), 5, 5,
1113 node = node->GetNext();
1117void GRIBUICtrlBar::createRequestDialog() {
1118 ::wxBeginBusyCursor();
1123 pPlugIn->SetDialogFont(pReq_Dialog);
1124 pPlugIn->SetDialogFont(pReq_Dialog->m_sScrolledDialog);
1127 pReq_Dialog->SetRequestDialogSize();
1128 if (::wxIsBusy()) ::wxEndBusyCursor();
1131void GRIBUICtrlBar::OnRequestForecastData(wxCommandEvent &event) {
1136 if (pReq_Dialog && pReq_Dialog->IsShown())
return;
1139 createRequestDialog();
1142 ::wxDisplaySize(&w,
nullptr);
1143 pReq_Dialog->Move((w - pReq_Dialog->GetSize().GetX()) / 2, 30);
1144 pReq_Dialog->Show();
1149void GRIBUICtrlBar::OnSettings(wxCommandEvent &event) {
1153 ::wxBeginBusyCursor();
1159 pPlugIn->SetDialogFont(dialog);
1160 for (
size_t i = 0; i < dialog->m_nSettingsBook->GetPageCount(); i++) {
1161 wxScrolledWindow *sc =
1162 ((wxScrolledWindow *)dialog->m_nSettingsBook->GetPage(i));
1166 dialog->m_nSettingsBook->ChangeSelection(dialog->GetPageIndex());
1167 dialog->SetSettingsDialogSize();
1170 ::wxDisplaySize(&w,
nullptr);
1171 dialog->Move((w - dialog->GetSize().GetX()) / 2, 30);
1174 ::wxEndBusyCursor();
1176 if (dialog->ShowModal() == wxID_OK) {
1177 dialog->WriteSettings();
1180 initSettings.Settings[GribOverlaySettings::WIND].m_Units &&
1182 GribOverlaySettings::BFS ||
1183 initSettings.Settings[GribOverlaySettings::WIND].m_Units ==
1184 GribOverlaySettings::BFS))
1186 STARTING_STATE_STYLE;
1190 m_DialogStyle = initSettings.m_iCtrlandDataStyle;
1192 ::wxBeginBusyCursor();
1194 dialog->SaveLastPage();
1196 m_InterpolateMode =
false;
1197 SetTimeLineMax(
true);
1198 SetFactoryOptions();
1200 SetDialogsStyleSizePosition(
true);
1206#ifdef __OCPN__ANDROID__
1207wxString callActivityMethod_ss(
const char *method, wxString parm);
1210void GRIBUICtrlBar::OnCompositeDialog(wxCommandEvent &event) {
1213 initSettings.Read();
1216 wxString json_begin = initSettings.SettingsToJSON(json);
1217 wxLogMessage(json_begin);
1226 double lon_min = wxRound(current_vp.
lon_min) - 1;
1227 double lon_max = wxRound(current_vp.
lon_max) + 1;
1228 double lat_min = wxRound(current_vp.
lat_min) - 1;
1229 double lat_max = wxRound(current_vp.
lat_max) + 1;
1233 int numErrors = reader.
Parse(json_begin, &v);
1234 if (numErrors > 0) {
1238 v[_T(
"latMin")] = lat_min;
1239 v[_T(
"latMax")] = lat_max;
1240 v[_T(
"lonMin")] = lon_min;
1241 v[_T(
"lonMax")] = lon_max;
1245 v[_T(
"grib_file")] = _T(
"");
1248 wxString json_final;
1249 w.
Write(v, json_final);
1250 wxLogMessage(json_final);
1252#ifdef __OCPN__ANDROID__
1253 wxString ret = callActivityMethod_ss(
"doGRIBActivity", json_final);
1260void GRIBUICtrlBar::OpenFileFromJSON(wxString json) {
1266 int numErrors = reader.
Parse(json, &root);
1267 if (numErrors > 0) {
1271 wxString file = root[(_T(
"grib_file"))].AsString();
1273 if (file.Length() && wxFileExists(file)) {
1274 wxFileName fn(file);
1282void GRIBUICtrlBar::OnPlayStop(wxCommandEvent &event) {
1286 m_bpPlay->SetBitmapLabel(
1287 GetScaledBitmap(wxBitmap(stop), _T(
"stop"), m_ScaledFactor));
1288 m_bpPlay->SetToolTip(_(
"Stop play back"));
1290 wxTIMER_CONTINUOUS);
1295void GRIBUICtrlBar::OnPlayStopTimer(wxTimerEvent &event) {
1296 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax()) {
1299 ComputeBestForecastForNow();
1300 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax())
1304 m_sTimeline->SetValue(0);
1311 ? GetNearestValue(GetNow(), 1)
1312 : GetNearestIndex(GetNow(), 2)
1313 : m_sTimeline->GetValue();
1314 m_sTimeline->SetValue(value + 1);
1318 if (!m_InterpolateMode)
1319 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1323void GRIBUICtrlBar::StopPlayBack() {
1326 m_bpPlay->SetBitmapLabel(
1327 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
1328 m_bpPlay->SetToolTip(_(
"Start play back"));
1332void GRIBUICtrlBar::TimelineChanged() {
1334 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1338 RestaureSelectionString();
1344 if (!m_InterpolateMode) {
1347 GribRecordSet &sel = rsa->Item(m_cRecordForecast->GetCurrentSelection());
1350 ? wxTimeSpan(t - MinTime()).GetMinutes() /
1353 : m_cRecordForecast->GetCurrentSelection());
1355 m_cRecordForecast->SetSelection(GetNearestIndex(time, 2));
1356 SaveSelectionString();
1358 m_cRecordForecast->SetString(m_Selection_index,
1361 m_cRecordForecast->SetStringSelection(
1367 pPlugIn->SendTimelineMessage(time);
1371void GRIBUICtrlBar::RestaureSelectionString() {
1372 if (!m_SelectionIsSaved)
return;
1374 int sel = m_cRecordForecast->GetSelection();
1375 m_cRecordForecast->SetString(m_Selection_index, m_Selection_label);
1376 m_cRecordForecast->SetSelection(sel);
1377 m_SelectionIsSaved =
false;
1380int GRIBUICtrlBar::GetNearestIndex(wxDateTime time,
int model) {
1385 wxDateTime itime, ip1time;
1386 for (i = 0; i < rsa->GetCount() - 1; i++) {
1387 itime = rsa->Item(i).m_Reference_Time;
1388 ip1time = rsa->Item(i + 1).m_Reference_Time;
1389 if (ip1time >= time)
break;
1391 if (!model)
return (time - itime > (ip1time - time) * 3) ? i + 1 : i;
1393 return model == 1 ? time == ip1time ? i : i + 1 : time == ip1time ? i + 1 : i;
1396int GRIBUICtrlBar::GetNearestValue(wxDateTime time,
int model) {
1398 if (m_TimeLineHours == 0)
return 0;
1399 wxDateTime itime, ip1time;
1402 wxTimeSpan span = time - MinTime();
1403 int t = span.GetMinutes() / stepmin;
1405 wxTimeSpan(t * stepmin / 60, (t * stepmin) % 60);
1406 ip1time = itime + wxTimeSpan(stepmin / 60, stepmin % 60);
1408 if (model == 1)
return time == ip1time ? t + 1 : t;
1410 return (time - itime > (ip1time - time) * 3) ? t + 1 : t;
1413wxDateTime GRIBUICtrlBar::GetNow() {
1414 wxDateTime now = wxDateTime::Now();
1420 now = (now > rsa->Item(rsa->GetCount() - 1).m_Reference_Time)
1421 ? rsa->Item(rsa->GetCount() - 1).m_Reference_Time
1422 : (now < rsa->Item(0).m_Reference_Time) ? rsa->Item(0).m_Reference_Time
1428 if (m_InterpolateMode) {
1429 int tl = (m_TimeLineHours == 0) ? 0 : m_sTimeline->GetValue();
1432 return MinTime() + wxTimeSpan(tl * stepmin / 60, (tl * stepmin) % 60);
1436 unsigned int index = m_cRecordForecast->GetCurrentSelection() < 1
1438 : m_cRecordForecast->GetCurrentSelection();
1439 if (rsa && index < rsa->GetCount())
return rsa->Item(index).m_Reference_Time;
1441 return wxDateTime::Now();
1444wxDateTime GRIBUICtrlBar::MinTime() {
1446 if (rsa && rsa->GetCount()) {
1450 return wxDateTime::Now();
1457 if (rsa->GetCount() == 0)
return nullptr;
1464 wxDateTime GR1time, GR2time;
1470 for (j = 0; j < rsa->GetCount(); j++) {
1476 if (curtime <= time) GR1time = curtime, GRS1 = GRS, GR1 = GR;
1478 if (curtime >= time) {
1479 GR2time = curtime, GRS2 = GRS, GR2 = GR;
1484 if (!GR1 || !GR2)
continue;
1486 wxDateTime mintime = MinTime();
1487 double minute2 = (GR2time - mintime).GetMinutes();
1488 double minute1 = (GR1time - mintime).GetMinutes();
1489 double nminute = (time - mintime).GetMinutes();
1491 if (minute2 < minute1 || nminute < minute1 || nminute > minute2)
continue;
1493 double interp_const;
1494 if (minute1 == minute2) {
1499 interp_const = (nminute - minute1) / (minute2 - minute1);
1530 *GR1, *GR2, interp_const, i ==
Idx_WVDIR));
1541 auto sog = m_ProjectBoatPanel->GetSpeed();
1542 auto cog = m_ProjectBoatPanel->GetCourse();
1544 static_cast<double>(now.GetTicks() -
pPlugIn->m_boat_time) * sog / 3600.0;
1546 pPlugIn->m_boat_lon, cog, dist,
1547 &m_projected_lat, &m_projected_lon);
1555double GRIBUICtrlBar::getTimeInterpolatedValue(
int idx,
double lon,
double lat,
1560 if (rsa->GetCount() == 0)
return GRIB_NOTDEF;
1562 GribRecord *before =
nullptr, *after =
nullptr;
1565 time_t t = time.GetTicks();
1566 for (j = 0; j < rsa->GetCount(); j++) {
1571 time_t curtime = GR->getRecordCurrentDate();
1574 if (curtime < t) before = GR;
1582 if (!before || !after)
return GRIB_NOTDEF;
1584 time_t t1 = before->getRecordCurrentDate();
1585 time_t t2 = after->getRecordCurrentDate();
1589 double v2 = after->getInterpolatedValue(lon, lat);
1590 if (v1 != GRIB_NOTDEF && v2 != GRIB_NOTDEF) {
1591 double k = fabs((
double)(t - t1) / (t2 - t1));
1592 return (1.0 - k) * v1 + k * v2;
1598bool GRIBUICtrlBar::getTimeInterpolatedValues(
double &M,
double &A,
int idx1,
1599 int idx2,
double lon,
double lat,
1607 if (rsa->GetCount() == 0)
return false;
1609 GribRecord *beforeX =
nullptr, *afterX =
nullptr;
1610 GribRecord *beforeY =
nullptr, *afterY =
nullptr;
1613 time_t t = time.GetTicks();
1614 for (j = 0; j < rsa->GetCount(); j++) {
1618 if (!GX || !GY)
continue;
1620 time_t curtime = GX->getRecordCurrentDate();
1635 if (!beforeX || !afterX)
return false;
1637 time_t t1 = beforeX->getRecordCurrentDate();
1638 time_t t2 = afterX->getRecordCurrentDate();
1643 double v1m, v2m, v1a, v2a;
1652 if (v1m == GRIB_NOTDEF || v2m == GRIB_NOTDEF || v1a == GRIB_NOTDEF ||
1656 double k = fabs((
double)(t - t1) / (t2 - t1));
1657 M = (1.0 - k) * v1m + k * v2m;
1658 A = (1.0 - k) * v1a + k * v2a;
1662void GRIBUICtrlBar::OnTimeline(wxScrollEvent &event) {
1665 if (!m_InterpolateMode)
1666 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1671void GRIBUICtrlBar::OnOpenFile(wxCommandEvent &event) {
1675#ifndef __OCPN__ANDROID__
1677 wxStandardPathsBase &path = wxStandardPaths::Get();
1678 wxString l_grib_dir = path.GetDocumentsDir();
1682 wxFileDialog *dialog =
1683 new wxFileDialog(
nullptr, _(
"Select a GRIB file"), l_grib_dir, _T(
""),
1685 "(*.grb;*.bz2;*.gz;*.grib2;*.grb2)|*.grb;*.bz2;*.gz;"
1686 "*.grib2;*.grb2|All files (*)|*.*"),
1687 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE,
1688 wxDefaultPosition, wxDefaultSize, _T(
"File Dialog"));
1690 if (dialog->ShowModal() == wxID_OK) {
1691 ::wxBeginBusyCursor();
1697 if (g_pi->m_bZoomToCenterAtInit) DoZoomToCenter();
1699 SetDialogsStyleSizePosition(
true);
1704 wxStandardPathsBase &path = wxStandardPaths::Get();
1710 nullptr, &file, _(
"Select a GRIB file"),
m_grib_dir, _T(
""), _T(
"*.*"));
1712 if (response == wxID_OK) {
1713 wxFileName fn(file);
1718 SetDialogsStyleSizePosition(
true);
1723void GRIBUICtrlBar::CreateActiveFileFromNames(
const wxArrayString &filenames) {
1724 if (filenames.GetCount() != 0) {
1731void GRIBUICtrlBar::PopulateComboDataList() {
1733 if (m_cRecordForecast->GetCount()) {
1734 index = m_cRecordForecast->GetCurrentSelection();
1735 m_cRecordForecast->Clear();
1739 for (
size_t i = 0; i < rsa->GetCount(); i++) {
1740 wxDateTime t(rsa->Item(i).m_Reference_Time);
1743 m_cRecordForecast->SetSelection(index);
1746void GRIBUICtrlBar::OnZoomToCenterClick(wxCommandEvent &event) {
1751 double latmin,latmax,lonmin,lonmax;
1752 if(!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax ))
1758 double width = lonmax - lonmin;
1759 double height = latmax - latmin;
1762 double clat = latmin + height / 2;
1763 double clon = lonmin + width / 2;
1767 lonmin = clon - 60.;
1768 lonmax = clon + 60.;
1771 latmin = clat - 60.;
1772 latmax = clat + 60.;
1782 int w =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetWidth();
1783 int h =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetHeight();
1787 ppm = wxMin(w/(ow*1852), h/(oh*1852)) * ( 100 - fabs( clat ) ) / 90;
1789 ppm = wxMin(ppm, 1.0);
1797void GRIBUICtrlBar::DoZoomToCenter() {
1800 double latmin, latmax, lonmin, lonmax;
1801 if (!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax))
1807 double width = lonmax - lonmin;
1808 double height = latmax - latmin;
1811 double clat = latmin + height / 2;
1812 double clon = lonmin + width / 2;
1816 lonmin = clon - 60.;
1817 lonmax = clon + 60.;
1819 if (height > 120.) {
1820 latmin = clat - 60.;
1821 latmax = clat + 60.;
1829 wxWindow *wx = GetGRIBCanvas();
1831 int w = wx->GetSize().x;
1832 int h = wx->GetSize().y;
1836 ppm = wxMin(w / (ow * 1852), h / (oh * 1852)) * (100 - fabs(clat)) / 90;
1838 ppm = wxMin(ppm, 1.0);
1843void GRIBUICtrlBar::OnPrev(wxCommandEvent &event) {
1847 RestaureSelectionString();
1851 selection = GetNearestIndex(GetNow(), 1);
1852 else if (m_InterpolateMode)
1856 selection = m_cRecordForecast->GetCurrentSelection();
1859 m_InterpolateMode =
false;
1861 m_cRecordForecast->SetSelection(selection < 1 ? 0 : selection - 1);
1866void GRIBUICtrlBar::OnNext(wxCommandEvent &event) {
1870 RestaureSelectionString();
1874 selection = GetNearestIndex(GetNow(), 2);
1875 else if (m_InterpolateMode)
1879 selection = m_cRecordForecast->GetCurrentSelection();
1881 m_cRecordForecast->SetSelection(selection);
1884 m_InterpolateMode =
false;
1886 if (selection == (
int)m_cRecordForecast->GetCount() - 1)
1889 m_cRecordForecast->SetSelection(selection + 1);
1894void GRIBUICtrlBar::ComputeBestForecastForNow() {
1896 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1900 wxDateTime now = GetNow();
1903 m_sTimeline->SetValue(GetNearestValue(now, 0));
1905 m_cRecordForecast->SetSelection(GetNearestIndex(now, 0));
1906 m_sTimeline->SetValue(m_cRecordForecast->GetCurrentSelection());
1909 if (
pPlugIn->GetStartOptions() !=
1916 m_InterpolateMode =
true;
1918 SetGribTimelineRecordSet(
1921 RestaureSelectionString();
1923 m_cRecordForecast->SetSelection(GetNearestIndex(now, 2));
1924 SaveSelectionString();
1926 m_cRecordForecast->SetString(m_Selection_index,
1929 m_cRecordForecast->SetStringSelection(nowTime);
1933 pPlugIn->SendTimelineMessage(now);
1937void GRIBUICtrlBar::SetGribTimelineRecordSet(
1942 if (!
pPlugIn->GetGRIBOverlayFactory())
return;
1947void GRIBUICtrlBar::SetTimeLineMax(
bool SetValue) {
1948 int oldmax = wxMax(m_sTimeline->GetMax(), 1),
1949 oldval = m_sTimeline->GetValue();
1954 m_sTimeline->SetMax(m_TimeLineHours * 60 / stepmin);
1958 m_sTimeline->SetMax(rsa->GetCount() - 1);
1963 if (SetValue && m_sTimeline->GetMax() != 0) {
1965 ComputeBestForecastForNow();
1967 m_sTimeline->SetValue(m_sTimeline->GetMax() * oldval / oldmax);
1971void GRIBUICtrlBar::SetFactoryOptions() {
1974 pPlugIn->GetGRIBOverlayFactory()->ClearCachedData();
1980void GRIBUICtrlBar::OnFormatRefreshTimer(wxTimerEvent &event) {
1983 wxDateTime referenceDate(1, wxDateTime::Jan, 2021, 12, 0, 0);
1986 if (currentFormat != m_sLastTimeFormat) {
1988 m_sLastTimeFormat = currentFormat;
1992 PopulateComboDataList();
2006unsigned int GRIBFile::ID = 0;
2012 m_pGribReader =
nullptr;
2013 m_last_message = wxEmptyString;
2014 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
2015 wxString file_name = file_names[i];
2016 if (::wxFileExists(file_name)) m_bOK =
true;
2019 if (m_bOK ==
false) {
2020 m_last_message = _(
" files don't exist!");
2029 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
2030 file_name = file_names[i];
2031 m_pGribReader->openFile(file_name);
2033 if (m_pGribReader->isOk()) {
2040 if (m_bOK ==
false) {
2041 m_last_message = _(
" can't be read!");
2046 m_FileNames.Clear();
2047 m_FileNames.Add(file_name);
2049 m_FileNames = file_names;
2053 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_TOT, LV_GND_SURF, 0);
2054 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_RATE, LV_GND_SURF, 0);
2055 m_pGribReader->computeAccumulationRecords(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
2063 m_nGribRecords = m_pGribReader->getTotalNumberOfGribRecords();
2067 std::set<time_t>::iterator iter;
2068 std::set<time_t> date_list = m_pGribReader->getListDates();
2069 for (iter = date_list.begin(); iter != date_list.end(); iter++) {
2071 time_t reftime = *iter;
2073 m_GribRecordSetArray.Add(t);
2081 bool polarWind(
false);
2082 bool polarCurrent(
false);
2083 bool sigWave(
false);
2086 std::map<std::string, std::vector<GribRecord *> *> *p_map =
2087 m_pGribReader->getGribMap();
2090 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
2091 for (it = p_map->begin(); it != p_map->end(); it++) {
2092 std::vector<GribRecord *> *ls = (*it).second;
2093 for (zuint i = 0; i < ls->size(); i++) {
2096 time_t thistime = pRec->getRecordCurrentDate();
2099 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2100 if (m_GribRecordSetArray.Item(j).m_Reference_Time == thistime) {
2101 int idx = -1, mdx = -1;
2125 case GRB_WIND_SPEED:
2148 polarCurrent =
true;
2154 polarCurrent =
true;
2186 case GRB_PRECIP_RATE:
2187 case GRB_PRECIP_TOT:
2212 mdx = 1000 + NORWAY_METNO;
2242 case GRB_GEOPOT_HGT:
2268 if (m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx]) {
2271 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2293 if (oRec->
getDataType() == GRB_HTSGW) skip =
true;
2303 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx] = pRec;
2304 if (m_GribIdxArray.Index(idx) == wxNOT_FOUND)
2305 m_GribIdxArray.Add(idx, 1);
2306 if (mdx != -1 && m_GribIdxArray.Index(mdx) == wxNOT_FOUND)
2307 m_GribIdxArray.Add(mdx, 1);
2315 if (polarWind || polarCurrent) {
2316 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2317 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
2321 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2323 if (pRec !=
nullptr && pRec->
getDataType() == GRB_WIND_DIR) {
2345 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2346 if (pRec1 !=
nullptr && pRec1->
getDataType() == GRB_WIND_SPEED)
2354 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2356 if (pRec !=
nullptr && pRec->
getDataType() == GRB_CUR_DIR) {
2366 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2367 if (pRec1 !=
nullptr && pRec1->
getDataType() == GRB_CUR_SPEED)
2378 pRec->getRecordRefDate();
2381GRIBFile::~GRIBFile() {
delete m_pGribReader; }
2388 :
GRIBUICDataBase(parent.pParent, CURSOR_DATA, _(
"GRIB Display Control"),
2389 wxDefaultPosition, wxDefaultSize,
2390 wxSYSTEM_MENU | wxNO_BORDER | wxSTAY_ON_TOP)
2393 wxDefaultPosition, wxDefaultSize,
2394 wxSYSTEM_MENU | wxNO_BORDER)
2397 m_gpparent(parent) {
2401 m_gCursorData =
new CursorData(
this, m_gpparent);
2402 m_fgCdataSizer->Add(m_gCursorData, 0, wxALL, 0);
2404 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICData::OnMove));
2407void GRIBUICData::OnMove(wxMoveEvent &event) {
2409 GetScreenPosition(&w, &h);
2410 m_gpparent.
pPlugIn->SetCursorDataXY(wxPoint(w, h));
2416#ifdef __OCPN__ANDROID__
2418#include <QtAndroidExtras/QAndroidJniObject>
2420bool CheckPendingJNIException() {
2427 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2432 if ((jenv)->ExceptionCheck() == JNI_TRUE) {
2440wxString callActivityMethod_ss(
const char *method, wxString parm) {
2446 if (CheckPendingJNIException())
return _T(
"NOK");
2448 wxString return_string;
2449 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2450 "org/qtproject/qt5/android/QtNative",
"activity",
2451 "()Landroid/app/Activity;");
2452 if (CheckPendingJNIException())
return _T(
"NOK");
2454 if (!activity.isValid()) {
2456 return return_string;
2461 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2463 return "jenv Error";
2466 jstring p = (jenv)->NewStringUTF(parm.c_str());
2472 QAndroidJniObject data = activity.callObjectMethod(
2473 method,
"(Ljava/lang/String;)Ljava/lang/String;", p);
2474 if (CheckPendingJNIException())
return _T(
"NOK");
2478 jstring s = data.object<jstring>();
2480 if ((jenv)->GetStringLength(s)) {
2481 const char *ret_string = (jenv)->GetStringUTFChars(s,
nullptr);
2482 return_string = wxString(ret_string, wxConvUTF8);
2485 return return_string;
@ Idx_AIR_TEMP850
Air temperature at 850 hPa in Kelvin (K)
@ Idx_COMP_REFL
Composite radar reflectivity in dBZ (decibel relative to Z)
@ Idx_PRECIP_TOT
Precipitation data in millimeters per hour.
@ Idx_AIR_TEMP
Air temperature at 2m in Kelvin (K)
@ Idx_PRESSURE
Surface pressure in Pascal (Pa)
@ Idx_WVDIR
Wave direction.
@ Idx_HUMID_RE850
Relative humidity at 850 hPa in % (percent, range 0-100%)
@ Idx_CLOUD_TOT
Total cloud cover in % (percent, range 0-100%)
@ Idx_WIND_GUST
Wind gust speed at surface in m/s.
@ Idx_WIND_VX
Surface wind velocity X component in m/s.
@ Idx_AIR_TEMP300
Air temperature at 300 hPa in Kelvin (K)
@ Idx_COUNT
Number of supported GRIB record types.
@ Idx_WIND_VY850
Wind velocity Y component at 850 hPa in m/s.
@ Idx_HUMID_RE500
Relative humidity at 500 hPa in % (percent, range 0-100%)
@ Idx_WIND_VX300
Wind velocity X component at 300 hPa in m/s.
@ Idx_HUMID_RE300
Relative humidity at 300 hPa in % (percent, range 0-100%)
@ Idx_WIND_VX850
Wind velocity X component at 850 hPa in m/s.
@ Idx_WIND_VY300
Wind velocity Y component at 300 hPa in m/s.
@ Idx_WIND_VX700
Wind velocity X component at 700 hPa in m/s.
@ Idx_HTSIGW
Significant wave height in meters.
@ Idx_AIR_TEMP700
Air temperature at 700 hPa in Kelvin (K)
@ Idx_WIND_VY500
Wind velocity Y component at 500 hPa in m/s.
@ Idx_GEOP_HGT500
Geopotential height at 500 hPa in gpm (geopotential meters)
@ Idx_SEACURRENT_VY
Sea current velocity Y component in m/s.
@ Idx_WIND_VX500
Wind velocity X component at 500 hPa in m/s.
@ Idx_GEOP_HGT300
Geopotential height at 300 hPa in gpm (geopotential meters)
@ Idx_GEOP_HGT700
Geopotential height at 700 hPa in gpm (geopotential meters)
@ Idx_WIND_VY700
Wind velocity Y component at 700 hPa in m/s.
@ Idx_SEA_TEMP
Sea surface temperature in Kelvin (K)
@ Idx_WIND_VY
Surface wind velocity Y component in m/s.
@ Idx_GEOP_HGT850
Geopotential height at 850 hPa in gpm (geopotential meters)
@ Idx_SEACURRENT_VX
Sea current velocity X component in m/s.
@ Idx_AIR_TEMP500
Air temperature at 500 hPa in Kelvin (K)
@ Idx_HUMID_RE700
Relative humidity at 700 hPa in % (percent, range 0-100%)
@ Idx_CAPE
Convective Available Potential Energy in J/kg (Joules per kilogram)
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(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.
wxFileConfig * GetOCPNConfigObject()
Gets OpenCPN's configuration object.
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 starting 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.
void DistanceBearingMercator_Plugin(double lat0, double lon0, double lat1, double lon1, double *brg, double *dist)
Calculates bearing and distance between two points using Mercator projection.
OpenGL Platform Abstraction Layer.
wxString toUsrDateTimeFormat_Plugin(const wxDateTime date_time, const DateTimeFormatOptions &options)
Format a date/time to a localized string representation, conforming to the global date/time format an...