33#include <wx/wfstream.h>
36#include <unordered_map>
40enum { SAILDOCS, ZYGRIB };
41enum { GFS, COAMPS, RTOFS, HRRR, ICON, ECMWF };
43wxString toMailFormat(
int NEflag,
46 char c = NEflag == 1 ? a < 0 ?
'S' :
'N' : a < 0 ?
'W' :
'E';
48 s.Printf(_T (
"%01d%c" ), abs(a), c);
52extern int m_SavedZoneSelMode;
53extern int m_ZoneSelMode;
64#if defined(__WXOSX__) || defined(__WXGTK3__)
66 m_displayScale = GetContentScaleFactor();
71 m_downloading =
false;
72 m_bTransferSuccess =
true;
75 auto bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)
76 .GetAsString(wxC2S_HTML_SYNTAX);
77 auto fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)
78 .GetAsString(wxC2S_HTML_SYNTAX);
79 m_htmlWinWorld->SetBorders(10);
80 m_htmlWinWorld->SetPage(
81 "<html><body bgcolor="
90 _(
"<h1>OpenCPN ECMWF forecast</h1>"
91 "<p>Free service based on ECMWF Open Data published under the terms of "
92 "Creative Commons CC-4.0-BY license</p>"
93 "<p>The IFS model GRIB files include information about surface "
95 "atmospheric pressure, wind strength, wind direction, wave height and "
96 "direction for the whole world on a 0.25 degree resolution "
98 "step in the first 144 hours and 6 hour step up to 10 days.</p>"
99 "The AIFS model contains data for wind, pressure and temperature on a "
100 "0.25 degree grid with 6 hour step for up to 15 days"
101 "<p>The data is updated twice a day as soon as the 00z and 12z model "
102 "runs finish and the "
103 "results are published by ECMWF, which usually means new forecast data "
104 "is available shortly after 8AM and 8PM UTC.</p>"
105 "<p>The grib downloaded covers the area of the primary chart "
107 "<p>The service is provided on best effort basis and comes with no "
108 "guarantees. The server is hosted by a volunteer and the service is "
109 "provided free of charge and without accepting any liability "
110 "whatsoever for its continuous availability, or for any loss or damage "
111 "arising from its use. If you find the service useful, please "
112 "consider making a donation to the OpenCPN project.</p>"
113 "<p>This service is based on data and products of the European Centre "
114 "for Medium-Range Weather Forecasts (ECMWF).</p>"
115 "<p>Source: www.ecmwf.int</p>"
116 "<p>Disclaimer: ECMWF does not accept any liability whatsoever for any "
117 "error or omission in the data, their availability, or for any loss or "
118 "damage arising from their use.</p>"
119 "</font></body></html>"));
120 m_htmlInfoWin->SetBorders(10);
121 m_htmlInfoWin->SetPage(
122 "<html><body bgcolor="
131 _(
"<h1>Grib weather forecasts</h1>"
132 "<p>Collection of local weather models from various sources available "
133 "for download over the internet.</p>"
134 "</font></body></html>"));
136 m_bLocal_source_selected =
false;
137 EnableDownloadButtons();
139 m_selectedAtmModelIndex = 0;
140 m_selectedWaveModelIndex = 0;
141 InitializeXygribDialog();
144GribRequestSetting::~GribRequestSetting() {
146 OCPN_cancelDownloadFileBackground(m_download_handle);
150 wxEVT_DOWNLOAD_EVENT,
151 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
159void GribRequestSetting::InitRequestConfig() {
160 wxFileConfig *pConf = GetOCPNConfigObject();
163 pConf->SetPath(_T(
"/PlugIns/GRIB" ));
166 pConf->Read(_T(
"MailRequestConfig" ), &m_RequestConfigBase,
167 _T(
"000220XX........0" ));
168 pConf->Read(_T(
"MailSenderAddress" ), &l, _T(
""));
169 m_pSenderAddress->ChangeValue(l);
170 pConf->Read(_T(
"MailRequestAddresses" ), &m_MailToAddresses,
171 _T(
"query@saildocs.com;gribauto@zygrib.org"));
172 pConf->Read(_T(
"ZyGribLogin" ), &l, _T(
""));
173 m_pLogin->ChangeValue(l);
174 pConf->Read(_T(
"ZyGribCode" ), &l, _T(
""));
175 m_pCode->ChangeValue(l);
176 pConf->Read(_T(
"SendMailMethod" ), &m_SendMethod, 0);
177 pConf->Read(_T(
"MovingGribSpeed" ), &m, 0);
178 m_sMovingSpeed->SetValue(m);
179 pConf->Read(_T(
"MovingGribCourse" ), &m, 0);
180 m_sMovingCourse->SetValue(m);
181 m_cManualZoneSel->SetValue(
182 m_SavedZoneSelMode !=
185 m_cUseSavedZone->SetValue(m_SavedZoneSelMode == SAVED_SELECTION);
186 fgZoneCoordinatesSizer->ShowItems(m_SavedZoneSelMode != AUTO_SELECTION);
187 m_cUseSavedZone->Show(m_SavedZoneSelMode != AUTO_SELECTION);
188 if (m_cManualZoneSel->GetValue()) {
189 pConf->Read(_T(
"RequestZoneMaxLat" ), &m, 0);
190 m_spMaxLat->SetValue(m);
191 pConf->Read(_T(
"RequestZoneMinLat" ), &m, 0);
192 m_spMinLat->SetValue(m);
193 pConf->Read(_T(
"RequestZoneMaxLon" ), &m, 0);
194 m_spMaxLon->SetValue(m);
195 pConf->Read(_T(
"RequestZoneMinLon" ), &m, 0);
196 m_spMinLon->SetValue(m);
198 SetCoordinatesText();
202 if (m_RequestConfigBase.Len() !=
203 wxString(_T(
"000220XX.............." )).Len())
204 m_RequestConfigBase = _T(
"000220XX.............." );
207 wxString s1[] = {_T(
"GFS"), _T(
"COAMPS"), _T(
"RTOFS"),
208 _T(
"HRRR"), _T(
"ICON"), _T(
"ECMWF")};
209 for (
unsigned int i = 0; i < (
sizeof(s1) /
sizeof(wxString)); i++)
210 m_pModel->Append(s1[i]);
211 wxString s2[] = {_T(
"Saildocs"), _T(
"zyGrib")};
212 for (
unsigned int i = 0; i < (
sizeof(s2) /
sizeof(wxString)); i++)
213 m_pMailTo->Append(s2[i]);
214 wxString s3[] = {_T(
"WW3-GLOBAL"), _T(
"WW3-MEDIT")};
215 for (
unsigned int i = 0; i < (
sizeof(s3) /
sizeof(wxString)); i++)
216 m_pWModel->Append(s3[i]);
217 m_rButtonYes->SetLabel(_(
"Send"));
218 m_rButtonApply->SetLabel(_(
"Save"));
219 m_tResUnit->SetLabel(wxString::Format(_T(
"\u00B0")));
220 m_sCourseUnit->SetLabel(wxString::Format(_T(
"\u00B0")));
224 GetTextExtent(_T(
"-360"), &w, &h, 0, 0,
228 m_sMovingSpeed->SetMinSize(wxSize(w, h));
229 m_sMovingCourse->SetMinSize(wxSize(w, h));
230 m_spMaxLat->SetMinSize(wxSize(w, h));
231 m_spMinLat->SetMinSize(wxSize(w, h));
232 m_spMaxLon->SetMinSize(wxSize(w, h));
233 m_spMinLon->SetMinSize(wxSize(w, h));
236 m_pSenderAddress->SetToolTip(
237 _(
"Address used to send request eMail. (Mandatory for LINUX)"));
238 m_pLogin->SetToolTip(_(
"This is your zyGrib's forum access Login"));
240 _(
"Get this Code in zyGrib's forum ( This is not your password! )"));
241 m_sMovingSpeed->SetToolTip(_(
"Enter your forescasted Speed (in Knots)"));
242 m_sMovingCourse->SetToolTip(_(
"Enter your forecasted Course"));
245 ((wxString)m_RequestConfigBase.GetChar(0)).ToLong(&i);
246 m_pMailTo->SetSelection(i);
247 ((wxString)m_RequestConfigBase.GetChar(1)).ToLong(&i);
248 m_pModel->SetSelection(i);
249 m_cMovingGribEnabled->SetValue(m_RequestConfigBase.GetChar(16) ==
251 ((wxString)m_RequestConfigBase.GetChar(2)).ToLong(&i);
252 ((wxString)m_RequestConfigBase.GetChar(3)).ToLong(&j);
253 ((wxString)m_RequestConfigBase.GetChar(4)).ToLong(&k, 16);
257 m_pSenderSizer->ShowItems(
false);
259 if (m_SendMethod == 0)
260 m_pSenderSizer->ShowItems(
false);
262 m_pSenderSizer->ShowItems(
266 m_tMouseEventTimer.Connect(
267 wxEVT_TIMER, wxTimerEventHandler(GribRequestSetting::OnMouseEventTimer),
270 m_RenderZoneOverlay = 0;
272 ApplyRequestConfig(i, j, k);
274 ((wxString)m_RequestConfigBase.GetChar(5)).ToLong(&j);
275 m_pWModel->SetSelection(j);
277 m_pWind->Enable(
false);
278 m_pPress->Enable(
false);
283 m_MailImage->SetValue(WriteMail());
286wxWindow *GetGRIBCanvas();
287void GribRequestSetting::OnClose(wxCloseEvent &event) {
289 OCPN_cancelDownloadFileBackground(m_download_handle);
290 m_downloading =
false;
291 m_download_handle = 0;
295 wxEVT_DOWNLOAD_EVENT,
296 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
298 m_RenderZoneOverlay = 0;
299 RequestRefresh(GetGRIBCanvas());
302 m_ZoneSelMode = m_SavedZoneSelMode;
303 m_parent.SetRequestBitmap(m_ZoneSelMode);
304 m_parent.m_highlight_latmax = 0;
305 m_parent.m_highlight_lonmax = 0;
306 m_parent.m_highlight_latmin = 0;
307 m_parent.m_highlight_lonmin = 0;
311void GribRequestSetting::SetRequestDialogSize() {
314 GetTextExtent(_T(
"abc"),
nullptr, &y, 0, 0,
OCPNGetFont(_(
"Dialog"), 0));
315 m_MailImage->SetMinSize(
316 wxSize(-1, ((y * m_MailImage->GetNumberOfLines()) + 10)));
320 m_fgScrollSizer->Fit(m_sScrolledDialog);
323 SetMinSize(wxSize(0, 0));
326 wxWindow *frame = wxTheApp->GetTopWindow();
328 int w = frame->GetClientSize().x;
329 int h = frame->GetClientSize().y;
331 h -= (m_rButton->GetSize().GetY() +
334 m_sScrolledDialog->SetMinSize(
335 wxSize(wxMin(w, scroll.x),
336 wxMin(h, scroll.y)));
341 wxSize sd = GetSize();
342 if (sd.y == GetClientSize().y) sd.y += 30;
343 SetSize(wxSize(sd.x, sd.y));
344 SetMinSize(wxSize(sd.x, sd.y));
350 double lonmax = vp->lon_max;
351 double lonmin = vp->lon_min;
352 if ((fabs(vp->lat_max) < 90.) && (fabs(lonmax) < 360.)) {
353 if (lonmax < -180.) lonmax += 360.;
354 if (lonmax > 180.) lonmax -= 360.;
356 if ((fabs(vp->lat_min) < 90.) && (fabs(lonmin) < 360.)) {
357 if (lonmin < -180.) lonmin += 360.;
358 if (lonmin > 180.) lonmin -= 360.;
361 bool bnew_val =
false;
362 if (m_spMaxLat->GetValue() != (
int)ceil(vp->lat_max)) bnew_val =
true;
363 if (m_spMinLon->GetValue() != (
int)floor(lonmin)) bnew_val =
true;
364 if (m_spMinLat->GetValue() != (
int)floor(vp->lat_min)) bnew_val =
true;
365 if (m_spMaxLon->GetValue() != (
int)ceil(lonmax)) bnew_val =
true;
368 m_spMaxLat->SetValue((
int)ceil(vp->lat_max));
369 m_spMinLon->SetValue((
int)floor(lonmin));
370 m_spMinLat->SetValue((
int)floor(vp->lat_min));
371 m_spMaxLon->SetValue((
int)ceil(lonmax));
373 SetCoordinatesText();
374 m_MailImage->SetValue(WriteMail());
378bool GribRequestSetting::MouseEventHook(wxMouseEvent &event) {
379 if (m_ZoneSelMode == AUTO_SELECTION || m_ZoneSelMode == SAVED_SELECTION ||
380 m_ZoneSelMode == START_SELECTION)
387 event.GetPosition(&xm, &ym);
388 xm *= m_displayScale;
389 ym *= m_displayScale;
397 if (event.LeftDown()) {
398 m_parent.pParent->SetFocus();
399 m_ZoneSelMode = DRAW_SELECTION;
400 m_parent.SetRequestBitmap(m_ZoneSelMode);
403 m_RenderZoneOverlay = 0;
406 if (event.LeftUp() && m_RenderZoneOverlay == 2) {
407 m_ZoneSelMode = COMPLETE_SELECTION;
408 m_parent.SetRequestBitmap(m_ZoneSelMode);
409 SetCoordinatesText();
410 m_MailImage->SetValue(WriteMail());
411 m_RenderZoneOverlay = 1;
414 if (event.Dragging()) {
415 if (m_RenderZoneOverlay < 2) {
418 m_RenderZoneOverlay = 2;
420 m_IsMaxLong = m_StartPoint.x > xm
423 GetCanvasLLPix(m_Vp, wxPoint(xm, ym) , &m_Lat,
425 if (!m_tMouseEventTimer.IsRunning())
426 m_tMouseEventTimer.Start(20, wxTIMER_ONE_SHOT);
431void GribRequestSetting::OnMouseEventTimer(wxTimerEvent &event) {
434 GetCanvasLLPix(m_Vp, m_StartPoint, &lat, &lon);
438 m_spMaxLat->SetValue((
int)ceil(lat));
439 m_spMinLat->SetValue((
int)floor(m_Lat));
441 m_spMaxLat->SetValue((
int)ceil(m_Lat));
442 m_spMinLat->SetValue((
int)floor(lat));
445 m_spMaxLon->SetValue((
int)ceil(lon));
446 m_spMinLon->SetValue((
int)floor(m_Lon));
448 m_spMaxLon->SetValue((
int)ceil(m_Lon));
449 m_spMinLon->SetValue((
int)floor(lon));
452 RequestRefresh(GetGRIBCanvas());
455void GribRequestSetting::SetCoordinatesText() {
456 m_stMaxLatNS->SetLabel(m_spMaxLat->GetValue() < 0 ? _(
"S") : _(
"N"));
457 m_stMinLonEW->SetLabel(m_spMinLon->GetValue() < 0 ? _(
"W") : _(
"E"));
458 m_stMaxLonEW->SetLabel(m_spMaxLon->GetValue() < 0 ? _(
"W") : _(
"E"));
459 m_stMinLatNS->SetLabel(m_spMinLat->GetValue() < 0 ? _(
"S") : _(
"N"));
462size_t LengthSelToHours(
int sel) {
476 switch (ev.getDLEventCondition()) {
477 case OCPN_DL_EVENT_TYPE_END:
479 (ev.getDLEventStatus() == OCPN_DL_NO_ERROR) ?
true : false;
480 Disconnect(wxEVT_DOWNLOAD_EVENT,
484 m_downloading =
false;
485 m_download_handle = 0;
489 case OCPN_DL_EVENT_TYPE_PROGRESS:
490 if (ev.getTotal() != 0) {
491 switch (m_downloadType) {
493 m_staticTextInfo->SetLabelText(
494 wxString::Format(_(
"Downloading... %li / %li"),
495 ev.getTransferred(), ev.getTotal()));
499 m_stLocalDownloadInfo->SetLabelText(
500 wxString::Format(_(
"Downloading... %li / %li"),
501 ev.getTransferred(), ev.getTotal()));
505 m_xygribPanel->m_progress_gauge->SetValue(
506 100 * ev.getTransferred() / ev.getTotal());
508 m_xygribPanel->m_status_text->SetLabel(wxString::Format(
509 "%s (%ld kB / %ld kB)",
510 _(
"Downloading GRIB file").c_str().AsChar(),
511 ev.getTransferred() / 1024, ev.getTotal() / 1024));
517 if (ev.getTransferred() > 0) {
518 switch (m_downloadType) {
520 m_staticTextInfo->SetLabelText(wxString::Format(
521 _(
"Downloading... %li / ???"), ev.getTransferred()));
525 m_stLocalDownloadInfo->SetLabelText(wxString::Format(
526 _(
"Downloading... %li / ???"), ev.getTransferred()));
540void GribRequestSetting::OnWorldDownload(wxCommandEvent &event) {
542 OCPN_cancelDownloadFileBackground(m_download_handle);
543 m_downloading =
false;
544 m_download_handle = 0;
546 wxEVT_DOWNLOAD_EVENT,
547 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
549 m_btnDownloadWorld->SetLabelText(_(
"Download"));
550 m_staticTextInfo->SetLabelText(_(
"Download canceled"));
553 EnableDownloadButtons();
554 wxTheApp->ProcessPendingEvents();
559 m_downloading =
true;
561 EnableDownloadButtons();
562 m_btnDownloadWorld->SetLabelText(_(
"Cancel"));
563 m_staticTextInfo->SetLabelText(_(
"Preparing data on server..."));
566 switch (m_chECMWFResolution->GetSelection()) {
571 model =
"ecmwfaifs0p25";
577 std::ostringstream oss;
578 oss <<
"https://grib.bosun.io/grib?";
579 oss <<
"model=" << model;
580 oss <<
"&latmin=" << m_Vp->lat_min;
581 oss <<
"&latmax=" << m_Vp->lat_max;
582 oss <<
"&lonmin=" << m_Vp->lon_min;
583 oss <<
"&lonmax=" << m_Vp->lon_max;
584 oss <<
"&length=" << LengthSelToHours(m_chForecastLength->GetSelection());
586 wxString::Format(
"ocpn_%s_%li_%s.grb2", model.c_str(),
587 LengthSelToHours(m_chForecastLength->GetSelection()),
588 wxDateTime::Now().Format(
"%F-%H-%M"));
589 wxString path = m_parent.GetGribDir();
590 path.Append(wxFileName::GetPathSeparator());
591 path.Append(filename);
595 wxEVT_DOWNLOAD_EVENT,
596 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
599 OCPN_downloadFileBackground(oss.str(), path,
this, &m_download_handle);
600 while (m_downloading) {
601 wxTheApp->ProcessPendingEvents();
605 if (m_bTransferSuccess) {
606 m_staticTextInfo->SetLabelText(
607 wxString::Format(_(
"Download complete: %s"), path.c_str()));
614 if (m_parent.
pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
616 m_parent.SetDialogsStyleSizePosition(
true);
619 m_staticTextInfo->SetLabelText(_(
"Download failed"));
622 m_btnDownloadWorld->SetLabelText(_(
"Download"));
624 EnableDownloadButtons();
627enum LocalSourceItem { SOURCE, AREA, GRIB };
629enum LocalGribDownloadType { DIRECT, MANIFEST, WEBPAGE };
632 GribCatalogInfo(LocalSourceItem type, wxString name, wxString description,
633 wxString url, wxString filename,
634 LocalGribDownloadType download_type,
double latmin,
635 double lonmin,
double latmax,
double lonmax)
638 description(description),
641 download_type(download_type),
646 LocalSourceItem type;
648 wxString description;
651 LocalGribDownloadType download_type;
658void GribRequestSetting::FillTreeCtrl(
wxJSONValue &data) {
659 m_SourcesTreeCtrl1->DeleteAllItems();
661 m_SourcesTreeCtrl1->AddRoot(_(
"Local high resolution forecasts"));
662 if (data.HasMember(
"sources") && data[
"sources"].IsArray()) {
663 for (
int i = 0; i < data[
"sources"].Size(); i++) {
666 LocalSourceItem::SOURCE, source[
"source"].AsString(),
667 source[
"description"].AsString(), source[
"url"].AsString(),
668 wxEmptyString, LocalGribDownloadType::WEBPAGE, 0, 0, 0, 0);
669 wxTreeItemId src_id = m_SourcesTreeCtrl1->AppendItem(
670 root, source[
"source"].AsString(), -1, -1, info);
671 if (source.
HasMember(
"areas") && source[
"areas"].IsArray()) {
672 for (
int j = 0; j < source[_T(
"areas")].
Size(); j++) {
675 LocalSourceItem::AREA, area[
"name"].AsString(),
676 source[
"description"].AsString(), source[
"url"].AsString(),
677 wxEmptyString, LocalGribDownloadType::WEBPAGE,
678 area[
"boundary"][
"lat_min"].AsDouble(),
679 area[
"boundary"][
"lon_min"].AsDouble(),
680 area[
"boundary"][
"lat_max"].AsDouble(),
681 area[
"boundary"][
"lon_max"].AsDouble());
682 m_SourcesTreeCtrl1->AppendItem(src_id, area[
"name"].AsString(), -1,
684 if (area.
HasMember(
"gribs") && area[
"gribs"].IsArray()) {
685 for (
int k = 0; k < area[
"gribs"].
Size(); k++) {
688 LocalSourceItem::GRIB, grib[
"name"].AsString(),
689 source[
"description"].AsString(),
690 grib.
HasMember(
"url") ? grib[
"url"].AsString()
691 : grib[
"cat_url"].AsString(),
692 grib.HasMember(
"filename") ? grib[
"filename"].AsString() :
"",
693 grib.HasMember(
"url") ? LocalGribDownloadType::DIRECT
694 : LocalGribDownloadType::MANIFEST,
695 area[
"boundary"][
"lat_min"].AsDouble(),
696 area[
"boundary"][
"lon_min"].AsDouble(),
697 area[
"boundary"][
"lat_max"].AsDouble(),
698 area[
"boundary"][
"lon_max"].AsDouble());
699 m_SourcesTreeCtrl1->AppendItem(
700 m_SourcesTreeCtrl1->GetLastChild(src_id),
701 grib[_T(
"name")].AsString(), -1, -1, info);
706 m_SourcesTreeCtrl1->CollapseAllChildren(src_id);
709 m_SourcesTreeCtrl1->Expand(root);
712void GribRequestSetting::ReadLocalCatalog() {
714 wxFileInputStream str(m_parent.
pPlugIn->m_local_sources_catalog);
716 reader.
Parse(str, &root);
720void GribRequestSetting::HighlightArea(
double latmax,
double lonmax,
721 double latmin,
double lonmin) {
722 m_parent.m_highlight_latmax = latmax;
723 m_parent.m_highlight_lonmax = lonmax;
724 m_parent.m_highlight_latmin = latmin;
725 m_parent.m_highlight_lonmin = lonmin;
728void GribRequestSetting::OnLocalTreeSelChanged(wxTreeEvent &event) {
729 wxTreeItemId item = m_SourcesTreeCtrl1->GetSelection();
732 if (src->type == LocalSourceItem::GRIB) {
733 m_stLocalDownloadInfo->SetLabelText(_(
"Download grib..."));
734 m_bLocal_source_selected =
true;
735 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
737 m_stLocalDownloadInfo->SetLabelText(_(
"Select grib..."));
738 m_bLocal_source_selected =
false;
739 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
742 EnableDownloadButtons();
745void GribRequestSetting::OnUpdateLocalCatalog(wxCommandEvent &event) {
747 OCPN_cancelDownloadFileBackground(m_download_handle);
748 m_downloading =
false;
749 m_download_handle = 0;
751 wxEVT_DOWNLOAD_EVENT,
752 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
754 m_btnDownloadLocal->SetLabelText(_(
"Download"));
755 m_stLocalDownloadInfo->SetLabelText(_(
"Download canceled"));
758 EnableDownloadButtons();
759 wxTheApp->ProcessPendingEvents();
764 m_downloading =
true;
766 EnableDownloadButtons();
767 m_btnDownloadLocal->SetLabelText(_(
"Cancel"));
768 m_staticTextInfo->SetLabelText(_(
"Downloading catalog update..."));
773 wxEVT_DOWNLOAD_EVENT,
774 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
776 auto res = OCPN_downloadFileBackground(
777 CATALOG_URL, m_parent.
pPlugIn->m_local_sources_catalog +
"new",
this,
779 while (m_downloading) {
780 wxTheApp->ProcessPendingEvents();
784 if (m_bTransferSuccess) {
785 wxRenameFile(m_parent.
pPlugIn->m_local_sources_catalog +
"new",
786 m_parent.
pPlugIn->m_local_sources_catalog,
true);
788 m_stLocalDownloadInfo->SetLabelText(_(
"Catalog update complete."));
790 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
793 m_btnDownloadLocal->SetLabelText(_(
"Download"));
795 EnableDownloadButtons();
798void GribRequestSetting::OnDownloadLocal(wxCommandEvent &event) {
800 OCPN_cancelDownloadFileBackground(m_download_handle);
801 m_downloading =
false;
802 m_download_handle = 0;
804 wxEVT_DOWNLOAD_EVENT,
805 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
807 m_btnDownloadLocal->SetLabelText(_(
"Download"));
808 m_stLocalDownloadInfo->SetLabelText(_(
"Download canceled"));
811 EnableDownloadButtons();
812 wxTheApp->ProcessPendingEvents();
817 m_downloading =
true;
819 EnableDownloadButtons();
820 m_btnDownloadLocal->SetLabelText(_(
"Cancel"));
821 m_staticTextInfo->SetLabelText(_(
"Downloading grib..."));
824 m_SourcesTreeCtrl1->GetSelection()));
825 if (!src || src->type != LocalSourceItem::GRIB || src->url.IsEmpty()) {
826 m_downloading =
false;
827 m_stLocalDownloadInfo->SetLabelText(_(
"Download can't be started."));
828 m_btnDownloadWorld->SetLabelText(_(
"Download"));
830 EnableDownloadButtons();
836 wxEVT_DOWNLOAD_EVENT,
837 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
839 wxString url = src->url;
842 if (src->download_type == LocalGribDownloadType::MANIFEST) {
843 wxString path = m_parent.GetGribDir();
844 path.Append(wxFileName::GetPathSeparator());
845 path.Append(
"grib_manifest.json");
846 auto res = OCPN_downloadFileBackground(url, path,
this, &m_download_handle);
847 while (m_downloading) {
848 wxTheApp->ProcessPendingEvents();
853 if (!m_bTransferSuccess) {
855 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
859 m_stLocalDownloadInfo->SetLabelText(_(
"Download canceled"));
863 wxFileInputStream str(path);
865 reader.
Parse(str, &root);
867 wxString parsed = root[
"url"].
AsString();
868 if (parsed.StartsWith(
"http")) {
871 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
878 m_downloading =
false;
879 m_download_handle = 0;
880 Disconnect(wxEVT_DOWNLOAD_EVENT,
884 m_btnDownloadLocal->SetLabelText(_(
"Download"));
885 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
888 EnableDownloadButtons();
889 wxTheApp->ProcessPendingEvents();
895 m_downloading =
true;
900 wxEVT_DOWNLOAD_EVENT,
901 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
904 if (!src->filename.IsEmpty()) {
905 filename = src->filename;
910 filename.Replace(
"?",
"_");
911 filename.Replace(
"&",
"_");
912 if (!(filename.Contains(
".grb2") || filename.Contains(
".grib2") ||
913 filename.Contains(
".grb") || filename.Contains(
".grib"))) {
914 filename.Append(
".grb");
918 wxString path = m_parent.GetGribDir();
919 path.Append(wxFileName::GetPathSeparator());
920 path.Append(filename);
921 auto res = OCPN_downloadFileBackground(url, path,
this, &m_download_handle);
922 while (m_downloading) {
923 wxTheApp->ProcessPendingEvents();
927 if (m_bTransferSuccess) {
928 m_stLocalDownloadInfo->SetLabelText(_(
"Grib download complete."));
929 m_stLocalDownloadInfo->SetLabelText(
930 wxString::Format(_(
"Download complete: %s"), path.c_str()));
938 if (m_parent.
pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
940 m_parent.SetDialogsStyleSizePosition(
true);
943 m_stLocalDownloadInfo->SetLabelText(_(
"Download failed"));
946 m_btnDownloadWorld->SetLabelText(_(
"Download"));
948 EnableDownloadButtons();
951void GribRequestSetting::EnableDownloadButtons() {
952 switch (m_downloadType) {
954 m_btnDownloadWorld->Enable(
true);
955 m_btnDownloadLocal->Enable(
false);
956 m_buttonUpdateCatalog->Enable(
false);
960 m_btnDownloadWorld->Enable(
false);
961 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
962 m_buttonUpdateCatalog->Enable(
false);
965 m_xygribPanel->m_download_button->Enable(
true);
968 m_btnDownloadWorld->Enable(
true);
969 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
970 m_buttonUpdateCatalog->Enable(
true);
971 m_xygribPanel->m_download_button->Enable(
true);
976void GribRequestSetting::StopGraphicalZoneSelection() {
977 m_RenderZoneOverlay = 0;
979 RequestRefresh(GetGRIBCanvas());
983 if (!vp || m_Vp == vp)
return;
988 GetCanvasPixLL(m_Vp, &m_StartPoint, m_spMaxLat->GetValue(),
989 m_spMinLon->GetValue());
991 if (!m_AllowSend)
return;
992 if (m_cManualZoneSel->GetValue())
return;
996 UpdateGribSizeEstimate();
999void GribRequestSetting::ApplyRequestConfig(
unsigned rs,
unsigned it,
1002 const wxString res[][RESOLUTIONS] = {
1003 {_T(
"0.25"), _T(
"0.5"), _T(
"1.0"), _T(
"2.0")},
1004 {_T(
"0.2"), _T(
"0.8"), _T(
"1.6"), wxEmptyString},
1005 {_T(
"0.08"), _T(
"0.24"), _T(
"1.0"), wxEmptyString},
1006 {_T(
"0.03"), _T(
"0.24"), _T(
"1.0"), wxEmptyString},
1007 {_T(
"0.0625"), _T(
"0.125"), wxEmptyString, wxEmptyString},
1008 {_T(
"0.4"), _T(
"1.0"), _T(
"2.0"), wxEmptyString}
1011 IsZYGRIB = m_pMailTo->GetCurrentSelection() == ZYGRIB;
1013 m_pModel->SetSelection(GFS);
1014 IsGFS = m_pModel->GetCurrentSelection() == GFS;
1015 bool IsRTOFS = m_pModel->GetCurrentSelection() == RTOFS;
1016 bool IsHRRR = m_pModel->GetCurrentSelection() == HRRR;
1017 bool IsICON = m_pModel->GetCurrentSelection() == ICON;
1018 bool IsECMWF = m_pModel->GetCurrentSelection() == ECMWF;
1021 m_pResolution->Clear();
1022 if (m_pModel->GetCurrentSelection() >= 0) {
1023 for (
int i = 0; i < RESOLUTIONS; i++) {
1024 if (res[m_pModel->GetCurrentSelection()][i] != wxEmptyString) {
1025 wxString s = res[m_pModel->GetCurrentSelection()][i];
1026 m_pResolution->Append(s);
1030 m_pResolution->SetSelection(rs);
1034 l = (IsGFS || IsRTOFS || IsICON || IsECMWF) ? 3 : IsHRRR ? 1 : 6;
1037 m = IsHRRR ? 2 : 25;
1039 m_pInterval->Clear();
1040 for (
unsigned i = l; i < m; i *= 2)
1041 m_pInterval->Append(wxString::Format(_T(
"%d"), i));
1042 m_pInterval->SetSelection(wxMin(it, m_pInterval->GetCount() - 1));
1052 m_pTimeRange->Clear();
1053 for (
unsigned i = 2; i < l + 1; i++)
1054 m_pTimeRange->Append(wxString::Format(_T(
"%d"), i));
1055 m_pTimeRange->SetSelection(wxMin(l - 2, tr));
1057 m_pModel->Enable(!IsZYGRIB);
1058 m_pWind->SetValue(!IsRTOFS);
1059 m_pPress->SetValue(!IsRTOFS);
1060 m_pWaves->SetValue(m_RequestConfigBase.GetChar(8) ==
'X' && IsGFS);
1061 m_pWaves->Enable(IsECMWF ||
1062 (IsGFS && m_pTimeRange->GetCurrentSelection() < 7));
1064 m_pRainfall->SetValue(m_RequestConfigBase.GetChar(9) ==
'X' &&
1066 m_pRainfall->Enable(IsGFS || IsHRRR);
1067 m_pCloudCover->SetValue(m_RequestConfigBase.GetChar(10) ==
'X' && IsGFS);
1068 m_pCloudCover->Enable(IsGFS);
1069 m_pAirTemp->SetValue(m_RequestConfigBase.GetChar(11) ==
'X' &&
1070 (IsGFS || IsHRRR || IsICON || IsECMWF));
1071 m_pAirTemp->Enable(IsGFS || IsHRRR || IsICON || IsECMWF);
1072 m_pSeaTemp->SetValue(m_RequestConfigBase.GetChar(12) ==
'X' &&
1073 ((!IsZYGRIB && IsGFS) || IsRTOFS || IsHRRR || IsICON));
1074 m_pSeaTemp->Enable(!IsZYGRIB && (IsGFS || IsHRRR || IsICON));
1075 m_pWindGust->SetValue(m_RequestConfigBase.GetChar(14) ==
'X' &&
1076 (IsGFS || IsHRRR || IsICON));
1077 m_pWindGust->Enable(IsGFS || IsHRRR || IsICON);
1078 m_pCAPE->SetValue(m_RequestConfigBase.GetChar(15) ==
'X' &&
1080 m_pCAPE->Enable(IsGFS || IsHRRR);
1081 m_pReflectivity->Enable(IsGFS || IsHRRR);
1083 m_pAltitudeData->SetValue(
1084 (IsGFS || IsICON || IsECMWF)
1085 ? m_RequestConfigBase.GetChar(17) ==
'X'
1087 m_pAltitudeData->Enable(IsGFS || IsICON || IsECMWF);
1088 m_p850hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(18) ==
'X'
1090 m_p850hpa->Enable(IsZYGRIB);
1091 m_p700hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(19) ==
'X'
1093 m_p700hpa->Enable(IsZYGRIB);
1094 m_p500hpa->SetValue((IsGFS || IsICON || IsECMWF)
1095 ? m_RequestConfigBase.GetChar(20) ==
'X'
1097 m_p500hpa->Enable(IsGFS || IsICON || IsECMWF);
1098 m_p300hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(21) ==
'X'
1100 m_p300hpa->Enable(IsZYGRIB);
1102 m_pCurrent->SetValue(IsRTOFS);
1103 m_pCurrent->Enable(
false);
1106 m_cMovingGribEnabled->Show(!IsZYGRIB);
1107 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1108 m_cMovingGribEnabled->IsShown());
1110 m_fgLog->ShowItems(IsZYGRIB);
1112 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1114 m_fgAltitudeData->ShowItems(
1115 m_pAltitudeData->IsChecked());
1118void GribRequestSetting::OnTopChange(wxCommandEvent &event) {
1120 if (m_pMailTo->GetCurrentSelection() == ZYGRIB) {
1121 m_pMailTo->SetSelection(0);
1122 int mes = OCPNMessageBox_PlugIn(
1124 _(
"Sorry...\nZyGrib momentary stopped providing this service...\nOnly "
1125 "Saildocs option is available"),
1126 _(
"Warning"), wxOK);
1128 ApplyRequestConfig(m_pResolution->GetCurrentSelection(),
1129 m_pInterval->GetCurrentSelection(),
1130 m_pTimeRange->GetCurrentSelection());
1132 m_cMovingGribEnabled->Show(m_pMailTo->GetCurrentSelection() == SAILDOCS);
1134 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1136 SetRequestDialogSize();
1139void GribRequestSetting::OnZoneSelectionModeChange(wxCommandEvent &event) {
1140 StopGraphicalZoneSelection();
1142 if (!m_ZoneSelMode) SetVpSize(m_Vp);
1144 if (event.GetId() == MANSELECT) {
1148 m_cManualZoneSel->GetValue() ? DRAW_SELECTION : AUTO_SELECTION;
1149 m_cUseSavedZone->SetValue(
false);
1150 }
else if (event.GetId() == SAVEDZONE) {
1155 m_cUseSavedZone->GetValue() ? SAVED_SELECTION : DRAW_SELECTION;
1157 m_parent.SetRequestBitmap(m_ZoneSelMode);
1158 fgZoneCoordinatesSizer->ShowItems(
1159 m_ZoneSelMode != AUTO_SELECTION);
1160 m_cUseSavedZone->Show(m_ZoneSelMode != AUTO_SELECTION);
1161 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1163 SetRequestDialogSize();
1166bool GribRequestSetting::DoRenderZoneOverlay() {
1168 GetCanvasPixLL(m_Vp, &p, m_Lat, m_Lon);
1170 int x = (m_StartPoint.x < p.x) ? m_StartPoint.x : p.x;
1171 int y = (m_StartPoint.y < p.y) ? m_StartPoint.y : p.y;
1173 int zw = fabs((
double)p.x - m_StartPoint.x);
1174 int zh = fabs((
double)p.y - m_StartPoint.y);
1177 center.x = x + (zw / 2);
1178 center.y = y + (zh / 2);
1182 (fo.GetPointSize() * m_displayScale / OCPN_GetWinDIPScaleFactor()));
1184 wxColour pen_color, back_color;
1185 GetGlobalColor(_T (
"DASHR" ), &pen_color);
1186 GetGlobalColor(_T (
"YELO1" ), &back_color);
1188 int label_offsetx = 5, label_offsety = 1;
1191 EstimateFileSize(&size);
1193 wxString label(_(
"Coord. "));
1194 label.Append(toMailFormat(1, m_spMaxLat->GetValue()) + _T(
" "));
1195 label.Append(toMailFormat(0, m_spMinLon->GetValue()) + _T(
" "));
1196 label.Append(toMailFormat(1, m_spMinLat->GetValue()) + _T(
" "));
1197 label.Append(toMailFormat(0, m_spMaxLon->GetValue()) + _T(
"\n"));
1198 label.Append(_T(
"Estim. Size "))
1199 .Append((wxString::Format(_T(
"%1.2f " ), size) + _(
"MB")));
1202 wxPen pen(pen_color);
1205 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
1206 m_pdc->DrawRectangle(x, y, zw, zh);
1211 sdc.GetMultiLineTextExtent(label, &w, &h, &sl, font);
1213 m_pdc->GetMultiLineTextExtent(label, &w, &h, &sl, font);
1214 w *= OCPN_GetWinDIPScaleFactor();
1215 h *= OCPN_GetWinDIPScaleFactor();
1217 w += 2 * label_offsetx, h += 2 * label_offsety;
1218 x = center.x - (w / 2);
1219 y = center.y - (h / 2);
1221 h *= m_displayScale;
1222 w *= m_displayScale;
1229 mdc.SetBrush(back_color);
1230 mdc.SetPen(*wxTRANSPARENT_PEN);
1231 mdc.SetTextForeground(wxColor(0, 0, 0));
1232 mdc.DrawRectangle(0, 0, w, h);
1233 mdc.DrawLabel(label, wxRect(label_offsetx, label_offsety, w, h));
1235 wxImage im = bm.ConvertToImage();
1237 w = im.GetWidth(), h = im.GetHeight();
1238 for (
int j = 0; j < h; j++)
1239 for (
int i = 0; i < w; i++) im.SetAlpha(i, j, 155);
1241 m_pdc->DrawBitmap(im, x, y,
true);
1245#ifndef USE_ANDROID_GLES2
1252 m_oDC->SetPen(wxPen(pen_color, 3));
1255 outline[0] = wxPoint(x, y);
1256 outline[1] = wxPoint(x + zw, y);
1257 outline[2] = wxPoint(x + zw, y + zh);
1258 outline[3] = wxPoint(x, y + zh);
1259 outline[4] = wxPoint(x, y);
1260 m_oDC->DrawLines(5, outline);
1262 m_oDC->SetFont(*font);
1264 m_oDC->GetTextExtent(label, &w, &h);
1265 h *= m_displayScale;
1266 w *= m_displayScale;
1268 m_oDC->GetTextExtent(
"W", &ww, &hw);
1270 int label_offsetx = ww, label_offsety = 1;
1271 int x = center.x - w / 2;
1272 int y = center.y - h / 2;
1274 w += 2 * label_offsetx, h += 2 * label_offsety;
1276 m_oDC->SetBrush(wxBrush(back_color));
1277 m_oDC->DrawRoundedRectangle(x, y, w, h, 0);
1280 m_oDC->SetPen(wxPen(wxColour(0, 0, 0), 1));
1282 outline[0] = wxPoint(x, y);
1283 outline[1] = wxPoint(x + w, y);
1284 outline[2] = wxPoint(x + w, y + h);
1285 outline[3] = wxPoint(x, y + h);
1286 outline[4] = wxPoint(x, y);
1287 m_oDC->DrawLines(5, outline);
1289 m_oDC->DrawText(label, x + label_offsetx, y + label_offsety);
1297bool GribRequestSetting::RenderGlZoneOverlay() {
1298 if (m_RenderZoneOverlay == 0)
return false;
1300 return DoRenderZoneOverlay();
1303bool GribRequestSetting::RenderZoneOverlay(wxDC &dc) {
1304 if (m_RenderZoneOverlay == 0)
return false;
1306 return DoRenderZoneOverlay();
1309void GribRequestSetting::OnMovingClick(wxCommandEvent &event) {
1310 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1311 m_cMovingGribEnabled->IsShown());
1313 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1314 SetRequestDialogSize();
1319void GribRequestSetting::OnCoordinatesChange(wxSpinEvent &event) {
1320 SetCoordinatesText();
1322 StopGraphicalZoneSelection();
1324 if (!m_AllowSend)
return;
1326 m_MailImage->SetValue(WriteMail());
1329void GribRequestSetting::OnAnyChange(wxCommandEvent &event) {
1330 m_fgAltitudeData->ShowItems(m_pAltitudeData->IsChecked());
1332 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1334 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1336 SetRequestDialogSize();
1339void GribRequestSetting::OnTimeRangeChange(wxCommandEvent &event) {
1340 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1342 if (m_pModel->GetCurrentSelection() == 0) {
1343 if (m_pTimeRange->GetCurrentSelection() >
1345 m_pWaves->SetValue(0);
1346 m_pWaves->Enable(
false);
1347 OCPNMessageBox_PlugIn(
1349 _(
"You request a forecast for more than 8 days horizon.\nThis is "
1350 "conflicting with Wave data which will be removed from your "
1351 "request.\nDon't forget that beyond the first 8 days, the "
1352 "resolution will be only 2.5\u00B0x2.5\u00B0\nand the time "
1353 "intervall 12 hours."),
1356 m_pWaves->Enable(
true);
1359 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1361 SetRequestDialogSize();
1364void GribRequestSetting::OnSaveMail(wxCommandEvent &event) {
1365 bool IsCOAMPS = m_pModel->GetCurrentSelection() == COAMPS;
1366 bool IsRTOFS = m_pModel->GetCurrentSelection() == RTOFS;
1367 bool IsICON = m_pModel->GetCurrentSelection() == ICON;
1368 bool IsECMWF = m_pModel->GetCurrentSelection() == ECMWF;
1369 m_RequestConfigBase.SetChar(
1370 0, (
char)(m_pMailTo->GetCurrentSelection() +
'0'));
1371 m_cMovingGribEnabled->IsChecked()
1372 ? m_RequestConfigBase.SetChar(16,
'X')
1373 : m_RequestConfigBase.SetChar(16,
'.');
1376 m_RequestConfigBase.SetChar(
1377 1, (
char)(m_pModel->GetCurrentSelection() +
'0'));
1379 m_RequestConfigBase.SetChar(
1380 2, (
char)(m_pResolution->GetCurrentSelection() +
'0'));
1382 m_RequestConfigBase.SetChar(3,
1383 (
char)(m_pInterval->GetCurrentSelection() +
'0'));
1386 range.Printf(_T(
"%x"), m_pTimeRange->GetCurrentSelection() +
1388 m_RequestConfigBase.SetChar(4, range.GetChar(0));
1390 if (IsZYGRIB && m_pWModel->IsShown())
1391 m_RequestConfigBase.SetChar(
1392 5, (
char)(m_pWModel->GetCurrentSelection() +
'0'));
1394 m_RequestConfigBase.SetChar(
1396 m_RequestConfigBase.SetChar(
1399 if (!IsCOAMPS && !IsRTOFS) {
1400 m_pWindGust->IsChecked() ? m_RequestConfigBase.SetChar(14,
'X')
1401 : m_RequestConfigBase.SetChar(14,
'.');
1402 m_pWaves->IsChecked() ? m_RequestConfigBase.SetChar(8,
'X')
1403 : m_RequestConfigBase.SetChar(8,
'.');
1404 m_pRainfall->IsChecked() ? m_RequestConfigBase.SetChar(9,
'X')
1405 : m_RequestConfigBase.SetChar(9,
'.');
1406 m_pCloudCover->IsChecked() ? m_RequestConfigBase.SetChar(10,
'X')
1407 : m_RequestConfigBase.SetChar(10,
'.');
1408 m_pAirTemp->IsChecked() ? m_RequestConfigBase.SetChar(11,
'X')
1409 : m_RequestConfigBase.SetChar(11,
'.');
1410 m_pSeaTemp->IsChecked() ? m_RequestConfigBase.SetChar(12,
'X')
1411 : m_RequestConfigBase.SetChar(12,
'.');
1412 m_pCAPE->IsChecked() ? m_RequestConfigBase.SetChar(15,
'X')
1413 : m_RequestConfigBase.SetChar(15,
'.');
1416 m_pCurrent->IsChecked() ? m_RequestConfigBase.SetChar(13,
'X')
1417 : m_RequestConfigBase.SetChar(13,
'.');
1419 if (IsGFS || IsICON || IsECMWF) {
1420 m_pAltitudeData->IsChecked()
1421 ? m_RequestConfigBase.SetChar(17,
'X')
1422 : m_RequestConfigBase.SetChar(17,
'.');
1423 m_p500hpa->IsChecked() ? m_RequestConfigBase.SetChar(20,
'X')
1424 : m_RequestConfigBase.SetChar(20,
'.');
1427 m_p850hpa->IsChecked() ? m_RequestConfigBase.SetChar(18,
'X')
1428 : m_RequestConfigBase.SetChar(18,
'.');
1429 m_p700hpa->IsChecked() ? m_RequestConfigBase.SetChar(19,
'X')
1430 : m_RequestConfigBase.SetChar(19,
'.');
1431 m_p300hpa->IsChecked() ? m_RequestConfigBase.SetChar(21,
'X')
1432 : m_RequestConfigBase.SetChar(21,
'.');
1435 wxFileConfig *pConf = GetOCPNConfigObject();
1437 pConf->SetPath(_T(
"/PlugIns/GRIB" ));
1439 pConf->Write(_T (
"MailRequestConfig" ), m_RequestConfigBase);
1440 pConf->Write(_T(
"MailSenderAddress" ), m_pSenderAddress->GetValue());
1441 pConf->Write(_T(
"MailRequestAddresses" ), m_MailToAddresses);
1442 pConf->Write(_T(
"ZyGribLogin" ), m_pLogin->GetValue());
1443 pConf->Write(_T(
"ZyGribCode" ), m_pCode->GetValue());
1444 pConf->Write(_T(
"SendMailMethod" ), m_SendMethod);
1445 pConf->Write(_T(
"MovingGribSpeed" ), m_sMovingSpeed->GetValue());
1446 pConf->Write(_T(
"MovingGribCourse" ), m_sMovingCourse->GetValue());
1448 m_SavedZoneSelMode = m_cUseSavedZone->GetValue() ? SAVED_SELECTION
1449 : m_cManualZoneSel->GetValue() ? START_SELECTION
1451 pConf->Write(_T(
"ManualRequestZoneSizing" ), m_SavedZoneSelMode);
1453 pConf->Write(_T(
"RequestZoneMaxLat" ), m_spMaxLat->GetValue());
1454 pConf->Write(_T(
"RequestZoneMinLat" ), m_spMinLat->GetValue());
1455 pConf->Write(_T(
"RequestZoneMaxLon" ), m_spMaxLon->GetValue());
1456 pConf->Write(_T(
"RequestZoneMinLon" ), m_spMinLon->GetValue());
1463wxString GribRequestSetting::WriteMail() {
1465 int limit = IsZYGRIB ? 2 : 0;
1469 const wxString s[] = {_T(
","), _T(
" ")};
1470 const wxString p[][11] = {
1472 {_T(
"APCP"), _T(
"TCDC"), _T(
"AIRTMP"), _T(
"HTSGW,WVPER,WVDIR"),
1473 _T(
"SEATMP"), _T(
"GUST"), _T(
"CAPE"), wxEmptyString, wxEmptyString,
1474 _T(
"WIND500,HGT500"), wxEmptyString},
1479 {_T(
""), _T(
""), _T(
"AIRTMP"), _T(
""), _T(
"SFCTMP"), _T(
"GUST"), _T(
""),
1480 _T(
""), _T(
""), _T(
"WIND500,HGT500"), _T(
"")},
1482 {_T(
""), _T(
""), _T(
"TEMP"), _T(
"WAVES"), _T(
""), _T(
""), _T(
""), _T(
""),
1483 _T(
""), _T(
"WIND500,HGT500"), _T(
"")},
1485 {_T(
"PRECIP"), _T(
"CLOUD"), _T(
"TEMP"), _T(
"WVSIG WVWIND"), wxEmptyString,
1486 _T(
"GUST"), _T(
"CAPE"), _T(
"A850"), _T(
"A700"), _T(
"A500"), _T(
"A300")}};
1488 wxString r_topmess, r_parameters, r_zone;
1490 switch (m_pMailTo->GetCurrentSelection()) {
1492 r_zone = toMailFormat(1, m_spMaxLat->GetValue()) + _T(
",") +
1493 toMailFormat(1, m_spMinLat->GetValue()) + _T(
",") +
1494 toMailFormat(2, m_spMinLon->GetValue()) + _T(
",") +
1495 toMailFormat(2, m_spMaxLon->GetValue());
1496 r_topmess = wxT(
"send ");
1497 r_topmess.Append(m_pModel->GetStringSelection() + _T(
":"));
1498 r_topmess.Append(r_zone + _T(
"|"));
1499 r_topmess.Append(m_pResolution->GetStringSelection())
1501 .Append(m_pResolution->GetStringSelection())
1504 m_pInterval->GetStringSelection().ToDouble(&v);
1505 r_topmess.Append(wxString::Format(_T(
"0,%d,%d"), (
int)v, (
int)v * 2));
1506 m_pTimeRange->GetStringSelection().ToDouble(&v);
1507 r_topmess.Append(wxString::Format(_T(
"..%d"), (
int)v * 24) + _T(
"|=\n"));
1510 double maxlon = (m_spMinLon->GetValue() > m_spMaxLon->GetValue() &&
1511 m_spMaxLon->GetValue() < 0)
1512 ? m_spMaxLon->GetValue() + 360
1513 : m_spMaxLon->GetValue();
1514 r_zone = toMailFormat(1, m_spMinLat->GetValue()) +
1515 toMailFormat(2, m_spMinLon->GetValue()) + _T(
" ") +
1516 toMailFormat(1, m_spMaxLat->GetValue()) +
1517 toMailFormat(2, maxlon);
1518 r_topmess = wxT(
"login : ");
1519 r_topmess.Append(m_pLogin->GetValue() + _T(
"\n"));
1520 r_topmess.Append(wxT(
"code :"));
1521 r_topmess.Append(m_pCode->GetValue() + _T(
"\n"));
1522 r_topmess.Append(wxT(
"area : "));
1523 r_topmess.append(r_zone + _T(
"\n"));
1524 r_topmess.Append(wxT(
"resol : "));
1525 r_topmess.append(m_pResolution->GetStringSelection() + _T(
"\n"));
1526 r_topmess.Append(wxT(
"days : "));
1527 r_topmess.append(m_pTimeRange->GetStringSelection() + _T(
"\n"));
1528 r_topmess.Append(wxT(
"hours : "));
1529 r_topmess.append(m_pInterval->GetStringSelection() + _T(
"\n"));
1530 if (m_pWaves->IsChecked()) {
1531 r_topmess.Append(wxT(
"waves : "));
1532 r_topmess.append(m_pWModel->GetStringSelection() + _T(
"\n"));
1534 r_topmess.Append(wxT(
"meteo : "));
1535 r_topmess.append(m_pModel->GetStringSelection() + _T(
"\n"));
1536 if (m_pLogin->GetValue().IsEmpty() || m_pCode->GetValue().IsEmpty())
1541 int GFSZ = IsZYGRIB ? 6 : 0;
1542 switch (m_pModel->GetCurrentSelection()) {
1544 r_parameters = wxT(
"WIND") + s[m_pMailTo->GetCurrentSelection()] +
1546 if (m_pRainfall->IsChecked())
1547 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1549 if (m_pCloudCover->IsChecked())
1550 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1552 if (m_pAirTemp->IsChecked())
1553 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1555 if (m_pWaves->IsChecked())
1556 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1558 if (m_pSeaTemp->IsChecked())
1559 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1561 if (m_pWindGust->IsChecked())
1562 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1564 if (m_pCAPE->IsChecked())
1565 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1567 if (m_pAltitudeData->IsChecked()) {
1568 if (m_p850hpa->IsChecked())
1569 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1571 if (m_p700hpa->IsChecked())
1572 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1574 if (m_p500hpa->IsChecked())
1575 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1577 if (m_p300hpa->IsChecked())
1578 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1583 r_parameters = wxT(
"WIND,PRMSL");
1587 r_parameters = wxT(
"CUR,WTMP");
1590 r_parameters = wxT(
"WIND,PRMSL");
1592 if (m_pRainfall->IsChecked())
1593 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][0]);
1594 if (m_pAirTemp->IsChecked())
1595 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][2]);
1596 if (m_pSeaTemp->IsChecked())
1597 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][4]);
1598 if (m_pWindGust->IsChecked())
1599 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][5]);
1600 if (m_pCAPE->IsChecked())
1601 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][6]);
1604 r_parameters = wxT(
"WIND,PRMSL");
1606 if (m_pAirTemp->IsChecked())
1607 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][2]);
1608 if (m_pSeaTemp->IsChecked())
1609 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][4]);
1610 if (m_pWindGust->IsChecked())
1611 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][5]);
1612 if (m_pAltitudeData->IsChecked()) {
1613 if (m_p500hpa->IsChecked())
1614 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][9]);
1618 r_parameters = wxT(
"WIND,MSLP");
1620 if (m_pAirTemp->IsChecked())
1621 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][2]);
1622 if (m_pAltitudeData->IsChecked()) {
1623 if (m_p500hpa->IsChecked())
1624 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1627 if (m_pWaves->IsChecked())
1628 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][3]);
1631 if (!IsZYGRIB && m_cMovingGribEnabled->IsChecked())
1632 r_parameters.Append(wxString::Format(
1633 _T(
"|%d,%d"), m_sMovingSpeed->GetValue(), m_sMovingCourse->GetValue()));
1637 char c = m_pMailTo->GetCurrentSelection() == SAILDOCS ?
',' :
' ';
1638 for (
size_t i = 0; i < r_parameters.Len(); i++) {
1639 if (r_parameters.GetChar(i) ==
'|')
1641 if (r_parameters.GetChar(i) == c) j++;
1643 r_parameters.insert(i + 1, m_pMailTo->GetCurrentSelection() == SAILDOCS
1651 m_MailError_Nb += EstimateFileSize(&size);
1653 m_tFileSize->SetLabel(wxString::Format(_T(
"%1.2f " ), size) + _(
"MB"));
1656 m_tLimit->SetLabel(wxString(_T(
"( ")) + _(
"Max") +
1657 wxString::Format(_T(
" %d "), limit) + _(
"MB") +
1659 if (size > limit) m_MailError_Nb += 2;
1661 m_tLimit->SetLabel(wxEmptyString);
1663 return wxString(r_topmess + r_parameters);
1666int GribRequestSetting::EstimateFileSize(
double *size) {
1667 if (!size)
return 0;
1671 double reso, time, inter;
1672 m_pResolution->GetStringSelection().ToDouble(&reso);
1673 m_pTimeRange->GetStringSelection().ToDouble(&time);
1674 m_pInterval->GetStringSelection().ToDouble(&inter);
1676 double maxlon = m_spMaxLon->GetValue(), minlon = m_spMinLon->GetValue();
1677 double maxlat = m_spMaxLat->GetValue(), minlat = m_spMinLat->GetValue();
1678 if (maxlat - minlat < 0)
return 3;
1679 double wlon = (maxlon > minlon ? 0 : 360) + maxlon - minlon;
1680 if (wlon > 180 || (maxlat - minlat > 180))
return 4;
1682 if (fabs(wlon) < 2 * reso || maxlat - minlat < 2 * reso)
1685 int npts = (int)(ceil(((
double)(maxlat - minlat) / reso)) *
1686 ceil(((
double)(wlon) / reso)));
1688 if (m_pModel->GetCurrentSelection() == COAMPS)
1689 npts = wxMin(npts, (
int)(ceil(40.0 / reso) * ceil(40.0 / reso)));
1692 int nbrec = (int)(time * 24 / inter) + 1;
1693 int nbPress = (m_pPress->IsChecked()) ? nbrec : 0;
1694 int nbWind = (m_pWind->IsChecked()) ? 2 * nbrec : 0;
1695 int nbwave = (m_pWaves->IsChecked()) ? 2 * nbrec : 0;
1696 int nbRain = (m_pRainfall->IsChecked()) ? nbrec - 1 : 0;
1697 int nbCloud = (m_pCloudCover->IsChecked()) ? nbrec - 1 : 0;
1698 int nbTemp = (m_pAirTemp->IsChecked()) ? nbrec : 0;
1699 int nbSTemp = (m_pSeaTemp->IsChecked()) ? nbrec : 0;
1700 int nbGUSTsfc = (m_pWindGust->IsChecked()) ? nbrec : 0;
1701 int nbCurrent = (m_pCurrent->IsChecked()) ? nbrec : 0;
1702 int nbCape = (m_pCAPE->IsChecked()) ? nbrec : 0;
1704 IsZYGRIB ? 5 * nbrec : 3 * nbrec;
1708 double estime = 0.0;
1712 estime += nbWind * (head + (nbits * npts) / 8 + 2);
1713 estime += nbCurrent * (head + (nbits * npts) / 8 + 2);
1716 estime += nbTemp * (head + (nbits * npts) / 8 + 2);
1717 estime += nbSTemp * (head + (nbits * npts) / 8 + 2);
1720 estime += nbRain * (head + (nbits * npts) / 8 + 2);
1723 estime += nbPress * (head + (nbits * npts) / 8 + 2);
1726 estime += nbCloud * (head + (nbits * npts) / 8 + 2);
1729 estime += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
1732 estime += nbCape * (head + (nbits * npts) / 8 + 2);
1735 estime += nbwave * (head + (nbits * npts) / 8 + 2);
1737 if (m_pAltitudeData->IsChecked()) {
1739 if (m_p850hpa->IsChecked()) nbalt++;
1740 if (m_p700hpa->IsChecked()) nbalt++;
1741 if (m_p500hpa->IsChecked()) nbalt++;
1742 if (m_p300hpa->IsChecked()) nbalt++;
1745 estime += nbAltitude * nbalt * (head + (nbits * npts) / 8 + 2);
1748 *size = estime / (1024. * 1024.);
1753const wxString EncodeURL(
const wxString &uri) {
1754 static std::unordered_map<int, wxString> sEncodeMap = {
1755 {(int)
'!',
"%21"}, {(int)
'#',
"%23"}, {(int)
'$',
"%24"},
1756 {(int)
'&',
"%26"}, {(int)
'\'',
"%27"}, {(int)
'(',
"%28"},
1757 {(int)
')',
"%29"}, {(int)
'*',
"%2A"}, {(int)
'+',
"%2B"},
1758 {(int)
',',
"%2C"}, {(int)
';',
"%3B"}, {(int)
'=',
"%3D"},
1759 {(int)
'?',
"%3F"}, {(int)
'@',
"%40"}, {(int)
'[',
"%5B"},
1760 {(int)
']',
"%5D"}, {(int)
' ',
"%20"}, {(int)
'|',
"%7C"},
1761 {(int)
':',
"%3A"}, {(int)
'\n',
"%0A"}};
1764 for (
size_t i = 0; i < uri.length(); ++i) {
1766 std::unordered_map<int, wxString>::iterator iter = sEncodeMap.find((
int)ch);
1767 if (iter != sEncodeMap.end()) {
1768 encoded << iter->second;
1776void GribRequestSetting::OnSendMaiL(wxCommandEvent &event) {
1777 StopGraphicalZoneSelection();
1780 m_rButtonCancel->Show();
1781 m_rButtonApply->Show();
1782 m_rButtonYes->SetLabel(_(
"Send"));
1784 m_MailImage->SetForegroundColour(
1788 m_MailImage->SetValue(WriteMail());
1789 SetRequestDialogSize();
1794 const wxString error[] = {
1796 _(
"Before sending an email to Zygrib you have to enter your Login and "
1797 "Code.\nPlease visit www.zygrib.org/ and follow instructions..."),
1798 _(
"Too big file! zyGrib limit is 2Mb!"),
1799 _(
"Error! Max Lat lower than Min Lat or Max Lon lower than Min Lon!"),
1800 _(
"Too large area! Each side must be less than 180\u00B0!"),
1801 _(
"Too small area for this resolution!")};
1803 ::wxBeginBusyCursor();
1805 m_MailImage->SetForegroundColour(wxColor(255, 0, 0));
1806 m_AllowSend =
false;
1808 if (m_MailError_Nb) {
1809 if (m_MailError_Nb > 7) {
1810 m_MailImage->SetValue(error[1] + error[0] + error[m_MailError_Nb - 6]);
1812 if (m_MailError_Nb == 6) m_MailError_Nb = 1;
1813 m_MailImage->SetValue(error[m_MailError_Nb]);
1816 m_rButtonCancel->Hide();
1817 m_rButtonApply->Hide();
1818 m_rButtonYes->SetLabel(_(
"Continue..."));
1819 m_rButton->Layout();
1820 SetRequestDialogSize();
1822 ::wxEndBusyCursor();
1833 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1834 ? _T(
"grib-request")
1836 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1837 ? m_MailToAddresses.BeforeFirst(_T(
';'))
1838 : m_MailToAddresses.AfterFirst(_T(
';')).BeforeFirst(_T(
';')),
1839 EncodeURL(WriteMail()),
1840 m_pSenderAddress->GetValue());
1843 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1844 ? _T(
"grib-request")
1846 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1847 ? m_MailToAddresses.BeforeFirst(_T(
';'))
1848 : m_MailToAddresses.AfterFirst(_T(
';')).BeforeFirst(_T(
';')),
1850 m_pSenderAddress->GetValue());
1854 if (mail.Send(*message, m_SendMethod)) {
1856 m_MailImage->SetValue(
1857 _(
"Your request is ready. An email is prepared in your email "
1858 "environment. \nYou have just to verify and send it...\nSave or "
1859 "Cancel to finish...or Continue..."));
1861 if (m_SendMethod == 0) {
1862 m_MailImage->SetValue(
1863 _(
"Your request is ready. An email is prepared in your email "
1864 "environment. \nYou have just to verify and send it...\nSave or "
1865 "Cancel to finish...or Continue..."));
1867 m_MailImage->SetValue(
1868 _(
"Your request was sent \n(if your system has an MTA configured and "
1869 "is able to send email).\nSave or Cancel to finish...or "
1874 m_MailImage->SetValue(
1875 _(
"Request can't be sent. Please verify your email systeme "
1876 "parameters.\nYou should also have a look at your log file.\nSave or "
1877 "Cancel to finish..."));
1878 m_rButtonYes->Hide();
1880 m_rButtonYes->SetLabel(_(
"Continue..."));
1881 m_rButton->Layout();
1882 SetRequestDialogSize();
1884 ::wxEndBusyCursor();
1889wxString GribRequestSetting::BuildXyGribUrl() {
1892 wxString::Format(
"http://grbsrv.opengribs.org/getmygribs2.php?");
1894 urlStr << wxString::Format(
"la1=%.0f", floor(m_Vp->lat_min));
1895 urlStr << wxString::Format(
"&la2=%.0f", ceil(m_Vp->lat_max));
1896 urlStr << wxString::Format(
"&lo1=%.0f", floor(m_Vp->lon_min));
1897 urlStr << wxString::Format(
"&lo2=%.0f", ceil(m_Vp->lon_max));
1900 urlStr << wxString::Format(
1902 xygribAtmModelList[m_selectedAtmModelIndex]
1903 ->reqName[m_xygribPanel->m_resolution_choice->GetSelection()]);
1905 urlStr << wxString::Format(
1907 xygribAtmModelList[m_selectedAtmModelIndex]
1908 ->interval[m_xygribPanel->m_interval_choice->GetSelection()]);
1910 urlStr << wxString::Format(
1911 "&days=%d", m_xygribPanel->m_duration_choice->GetSelection() + 1);
1915 wxString selStr = m_xygribPanel->m_run_choice->GetStringSelection();
1916 if (selStr.IsSameAs(
"18h",
false)) {
1917 urlStr <<
"&cyc=18";
1918 }
else if (selStr.IsSameAs(
"12h",
false)) {
1919 urlStr <<
"&cyc=12";
1920 }
else if (selStr.IsSameAs(
"6h",
false)) {
1921 urlStr <<
"&cyc=06";
1922 }
else if (selStr.IsSameAs(
"0h",
false)) {
1923 urlStr <<
"&cyc=00";
1925 urlStr <<
"&cyc=last";
1930 if (m_xygribPanel->m_wind_cbox->IsEnabled() &&
1931 m_xygribPanel->m_wind_cbox->IsChecked())
1933 if (m_xygribPanel->m_pressure_cbox->IsEnabled() &&
1934 m_xygribPanel->m_pressure_cbox->IsChecked()) {
1935 if (xygribAtmModelList[m_selectedAtmModelIndex]->altPressure) {
1941 if (m_xygribPanel->m_precipitation_cbox->IsEnabled() &&
1942 m_xygribPanel->m_precipitation_cbox->IsChecked())
1944 if (m_xygribPanel->m_cloudcover_cbox->IsEnabled() &&
1945 m_xygribPanel->m_cloudcover_cbox->IsChecked())
1947 if (m_xygribPanel->m_temperature_cbox->IsEnabled() &&
1948 m_xygribPanel->m_temperature_cbox->IsChecked())
1950 if (m_xygribPanel->m_cape_cbox->IsEnabled() &&
1951 m_xygribPanel->m_cape_cbox->IsChecked())
1953 if (m_xygribPanel->m_reflectivity_cbox->IsEnabled() &&
1954 m_xygribPanel->m_reflectivity_cbox->IsChecked())
1956 if (m_xygribPanel->m_gust_cbox->IsEnabled() &&
1957 m_xygribPanel->m_gust_cbox->IsChecked())
1961 if ((m_selectedWaveModelIndex >= 0) &&
1962 (xygribWaveModelList[m_selectedWaveModelIndex] !=
nullptr)) {
1963 wxString modelStr = wxString::Format(
1964 "&wmdl=%s", xygribWaveModelList[m_selectedWaveModelIndex]->reqName);
1965 wxString wParams =
"";
1966 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
1969 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
1970 wParams <<
"h;d;p;";
1972 if (wParams.length() > 0) {
1973 urlStr << wxString::Format(
"%s&wpar=%s", modelStr.c_str(),
1976 urlStr <<
"&wmdl=none";
1979 urlStr <<
"&wmdl=none";
1987wxString GribRequestSetting::BuildGribFileName() {
1988 wxString selStr = m_xygribPanel->m_resolution_choice->GetStringSelection();
1989 selStr.Replace(
".",
"P");
1992 if (m_selectedWaveModelIndex < 0) {
1993 fileName = wxString::Format(
1994 "XyGrib_%s_%s_%s.grb2", wxDateTime::Now().Format(
"%F-%H-%M"),
1995 m_xygribPanel->m_atmmodel_choice->GetStringSelection(), selStr);
1997 fileName = wxString::Format(
1998 "XyGrib_%s_%s_%s_%s.grb2", wxDateTime::Now().Format(
"%F-%H-%M"),
1999 m_xygribPanel->m_atmmodel_choice->GetStringSelection(), selStr,
2000 m_xygribPanel->m_wavemodel_choice->GetStringSelection());
2011void GribRequestSetting::OnXyGribDownloadButton(wxCommandEvent &event) {
2013 if (m_downloading) {
2016 OCPN_cancelDownloadFileBackground(m_download_handle);
2017 m_downloading =
false;
2018 m_download_handle = 0;
2020 wxEVT_DOWNLOAD_EVENT,
2021 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2022 m_connected =
false;
2023 m_xygribPanel->m_progress_gauge->SetValue(0);
2024 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2025 m_xygribPanel->m_status_text->SetLabelText(_(
"Download cancelled"));
2028 EnableDownloadButtons();
2029 wxTheApp->ProcessPendingEvents();
2034 if (m_gribSizeEstimate > XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB * 1024 * 1024) {
2035 m_xygribPanel->m_status_text->SetLabelText(
2036 wxString::Format(_(
"Can't download GRIB file bigger than %d MB"),
2037 (
int)XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB));
2043 MemorizeXyGribConfiguration();
2045 m_downloading =
true;
2047 EnableDownloadButtons();
2049 m_xygribPanel->m_download_button->SetLabelText(_(
"Cancel"));
2050 m_xygribPanel->m_status_text->SetLabelText(
2051 _(
"Preparing GRIB file on server..."));
2055 wxString requestUrl = BuildXyGribUrl();
2060 wxString filename = wxString::Format(
"ocpn_xygrib_%s.xml",
2061 wxDateTime::Now().Format(
"%F-%H-%M"));
2062 wxString path = m_parent.GetGribDir();
2063 path << wxFileName::GetPathSeparator();
2068 wxEVT_DOWNLOAD_EVENT,
2069 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2071 auto res = OCPN_downloadFileBackground(requestUrl.c_str(), path,
this,
2072 &m_download_handle);
2077 while (m_downloading) {
2078 wxTheApp->ProcessPendingEvents();
2082 if ((m_canceled) || (!m_bTransferSuccess)) {
2084 m_xygribPanel->m_status_text->SetLabelText(_(
"Grib request failed"));
2085 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2087 EnableDownloadButtons();
2095 bool readOk = xmlFile.Open(path);
2097 readOk &= xmlFile.ReadAll(&strXml);
2105 if (readOk && (((
int)strXml.find(
"\"status\":true") == wxNOT_FOUND))) {
2108 int errPos = strXml.find(
"\"message\":\"");
2109 int errEnd = strXml.find(
"\"}");
2110 if ((errPos != wxNOT_FOUND) && (errEnd != wxNOT_FOUND)) {
2112 errorStr = strXml.Mid(errPos, errEnd - errPos);
2114 errorStr =
"Unknown server error";
2117 m_xygribPanel->m_status_text->SetLabelText(
2118 wxString::Format(
"%s (%s)", _(
"Server Error"), errorStr));
2119 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2121 EnableDownloadButtons();
2126 int urlPos = strXml.find(
"\"url\":\"http:");
2127 int urlEnd = strXml.find(
".grb2\"");
2128 if ((urlPos != wxNOT_FOUND) && (urlEnd != wxNOT_FOUND)) {
2131 url = strXml.Mid(urlPos, urlEnd - urlPos);
2132 url.Replace(
"\\/",
"/");
2143 m_xygribPanel->m_status_text->SetLabelText(
2144 _(
"Error parsing XML file from server"));
2145 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2147 EnableDownloadButtons();
2151 m_xygribPanel->m_status_text->SetLabelText(_(
"Downloading GRIB file"));
2154 path = m_parent.GetGribDir();
2155 path << wxFileName::GetPathSeparator();
2156 path << BuildGribFileName();
2160 m_downloading =
true;
2164 wxEVT_DOWNLOAD_EVENT,
2165 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2168 OCPN_downloadFileBackground(url.c_str(), path,
this, &m_download_handle);
2171 while (m_downloading) {
2172 wxTheApp->ProcessPendingEvents();
2177 m_xygribPanel->m_download_button->SetLabelText(_(
"Download"));
2180 if (m_bTransferSuccess) {
2182 m_xygribPanel->m_status_text->SetLabelText(_(
"Download complete"));
2183 wxFileName fn(path);
2187 m_parent.OpenFile();
2189 if (m_parent.
pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
2191 m_parent.SetDialogsStyleSizePosition(
true);
2195 m_xygribPanel->m_status_text->SetLabelText(_(
"Download failed"));
2199 EnableDownloadButtons();
2205void GribRequestSetting::OnXyGribAtmModelChoice(wxCommandEvent &event) {
2209 wxString atmModel = m_xygribPanel->m_atmmodel_choice->GetStringSelection();
2211 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) !=
nullptr) {
2212 if (selectedAtmModel->name.IsSameAs(atmModel,
true)) {
2219 if (selectedAtmModel ==
nullptr) {
2220 selectedAtmModel = xygribAtmModelList[0];
2225 if (selectedAtmModel->wind)
2226 m_xygribPanel->m_wind_cbox->Enable();
2228 m_xygribPanel->m_wind_cbox->Disable();
2230 if (selectedAtmModel->gust)
2231 m_xygribPanel->m_gust_cbox->Enable();
2233 m_xygribPanel->m_gust_cbox->Disable();
2235 if (selectedAtmModel->pressure)
2236 m_xygribPanel->m_pressure_cbox->Enable();
2238 m_xygribPanel->m_pressure_cbox->Disable();
2240 if (selectedAtmModel->temperature)
2241 m_xygribPanel->m_temperature_cbox->Enable();
2243 m_xygribPanel->m_temperature_cbox->Disable();
2245 if (selectedAtmModel->cape)
2246 m_xygribPanel->m_cape_cbox->Enable();
2248 m_xygribPanel->m_cape_cbox->Disable();
2250 if (selectedAtmModel->reflectivity)
2251 m_xygribPanel->m_reflectivity_cbox->Enable();
2253 m_xygribPanel->m_reflectivity_cbox->Disable();
2255 if (selectedAtmModel->cloudCover)
2256 m_xygribPanel->m_cloudcover_cbox->Enable();
2258 m_xygribPanel->m_cloudcover_cbox->Disable();
2260 if (selectedAtmModel->precipitation)
2261 m_xygribPanel->m_precipitation_cbox->Enable();
2263 m_xygribPanel->m_precipitation_cbox->Disable();
2266 m_xygribPanel->m_resolution_choice->Clear();
2267 for (
int i = 0; i < selectedAtmModel->nbRes; i++) {
2268 m_xygribPanel->m_resolution_choice->Insert(selectedAtmModel->resolution[i],
2273 m_xygribPanel->m_duration_choice->Clear();
2274 for (
int i = 0; i < selectedAtmModel->duration; i++) {
2275 m_xygribPanel->m_duration_choice->Insert(wxString::Format(
"%d", i + 1), i);
2279 m_xygribPanel->m_interval_choice->Clear();
2280 for (
int i = 0; i < selectedAtmModel->nbInterval; i++) {
2281 m_xygribPanel->m_interval_choice->Insert(
2282 wxString::Format(
"%dh", selectedAtmModel->interval[i]), i);
2286 m_xygribPanel->m_run_choice->Clear();
2287 if (selectedAtmModel->runMask == XYGRIB_RUN_0_12) {
2288 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2289 m_xygribPanel->m_run_choice->Insert(
"12h", 1);
2290 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 2);
2292 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2293 m_xygribPanel->m_run_choice->Insert(
"6h", 1);
2294 m_xygribPanel->m_run_choice->Insert(
"12h", 2);
2295 m_xygribPanel->m_run_choice->Insert(
"18h", 3);
2296 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 4);
2299 if (modelIndex == m_parent.xyGribConfig.atmModelIndex) {
2300 ApplyXyGribConfiguration();
2302 m_selectedAtmModelIndex = modelIndex;
2303 m_xygribPanel->m_resolution_choice->SetSelection(0);
2304 m_xygribPanel->m_duration_choice->SetSelection(
2305 m_xygribPanel->m_duration_choice->GetCount() - 1);
2306 m_xygribPanel->m_interval_choice->SetSelection(0);
2307 m_xygribPanel->m_run_choice->SetSelection(
2308 m_xygribPanel->m_run_choice->GetCount() - 1);
2310 MemorizeXyGribConfiguration();
2316void GribRequestSetting::OnXyGribWaveModelChoice(wxCommandEvent &event) {
2320 wxString waveModel = m_xygribPanel->m_wavemodel_choice->GetStringSelection();
2322 while ((selectedModel = xygribWaveModelList[modelIndex]) !=
nullptr) {
2323 if (selectedModel->name.IsSameAs(waveModel,
true)) {
2330 if (selectedModel ==
nullptr) {
2332 m_selectedWaveModelIndex = -1;
2333 m_xygribPanel->m_waveheight_cbox->Disable();
2334 m_xygribPanel->m_windwave_cbox->Disable();
2335 MemorizeXyGribConfiguration();
2339 m_selectedWaveModelIndex = modelIndex;
2342 if (selectedModel->significantHeight) {
2343 m_xygribPanel->m_waveheight_cbox->Enable();
2345 m_xygribPanel->m_waveheight_cbox->Disable();
2348 if (selectedModel->windWaves) {
2349 m_xygribPanel->m_windwave_cbox->Enable();
2351 m_xygribPanel->m_windwave_cbox->Disable();
2353 MemorizeXyGribConfiguration();
2359void GribRequestSetting::OnXyGribConfigChange(wxCommandEvent &event) {
2360 MemorizeXyGribConfiguration();
2364void GribRequestSetting::InitializeXygribDialog() {
2369 m_xygribPanel->m_atmmodel_choice->Clear();
2371 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) !=
nullptr) {
2372 m_xygribPanel->m_atmmodel_choice->Insert(selectedAtmModel->name,
2377 m_selectedAtmModelIndex = m_parent.xyGribConfig.atmModelIndex;
2378 selectedAtmModel = xygribAtmModelList[m_selectedAtmModelIndex];
2381 m_xygribPanel->m_wavemodel_choice->Clear();
2383 while ((selectedWaveModel = xygribWaveModelList[modelIndex]) !=
nullptr) {
2384 m_xygribPanel->m_wavemodel_choice->Insert(selectedWaveModel->name,
2389 m_xygribPanel->m_wavemodel_choice->Insert(
"None", modelIndex);
2390 m_selectedWaveModelIndex = m_parent.xyGribConfig.waveModelIndex;
2391 selectedWaveModel = xygribWaveModelList[m_selectedWaveModelIndex];
2392 if (selectedWaveModel ==
nullptr) {
2393 m_selectedWaveModelIndex = -1;
2397 m_xygribPanel->m_resolution_choice->Clear();
2398 for (
int i = 0; i < selectedAtmModel->nbRes; i++) {
2399 m_xygribPanel->m_resolution_choice->Insert(selectedAtmModel->resolution[i],
2404 m_xygribPanel->m_duration_choice->Clear();
2405 for (
int i = 0; i < selectedAtmModel->duration; i++) {
2406 m_xygribPanel->m_duration_choice->Insert(wxString::Format(
"%d", i + 1), i);
2410 m_xygribPanel->m_interval_choice->Clear();
2411 for (
int i = 0; i < selectedAtmModel->nbInterval; i++) {
2412 m_xygribPanel->m_interval_choice->Insert(
2413 wxString::Format(
"%dh", selectedAtmModel->interval[i]), i);
2417 m_xygribPanel->m_run_choice->Clear();
2418 if (selectedAtmModel->runMask == XYGRIB_RUN_0_12) {
2419 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2420 m_xygribPanel->m_run_choice->Insert(
"12h", 1);
2421 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 2);
2423 m_xygribPanel->m_run_choice->Insert(
"0h", 0);
2424 m_xygribPanel->m_run_choice->Insert(
"6h", 1);
2425 m_xygribPanel->m_run_choice->Insert(
"12h", 2);
2426 m_xygribPanel->m_run_choice->Insert(
"18h", 3);
2427 m_xygribPanel->m_run_choice->Insert(_(
"Latest"), 4);
2430 if (selectedAtmModel->wind)
2431 m_xygribPanel->m_wind_cbox->Enable();
2433 m_xygribPanel->m_wind_cbox->Disable();
2435 if (selectedAtmModel->gust)
2436 m_xygribPanel->m_gust_cbox->Enable();
2438 m_xygribPanel->m_gust_cbox->Disable();
2440 if (selectedAtmModel->pressure)
2441 m_xygribPanel->m_pressure_cbox->Enable();
2443 m_xygribPanel->m_pressure_cbox->Disable();
2445 if (selectedAtmModel->temperature)
2446 m_xygribPanel->m_temperature_cbox->Enable();
2448 m_xygribPanel->m_temperature_cbox->Disable();
2450 if (selectedAtmModel->cape)
2451 m_xygribPanel->m_cape_cbox->Enable();
2453 m_xygribPanel->m_cape_cbox->Disable();
2455 if (selectedAtmModel->reflectivity)
2456 m_xygribPanel->m_reflectivity_cbox->Enable();
2458 m_xygribPanel->m_reflectivity_cbox->Disable();
2460 if (selectedAtmModel->cloudCover)
2461 m_xygribPanel->m_cloudcover_cbox->Enable();
2463 m_xygribPanel->m_cloudcover_cbox->Disable();
2465 if (selectedAtmModel->precipitation)
2466 m_xygribPanel->m_precipitation_cbox->Enable();
2468 m_xygribPanel->m_precipitation_cbox->Disable();
2470 if ((selectedWaveModel !=
nullptr) && (selectedWaveModel->significantHeight))
2471 m_xygribPanel->m_waveheight_cbox->Enable();
2473 m_xygribPanel->m_waveheight_cbox->Disable();
2475 if ((selectedWaveModel !=
nullptr) && (selectedWaveModel->windWaves))
2476 m_xygribPanel->m_windwave_cbox->Enable();
2478 m_xygribPanel->m_windwave_cbox->Disable();
2480 ApplyXyGribConfiguration();
2485void GribRequestSetting::ApplyXyGribConfiguration() {
2486 m_xygribPanel->m_atmmodel_choice->SetSelection(
2487 m_parent.xyGribConfig.atmModelIndex);
2488 m_xygribPanel->m_wavemodel_choice->SetSelection(
2489 m_parent.xyGribConfig.waveModelIndex);
2491 m_xygribPanel->m_wind_cbox->SetValue(m_parent.xyGribConfig.wind);
2492 m_xygribPanel->m_gust_cbox->SetValue(m_parent.xyGribConfig.gust);
2493 m_xygribPanel->m_pressure_cbox->SetValue(m_parent.xyGribConfig.pressure);
2494 m_xygribPanel->m_temperature_cbox->SetValue(
2495 m_parent.xyGribConfig.temperature);
2496 m_xygribPanel->m_cape_cbox->SetValue(m_parent.xyGribConfig.cape);
2497 m_xygribPanel->m_reflectivity_cbox->SetValue(
2498 m_parent.xyGribConfig.reflectivity);
2499 m_xygribPanel->m_cloudcover_cbox->SetValue(m_parent.xyGribConfig.cloudCover);
2500 m_xygribPanel->m_precipitation_cbox->SetValue(
2501 m_parent.xyGribConfig.precipitation);
2502 m_xygribPanel->m_waveheight_cbox->SetValue(m_parent.xyGribConfig.waveHeight);
2503 m_xygribPanel->m_windwave_cbox->SetValue(m_parent.xyGribConfig.windWaves);
2504 m_xygribPanel->m_resolution_choice->SetSelection(
2505 m_parent.xyGribConfig.resolutionIndex);
2506 m_xygribPanel->m_duration_choice->SetSelection(
2507 m_parent.xyGribConfig.durationIndex);
2508 m_xygribPanel->m_interval_choice->SetSelection(
2509 m_parent.xyGribConfig.intervalIndex);
2510 m_xygribPanel->m_run_choice->SetSelection(m_parent.xyGribConfig.runIndex);
2512 UpdateGribSizeEstimate();
2517void GribRequestSetting::MemorizeXyGribConfiguration() {
2518 m_parent.xyGribConfig.atmModelIndex =
2519 m_xygribPanel->m_atmmodel_choice->GetSelection();
2520 m_parent.xyGribConfig.waveModelIndex =
2521 m_xygribPanel->m_wavemodel_choice->GetSelection();
2523 m_parent.xyGribConfig.wind = m_xygribPanel->m_wind_cbox->IsChecked();
2524 m_parent.xyGribConfig.gust = m_xygribPanel->m_gust_cbox->IsChecked();
2525 m_parent.xyGribConfig.pressure = m_xygribPanel->m_pressure_cbox->IsChecked();
2526 m_parent.xyGribConfig.temperature =
2527 m_xygribPanel->m_temperature_cbox->IsChecked();
2528 m_parent.xyGribConfig.cape = m_xygribPanel->m_cape_cbox->IsChecked();
2529 m_parent.xyGribConfig.reflectivity =
2530 m_xygribPanel->m_reflectivity_cbox->IsChecked();
2531 m_parent.xyGribConfig.cloudCover =
2532 m_xygribPanel->m_cloudcover_cbox->IsChecked();
2533 m_parent.xyGribConfig.precipitation =
2534 m_xygribPanel->m_precipitation_cbox->IsChecked();
2535 m_parent.xyGribConfig.waveHeight =
2536 m_xygribPanel->m_waveheight_cbox->IsChecked();
2537 m_parent.xyGribConfig.windWaves = m_xygribPanel->m_windwave_cbox->IsChecked();
2539 m_parent.xyGribConfig.resolutionIndex =
2540 m_xygribPanel->m_resolution_choice->GetSelection();
2541 m_parent.xyGribConfig.durationIndex =
2542 m_xygribPanel->m_duration_choice->GetSelection();
2543 m_parent.xyGribConfig.intervalIndex =
2544 m_xygribPanel->m_interval_choice->GetSelection();
2545 m_parent.xyGribConfig.runIndex = m_xygribPanel->m_run_choice->GetSelection();
2547 UpdateGribSizeEstimate();
2553void GribRequestSetting::UpdateGribSizeEstimate() {
2558 if (!m_xygribPanel->m_resolution_choice->GetStringSelection().ToCDouble(
2560 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2563 if (!m_xygribPanel->m_duration_choice->GetStringSelection().ToCLong(&days)) {
2564 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2567 wxString intvStr = m_xygribPanel->m_interval_choice->GetStringSelection();
2568 intvStr.Replace(
"h",
"");
2569 if (!intvStr.ToCLong(&interval)) {
2570 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2574 if (m_Vp ==
nullptr) {
2575 m_xygribPanel->m_sizeestimate_text->SetLabel(
"Unknown");
2579 double xmax = m_Vp->lon_max;
2580 double xmin = m_Vp->lon_min;
2581 double ymax = m_Vp->lat_max;
2582 double ymin = m_Vp->lat_min;
2584 int npts = (int)(ceil(fabs(xmax - xmin) / resolution) *
2585 ceil(fabs(ymax - ymin) / resolution));
2588 int nbrec = (int)days * 24 / interval + 1;
2590 int nbPress = (m_xygribPanel->m_pressure_cbox->IsChecked() &&
2591 m_xygribPanel->m_pressure_cbox->IsEnabled())
2594 int nbWind = (m_xygribPanel->m_wind_cbox->IsChecked() &&
2595 m_xygribPanel->m_wind_cbox->IsEnabled())
2598 int nbRain = (m_xygribPanel->m_precipitation_cbox->IsChecked() &&
2599 m_xygribPanel->m_precipitation_cbox->IsEnabled())
2602 int nbCloud = (m_xygribPanel->m_cloudcover_cbox->IsChecked() &&
2603 m_xygribPanel->m_cloudcover_cbox->IsEnabled())
2606 int nbTemp = (m_xygribPanel->m_temperature_cbox->IsChecked() &&
2607 m_xygribPanel->m_temperature_cbox->IsEnabled())
2611 int nbCAPEsfc = (m_xygribPanel->m_cape_cbox->IsChecked() &&
2612 m_xygribPanel->m_cape_cbox->IsEnabled())
2615 int nbReflectivity = (m_xygribPanel->m_reflectivity_cbox->IsChecked() &&
2616 m_xygribPanel->m_reflectivity_cbox->IsEnabled())
2619 int nbGUSTsfc = (m_xygribPanel->m_gust_cbox->IsChecked() &&
2620 m_xygribPanel->m_gust_cbox->IsEnabled())
2630 estimate += nbWind * (head + (nbits * npts) / 8 + 2);
2633 estimate += nbTemp * (head + (nbits * npts) / 8 + 2);
2639 estimate += nbRain * (head + 24 + (nbits * npts) / 8 + 2);
2642 estimate += nbPress * (head + (nbits * npts) / 8 + 2);
2645 estimate += nbCloud * (head + 24 + (nbits * npts) / 8 + 2);
2648 estimate += nbReflectivity * (head + (nbits * npts) / 8 + 2);
2651 estimate += nbCAPEsfc * (head + (nbits * npts) / 8 + 2);
2654 estimate += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
2658 int atmEstimate = estimate;
2662 if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2665 npts = (int)(ceil(fabs(xmax - xmin) / 0.5) * ceil(fabs(ymax - ymin) / 0.5));
2666 nbrec = (int)fmin(8, days) * 24 / interval + 1;
2667 }
else if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2671 (int)(ceil(fabs(xmax - xmin) / 0.25) * ceil(fabs(ymax - ymin) / 0.25));
2672 nbrec = (int)fmin(8, days) * 24 / interval + 1;
2673 }
else if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2677 (int)(ceil(fabs(xmax - xmin) / 0.05) * ceil(fabs(ymax - ymin) / 0.1));
2678 nbrec = (int)fmin(4, days) * 24 / interval + 1;
2684 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
2686 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2689 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
2691 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2693 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2695 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2698 int wavEstimate = estimate - atmEstimate;
2700 wavEstimate = wavEstimate * 0.6;
2702 estimate = atmEstimate + wavEstimate;
2705 estimate = estimate * 0.65;
2707 wxString warningStr =
"";
2708 if (estimate / (1024 * 1024) > XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB) {
2709 warningStr = wxString::Format(
"(Warning GRIB exceeds %d MB limit)",
2710 XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB);
2713 m_xygribPanel->m_sizeestimate_text->SetLabel(
2714 wxString::Format(
"%d kB %s", estimate / 1024, warningStr));
2716 m_gribSizeEstimate = estimate;
GRIB Data Visualization and Rendering Factory.
GRIB Weather Data Request and Download Management.
@ WORLD
Global forecast downloads (e.g., GFS)
@ XYGRIB
Downloads from XyGrib service.
@ NONE
No download source selected.
@ LOCAL_CATALOG
Downloads from configured catalogs.
@ LOCAL
Downloads from local sources.
XyGrib Model Configuration and Definitions.
wxString m_grib_dir
Directory containing GRIB files.
grib_pi * pPlugIn
Plugin instance that owns this control bar.
wxArrayString m_file_names
List of GRIB filenames being displayed.
Class GribRequestSettingBase.
Manages GRIB file request configuration and downloads.
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
int Size() const
Return the size of the array or map stored in this value.
bool HasMember(unsigned index) const
Return TRUE if the object contains an element at the specified index.
wxString AsString() const
Return the stored value as a wxWidget's string.
Email Request System for GRIB Data.
GRIB Weather Data Plugin for OpenCPN.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
OpenGL Platform Abstraction Layer.