OpenCPN Partial API docs
Loading...
Searching...
No Matches
GribRequestDialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
23#include "wx/wx.h"
24#include <wx/utils.h>
25#include <sstream>
26#include "email.h"
27#include "XyGribModelDef.h"
28
29#include "pi_gl.h"
30
31#include "GribRequestDialog.h"
32#include "GribOverlayFactory.h"
33#include <wx/wfstream.h>
34#include "grib_pi.h"
35
36#include <unordered_map>
37
38#define RESOLUTIONS 4
39
40enum { SAILDOCS, ZYGRIB }; // grib providers
41enum { GFS, COAMPS, RTOFS, HRRR, ICON, ECMWF }; // forecast models
42
43wxString toMailFormat(int NEflag,
44 int a) // convert position to mail necessary format
45{
46 char c = NEflag == 1 ? a < 0 ? 'S' : 'N' : a < 0 ? 'W' : 'E';
47 wxString s;
48 s.Printf(_T ( "%01d%c" ), abs(a), c);
49 return s;
50}
51
52extern int m_SavedZoneSelMode;
53extern int m_ZoneSelMode;
54
55//----------------------------------------------------------------------------------------------------------
56// GRIB Request Implementation
57//----------------------------------------------------------------------------------------------------------
58GribRequestSetting::GribRequestSetting(GRIBUICtrlBar &parent)
59 : GribRequestSettingBase(&parent), m_parent(parent) {
60 m_Vp = 0;
61 m_oDC = nullptr;
62
63 m_displayScale = 1.0;
64#if defined(__WXOSX__) || defined(__WXGTK3__)
65 // Support scaled HDPI displays.
66 m_displayScale = GetContentScaleFactor();
67#endif
68
69 InitRequestConfig();
70 m_connected = false;
71 m_downloading = false;
72 m_bTransferSuccess = true;
73 m_downloadType = GribDownloadType::NONE;
74
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="
82 "" +
83 bg +
84 ""
85 "><font color="
86 "" +
87 fg +
88 ""
89 ">" +
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 "
94 "temperature, "
95 "atmospheric pressure, wind strength, wind direction, wave height and "
96 "direction for the whole world on a 0.25 degree resolution "
97 "grid with 3 hour "
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 "
106 "canvas.</p>"
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="
123 "" +
124 bg +
125 ""
126 "><font color="
127 "" +
128 fg +
129 ""
130 ">" +
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>"));
135 ReadLocalCatalog();
136 m_bLocal_source_selected = false;
137 EnableDownloadButtons();
138
139 m_selectedAtmModelIndex = 0;
140 m_selectedWaveModelIndex = 0;
141 InitializeXygribDialog();
142}
143
144GribRequestSetting::~GribRequestSetting() {
145 if (m_downloading) {
146 OCPN_cancelDownloadFileBackground(m_download_handle);
147 }
148 if (m_connected) {
149 Disconnect(
150 wxEVT_DOWNLOAD_EVENT,
151 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
152 }
153 delete m_Vp;
154 if (m_oDC) {
155 delete m_oDC;
156 }
157}
158
159void GribRequestSetting::InitRequestConfig() {
160 wxFileConfig *pConf = GetOCPNConfigObject();
161
162 if (pConf) {
163 pConf->SetPath(_T( "/PlugIns/GRIB" ));
164 wxString l;
165 int m;
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 !=
183 AUTO_SELECTION); // has been read in GriUbICtrlBar dialog
184 // implementation or updated previously
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);
197
198 SetCoordinatesText();
199 }
200 // if GriDataConfig has been corrupted , take the standard one to fix a
201 // crash
202 if (m_RequestConfigBase.Len() !=
203 wxString(_T( "000220XX.............." )).Len())
204 m_RequestConfigBase = _T( "000220XX.............." );
205 }
206 // populate model, mail to, waves model choices
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")));
221
222 // Set wxSpinCtrl sizing
223 int w, h;
224 GetTextExtent(_T("-360"), &w, &h, 0, 0,
225 OCPNGetFont(_("Dialog"), 0)); // optimal text control size
226 w += 30;
227 h += 4;
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));
234
235 // add tooltips
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"));
239 m_pCode->SetToolTip(
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"));
243
244 long i, j, k;
245 ((wxString)m_RequestConfigBase.GetChar(0)).ToLong(&i); // MailTo
246 m_pMailTo->SetSelection(i);
247 ((wxString)m_RequestConfigBase.GetChar(1)).ToLong(&i); // Model
248 m_pModel->SetSelection(i);
249 m_cMovingGribEnabled->SetValue(m_RequestConfigBase.GetChar(16) ==
250 'X'); // Moving Grib
251 ((wxString)m_RequestConfigBase.GetChar(2)).ToLong(&i); // Resolution
252 ((wxString)m_RequestConfigBase.GetChar(3)).ToLong(&j); // interval
253 ((wxString)m_RequestConfigBase.GetChar(4)).ToLong(&k, 16); // Time Range
254 k--; // range max = 2 to 16 stored in hexa from 1 to f
255
256#ifdef __WXMSW__ // show / hide sender elemants as necessary
257 m_pSenderSizer->ShowItems(false);
258#else
259 if (m_SendMethod == 0)
260 m_pSenderSizer->ShowItems(false);
261 else
262 m_pSenderSizer->ShowItems(
263 true); // possibility to use "sendmail" method with Linux
264#endif
265
266 m_tMouseEventTimer.Connect(
267 wxEVT_TIMER, wxTimerEventHandler(GribRequestSetting::OnMouseEventTimer),
268 nullptr, this);
269
270 m_RenderZoneOverlay = 0;
271
272 ApplyRequestConfig(i, j, k);
273
274 ((wxString)m_RequestConfigBase.GetChar(5)).ToLong(&j); // Waves model
275 m_pWModel->SetSelection(j);
276
277 m_pWind->Enable(false); // always selected if available
278 m_pPress->Enable(false);
279
280 DimeWindow(this); // aplly global colours scheme
281
282 m_AllowSend = true;
283 m_MailImage->SetValue(WriteMail());
284}
285
286wxWindow *GetGRIBCanvas();
287void GribRequestSetting::OnClose(wxCloseEvent &event) {
288 if (m_downloading) {
289 OCPN_cancelDownloadFileBackground(m_download_handle);
290 m_downloading = false;
291 m_download_handle = 0;
292 }
293 if (m_connected) {
294 Disconnect(
295 wxEVT_DOWNLOAD_EVENT,
296 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
297 }
298 m_RenderZoneOverlay = 0; // eventually stop graphical zone display
299 RequestRefresh(GetGRIBCanvas());
300
301 // allow to be back to old value if changes have not been saved
302 m_ZoneSelMode = m_SavedZoneSelMode;
303 m_parent.SetRequestBitmap(m_ZoneSelMode); // set appopriate bitmap
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;
308 this->Hide();
309}
310
311void GribRequestSetting::SetRequestDialogSize() {
312 int y;
313 /*first let's size the mail display space*/
314 GetTextExtent(_T("abc"), nullptr, &y, 0, 0, OCPNGetFont(_("Dialog"), 0));
315 m_MailImage->SetMinSize(
316 wxSize(-1, ((y * m_MailImage->GetNumberOfLines()) + 10)));
317
318 /*then as default sizing do not work with wxScolledWindow let's compute it*/
319 wxSize scroll =
320 m_fgScrollSizer->Fit(m_sScrolledDialog); // the area size to be scrolled
321
322#ifdef __WXGTK__
323 SetMinSize(wxSize(0, 0));
324#endif
325
326 wxWindow *frame = wxTheApp->GetTopWindow();
327
328 int w = frame->GetClientSize().x; // the display size
329 int h = frame->GetClientSize().y;
330 int dMargin = 80; // set a margin
331 h -= (m_rButton->GetSize().GetY() +
332 dMargin); // height available for the scrolled window
333 w -= dMargin; // width available for the scrolled window
334 m_sScrolledDialog->SetMinSize(
335 wxSize(wxMin(w, scroll.x),
336 wxMin(h, scroll.y))); // set scrolled area size with margin
337
338 Layout();
339 Fit();
340#ifdef __WXGTK__
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));
345#endif
346 Refresh();
347}
348
349void GribRequestSetting::SetVpSize(PlugIn_ViewPort *vp) {
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.;
355 }
356 if ((fabs(vp->lat_min) < 90.) && (fabs(lonmin) < 360.)) {
357 if (lonmin < -180.) lonmin += 360.;
358 if (lonmin > 180.) lonmin -= 360.;
359 }
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;
366
367 if (bnew_val) {
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));
372
373 SetCoordinatesText();
374 m_MailImage->SetValue(WriteMail());
375 }
376}
377
378bool GribRequestSetting::MouseEventHook(wxMouseEvent &event) {
379 if (m_ZoneSelMode == AUTO_SELECTION || m_ZoneSelMode == SAVED_SELECTION ||
380 m_ZoneSelMode == START_SELECTION)
381 return false;
382
383 if (event.Moving())
384 return false; // maintain status bar and tracking dialog updated
385
386 int xm, ym;
387 event.GetPosition(&xm, &ym);
388 xm *= m_displayScale;
389 ym *= m_displayScale;
390
391 // This does not work, but something like it should
392 // wxObject *obj = event.GetEventObject();
393 // wxWindow *win = dynamic_cast<wxWindow*>(obj);
394 // if( win && (win != PluginGetFocusCanvas()))
395 // return false;
396
397 if (event.LeftDown()) {
398 m_parent.pParent->SetFocus();
399 m_ZoneSelMode = DRAW_SELECTION; // restart a new drawing
400 m_parent.SetRequestBitmap(m_ZoneSelMode);
401 if (this->IsShown())
402 this->Hide(); // eventually hide diaog in case of mode change
403 m_RenderZoneOverlay = 0; // eventually hide previous drawing
404 }
405
406 if (event.LeftUp() && m_RenderZoneOverlay == 2) {
407 m_ZoneSelMode = COMPLETE_SELECTION; // ask to complete selection
408 m_parent.SetRequestBitmap(m_ZoneSelMode);
409 SetCoordinatesText();
410 m_MailImage->SetValue(WriteMail());
411 m_RenderZoneOverlay = 1;
412 }
413
414 if (event.Dragging()) {
415 if (m_RenderZoneOverlay < 2) {
416 m_StartPoint =
417 wxPoint(xm, ym); // event.GetPosition(); // starting selection point
418 m_RenderZoneOverlay = 2;
419 }
420 m_IsMaxLong = m_StartPoint.x > xm
421 ? true
422 : false; // find if startpoint is max longitude
423 GetCanvasLLPix(m_Vp, wxPoint(xm, ym) /*event.GetPosition()*/, &m_Lat,
424 &m_Lon); // extend selection
425 if (!m_tMouseEventTimer.IsRunning())
426 m_tMouseEventTimer.Start(20, wxTIMER_ONE_SHOT);
427 }
428 return true;
429}
430
431void GribRequestSetting::OnMouseEventTimer(wxTimerEvent &event) {
432 // compute zone starting point lon/lat for zone drawing
433 double lat, lon;
434 GetCanvasLLPix(m_Vp, m_StartPoint, &lat, &lon);
435
436 // compute rounded coordinates
437 if (lat > m_Lat) {
438 m_spMaxLat->SetValue((int)ceil(lat));
439 m_spMinLat->SetValue((int)floor(m_Lat));
440 } else {
441 m_spMaxLat->SetValue((int)ceil(m_Lat));
442 m_spMinLat->SetValue((int)floor(lat));
443 }
444 if (m_IsMaxLong) {
445 m_spMaxLon->SetValue((int)ceil(lon));
446 m_spMinLon->SetValue((int)floor(m_Lon));
447 } else {
448 m_spMaxLon->SetValue((int)ceil(m_Lon));
449 m_spMinLon->SetValue((int)floor(lon));
450 }
451
452 RequestRefresh(GetGRIBCanvas());
453}
454
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"));
460}
461
462size_t LengthSelToHours(int sel) {
463 switch (sel) {
464 case 1:
465 return 72;
466 case 2:
467 return 999;
468 default:
469 return 24;
470 }
471}
472
473void GribRequestSetting::onDLEvent(OCPN_downloadEvent &ev) {
474 // std::cout << "onDLEvent " << ev.getDLEventCondition() << " "
475 // << ev.getDLEventStatus() << std::endl;
476 switch (ev.getDLEventCondition()) {
477 case OCPN_DL_EVENT_TYPE_END:
478 m_bTransferSuccess =
479 (ev.getDLEventStatus() == OCPN_DL_NO_ERROR) ? true : false;
480 Disconnect(wxEVT_DOWNLOAD_EVENT,
481 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::
482 onDLEvent);
483 m_connected = false;
484 m_downloading = false;
485 m_download_handle = 0;
486 wxYieldIfNeeded();
487 break;
488
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()));
496 break;
499 m_stLocalDownloadInfo->SetLabelText(
500 wxString::Format(_("Downloading... %li / %li"),
501 ev.getTransferred(), ev.getTotal()));
502 break;
504 // Update XyGrib progress gauge
505 m_xygribPanel->m_progress_gauge->SetValue(
506 100 * ev.getTransferred() / ev.getTotal());
507 // Update status text to display information on file size
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));
512 break;
513 default:
514 break;
515 }
516 } else {
517 if (ev.getTransferred() > 0) {
518 switch (m_downloadType) {
520 m_staticTextInfo->SetLabelText(wxString::Format(
521 _("Downloading... %li / ???"), ev.getTransferred()));
522 break;
525 m_stLocalDownloadInfo->SetLabelText(wxString::Format(
526 _("Downloading... %li / ???"), ev.getTransferred()));
527 break;
528 default:
529 break;
530 }
531 }
532 }
533 wxYieldIfNeeded();
534 break;
535 default:
536 break;
537 }
538}
539
540void GribRequestSetting::OnWorldDownload(wxCommandEvent &event) {
541 if (m_downloading) {
542 OCPN_cancelDownloadFileBackground(m_download_handle);
543 m_downloading = false;
544 m_download_handle = 0;
545 Disconnect(
546 wxEVT_DOWNLOAD_EVENT,
547 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
548 m_connected = false;
549 m_btnDownloadWorld->SetLabelText(_("Download"));
550 m_staticTextInfo->SetLabelText(_("Download canceled"));
551 m_canceled = true;
552 m_downloadType = GribDownloadType::NONE;
553 EnableDownloadButtons();
554 wxTheApp->ProcessPendingEvents();
555 wxYieldIfNeeded();
556 return;
557 }
558 m_canceled = false;
559 m_downloading = true;
560 m_downloadType = GribDownloadType::WORLD;
561 EnableDownloadButtons();
562 m_btnDownloadWorld->SetLabelText(_("Cancel"));
563 m_staticTextInfo->SetLabelText(_("Preparing data on server..."));
564 wxYieldIfNeeded();
565 wxString model;
566 switch (m_chECMWFResolution->GetSelection()) {
567 case 0:
568 model = "ecmwf0p25";
569 break;
570 case 1:
571 model = "ecmwfaifs0p25";
572 break;
573 default:
574 model = "ecmwf0p25";
575 break;
576 }
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());
585 wxString filename =
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);
592 if (!m_connected) {
593 m_connected = true;
594 Connect(
595 wxEVT_DOWNLOAD_EVENT,
596 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
597 }
598 auto res =
599 OCPN_downloadFileBackground(oss.str(), path, this, &m_download_handle);
600 while (m_downloading) {
601 wxTheApp->ProcessPendingEvents();
602 wxMilliSleep(10);
603 }
604 if (!m_canceled) {
605 if (m_bTransferSuccess) {
606 m_staticTextInfo->SetLabelText(
607 wxString::Format(_("Download complete: %s"), path.c_str()));
608 wxFileName fn(path);
609 m_parent.m_grib_dir = fn.GetPath();
610 m_parent.m_file_names.Clear();
611 m_parent.m_file_names.Add(path);
612 m_parent.OpenFile();
613 if (m_parent.pPlugIn) {
614 if (m_parent.pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
615 }
616 m_parent.SetDialogsStyleSizePosition(true);
617 Close();
618 } else {
619 m_staticTextInfo->SetLabelText(_("Download failed"));
620 }
621 }
622 m_btnDownloadWorld->SetLabelText(_("Download"));
623 m_downloadType = GribDownloadType::NONE;
624 EnableDownloadButtons();
625}
626
627enum LocalSourceItem { SOURCE, AREA, GRIB };
628
629enum LocalGribDownloadType { DIRECT, MANIFEST, WEBPAGE };
630
631struct GribCatalogInfo : public wxTreeItemData {
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)
636 : type(type),
637 name(name),
638 description(description),
639 url(url),
640 filename(filename),
641 download_type(download_type),
642 latmin(latmin),
643 lonmin(lonmin),
644 latmax(latmax),
645 lonmax(lonmax) {}
646 LocalSourceItem type;
647 wxString name;
648 wxString description;
649 wxString url;
650 wxString filename;
651 LocalGribDownloadType download_type;
652 double latmin;
653 double lonmin;
654 double latmax;
655 double lonmax;
656};
657
658void GribRequestSetting::FillTreeCtrl(wxJSONValue &data) {
659 m_SourcesTreeCtrl1->DeleteAllItems();
660 wxTreeItemId root =
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++) {
664 wxJSONValue source = data["sources"][i];
665 auto info = new GribCatalogInfo(
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++) {
673 wxJSONValue area = source[_T("areas")][j];
674 auto info = new GribCatalogInfo(
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,
683 -1, info);
684 if (area.HasMember("gribs") && area["gribs"].IsArray()) {
685 for (int k = 0; k < area["gribs"].Size(); k++) {
686 wxJSONValue grib = area["gribs"][k];
687 auto info = new GribCatalogInfo(
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);
702 }
703 }
704 }
705 }
706 m_SourcesTreeCtrl1->CollapseAllChildren(src_id);
707 }
708 }
709 m_SourcesTreeCtrl1->Expand(root);
710}
711
712void GribRequestSetting::ReadLocalCatalog() {
713 wxJSONReader reader;
714 wxFileInputStream str(m_parent.pPlugIn->m_local_sources_catalog);
715 wxJSONValue root;
716 reader.Parse(str, &root);
717 FillTreeCtrl(root);
718}
719
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;
726}
727
728void GribRequestSetting::OnLocalTreeSelChanged(wxTreeEvent &event) {
729 wxTreeItemId item = m_SourcesTreeCtrl1->GetSelection();
730 auto src = (GribCatalogInfo *)(m_SourcesTreeCtrl1->GetItemData(item));
731 if (src) {
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);
736 } else {
737 m_stLocalDownloadInfo->SetLabelText(_("Select grib..."));
738 m_bLocal_source_selected = false;
739 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
740 }
741 }
742 EnableDownloadButtons();
743}
744
745void GribRequestSetting::OnUpdateLocalCatalog(wxCommandEvent &event) {
746 if (m_downloading) {
747 OCPN_cancelDownloadFileBackground(m_download_handle);
748 m_downloading = false;
749 m_download_handle = 0;
750 Disconnect(
751 wxEVT_DOWNLOAD_EVENT,
752 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
753 m_connected = false;
754 m_btnDownloadLocal->SetLabelText(_("Download"));
755 m_stLocalDownloadInfo->SetLabelText(_("Download canceled"));
756 m_canceled = true;
757 m_downloadType = GribDownloadType::NONE;
758 EnableDownloadButtons();
759 wxTheApp->ProcessPendingEvents();
760 wxYieldIfNeeded();
761 return;
762 }
763 m_canceled = false;
764 m_downloading = true;
765 m_downloadType = GribDownloadType::LOCAL_CATALOG;
766 EnableDownloadButtons();
767 m_btnDownloadLocal->SetLabelText(_("Cancel"));
768 m_staticTextInfo->SetLabelText(_("Downloading catalog update..."));
769 wxYieldIfNeeded();
770 if (!m_connected) {
771 m_connected = true;
772 Connect(
773 wxEVT_DOWNLOAD_EVENT,
774 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
775 }
776 auto res = OCPN_downloadFileBackground(
777 CATALOG_URL, m_parent.pPlugIn->m_local_sources_catalog + "new", this,
778 &m_download_handle);
779 while (m_downloading) {
780 wxTheApp->ProcessPendingEvents();
781 wxMilliSleep(10);
782 }
783 if (!m_canceled) {
784 if (m_bTransferSuccess) {
785 wxRenameFile(m_parent.pPlugIn->m_local_sources_catalog + "new",
786 m_parent.pPlugIn->m_local_sources_catalog, true);
787 ReadLocalCatalog();
788 m_stLocalDownloadInfo->SetLabelText(_("Catalog update complete."));
789 } else {
790 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
791 }
792 }
793 m_btnDownloadLocal->SetLabelText(_("Download"));
794 m_downloadType = GribDownloadType::NONE;
795 EnableDownloadButtons();
796}
797
798void GribRequestSetting::OnDownloadLocal(wxCommandEvent &event) {
799 if (m_downloading) {
800 OCPN_cancelDownloadFileBackground(m_download_handle);
801 m_downloading = false;
802 m_download_handle = 0;
803 Disconnect(
804 wxEVT_DOWNLOAD_EVENT,
805 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
806 m_connected = false;
807 m_btnDownloadLocal->SetLabelText(_("Download"));
808 m_stLocalDownloadInfo->SetLabelText(_("Download canceled"));
809 m_canceled = true;
810 m_downloadType = GribDownloadType::NONE;
811 EnableDownloadButtons();
812 wxTheApp->ProcessPendingEvents();
813 wxYieldIfNeeded();
814 return;
815 }
816 m_canceled = false;
817 m_downloading = true;
818 m_downloadType = GribDownloadType::LOCAL;
819 EnableDownloadButtons();
820 m_btnDownloadLocal->SetLabelText(_("Cancel"));
821 m_staticTextInfo->SetLabelText(_("Downloading grib..."));
822 wxYieldIfNeeded();
823 auto src = (GribCatalogInfo *)(m_SourcesTreeCtrl1->GetItemData(
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"));
829 m_downloadType = GribDownloadType::NONE;
830 EnableDownloadButtons();
831 return;
832 }
833 if (!m_connected) {
834 m_connected = true;
835 Connect(
836 wxEVT_DOWNLOAD_EVENT,
837 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
838 }
839 wxString url = src->url;
840 // If it is a grib that changes location and requires help of, download the
841 // manifest first
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();
849 wxMilliSleep(10);
850 }
851 bool success = true;
852 if (!m_canceled) {
853 if (!m_bTransferSuccess) {
854 success = false;
855 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
856 }
857 } else {
858 success = false;
859 m_stLocalDownloadInfo->SetLabelText(_("Download canceled"));
860 }
861 if (success) {
862 wxJSONReader reader;
863 wxFileInputStream str(path);
864 wxJSONValue root;
865 reader.Parse(str, &root);
866 if (root.HasMember("url")) {
867 wxString parsed = root["url"].AsString();
868 if (parsed.StartsWith("http")) {
869 url = parsed;
870 } else {
871 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
872 success = false;
873 }
874 }
875 }
876 if (!success) { // Something went wrong, clean up and do not continue to
877 // the actual download
878 m_downloading = false;
879 m_download_handle = 0;
880 Disconnect(wxEVT_DOWNLOAD_EVENT,
881 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::
882 onDLEvent);
883 m_connected = false;
884 m_btnDownloadLocal->SetLabelText(_("Download"));
885 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
886 m_canceled = true;
887 m_downloadType = GribDownloadType::NONE;
888 EnableDownloadButtons();
889 wxTheApp->ProcessPendingEvents();
890 wxYieldIfNeeded();
891 return;
892 }
893 }
894 // Download the actual grib
895 m_downloading = true;
896 wxYieldIfNeeded();
897 if (!m_connected) {
898 m_connected = true;
899 Connect(
900 wxEVT_DOWNLOAD_EVENT,
901 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
902 }
903 wxString filename;
904 if (!src->filename.IsEmpty()) {
905 filename = src->filename;
906 } else {
907 filename =
908 url.AfterLast('/'); // Get last part of the URL and try to sanitize the
909 // filename somewhat if we call some API...
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");
915 }
916 }
917
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();
924 wxMilliSleep(10);
925 }
926 if (!m_canceled) {
927 if (m_bTransferSuccess) {
928 m_stLocalDownloadInfo->SetLabelText(_("Grib download complete."));
929 m_stLocalDownloadInfo->SetLabelText(
930 wxString::Format(_("Download complete: %s"), path.c_str()));
931 wxFileName fn(path);
932 m_parent.m_grib_dir = fn.GetPath();
933 m_parent.m_file_names.Clear();
934 m_parent.m_file_names.Add(
935 path); //("/home/nohal/Downloads/Cherbourg_4km_WRF_WAM_240228-12.grb.bz2");
936 m_parent.OpenFile();
937 if (m_parent.pPlugIn) {
938 if (m_parent.pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
939 }
940 m_parent.SetDialogsStyleSizePosition(true);
941 Close();
942 } else {
943 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
944 }
945 }
946 m_btnDownloadWorld->SetLabelText(_("Download"));
947 m_downloadType = GribDownloadType::NONE;
948 EnableDownloadButtons();
949}
950
951void GribRequestSetting::EnableDownloadButtons() {
952 switch (m_downloadType) {
954 m_btnDownloadWorld->Enable(true);
955 m_btnDownloadLocal->Enable(false);
956 m_buttonUpdateCatalog->Enable(false);
957 break;
960 m_btnDownloadWorld->Enable(false);
961 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
962 m_buttonUpdateCatalog->Enable(false);
963 break;
965 m_xygribPanel->m_download_button->Enable(true);
966 break;
967 default:
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);
972 break;
973 }
974}
975
976void GribRequestSetting::StopGraphicalZoneSelection() {
977 m_RenderZoneOverlay = 0; // eventually stop graphical zone display
978
979 RequestRefresh(GetGRIBCanvas());
980}
981
982void GribRequestSetting::OnVpChange(PlugIn_ViewPort *vp) {
983 if (!vp || m_Vp == vp) return;
984
985 delete m_Vp;
986 m_Vp = new PlugIn_ViewPort(*vp);
987
988 GetCanvasPixLL(m_Vp, &m_StartPoint, m_spMaxLat->GetValue(),
989 m_spMinLon->GetValue());
990
991 if (!m_AllowSend) return;
992 if (m_cManualZoneSel->GetValue()) return;
993
994 SetVpSize(vp);
995 // Viewport has changed : XyGrib estimated size must be recalculated
996 UpdateGribSizeEstimate();
997}
998
999void GribRequestSetting::ApplyRequestConfig(unsigned rs, unsigned it,
1000 unsigned tr) {
1001 // some useful strings
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}, // RTOFS
1006 {_T("0.03"), _T("0.24"), _T("1.0"), wxEmptyString}, // HRRR
1007 {_T("0.0625"), _T("0.125"), wxEmptyString, wxEmptyString}, // ICON
1008 {_T("0.4"), _T("1.0"), _T("2.0"), wxEmptyString} // ECMWF
1009 };
1010
1011 IsZYGRIB = m_pMailTo->GetCurrentSelection() == ZYGRIB;
1012 if (IsZYGRIB)
1013 m_pModel->SetSelection(GFS); // Model is always GFS when Zygrib selected
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;
1019
1020 // populate resolution choice
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);
1027 }
1028 }
1029 }
1030 m_pResolution->SetSelection(rs);
1031
1032 unsigned l;
1033 // populate time interval choice
1034 l = (IsGFS || IsRTOFS || IsICON || IsECMWF) ? 3 : IsHRRR ? 1 : 6;
1035
1036 unsigned m;
1037 m = IsHRRR ? 2 : 25;
1038
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));
1043
1044 // populate time range choice
1045 l = IsZYGRIB ? 8
1046 : IsGFS ? 16
1047 : IsRTOFS ? 6
1048 : IsECMWF ? 10
1049 : IsICON ? 7
1050 : IsHRRR ? 2
1051 : 3;
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));
1056
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));
1063 // gfs & time range less than 8 days
1064 m_pRainfall->SetValue(m_RequestConfigBase.GetChar(9) == 'X' &&
1065 (IsGFS || IsHRRR));
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' &&
1079 (IsGFS || IsHRRR));
1080 m_pCAPE->Enable(IsGFS || IsHRRR);
1081 m_pReflectivity->Enable(IsGFS || IsHRRR);
1082
1083 m_pAltitudeData->SetValue(
1084 (IsGFS || IsICON || IsECMWF)
1085 ? m_RequestConfigBase.GetChar(17) == 'X'
1086 : false); // altitude data zigrib + saildocs GFS and ICON
1087 m_pAltitudeData->Enable(IsGFS || IsICON || IsECMWF);
1088 m_p850hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(18) == 'X'
1089 : false); // only zygrib
1090 m_p850hpa->Enable(IsZYGRIB);
1091 m_p700hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(19) == 'X'
1092 : false); // only zigrib
1093 m_p700hpa->Enable(IsZYGRIB);
1094 m_p500hpa->SetValue((IsGFS || IsICON || IsECMWF)
1095 ? m_RequestConfigBase.GetChar(20) == 'X'
1096 : false); // zigrib + saildocs GFS ICON ECMWF
1097 m_p500hpa->Enable(IsGFS || IsICON || IsECMWF);
1098 m_p300hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(21) == 'X'
1099 : false); // only zigrib
1100 m_p300hpa->Enable(IsZYGRIB);
1101
1102 m_pCurrent->SetValue(IsRTOFS);
1103 m_pCurrent->Enable(false);
1104
1105 // show parameters only if necessary
1106 m_cMovingGribEnabled->Show(!IsZYGRIB); // show/hide Moving settings
1107 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1108 m_cMovingGribEnabled->IsShown());
1109
1110 m_fgLog->ShowItems(IsZYGRIB); // show/hide zigrib login
1111
1112 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked()); // show/hide waves model
1113
1114 m_fgAltitudeData->ShowItems(
1115 m_pAltitudeData->IsChecked()); // show/hide altitude params
1116}
1117
1118void GribRequestSetting::OnTopChange(wxCommandEvent &event) {
1119 // deactivate momentary ZyGrib option
1120 if (m_pMailTo->GetCurrentSelection() == ZYGRIB) {
1121 m_pMailTo->SetSelection(0);
1122 int mes = OCPNMessageBox_PlugIn(
1123 this,
1124 _("Sorry...\nZyGrib momentary stopped providing this service...\nOnly "
1125 "Saildocs option is available"),
1126 _("Warning"), wxOK);
1127 }
1128 ApplyRequestConfig(m_pResolution->GetCurrentSelection(),
1129 m_pInterval->GetCurrentSelection(),
1130 m_pTimeRange->GetCurrentSelection());
1131
1132 m_cMovingGribEnabled->Show(m_pMailTo->GetCurrentSelection() == SAILDOCS);
1133
1134 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1135
1136 SetRequestDialogSize();
1137}
1138
1139void GribRequestSetting::OnZoneSelectionModeChange(wxCommandEvent &event) {
1140 StopGraphicalZoneSelection(); // eventually stop graphical zone display
1141
1142 if (!m_ZoneSelMode) SetVpSize(m_Vp); // recompute zone
1143
1144 if (event.GetId() == MANSELECT) {
1145 // set temporarily zone selection mode if manual selection set, put it
1146 // directly in "drawing" position else put it in "auto selection position
1147 m_ZoneSelMode =
1148 m_cManualZoneSel->GetValue() ? DRAW_SELECTION : AUTO_SELECTION;
1149 m_cUseSavedZone->SetValue(false);
1150 } else if (event.GetId() == SAVEDZONE) {
1151 // set temporarily zone selection mode if saved selection set, put it
1152 // directly in "no selection" position else put it directly in "drawing"
1153 // position
1154 m_ZoneSelMode =
1155 m_cUseSavedZone->GetValue() ? SAVED_SELECTION : DRAW_SELECTION;
1156 }
1157 m_parent.SetRequestBitmap(m_ZoneSelMode); // set appopriate bitmap
1158 fgZoneCoordinatesSizer->ShowItems(
1159 m_ZoneSelMode != AUTO_SELECTION); // show coordinate if necessary
1160 m_cUseSavedZone->Show(m_ZoneSelMode != AUTO_SELECTION);
1161 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1162
1163 SetRequestDialogSize();
1164}
1165
1166bool GribRequestSetting::DoRenderZoneOverlay() {
1167 wxPoint p;
1168 GetCanvasPixLL(m_Vp, &p, m_Lat, m_Lon);
1169
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;
1172
1173 int zw = fabs((double)p.x - m_StartPoint.x);
1174 int zh = fabs((double)p.y - m_StartPoint.y);
1175
1176 wxPoint center;
1177 center.x = x + (zw / 2);
1178 center.y = y + (zh / 2);
1179
1180 wxFont fo = *OCPNGetFont(_("Dialog"), 0);
1181 fo.SetPointSize(
1182 (fo.GetPointSize() * m_displayScale / OCPN_GetWinDIPScaleFactor()));
1183 wxFont *font = &fo;
1184 wxColour pen_color, back_color;
1185 GetGlobalColor(_T ( "DASHR" ), &pen_color);
1186 GetGlobalColor(_T ( "YELO1" ), &back_color);
1187
1188 int label_offsetx = 5, label_offsety = 1;
1189
1190 double size;
1191 EstimateFileSize(&size);
1192
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")));
1200
1201 if (m_pdc) {
1202 wxPen pen(pen_color);
1203 pen.SetWidth(3);
1204 m_pdc->SetPen(pen);
1205 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
1206 m_pdc->DrawRectangle(x, y, zw, zh);
1207
1208 int w, h, sl;
1209#ifdef __WXMAC__
1210 wxScreenDC sdc;
1211 sdc.GetMultiLineTextExtent(label, &w, &h, &sl, font);
1212#else
1213 m_pdc->GetMultiLineTextExtent(label, &w, &h, &sl, font);
1214 w *= OCPN_GetWinDIPScaleFactor();
1215 h *= OCPN_GetWinDIPScaleFactor();
1216#endif
1217 w += 2 * label_offsetx, h += 2 * label_offsety;
1218 x = center.x - (w / 2);
1219 y = center.y - (h / 2);
1220
1221 h *= m_displayScale;
1222 w *= m_displayScale;
1223
1224 wxBitmap bm(w, h);
1225 wxMemoryDC mdc(bm);
1226 mdc.Clear();
1227
1228 mdc.SetFont(*font);
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));
1234
1235 wxImage im = bm.ConvertToImage();
1236 im.InitAlpha();
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);
1240
1241 m_pdc->DrawBitmap(im, x, y, true);
1242
1243 } else {
1244#ifdef ocpnUSE_GL
1245#ifndef USE_ANDROID_GLES2
1246
1247 if (!m_oDC) {
1248 m_oDC = new pi_ocpnDC();
1249 }
1250
1251 m_oDC->SetVP(m_Vp);
1252 m_oDC->SetPen(wxPen(pen_color, 3));
1253
1254 wxPoint outline[5];
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);
1261
1262 m_oDC->SetFont(*font);
1263 int w, h, ww, hw;
1264 m_oDC->GetTextExtent(label, &w, &h);
1265 h *= m_displayScale;
1266 w *= m_displayScale;
1267
1268 m_oDC->GetTextExtent("W", &ww, &hw);
1269
1270 int label_offsetx = ww, label_offsety = 1;
1271 int x = center.x - w / 2;
1272 int y = center.y - h / 2;
1273
1274 w += 2 * label_offsetx, h += 2 * label_offsety;
1275
1276 m_oDC->SetBrush(wxBrush(back_color));
1277 m_oDC->DrawRoundedRectangle(x, y, w, h, 0);
1278
1279 /* draw bounding rectangle */
1280 m_oDC->SetPen(wxPen(wxColour(0, 0, 0), 1));
1281
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);
1288
1289 m_oDC->DrawText(label, x + label_offsetx, y + label_offsety);
1290
1291#endif
1292#endif
1293 }
1294 return true;
1295}
1296
1297bool GribRequestSetting::RenderGlZoneOverlay() {
1298 if (m_RenderZoneOverlay == 0) return false;
1299 m_pdc = nullptr; // inform lower layers that this is OpenGL render
1300 return DoRenderZoneOverlay();
1301}
1302
1303bool GribRequestSetting::RenderZoneOverlay(wxDC &dc) {
1304 if (m_RenderZoneOverlay == 0) return false;
1305 m_pdc = &dc;
1306 return DoRenderZoneOverlay();
1307}
1308
1309void GribRequestSetting::OnMovingClick(wxCommandEvent &event) {
1310 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1311 m_cMovingGribEnabled->IsShown());
1312
1313 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1314 SetRequestDialogSize();
1315
1316 this->Refresh();
1317}
1318
1319void GribRequestSetting::OnCoordinatesChange(wxSpinEvent &event) {
1320 SetCoordinatesText();
1321
1322 StopGraphicalZoneSelection(); // eventually stop graphical zone display
1323
1324 if (!m_AllowSend) return;
1325
1326 m_MailImage->SetValue(WriteMail());
1327}
1328
1329void GribRequestSetting::OnAnyChange(wxCommandEvent &event) {
1330 m_fgAltitudeData->ShowItems(m_pAltitudeData->IsChecked());
1331
1332 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1333
1334 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1335
1336 SetRequestDialogSize();
1337}
1338
1339void GribRequestSetting::OnTimeRangeChange(wxCommandEvent &event) {
1340 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1341
1342 if (m_pModel->GetCurrentSelection() == 0) { // gfs
1343 if (m_pTimeRange->GetCurrentSelection() >
1344 6) { // time range more than 8 days
1345 m_pWaves->SetValue(0);
1346 m_pWaves->Enable(false);
1347 OCPNMessageBox_PlugIn(
1348 this,
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."),
1354 _("Warning!"));
1355 } else
1356 m_pWaves->Enable(true);
1357 }
1358
1359 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1360
1361 SetRequestDialogSize();
1362}
1363
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')); // recipient
1371 m_cMovingGribEnabled->IsChecked()
1372 ? m_RequestConfigBase.SetChar(16, 'X') // moving grib
1373 : m_RequestConfigBase.SetChar(16, '.');
1374
1375 if (!IsZYGRIB)
1376 m_RequestConfigBase.SetChar(
1377 1, (char)(m_pModel->GetCurrentSelection() + '0')); // model
1378 if (!IsECMWF)
1379 m_RequestConfigBase.SetChar(
1380 2, (char)(m_pResolution->GetCurrentSelection() + '0')); // resolution
1381
1382 m_RequestConfigBase.SetChar(3,
1383 (char)(m_pInterval->GetCurrentSelection() + '0'));
1384
1385 wxString range;
1386 range.Printf(_T("%x"), m_pTimeRange->GetCurrentSelection() +
1387 1); // range max = 2 to 16 stored in hexa 1 to f
1388 m_RequestConfigBase.SetChar(4, range.GetChar(0));
1389
1390 if (IsZYGRIB && m_pWModel->IsShown())
1391 m_RequestConfigBase.SetChar(
1392 5, (char)(m_pWModel->GetCurrentSelection() + '0')); // waves model
1393
1394 m_RequestConfigBase.SetChar(
1395 6, 'X'); // wind must be always selected as a default
1396 m_RequestConfigBase.SetChar(
1397 7, 'X'); // pressure must be always selected as a default
1398
1399 if (!IsCOAMPS && !IsRTOFS) {
1400 m_pWindGust->IsChecked() ? m_RequestConfigBase.SetChar(14, 'X') // Gust
1401 : m_RequestConfigBase.SetChar(14, '.');
1402 m_pWaves->IsChecked() ? m_RequestConfigBase.SetChar(8, 'X') // waves
1403 : m_RequestConfigBase.SetChar(8, '.');
1404 m_pRainfall->IsChecked() ? m_RequestConfigBase.SetChar(9, 'X') // rainfall
1405 : m_RequestConfigBase.SetChar(9, '.');
1406 m_pCloudCover->IsChecked() ? m_RequestConfigBase.SetChar(10, 'X') // clouds
1407 : m_RequestConfigBase.SetChar(10, '.');
1408 m_pAirTemp->IsChecked() ? m_RequestConfigBase.SetChar(11, 'X') // air temp
1409 : m_RequestConfigBase.SetChar(11, '.');
1410 m_pSeaTemp->IsChecked() ? m_RequestConfigBase.SetChar(12, 'X') // sea temp
1411 : m_RequestConfigBase.SetChar(12, '.');
1412 m_pCAPE->IsChecked() ? m_RequestConfigBase.SetChar(15, 'X') // cape
1413 : m_RequestConfigBase.SetChar(15, '.');
1414 }
1415 if (IsRTOFS) // current
1416 m_pCurrent->IsChecked() ? m_RequestConfigBase.SetChar(13, 'X')
1417 : m_RequestConfigBase.SetChar(13, '.');
1418
1419 if (IsGFS || IsICON || IsECMWF) {
1420 m_pAltitudeData->IsChecked()
1421 ? m_RequestConfigBase.SetChar(17, 'X') // altitude data
1422 : m_RequestConfigBase.SetChar(17, '.');
1423 m_p500hpa->IsChecked() ? m_RequestConfigBase.SetChar(20, 'X')
1424 : m_RequestConfigBase.SetChar(20, '.');
1425 }
1426 if (IsZYGRIB) {
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, '.');
1433 }
1434
1435 wxFileConfig *pConf = GetOCPNConfigObject();
1436 if (pConf) {
1437 pConf->SetPath(_T( "/PlugIns/GRIB" ));
1438
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());
1447
1448 m_SavedZoneSelMode = m_cUseSavedZone->GetValue() ? SAVED_SELECTION
1449 : m_cManualZoneSel->GetValue() ? START_SELECTION
1450 : AUTO_SELECTION;
1451 pConf->Write(_T( "ManualRequestZoneSizing" ), m_SavedZoneSelMode);
1452
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());
1457 }
1458
1459 wxCloseEvent evt;
1460 OnClose(evt);
1461}
1462
1463wxString GribRequestSetting::WriteMail() {
1464 // define size limits for zyGrib
1465 int limit = IsZYGRIB ? 2 : 0; // new limit 2 mb
1466
1467 m_MailError_Nb = 0;
1468 // some useful strings
1469 const wxString s[] = {_T(","), _T(" ")}; // separators
1470 const wxString p[][11] = {
1471 // parameters GFS from Saildocs
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},
1475 {}, // COAMPS
1476 {}, // RTOFS
1477 {}, // HRRR = same parameters as GFS
1478 // parametres ICON
1479 {_T(""), _T(""), _T("AIRTMP"), _T(""), _T("SFCTMP"), _T("GUST"), _T(""),
1480 _T(""), _T(""), _T("WIND500,HGT500"), _T("")},
1481 // parametres ECMWF
1482 {_T(""), _T(""), _T("TEMP"), _T("WAVES"), _T(""), _T(""), _T(""), _T(""),
1483 _T(""), _T("WIND500,HGT500"), _T("")},
1484 // parameters GFS from zygrib
1485 {_T("PRECIP"), _T("CLOUD"), _T("TEMP"), _T("WVSIG WVWIND"), wxEmptyString,
1486 _T("GUST"), _T("CAPE"), _T("A850"), _T("A700"), _T("A500"), _T("A300")}};
1487
1488 wxString r_topmess, r_parameters, r_zone;
1489 // write the top part of the mail
1490 switch (m_pMailTo->GetCurrentSelection()) {
1491 case SAILDOCS: // Saildocs
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())
1500 .Append(_T(","))
1501 .Append(m_pResolution->GetStringSelection())
1502 .Append(_T("|"));
1503 double v;
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"));
1508 break;
1509 case ZYGRIB: // Zygrib
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"));
1533 }
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())
1537 m_MailError_Nb = 6;
1538 break;
1539 }
1540 // write the parameters part of the mail
1541 int GFSZ = IsZYGRIB ? 6 : 0;
1542 switch (m_pModel->GetCurrentSelection()) {
1543 case GFS: // GFS
1544 r_parameters = wxT("WIND") + s[m_pMailTo->GetCurrentSelection()] +
1545 wxT("PRESS"); // the default minimum request parameters
1546 if (m_pRainfall->IsChecked())
1547 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1548 p[GFS + GFSZ][0]);
1549 if (m_pCloudCover->IsChecked())
1550 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1551 p[GFS + GFSZ][1]);
1552 if (m_pAirTemp->IsChecked())
1553 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1554 p[GFS + GFSZ][2]);
1555 if (m_pWaves->IsChecked())
1556 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1557 p[GFS + GFSZ][3]);
1558 if (m_pSeaTemp->IsChecked())
1559 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1560 p[GFS + GFSZ][4]);
1561 if (m_pWindGust->IsChecked())
1562 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1563 p[GFS + GFSZ][5]);
1564 if (m_pCAPE->IsChecked())
1565 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1566 p[GFS + GFSZ][6]);
1567 if (m_pAltitudeData->IsChecked()) {
1568 if (m_p850hpa->IsChecked())
1569 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1570 p[GFS + GFSZ][7]);
1571 if (m_p700hpa->IsChecked())
1572 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1573 p[GFS + GFSZ][8]);
1574 if (m_p500hpa->IsChecked())
1575 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1576 p[GFS + GFSZ][9]);
1577 if (m_p300hpa->IsChecked())
1578 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1579 p[GFS + GFSZ][10]);
1580 }
1581 break;
1582 case COAMPS: // COAMPS
1583 r_parameters = wxT("WIND,PRMSL"); // the default parameters for this
1584 // model
1585 break;
1586 case RTOFS: // RTOFS
1587 r_parameters = wxT("CUR,WTMP"); // the default parameters for this model
1588 break;
1589 case HRRR: // HRRR
1590 r_parameters = wxT("WIND,PRMSL"); // the default parameters for this
1591 // model
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]);
1602 break;
1603 case ICON:
1604 r_parameters = wxT("WIND,PRMSL"); // the default parameters for this
1605 // model
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]);
1615 }
1616 break;
1617 case ECMWF:
1618 r_parameters = wxT("WIND,MSLP"); // the default parameters for this
1619 // model
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()] +
1625 p[ECMWF][9]);
1626 }
1627 if (m_pWaves->IsChecked())
1628 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][3]);
1629 break;
1630 }
1631 if (!IsZYGRIB && m_cMovingGribEnabled->IsChecked()) // moving grib
1632 r_parameters.Append(wxString::Format(
1633 _T("|%d,%d"), m_sMovingSpeed->GetValue(), m_sMovingCourse->GetValue()));
1634
1635 // line lenth limitation
1636 int j = 0;
1637 char c = m_pMailTo->GetCurrentSelection() == SAILDOCS ? ',' : ' ';
1638 for (size_t i = 0; i < r_parameters.Len(); i++) {
1639 if (r_parameters.GetChar(i) == '|')
1640 j--; // do not split Saildocs "moving" values
1641 if (r_parameters.GetChar(i) == c) j++;
1642 if (j > 6) { // no more than 6 parameters on the same line
1643 r_parameters.insert(i + 1, m_pMailTo->GetCurrentSelection() == SAILDOCS
1644 ? _T("=\n")
1645 : _T("\n"));
1646 break;
1647 }
1648 }
1649
1650 double size;
1651 m_MailError_Nb += EstimateFileSize(&size);
1652
1653 m_tFileSize->SetLabel(wxString::Format(_T("%1.2f " ), size) + _("MB"));
1654
1655 if (IsZYGRIB) {
1656 m_tLimit->SetLabel(wxString(_T("( ")) + _("Max") +
1657 wxString::Format(_T(" %d "), limit) + _("MB") +
1658 _T(" )"));
1659 if (size > limit) m_MailError_Nb += 2;
1660 } else
1661 m_tLimit->SetLabel(wxEmptyString);
1662
1663 return wxString(r_topmess + r_parameters);
1664}
1665
1666int GribRequestSetting::EstimateFileSize(double *size) {
1667 if (!size) return 0; // Wrong parameter
1668 *size = 0.;
1669
1670 // too small zone ? ( mini 2 * resolutions )
1671 double reso, time, inter;
1672 m_pResolution->GetStringSelection().ToDouble(&reso);
1673 m_pTimeRange->GetStringSelection().ToDouble(&time);
1674 m_pInterval->GetStringSelection().ToDouble(&inter);
1675
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; // maxlat must be > minlat
1679 double wlon = (maxlon > minlon ? 0 : 360) + maxlon - minlon;
1680 if (wlon > 180 || (maxlat - minlat > 180)) return 4; // ovoid too big area
1681
1682 if (fabs(wlon) < 2 * reso || maxlat - minlat < 2 * reso)
1683 return 5; // ovoid too small area
1684
1685 int npts = (int)(ceil(((double)(maxlat - minlat) / reso)) *
1686 ceil(((double)(wlon) / reso)));
1687
1688 if (m_pModel->GetCurrentSelection() == COAMPS) // limited area for COAMPS
1689 npts = wxMin(npts, (int)(ceil(40.0 / reso) * ceil(40.0 / reso)));
1690
1691 // Nombre de GribRecords
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;
1703 int nbAltitude =
1704 IsZYGRIB ? 5 * nbrec : 3 * nbrec; // five data types are included in each
1705 // ZyGrib altitude request and only
1706 // three in sSaildocs's
1707 int head = 84;
1708 double estime = 0.0;
1709 int nbits;
1710
1711 nbits = 13;
1712 estime += nbWind * (head + (nbits * npts) / 8 + 2);
1713 estime += nbCurrent * (head + (nbits * npts) / 8 + 2);
1714
1715 nbits = 11;
1716 estime += nbTemp * (head + (nbits * npts) / 8 + 2);
1717 estime += nbSTemp * (head + (nbits * npts) / 8 + 2);
1718
1719 nbits = 4;
1720 estime += nbRain * (head + (nbits * npts) / 8 + 2);
1721
1722 nbits = 15;
1723 estime += nbPress * (head + (nbits * npts) / 8 + 2);
1724
1725 nbits = 4;
1726 estime += nbCloud * (head + (nbits * npts) / 8 + 2);
1727
1728 nbits = 7;
1729 estime += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
1730
1731 nbits = 5;
1732 estime += nbCape * (head + (nbits * npts) / 8 + 2);
1733
1734 nbits = 6;
1735 estime += nbwave * (head + (nbits * npts) / 8 + 2);
1736
1737 if (m_pAltitudeData->IsChecked()) {
1738 int nbalt = 0;
1739 if (m_p850hpa->IsChecked()) nbalt++;
1740 if (m_p700hpa->IsChecked()) nbalt++;
1741 if (m_p500hpa->IsChecked()) nbalt++;
1742 if (m_p300hpa->IsChecked()) nbalt++;
1743
1744 nbits = 12;
1745 estime += nbAltitude * nbalt * (head + (nbits * npts) / 8 + 2);
1746 }
1747
1748 *size = estime / (1024. * 1024.);
1749
1750 return 0;
1751}
1752
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"}};
1762
1763 wxString encoded;
1764 for (size_t i = 0; i < uri.length(); ++i) {
1765 wxChar ch = uri[i];
1766 std::unordered_map<int, wxString>::iterator iter = sEncodeMap.find((int)ch);
1767 if (iter != sEncodeMap.end()) {
1768 encoded << iter->second;
1769 } else {
1770 encoded << ch;
1771 }
1772 }
1773 return encoded;
1774}
1775
1776void GribRequestSetting::OnSendMaiL(wxCommandEvent &event) {
1777 StopGraphicalZoneSelection(); // eventually stop graphical zone display
1778
1779 if (!m_AllowSend) {
1780 m_rButtonCancel->Show();
1781 m_rButtonApply->Show();
1782 m_rButtonYes->SetLabel(_("Send"));
1783
1784 m_MailImage->SetForegroundColour(
1785 wxColor(0, 0, 0)); // permit to send a (new) message
1786 m_AllowSend = true;
1787
1788 m_MailImage->SetValue(WriteMail());
1789 SetRequestDialogSize();
1790
1791 return;
1792 }
1793
1794 const wxString error[] = {
1795 _T("\n\n"),
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!")};
1802
1803 ::wxBeginBusyCursor();
1804
1805 m_MailImage->SetForegroundColour(wxColor(255, 0, 0));
1806 m_AllowSend = false;
1807
1808 if (m_MailError_Nb) {
1809 if (m_MailError_Nb > 7) {
1810 m_MailImage->SetValue(error[1] + error[0] + error[m_MailError_Nb - 6]);
1811 } else {
1812 if (m_MailError_Nb == 6) m_MailError_Nb = 1;
1813 m_MailImage->SetValue(error[m_MailError_Nb]);
1814 }
1815
1816 m_rButtonCancel->Hide();
1817 m_rButtonApply->Hide();
1818 m_rButtonYes->SetLabel(_("Continue..."));
1819 m_rButton->Layout();
1820 SetRequestDialogSize();
1821
1822 ::wxEndBusyCursor();
1823
1824 return;
1825 }
1826
1827#ifdef __WXMAC__
1828 // macOS, at least Big Sur, requires the body to be URLEncoded, otherwise the
1829 // invocation of the mail application via sh/open in wxEmail fails due to
1830 // "invalid characters" in "filename" regardless of quotation used (which is
1831 // weird, but real)
1832 wxMailMessage *message = new wxMailMessage(
1833 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1834 ? _T("grib-request")
1835 : wxT("gribauto"), // requested subject
1836 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1837 ? m_MailToAddresses.BeforeFirst(_T(';')) // to request address
1838 : m_MailToAddresses.AfterFirst(_T(';')).BeforeFirst(_T(';')),
1839 EncodeURL(WriteMail()), // message image
1840 m_pSenderAddress->GetValue());
1841#else
1842 wxMailMessage *message = new wxMailMessage(
1843 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1844 ? _T("grib-request")
1845 : wxT("gribauto"), // requested subject
1846 (m_pMailTo->GetCurrentSelection() == SAILDOCS)
1847 ? m_MailToAddresses.BeforeFirst(_T(';')) // to request address
1848 : m_MailToAddresses.AfterFirst(_T(';')).BeforeFirst(_T(';')),
1849 WriteMail(), // message image
1850 m_pSenderAddress->GetValue());
1851#endif
1852
1853 wxEmail mail;
1854 if (mail.Send(*message, m_SendMethod)) {
1855#ifdef __WXMSW__
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..."));
1860#else
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..."));
1866 } else {
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 "
1870 "Continue..."));
1871 }
1872#endif
1873 } else {
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();
1879 }
1880 m_rButtonYes->SetLabel(_("Continue..."));
1881 m_rButton->Layout();
1882 SetRequestDialogSize();
1883 delete message;
1884 ::wxEndBusyCursor();
1885}
1886
1889wxString GribRequestSetting::BuildXyGribUrl() {
1890 // Server's base address
1891 wxString urlStr =
1892 wxString::Format("http://grbsrv.opengribs.org/getmygribs2.php?");
1893 // Bounding box
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));
1898
1899 // Atmospheric Model & resolution reference
1900 urlStr << wxString::Format(
1901 "&model=%s",
1902 xygribAtmModelList[m_selectedAtmModelIndex]
1903 ->reqName[m_xygribPanel->m_resolution_choice->GetSelection()]);
1904 // Interval
1905 urlStr << wxString::Format(
1906 "&intv=%d",
1907 xygribAtmModelList[m_selectedAtmModelIndex]
1908 ->interval[m_xygribPanel->m_interval_choice->GetSelection()]);
1909 // Length in days
1910 urlStr << wxString::Format(
1911 "&days=%d", m_xygribPanel->m_duration_choice->GetSelection() + 1);
1912
1913 // Selected run
1914 // TODO : available runs depend on model
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";
1924 } else {
1925 urlStr << "&cyc=last";
1926 }
1927
1928 // Atmospheric data fields
1929 urlStr << "&par=";
1930 if (m_xygribPanel->m_wind_cbox->IsEnabled() &&
1931 m_xygribPanel->m_wind_cbox->IsChecked())
1932 urlStr << "W;";
1933 if (m_xygribPanel->m_pressure_cbox->IsEnabled() &&
1934 m_xygribPanel->m_pressure_cbox->IsChecked()) {
1935 if (xygribAtmModelList[m_selectedAtmModelIndex]->altPressure) {
1936 urlStr << "p;";
1937 } else {
1938 urlStr << "P;";
1939 }
1940 }
1941 if (m_xygribPanel->m_precipitation_cbox->IsEnabled() &&
1942 m_xygribPanel->m_precipitation_cbox->IsChecked())
1943 urlStr << "R;";
1944 if (m_xygribPanel->m_cloudcover_cbox->IsEnabled() &&
1945 m_xygribPanel->m_cloudcover_cbox->IsChecked())
1946 urlStr << "C;";
1947 if (m_xygribPanel->m_temperature_cbox->IsEnabled() &&
1948 m_xygribPanel->m_temperature_cbox->IsChecked())
1949 urlStr << "T;";
1950 if (m_xygribPanel->m_cape_cbox->IsEnabled() &&
1951 m_xygribPanel->m_cape_cbox->IsChecked())
1952 urlStr << "c;";
1953 if (m_xygribPanel->m_reflectivity_cbox->IsEnabled() &&
1954 m_xygribPanel->m_reflectivity_cbox->IsChecked())
1955 urlStr << "r;";
1956 if (m_xygribPanel->m_gust_cbox->IsEnabled() &&
1957 m_xygribPanel->m_gust_cbox->IsChecked())
1958 urlStr << "G;";
1959
1960 // Wave model a data fields
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()) {
1967 wParams << "s;";
1968 }
1969 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
1970 wParams << "h;d;p;";
1971 }
1972 if (wParams.length() > 0) {
1973 urlStr << wxString::Format("%s&wpar=%s", modelStr.c_str(),
1974 wParams.c_str());
1975 } else {
1976 urlStr << "&wmdl=none";
1977 }
1978 } else {
1979 urlStr << "&wmdl=none";
1980 }
1981
1982 return urlStr;
1983}
1984
1987wxString GribRequestSetting::BuildGribFileName() {
1988 wxString selStr = m_xygribPanel->m_resolution_choice->GetStringSelection();
1989 selStr.Replace(".", "P");
1990
1991 wxString fileName;
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);
1996 } else {
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());
2001 }
2002
2003 return fileName;
2004}
2005
2011void GribRequestSetting::OnXyGribDownloadButton(wxCommandEvent &event) {
2012 // Check if we are already downloading a GRIB file
2013 if (m_downloading) {
2014 // Yes : it means that "Download" button has been changed to "Cancel"
2015 // button. So, let's cancel the on-going download
2016 OCPN_cancelDownloadFileBackground(m_download_handle);
2017 m_downloading = false;
2018 m_download_handle = 0;
2019 Disconnect(
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"));
2026 m_canceled = true;
2027 m_downloadType = GribDownloadType::NONE;
2028 EnableDownloadButtons();
2029 wxTheApp->ProcessPendingEvents();
2030 wxYieldIfNeeded();
2031 return;
2032 }
2033 // No : start a new download
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));
2038 return;
2039 }
2040
2041 // First we memorize the current configuration. This is the one which will be
2042 // saved in OpenCPN' config file at exit
2043 MemorizeXyGribConfiguration();
2044 m_canceled = false;
2045 m_downloading = true;
2046 m_downloadType = GribDownloadType::XYGRIB;
2047 EnableDownloadButtons();
2048 // Change "Download" button into "Cancel" button
2049 m_xygribPanel->m_download_button->SetLabelText(_("Cancel"));
2050 m_xygribPanel->m_status_text->SetLabelText(
2051 _("Preparing GRIB file on server..."));
2052 wxYieldIfNeeded();
2053
2054 // Build the XyGrib DownloadURL from the current GUI configuration
2055 wxString requestUrl = BuildXyGribUrl();
2056
2057 // First we download the temporary XML file that will tell us where to
2058 // download the file on the server Downloading the XML triggers the
2059 // construction of the GRIB file on the server.
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();
2064 path << filename;
2065 if (!m_connected) {
2066 m_connected = true;
2067 Connect(
2068 wxEVT_DOWNLOAD_EVENT,
2069 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2070 }
2071 auto res = OCPN_downloadFileBackground(requestUrl.c_str(), path, this,
2072 &m_download_handle);
2073
2074 // Wait for the file to be downloaded. Note that it can take some time because
2075 // server will not send it to us until the GRIB file is ready, or an error
2076 // occured.
2077 while (m_downloading) {
2078 wxTheApp->ProcessPendingEvents();
2079 wxMilliSleep(10);
2080 }
2081
2082 if ((m_canceled) || (!m_bTransferSuccess)) {
2083 // Something went wrong : publish error on GUI
2084 m_xygribPanel->m_status_text->SetLabelText(_("Grib request failed"));
2085 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2086 m_downloadType = GribDownloadType::NONE;
2087 EnableDownloadButtons();
2088 wxRemoveFile(path);
2089 return;
2090 }
2091
2092 // Read the XML file in a wxString
2093 wxFile xmlFile;
2094 wxString strXml;
2095 bool readOk = xmlFile.Open(path);
2096 if (readOk) {
2097 readOk &= xmlFile.ReadAll(&strXml);
2098 if (readOk) {
2099 xmlFile.Close();
2100 }
2101 }
2102
2103 // Quick and dirty read of the XML file to check status (OK/NOK)
2104 wxString url;
2105 if (readOk && (((int)strXml.find("\"status\":true") == wxNOT_FOUND))) {
2106 // Status is NOK : stop download and report error to GUI
2107 wxString errorStr;
2108 int errPos = strXml.find("\"message\":\"");
2109 int errEnd = strXml.find("\"}");
2110 if ((errPos != wxNOT_FOUND) && (errEnd != wxNOT_FOUND)) {
2111 errPos += 11;
2112 errorStr = strXml.Mid(errPos, errEnd - errPos);
2113 } else {
2114 errorStr = "Unknown server error";
2115 }
2116
2117 m_xygribPanel->m_status_text->SetLabelText(
2118 wxString::Format("%s (%s)", _("Server Error"), errorStr));
2119 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2120 m_downloadType = GribDownloadType::NONE;
2121 EnableDownloadButtons();
2122 wxRemoveFile(path);
2123 return;
2124 } else {
2125 // Extract GRIB URL from XML
2126 int urlPos = strXml.find("\"url\":\"http:");
2127 int urlEnd = strXml.find(".grb2\"");
2128 if ((urlPos != wxNOT_FOUND) && (urlEnd != wxNOT_FOUND)) {
2129 urlPos += 7;
2130 urlEnd += 5;
2131 url = strXml.Mid(urlPos, urlEnd - urlPos);
2132 url.Replace("\\/", "/");
2133 } else {
2134 readOk = false;
2135 }
2136 }
2137
2138 wxRemoveFile(path);
2139
2140 // Check if there was any error in the previous phase
2141 if (!readOk) {
2142 // Yes : stop download and report error to GUI
2143 m_xygribPanel->m_status_text->SetLabelText(
2144 _("Error parsing XML file from server"));
2145 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2146 m_downloadType = GribDownloadType::NONE;
2147 EnableDownloadButtons();
2148 return;
2149 }
2150
2151 m_xygribPanel->m_status_text->SetLabelText(_("Downloading GRIB file"));
2152
2153 // Build name of the GRIB file for disk storage
2154 path = m_parent.GetGribDir();
2155 path << wxFileName::GetPathSeparator();
2156 path << BuildGribFileName();
2157
2158 // Start download
2159 m_canceled = false;
2160 m_downloading = true;
2161 if (!m_connected) {
2162 m_connected = true;
2163 Connect(
2164 wxEVT_DOWNLOAD_EVENT,
2165 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2166 }
2167 res =
2168 OCPN_downloadFileBackground(url.c_str(), path, this, &m_download_handle);
2169 // Wait for end of download. Note that the previously registered callback
2170 // "onDLEvent" will update the progress indicator on the GUI.
2171 while (m_downloading) {
2172 wxTheApp->ProcessPendingEvents();
2173 wxMilliSleep(10);
2174 }
2175
2176 // Download finished : restore "Download" button
2177 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2178
2179 if (!m_canceled) {
2180 if (m_bTransferSuccess) {
2181 // Transfer successfull : switch to GRIB display on chart
2182 m_xygribPanel->m_status_text->SetLabelText(_("Download complete"));
2183 wxFileName fn(path);
2184 m_parent.m_grib_dir = fn.GetPath();
2185 m_parent.m_file_names.Clear();
2186 m_parent.m_file_names.Add(path);
2187 m_parent.OpenFile();
2188 if (m_parent.pPlugIn) {
2189 if (m_parent.pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
2190 }
2191 m_parent.SetDialogsStyleSizePosition(true);
2192 Close();
2193 } else {
2194 // Download failed : report error to GUI
2195 m_xygribPanel->m_status_text->SetLabelText(_("Download failed"));
2196 }
2197 }
2198 m_downloadType = GribDownloadType::NONE;
2199 EnableDownloadButtons();
2200}
2201
2205void GribRequestSetting::OnXyGribAtmModelChoice(wxCommandEvent &event) {
2206 AtmModelDef_t *selectedAtmModel = nullptr;
2207
2208 // Find the model descriptor associated to the selected atmospheric model
2209 wxString atmModel = m_xygribPanel->m_atmmodel_choice->GetStringSelection();
2210 int modelIndex = 0;
2211 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) != nullptr) {
2212 if (selectedAtmModel->name.IsSameAs(atmModel, true)) {
2213 break;
2214 }
2215 modelIndex++;
2216 }
2217
2218 // If not found, use the first one. This is not supposed to happen.
2219 if (selectedAtmModel == nullptr) {
2220 selectedAtmModel = xygribAtmModelList[0];
2221 modelIndex = 0;
2222 }
2223
2224 // Enable or disable parameters according to the model definition
2225 if (selectedAtmModel->wind)
2226 m_xygribPanel->m_wind_cbox->Enable();
2227 else
2228 m_xygribPanel->m_wind_cbox->Disable();
2229
2230 if (selectedAtmModel->gust)
2231 m_xygribPanel->m_gust_cbox->Enable();
2232 else
2233 m_xygribPanel->m_gust_cbox->Disable();
2234
2235 if (selectedAtmModel->pressure)
2236 m_xygribPanel->m_pressure_cbox->Enable();
2237 else
2238 m_xygribPanel->m_pressure_cbox->Disable();
2239
2240 if (selectedAtmModel->temperature)
2241 m_xygribPanel->m_temperature_cbox->Enable();
2242 else
2243 m_xygribPanel->m_temperature_cbox->Disable();
2244
2245 if (selectedAtmModel->cape)
2246 m_xygribPanel->m_cape_cbox->Enable();
2247 else
2248 m_xygribPanel->m_cape_cbox->Disable();
2249
2250 if (selectedAtmModel->reflectivity)
2251 m_xygribPanel->m_reflectivity_cbox->Enable();
2252 else
2253 m_xygribPanel->m_reflectivity_cbox->Disable();
2254
2255 if (selectedAtmModel->cloudCover)
2256 m_xygribPanel->m_cloudcover_cbox->Enable();
2257 else
2258 m_xygribPanel->m_cloudcover_cbox->Disable();
2259
2260 if (selectedAtmModel->precipitation)
2261 m_xygribPanel->m_precipitation_cbox->Enable();
2262 else
2263 m_xygribPanel->m_precipitation_cbox->Disable();
2264
2265 // Fill the resolution choice selection
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],
2269 i);
2270 }
2271
2272 // Fill the duration choice selection
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);
2276 }
2277
2278 // Fill the interval choice selection
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);
2283 }
2284
2285 // Fill the run choice selection
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);
2291 } else {
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);
2297 }
2298
2299 if (modelIndex == m_parent.xyGribConfig.atmModelIndex) {
2300 ApplyXyGribConfiguration();
2301 } else {
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);
2309 }
2310 MemorizeXyGribConfiguration();
2311}
2312
2316void GribRequestSetting::OnXyGribWaveModelChoice(wxCommandEvent &event) {
2317 WaveModelDef_t *selectedModel = nullptr;
2318
2319 // Find the model descriptor associated to the selected wave model
2320 wxString waveModel = m_xygribPanel->m_wavemodel_choice->GetStringSelection();
2321 int modelIndex = 0;
2322 while ((selectedModel = xygribWaveModelList[modelIndex]) != nullptr) {
2323 if (selectedModel->name.IsSameAs(waveModel, true)) {
2324 break;
2325 }
2326 modelIndex++;
2327 }
2328
2329 // Model found in the table ?
2330 if (selectedModel == nullptr) {
2331 // If the model is not found in the table, disable wave model downloading
2332 m_selectedWaveModelIndex = -1;
2333 m_xygribPanel->m_waveheight_cbox->Disable();
2334 m_xygribPanel->m_windwave_cbox->Disable();
2335 MemorizeXyGribConfiguration();
2336 return;
2337 }
2338
2339 m_selectedWaveModelIndex = modelIndex;
2340
2341 // Else configure parameters according to model definition
2342 if (selectedModel->significantHeight) {
2343 m_xygribPanel->m_waveheight_cbox->Enable();
2344 } else {
2345 m_xygribPanel->m_waveheight_cbox->Disable();
2346 }
2347
2348 if (selectedModel->windWaves) {
2349 m_xygribPanel->m_windwave_cbox->Enable();
2350 } else {
2351 m_xygribPanel->m_windwave_cbox->Disable();
2352 }
2353 MemorizeXyGribConfiguration();
2354}
2355
2359void GribRequestSetting::OnXyGribConfigChange(wxCommandEvent &event) {
2360 MemorizeXyGribConfiguration();
2361}
2362
2364void GribRequestSetting::InitializeXygribDialog() {
2365 AtmModelDef_t *selectedAtmModel = nullptr;
2366 WaveModelDef_t *selectedWaveModel = nullptr;
2367
2368 // Fill selection of atmospheric models with the ones found in the model table
2369 m_xygribPanel->m_atmmodel_choice->Clear();
2370 int modelIndex = 0;
2371 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) != nullptr) {
2372 m_xygribPanel->m_atmmodel_choice->Insert(selectedAtmModel->name,
2373 modelIndex);
2374 modelIndex++;
2375 }
2376 // Select the initial value from configuration
2377 m_selectedAtmModelIndex = m_parent.xyGribConfig.atmModelIndex;
2378 selectedAtmModel = xygribAtmModelList[m_selectedAtmModelIndex];
2379
2380 // Fill selection of wave models with the ones found in the table
2381 m_xygribPanel->m_wavemodel_choice->Clear();
2382 modelIndex = 0;
2383 while ((selectedWaveModel = xygribWaveModelList[modelIndex]) != nullptr) {
2384 m_xygribPanel->m_wavemodel_choice->Insert(selectedWaveModel->name,
2385 modelIndex);
2386 modelIndex++;
2387 }
2388 // Add the "None" selection
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;
2394 }
2395
2396 // Fill the resolution choice selection
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],
2400 i);
2401 }
2402
2403 // Fill the duration choice selection
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);
2407 }
2408
2409 // Fill the interval choice selection
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);
2414 }
2415
2416 // Fill the run choice selection
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);
2422 } else {
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);
2428 }
2429
2430 if (selectedAtmModel->wind)
2431 m_xygribPanel->m_wind_cbox->Enable();
2432 else
2433 m_xygribPanel->m_wind_cbox->Disable();
2434
2435 if (selectedAtmModel->gust)
2436 m_xygribPanel->m_gust_cbox->Enable();
2437 else
2438 m_xygribPanel->m_gust_cbox->Disable();
2439
2440 if (selectedAtmModel->pressure)
2441 m_xygribPanel->m_pressure_cbox->Enable();
2442 else
2443 m_xygribPanel->m_pressure_cbox->Disable();
2444
2445 if (selectedAtmModel->temperature)
2446 m_xygribPanel->m_temperature_cbox->Enable();
2447 else
2448 m_xygribPanel->m_temperature_cbox->Disable();
2449
2450 if (selectedAtmModel->cape)
2451 m_xygribPanel->m_cape_cbox->Enable();
2452 else
2453 m_xygribPanel->m_cape_cbox->Disable();
2454
2455 if (selectedAtmModel->reflectivity)
2456 m_xygribPanel->m_reflectivity_cbox->Enable();
2457 else
2458 m_xygribPanel->m_reflectivity_cbox->Disable();
2459
2460 if (selectedAtmModel->cloudCover)
2461 m_xygribPanel->m_cloudcover_cbox->Enable();
2462 else
2463 m_xygribPanel->m_cloudcover_cbox->Disable();
2464
2465 if (selectedAtmModel->precipitation)
2466 m_xygribPanel->m_precipitation_cbox->Enable();
2467 else
2468 m_xygribPanel->m_precipitation_cbox->Disable();
2469
2470 if ((selectedWaveModel != nullptr) && (selectedWaveModel->significantHeight))
2471 m_xygribPanel->m_waveheight_cbox->Enable();
2472 else
2473 m_xygribPanel->m_waveheight_cbox->Disable();
2474
2475 if ((selectedWaveModel != nullptr) && (selectedWaveModel->windWaves))
2476 m_xygribPanel->m_windwave_cbox->Enable();
2477 else
2478 m_xygribPanel->m_windwave_cbox->Disable();
2479
2480 ApplyXyGribConfiguration();
2481}
2482
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);
2490
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);
2511
2512 UpdateGribSizeEstimate();
2513}
2514
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();
2522
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();
2538
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();
2546
2547 UpdateGribSizeEstimate();
2548}
2549
2553void GribRequestSetting::UpdateGribSizeEstimate() {
2554 double resolution;
2555 long days;
2556 long interval;
2557
2558 if (!m_xygribPanel->m_resolution_choice->GetStringSelection().ToCDouble(
2559 &resolution)) {
2560 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2561 return;
2562 }
2563 if (!m_xygribPanel->m_duration_choice->GetStringSelection().ToCLong(&days)) {
2564 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2565 return;
2566 }
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");
2571 return;
2572 }
2573
2574 if (m_Vp == nullptr) {
2575 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2576 return;
2577 }
2578
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;
2583
2584 int npts = (int)(ceil(fabs(xmax - xmin) / resolution) *
2585 ceil(fabs(ymax - ymin) / resolution));
2586
2587 // Number of GribRecords
2588 int nbrec = (int)days * 24 / interval + 1;
2589
2590 int nbPress = (m_xygribPanel->m_pressure_cbox->IsChecked() &&
2591 m_xygribPanel->m_pressure_cbox->IsEnabled())
2592 ? nbrec
2593 : 0;
2594 int nbWind = (m_xygribPanel->m_wind_cbox->IsChecked() &&
2595 m_xygribPanel->m_wind_cbox->IsEnabled())
2596 ? 2 * nbrec
2597 : 0;
2598 int nbRain = (m_xygribPanel->m_precipitation_cbox->IsChecked() &&
2599 m_xygribPanel->m_precipitation_cbox->IsEnabled())
2600 ? nbrec - 1
2601 : 0;
2602 int nbCloud = (m_xygribPanel->m_cloudcover_cbox->IsChecked() &&
2603 m_xygribPanel->m_cloudcover_cbox->IsEnabled())
2604 ? nbrec - 1
2605 : 0;
2606 int nbTemp = (m_xygribPanel->m_temperature_cbox->IsChecked() &&
2607 m_xygribPanel->m_temperature_cbox->IsEnabled())
2608 ? nbrec
2609 : 0;
2610
2611 int nbCAPEsfc = (m_xygribPanel->m_cape_cbox->IsChecked() &&
2612 m_xygribPanel->m_cape_cbox->IsEnabled())
2613 ? nbrec
2614 : 0;
2615 int nbReflectivity = (m_xygribPanel->m_reflectivity_cbox->IsChecked() &&
2616 m_xygribPanel->m_reflectivity_cbox->IsEnabled())
2617 ? nbrec
2618 : 0;
2619 int nbGUSTsfc = (m_xygribPanel->m_gust_cbox->IsChecked() &&
2620 m_xygribPanel->m_gust_cbox->IsEnabled())
2621 ? nbrec
2622 : 0;
2623
2624 int head = 179;
2625 int estimate = 0;
2626 int nbits; // this can vary when c3 packing is used. Average numbers are used
2627 // here
2628
2629 nbits = 12;
2630 estimate += nbWind * (head + (nbits * npts) / 8 + 2);
2631
2632 nbits = 9;
2633 estimate += nbTemp * (head + (nbits * npts) / 8 + 2);
2634
2635 // estime += nbTempMin*(head+(nbits*npts)/8+2 );
2636 // estime += nbTempMax*(head+(nbits*npts)/8+2 );
2637
2638 nbits = 9;
2639 estimate += nbRain * (head + 24 + (nbits * npts) / 8 + 2);
2640
2641 nbits = 14;
2642 estimate += nbPress * (head + (nbits * npts) / 8 + 2);
2643
2644 nbits = 7;
2645 estimate += nbCloud * (head + 24 + (nbits * npts) / 8 + 2);
2646
2647 nbits = 11;
2648 estimate += nbReflectivity * (head + (nbits * npts) / 8 + 2);
2649
2650 nbits = 12;
2651 estimate += nbCAPEsfc * (head + (nbits * npts) / 8 + 2);
2652
2653 nbits = 9;
2654 estimate += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
2655 // estime += nbSUNSDsfc*(head+(nbits*npts)/8+2 );
2656
2657 // keep a record of the atmosphere estimate. if 0 nothing was selected
2658 int atmEstimate = estimate;
2659
2660 // and now the wave estimate
2661 // recalculate number of points based on which model is used
2662 if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2663 "WW3")) // 0.5 deg
2664 {
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(
2668 "GWAM")) // 0.25 deg
2669 {
2670 npts =
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(
2674 "EWAM")) // 0.1 x 0.05 deg
2675 {
2676 npts =
2677 (int)(ceil(fabs(xmax - xmin) / 0.05) * ceil(fabs(ymax - ymin) / 0.1));
2678 nbrec = (int)fmin(4, days) * 24 / interval + 1;
2679 } else {
2680 npts = 0;
2681 nbrec = 0;
2682 }
2683
2684 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
2685 nbits = 9;
2686 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2687 }
2688
2689 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
2690 nbits = 15;
2691 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2692 nbits = 8;
2693 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2694 nbits = 10;
2695 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2696 }
2697
2698 int wavEstimate = estimate - atmEstimate;
2699 // reduce wave estimate due to land overlapping by average of 40%
2700 wavEstimate = wavEstimate * 0.6;
2701 // now adjusted estimate is
2702 estimate = atmEstimate + wavEstimate;
2703
2704 // adjust for packing ~ 65%
2705 estimate = estimate * 0.65;
2706
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);
2711 }
2712
2713 m_xygribPanel->m_sizeestimate_text->SetLabel(
2714 wxString::Format("%d kB %s", estimate / 1024, warningStr));
2715
2716 m_gribSizeEstimate = estimate;
2717}
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.
The JSON parser.
Definition jsonreader.h:50
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
Definition jsonval.h:84
int Size() const
Return the size of the array or map stored in this value.
Definition jsonval.cpp:1332
bool HasMember(unsigned index) const
Return TRUE if the object contains an element at the specified index.
Definition jsonval.cpp:1298
wxString AsString() const
Return the stored value as a wxWidget's string.
Definition jsonval.cpp:872
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.