24#include "wx/tokenzr.h"
25#include "wx/datetime.h"
27#include <wx/wfstream.h>
29#include <wx/filename.h>
31#include <wx/graphics.h>
34#include <wx/stdpaths.h>
47#include <wx/arrimpl.cpp>
50#include "android_jvm.h"
54double m_cursor_lat, m_cursor_lon;
90 return ((x - i) >= 0.5) ? (i + 1) : (i);
92 return (-x + i >= 0.5) ? (i - 1) : (i);
102#if wxCHECK_VERSION(2, 9, 4)
103#define SetBitmapLabelLabel SetBitmap
106#define DEFAULT_STYLE \
107 = wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL
109WX_DEFINE_OBJARRAY(ArrayOfGribRecordSets);
112static int CompareFileStringTime(
const wxString &first,
113 const wxString &second) {
115 wxFileName s(second);
116 wxTimeSpan sp = s.GetModificationTime() - f.GetModificationTime();
117 return sp.GetMinutes();
123wxWindow *GetGRIBCanvas() {
146GribTimelineRecordSet::~GribTimelineRecordSet() {
151void GribTimelineRecordSet::ClearCachedData() {
155 for (
unsigned int j = 0; j <
m_IsobarArray[i]->GetCount(); j++) {
169GRIBUICtrlBar::GRIBUICtrlBar(wxWindow *parent, wxWindowID
id,
170 const wxString &title,
const wxPoint &pos,
171 const wxSize &size,
long style,
grib_pi *ppi,
179 pReq_Dialog =
nullptr;
180 m_bGRIBActiveFile =
nullptr;
181 m_pTimelineSet =
nullptr;
182 m_gCursorData =
nullptr;
183 m_gGRIBUICData =
nullptr;
184 m_gtk_started =
false;
189 m_fgCtrlGrabberSize->Add(m_gGrabber, 0, wxALL, 0);
191 this->SetSizer(m_fgCtrlBarSizer);
193 m_fgCtrlBarSizer->Fit(
this);
196 m_tFormatRefresh.Connect(
197 wxEVT_TIMER, wxTimerEventHandler(GRIBUICtrlBar::OnFormatRefreshTimer),
202 wxDateTime referenceDate(1, wxDateTime::Jan, 2021, 12, 0, 0);
206 m_tFormatRefresh.Start(5000);
209 pConf->SetPath(_T (
"/Settings/GRIB" ));
210 pConf->Read(_T (
"WindPlot" ), &m_bDataPlot[GribOverlaySettings::WIND],
212 pConf->Read(_T (
"WindGustPlot" ),
213 &m_bDataPlot[GribOverlaySettings::WIND_GUST],
false);
214 pConf->Read(_T (
"PressurePlot" ),
215 &m_bDataPlot[GribOverlaySettings::PRESSURE],
false);
216 pConf->Read(_T (
"WavePlot" ), &m_bDataPlot[GribOverlaySettings::WAVE],
218 pConf->Read(_T (
"CurrentPlot" ),
219 &m_bDataPlot[GribOverlaySettings::CURRENT],
false);
220 pConf->Read(_T (
"PrecipitationPlot" ),
221 &m_bDataPlot[GribOverlaySettings::PRECIPITATION],
false);
222 pConf->Read(_T (
"CloudPlot" ), &m_bDataPlot[GribOverlaySettings::CLOUD],
224 pConf->Read(_T (
"AirTemperaturePlot" ),
225 &m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE],
false);
226 pConf->Read(_T (
"SeaTemperaturePlot" ),
227 &m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE],
false);
228 pConf->Read(_T (
"CAPEPlot" ), &m_bDataPlot[GribOverlaySettings::CAPE],
230 pConf->Read(_T (
"CompReflectivityPlot" ),
231 &m_bDataPlot[GribOverlaySettings::COMP_REFL],
false);
233 pConf->Read(_T (
"CursorDataShown" ), &m_CDataIsShown,
true);
235 pConf->Read(_T (
"lastdatatype" ), &m_lastdatatype, 0);
237 pConf->SetPath(_T (
"/Settings/GRIB/FileNames" ));
238 m_file_names.Clear();
239 if (pConf->GetNumberOfEntries()) {
242 bool bCont = pConf->GetFirstEntry(str, dummy);
244 pConf->Read(str, &val);
245 m_file_names.Add(val);
246 bCont = pConf->GetNextEntry(str, dummy);
250 wxStandardPathsBase &spath = wxStandardPaths::Get();
252 pConf->SetPath(_T (
"/Directories" ));
253 pConf->Read(_T (
"GRIBDirectory" ), &m_grib_dir);
255 pConf->SetPath(_T(
"/PlugIns/GRIB" ));
259 pConf->SetPath(_T (
"/Settings/GRIB/XyGrib" ));
260 pConf->Read(_T(
"AtmModelIndex" ), &xyGribConfig.atmModelIndex, 0);
261 pConf->Read(_T(
"WaveModelIndex" ), &xyGribConfig.waveModelIndex, 0);
262 pConf->Read(_T(
"ResolutionIndex" ), &xyGribConfig.resolutionIndex, 0);
263 pConf->Read(_T(
"DurationIndex" ), &xyGribConfig.durationIndex, 0);
264 pConf->Read(_T(
"RunIndex" ), &xyGribConfig.runIndex, 0);
265 pConf->Read(_T(
"IntervalIndex" ), &xyGribConfig.intervalIndex, 0);
266 pConf->Read(_T(
"Wind" ), &xyGribConfig.wind,
true);
267 pConf->Read(_T(
"Gust" ), &xyGribConfig.gust,
true);
268 pConf->Read(_T(
"Pressure" ), &xyGribConfig.pressure,
false);
269 pConf->Read(_T(
"Temperature" ), &xyGribConfig.temperature,
true);
270 pConf->Read(_T(
"Cape" ), &xyGribConfig.cape,
false);
271 pConf->Read(_T(
"Reflectivity" ), &xyGribConfig.reflectivity,
false);
272 pConf->Read(_T(
"CloudCover" ), &xyGribConfig.cloudCover,
true);
273 pConf->Read(_T(
"Precipitation" ), &xyGribConfig.precipitation,
true);
274 pConf->Read(_T(
"WaveHeight" ), &xyGribConfig.waveHeight,
true);
275 pConf->Read(_T(
"WindWaves" ), &xyGribConfig.windWaves,
true);
281 m_tPlayStop.Connect(wxEVT_TIMER,
282 wxTimerEventHandler(GRIBUICtrlBar::OnPlayStopTimer),
285 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICtrlBar::OnMove));
287 m_OverlaySettings.Read();
292 SetMinSize(GetBestSize());
293 if (m_ProjectBoatPanel) {
294 m_ProjectBoatPanel->SetSpeed(pPlugIn->m_boat_sog);
295 m_ProjectBoatPanel->SetCourse(pPlugIn->m_boat_cog);
297 m_highlight_latmax = 0;
298 m_highlight_lonmax = 0;
299 m_highlight_latmin = 0;
300 m_highlight_lonmin = 0;
302#ifndef __OCPN__ANDROID__
308 createRequestDialog();
312GRIBUICtrlBar::~GRIBUICtrlBar() {
317 pConf->SetPath(_T (
"/Settings/GRIB" ));
318 pConf->Write(_T (
"WindPlot" ), m_bDataPlot[GribOverlaySettings::WIND]);
319 pConf->Write(_T (
"WindGustPlot" ),
320 m_bDataPlot[GribOverlaySettings::WIND_GUST]);
321 pConf->Write(_T (
"PressurePlot" ),
322 m_bDataPlot[GribOverlaySettings::PRESSURE]);
323 pConf->Write(_T (
"WavePlot" ), m_bDataPlot[GribOverlaySettings::WAVE]);
324 pConf->Write(_T (
"CurrentPlot" ),
325 m_bDataPlot[GribOverlaySettings::CURRENT]);
326 pConf->Write(_T (
"PrecipitationPlot" ),
327 m_bDataPlot[GribOverlaySettings::PRECIPITATION]);
328 pConf->Write(_T (
"CloudPlot" ), m_bDataPlot[GribOverlaySettings::CLOUD]);
329 pConf->Write(_T (
"AirTemperaturePlot" ),
330 m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE]);
331 pConf->Write(_T (
"SeaTemperaturePlot" ),
332 m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE]);
333 pConf->Write(_T (
"CAPEPlot" ), m_bDataPlot[GribOverlaySettings::CAPE]);
334 pConf->Write(_T (
"CompReflectivityPlot" ),
335 m_bDataPlot[GribOverlaySettings::COMP_REFL]);
337 pConf->Write(_T (
"CursorDataShown" ), m_CDataIsShown);
339 pConf->Write(_T (
"lastdatatype" ), m_lastdatatype);
341 pConf->SetPath(_T (
"/Settings/GRIB/FileNames" ));
342 int iFileMax = pConf->GetNumberOfEntries();
346 for (
int i = 0; i < iFileMax; i++) {
347 if (pConf->GetFirstEntry(key, dummy)) pConf->DeleteEntry(key,
false);
351 for (
unsigned int i = 0; i <
m_file_names.GetCount(); i++) {
353 key.Printf(_T(
"Filename%d"), i);
357 pConf->SetPath(_T (
"/Directories" ));
358 pConf->Write(_T (
"GRIBDirectory" ),
m_grib_dir);
361 pConf->SetPath(_T (
"/Settings/GRIB/XyGrib" ));
362 pConf->Write(_T(
"AtmModelIndex" ), xyGribConfig.atmModelIndex);
363 pConf->Write(_T(
"WaveModelIndex" ), xyGribConfig.waveModelIndex);
364 pConf->Write(_T(
"ResolutionIndex" ), xyGribConfig.resolutionIndex);
365 pConf->Write(_T(
"DurationIndex" ), xyGribConfig.durationIndex);
366 pConf->Write(_T(
"RunIndex" ), xyGribConfig.runIndex);
367 pConf->Write(_T(
"IntervalIndex" ), xyGribConfig.intervalIndex);
368 pConf->Write(_T(
"Wind" ), xyGribConfig.wind);
369 pConf->Write(_T(
"Gust" ), xyGribConfig.gust);
370 pConf->Write(_T(
"Pressure" ), xyGribConfig.pressure);
371 pConf->Write(_T(
"Temperature" ), xyGribConfig.temperature);
372 pConf->Write(_T(
"Cape" ), xyGribConfig.cape);
373 pConf->Write(_T(
"Reflectivity" ), xyGribConfig.reflectivity);
374 pConf->Write(_T(
"CloudCover" ), xyGribConfig.cloudCover);
375 pConf->Write(_T(
"Precipitation" ), xyGribConfig.precipitation);
376 pConf->Write(_T(
"WaveHeight" ), xyGribConfig.waveHeight);
377 pConf->Write(_T(
"WindWaves" ), xyGribConfig.windWaves);
383void GRIBUICtrlBar::SetScaledBitmap(
double factor) {
385 m_ScaledFactor = wxRound(factor * 4.0) / 4.0;
387 m_bpPrev->SetBitmapLabel(
388 GetScaledBitmap(wxBitmap(prev), _T(
"prev"), m_ScaledFactor));
389 m_bpNext->SetBitmapLabel(
390 GetScaledBitmap(wxBitmap(next), _T(
"next"), m_ScaledFactor));
391 m_bpAltitude->SetBitmapLabel(
392 GetScaledBitmap(wxBitmap(altitude), _T(
"altitude"), m_ScaledFactor));
393 m_bpNow->SetBitmapLabel(
394 GetScaledBitmap(wxBitmap(now), _T(
"now"), m_ScaledFactor));
395 m_bpZoomToCenter->SetBitmapLabel(
396 GetScaledBitmap(wxBitmap(zoomto), _T(
"zoomto"), m_ScaledFactor));
397 m_bpPlay->SetBitmapLabel(
398 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
399 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(
400 wxBitmap(m_CDataIsShown ? curdata : ncurdata),
401 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"), m_ScaledFactor));
403 m_bpOpenFile->SetBitmapLabel(
404 GetScaledBitmap(wxBitmap(openfile), _T(
"openfile"), m_ScaledFactor));
405 m_bpSettings->SetBitmapLabel(
406 GetScaledBitmap(wxBitmap(setting), _T(
"setting"), m_ScaledFactor));
412#ifdef __OCPN__ANDROID__
413 m_sTimeline->SetSize(wxSize(20 * m_ScaledFactor, -1));
414 m_sTimeline->SetMinSize(wxSize(20 * m_ScaledFactor, -1));
416 m_sTimeline->SetSize(wxSize(90 * m_ScaledFactor, -1));
417 m_sTimeline->SetMinSize(wxSize(90 * m_ScaledFactor, -1));
422 if (
nullptr == m_bpRequest)
return;
423 m_bpRequest->SetBitmapLabel(
424 GetScaledBitmap(wxBitmap(request), _T(
"request"), m_ScaledFactor));
425 m_bpRequest->SetToolTip(_(
"Start a download request"));
428void GRIBUICtrlBar::OpenFile(
bool newestFile) {
429 m_bpPlay->SetBitmapLabel(
430 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
431 m_cRecordForecast->Clear();
432 pPlugIn->GetGRIBOverlayFactory()->ClearParticles();
438 m_sTimeline->SetValue(0);
440 m_InterpolateMode =
false;
442 m_SelectionIsSaved =
false;
443 m_HasAltitude =
false;
464 title = (_(
"File: "));
465 title.Append(fn.GetFullName());
466 if (rsa->GetCount() == 0) {
469 title.Prepend(_(
"Error! ")).Append(_(
" contains no valid data!"));
471 PopulateComboDataList();
477 if (rsa->GetCount() > 1) {
479 &last = rsa->Item(rsa->GetCount() - 1);
482 wxTimeSpan span = wxDateTime(last.m_Reference_Time) -
484 m_TimeLineHours = span.GetHours();
487 int halfintermin(wxTimeSpan(wxDateTime(second.m_Reference_Time) -
491 for (m_FileIntervalIndex = 0;; m_FileIntervalIndex++) {
496 if (m_FileIntervalIndex > 0) m_FileIntervalIndex--;
504 title = _(
"No valid GRIB file");
506 pPlugIn->GetGRIBOverlayFactory()->SetMessage(title);
508 SetTimeLineMax(
false);
510 if (
pPlugIn->GetStartOptions() &&
511 m_TimeLineHours != 0)
512 ComputeBestForecastForNow();
518 for (
int i = 1; i < 5; i++) {
523 m_HasAltitude =
true;
528#ifdef __OCPN__ANDROID__
529 m_bpSettings->Enable(
true);
535 m_sTimeline->Enable(
m_pTimelineSet !=
nullptr && m_TimeLineHours);
554 bool bconfigOK =
false;
555 if (m_bDataPlot[GribOverlaySettings::WIND] &&
558 if (m_bDataPlot[GribOverlaySettings::WIND_GUST] &&
561 if (m_bDataPlot[GribOverlaySettings::PRESSURE] &&
564 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
567 if (m_bDataPlot[GribOverlaySettings::WAVE] &&
570 if (m_bDataPlot[GribOverlaySettings::CURRENT] &&
574 if (m_bDataPlot[GribOverlaySettings::PRECIPITATION] &&
577 if (m_bDataPlot[GribOverlaySettings::CLOUD] &&
580 if (m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE] &&
583 if (m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE] &&
586 if (m_bDataPlot[GribOverlaySettings::CAPE] &&
589 if (m_bDataPlot[GribOverlaySettings::COMP_REFL] &&
596 for (
int i = 0; i < (int)GribOverlaySettings::GEO_ALTITUDE; i++) {
598 m_bDataPlot[i] =
true;
605 double *latmin,
double *latmax,
606 double *lonmin,
double *lonmax) {
609 double ltmi = -GRIB_NOTDEF, ltma = GRIB_NOTDEF, lnmi = -GRIB_NOTDEF,
611 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
614 if (pGRA->getLatMin() < ltmi) ltmi = pGRA->getLatMin();
615 if (pGRA->getLatMax() > ltma) ltma = pGRA->getLatMax();
616 if (pGRA->getLonMin() < lnmi) lnmi = pGRA->getLonMin();
617 if (pGRA->getLonMax() > lnma) lnma = pGRA->getLonMax();
619 if (ltmi == -GRIB_NOTDEF || lnmi == -GRIB_NOTDEF || ltma == GRIB_NOTDEF ||
623 if (latmin) *latmin = ltmi;
624 if (latmax) *latmax = ltma;
625 if (lonmin) *lonmin = lnmi;
626 if (lonmax) *lonmax = lnma;
633 : m_files(files), m_pattern(pattern) {}
634 virtual wxDirTraverseResult OnFile(
const wxString &filename) {
635 if (m_pattern.Matches(filename)) m_files.Add(filename);
636 return wxDIR_CONTINUE;
638 virtual wxDirTraverseResult OnDir(
const wxString &WXUNUSED(dirname)) {
643 wxArrayString &m_files;
644 const wxRegEx &m_pattern;
647wxArrayString GRIBUICtrlBar::GetFilesInDirectory() {
648 wxArrayString file_array;
649 if (!wxDir::Exists(
m_grib_dir))
return file_array;
653 wxRegEx pattern(_T(
".+\\.gri?b2?(\\.(bz2|gz))?$"),
654 wxRE_EXTENDED | wxRE_ICASE | wxRE_NOSUB);
657 dir.Traverse(collector);
659 CompareFileStringTime);
663void GRIBUICtrlBar::SetCursorLatLon(
double lat,
double lon) {
667 if (m_vpMouse && ((lat > m_vpMouse->
lat_min) && (lat < m_vpMouse->lat_max)) &&
668 ((lon > m_vpMouse->
lon_min) && (lon < m_vpMouse->lon_max)))
673 if (!m_CDataIsShown)
return;
675 if (m_DialogStyle >> 1 == SEPARATED) {
676 if (m_gGRIBUICData) {
677 if (!m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.IsRunning())
678 m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.Start(
679 50, wxTIMER_ONE_SHOT);
683 if (!m_gCursorData->m_tCursorTrackTimer.IsRunning())
684 m_gCursorData->m_tCursorTrackTimer.Start(50, wxTIMER_ONE_SHOT);
689void GRIBUICtrlBar::OnShowCursorData(wxCommandEvent &event) {
690 m_CDataIsShown = !m_CDataIsShown;
691 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(
692 wxBitmap(m_CDataIsShown ? curdata : ncurdata),
693 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"), m_ScaledFactor));
694 SetDialogsStyleSizePosition(
true);
697void GRIBUICtrlBar::SetDialogsStyleSizePosition(
bool force_recompute) {
702 if (!force_recompute &&
703 (m_old_DialogStyle == m_DialogStyle
705 (m_old_DialogStyle >> 1 == ATTACHED && m_DialogStyle >> 1 == ATTACHED)))
708 bool m_HasCaption = GetWindowStyleFlag() == (wxCAPTION | wxCLOSE_BOX |
709 wxSYSTEM_MENU | wxTAB_TRAVERSAL);
714 int state = (m_DialogStyle >> 1 == ATTACHED && m_CDataIsShown) ? 0 : 1;
717 bool vis = i > 0 ? true : m_HasAltitude ? true :
false;
718 if (FindWindow(i + ID_CTRLALTITUDE))
719 FindWindow(i + ID_CTRLALTITUDE)
725 m_bpShowCursorData->SetToolTip(m_CDataIsShown ? _(
"Hide data at cursor")
726 : _(
"Show data at cursor"));
727 m_bpPlay->SetToolTip(_(
"Start play back"));
732 m_gCursorData->Hide();
733 m_fgCDataSizer->Detach(m_gCursorData);
736 SetMinSize(wxSize(0, 0));
740 if (m_gGRIBUICData) {
741 m_gGRIBUICData->Destroy();
742 m_gGRIBUICData =
nullptr;
745 if ((m_DialogStyle >> 1 == SEPARATED || !m_CDataIsShown) &&
752 if (m_CDataIsShown) {
753 if (m_DialogStyle >> 1 == ATTACHED) {
755 if (!m_gCursorData) m_gCursorData =
new CursorData(
this, *
this);
756 pPlugIn->SetDialogFont(m_gCursorData);
757 m_gCursorData->PopulateTrackingControls(
false);
759 if (m_fgCDataSizer->GetItem(m_gCursorData) ==
nullptr)
760 m_fgCDataSizer->Add(m_gCursorData, 0);
761 m_gCursorData->Show();
763 }
else if (m_DialogStyle >> 1 == SEPARATED) {
766 m_gGRIBUICData->m_gCursorData->PopulateTrackingControls(
767 m_DialogStyle == SEPARATED_VERTICAL);
768 pPlugIn->SetDialogFont(m_gGRIBUICData->m_gCursorData);
769 m_gGRIBUICData->Fit();
770 m_gGRIBUICData->Update();
771 m_gGRIBUICData->Show();
773 m_gGRIBUICData->Layout();
774 m_gGRIBUICData->Fit();
779 wxSize sd = GetSize();
781 if (!m_gtk_started && m_HasCaption ) {
783 m_gtk_started =
true;
786 SetSize(wxSize(sd.x, sd.y));
787 SetMinSize(wxSize(sd.x, sd.y));
788#ifdef __OCPN__ANDROID__
794 wxPoint pNew =
pPlugIn->GetCtrlBarXY();
795 pNew.x = tbRect.x + tbRect.width + 4;
803 if (sd.x > widthAvail) {
806 int target_char_width = (float)widthAvail / 28;
815 wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
817 dc.GetTextExtent(_T(
"W"), &width, &height,
nullptr,
nullptr, sFont);
818 if (width <= target_char_width) bOK =
true;
820 if (pointSize <= 10) bOK =
true;
823 m_cRecordForecast->SetFont(*sFont);
828 SetSize(wxSize(widthAvail, sd.y));
829 SetMinSize(wxSize(widthAvail, sd.y));
833 wxPoint pNow =
pPlugIn->GetCtrlBarXY();
840 m_old_DialogStyle = m_DialogStyle;
843void GRIBUICtrlBar::OnAltitude(wxCommandEvent &event) {
844 if (!m_HasAltitude)
return;
846 wxMenu *amenu =
new wxMenu();
847 amenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
848 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
this);
850 for (
int i = 0; i < 5; i++) {
858 amenu, ID_CTRLALTITUDE + 1000 + i,
867 amenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
874void GRIBUICtrlBar::OnMove(wxMoveEvent &event) {
876 GetScreenPosition(&w, &h);
877 pPlugIn->SetCtrlBarXY(wxPoint(w, h));
880void GRIBUICtrlBar::OnMenuEvent(wxMenuEvent &event) {
881 int id =
event.GetId();
884 int alt = m_Altitude;
887 case ID_CTRLALTITUDE + 1000:
890 case ID_CTRLALTITUDE + 1001:
893 case ID_CTRLALTITUDE + 1002:
896 case ID_CTRLALTITUDE + 1003:
899 case ID_CTRLALTITUDE + 1004:
907 OnZoomToCenterClick(evt);
909 case ID_BTNSHOWCDATA:
910 OnShowCursorData(evt);
922 OnRequestForecastData(evt);
924 if (alt != m_Altitude) {
925 SetDialogsStyleSizePosition(
true);
930void GRIBUICtrlBar::MenuAppend(wxMenu *menu,
int id, wxString label,
931 wxItemKind kind, wxBitmap bitmap,
933 wxMenuItem *item =
new wxMenuItem(menu,
id, label, _T(
""), kind);
936 item->SetSubMenu(submenu);
946#if defined(__WXMSW__) || defined(__WXGTK__)
947 if (!bitmap.IsSameAs(wxNullBitmap)) item->SetBitmap(bitmap);
953void GRIBUICtrlBar::OnMouseEvent(wxMouseEvent &event) {
954 if (event.RightDown()) {
956 wxMenu *xmenu =
new wxMenu();
957 xmenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
958 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
962 wxMenu *smenu =
new wxMenu();
963 smenu->Connect(wxEVT_COMMAND_MENU_SELECTED,
964 wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent),
nullptr,
967 for (
int i = 0; i < 5; i++) {
975 smenu, ID_CTRLALTITUDE + 1000 + i,
982 smenu->Check(ID_CTRLALTITUDE + 1000 + m_Altitude,
true);
984 xmenu, wxID_ANY, _(
"Select geopotential altitude"), wxITEM_NORMAL,
985 GetScaledBitmap(wxBitmap(altitude), _T(
"altitude"), m_ScaledFactor),
988 MenuAppend(xmenu, ID_BTNNOW, _(
"Now"), wxITEM_NORMAL,
989 GetScaledBitmap(wxBitmap(now), _T(
"now"), m_ScaledFactor));
990 MenuAppend(xmenu, ID_BTNZOOMTC, _(
"Zoom To Center"), wxITEM_NORMAL,
991 GetScaledBitmap(wxBitmap(zoomto), _T(
"zoomto"), m_ScaledFactor));
993 xmenu, ID_BTNSHOWCDATA,
994 m_CDataIsShown ? _(
"Hide data at cursor") : _(
"Show data at cursor"),
996 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
997 m_CDataIsShown ? _T(
"curdata") : _T(
"ncurdata"),
1001 m_tPlayStop.IsRunning() ? _(
"Stop play back") : _(
"Start play back"),
1003 GetScaledBitmap(wxBitmap(
m_tPlayStop.IsRunning() ? stop : play),
1004 m_tPlayStop.IsRunning() ? _T(
"stop") : _T(
"play"),
1007 xmenu, ID_BTNOPENFILE, _(
"Open a new file"), wxITEM_NORMAL,
1008 GetScaledBitmap(wxBitmap(openfile), _T(
"openfile"), m_ScaledFactor));
1010 xmenu, ID_BTNSETTING, _(
"Settings"), wxITEM_NORMAL,
1011 GetScaledBitmap(wxBitmap(setting), _T(
"setting"), m_ScaledFactor));
1017 requeststate1 ? _(
"Request forecast data")
1019 ? _(
"Draw requested Area or Click here to stop request")
1020 : _(
"Valid Area and Continue"),
1022 GetScaledBitmap(wxBitmap(requeststate1 ? request
1023 : requeststate3 ? selzone
1025 requeststate1 ? _T(
"request")
1026 : requeststate3 ? _T(
"selzone")
1027 : _T(
"request_end"),
1037 if (m_DialogStyle >> 1 == SEPARATED)
return;
1038 wxMouseEvent evt(event);
1041#ifndef __OCPN__ANDROID__
1042 if (m_gCursorData && m_CDataIsShown) {
1043 m_gCursorData->OnMouseEvent(evt);
1048void GRIBUICtrlBar::ContextMenuItemCallback(
int id) {
1050 bool dataisshown = m_CDataIsShown;
1051 m_CDataIsShown =
false;
1064 m_CDataIsShown = dataisshown;
1069 if (m_vpMouse == vp)
return;
1081void GRIBUICtrlBar::OnClose(wxCloseEvent &event) {
1083 if (m_gGRIBUICData) m_gGRIBUICData->Hide();
1086 pReq_Dialog->StopGraphicalZoneSelection();
1090 pPlugIn->SendTimelineMessage(wxInvalidDateTime);
1092 pPlugIn->OnGribCtrlBarClose();
1095void GRIBUICtrlBar::OnSize(wxSizeEvent &event) {
1097 wxSize p =
event.GetSize();
1103void GRIBUICtrlBar::OnPaint(wxPaintEvent &event) {
1104 wxWindowListNode *node = this->GetChildren().GetFirst();
1107 wxWindow *win = node->GetData();
1108 if (
dynamic_cast<wxBitmapButton *
>(win))
1109 dc.DrawBitmap(
dynamic_cast<wxBitmapButton *
>(win)->GetBitmap(), 5, 5,
1111 node = node->GetNext();
1115void GRIBUICtrlBar::createRequestDialog() {
1116 ::wxBeginBusyCursor();
1121 pPlugIn->SetDialogFont(pReq_Dialog);
1122 pPlugIn->SetDialogFont(pReq_Dialog->m_sScrolledDialog);
1124 pReq_Dialog->SetRequestDialogSize();
1125 if (::wxIsBusy()) ::wxEndBusyCursor();
1128void GRIBUICtrlBar::OnRequestForecastData(wxCommandEvent &event) {
1133 if (pReq_Dialog && pReq_Dialog->IsShown())
return;
1136 createRequestDialog();
1139 ::wxDisplaySize(&w,
nullptr);
1140 pReq_Dialog->Move((w - pReq_Dialog->GetSize().GetX()) / 2, 30);
1141 pReq_Dialog->Show();
1146void GRIBUICtrlBar::OnSettings(wxCommandEvent &event) {
1150 ::wxBeginBusyCursor();
1156 pPlugIn->SetDialogFont(dialog);
1157 for (
size_t i = 0; i < dialog->m_nSettingsBook->GetPageCount(); i++) {
1158 wxScrolledWindow *sc =
1159 ((wxScrolledWindow *)dialog->m_nSettingsBook->GetPage(i));
1163 dialog->m_nSettingsBook->ChangeSelection(dialog->GetPageIndex());
1164 dialog->SetSettingsDialogSize();
1167 ::wxDisplaySize(&w,
nullptr);
1168 dialog->Move((w - dialog->GetSize().GetX()) / 2, 30);
1171 ::wxEndBusyCursor();
1173 if (dialog->ShowModal() == wxID_OK) {
1174 dialog->WriteSettings();
1177 initSettings.Settings[GribOverlaySettings::WIND].m_Units &&
1179 GribOverlaySettings::BFS ||
1180 initSettings.Settings[GribOverlaySettings::WIND].m_Units ==
1181 GribOverlaySettings::BFS))
1183 STARTING_STATE_STYLE;
1187 m_DialogStyle = initSettings.m_iCtrlandDataStyle;
1189 ::wxBeginBusyCursor();
1191 dialog->SaveLastPage();
1193 m_InterpolateMode =
false;
1194 SetTimeLineMax(
true);
1195 SetFactoryOptions();
1197 SetDialogsStyleSizePosition(
true);
1203#ifdef __OCPN__ANDROID__
1204wxString callActivityMethod_ss(
const char *method, wxString parm);
1207void GRIBUICtrlBar::OnCompositeDialog(wxCommandEvent &event) {
1210 initSettings.Read();
1213 wxString json_begin = initSettings.SettingsToJSON(json);
1214 wxLogMessage(json_begin);
1223 double lon_min = wxRound(current_vp.
lon_min) - 1;
1224 double lon_max = wxRound(current_vp.
lon_max) + 1;
1225 double lat_min = wxRound(current_vp.
lat_min) - 1;
1226 double lat_max = wxRound(current_vp.
lat_max) + 1;
1230 int numErrors = reader.
Parse(json_begin, &v);
1231 if (numErrors > 0) {
1235 v[_T(
"latMin")] = lat_min;
1236 v[_T(
"latMax")] = lat_max;
1237 v[_T(
"lonMin")] = lon_min;
1238 v[_T(
"lonMax")] = lon_max;
1242 v[_T(
"grib_file")] = _T(
"");
1245 wxString json_final;
1246 w.
Write(v, json_final);
1247 wxLogMessage(json_final);
1249#ifdef __OCPN__ANDROID__
1250 wxString ret = callActivityMethod_ss(
"doGRIBActivity", json_final);
1257void GRIBUICtrlBar::OpenFileFromJSON(wxString json) {
1263 int numErrors = reader.
Parse(json, &root);
1264 if (numErrors > 0) {
1268 wxString file = root[(_T(
"grib_file"))].AsString();
1270 if (file.Length() && wxFileExists(file)) {
1271 wxFileName fn(file);
1279void GRIBUICtrlBar::OnPlayStop(wxCommandEvent &event) {
1283 m_bpPlay->SetBitmapLabel(
1284 GetScaledBitmap(wxBitmap(stop), _T(
"stop"), m_ScaledFactor));
1285 m_bpPlay->SetToolTip(_(
"Stop play back"));
1287 wxTIMER_CONTINUOUS);
1292void GRIBUICtrlBar::OnPlayStopTimer(wxTimerEvent &event) {
1293 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax()) {
1296 ComputeBestForecastForNow();
1297 if (m_sTimeline->GetValue() >= m_sTimeline->GetMax())
1301 m_sTimeline->SetValue(0);
1308 ? GetNearestValue(GetNow(), 1)
1309 : GetNearestIndex(GetNow(), 2)
1310 : m_sTimeline->GetValue();
1311 m_sTimeline->SetValue(value + 1);
1315 if (!m_InterpolateMode)
1316 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1320void GRIBUICtrlBar::StopPlayBack() {
1323 m_bpPlay->SetBitmapLabel(
1324 GetScaledBitmap(wxBitmap(play), _T(
"play"), m_ScaledFactor));
1325 m_bpPlay->SetToolTip(_(
"Start play back"));
1329void GRIBUICtrlBar::TimelineChanged() {
1331 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1335 RestaureSelectionString();
1341 if (!m_InterpolateMode) {
1344 GribRecordSet &sel = rsa->Item(m_cRecordForecast->GetCurrentSelection());
1347 ? wxTimeSpan(t - MinTime()).GetMinutes() /
1350 : m_cRecordForecast->GetCurrentSelection());
1352 m_cRecordForecast->SetSelection(GetNearestIndex(time, 2));
1353 SaveSelectionString();
1355 m_cRecordForecast->SetString(m_Selection_index,
1358 m_cRecordForecast->SetStringSelection(
1364 pPlugIn->SendTimelineMessage(time);
1368void GRIBUICtrlBar::RestaureSelectionString() {
1369 if (!m_SelectionIsSaved)
return;
1371 int sel = m_cRecordForecast->GetSelection();
1372 m_cRecordForecast->SetString(m_Selection_index, m_Selection_label);
1373 m_cRecordForecast->SetSelection(sel);
1374 m_SelectionIsSaved =
false;
1377int GRIBUICtrlBar::GetNearestIndex(wxDateTime time,
int model) {
1382 wxDateTime itime, ip1time;
1383 for (i = 0; i < rsa->GetCount() - 1; i++) {
1384 itime = rsa->Item(i).m_Reference_Time;
1385 ip1time = rsa->Item(i + 1).m_Reference_Time;
1386 if (ip1time >= time)
break;
1388 if (!model)
return (time - itime > (ip1time - time) * 3) ? i + 1 : i;
1390 return model == 1 ? time == ip1time ? i : i + 1 : time == ip1time ? i + 1 : i;
1393int GRIBUICtrlBar::GetNearestValue(wxDateTime time,
int model) {
1395 if (m_TimeLineHours == 0)
return 0;
1396 wxDateTime itime, ip1time;
1399 wxTimeSpan span = time - MinTime();
1400 int t = span.GetMinutes() / stepmin;
1402 wxTimeSpan(t * stepmin / 60, (t * stepmin) % 60);
1403 ip1time = itime + wxTimeSpan(stepmin / 60, stepmin % 60);
1405 if (model == 1)
return time == ip1time ? t + 1 : t;
1407 return (time - itime > (ip1time - time) * 3) ? t + 1 : t;
1410wxDateTime GRIBUICtrlBar::GetNow() {
1411 wxDateTime now = wxDateTime::Now();
1417 now = (now > rsa->Item(rsa->GetCount() - 1).m_Reference_Time)
1418 ? rsa->Item(rsa->GetCount() - 1).m_Reference_Time
1419 : (now < rsa->Item(0).m_Reference_Time) ? rsa->Item(0).m_Reference_Time
1425 if (m_InterpolateMode) {
1426 int tl = (m_TimeLineHours == 0) ? 0 : m_sTimeline->GetValue();
1429 return MinTime() + wxTimeSpan(tl * stepmin / 60, (tl * stepmin) % 60);
1433 unsigned int index = m_cRecordForecast->GetCurrentSelection() < 1
1435 : m_cRecordForecast->GetCurrentSelection();
1436 if (rsa && index < rsa->GetCount())
return rsa->Item(index).m_Reference_Time;
1438 return wxDateTime::Now();
1441wxDateTime GRIBUICtrlBar::MinTime() {
1443 if (rsa && rsa->GetCount()) {
1447 return wxDateTime::Now();
1454 if (rsa->GetCount() == 0)
return nullptr;
1461 wxDateTime GR1time, GR2time;
1467 for (j = 0; j < rsa->GetCount(); j++) {
1473 if (curtime <= time) GR1time = curtime, GRS1 = GRS, GR1 = GR;
1475 if (curtime >= time) {
1476 GR2time = curtime, GRS2 = GRS, GR2 = GR;
1481 if (!GR1 || !GR2)
continue;
1483 wxDateTime mintime = MinTime();
1484 double minute2 = (GR2time - mintime).GetMinutes();
1485 double minute1 = (GR1time - mintime).GetMinutes();
1486 double nminute = (time - mintime).GetMinutes();
1488 if (minute2 < minute1 || nminute < minute1 || nminute > minute2)
continue;
1490 double interp_const;
1491 if (minute1 == minute2) {
1496 interp_const = (nminute - minute1) / (minute2 - minute1);
1527 *GR1, *GR2, interp_const, i ==
Idx_WVDIR));
1538 auto sog = m_ProjectBoatPanel->GetSpeed();
1539 auto cog = m_ProjectBoatPanel->GetCourse();
1541 static_cast<double>(now.GetTicks() -
pPlugIn->m_boat_time) * sog / 3600.0;
1543 pPlugIn->m_boat_lon, cog, dist,
1544 &m_projected_lat, &m_projected_lon);
1552double GRIBUICtrlBar::getTimeInterpolatedValue(
int idx,
double lon,
double lat,
1557 if (rsa->GetCount() == 0)
return GRIB_NOTDEF;
1559 GribRecord *before =
nullptr, *after =
nullptr;
1562 time_t t = time.GetTicks();
1563 for (j = 0; j < rsa->GetCount(); j++) {
1568 time_t curtime = GR->getRecordCurrentDate();
1571 if (curtime < t) before = GR;
1579 if (!before || !after)
return GRIB_NOTDEF;
1581 time_t t1 = before->getRecordCurrentDate();
1582 time_t t2 = after->getRecordCurrentDate();
1586 double v2 = after->getInterpolatedValue(lon, lat);
1587 if (v1 != GRIB_NOTDEF && v2 != GRIB_NOTDEF) {
1588 double k = fabs((
double)(t - t1) / (t2 - t1));
1589 return (1.0 - k) * v1 + k * v2;
1595bool GRIBUICtrlBar::getTimeInterpolatedValues(
double &M,
double &A,
int idx1,
1596 int idx2,
double lon,
double lat,
1604 if (rsa->GetCount() == 0)
return false;
1606 GribRecord *beforeX =
nullptr, *afterX =
nullptr;
1607 GribRecord *beforeY =
nullptr, *afterY =
nullptr;
1610 time_t t = time.GetTicks();
1611 for (j = 0; j < rsa->GetCount(); j++) {
1615 if (!GX || !GY)
continue;
1617 time_t curtime = GX->getRecordCurrentDate();
1632 if (!beforeX || !afterX)
return false;
1634 time_t t1 = beforeX->getRecordCurrentDate();
1635 time_t t2 = afterX->getRecordCurrentDate();
1640 double v1m, v2m, v1a, v2a;
1649 if (v1m == GRIB_NOTDEF || v2m == GRIB_NOTDEF || v1a == GRIB_NOTDEF ||
1653 double k = fabs((
double)(t - t1) / (t2 - t1));
1654 M = (1.0 - k) * v1m + k * v2m;
1655 A = (1.0 - k) * v1a + k * v2a;
1659void GRIBUICtrlBar::OnTimeline(wxScrollEvent &event) {
1662 if (!m_InterpolateMode)
1663 m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1668void GRIBUICtrlBar::OnOpenFile(wxCommandEvent &event) {
1672#ifndef __OCPN__ANDROID__
1674 wxStandardPathsBase &path = wxStandardPaths::Get();
1675 wxString l_grib_dir = path.GetDocumentsDir();
1679 wxFileDialog *dialog =
1680 new wxFileDialog(
nullptr, _(
"Select a GRIB file"), l_grib_dir, _T(
""),
1682 "(*.grb;*.bz2;*.gz;*.grib2;*.grb2)|*.grb;*.bz2;*.gz;"
1683 "*.grib2;*.grb2|All files (*)|*.*"),
1684 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE,
1685 wxDefaultPosition, wxDefaultSize, _T(
"File Dialog"));
1687 if (dialog->ShowModal() == wxID_OK) {
1688 ::wxBeginBusyCursor();
1694 if (g_pi->m_bZoomToCenterAtInit) DoZoomToCenter();
1696 SetDialogsStyleSizePosition(
true);
1701 wxStandardPathsBase &path = wxStandardPaths::Get();
1707 nullptr, &file, _(
"Select a GRIB file"),
m_grib_dir, _T(
""), _T(
"*.*"));
1709 if (response == wxID_OK) {
1710 wxFileName fn(file);
1715 SetDialogsStyleSizePosition(
true);
1720void GRIBUICtrlBar::CreateActiveFileFromNames(
const wxArrayString &filenames) {
1721 if (filenames.GetCount() != 0) {
1728void GRIBUICtrlBar::PopulateComboDataList() {
1730 if (m_cRecordForecast->GetCount()) {
1731 index = m_cRecordForecast->GetCurrentSelection();
1732 m_cRecordForecast->Clear();
1736 for (
size_t i = 0; i < rsa->GetCount(); i++) {
1737 wxDateTime t(rsa->Item(i).m_Reference_Time);
1740 m_cRecordForecast->SetSelection(index);
1743void GRIBUICtrlBar::OnZoomToCenterClick(wxCommandEvent &event) {
1748 double latmin,latmax,lonmin,lonmax;
1749 if(!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax ))
1755 double width = lonmax - lonmin;
1756 double height = latmax - latmin;
1759 double clat = latmin + height / 2;
1760 double clon = lonmin + width / 2;
1764 lonmin = clon - 60.;
1765 lonmax = clon + 60.;
1768 latmin = clat - 60.;
1769 latmax = clat + 60.;
1779 int w =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetWidth();
1780 int h =
pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetHeight();
1784 ppm = wxMin(w/(ow*1852), h/(oh*1852)) * ( 100 - fabs( clat ) ) / 90;
1786 ppm = wxMin(ppm, 1.0);
1794void GRIBUICtrlBar::DoZoomToCenter() {
1797 double latmin, latmax, lonmin, lonmax;
1798 if (!GetGribZoneLimits(
m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax))
1804 double width = lonmax - lonmin;
1805 double height = latmax - latmin;
1808 double clat = latmin + height / 2;
1809 double clon = lonmin + width / 2;
1813 lonmin = clon - 60.;
1814 lonmax = clon + 60.;
1816 if (height > 120.) {
1817 latmin = clat - 60.;
1818 latmax = clat + 60.;
1826 wxWindow *wx = GetGRIBCanvas();
1828 int w = wx->GetSize().x;
1829 int h = wx->GetSize().y;
1833 ppm = wxMin(w / (ow * 1852), h / (oh * 1852)) * (100 - fabs(clat)) / 90;
1835 ppm = wxMin(ppm, 1.0);
1840void GRIBUICtrlBar::OnPrev(wxCommandEvent &event) {
1844 RestaureSelectionString();
1848 selection = GetNearestIndex(GetNow(), 1);
1849 else if (m_InterpolateMode)
1853 selection = m_cRecordForecast->GetCurrentSelection();
1856 m_InterpolateMode =
false;
1858 m_cRecordForecast->SetSelection(selection < 1 ? 0 : selection - 1);
1863void GRIBUICtrlBar::OnNext(wxCommandEvent &event) {
1867 RestaureSelectionString();
1871 selection = GetNearestIndex(GetNow(), 2);
1872 else if (m_InterpolateMode)
1876 selection = m_cRecordForecast->GetCurrentSelection();
1878 m_cRecordForecast->SetSelection(selection);
1881 m_InterpolateMode =
false;
1883 if (selection == (
int)m_cRecordForecast->GetCount() - 1)
1886 m_cRecordForecast->SetSelection(selection + 1);
1891void GRIBUICtrlBar::ComputeBestForecastForNow() {
1893 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(
nullptr);
1897 wxDateTime now = GetNow();
1900 m_sTimeline->SetValue(GetNearestValue(now, 0));
1902 m_cRecordForecast->SetSelection(GetNearestIndex(now, 0));
1903 m_sTimeline->SetValue(m_cRecordForecast->GetCurrentSelection());
1906 if (
pPlugIn->GetStartOptions() !=
1913 m_InterpolateMode =
true;
1915 SetGribTimelineRecordSet(
1918 RestaureSelectionString();
1920 m_cRecordForecast->SetSelection(GetNearestIndex(now, 2));
1921 SaveSelectionString();
1923 m_cRecordForecast->SetString(m_Selection_index,
1926 m_cRecordForecast->SetStringSelection(nowTime);
1930 pPlugIn->SendTimelineMessage(now);
1934void GRIBUICtrlBar::SetGribTimelineRecordSet(
1939 if (!
pPlugIn->GetGRIBOverlayFactory())
return;
1944void GRIBUICtrlBar::SetTimeLineMax(
bool SetValue) {
1945 int oldmax = wxMax(m_sTimeline->GetMax(), 1),
1946 oldval = m_sTimeline->GetValue();
1951 m_sTimeline->SetMax(m_TimeLineHours * 60 / stepmin);
1955 m_sTimeline->SetMax(rsa->GetCount() - 1);
1960 if (SetValue && m_sTimeline->GetMax() != 0) {
1962 ComputeBestForecastForNow();
1964 m_sTimeline->SetValue(m_sTimeline->GetMax() * oldval / oldmax);
1968void GRIBUICtrlBar::SetFactoryOptions() {
1971 pPlugIn->GetGRIBOverlayFactory()->ClearCachedData();
1977void GRIBUICtrlBar::OnFormatRefreshTimer(wxTimerEvent &event) {
1980 wxDateTime referenceDate(1, wxDateTime::Jan, 2021, 12, 0, 0);
1983 if (currentFormat != m_sLastTimeFormat) {
1985 m_sLastTimeFormat = currentFormat;
1989 PopulateComboDataList();
2003unsigned int GRIBFile::ID = 0;
2009 m_pGribReader =
nullptr;
2010 m_last_message = wxEmptyString;
2011 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
2012 wxString file_name = file_names[i];
2013 if (::wxFileExists(file_name)) m_bOK =
true;
2016 if (m_bOK ==
false) {
2017 m_last_message = _(
" files don't exist!");
2026 for (
unsigned int i = 0; i < file_names.GetCount(); i++) {
2027 file_name = file_names[i];
2028 m_pGribReader->openFile(file_name);
2030 if (m_pGribReader->isOk()) {
2037 if (m_bOK ==
false) {
2038 m_last_message = _(
" can't be read!");
2043 m_FileNames.Clear();
2044 m_FileNames.Add(file_name);
2046 m_FileNames = file_names;
2050 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_TOT, LV_GND_SURF, 0);
2051 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_RATE, LV_GND_SURF, 0);
2052 m_pGribReader->computeAccumulationRecords(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
2060 m_nGribRecords = m_pGribReader->getTotalNumberOfGribRecords();
2064 std::set<time_t>::iterator iter;
2065 std::set<time_t> date_list = m_pGribReader->getListDates();
2066 for (iter = date_list.begin(); iter != date_list.end(); iter++) {
2068 time_t reftime = *iter;
2070 m_GribRecordSetArray.Add(t);
2078 bool polarWind(
false);
2079 bool polarCurrent(
false);
2080 bool sigWave(
false);
2083 std::map<std::string, std::vector<GribRecord *> *> *p_map =
2084 m_pGribReader->getGribMap();
2087 std::map<std::string, std::vector<GribRecord *> *>::iterator it;
2088 for (it = p_map->begin(); it != p_map->end(); it++) {
2089 std::vector<GribRecord *> *ls = (*it).second;
2090 for (zuint i = 0; i < ls->size(); i++) {
2093 time_t thistime = pRec->getRecordCurrentDate();
2096 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2097 if (m_GribRecordSetArray.Item(j).m_Reference_Time == thistime) {
2098 int idx = -1, mdx = -1;
2122 case GRB_WIND_SPEED:
2145 polarCurrent =
true;
2151 polarCurrent =
true;
2183 case GRB_PRECIP_RATE:
2184 case GRB_PRECIP_TOT:
2209 mdx = 1000 + NORWAY_METNO;
2239 case GRB_GEOPOT_HGT:
2265 if (m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx]) {
2268 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2290 if (oRec->
getDataType() == GRB_HTSGW) skip =
true;
2300 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx] = pRec;
2301 if (m_GribIdxArray.Index(idx) == wxNOT_FOUND)
2302 m_GribIdxArray.Add(idx, 1);
2303 if (mdx != -1 && m_GribIdxArray.Index(mdx) == wxNOT_FOUND)
2304 m_GribIdxArray.Add(mdx, 1);
2312 if (polarWind || polarCurrent) {
2313 for (
unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++) {
2314 for (
unsigned int i = 0; i <
Idx_COUNT; i++) {
2318 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2320 if (pRec !=
nullptr && pRec->
getDataType() == GRB_WIND_DIR) {
2342 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2343 if (pRec1 !=
nullptr && pRec1->
getDataType() == GRB_WIND_SPEED)
2351 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[i];
2353 if (pRec !=
nullptr && pRec->
getDataType() == GRB_CUR_DIR) {
2363 m_GribRecordSetArray.Item(j).m_GribRecordPtrArray[idx];
2364 if (pRec1 !=
nullptr && pRec1->
getDataType() == GRB_CUR_SPEED)
2375 pRec->getRecordRefDate();
2378GRIBFile::~GRIBFile() {
delete m_pGribReader; }
2385 :
GRIBUICDataBase(parent.pParent, CURSOR_DATA, _(
"GRIB Display Control"),
2386 wxDefaultPosition, wxDefaultSize,
2387 wxSYSTEM_MENU | wxNO_BORDER | wxSTAY_ON_TOP)
2390 wxDefaultPosition, wxDefaultSize,
2391 wxSYSTEM_MENU | wxNO_BORDER)
2394 m_gpparent(parent) {
2398 m_gCursorData =
new CursorData(
this, m_gpparent);
2399 m_fgCdataSizer->Add(m_gCursorData, 0, wxALL, 0);
2401 Connect(wxEVT_MOVE, wxMoveEventHandler(GRIBUICData::OnMove));
2404void GRIBUICData::OnMove(wxMoveEvent &event) {
2406 GetScreenPosition(&w, &h);
2407 m_gpparent.
pPlugIn->SetCursorDataXY(wxPoint(w, h));
2413#ifdef __OCPN__ANDROID__
2415#include <QtAndroidExtras/QAndroidJniObject>
2417bool CheckPendingJNIException() {
2424 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2429 if ((jenv)->ExceptionCheck() == JNI_TRUE) {
2437wxString callActivityMethod_ss(
const char *method, wxString parm) {
2443 if (CheckPendingJNIException())
return _T(
"NOK");
2445 wxString return_string;
2446 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod(
2447 "org/qtproject/qt5/android/QtNative",
"activity",
2448 "()Landroid/app/Activity;");
2449 if (CheckPendingJNIException())
return _T(
"NOK");
2451 if (!activity.isValid()) {
2453 return return_string;
2458 if (java_vm->GetEnv((
void **)&jenv, JNI_VERSION_1_6) != JNI_OK) {
2460 return "jenv Error";
2463 jstring p = (jenv)->NewStringUTF(parm.c_str());
2469 QAndroidJniObject data = activity.callObjectMethod(
2470 method,
"(Ljava/lang/String;)Ljava/lang/String;", p);
2471 if (CheckPendingJNIException())
return _T(
"NOK");
2475 jstring s = data.object<jstring>();
2477 if ((jenv)->GetStringLength(s)) {
2478 const char *ret_string = (jenv)->GetStringUTFChars(s,
nullptr);
2479 return_string = wxString(ret_string, wxConvUTF8);
2482 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.
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.
wxFileConfig * GetOCPNConfigObject(void)
Gets OpenCPN's configuration object.
void DistanceBearingMercator_Plugin(double lat0, double lon0, double lat1, double lon1, double *brg, double *dist)
Calculates bearing and distance between two points 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...