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>
43#include "jsonwriter.h"
50#include <wx/arrimpl.cpp>
53#include "android_jvm.h"
57double m_cursor_lat, m_cursor_lon;
93 return ((x - i) >= 0.5) ? (i + 1) : (i);
95 return (-x + i >= 0.5) ? (i - 1) : (i);
105#if wxCHECK_VERSION(2, 9, 4)
106#define SetBitmapLabelLabel SetBitmap
109#define DEFAULT_STYLE \
110 = wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL
112WX_DEFINE_OBJARRAY(ArrayOfGribRecordSets);
115static int CompareFileStringTime(
const wxString &first,
116 const wxString &second) {
118 wxFileName s(second);
119 wxTimeSpan sp = s.GetModificationTime() - f.GetModificationTime();
120 return sp.GetMinutes();
126wxWindow *GetGRIBCanvas() {
149GribTimelineRecordSet::~GribTimelineRecordSet() {
154void GribTimelineRecordSet::ClearCachedData() {
158 for (
unsigned int j = 0; j <
m_IsobarArray[i]->GetCount(); j++) {
172GRIBUICtrlBar::GRIBUICtrlBar(wxWindow *parent, wxWindowID
id,
173 const wxString &title,
const wxPoint &pos,
174 const wxSize &size,
long style,
GribPi *ppi,
182 pReq_Dialog =
nullptr;
183 m_bGRIBActiveFile =
nullptr;
184 m_pTimelineSet =
nullptr;
185 m_gCursorData =
nullptr;
186 m_gGRIBUICData =
nullptr;
187 m_gtk_started =
false;
192 m_fgCtrlGrabberSize->Add(m_gGrabber, 0, wxALL, 0);
194 this->SetSizer(m_fgCtrlBarSizer);
196 m_fgCtrlBarSizer->Fit(
this);
199 m_tFormatRefresh.Connect(
200 wxEVT_TIMER, wxTimerEventHandler(GRIBUICtrlBar::OnFormatRefreshTimer),
205 wxDateTime referenceDate(1, wxDateTime::Jan, 2021, 12, 0, 0);
209 m_tFormatRefresh.Start(5000);
212 pConf->SetPath(
"/Settings/GRIB");
213 pConf->Read(
"WindPlot", &m_bDataPlot[GribOverlaySettings::WIND],
true);
214 pConf->Read(
"WindGustPlot", &m_bDataPlot[GribOverlaySettings::WIND_GUST],
216 pConf->Read(
"PressurePlot", &m_bDataPlot[GribOverlaySettings::PRESSURE],
218 pConf->Read(
"WavePlot", &m_bDataPlot[GribOverlaySettings::WAVE],
false);
219 pConf->Read(
"CurrentPlot", &m_bDataPlot[GribOverlaySettings::CURRENT],
221 pConf->Read(
"PrecipitationPlot",
222 &m_bDataPlot[GribOverlaySettings::PRECIPITATION],
false);
223 pConf->Read(
"CloudPlot", &m_bDataPlot[GribOverlaySettings::CLOUD],
false);
224 pConf->Read(
"AirTemperaturePlot",
225 &m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE],
false);
226 pConf->Read(
"SeaTemperaturePlot",
227 &m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE],
false);
228 pConf->Read(
"CAPEPlot", &m_bDataPlot[GribOverlaySettings::CAPE],
false);
229 pConf->Read(
"CompReflectivityPlot",
230 &m_bDataPlot[GribOverlaySettings::COMP_REFL],
false);
232 pConf->Read(
"CursorDataShown", &m_CDataIsShown,
true);
234 pConf->Read(
"lastdatatype", &m_lastdatatype, 0);
236 pConf->SetPath(
"/Settings/GRIB/FileNames");
237 m_file_names.Clear();
238 if (pConf->GetNumberOfEntries()) {
241 bool bCont = pConf->GetFirstEntry(str, dummy);
243 pConf->Read(str, &val);
244 m_file_names.Add(val);
245 bCont = pConf->GetNextEntry(str, dummy);
249 wxStandardPathsBase &spath = wxStandardPaths::Get();
251 pConf->SetPath(
"/Directories");
252 pConf->Read(
"GRIBDirectory", &m_grib_dir);
254 pConf->SetPath(
"/PlugIns/GRIB");
258 pConf->SetPath(
"/Settings/GRIB/XyGrib");
259 pConf->Read(
"AtmModelIndex", &xyGribConfig.atmModelIndex, 0);
260 pConf->Read(
"WaveModelIndex", &xyGribConfig.waveModelIndex, 0);
261 pConf->Read(
"ResolutionIndex", &xyGribConfig.resolutionIndex, 0);
262 pConf->Read(
"DurationIndex", &xyGribConfig.durationIndex, 0);
263 pConf->Read(
"RunIndex", &xyGribConfig.runIndex, 0);
264 pConf->Read(
"IntervalIndex", &xyGribConfig.intervalIndex, 0);
265 pConf->Read(
"Wind", &xyGribConfig.wind,
true);
266 pConf->Read(
"Gust", &xyGribConfig.gust,
true);
267 pConf->Read(
"Pressure", &xyGribConfig.pressure,
false);
268 pConf->Read(
"Temperature", &xyGribConfig.temperature,
true);
269 pConf->Read(
"Cape", &xyGribConfig.cape,
false);
270 pConf->Read(
"Reflectivity", &xyGribConfig.reflectivity,
false);
271 pConf->Read(
"CloudCover", &xyGribConfig.cloudCover,
true);
272 pConf->Read(
"Precipitation", &xyGribConfig.precipitation,
true);
273 pConf->Read(
"WaveHeight", &xyGribConfig.waveHeight,
true);
274 pConf->Read(
"WindWaves", &xyGribConfig.windWaves,
true);
280 m_tPlayStop.Connect(wxEVT_TIMER,
281 wxTimerEventHandler(GRIBUICtrlBar::OnPlayStopTimer),
284 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICtrlBar::OnMove));
286 m_OverlaySettings.Read();
291 SetMinSize(GetBestSize());
292 if (m_ProjectBoatPanel) {
293 m_ProjectBoatPanel->SetSpeed(pPlugIn->m_boat_sog);
294 m_ProjectBoatPanel->SetCourse(pPlugIn->m_boat_cog);
296 m_highlight_latmax = 0;
297 m_highlight_lonmax = 0;
298 m_highlight_latmin = 0;
299 m_highlight_lonmin = 0;
307 createRequestDialog();
311GRIBUICtrlBar::~GRIBUICtrlBar() {
316 pConf->SetPath(
"/Settings/GRIB");
317 pConf->Write(
"WindPlot", m_bDataPlot[GribOverlaySettings::WIND]);
318 pConf->Write(
"WindGustPlot", m_bDataPlot[GribOverlaySettings::WIND_GUST]);
319 pConf->Write(
"PressurePlot", m_bDataPlot[GribOverlaySettings::PRESSURE]);
320 pConf->Write(
"WavePlot", m_bDataPlot[GribOverlaySettings::WAVE]);
321 pConf->Write(
"CurrentPlot", m_bDataPlot[GribOverlaySettings::CURRENT]);
322 pConf->Write(
"PrecipitationPlot",
323 m_bDataPlot[GribOverlaySettings::PRECIPITATION]);
324 pConf->Write(
"CloudPlot", m_bDataPlot[GribOverlaySettings::CLOUD]);
325 pConf->Write(
"AirTemperaturePlot",
326 m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE]);
327 pConf->Write(
"SeaTemperaturePlot",
328 m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE]);
329 pConf->Write(
"CAPEPlot", m_bDataPlot[GribOverlaySettings::CAPE]);
330 pConf->Write(
"CompReflectivityPlot",
331 m_bDataPlot[GribOverlaySettings::COMP_REFL]);
333 pConf->Write(
"CursorDataShown", m_CDataIsShown);
335 pConf->Write(
"lastdatatype", m_lastdatatype);
337 pConf->SetPath(
"/Settings/GRIB/FileNames");
338 int iFileMax = pConf->GetNumberOfEntries();
342 for (
int i = 0; i < iFileMax; i++) {
343 if (pConf->GetFirstEntry(key, dummy)) pConf->DeleteEntry(key,
false);
347 for (
unsigned int i = 0; i <
m_file_names.GetCount(); i++) {
349 key.Printf(
"Filename%d", i);
353 pConf->SetPath(
"/Directories");
357 pConf->SetPath(
"/Settings/GRIB/XyGrib");
358 pConf->Write(
"AtmModelIndex", xyGribConfig.atmModelIndex);
359 pConf->Write(
"WaveModelIndex", xyGribConfig.waveModelIndex);
360 pConf->Write(
"ResolutionIndex", xyGribConfig.resolutionIndex);
361 pConf->Write(
"DurationIndex", xyGribConfig.durationIndex);
362 pConf->Write(
"RunIndex", xyGribConfig.runIndex);
363 pConf->Write(
"IntervalIndex", xyGribConfig.intervalIndex);
364 pConf->Write(
"Wind", xyGribConfig.wind);
365 pConf->Write(
"Gust", xyGribConfig.gust);
366 pConf->Write(
"Pressure", xyGribConfig.pressure);
367 pConf->Write(
"Temperature", xyGribConfig.temperature);
368 pConf->Write(
"Cape", xyGribConfig.cape);
369 pConf->Write(
"Reflectivity", xyGribConfig.reflectivity);
370 pConf->Write(
"CloudCover", xyGribConfig.cloudCover);
371 pConf->Write(
"Precipitation", xyGribConfig.precipitation);
372 pConf->Write(
"WaveHeight", xyGribConfig.waveHeight);
373 pConf->Write(
"WindWaves", xyGribConfig.windWaves);
379void GRIBUICtrlBar::SetScaledBitmap(
double factor) {
381 m_ScaledFactor = wxRound(factor * 4.0) / 4.0;
383 m_bpPrev->SetBitmapLabel(
384 GetScaledBitmap(wxBitmap(prev),
"prev", m_ScaledFactor));
385 m_bpNext->SetBitmapLabel(
386 GetScaledBitmap(wxBitmap(next),
"next", m_ScaledFactor));
387 m_bpAltitude->SetBitmapLabel(
388 GetScaledBitmap(wxBitmap(altitude),
"altitude", m_ScaledFactor));
389 m_bpNow->SetBitmapLabel(
390 GetScaledBitmap(wxBitmap(now),
"now", m_ScaledFactor));
391 m_bpZoomToCenter->SetBitmapLabel(
392 GetScaledBitmap(wxBitmap(zoomto),
"zoomto", m_ScaledFactor));
393 m_bpPlay->SetBitmapLabel(
394 GetScaledBitmap(wxBitmap(play),
"play", m_ScaledFactor));
395 m_bpShowCursorData->SetBitmapLabel(
396 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
397 m_CDataIsShown ?
"curdata" :
"ncurdata", m_ScaledFactor));
399 m_bpOpenFile->SetBitmapLabel(
400 GetScaledBitmap(wxBitmap(openfile),
"openfile", m_ScaledFactor));
401 m_bpSettings->SetBitmapLabel(
402 GetScaledBitmap(wxBitmap(setting),
"setting", m_ScaledFactor));
409 m_sTimeline->SetSize(wxSize(20 * m_ScaledFactor, -1));
410 m_sTimeline->SetMinSize(wxSize(20 * m_ScaledFactor, -1));
412 m_sTimeline->SetSize(wxSize(90 * m_ScaledFactor, -1));
413 m_sTimeline->SetMinSize(wxSize(90 * m_ScaledFactor, -1));
418 if (
nullptr == m_bpRequest)
return;
419 m_bpRequest->SetBitmapLabel(
420 GetScaledBitmap(wxBitmap(request),
"request", m_ScaledFactor));
421 m_bpRequest->SetToolTip(_(
"Start a download request"));
424void GRIBUICtrlBar::OpenFile(
bool newestFile) {
425 m_bpPlay->SetBitmapLabel(
426 GetScaledBitmap(wxBitmap(play),
"play", m_ScaledFactor));
427 m_cRecordForecast->Clear();
428 pPlugIn->GetGRIBOverlayFactory()->ClearParticles();
434 m_sTimeline->SetValue(0);
436 m_InterpolateMode =
false;
438 m_SelectionIsSaved =
false;
439 m_HasAltitude =
false;
460 title = (_(
"File: "));
461 title.Append(fn.GetFullName());
462 if (rsa->GetCount() == 0) {
465 title.Prepend(_(
"Error! ")).Append(_(
" contains no valid data!"));
467 PopulateComboDataList();
473 if (rsa->GetCount() > 1) {
475 &last = rsa->Item(rsa->GetCount() - 1);
478 wxTimeSpan span = wxDateTime(last.m_Reference_Time) -
480 m_TimeLineHours = span.GetHours();
483 int halfintermin(wxTimeSpan(wxDateTime(second.m_Reference_Time) -
487 for (m_FileIntervalIndex = 0;; m_FileIntervalIndex++) {
492 if (m_FileIntervalIndex > 0) m_FileIntervalIndex--;
500 title = _(
"No valid GRIB file");
502 pPlugIn->GetGRIBOverlayFactory()->SetMessage(title);
504 SetTimeLineMax(
false);
506 if (
pPlugIn->GetStartOptions() &&
507 m_TimeLineHours != 0)
508 ComputeBestForecastForNow();
514 for (
int i = 1; i < 5; i++) {
519 m_HasAltitude =
true;
525 m_bpSettings->Enable(
true);
531 m_sTimeline->Enable(
m_pTimelineSet !=
nullptr && m_TimeLineHours);
550 bool bconfigOK =
false;
551 if (m_bDataPlot[GribOverlaySettings::WIND] &&
554 if (m_bDataPlot[GribOverlaySettings::WIND_GUST] &&
557 if (m_bDataPlot[GribOverlaySettings::PRESSURE] &&
560 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
563 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
566 if (m_bDataPlot[GribOverlaySettings::CURRENT] &&
570 if (m_bDataPlot[GribOverlaySettings::PRECIPITATION] &&
573 if (m_bDataPlot[GribOverlaySettings::CLOUD] &&
576 if (m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE] &&
579 if (m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE] &&
582 if (m_bDataPlot[GribOverlaySettings::CAPE] &&
585 if (m_bDataPlot[GribOverlaySettings::COMP_REFL] &&
592 for (
int i = 0; i < (int)GribOverlaySettings::GEO_ALTITUDE; i++) {
594 m_bDataPlot[i] =
true;
601 double *latmin,
double *latmax,
602 double *lonmin,
double *lonmax) {
605 double ltmi = -GRIB_NOTDEF, ltma = GRIB_NOTDEF, lnmi = -GRIB_NOTDEF,
607 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
610 if (pGRA->GetLatMin() < ltmi) ltmi = pGRA->GetLatMin();
611 if (pGRA->GetLatMax() > ltma) ltma = pGRA->GetLatMax();
612 if (pGRA->GetLonMin() < lnmi) lnmi = pGRA->GetLonMin();
613 if (pGRA->GetLonMax() > lnma) lnma = pGRA->GetLonMax();
615 if (ltmi == -GRIB_NOTDEF || lnmi == -GRIB_NOTDEF || ltma == GRIB_NOTDEF ||
619 if (latmin) *latmin = ltmi;
620 if (latmax) *latmax = ltma;
621 if (lonmin) *lonmin = lnmi;
622 if (lonmax) *lonmax = lnma;
629 : m_files(files), m_pattern(pattern) {}
630 virtual wxDirTraverseResult OnFile(
const wxString &filename) {
631 if (m_pattern.Matches(filename)) m_files.Add(filename);
632 return wxDIR_CONTINUE;
634 virtual wxDirTraverseResult OnDir(
const wxString &WXUNUSED(dirname)) {
639 wxArrayString &m_files;
640 const wxRegEx &m_pattern;
643wxArrayString GRIBUICtrlBar::GetFilesInDirectory() {
644 wxArrayString file_array;
645 if (!wxDir::Exists(
m_grib_dir))
return file_array;
649 wxRegEx pattern(
".+\\.gri?b2?(\\.(bz2|gz))?$",
650 wxRE_EXTENDED | wxRE_ICASE | wxRE_NOSUB);
653 dir.Traverse(collector);
655 CompareFileStringTime);
659void GRIBUICtrlBar::SetCursorLatLon(
double lat,
double lon) {
663 if (m_vpMouse && ((lat > m_vpMouse->
lat_min) && (lat < m_vpMouse->lat_max)) &&
664 ((lon > m_vpMouse->
lon_min) && (lon < m_vpMouse->lon_max)))
669 if (!m_CDataIsShown)
return;
671 if (m_DialogStyle >> 1 == SEPARATED) {
672 if (m_gGRIBUICData) {
673 if (!m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.IsRunning())
674 m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.Start(
675 50, wxTIMER_ONE_SHOT);
679 if (!m_gCursorData->m_tCursorTrackTimer.IsRunning())
680 m_gCursorData->m_tCursorTrackTimer.Start(50, wxTIMER_ONE_SHOT);
685void GRIBUICtrlBar::OnShowCursorData(wxCommandEvent &event) {
686 m_CDataIsShown = !m_CDataIsShown;
687 m_bpShowCursorData->SetBitmapLabel(
688 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
689 m_CDataIsShown ?
"curdata" :
"ncurdata", m_ScaledFactor));
690 SetDialogsStyleSizePosition(
true);
693void GRIBUICtrlBar::SetDialogsStyleSizePosition(
bool force_recompute) {
698 if (!force_recompute &&
699 (m_old_DialogStyle == m_DialogStyle
701 (m_old_DialogStyle >> 1 == ATTACHED && m_DialogStyle >> 1 == ATTACHED)))
704 bool m_HasCaption = GetWindowStyleFlag() == (wxCAPTION |
wxCLOSE_BOX |
705 wxSYSTEM_MENU | wxTAB_TRAVERSAL);
710 int state = (m_DialogStyle >> 1 == ATTACHED && m_CDataIsShown) ? 0 : 1;
713 bool vis = i > 0 ? true : m_HasAltitude ? true :
false;
714 if (FindWindow(i + ID_CTRLALTITUDE))
715 FindWindow(i + ID_CTRLALTITUDE)
721 m_bpShowCursorData->SetToolTip(m_CDataIsShown ? _(
"Hide data at cursor")
722 : _(
"Show data at cursor"));
723 m_bpPlay->SetToolTip(_(
"Start play back"));
728 m_gCursorData->Hide();
729 m_fgCDataSizer->Detach(m_gCursorData);
732 SetMinSize(wxSize(0, 0));
736 if (m_gGRIBUICData) {
737 m_gGRIBUICData->Destroy();
738 m_gGRIBUICData =
nullptr;
741 if ((m_DialogStyle >> 1 == SEPARATED || !m_CDataIsShown) &&
748 if (m_CDataIsShown) {
749 if (m_DialogStyle >> 1 == ATTACHED) {
751 if (!m_gCursorData) m_gCursorData =
new CursorData(
this, *
this);
752 pPlugIn->SetDialogFont(m_gCursorData);
753 m_gCursorData->PopulateTrackingControls(
false);
755 if (m_fgCDataSizer->GetItem(m_gCursorData) ==
nullptr)
756 m_fgCDataSizer->Add(m_gCursorData, 0);
757 m_gCursorData->Show();
759 }
else if (m_DialogStyle >> 1 == SEPARATED) {
762 m_gGRIBUICData->m_gCursorData->PopulateTrackingControls(
763 m_DialogStyle == SEPARATED_VERTICAL);
764 pPlugIn->SetDialogFont(m_gGRIBUICData->m_gCursorData);
765 m_gGRIBUICData->Fit();
766 m_gGRIBUICData->Update();
767 m_gGRIBUICData->Show();
769 m_gGRIBUICData->Layout();
770 m_gGRIBUICData->Fit();
775 wxSize sd = GetSize();
777 if (!m_gtk_started && m_HasCaption ) {
779 m_gtk_started =
true;
782 SetSize(wxSize(sd.x, sd.y));
783 SetMinSize(wxSize(sd.x, sd.y));
790 wxPoint pNew =
pPlugIn->GetCtrlBarXY();
791 pNew.x = tbRect.x + tbRect.width + 4;
799 if (sd.x > widthAvail) {
802 int target_char_width = (float)widthAvail / 28;
811 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
813 dc.GetTextExtent(
"W", &width, &height,
nullptr,
nullptr, sFont);
814 if (width <= target_char_width) bOK =
true;
816 if (pointSize <= 10) bOK =
true;
819 m_cRecordForecast->SetFont(*sFont);
824 SetSize(wxSize(widthAvail, sd.y));
825 SetMinSize(wxSize(widthAvail, sd.y));
829 wxPoint pNow =
pPlugIn->GetCtrlBarXY();
836 m_old_DialogStyle = m_DialogStyle;
839void GRIBUICtrlBar::OnAltitude(wxCommandEvent &event) {
840 if (!m_HasAltitude)
return;
842 wxMenu *amenu =
new wxMenu();
843 amenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
844 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
this);
846 for (
int i = 0; i < 5; i++) {
854 amenu, ID_CTRLALTITUDE + 1000 + i,
863 amenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
870void GRIBUICtrlBar::OnMove(wxMoveEvent &event) {
872 GetScreenPosition(&w, &h);
873 pPlugIn->SetCtrlBarXY(wxPoint(w, h));
876void GRIBUICtrlBar::OnMenuEvent(wxMenuEvent &event) {
877 int id =
event.GetId();
880 int alt = m_Altitude;
883 case ID_CTRLALTITUDE + 1000:
886 case ID_CTRLALTITUDE + 1001:
889 case ID_CTRLALTITUDE + 1002:
892 case ID_CTRLALTITUDE + 1003:
895 case ID_CTRLALTITUDE + 1004:
903 OnZoomToCenterClick(evt);
905 case ID_BTNSHOWCDATA:
906 OnShowCursorData(evt);
920 if (alt != m_Altitude) {
921 SetDialogsStyleSizePosition(
true);
926void GRIBUICtrlBar::MenuAppend(wxMenu *menu,
int id, wxString label,
927 wxItemKind kind, wxBitmap bitmap,
929 wxMenuItem *item =
new wxMenuItem(menu,
id, label,
"", kind);
932 item->SetSubMenu(submenu);
942#if defined(__WXMSW__) || defined(__WXGTK__)
943 if (!bitmap.IsSameAs(wxNullBitmap)) item->SetBitmap(bitmap);
949void GRIBUICtrlBar::OnMouseEvent(wxMouseEvent &event) {
950 if (event.RightDown()) {
952 wxMenu *xmenu =
new wxMenu();
953 xmenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
954 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
958 wxMenu *smenu =
new wxMenu();
959 smenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
960 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
963 for (
int i = 0; i < 5; i++) {
971 smenu, ID_CTRLALTITUDE + 1000 + i,
978 smenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
980 xmenu, wxID_ANY, _(
"Select geopotential altitude"), wxITEM_NORMAL,
981 GetScaledBitmap(wxBitmap(altitude),
"altitude", m_ScaledFactor),
984 MenuAppend(xmenu, ID_BTNNOW, _(
"Now"), wxITEM_NORMAL,
985 GetScaledBitmap(wxBitmap(now),
"now", m_ScaledFactor));
986 MenuAppend(xmenu, ID_BTNZOOMTC, _(
"Zoom To Center"), wxITEM_NORMAL,
987 GetScaledBitmap(wxBitmap(zoomto),
"zoomto", m_ScaledFactor));
989 xmenu, ID_BTNSHOWCDATA,
990 m_CDataIsShown ? _(
"Hide data at cursor") : _(
"Show data at cursor"),
992 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
993 m_CDataIsShown ?
"curdata" :
"ncurdata",
997 m_tPlayStop.IsRunning() ? _(
"Stop play back") : _(
"Start play back"),
999 GetScaledBitmap(wxBitmap(
m_tPlayStop.IsRunning() ? stop : play),
1002 MenuAppend(xmenu, ID_BTNOPENFILE, _(
"Open a new file"), wxITEM_NORMAL,
1003 GetScaledBitmap(wxBitmap(openfile),
"openfile", m_ScaledFactor));
1004 MenuAppend(xmenu, ID_BTNSETTING, _(
"Settings"), wxITEM_NORMAL,
1005 GetScaledBitmap(wxBitmap(setting),
"setting", m_ScaledFactor));
1011 requeststate1 ? _(
"Request forecast data")
1013 ? _(
"Draw requested Area or Click here to stop request")
1014 : _(
"Valid Area and Continue"),
1016 GetScaledBitmap(wxBitmap(requeststate1 ? request
1017 : requeststate3 ? selzone
1019 requeststate1 ?
"request"
1020 : requeststate3 ?
"selzone"
1031 if (m_DialogStyle >> 1 == SEPARATED)
return;
1032 wxMouseEvent evt(event);
1036 if (m_gCursorData && m_CDataIsShown) {
1037 m_gCursorData->OnMouseEvent(evt);
1042void GRIBUICtrlBar::ContextMenuItemCallback(
int id) {
1044 bool dataisshown = m_CDataIsShown;
1045 m_CDataIsShown =
false;
1058 m_CDataIsShown = dataisshown;
1063 if (m_vpMouse == vp)
return;
1075void GRIBUICtrlBar::OnClose(wxCloseEvent &event) {
1077 if (m_gGRIBUICData) m_gGRIBUICData->Hide();
1080 pReq_Dialog->StopGraphicalZoneSelection();
1084 pPlugIn->SendTimelineMessage(wxInvalidDateTime);
1086 pPlugIn->OnGribCtrlBarClose();
1089void GRIBUICtrlBar::OnSize(wxSizeEvent &event) {
1091 wxSize p =
event.GetSize();
1097void GRIBUICtrlBar::OnPaint(wxPaintEvent &event) {
1098 wxWindowListNode *node = this->GetChildren().GetFirst();
1101 wxWindow *win = node->GetData();
1102 if (
dynamic_cast<wxBitmapButton *
>(win))
1103 dc.DrawBitmap(
dynamic_cast<wxBitmapButton *
>(win)->GetBitmap(), 5, 5,
1105 node = node->GetNext();
1109void GRIBUICtrlBar::createRequestDialog() {
1110 ::wxBeginBusyCursor();
1115 pPlugIn->SetDialogFont(pReq_Dialog);
1116 pPlugIn->SetDialogFont(pReq_Dialog->m_sScrolledDialog);
1119 pReq_Dialog->SetRequestDialogSize();
1120 if (::wxIsBusy()) ::wxEndBusyCursor();
1128 if (pReq_Dialog && pReq_Dialog->IsShown())
return;
1131 createRequestDialog();
1134 ::wxDisplaySize(&w,
nullptr);
1135 pReq_Dialog->Move((w - pReq_Dialog->GetSize().GetX()) / 2, 30);
1136 pReq_Dialog->Show();
1141void GRIBUICtrlBar::OnSettings(wxCommandEvent &event) {
1145 ::wxBeginBusyCursor();
1151 pPlugIn->SetDialogFont(dialog);
1152 for (
size_t i = 0; i < dialog->m_nSettingsBook->GetPageCount(); i++) {
1153 wxScrolledWindow *sc =
1154 ((wxScrolledWindow *)dialog->m_nSettingsBook->GetPage(i));
1158 dialog->m_nSettingsBook->ChangeSelection(dialog->GetPageIndex());
1159 dialog->SetSettingsDialogSize();
1162 ::wxDisplaySize(&w,
nullptr);
1163 dialog->Move((w - dialog->GetSize().GetX()) / 2, 30);
1166 ::wxEndBusyCursor();
1168 if (dialog->ShowModal() == wxID_OK) {
1169 dialog->WriteSettings();
1172 initSettings.Settings[GribOverlaySettings::WIND].m_Units &&
1174 GribOverlaySettings::BFS ||
1175 initSettings.Settings[GribOverlaySettings::WIND].m_Units ==
1176 GribOverlaySettings::BFS))
1178 STARTING_STATE_STYLE;
1182 m_DialogStyle = initSettings.m_iCtrlandDataStyle;
1184 ::wxBeginBusyCursor();
1186 dialog->SaveLastPage();
1188 m_InterpolateMode =
false;
1189 SetTimeLineMax(
true);
1190 SetFactoryOptions();
1192 SetDialogsStyleSizePosition(
true);
1199wxString callActivityMethod_ss(
const char *method, wxString parm);
1202void GRIBUICtrlBar::OnCompositeDialog(wxCommandEvent &event) {
1205 initSettings.Read();
1208 wxString json_begin = initSettings.SettingsToJSON(json);
1209 wxLogMessage(json_begin);
1218 double lon_min = wxRound(current_vp.
lon_min) - 1;
1219 double lon_max = wxRound(current_vp.
lon_max) + 1;
1220 double lat_min = wxRound(current_vp.
lat_min) - 1;
1221 double lat_max = wxRound(current_vp.
lat_max) + 1;
1225 int numErrors = reader.
Parse(json_begin, &v);
1226 if (numErrors > 0) {
1230 v[
"latMin"] = lat_min;
1231 v[
"latMax"] = lat_max;
1232 v[
"lonMin"] = lon_min;
1233 v[
"lonMax"] = lon_max;
1237 v[
"grib_file"] =
"";
1240 wxString json_final;
1241 w.
Write(v, json_final);
1242 wxLogMessage(json_final);
1245 wxString ret = callActivityMethod_ss(
"doGRIBActivity", json_final);
1252void GRIBUICtrlBar::OpenFileFromJSON(wxString json) {
1258 int numErrors = reader.
Parse(json, &root);
1259 if (numErrors > 0) {
1263 wxString file = root[(
"grib_file")].AsString();
1265 if (file.Length() && wxFileExists(file)) {
1266 wxFileName fn(file);
1274void GRIBUICtrlBar::OnPlayStop(wxCommandEvent &event) {
1278 m_bpPlay->SetBitmapLabel(
1279 GetScaledBitmap(wxBitmap(stop),
"stop", m_ScaledFactor));
1280 m_bpPlay->SetToolTip(_(
"Stop play back"));
1282 wxTIMER_CONTINUOUS);
1287void GRIBUICtrlBar::OnPlayStopTimer(wxTimerEvent &event) {
1288 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax()) {
1291 ComputeBestForecastForNow();
1292 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax())
1296 m_sTimeline->SetValue(0);
1303 ? GetNearestValue(GetNow(), 1)
1304 : GetNearestIndex(GetNow(), 2)
1305 : m_sTimeline->GetValue();
1306 m_sTimeline->SetValue(value + 1);
1310 if (!m_InterpolateMode)
1311 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1315void GRIBUICtrlBar::StopPlayBack() {
1318 m_bpPlay->SetBitmapLabel(
1319 GetScaledBitmap(wxBitmap(play),
"play", m_ScaledFactor));
1320 m_bpPlay->SetToolTip(_(
"Start play back"));
1324void GRIBUICtrlBar::TimelineChanged() {
1326 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1330 RestaureSelectionString();
1336 if (!m_InterpolateMode) {
1339 GribRecordSet &sel = rsa->Item(m_cRecordForecast->GetCurrentSelection());
1342 ? wxTimeSpan(t - MinTime()).GetMinutes() /
1345 : m_cRecordForecast->GetCurrentSelection());
1347 m_cRecordForecast->SetSelection(GetNearestIndex(time, 2));
1348 SaveSelectionString();
1350 m_cRecordForecast->SetString(m_Selection_index,
1353 m_cRecordForecast->SetStringSelection(
1359 pPlugIn->SendTimelineMessage(time);
1363void GRIBUICtrlBar::RestaureSelectionString() {
1364 if (!m_SelectionIsSaved)
return;
1366 int sel = m_cRecordForecast->GetSelection();
1367 m_cRecordForecast->SetString(m_Selection_index, m_Selection_label);
1368 m_cRecordForecast->SetSelection(sel);
1369 m_SelectionIsSaved =
false;
1372int GRIBUICtrlBar::GetNearestIndex(wxDateTime time,
int model) {
1377 wxDateTime itime, ip1time;
1378 for (i = 0; i < rsa->GetCount() - 1; i++) {
1379 itime = rsa->Item(i).m_Reference_Time;
1380 ip1time = rsa->Item(i + 1).m_Reference_Time;
1381 if (ip1time >= time)
break;
1383 if (!model)
return (time - itime > (ip1time - time) * 3) ? i + 1 : i;
1385 return model == 1 ? time == ip1time ? i : i + 1 : time == ip1time ? i + 1 : i;
1388int GRIBUICtrlBar::GetNearestValue(wxDateTime time,
int model) {
1390 if (m_TimeLineHours == 0)
return 0;
1391 wxDateTime itime, ip1time;
1394 wxTimeSpan span = time - MinTime();
1395 int t = span.GetMinutes() / stepmin;
1397 wxTimeSpan(t * stepmin / 60, (t * stepmin) % 60);
1398 ip1time = itime + wxTimeSpan(stepmin / 60, stepmin % 60);
1400 if (model == 1)
return time == ip1time ? t + 1 : t;
1402 return (time - itime > (ip1time - time) * 3) ? t + 1 : t;
1405wxDateTime GRIBUICtrlBar::GetNow() {
1406 wxDateTime now = wxDateTime::Now();
1412 now = (now > rsa->Item(rsa->GetCount() - 1).m_Reference_Time)
1413 ? rsa->Item(rsa->GetCount() - 1).m_Reference_Time
1414 : (now < rsa->Item(0).m_Reference_Time) ? rsa->Item(0).m_Reference_Time
1420 if (m_InterpolateMode) {
1421 int tl = (m_TimeLineHours == 0) ? 0 : m_sTimeline->GetValue();
1424 return MinTime() + wxTimeSpan(tl * stepmin / 60, (tl * stepmin) % 60);
1428 unsigned int index = m_cRecordForecast->GetCurrentSelection() < 1
1430 : m_cRecordForecast->GetCurrentSelection();
1431 if (rsa && index < rsa->GetCount())
return rsa->Item(index).m_Reference_Time;
1433 return wxDateTime::Now();
1436wxDateTime GRIBUICtrlBar::MinTime() {
1438 if (rsa && rsa->GetCount()) {
1442 return wxDateTime::Now();
1449 if (rsa->GetCount() == 0)
return nullptr;
1456 wxDateTime GR1time, GR2time;
1462 for (j = 0; j < rsa->GetCount(); j++) {
1468 if (curtime <= time) GR1time = curtime, GRS1 = GRS, GR1 = GR;
1470 if (curtime >= time) {
1471 GR2time = curtime, GRS2 = GRS, GR2 = GR;
1476 if (!GR1 || !GR2)
continue;
1478 wxDateTime mintime = MinTime();
1479 double minute2 = (GR2time - mintime).GetMinutes();
1480 double minute1 = (GR1time - mintime).GetMinutes();
1481 double nminute = (time - mintime).GetMinutes();
1483 if (minute2 < minute1 || nminute < minute1 || nminute > minute2)
continue;
1485 double interp_const;
1486 if (minute1 == minute2) {
1491 interp_const = (nminute - minute1) / (minute2 - minute1);
1522 *GR1, *GR2, interp_const, i ==
Idx_WVDIR));
1533 auto sog = m_ProjectBoatPanel->GetSpeed();
1534 auto cog = m_ProjectBoatPanel->GetCourse();
1536 static_cast<double>(now.GetTicks() -
pPlugIn->m_boat_time) * sog / 3600.0;
1538 pPlugIn->m_boat_lon, cog, dist,
1539 &m_projected_lat, &m_projected_lon);
1547double GRIBUICtrlBar::getTimeInterpolatedValue(
int idx,
double lon,
double lat,
1552 if (rsa->GetCount() == 0)
return GRIB_NOTDEF;
1554 GribRecord *before =
nullptr, *after =
nullptr;
1557 time_t t = time.GetTicks();
1558 for (j = 0; j < rsa->GetCount(); j++) {
1563 time_t curtime = GR->GetRecordCurrentDate();
1566 if (curtime < t) before = GR;
1574 if (!before || !after)
return GRIB_NOTDEF;
1576 time_t t1 = before->GetRecordCurrentDate();
1577 time_t t2 = after->GetRecordCurrentDate();
1581 double v2 = after->GetInterpolatedValue(lon, lat);
1582 if (v1 != GRIB_NOTDEF && v2 != GRIB_NOTDEF) {
1583 double k = fabs((
double)(t - t1) / (t2 - t1));
1584 return (1.0 - k) * v1 + k * v2;
1590bool GRIBUICtrlBar::getTimeInterpolatedValues(
double &M,
double &A,
int idx1,
1591 int idx2,
double lon,
double lat,
1599 if (rsa->GetCount() == 0)
return false;
1601 GribRecord *beforeX =
nullptr, *afterX =
nullptr;
1602 GribRecord *beforeY =
nullptr, *afterY =
nullptr;
1605 time_t t = time.GetTicks();
1606 for (j = 0; j < rsa->GetCount(); j++) {
1610 if (!GX || !GY)
continue;
1612 time_t curtime = GX->GetRecordCurrentDate();
1627 if (!beforeX || !afterX)
return false;
1629 time_t t1 = beforeX->GetRecordCurrentDate();
1630 time_t t2 = afterX->GetRecordCurrentDate();
1635 double v1m, v2m, v1a, v2a;
1644 if (v1m == GRIB_NOTDEF || v2m == GRIB_NOTDEF || v1a == GRIB_NOTDEF ||
1648 double k = fabs((
double)(t - t1) / (t2 - t1));
1649 M = (1.0 - k) * v1m + k * v2m;
1650 A = (1.0 - k) * v1a + k * v2a;
1654void GRIBUICtrlBar::OnTimeline(wxScrollEvent &event) {
1657 if (!m_InterpolateMode)
1658 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1663void GRIBUICtrlBar::OnOpenFile(wxCommandEvent &event) {
1669 wxStandardPathsBase &path = wxStandardPaths::Get();
1670 wxString l_grib_dir = path.GetDocumentsDir();
1679 auto saved_show_types_setting =
1680 wxSystemOptions::GetOptionInt(wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES);
1681 wxSystemOptions::SetOption(wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES, 1);
1683 wxFileDialog *dialog =
new wxFileDialog(
1684 nullptr, _(
"Select a GRIB file"), l_grib_dir,
"",
1686 " (*.grb;*.grib;*.bz2;*.gz;*.grib2;*.grb2)|*.grb;*.grib;*.bz2;*.gz;" +
1687 "*.grib2;*.grb2|" + _(
"All files") +
"(*)|*.*",
1688 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE, wxDefaultPosition,
1689 wxDefaultSize, _(
"File Dialog"));
1691 if (dialog->ShowModal() == wxID_OK) {
1692 ::wxBeginBusyCursor();
1698 if (g_pi->m_bZoomToCenterAtInit) DoZoomToCenter();
1700 SetDialogsStyleSizePosition(
true);
1706 wxSystemOptions::SetOption(wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES,
1707 saved_show_types_setting);
1712 wxStandardPathsBase &path = wxStandardPaths::Get();
1718 nullptr, &file, _(
"Select a GRIB file"),
m_grib_dir,
"",
"*.*");
1720 if (response == wxID_OK) {
1721 wxFileName fn(file);
1726 SetDialogsStyleSizePosition(
true);
1731void GRIBUICtrlBar::CreateActiveFileFromNames(
const wxArrayString &filenames) {
1732 if (filenames.GetCount() != 0) {
1739void GRIBUICtrlBar::PopulateComboDataList() {
1741 if (m_cRecordForecast->GetCount()) {
1742 index = m_cRecordForecast->GetCurrentSelection();
1743 m_cRecordForecast->Clear();
1747 for (
size_t i = 0; i < rsa->GetCount(); i++) {
1748 wxDateTime t(rsa->Item(i).m_Reference_Time);
1751 m_cRecordForecast->SetSelection(index);
1754void GRIBUICtrlBar::OnZoomToCenterClick(wxCommandEvent &event) {
1759 double latmin,latmax,lonmin,lonmax;
1760 if(!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax ))
1766 double width = lonmax - lonmin;
1767 double height = latmax - latmin;
1770 double clat = latmin + height / 2;
1771 double clon = lonmin + width / 2;
1775 lonmin = clon - 60.;
1776 lonmax = clon + 60.;
1779 latmin = clat - 60.;
1780 latmax = clat + 60.;
1790 int w =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetWidth();
1791 int h =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetHeight();
1795 ppm = wxMin(w/(ow*1852), h/(oh*1852)) * ( 100 - fabs( clat ) ) / 90;
1797 ppm = wxMin(ppm, 1.0);
1805void GRIBUICtrlBar::DoZoomToCenter() {
1808 double latmin, latmax, lonmin, lonmax;
1809 if (!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax))
1815 double width = lonmax - lonmin;
1816 double height = latmax - latmin;
1819 double clat = latmin + height / 2;
1820 double clon = lonmin + width / 2;
1824 lonmin = clon - 60.;
1825 lonmax = clon + 60.;
1827 if (height > 120.) {
1828 latmin = clat - 60.;
1829 latmax = clat + 60.;
1837 wxWindow *wx = GetGRIBCanvas();
1839 int w = wx->GetSize().x;
1840 int h = wx->GetSize().y;
1844 ppm = wxMin(w / (ow * 1852), h / (oh * 1852)) * (100 - fabs(clat)) / 90;
1846 ppm = wxMin(ppm, 1.0);
1851void GRIBUICtrlBar::OnPrev(wxCommandEvent &event) {
1855 RestaureSelectionString();
1859 selection = GetNearestIndex(GetNow(), 1);
1860 else if (m_InterpolateMode)
1864 selection = m_cRecordForecast->GetCurrentSelection();
1867 m_InterpolateMode =
false;
1869 m_cRecordForecast->SetSelection(selection < 1 ? 0 : selection - 1);
1874void GRIBUICtrlBar::OnNext(wxCommandEvent &event) {
1878 RestaureSelectionString();
1882 selection = GetNearestIndex(GetNow(), 2);
1883 else if (m_InterpolateMode)
1887 selection = m_cRecordForecast->GetCurrentSelection();
1889 m_cRecordForecast->SetSelection(selection);
1892 m_InterpolateMode =
false;
1894 if (selection == (
int)m_cRecordForecast->GetCount() - 1)
1897 m_cRecordForecast->SetSelection(selection + 1);
1902void GRIBUICtrlBar::ComputeBestForecastForNow() {
1904 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1908 wxDateTime now = GetNow();
1911 m_sTimeline->SetValue(GetNearestValue(now, 0));
1913 m_cRecordForecast->SetSelection(GetNearestIndex(now, 0));
1914 m_sTimeline->SetValue(m_cRecordForecast->GetCurrentSelection());
1917 if (
pPlugIn->GetStartOptions() !=
1924 m_InterpolateMode =
true;
1926 SetGribTimelineRecordSet(
1929 RestaureSelectionString();
1931 m_cRecordForecast->SetSelection(GetNearestIndex(now, 2));
1932 SaveSelectionString();
1934 m_cRecordForecast->SetString(m_Selection_index,
1937 m_cRecordForecast->SetStringSelection(nowTime);
1941 pPlugIn->SendTimelineMessage(now);
1945void GRIBUICtrlBar::SetGribTimelineRecordSet(
1950 if (!
pPlugIn->GetGRIBOverlayFactory())
return;
1955void GRIBUICtrlBar::SetTimeLineMax(
bool SetValue) {
1956 int oldmax = wxMax(m_sTimeline->GetMax(), 1),
1957 oldval = m_sTimeline->GetValue();
1962 m_sTimeline->SetMax(m_TimeLineHours * 60 / stepmin);
1966 m_sTimeline->SetMax(rsa->GetCount() - 1);
1971 if (SetValue && m_sTimeline->GetMax() != 0) {
1973 ComputeBestForecastForNow();
1975 m_sTimeline->SetValue(m_sTimeline->GetMax() * oldval / oldmax);
1979void GRIBUICtrlBar::SetFactoryOptions() {
1982 pPlugIn->GetGRIBOverlayFactory()->ClearCachedData();
1988void GRIBUICtrlBar::OnFormatRefreshTimer(wxTimerEvent &event) {
1991 wxDateTime referenceDate(1, wxDateTime::Jan, 2021, 12, 0, 0);
1994 if (currentFormat != m_sLastTimeFormat) {
1996 m_sLastTimeFormat = currentFormat;
2000 PopulateComboDataList();
2014unsigned int GRIBFile::ID = 0;
2020 m_pGribReader =
nullptr;
2021 m_last_message = wxEmptyString;
2022 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
2023 wxString file_name = file_names[i];
2024 if (::wxFileExists(file_name)) m_bOK =
true;
2027 if (m_bOK ==
false) {
2028 m_last_message = _(
" files don't exist!");
2037 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
2038 file_name = file_names[i];
2039 m_pGribReader->OpenFile(file_name);
2041 if (m_pGribReader->IsOk()) {
2048 if (m_bOK ==
false) {
2049 m_last_message = _(
" can't be read!");
2054 m_FileNames.Clear();
2055 m_FileNames.Add(file_name);
2057 m_FileNames = file_names;
2061 m_pGribReader->ComputeAccumulationRecords(GRB_PRECIP_TOT, LV_GND_SURF, 0);
2062 m_pGribReader->ComputeAccumulationRecords(GRB_PRECIP_RATE, LV_GND_SURF, 0);
2063 m_pGribReader->ComputeAccumulationRecords(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
2071 m_nGribRecords = m_pGribReader->GetTotalNumberOfGribRecords();
2075 std::set<time_t>::iterator iter;
2076 std::set<time_t> date_list = m_pGribReader->GetListDates();
2077 for (iter = date_list.begin(); iter != date_list.end(); iter++) {
2079 time_t reftime = *iter;
2081 m_GribRecordSetArray.Add(t);
2089 bool polarWind(
false);
2090 bool polarCurrent(
false);
2091 bool sigWave(
false);
2094 std::map<std::string, std::vector<GribRecord *> *> *p_map =
2095 m_pGribReader->GetGribMap();
2098 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
2099 for (it = p_map->begin(); it != p_map->end(); it++) {
2100 std::vector<GribRecord *> *ls = (*it).second;
2101 for (zuint i = 0; i < ls->size(); i++) {
2104 time_t thistime = pRec->GetRecordCurrentDate();
2107 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2108 if (m_GribRecordSetArray.Item(j).m_Reference_Time == thistime) {
2109 int idx = -1, mdx = -1;
2133 case GRB_WIND_SPEED:
2156 polarCurrent =
true;
2162 polarCurrent =
true;
2194 case GRB_PRECIP_RATE:
2195 case GRB_PRECIP_TOT:
2220 mdx = 1000 + NORWAY_METNO;
2250 case GRB_GEOPOT_HGT:
2276 if (m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx]) {
2279 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2301 if (oRec->
GetDataType() == GRB_HTSGW) skip =
true;
2311 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx] = pRec;
2312 if (m_GribIdxArray.Index(idx) == wxNOT_FOUND)
2313 m_GribIdxArray.Add(idx, 1);
2314 if (mdx != -1 && m_GribIdxArray.Index(mdx) == wxNOT_FOUND)
2315 m_GribIdxArray.Add(mdx, 1);
2323 if (polarWind || polarCurrent) {
2324 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2325 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
2329 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2331 if (pRec !=
nullptr && pRec->
GetDataType() == GRB_WIND_DIR) {
2353 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2354 if (pRec1 !=
nullptr && pRec1->
GetDataType() == GRB_WIND_SPEED)
2362 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2364 if (pRec !=
nullptr && pRec->
GetDataType() == GRB_CUR_DIR) {
2374 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2375 if (pRec1 !=
nullptr && pRec1->
GetDataType() == GRB_CUR_SPEED)
2386 pRec->GetRecordRefDate();
2389GRIBFile::~GRIBFile() {
delete m_pGribReader; }
2396 :
GRIBUICDataBase(parent.pParent, CURSOR_DATA, _(
"GRIB Display Control"),
2397 wxDefaultPosition, wxDefaultSize,
2398 wxSYSTEM_MENU | wxNO_BORDER | wxSTAY_ON_TOP)
2401 wxDefaultPosition, wxDefaultSize,
2402 wxSYSTEM_MENU | wxNO_BORDER)
2405 m_gpparent(parent) {
2409 m_gCursorData =
new CursorData(
this, m_gpparent);
2410 m_fgCdataSizer->Add(m_gCursorData, 0, wxALL, 0);
2412 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICData::OnMove));
2415void GRIBUICData::OnMove(wxMoveEvent &event) {
2417 GetScreenPosition(&w, &h);
2418 m_gpparent.
pPlugIn->SetCursorDataXY(wxPoint(w, h));
2426#include <QtAndroidExtras/QAndroidJniObject>
2428bool CheckPendingJNIException() {
2435 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2440 if ((jenv)->ExceptionCheck() == JNI_TRUE) {
2448wxString callActivityMethod_ss(
const char *method, wxString parm) {
2454 if (CheckPendingJNIException())
return "NOK";
2456 wxString return_string;
2457 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2458 "org/qtproject/qt5/android/QtNative",
"activity",
2459 "()Landroid/app/Activity;");
2460 if (CheckPendingJNIException())
return "NOK";
2462 if (!activity.isValid()) {
2464 return return_string;
2469 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2471 return "jenv Error";
2474 jstring p = (jenv)->NewStringUTF(parm.c_str());
2480 QAndroidJniObject data = activity.callObjectMethod(
2481 method,
"(Ljava/lang/String;)Ljava/lang/String;", p);
2482 if (CheckPendingJNIException())
return "NOK";
2486 jstring s = data.object<jstring>();
2488 if ((jenv)->GetStringLength(s)) {
2489 const char *ret_string = (jenv)->GetStringUTFChars(s,
nullptr);
2490 return_string = wxString(ret_string, wxConvUTF8);
2493 return return_string;
Tracks and displays GRIB meteorological data at cursor position.
Manages multiple GRIB record sets from one or more GRIB files.
bool IsOK() const
Checks if file loading and parsing was successful.
wxArrayString & GetFileNames()
Gets the list of source filenames being used.
GRIBFile(const wxArrayString &file_names, bool CumRec, bool WaveRec, bool newestFile=false)
Creates a new GRIBFile by parsing one or more GRIB files.
ArrayOfGribRecordSets * GetRecordSetArrayPtr()
Gets pointer to array of record sets organized by timestamp.
time_t GetRefDateTime() const
Returns the reference datetime of the GRIB data, as the number of seconds since the epoch.
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.
GribPi * pPlugIn
Plugin instance that owns this control bar.
wxString m_grib_dir
Directory containing GRIB files.
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.
void OnRequestForecastData(wxCommandEvent &event) override
Callback invoked when user clicks download/request forecast data.
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.
bool GetCopyFirstCumRec() const
Returns true if cumulative parameters like precipitation and cloud cover should initialize their star...
bool GetCopyMissWaveRec() const
Returns true if wave data should be propagated across time periods where wave records are missing.
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.
A meteorological data grid from a GRIB (Gridded Binary) file.
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.
static void Polar2UV(GribRecord *pDIR, GribRecord *pSPEED)
Converts wind or current values from polar (direction/speed) to cartesian (U/V) components.
zuchar GetTimeRange() const
Returns the time range indicator that defines how P1 and P2 should be interpreted.
zuint GetDataCenterModel() const
Returns the numerical weather prediction model/center that produced this data.
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).
zuchar GetDataType() const
Returns the type of meteorological parameter stored in this grid.
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.
double GetInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
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.
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.
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.
@ 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.
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.
#define ID_BTNREQUEST
ID of button for requesting/downloading GRIB data./*#end#*/.
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...