OpenCPN Partial API docs
Loading...
Searching...
No Matches
grib_request_dlg.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, see <https://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17
24// Disable the maybe-uninitialized warning as it triggers in std::regex and
25// makes the build with sanitizers impossible
26#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
27
28#include "wx/wx.h"
29#include <wx/utils.h>
30#include <sstream>
31#include "email.h"
32#include "xy_grib_model_def.h"
33
34#include "pi_gl.h"
35
36#include "grib_request_dlg.h"
38#include <wx/wfstream.h>
39#include "grib_pi.h"
40
41#include <unordered_map>
42#include <regex>
43#include <string>
44
45#define RESOLUTIONS 4
46
47enum { SAILDOCS, ZYGRIB }; // grib providers
48enum { GFS, COAMPS, RTOFS, HRRR, ICON, ECMWF }; // forecast models
49
50wxString toMailFormat(int NEflag,
51 int a) // convert position to mail necessary format
52{
53 char c = NEflag == 1 ? a < 0 ? 'S' : 'N' : a < 0 ? 'W' : 'E';
54 wxString s;
55 s.Printf("%01d%c", abs(a), c);
56 return s;
57}
58
59extern int m_SavedZoneSelMode;
60extern int m_ZoneSelMode;
61
62//----------------------------------------------------------------------------------------------------------
63// GRIB Request Implementation
64//----------------------------------------------------------------------------------------------------------
65GribRequestSetting::GribRequestSetting(GRIBUICtrlBar &parent)
66 : GribRequestSettingBase(&parent), m_parent(parent) {
67 m_VpFocus = nullptr;
68 m_VpMouse = nullptr;
69 m_oDC = nullptr;
70 m_boundingBoxCanvasIndex = -1;
71
72 m_displayScale = 1.0;
73#if defined(__WXOSX__) || defined(__WXGTK3__)
74 // Support scaled HDPI displays.
75 m_displayScale = wxWindow::GetContentScaleFactor();
76#endif
77
78 InitRequestConfig();
79 m_connected = false;
80 m_downloading = false;
81 m_bTransferSuccess = true;
82 m_downloadType = GribDownloadType::NONE;
83
84 auto bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)
85 .GetAsString(wxC2S_HTML_SYNTAX);
86 auto fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT)
87 .GetAsString(wxC2S_HTML_SYNTAX);
88 m_htmlWinWorld->SetBorders(10);
89 m_htmlWinWorld->SetPage(
90 "<html><body bgcolor="
91 "" +
92 bg +
93 ""
94 "><font color="
95 "" +
96 fg +
97 ""
98 ">" +
99 _("<h1>OpenCPN ECMWF forecast</h1>"
100 "<p>Free service based on ECMWF Open Data published under the terms of "
101 "Creative Commons CC-4.0-BY license</p>"
102 "<p>The IFS model GRIB files include information about surface "
103 "temperature, "
104 "atmospheric pressure, wind strength, wind direction, wave height and "
105 "direction for the whole world on a 0.25 degree resolution "
106 "grid with 3 hour "
107 "step in the first 144 hours and 6 hour step up to 10 days.</p>"
108 "The AIFS model contains data for wind, pressure and temperature on a "
109 "0.25 degree grid with 6 hour step for up to 15 days"
110 "<p>The data is updated twice a day as soon as the 00z and 12z model "
111 "runs finish and the "
112 "results are published by ECMWF, which usually means new forecast data "
113 "is available shortly after 8AM and 8PM UTC.</p>"
114 "<p>The grib downloaded covers the area of the primary chart "
115 "canvas.</p>"
116 "<p>The service is provided on best effort basis and comes with no "
117 "guarantees. The server is hosted by a volunteer and the service is "
118 "provided free of charge and without accepting any liability "
119 "whatsoever for its continuous availability, or for any loss or damage "
120 "arising from its use. If you find the service useful, please "
121 "consider making a donation to the OpenCPN project.</p>"
122 "<p>This service is based on data and products of the European Centre "
123 "for Medium-Range Weather Forecasts (ECMWF).</p>"
124 "<p>Source: www.ecmwf.int</p>"
125 "<p>Disclaimer: ECMWF does not accept any liability whatsoever for any "
126 "error or omission in the data, their availability, or for any loss or "
127 "damage arising from their use.</p>"
128 "</font></body></html>"));
129 m_htmlInfoWin->SetBorders(10);
130 m_htmlInfoWin->SetPage(
131 "<html><body bgcolor="
132 "" +
133 bg +
134 ""
135 "><font color="
136 "" +
137 fg +
138 ""
139 ">" +
140 _("<h1>Grib weather forecasts</h1>"
141 "<p>Collection of local weather models from various sources available "
142 "for download over the internet.</p>"
143 "</font></body></html>"));
144 ReadLocalCatalog();
145 m_bLocal_source_selected = false;
146 EnableDownloadButtons();
147
148 m_selectedAtmModelIndex = 0;
149 m_selectedWaveModelIndex = 0;
150 InitializeXygribDialog();
151}
152
153GribRequestSetting::~GribRequestSetting() {
154 if (m_downloading) {
155 OCPN_cancelDownloadFileBackground(m_download_handle);
156 }
157 if (m_connected) {
158 Disconnect(
159 wxEVT_DOWNLOAD_EVENT,
160 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
161 }
162 delete m_VpFocus;
163 delete m_VpMouse;
164 delete m_oDC;
165}
166
167void GribRequestSetting::SaveConfig() {
168 wxFileConfig *pConf = GetOCPNConfigObject();
169 if (pConf) {
170 pConf->SetPath("/PlugIns/GRIB");
171
172 pConf->Write("MailRequestConfig", m_RequestConfigBase);
173 pConf->Write("MailSenderAddress", m_pSenderAddress->GetValue());
174 pConf->Write("MailRequestAddresses", m_MailToAddresses);
175 pConf->Write("ZyGribLogin", m_pLogin->GetValue());
176 pConf->Write("ZyGribCode", m_pCode->GetValue());
177 pConf->Write("SendMailMethod", m_SendMethod);
178 pConf->Write("MovingGribSpeed", m_sMovingSpeed->GetValue());
179 pConf->Write("MovingGribCourse", m_sMovingCourse->GetValue());
180
181 m_SavedZoneSelMode = m_cUseSavedZone->GetValue() ? SAVED_SELECTION
182 : m_rbManualSelect->GetValue() ? START_SELECTION
184 pConf->Write("ManualRequestZoneSizingMode", m_ZoneSelMode);
185 pConf->Write("ManualRequestZoneSizing", m_SavedZoneSelMode);
186
187 pConf->Write("RequestZoneMaxLat", m_spMaxLat->GetValue());
188 pConf->Write("RequestZoneMinLat", m_spMinLat->GetValue());
189 pConf->Write("RequestZoneMaxLon", m_spMaxLon->GetValue());
190 pConf->Write("RequestZoneMinLon", m_spMinLon->GetValue());
191 }
192}
193
194void GribRequestSetting::InitRequestConfig() {
195 wxFileConfig *pConf = GetOCPNConfigObject();
196
197 if (pConf) {
198 pConf->SetPath("/PlugIns/GRIB");
199 wxString l;
200 int m;
201 pConf->Read("MailRequestConfig", &m_RequestConfigBase, "000220XX........0");
202 pConf->Read("MailSenderAddress", &l, "");
203 m_pSenderAddress->ChangeValue(l);
204 pConf->Read("MailRequestAddresses", &m_MailToAddresses,
205 "query@saildocs.com;gribauto@zygrib.org");
206 pConf->Read("ZyGribLogin", &l, "");
207 m_pLogin->ChangeValue(l);
208 pConf->Read("ZyGribCode", &l, "");
209 m_pCode->ChangeValue(l);
210 pConf->Read("SendMailMethod", &m_SendMethod, 0);
211 pConf->Read("MovingGribSpeed", &m, 0);
212 m_sMovingSpeed->SetValue(m);
213 pConf->Read("MovingGribCourse", &m, 0);
214 m_sMovingCourse->SetValue(m);
215 pConf->Read("ManualRequestZoneSizingMode", &m, 0);
216 m_ZoneSelMode = m;
217 pConf->Read("ManualRequestZoneSizing", &m, 0);
219 m_cUseSavedZone->SetValue(m_SavedZoneSelMode == SAVED_SELECTION);
222 }
224 UpdateAreaSelectionState();
225 pConf->Read("RequestZoneMaxLat", &m, 0);
226 m_spMaxLat->SetValue(m);
227 pConf->Read("RequestZoneMinLat", &m, 0);
228 m_spMinLat->SetValue(m);
229 pConf->Read("RequestZoneMaxLon", &m, 0);
230 m_spMaxLon->SetValue(m);
231 pConf->Read("RequestZoneMinLon", &m, 0);
232 m_spMinLon->SetValue(m);
233
234 SetCoordinatesText();
235 // if GriDataConfig has been corrupted , take the standard one to fix a
236 // crash
237 if (m_RequestConfigBase.Len() != wxString("000220XX..............").Len())
238 m_RequestConfigBase = "000220XX..............";
239 }
240 // populate model, mail to, waves model choices
241 wxString s1[] = {"GFS", "COAMPS", "RTOFS", "HRRR", "ICON", "ECMWF"};
242 for (unsigned int i = 0; i < (sizeof(s1) / sizeof(wxString)); i++)
243 m_pModel->Append(s1[i]);
244 wxString s2[] = {"Saildocs", "zyGrib"};
245 for (unsigned int i = 0; i < (sizeof(s2) / sizeof(wxString)); i++)
246 m_pMailTo->Append(s2[i]);
247 wxString s3[] = {"WW3-GLOBAL", "WW3-MEDIT"};
248 for (unsigned int i = 0; i < (sizeof(s3) / sizeof(wxString)); i++)
249 m_pWModel->Append(s3[i]);
250 m_rButtonYes->SetLabel(_("Send"));
251 m_rButtonApply->SetLabel(_("OK"));
252 m_tResUnit->SetLabel(wxString::Format("\u00B0"));
253 m_sCourseUnit->SetLabel(wxString::Format("\u00B0"));
254
255 // Set wxSpinCtrl sizing
256 int w, h;
257 GetTextExtent("-360", &w, &h, nullptr, nullptr,
258 OCPNGetFont(_("Dialog"))); // optimal text control size
259 w += 30;
260 h += 4;
261 m_sMovingSpeed->SetMinSize(wxSize(w, h));
262 m_sMovingCourse->SetMinSize(wxSize(w, h));
263 m_spMaxLat->SetMinSize(wxSize(w, h));
264 m_spMinLat->SetMinSize(wxSize(w, h));
265 m_spMaxLon->SetMinSize(wxSize(w, h));
266 m_spMinLon->SetMinSize(wxSize(w, h));
267
268 // add tooltips
269 m_pSenderAddress->SetToolTip(
270 _("Address used to send request eMail. (Mandatory for LINUX)"));
271 m_pLogin->SetToolTip(_("This is your zyGrib's forum access Login"));
272 m_pCode->SetToolTip(
273 _("Get this Code in zyGrib's forum ( This is not your password! )"));
274 m_sMovingSpeed->SetToolTip(_("Enter your forescasted Speed (in Knots)"));
275 m_sMovingCourse->SetToolTip(_("Enter your forecasted Course"));
276
277 long i, j, k;
278 ((wxString)m_RequestConfigBase.GetChar(0)).ToLong(&i); // MailTo
279 m_pMailTo->SetSelection(i);
280 ((wxString)m_RequestConfigBase.GetChar(1)).ToLong(&i); // Model
281 m_pModel->SetSelection(i);
282 m_cMovingGribEnabled->SetValue(m_RequestConfigBase.GetChar(16) ==
283 'X'); // Moving Grib
284 ((wxString)m_RequestConfigBase.GetChar(2)).ToLong(&i); // Resolution
285 ((wxString)m_RequestConfigBase.GetChar(3)).ToLong(&j); // interval
286 ((wxString)m_RequestConfigBase.GetChar(4)).ToLong(&k, 16); // Time Range
287 k--; // range max = 2 to 16 stored in hexa from 1 to f
288
289#ifdef __WXMSW__ // show / hide sender elemants as necessary
290 m_pSenderSizer->ShowItems(false);
291#else
292 if (m_SendMethod == 0)
293 m_pSenderSizer->ShowItems(false);
294 else
295 m_pSenderSizer->ShowItems(
296 true); // possibility to use "sendmail" method with Linux
297#endif
298
299 m_tMouseEventTimer.Connect(
300 wxEVT_TIMER, wxTimerEventHandler(GribRequestSetting::OnMouseEventTimer),
301 nullptr, this);
302
303 m_RenderSelectionZoneState = RENDER_NONE;
304
305 ApplyRequestConfig(i, j, k);
306
307 ((wxString)m_RequestConfigBase.GetChar(5)).ToLong(&j); // Waves model
308 m_pWModel->SetSelection(j);
309
310 m_pWind->Enable(false); // always selected if available
311 m_pPress->Enable(false);
312
313 DimeWindow(this); // aplly global colours scheme
314
315 m_AllowSend = true;
316 m_MailImage->SetValue(WriteMail());
317}
318
319wxWindow *GetGRIBCanvas();
320void GribRequestSetting::OnClose(wxCloseEvent &event) {
321 if (m_downloading) {
322 OCPN_cancelDownloadFileBackground(m_download_handle);
323 m_downloading = false;
324 m_download_handle = 0;
325 }
326 if (m_connected) {
327 Disconnect(
328 wxEVT_DOWNLOAD_EVENT,
329 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
330 }
332 RENDER_NONE; // eventually stop graphical zone display
333 RequestRefresh(GetGRIBCanvas());
334
335 // allow to be back to old value if changes have not been saved
337 m_parent.SetRequestButtonBitmap(m_ZoneSelMode); // set appropriate bitmap
338 m_parent.m_highlight_latmax = 0;
339 m_parent.m_highlight_lonmax = 0;
340 m_parent.m_highlight_latmin = 0;
341 m_parent.m_highlight_lonmin = 0;
342 this->Hide();
343}
344
345void GribRequestSetting::SetRequestDialogSize() {
346 int y;
347 /*first let's size the mail display space*/
348 GetTextExtent("abc", nullptr, &y, nullptr, nullptr, OCPNGetFont(_("Dialog")));
349 m_MailImage->SetMinSize(
350 wxSize(-1, ((y * m_MailImage->GetNumberOfLines()) + 10)));
351
352 /*then as default sizing do not work with wxScolledWindow let's compute it*/
353 wxSize scroll =
354 m_fgScrollSizer->Fit(m_sScrolledDialog); // the area size to be scrolled
355
356#ifdef __WXGTK__
357 SetMinSize(wxSize(0, 0));
358#endif
359
360 wxWindow *frame = wxTheApp->GetTopWindow();
361
362 int w = frame->GetClientSize().x; // the display size
363 int h = frame->GetClientSize().y;
364 int dMargin = 80; // set a margin
365
366 // height available for the scrolled window.
367 h -= (m_rButtonCancel->GetSize().GetY() + dMargin);
368 w -= dMargin; // width available for the scrolled window
369 m_sScrolledDialog->SetMinSize(
370 wxSize(wxMin(w, scroll.x),
371 wxMin(h, scroll.y))); // set scrolled area size with margin
372
373 Layout();
374 Fit();
375#ifdef __WXGTK__
376 wxSize sd = GetSize();
377 if (sd.y == GetClientSize().y) sd.y += 30;
378 SetSize(wxSize(sd.x, sd.y));
379 SetMinSize(wxSize(sd.x, sd.y));
380#endif
381 Refresh();
382}
383
384void GribRequestSetting::SetVpSize(PlugIn_ViewPort *vp) {
385 double lonmax = vp->lon_max;
386 double lonmin = vp->lon_min;
387 if ((fabs(vp->lat_max) < 90.) && (fabs(lonmax) < 360.)) {
388 if (lonmax < -180.) lonmax += 360.;
389 if (lonmax > 180.) lonmax -= 360.;
390 }
391 if ((fabs(vp->lat_min) < 90.) && (fabs(lonmin) < 360.)) {
392 if (lonmin < -180.) lonmin += 360.;
393 if (lonmin > 180.) lonmin -= 360.;
394 }
395
396 bool bnew_val = false;
397 if (m_spMaxLat->GetValue() != (int)ceil(vp->lat_max)) bnew_val = true;
398 if (m_spMinLon->GetValue() != (int)floor(lonmin)) bnew_val = true;
399 if (m_spMinLat->GetValue() != (int)floor(vp->lat_min)) bnew_val = true;
400 if (m_spMaxLon->GetValue() != (int)ceil(lonmax)) bnew_val = true;
401
402 if (bnew_val) {
403 m_spMaxLat->SetValue((int)ceil(vp->lat_max));
404 m_spMinLon->SetValue((int)floor(lonmin));
405 m_spMinLat->SetValue((int)floor(vp->lat_min));
406 m_spMaxLon->SetValue((int)ceil(lonmax));
407
408 SetCoordinatesText();
409 m_MailImage->SetValue(WriteMail());
410 }
411}
412
413bool GribRequestSetting::MouseEventHook(wxMouseEvent &event) {
414 if (!(event.ShiftDown() || m_bpManualSelection->GetValue())) {
415 // Only handle selection when Shift is pressed, or when the "manual
416 // selection button" is pressed.
417 return false; // Let the chart handle normal panning
418 }
419 if (event.LeftDown() && !event.Dragging()) {
420 // Automatically switch to manual selection,
421 // without requiring user to set the manual mode checkbox.
423 m_rbManualSelect->SetValue(true); // Update the UI checkbox
424 }
425 // User can still switch back to auto mode by unchecking the manual mode.
428 return false;
429
430 if (event.Moving())
431 return false; // maintain status bar and tracking dialog updated
432
433 // Mouse event position is in logical pixels.
434 int xm = event.GetX() * m_displayScale;
435 int ym = event.GetY() * m_displayScale;
436
437 if (event.LeftDown() && !event.Dragging()) {
438 m_parent.pParent->SetFocus();
439 m_ZoneSelMode = DRAW_SELECTION; // Starting a new bounding box selection.
441 wxPoint(xm, ym); // Set the starting point of the bounding box.
444 // if (this->IsShown())
445 // this->Hide(); // eventually hide dialog in case of mode change
446 m_RenderSelectionZoneState = RENDER_NONE; // hide previous drawing
447 m_boundingBoxCanvasIndex = GetCanvasIndexUnderMouse();
448 } else if (event.LeftUp() && m_RenderSelectionZoneState == RENDER_DRAWING) {
449 m_ZoneSelMode = COMPLETE_SELECTION; // ask to complete selection
451 SetCoordinatesText();
452 UpdateAreaSelectionState();
453 m_MailImage->SetValue(WriteMail());
454 m_RenderSelectionZoneState = RENDER_COMPLETE;
455 // The zone selection is complete, so we can update the grib size estimate.
456 UpdateGribSizeEstimate();
457 m_boundingBoxCanvasIndex = -1;
458 } else if (event.Dragging()) {
459 if (m_boundingBoxCanvasIndex != GetCanvasIndexUnderMouse()) {
460 // The user cannot draw a selection across view ports.
461 return false;
462 }
463 if (m_RenderSelectionZoneState < RENDER_DRAWING) {
464 m_RenderSelectionZoneState = RENDER_DRAWING;
465 }
466 m_IsMaxLong = m_StartPoint.x > xm
467 ? true
468 : false; // find if startpoint is max longitude
469 GetCanvasLLPix(m_VpMouse, wxPoint(xm, ym), &m_Lat,
470 &m_Lon); // extend selection
471 m_Lat = wxMin(90.0, wxMax(-90.0, m_Lat));
472 m_Lon = wxMin(180.0, wxMax(-180.0, m_Lon));
473 if (!m_tMouseEventTimer.IsRunning())
474 m_tMouseEventTimer.Start(20, wxTIMER_ONE_SHOT);
475 }
476 return true;
477}
478
479void GribRequestSetting::OnMouseEventTimer(wxTimerEvent &event) {
480 // compute zone starting point lon/lat for zone drawing
481
482 // compute rounded coordinates
483 if (m_StartLat > m_Lat) {
484 m_spMaxLat->SetValue((int)ceil(m_StartLat));
485 m_spMinLat->SetValue((int)floor(m_Lat));
486 } else {
487 m_spMaxLat->SetValue((int)ceil(m_Lat));
488 m_spMinLat->SetValue((int)floor(m_StartLat));
489 }
490 if (m_IsMaxLong) {
491 m_spMaxLon->SetValue((int)ceil(m_StartLon));
492 m_spMinLon->SetValue((int)floor(m_Lon));
493 } else {
494 m_spMaxLon->SetValue((int)ceil(m_Lon));
495 m_spMinLon->SetValue((int)floor(m_StartLon));
496 }
497
498 RequestRefresh(GetGRIBCanvas());
499}
500
501void GribRequestSetting::SetCoordinatesText() {
502 m_stMaxLatNS->SetLabel(m_spMaxLat->GetValue() < 0 ? _("S") : _("N"));
503 m_stMinLonEW->SetLabel(m_spMinLon->GetValue() < 0 ? _("W") : _("E"));
504 m_stMaxLonEW->SetLabel(m_spMaxLon->GetValue() < 0 ? _("W") : _("E"));
505 m_stMinLatNS->SetLabel(m_spMinLat->GetValue() < 0 ? _("S") : _("N"));
506}
507
508size_t LengthSelToHours(int sel) {
509 switch (sel) {
510 case 1:
511 return 72;
512 case 2:
513 return 999;
514 default:
515 return 24;
516 }
517}
518
519template <typename T>
520std::string GribRequestSetting::FormatPerLocale(T value) {
521 std::stringstream ss;
522 // use the the user-preferred locale rather than the default "C" locale
523 ss.imbue(std::locale(""));
524 ss << value; // Output for a US locale would be: 12,345,678 for integers
525 return ss.str();
526}
527
528wxString GribRequestSetting::GetDownloadProgressText(long transferredBytes,
529 long totalBytes) {
530 if (totalBytes > 0) {
531 return wxString::Format(_("Downloading... %s kB / %s kB (%li%%)"),
532 FormatPerLocale(transferredBytes / 1024).c_str(),
533 FormatPerLocale(totalBytes / 1024).c_str(),
534 (int)((double)transferredBytes / totalBytes * 100));
535 } else {
536 return wxString::Format(_("Downloading... %s kB / ???"),
537 FormatPerLocale(transferredBytes / 1024).c_str());
538 }
539}
540
541void GribRequestSetting::onDLEvent(OCPN_downloadEvent &ev) {
542 // std::cout << "onDLEvent " << ev.getDLEventCondition() << " "
543 // << ev.getDLEventStatus() << std::endl;
544 switch (ev.getDLEventCondition()) {
546 m_bTransferSuccess =
547 (ev.getDLEventStatus() == OCPN_DL_NO_ERROR) ? true : false;
548 Disconnect(wxEVT_DOWNLOAD_EVENT,
549 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::
550 onDLEvent);
551 m_connected = false;
552 m_downloading = false;
553 m_download_handle = 0;
554 wxYieldIfNeeded();
555 break;
556
558 switch (m_downloadType) {
560 m_staticTextInfo->SetLabelText(
561 GetDownloadProgressText(ev.getTransferred(), ev.getTotal()));
562 break;
565 m_stLocalDownloadInfo->SetLabelText(
566 GetDownloadProgressText(ev.getTransferred(), ev.getTotal()));
567 break;
569 // Update XyGrib progress gauge
570 if (ev.getTotal()) {
571 m_xygribPanel->m_progress_gauge->SetValue(
572 100 * ev.getTransferred() / ev.getTotal());
573 }
574 // Update status text to display information on file size
575 m_xygribPanel->m_status_text->SetLabel(
576 GetDownloadProgressText(ev.getTransferred(), ev.getTotal()));
577 break;
578 default:
579 break;
580 }
581 wxYieldIfNeeded();
582 break;
583 default:
584 break;
585 }
586}
587
588void GribRequestSetting::OnWorldDownload(wxCommandEvent &event) {
589 if (m_downloading) {
590 OCPN_cancelDownloadFileBackground(m_download_handle);
591 m_downloading = false;
592 m_download_handle = 0;
593 Disconnect(
594 wxEVT_DOWNLOAD_EVENT,
595 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
596 m_connected = false;
597 m_btnDownloadWorld->SetLabelText(_("Download"));
598 m_staticTextInfo->SetLabelText(_("Download canceled"));
599 m_canceled = true;
600 m_downloadType = GribDownloadType::NONE;
601 EnableDownloadButtons();
602 wxTheApp->ProcessPendingEvents();
603 wxYieldIfNeeded();
604 return;
605 }
606 m_canceled = false;
607 m_downloading = true;
608 m_downloadType = GribDownloadType::WORLD;
609 EnableDownloadButtons();
610 m_btnDownloadWorld->SetLabelText(_("Cancel"));
611 m_staticTextInfo->SetLabelText(_("Preparing data on server..."));
612 wxYieldIfNeeded();
613 wxString model;
614 switch (m_chECMWFResolution->GetSelection()) {
615 case 0:
616 model = "ecmwf0p25";
617 break;
618 case 1:
619 model = "ecmwfaifs0p25";
620 break;
621 default:
622 model = "ecmwf0p25";
623 break;
624 }
625 std::ostringstream oss;
626 oss << "https://grib.bosun.io/grib?";
627 oss << "model=" << model;
628 oss << "&latmin=" << GetMinLat();
629 oss << "&latmax=" << GetMaxLat();
630 oss << "&lonmin=" << GetMinLon();
631 oss << "&lonmax=" << GetMaxLon();
632 oss << "&length=" << LengthSelToHours(m_chForecastLength->GetSelection());
633 wxString filename =
634 wxString::Format("ocpn_%s_%li_%s.grb2", model.c_str(),
635 LengthSelToHours(m_chForecastLength->GetSelection()),
636 wxDateTime::Now().Format("%F-%H-%M"));
637 wxString path = m_parent.GetGribDir();
638 path.Append(wxFileName::GetPathSeparator());
639 path.Append(filename);
640 if (!m_connected) {
641 m_connected = true;
642 Connect(
643 wxEVT_DOWNLOAD_EVENT,
644 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
645 }
646 OCPN_downloadFileBackground(oss.str(), path, this, &m_download_handle);
647 while (m_downloading) {
648 wxTheApp->ProcessPendingEvents();
649 wxMilliSleep(10);
650 }
651 if (!m_canceled) {
652 if (m_bTransferSuccess) {
653 m_staticTextInfo->SetLabelText(
654 wxString::Format(_("Download complete: %s"), path.c_str()));
655 wxFileName fn(path);
656 m_parent.m_grib_dir = fn.GetPath();
657 m_parent.m_file_names.Clear();
658 m_parent.m_file_names.Add(path);
659 m_parent.OpenFile();
660 if (m_parent.pPlugIn) {
661 if (m_parent.pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
662 }
663 m_parent.SetDialogsStyleSizePosition(true);
664 SaveConfig();
665 Close();
666 } else {
667 m_staticTextInfo->SetLabelText(_("Download failed"));
668 }
669 }
670 m_btnDownloadWorld->SetLabelText(_("Download"));
671 m_downloadType = GribDownloadType::NONE;
672 EnableDownloadButtons();
673}
674
675enum LocalSourceItem { SOURCE, AREA, GRIB };
676
677enum LocalGribDownloadType { DIRECT, MANIFEST, WEBPAGE };
678
679struct GribCatalogInfo : public wxTreeItemData {
680 GribCatalogInfo(LocalSourceItem type, wxString name, wxString description,
681 wxString url, wxString filename,
682 LocalGribDownloadType download_type, double latmin,
683 double lonmin, double latmax, double lonmax)
684 : type(type),
685 name(name),
686 description(description),
687 url(url),
688 filename(filename),
689 download_type(download_type),
690 latmin(latmin),
691 lonmin(lonmin),
692 latmax(latmax),
693 lonmax(lonmax) {}
694 LocalSourceItem type;
695 wxString name;
696 wxString description;
697 wxString url;
698 wxString filename;
699 LocalGribDownloadType download_type;
700 double latmin;
701 double lonmin;
702 double latmax;
703 double lonmax;
704};
705
706void GribRequestSetting::FillTreeCtrl(wxJSONValue &data) {
707 m_SourcesTreeCtrl1->DeleteAllItems();
708 wxTreeItemId root =
709 m_SourcesTreeCtrl1->AddRoot(_("Local high resolution forecasts"));
710 if (data.HasMember("sources") && data["sources"].IsArray()) {
711 for (int i = 0; i < data["sources"].Size(); i++) {
712 wxJSONValue source = data["sources"][i];
713 auto info = new GribCatalogInfo(
714 LocalSourceItem::SOURCE, source["source"].AsString(),
715 source["description"].AsString(), source["url"].AsString(),
716 wxEmptyString, LocalGribDownloadType::WEBPAGE, 0, 0, 0, 0);
717 wxTreeItemId src_id = m_SourcesTreeCtrl1->AppendItem(
718 root, source["source"].AsString(), -1, -1, info);
719 if (source.HasMember("areas") && source["areas"].IsArray()) {
720 for (int j = 0; j < source["areas"].Size(); j++) {
721 wxJSONValue area = source["areas"][j];
722 auto info_1 = new GribCatalogInfo(
723 LocalSourceItem::AREA, area["name"].AsString(),
724 source["description"].AsString(), source["url"].AsString(),
725 wxEmptyString, LocalGribDownloadType::WEBPAGE,
726 area["boundary"]["lat_min"].AsDouble(),
727 area["boundary"]["lon_min"].AsDouble(),
728 area["boundary"]["lat_max"].AsDouble(),
729 area["boundary"]["lon_max"].AsDouble());
730 m_SourcesTreeCtrl1->AppendItem(src_id, area["name"].AsString(), -1,
731 -1, info_1);
732 if (area.HasMember("gribs") && area["gribs"].IsArray()) {
733 for (int k = 0; k < area["gribs"].Size(); k++) {
734 wxJSONValue grib = area["gribs"][k];
735 auto inf_1 = new GribCatalogInfo(
736 LocalSourceItem::GRIB, grib["name"].AsString(),
737 source["description"].AsString(),
738 grib.HasMember("url") ? grib["url"].AsString()
739 : grib["cat_url"].AsString(),
740 grib.HasMember("filename") ? grib["filename"].AsString() : "",
741 grib.HasMember("url") ? LocalGribDownloadType::DIRECT
742 : LocalGribDownloadType::MANIFEST,
743 area["boundary"]["lat_min"].AsDouble(),
744 area["boundary"]["lon_min"].AsDouble(),
745 area["boundary"]["lat_max"].AsDouble(),
746 area["boundary"]["lon_max"].AsDouble());
747 m_SourcesTreeCtrl1->AppendItem(
748 m_SourcesTreeCtrl1->GetLastChild(src_id),
749 grib["name"].AsString(), -1, -1, inf_1);
750 }
751 }
752 }
753 }
754 m_SourcesTreeCtrl1->CollapseAllChildren(src_id);
755 }
756 }
757 m_SourcesTreeCtrl1->Expand(root);
758}
759
760void GribRequestSetting::ReadLocalCatalog() {
761 wxJSONReader reader;
762 wxFileInputStream str(m_parent.pPlugIn->m_local_sources_catalog);
763 wxJSONValue root;
764 reader.Parse(str, &root);
765 FillTreeCtrl(root);
766}
767
768void GribRequestSetting::HighlightArea(double latmax, double lonmax,
769 double latmin, double lonmin) {
770 m_parent.m_highlight_latmax = latmax;
771 m_parent.m_highlight_lonmax = lonmax;
772 m_parent.m_highlight_latmin = latmin;
773 m_parent.m_highlight_lonmin = lonmin;
774}
775
776void GribRequestSetting::OnLocalTreeSelChanged(wxTreeEvent &event) {
777 wxTreeItemId item = m_SourcesTreeCtrl1->GetSelection();
778 auto src = (GribCatalogInfo *)(m_SourcesTreeCtrl1->GetItemData(item));
779 if (src) {
780 if (src->type == LocalSourceItem::GRIB) {
781 m_stLocalDownloadInfo->SetLabelText(_("Download grib..."));
782 m_bLocal_source_selected = true;
783 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
784 } else {
785 m_stLocalDownloadInfo->SetLabelText(_("Select grib..."));
786 m_bLocal_source_selected = false;
787 HighlightArea(src->latmax, src->lonmax, src->latmin, src->lonmin);
788 }
789 }
790 EnableDownloadButtons();
791}
792
793void GribRequestSetting::OnUpdateLocalCatalog(wxCommandEvent &event) {
794 if (m_downloading) {
795 OCPN_cancelDownloadFileBackground(m_download_handle);
796 m_downloading = false;
797 m_download_handle = 0;
798 Disconnect(
799 wxEVT_DOWNLOAD_EVENT,
800 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
801 m_connected = false;
802 m_btnDownloadLocal->SetLabelText(_("Download"));
803 m_stLocalDownloadInfo->SetLabelText(_("Download canceled"));
804 m_canceled = true;
805 m_downloadType = GribDownloadType::NONE;
806 EnableDownloadButtons();
807 wxTheApp->ProcessPendingEvents();
808 wxYieldIfNeeded();
809 return;
810 }
811 m_canceled = false;
812 m_downloading = true;
813 m_downloadType = GribDownloadType::LOCAL_CATALOG;
814 EnableDownloadButtons();
815 m_btnDownloadLocal->SetLabelText(_("Cancel"));
816 m_staticTextInfo->SetLabelText(_("Downloading catalog update..."));
817 wxYieldIfNeeded();
818 if (!m_connected) {
819 m_connected = true;
820 Connect(
821 wxEVT_DOWNLOAD_EVENT,
822 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
823 }
824 OCPN_downloadFileBackground(CATALOG_URL,
825 m_parent.pPlugIn->m_local_sources_catalog + "new",
826 this, &m_download_handle);
827 while (m_downloading) {
828 wxTheApp->ProcessPendingEvents();
829 wxMilliSleep(10);
830 }
831 if (!m_canceled) {
832 if (m_bTransferSuccess) {
833 wxRenameFile(m_parent.pPlugIn->m_local_sources_catalog + "new",
834 m_parent.pPlugIn->m_local_sources_catalog, true);
835 ReadLocalCatalog();
836 m_stLocalDownloadInfo->SetLabelText(_("Catalog update complete."));
837 } else {
838 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
839 }
840 }
841 m_btnDownloadLocal->SetLabelText(_("Download"));
842 m_downloadType = GribDownloadType::NONE;
843 EnableDownloadButtons();
844}
845
846void GribRequestSetting::OnDownloadLocal(wxCommandEvent &event) {
847 if (m_downloading) {
848 OCPN_cancelDownloadFileBackground(m_download_handle);
849 m_downloading = false;
850 m_download_handle = 0;
851 Disconnect(
852 wxEVT_DOWNLOAD_EVENT,
853 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
854 m_connected = false;
855 m_btnDownloadLocal->SetLabelText(_("Download"));
856 m_stLocalDownloadInfo->SetLabelText(_("Download canceled"));
857 m_canceled = true;
858 m_downloadType = GribDownloadType::NONE;
859 EnableDownloadButtons();
860 wxTheApp->ProcessPendingEvents();
861 wxYieldIfNeeded();
862 return;
863 }
864 m_canceled = false;
865 m_downloading = true;
866 m_downloadType = GribDownloadType::LOCAL;
867 EnableDownloadButtons();
868 m_btnDownloadLocal->SetLabelText(_("Cancel"));
869 m_staticTextInfo->SetLabelText(_("Downloading grib..."));
870 wxYieldIfNeeded();
871 auto src = (GribCatalogInfo *)(m_SourcesTreeCtrl1->GetItemData(
872 m_SourcesTreeCtrl1->GetSelection()));
873 if (!src || src->type != LocalSourceItem::GRIB || src->url.IsEmpty()) {
874 m_downloading = false;
875 m_stLocalDownloadInfo->SetLabelText(_("Download can't be started."));
876 m_btnDownloadWorld->SetLabelText(_("Download"));
877 m_downloadType = GribDownloadType::NONE;
878 EnableDownloadButtons();
879 return;
880 }
881 if (!m_connected) {
882 m_connected = true;
883 Connect(
884 wxEVT_DOWNLOAD_EVENT,
885 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
886 }
887 wxString url = src->url;
888 // If it is a grib that changes location and requires help of, download the
889 // manifest first
890 if (src->download_type == LocalGribDownloadType::MANIFEST) {
891 wxString path = m_parent.GetGribDir();
892 path.Append(wxFileName::GetPathSeparator());
893 path.Append("grib_manifest.json");
894 OCPN_downloadFileBackground(url, path, this, &m_download_handle);
895 while (m_downloading) {
896 wxTheApp->ProcessPendingEvents();
897 wxMilliSleep(10);
898 }
899 bool success = true;
900 if (!m_canceled) {
901 if (!m_bTransferSuccess) {
902 success = false;
903 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
904 }
905 } else {
906 success = false;
907 m_stLocalDownloadInfo->SetLabelText(_("Download canceled"));
908 }
909 if (success) {
910 wxJSONReader reader;
911 wxFileInputStream str(path);
912 wxJSONValue root;
913 reader.Parse(str, &root);
914 if (root.HasMember("url")) {
915 wxString parsed = root["url"].AsString();
916 if (parsed.StartsWith("http")) {
917 url = parsed;
918 } else {
919 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
920 success = false;
921 }
922 }
923 }
924 if (!success) { // Something went wrong, clean up and do not continue to
925 // the actual download
926 m_downloading = false;
927 m_download_handle = 0;
928 Disconnect(wxEVT_DOWNLOAD_EVENT,
929 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::
930 onDLEvent);
931 m_connected = false;
932 m_btnDownloadLocal->SetLabelText(_("Download"));
933 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
934 m_canceled = true;
935 m_downloadType = GribDownloadType::NONE;
936 EnableDownloadButtons();
937 wxTheApp->ProcessPendingEvents();
938 wxYieldIfNeeded();
939 return;
940 }
941 }
942 // Download the actual grib
943 m_downloading = true;
944 wxYieldIfNeeded();
945 if (!m_connected) {
946 m_connected = true;
947 Connect(
948 wxEVT_DOWNLOAD_EVENT,
949 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
950 }
951 wxString filename;
952 if (!src->filename.IsEmpty()) {
953 filename = src->filename;
954 } else {
955 filename =
956 url.AfterLast('/'); // Get last part of the URL and try to sanitize the
957 // filename somewhat if we call some API...
958 filename.Replace("?", "_");
959 filename.Replace("&", "_");
960 if (!(filename.Contains(".grb2") || filename.Contains(".grib2") ||
961 filename.Contains(".grb") || filename.Contains(".grib"))) {
962 filename.Append(".grb");
963 }
964 }
965
966 wxString path = m_parent.GetGribDir();
967 path.Append(wxFileName::GetPathSeparator());
968 path.Append(filename);
969 OCPN_downloadFileBackground(url, path, this, &m_download_handle);
970 while (m_downloading) {
971 wxTheApp->ProcessPendingEvents();
972 wxMilliSleep(10);
973 }
974 if (!m_canceled) {
975 if (m_bTransferSuccess) {
976 m_stLocalDownloadInfo->SetLabelText(_("Grib download complete."));
977 m_stLocalDownloadInfo->SetLabelText(
978 wxString::Format(_("Download complete: %s"), path.c_str()));
979 wxFileName fn(path);
980 m_parent.m_grib_dir = fn.GetPath();
981 m_parent.m_file_names.Clear();
982 m_parent.m_file_names.Add(
983 path); //("/home/nohal/Downloads/Cherbourg_4km_WRF_WAM_240228-12.grb.bz2");
984 m_parent.OpenFile();
985 if (m_parent.pPlugIn) {
986 if (m_parent.pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
987 }
988 m_parent.SetDialogsStyleSizePosition(true);
989 SaveConfig();
990 Close();
991 } else {
992 m_stLocalDownloadInfo->SetLabelText(_("Download failed"));
993 }
994 }
995 m_btnDownloadWorld->SetLabelText(_("Download"));
996 m_downloadType = GribDownloadType::NONE;
997 EnableDownloadButtons();
998}
999
1000void GribRequestSetting::EnableDownloadButtons() {
1001 switch (m_downloadType) {
1003 m_btnDownloadWorld->Enable(true);
1004 m_btnDownloadLocal->Enable(false);
1005 m_buttonUpdateCatalog->Enable(false);
1006 break;
1009 m_btnDownloadWorld->Enable(false);
1010 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
1011 m_buttonUpdateCatalog->Enable(false);
1012 break;
1014 m_xygribPanel->m_download_button->Enable(true);
1015 break;
1016 default:
1017 m_btnDownloadWorld->Enable(true);
1018 m_btnDownloadLocal->Enable(m_bLocal_source_selected || m_downloading);
1019 m_buttonUpdateCatalog->Enable(true);
1020 m_xygribPanel->m_download_button->Enable(true);
1021 break;
1022 }
1023}
1024
1025void GribRequestSetting::StopGraphicalZoneSelection() {
1027 RENDER_NONE; // eventually stop graphical zone display
1028
1029 RequestRefresh(GetGRIBCanvas());
1030}
1031
1033 if (!vp || m_VpMouse == vp) return;
1034
1035 delete m_VpMouse;
1036 m_VpMouse = new PlugIn_ViewPort(*vp);
1037}
1038
1040 if (!vp || m_VpFocus == vp) return;
1041
1042 delete m_VpFocus;
1043 m_VpFocus = new PlugIn_ViewPort(*vp);
1044
1045 if (!m_AllowSend) return;
1046 if (m_rbManualSelect->GetValue()) return;
1047
1048 SetVpSize(vp);
1049 // Viewport has changed : XyGrib estimated size must be recalculated
1050 // when in automatic selection mode.
1051 UpdateGribSizeEstimate();
1052}
1053
1054void GribRequestSetting::ApplyRequestConfig(unsigned rs, unsigned it,
1055 unsigned tr) {
1056 // some useful strings
1057 const wxString res[][RESOLUTIONS] = {
1058 {"0.25", "0.5", "1.0", "2.0"},
1059 {"0.2", "0.8", "1.6", wxEmptyString},
1060 {"0.08", "0.24", "1.0", wxEmptyString}, // RTOFS
1061 {"0.03", "0.24", "1.0", wxEmptyString}, // HRRR
1062 {"0.0625", "0.125", wxEmptyString, wxEmptyString}, // ICON
1063 {"0.4", "1.0", "2.0", wxEmptyString} // ECMWF
1064 };
1065
1066 IsZYGRIB = m_pMailTo->GetCurrentSelection() == ZYGRIB;
1067 if (IsZYGRIB)
1068 m_pModel->SetSelection(GFS); // Model is always GFS when Zygrib selected
1069 IsGFS = m_pModel->GetCurrentSelection() == GFS;
1070 bool IsRTOFS = m_pModel->GetCurrentSelection() == RTOFS;
1071 bool IsHRRR = m_pModel->GetCurrentSelection() == HRRR;
1072 bool IsICON = m_pModel->GetCurrentSelection() == ICON;
1073 bool IsECMWF = m_pModel->GetCurrentSelection() == ECMWF;
1074
1075 // populate resolution choice
1076 m_pResolution->Clear();
1077 if (m_pModel->GetCurrentSelection() >= 0) {
1078 for (int i = 0; i < RESOLUTIONS; i++) {
1079 if (res[m_pModel->GetCurrentSelection()][i] != wxEmptyString) {
1080 wxString s = res[m_pModel->GetCurrentSelection()][i];
1081 m_pResolution->Append(s);
1082 }
1083 }
1084 }
1085 m_pResolution->SetSelection(rs);
1086
1087 unsigned l;
1088 // populate time interval choice
1089 l = (IsGFS || IsRTOFS || IsICON || IsECMWF) ? 3 : IsHRRR ? 1 : 6;
1090
1091 unsigned m;
1092 m = IsHRRR ? 2 : 25;
1093
1094 m_pInterval->Clear();
1095 for (unsigned i = l; i < m; i *= 2)
1096 m_pInterval->Append(wxString::Format("%d", i));
1097 m_pInterval->SetSelection(wxMin(it, m_pInterval->GetCount() - 1));
1098
1099 // populate time range choice
1100 l = IsZYGRIB ? 8
1101 : IsGFS ? 16
1102 : IsRTOFS ? 6
1103 : IsECMWF ? 10
1104 : IsICON ? 7
1105 : IsHRRR ? 2
1106 : 3;
1107 m_pTimeRange->Clear();
1108 for (unsigned i = 2; i < l + 1; i++)
1109 m_pTimeRange->Append(wxString::Format("%d", i));
1110 m_pTimeRange->SetSelection(wxMin(l - 2, tr));
1111
1112 m_pModel->Enable(!IsZYGRIB);
1113 m_pWind->SetValue(!IsRTOFS);
1114 m_pPress->SetValue(!IsRTOFS);
1115 m_pWaves->SetValue(m_RequestConfigBase.GetChar(8) == 'X' && IsGFS);
1116 m_pWaves->Enable(IsECMWF ||
1117 (IsGFS && m_pTimeRange->GetCurrentSelection() < 7));
1118 // gfs & time range less than 8 days
1119 m_pRainfall->SetValue(m_RequestConfigBase.GetChar(9) == 'X' &&
1120 (IsGFS || IsHRRR));
1121 m_pRainfall->Enable(IsGFS || IsHRRR);
1122 m_pCloudCover->SetValue(m_RequestConfigBase.GetChar(10) == 'X' && IsGFS);
1123 m_pCloudCover->Enable(IsGFS);
1124 m_pAirTemp->SetValue(m_RequestConfigBase.GetChar(11) == 'X' &&
1125 (IsGFS || IsHRRR || IsICON || IsECMWF));
1126 m_pAirTemp->Enable(IsGFS || IsHRRR || IsICON || IsECMWF);
1127 m_pSeaTemp->SetValue(m_RequestConfigBase.GetChar(12) == 'X' &&
1128 ((!IsZYGRIB && IsGFS) || IsRTOFS || IsHRRR || IsICON));
1129 m_pSeaTemp->Enable(!IsZYGRIB && (IsGFS || IsHRRR || IsICON));
1130 m_pWindGust->SetValue(m_RequestConfigBase.GetChar(14) == 'X' &&
1131 (IsGFS || IsHRRR || IsICON));
1132 m_pWindGust->Enable(IsGFS || IsHRRR || IsICON);
1133 m_pCAPE->SetValue(m_RequestConfigBase.GetChar(15) == 'X' &&
1134 (IsGFS || IsHRRR));
1135 m_pCAPE->Enable(IsGFS || IsHRRR);
1136 m_pReflectivity->Enable(IsGFS || IsHRRR);
1137
1138 m_pAltitudeData->SetValue(
1139 (IsGFS || IsICON || IsECMWF)
1140 ? m_RequestConfigBase.GetChar(17) == 'X'
1141 : false); // altitude data zigrib + saildocs GFS and ICON
1142 m_pAltitudeData->Enable(IsGFS || IsICON || IsECMWF);
1143 m_p850hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(18) == 'X'
1144 : false); // only zygrib
1145 m_p850hpa->Enable(IsZYGRIB);
1146 m_p700hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(19) == 'X'
1147 : false); // only zigrib
1148 m_p700hpa->Enable(IsZYGRIB);
1149 m_p500hpa->SetValue((IsGFS || IsICON || IsECMWF)
1150 ? m_RequestConfigBase.GetChar(20) == 'X'
1151 : false); // zigrib + saildocs GFS ICON ECMWF
1152 m_p500hpa->Enable(IsGFS || IsICON || IsECMWF);
1153 m_p300hpa->SetValue(IsZYGRIB ? m_RequestConfigBase.GetChar(21) == 'X'
1154 : false); // only zigrib
1155 m_p300hpa->Enable(IsZYGRIB);
1156
1157 m_pCurrent->SetValue(IsRTOFS);
1158 m_pCurrent->Enable(false);
1159
1160 // show parameters only if necessary
1161 m_cMovingGribEnabled->Show(!IsZYGRIB); // show/hide Moving settings
1162 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1163 m_cMovingGribEnabled->IsShown());
1164
1165 m_fgLog->ShowItems(IsZYGRIB); // show/hide zigrib login
1166
1167 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked()); // show/hide waves model
1168
1169 m_fgAltitudeData->ShowItems(
1170 m_pAltitudeData->IsChecked()); // show/hide altitude params
1171}
1172
1173void GribRequestSetting::OnTopChange(wxCommandEvent &event) {
1174 // deactivate momentary ZyGrib option
1175 if (m_pMailTo->GetCurrentSelection() == ZYGRIB) {
1176 m_pMailTo->SetSelection(0);
1178 this,
1179 _("Sorry...\nZyGrib momentary stopped providing this service...\nOnly "
1180 "Saildocs option is available"),
1181 _("Warning"), wxOK);
1182 }
1183 ApplyRequestConfig(m_pResolution->GetCurrentSelection(),
1184 m_pInterval->GetCurrentSelection(),
1185 m_pTimeRange->GetCurrentSelection());
1186
1187 m_cMovingGribEnabled->Show(m_pMailTo->GetCurrentSelection() == SAILDOCS);
1188
1189 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1190
1191 SetRequestDialogSize();
1192}
1193
1194void GribRequestSetting::UpdateAreaSelectionState() {
1195 bool readOnly = (m_ZoneSelMode == AUTO_SELECTION);
1196 m_spMaxLat->Enable(!readOnly);
1197 m_spMaxLon->Enable(!readOnly);
1198 m_spMinLat->Enable(!readOnly);
1199 m_spMinLon->Enable(!readOnly);
1200 m_cUseSavedZone->Enable(m_ZoneSelMode != AUTO_SELECTION);
1201}
1202
1203void GribRequestSetting::OnZoneSelectionModeChange(wxCommandEvent &event) {
1204 StopGraphicalZoneSelection(); // eventually stop graphical zone display
1205
1207 // Recompute zone based on the viewport that has the focus.
1208 SetVpSize(m_VpFocus);
1209 }
1210
1211 if (event.GetId() == AUTOSELECT) {
1212 m_rbManualSelect->SetValue(false);
1213 } else if (event.GetId() == MANSELECT) {
1214 m_rbCurrentView->SetValue(false);
1215 // set temporarily zone selection mode if manual selection set, put it
1216 // directly in "drawing" position else put it in "auto selection" position
1219 m_cUseSavedZone->SetValue(false);
1220 } else if (event.GetId() == SAVEDZONE) {
1221 // set temporarily zone selection mode if saved selection set, put it
1222 // directly in "no selection" position else put it directly in "drawing"
1223 // position
1225 m_cUseSavedZone->GetValue() ? SAVED_SELECTION : DRAW_SELECTION;
1226 }
1227 m_parent.SetRequestButtonBitmap(m_ZoneSelMode); // set appopriate bitmap
1228 UpdateAreaSelectionState(); // update the state of the coordinate spinners
1229 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1230
1231 SetRequestDialogSize();
1232}
1233
1235 wxPoint p;
1237
1238 int x = (m_StartPoint.x < p.x) ? m_StartPoint.x : p.x;
1239 int y = (m_StartPoint.y < p.y) ? m_StartPoint.y : p.y;
1240
1241 int zw = fabs((double)p.x - m_StartPoint.x);
1242 int zh = fabs((double)p.y - m_StartPoint.y);
1243
1244 wxPoint center;
1245 center.x = x + (zw / 2);
1246 center.y = y + (zh / 2);
1247
1248 wxFont fo = *OCPNGetFont(_("Dialog"));
1249 fo.SetPointSize(
1250 (fo.GetPointSize() * m_displayScale / OCPN_GetWinDIPScaleFactor()));
1251 wxFont *font = &fo;
1252 wxColour pen_color, back_color;
1253 GetGlobalColor("DASHR", &pen_color);
1254 GetGlobalColor("YELO1", &back_color);
1255
1256 int label_offsetx = 5, label_offsety = 1;
1257
1258 double size;
1259 EstimateFileSize(&size);
1260
1261 wxString label(_("Coord. "));
1262 label.Append(toMailFormat(1, m_spMaxLat->GetValue()) + " ");
1263 label.Append(toMailFormat(0, m_spMinLon->GetValue()) + " ");
1264 label.Append(toMailFormat(1, m_spMinLat->GetValue()) + " ");
1265 label.Append(toMailFormat(0, m_spMaxLon->GetValue()) + "\n");
1266 label.Append("Estim. Size ")
1267 .Append((wxString::Format("%1.2f ", size) + _("MB")));
1268
1269 if (m_pdc) {
1270 wxPen pen(pen_color);
1271 pen.SetWidth(3);
1272 m_pdc->SetPen(pen);
1273 m_pdc->SetBrush(*wxTRANSPARENT_BRUSH);
1274 m_pdc->DrawRectangle(x, y, zw, zh);
1275
1276 int w, h, sl;
1277#ifdef __WXMAC__
1278 wxScreenDC sdc;
1279 sdc.GetMultiLineTextExtent(label, &w, &h, &sl, font);
1280#else
1281 m_pdc->GetMultiLineTextExtent(label, &w, &h, &sl, font);
1284#endif
1285 w += 2 * label_offsetx, h += 2 * label_offsety;
1286 x = center.x - (w / 2);
1287 y = center.y - (h / 2);
1288
1289 h *= m_displayScale;
1290 w *= m_displayScale;
1291
1292 wxBitmap bm(w, h);
1293 wxMemoryDC mdc(bm);
1294 mdc.Clear();
1295
1296 mdc.SetFont(*font);
1297 mdc.SetBrush(back_color);
1298 mdc.SetPen(*wxTRANSPARENT_PEN);
1299 mdc.SetTextForeground(wxColor(0, 0, 0));
1300 mdc.DrawRectangle(0, 0, w, h);
1301 mdc.DrawLabel(label, wxRect(label_offsetx, label_offsety, w, h));
1302
1303 wxImage im = bm.ConvertToImage();
1304 im.InitAlpha();
1305 w = im.GetWidth(), h = im.GetHeight();
1306 for (int j = 0; j < h; j++)
1307 for (int i = 0; i < w; i++) im.SetAlpha(i, j, 155);
1308
1309 m_pdc->DrawBitmap(im, x, y, true);
1310
1311 } else {
1312#ifdef ocpnUSE_GL
1313#ifndef USE_ANDROID_GLES2
1314
1315 if (!m_oDC) {
1316 m_oDC = new pi_ocpnDC();
1317 }
1318
1319 m_oDC->SetVP(m_VpMouse);
1320 m_oDC->SetPen(wxPen(pen_color, 3));
1321
1322 wxPoint outline[5];
1323 outline[0] = wxPoint(x, y);
1324 outline[1] = wxPoint(x + zw, y);
1325 outline[2] = wxPoint(x + zw, y + zh);
1326 outline[3] = wxPoint(x, y + zh);
1327 outline[4] = wxPoint(x, y);
1328 m_oDC->DrawLines(5, outline);
1329
1330 m_oDC->SetFont(*font);
1331 int w, h, ww, hw;
1332 m_oDC->GetTextExtent(label, &w, &h);
1333 h *= m_displayScale;
1334 w *= m_displayScale;
1335
1336 m_oDC->GetTextExtent("W", &ww, &hw);
1337
1338 int label_offsetx_ = ww, label_offsety_ = 1;
1339 int x_ = center.x - w / 2;
1340 int y_ = center.y - h / 2;
1341
1342 w += 2 * label_offsetx_, h += 2 * label_offsety_;
1343
1344 m_oDC->SetBrush(wxBrush(back_color));
1345 m_oDC->DrawRoundedRectangle(x_, y_, w, h, 0);
1346
1347 /* draw bounding rectangle */
1348 m_oDC->SetPen(wxPen(wxColour(0, 0, 0), 1));
1349
1350 outline[0] = wxPoint(x_, y_);
1351 outline[1] = wxPoint(x_ + w, y_);
1352 outline[2] = wxPoint(x_ + w, y_ + h);
1353 outline[3] = wxPoint(x_, y_ + h);
1354 outline[4] = wxPoint(x_, y_);
1355 m_oDC->DrawLines(5, outline);
1356
1357 m_oDC->DrawText(label, x_ + label_offsetx_, y_ + label_offsety_);
1358
1359#endif
1360#endif
1361 }
1362 return true;
1363}
1364
1366 if (m_RenderSelectionZoneState == RENDER_NONE) return false;
1367 m_pdc = nullptr; // inform lower layers that this is OpenGL render
1368 return DoRenderZoneOverlay();
1369}
1370
1372 if (m_RenderSelectionZoneState == RENDER_NONE) return false;
1373 m_pdc = &dc;
1374 return DoRenderZoneOverlay();
1375}
1376
1377void GribRequestSetting::OnMovingClick(wxCommandEvent &event) {
1378 m_fgMovingParams->ShowItems(m_cMovingGribEnabled->IsChecked() &&
1379 m_cMovingGribEnabled->IsShown());
1380
1381 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1382 SetRequestDialogSize();
1383
1384 this->Refresh();
1385}
1386
1387void GribRequestSetting::OnCoordinatesChange(wxSpinEvent &event) {
1388 SetCoordinatesText();
1389
1390 StopGraphicalZoneSelection(); // eventually stop graphical zone display
1391
1392 if (!m_AllowSend) return;
1393
1394 m_MailImage->SetValue(WriteMail());
1395}
1396
1397void GribRequestSetting::OnAnyChange(wxCommandEvent &event) {
1398 m_fgAltitudeData->ShowItems(m_pAltitudeData->IsChecked());
1399
1400 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1401
1402 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1403
1404 SetRequestDialogSize();
1405}
1406
1407void GribRequestSetting::OnTimeRangeChange(wxCommandEvent &event) {
1408 m_pWModel->Show(IsZYGRIB && m_pWaves->IsChecked());
1409
1410 if (m_pModel->GetCurrentSelection() == 0) { // gfs
1411 if (m_pTimeRange->GetCurrentSelection() >
1412 6) { // time range more than 8 days
1413 m_pWaves->SetValue(0);
1414 m_pWaves->Enable(false);
1416 this,
1417 _("You request a forecast for more than 8 days horizon.\nThis is "
1418 "conflicting with Wave data which will be removed from your "
1419 "request.\nDon't forget that beyond the first 8 days, the "
1420 "resolution will be only 2.5\u00B0x2.5\u00B0\nand the time "
1421 "intervall 12 hours."),
1422 _("Warning!"));
1423 } else
1424 m_pWaves->Enable(true);
1425 }
1426
1427 if (m_AllowSend) m_MailImage->SetValue(WriteMail());
1428
1429 SetRequestDialogSize();
1430}
1431
1432void GribRequestSetting::OnOK(wxCommandEvent &event) {
1433 bool IsCOAMPS = m_pModel->GetCurrentSelection() == COAMPS;
1434 bool IsRTOFS = m_pModel->GetCurrentSelection() == RTOFS;
1435 bool IsICON = m_pModel->GetCurrentSelection() == ICON;
1436 bool IsECMWF = m_pModel->GetCurrentSelection() == ECMWF;
1437 m_RequestConfigBase.SetChar(
1438 0, (char)(m_pMailTo->GetCurrentSelection() + '0')); // recipient
1439 m_cMovingGribEnabled->IsChecked()
1440 ? m_RequestConfigBase.SetChar(16, 'X') // moving grib
1441 : m_RequestConfigBase.SetChar(16, '.');
1442
1443 if (!IsZYGRIB)
1444 m_RequestConfigBase.SetChar(
1445 1, (char)(m_pModel->GetCurrentSelection() + '0')); // model
1446 if (!IsECMWF)
1447 m_RequestConfigBase.SetChar(
1448 2, (char)(m_pResolution->GetCurrentSelection() + '0')); // resolution
1449
1450 m_RequestConfigBase.SetChar(3,
1451 (char)(m_pInterval->GetCurrentSelection() + '0'));
1452
1453 wxString range;
1454 range.Printf("%x", m_pTimeRange->GetCurrentSelection() +
1455 1); // range max = 2 to 16 stored in hexa 1 to f
1456 m_RequestConfigBase.SetChar(4, range.GetChar(0));
1457
1458 if (IsZYGRIB && m_pWModel->IsShown())
1459 m_RequestConfigBase.SetChar(
1460 5, (char)(m_pWModel->GetCurrentSelection() + '0')); // waves model
1461
1462 m_RequestConfigBase.SetChar(
1463 6, 'X'); // wind must be always selected as a default
1464 m_RequestConfigBase.SetChar(
1465 7, 'X'); // pressure must be always selected as a default
1466
1467 if (!IsCOAMPS && !IsRTOFS) {
1468 m_pWindGust->IsChecked() ? m_RequestConfigBase.SetChar(14, 'X') // Gust
1469 : m_RequestConfigBase.SetChar(14, '.');
1470 m_pWaves->IsChecked() ? m_RequestConfigBase.SetChar(8, 'X') // waves
1471 : m_RequestConfigBase.SetChar(8, '.');
1472 m_pRainfall->IsChecked() ? m_RequestConfigBase.SetChar(9, 'X') // rainfall
1473 : m_RequestConfigBase.SetChar(9, '.');
1474 m_pCloudCover->IsChecked() ? m_RequestConfigBase.SetChar(10, 'X') // clouds
1475 : m_RequestConfigBase.SetChar(10, '.');
1476 m_pAirTemp->IsChecked() ? m_RequestConfigBase.SetChar(11, 'X') // air temp
1477 : m_RequestConfigBase.SetChar(11, '.');
1478 m_pSeaTemp->IsChecked() ? m_RequestConfigBase.SetChar(12, 'X') // sea temp
1479 : m_RequestConfigBase.SetChar(12, '.');
1480 m_pCAPE->IsChecked() ? m_RequestConfigBase.SetChar(15, 'X') // cape
1481 : m_RequestConfigBase.SetChar(15, '.');
1482 }
1483 if (IsRTOFS) // current
1484 m_pCurrent->IsChecked() ? m_RequestConfigBase.SetChar(13, 'X')
1485 : m_RequestConfigBase.SetChar(13, '.');
1486
1487 if (IsGFS || IsICON || IsECMWF) {
1488 m_pAltitudeData->IsChecked()
1489 ? m_RequestConfigBase.SetChar(17, 'X') // altitude data
1490 : m_RequestConfigBase.SetChar(17, '.');
1491 m_p500hpa->IsChecked() ? m_RequestConfigBase.SetChar(20, 'X')
1492 : m_RequestConfigBase.SetChar(20, '.');
1493 }
1494 if (IsZYGRIB) {
1495 m_p850hpa->IsChecked() ? m_RequestConfigBase.SetChar(18, 'X')
1496 : m_RequestConfigBase.SetChar(18, '.');
1497 m_p700hpa->IsChecked() ? m_RequestConfigBase.SetChar(19, 'X')
1498 : m_RequestConfigBase.SetChar(19, '.');
1499 m_p300hpa->IsChecked() ? m_RequestConfigBase.SetChar(21, 'X')
1500 : m_RequestConfigBase.SetChar(21, '.');
1501 }
1502 SaveConfig();
1503 wxCloseEvent evt;
1504 OnClose(evt);
1505}
1506
1507wxString GribRequestSetting::WriteMail() {
1508 // define size limits for zyGrib
1509 int limit = IsZYGRIB ? 2 : 0; // new limit 2 mb
1510
1511 m_MailError_Nb = 0;
1512 // some useful strings
1513 const wxString s[] = {",", " "}; // separators
1514 const wxString p[][11] = {
1515 // parameters GFS from Saildocs
1516 {"APCP", "TCDC", "AIRTMP", "HTSGW,WVPER,WVDIR", "SEATMP", "GUST", "CAPE",
1517 wxEmptyString, wxEmptyString, "WIND500,HGT500", wxEmptyString},
1518 {}, // COAMPS
1519 {}, // RTOFS
1520 {}, // HRRR = same parameters as GFS
1521 // parametres ICON
1522 {"", "", "AIRTMP", "", "SFCTMP", "GUST", "", "", "", "WIND500,HGT500",
1523 ""},
1524 // parametres ECMWF
1525 {"", "", "TEMP", "WAVES", "", "", "", "", "", "WIND500,HGT500", ""},
1526 // parameters GFS from zygrib
1527 {"PRECIP", "CLOUD", "TEMP", "WVSIG WVWIND", wxEmptyString, "GUST", "CAPE",
1528 "A850", "A700", "A500", "A300"}};
1529
1530 wxString r_topmess, r_parameters, r_zone;
1531 // write the top part of the mail
1532 switch (m_pMailTo->GetCurrentSelection()) {
1533 case SAILDOCS: // Saildocs
1534 r_zone = toMailFormat(1, m_spMaxLat->GetValue()) + "," +
1535 toMailFormat(1, m_spMinLat->GetValue()) + "," +
1536 toMailFormat(2, m_spMinLon->GetValue()) + "," +
1537 toMailFormat(2, m_spMaxLon->GetValue());
1538 r_topmess = "send ";
1539 r_topmess.Append(m_pModel->GetStringSelection() + ":");
1540 r_topmess.Append(r_zone + "|");
1541 r_topmess.Append(m_pResolution->GetStringSelection())
1542 .Append(",")
1543 .Append(m_pResolution->GetStringSelection())
1544 .Append("|");
1545 double v;
1546 m_pInterval->GetStringSelection().ToDouble(&v);
1547 r_topmess.Append(wxString::Format("0,%d,%d", (int)v, (int)v * 2));
1548 m_pTimeRange->GetStringSelection().ToDouble(&v);
1549 r_topmess.Append(wxString::Format("..%d", (int)v * 24) + "|=\n");
1550 break;
1551 case ZYGRIB: // Zygrib
1552 double maxlon = (m_spMinLon->GetValue() > m_spMaxLon->GetValue() &&
1553 m_spMaxLon->GetValue() < 0)
1554 ? m_spMaxLon->GetValue() + 360
1555 : m_spMaxLon->GetValue();
1556 r_zone = toMailFormat(1, m_spMinLat->GetValue()) +
1557 toMailFormat(2, m_spMinLon->GetValue()) + " " +
1558 toMailFormat(1, m_spMaxLat->GetValue()) +
1559 toMailFormat(2, maxlon);
1560 r_topmess = "login : ";
1561 r_topmess.Append(m_pLogin->GetValue() + "\n");
1562 r_topmess.Append("code :");
1563 r_topmess.Append(m_pCode->GetValue() + "\n");
1564 r_topmess.Append("area : ");
1565 r_topmess.append(r_zone + "\n");
1566 r_topmess.Append("resol : ");
1567 r_topmess.append(m_pResolution->GetStringSelection() + "\n");
1568 r_topmess.Append("days : ");
1569 r_topmess.append(m_pTimeRange->GetStringSelection() + "\n");
1570 r_topmess.Append("hours : ");
1571 r_topmess.append(m_pInterval->GetStringSelection() + "\n");
1572 if (m_pWaves->IsChecked()) {
1573 r_topmess.Append("waves : ");
1574 r_topmess.append(m_pWModel->GetStringSelection() + "\n");
1575 }
1576 r_topmess.Append("meteo : ");
1577 r_topmess.append(m_pModel->GetStringSelection() + "\n");
1578 if (m_pLogin->GetValue().IsEmpty() || m_pCode->GetValue().IsEmpty())
1579 m_MailError_Nb = 6;
1580 break;
1581 }
1582 // write the parameters part of the mail
1583 int GFSZ = IsZYGRIB ? 6 : 0;
1584 switch (m_pModel->GetCurrentSelection()) {
1585 case GFS: // GFS
1586 r_parameters = "WIND" + s[m_pMailTo->GetCurrentSelection()] +
1587 "PRESS"; // the default minimum request parameters
1588 if (m_pRainfall->IsChecked())
1589 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1590 p[GFS + GFSZ][0]);
1591 if (m_pCloudCover->IsChecked())
1592 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1593 p[GFS + GFSZ][1]);
1594 if (m_pAirTemp->IsChecked())
1595 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1596 p[GFS + GFSZ][2]);
1597 if (m_pWaves->IsChecked())
1598 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1599 p[GFS + GFSZ][3]);
1600 if (m_pSeaTemp->IsChecked())
1601 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1602 p[GFS + GFSZ][4]);
1603 if (m_pWindGust->IsChecked())
1604 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1605 p[GFS + GFSZ][5]);
1606 if (m_pCAPE->IsChecked())
1607 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1608 p[GFS + GFSZ][6]);
1609 if (m_pAltitudeData->IsChecked()) {
1610 if (m_p850hpa->IsChecked())
1611 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1612 p[GFS + GFSZ][7]);
1613 if (m_p700hpa->IsChecked())
1614 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1615 p[GFS + GFSZ][8]);
1616 if (m_p500hpa->IsChecked())
1617 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1618 p[GFS + GFSZ][9]);
1619 if (m_p300hpa->IsChecked())
1620 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1621 p[GFS + GFSZ][10]);
1622 }
1623 break;
1624 case COAMPS: // COAMPS
1625 r_parameters = "WIND,PRMSL"; // the default parameters for this
1626 // model
1627 break;
1628 case RTOFS: // RTOFS
1629 r_parameters = "CUR,WTMP"; // the default parameters for this model
1630 break;
1631 case HRRR: // HRRR
1632 r_parameters = "WIND,PRMSL"; // the default parameters for this
1633 // model
1634 if (m_pRainfall->IsChecked())
1635 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][0]);
1636 if (m_pAirTemp->IsChecked())
1637 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][2]);
1638 if (m_pSeaTemp->IsChecked())
1639 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][4]);
1640 if (m_pWindGust->IsChecked())
1641 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][5]);
1642 if (m_pCAPE->IsChecked())
1643 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[GFS][6]);
1644 break;
1645 case ICON:
1646 r_parameters = "WIND,PRMSL"; // the default parameters for this
1647 // model
1648 if (m_pAirTemp->IsChecked())
1649 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][2]);
1650 if (m_pSeaTemp->IsChecked())
1651 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][4]);
1652 if (m_pWindGust->IsChecked())
1653 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][5]);
1654 if (m_pAltitudeData->IsChecked()) {
1655 if (m_p500hpa->IsChecked())
1656 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ICON][9]);
1657 }
1658 break;
1659 case ECMWF:
1660 r_parameters = "WIND,MSLP"; // the default parameters for this
1661 // model
1662 if (m_pAirTemp->IsChecked())
1663 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][2]);
1664 if (m_pAltitudeData->IsChecked()) {
1665 if (m_p500hpa->IsChecked())
1666 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] +
1667 p[ECMWF][9]);
1668 }
1669 if (m_pWaves->IsChecked())
1670 r_parameters.Append(s[m_pMailTo->GetCurrentSelection()] + p[ECMWF][3]);
1671 break;
1672 }
1673 if (!IsZYGRIB && m_cMovingGribEnabled->IsChecked()) // moving grib
1674 r_parameters.Append(wxString::Format("|%d,%d", m_sMovingSpeed->GetValue(),
1675 m_sMovingCourse->GetValue()));
1676
1677 // line lenth limitation
1678 int j = 0;
1679 char c = m_pMailTo->GetCurrentSelection() == SAILDOCS ? ',' : ' ';
1680 for (size_t i = 0; i < r_parameters.Len(); i++) {
1681 if (r_parameters.GetChar(i) == '|')
1682 j--; // do not split Saildocs "moving" values
1683 if (r_parameters.GetChar(i) == c) j++;
1684 if (j > 6) { // no more than 6 parameters on the same line
1685 r_parameters.insert(
1686 i + 1, m_pMailTo->GetCurrentSelection() == SAILDOCS ? "=\n" : "\n");
1687 break;
1688 }
1689 }
1690
1691 double size;
1692 m_MailError_Nb += EstimateFileSize(&size);
1693
1694 m_tFileSize->SetLabel(wxString::Format("%1.2f ", size) + _("MB"));
1695
1696 if (IsZYGRIB) {
1697 m_tLimit->SetLabel(wxString("( ") + _("Max") +
1698 wxString::Format(" %d ", limit) + _("MB") + " )");
1699 if (size > limit) m_MailError_Nb += 2;
1700 } else
1701 m_tLimit->SetLabel(wxEmptyString);
1702
1703 return wxString(r_topmess + r_parameters);
1704}
1705
1706int GribRequestSetting::EstimateFileSize(double *size) {
1707 if (!size) return 0; // Wrong parameter
1708 *size = 0.;
1709
1710 // too small zone ? ( mini 2 * resolutions )
1711 double reso, time, inter;
1712 m_pResolution->GetStringSelection().ToDouble(&reso);
1713 m_pTimeRange->GetStringSelection().ToDouble(&time);
1714 m_pInterval->GetStringSelection().ToDouble(&inter);
1715
1716 double maxlon = m_spMaxLon->GetValue(), minlon = m_spMinLon->GetValue();
1717 double maxlat = m_spMaxLat->GetValue(), minlat = m_spMinLat->GetValue();
1718 if (maxlat - minlat < 0) return 3; // maxlat must be > minlat
1719 double wlon = (maxlon > minlon ? 0 : 360) + maxlon - minlon;
1720 if (wlon > 180 || (maxlat - minlat > 180)) return 4; // ovoid too big area
1721
1722 if (fabs(wlon) < 2 * reso || maxlat - minlat < 2 * reso)
1723 return 5; // ovoid too small area
1724
1725 int npts = (int)(ceil(((double)(maxlat - minlat) / reso)) *
1726 ceil(((double)(wlon) / reso)));
1727
1728 if (m_pModel->GetCurrentSelection() == COAMPS) // limited area for COAMPS
1729 npts = wxMin(npts, (int)(ceil(40.0 / reso) * ceil(40.0 / reso)));
1730
1731 // Nombre de GribRecords
1732 int nbrec = (int)(time * 24 / inter) + 1;
1733 int nbPress = (m_pPress->IsChecked()) ? nbrec : 0;
1734 int nbWind = (m_pWind->IsChecked()) ? 2 * nbrec : 0;
1735 int nbwave = (m_pWaves->IsChecked()) ? 2 * nbrec : 0;
1736 int nbRain = (m_pRainfall->IsChecked()) ? nbrec - 1 : 0;
1737 int nbCloud = (m_pCloudCover->IsChecked()) ? nbrec - 1 : 0;
1738 int nbTemp = (m_pAirTemp->IsChecked()) ? nbrec : 0;
1739 int nbSTemp = (m_pSeaTemp->IsChecked()) ? nbrec : 0;
1740 int nbGUSTsfc = (m_pWindGust->IsChecked()) ? nbrec : 0;
1741 int nbCurrent = (m_pCurrent->IsChecked()) ? nbrec : 0;
1742 int nbCape = (m_pCAPE->IsChecked()) ? nbrec : 0;
1743 int nbAltitude =
1744 IsZYGRIB ? 5 * nbrec : 3 * nbrec; // five data types are included in each
1745 // ZyGrib altitude request and only
1746 // three in sSaildocs's
1747 int head = 84;
1748 double estime = 0.0;
1749 int nbits;
1750
1751 nbits = 13;
1752 estime += nbWind * (head + (nbits * npts) / 8 + 2);
1753 estime += nbCurrent * (head + (nbits * npts) / 8 + 2);
1754
1755 nbits = 11;
1756 estime += nbTemp * (head + (nbits * npts) / 8 + 2);
1757 estime += nbSTemp * (head + (nbits * npts) / 8 + 2);
1758
1759 nbits = 4;
1760 estime += nbRain * (head + (nbits * npts) / 8 + 2);
1761
1762 nbits = 15;
1763 estime += nbPress * (head + (nbits * npts) / 8 + 2);
1764
1765 nbits = 4;
1766 estime += nbCloud * (head + (nbits * npts) / 8 + 2);
1767
1768 nbits = 7;
1769 estime += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
1770
1771 nbits = 5;
1772 estime += nbCape * (head + (nbits * npts) / 8 + 2);
1773
1774 nbits = 6;
1775 estime += nbwave * (head + (nbits * npts) / 8 + 2);
1776
1777 if (m_pAltitudeData->IsChecked()) {
1778 int nbalt = 0;
1779 if (m_p850hpa->IsChecked()) nbalt++;
1780 if (m_p700hpa->IsChecked()) nbalt++;
1781 if (m_p500hpa->IsChecked()) nbalt++;
1782 if (m_p300hpa->IsChecked()) nbalt++;
1783
1784 nbits = 12;
1785 estime += nbAltitude * nbalt * (head + (nbits * npts) / 8 + 2);
1786 }
1787
1788 *size = estime / (1024. * 1024.);
1789
1790 return 0;
1791}
1792
1793const wxString EncodeURL(const wxString &uri) {
1794 static std::unordered_map<int, wxString> sEncodeMap = {
1795 {(int)'!', "%21"}, {(int)'#', "%23"}, {(int)'$', "%24"},
1796 {(int)'&', "%26"}, {(int)'\'', "%27"}, {(int)'(', "%28"},
1797 {(int)')', "%29"}, {(int)'*', "%2A"}, {(int)'+', "%2B"},
1798 {(int)',', "%2C"}, {(int)';', "%3B"}, {(int)'=', "%3D"},
1799 {(int)'?', "%3F"}, {(int)'@', "%40"}, {(int)'[', "%5B"},
1800 {(int)']', "%5D"}, {(int)' ', "%20"}, {(int)'|', "%7C"},
1801 {(int)':', "%3A"}, {(int)'\n', "%0A"}};
1802
1803 wxString encoded;
1804 for (size_t i = 0; i < uri.length(); ++i) {
1805 wxChar ch = uri[i];
1806 std::unordered_map<int, wxString>::iterator iter = sEncodeMap.find((int)ch);
1807 if (iter != sEncodeMap.end()) {
1808 encoded << iter->second;
1809 } else {
1810 encoded << ch;
1811 }
1812 }
1813 return encoded;
1814}
1815
1816void GribRequestSetting::OnSendMaiL(wxCommandEvent &event) {
1817 StopGraphicalZoneSelection(); // eventually stop graphical zone display
1818
1819 if (!m_AllowSend) {
1820 m_rButtonCancel->Show();
1821 m_rButtonApply->Show();
1822 m_rButtonYes->SetLabel(_("Send"));
1823
1824 m_MailImage->SetForegroundColour(
1825 wxColor(0, 0, 0)); // permit to send a (new) message
1826 m_AllowSend = true;
1827
1828 m_MailImage->SetValue(WriteMail());
1829 SetRequestDialogSize();
1830
1831 return;
1832 }
1833
1834 const wxString error[] = {
1835 "\n\n",
1836 _("Before sending an email to Zygrib you have to enter your Login and "
1837 "Code.\nPlease visit www.zygrib.org/ and follow instructions..."),
1838 _("Too big file! zyGrib limit is 2Mb!"),
1839 _("Error! Max Lat lower than Min Lat or Max Lon lower than Min Lon!"),
1840 _("Too large area! Each side must be less than 180\u00B0!"),
1841 _("Too small area for this resolution!")};
1842
1843 ::wxBeginBusyCursor();
1844
1845 m_MailImage->SetForegroundColour(wxColor(255, 0, 0));
1846 m_AllowSend = false;
1847
1848 if (m_MailError_Nb) {
1849 if (m_MailError_Nb > 7) {
1850 m_MailImage->SetValue(error[1] + error[0] + error[m_MailError_Nb - 6]);
1851 } else {
1852 if (m_MailError_Nb == 6) m_MailError_Nb = 1;
1853 m_MailImage->SetValue(error[m_MailError_Nb]);
1854 }
1855
1856 m_rButtonYes->SetLabel(_("Continue..."));
1857 SetRequestDialogSize();
1858
1859 ::wxEndBusyCursor();
1860
1861 return;
1862 }
1863
1864 std::string mailto =
1865 (m_pMailTo->GetCurrentSelection() == SAILDOCS
1866 ? m_MailToAddresses.BeforeFirst(';') // to request address
1867 : m_MailToAddresses.AfterFirst(';').BeforeFirst(';'))
1868 .ToStdString();
1869 std::string mailfrom = m_pSenderAddress->GetValue().ToStdString();
1870
1871 std::regex mailregex("^([a-z0-9+_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$");
1872
1873 if ((!mailto.empty() && !std::regex_match(mailto, mailregex)) ||
1874 (!mailfrom.empty() && !std::regex_match(mailfrom, mailregex))) {
1876 this,
1877 _("Sender or recipient e-mail address seems invalid.\nPlease correct "
1878 "it in the configuration file."),
1879 _("Error"), wxOK | wxICON_ERROR);
1880 return;
1881 }
1882
1883#ifdef __WXMAC__
1884 // macOS, at least Big Sur, requires the body to be URLEncoded, otherwise the
1885 // invocation of the mail application via sh/open in wxEmail fails due to
1886 // "invalid characters" in "filename" regardless of quotation used (which is
1887 // weird, but real)
1888 wxMailMessage *message =
1889 new wxMailMessage((m_pMailTo->GetCurrentSelection() == SAILDOCS)
1890 ? "grib-request"
1891 : "gribauto", // requested subject
1892 mailto,
1893 EncodeURL(WriteMail()), // message image
1894 mailfrom);
1895#else
1896 wxMailMessage *message =
1897 new wxMailMessage((m_pMailTo->GetCurrentSelection() == SAILDOCS)
1898 ? "grib-request"
1899 : "gribauto", // requested subject
1900 mailto,
1901 WriteMail(), // message image
1902 mailfrom);
1903#endif
1904
1905 wxEmail mail;
1906 if (mail.Send(*message, m_SendMethod)) {
1907#ifdef __WXMSW__
1908 m_MailImage->SetValue(
1909 _("Your request is ready. An email is prepared in your email "
1910 "environment. \nYou have just to verify and send it...\nSave or "
1911 "Cancel to finish...or Continue..."));
1912#else
1913 if (m_SendMethod == 0) {
1914 m_MailImage->SetValue(
1915 _("Your request is ready. An email is prepared in your email "
1916 "environment. \nYou have just to verify and send it...\nSave or "
1917 "Cancel to finish...or Continue..."));
1918 } else {
1919 m_MailImage->SetValue(
1920 _("Your request was sent \n(if your system has an MTA configured and "
1921 "is able to send email).\nSave or Cancel to finish...or "
1922 "Continue..."));
1923 }
1924#endif
1925 } else {
1926 m_MailImage->SetValue(
1927 _("Request can't be sent. Please verify your email systeme "
1928 "parameters.\nYou should also have a look at your log file.\nSave or "
1929 "Cancel to finish..."));
1930 m_rButtonYes->Hide();
1931 }
1932 m_rButtonYes->SetLabel(_("Continue..."));
1933 SetRequestDialogSize();
1934 delete message;
1935 ::wxEndBusyCursor();
1936}
1937
1940wxString GribRequestSetting::BuildXyGribUrl() {
1941 // Server's base address
1942 wxString urlStr =
1943 wxString::Format("http://grbsrv.opengribs.org/getmygribs2.php?");
1944 // Bounding box
1945 urlStr << wxString::Format("la1=%.0f", floor(GetMinLat()));
1946 urlStr << wxString::Format("&la2=%.0f", ceil(GetMaxLat()));
1947 urlStr << wxString::Format("&lo1=%.0f", floor(GetMinLon()));
1948 urlStr << wxString::Format("&lo2=%.0f", ceil(GetMaxLon()));
1949
1950 // Atmospheric Model & resolution reference
1951 urlStr << wxString::Format(
1952 "&model=%s",
1953 xygribAtmModelList[m_selectedAtmModelIndex]
1954 ->reqName[m_xygribPanel->m_resolution_choice->GetSelection()]);
1955 // Interval
1956 urlStr << wxString::Format(
1957 "&intv=%d",
1958 xygribAtmModelList[m_selectedAtmModelIndex]
1959 ->interval[m_xygribPanel->m_interval_choice->GetSelection()]);
1960 // Length in days
1961 urlStr << wxString::Format(
1962 "&days=%d", m_xygribPanel->m_duration_choice->GetSelection() + 1);
1963
1964 // Selected run
1965 // TODO : available runs depend on model
1966 wxString selStr = m_xygribPanel->m_run_choice->GetStringSelection();
1967 if (selStr.IsSameAs("18h", false)) {
1968 urlStr << "&cyc=18";
1969 } else if (selStr.IsSameAs("12h", false)) {
1970 urlStr << "&cyc=12";
1971 } else if (selStr.IsSameAs("6h", false)) {
1972 urlStr << "&cyc=06";
1973 } else if (selStr.IsSameAs("0h", false)) {
1974 urlStr << "&cyc=00";
1975 } else {
1976 urlStr << "&cyc=last";
1977 }
1978
1979 // Atmospheric data fields
1980 urlStr << "&par=";
1981 if (m_xygribPanel->m_wind_cbox->IsEnabled() &&
1982 m_xygribPanel->m_wind_cbox->IsChecked())
1983 urlStr << "W;";
1984 if (m_xygribPanel->m_pressure_cbox->IsEnabled() &&
1985 m_xygribPanel->m_pressure_cbox->IsChecked()) {
1986 if (xygribAtmModelList[m_selectedAtmModelIndex]->altPressure) {
1987 urlStr << "p;";
1988 } else {
1989 urlStr << "P;";
1990 }
1991 }
1992 if (m_xygribPanel->m_precipitation_cbox->IsEnabled() &&
1993 m_xygribPanel->m_precipitation_cbox->IsChecked())
1994 urlStr << "R;";
1995 if (m_xygribPanel->m_cloudcover_cbox->IsEnabled() &&
1996 m_xygribPanel->m_cloudcover_cbox->IsChecked())
1997 urlStr << "C;";
1998 if (m_xygribPanel->m_temperature_cbox->IsEnabled() &&
1999 m_xygribPanel->m_temperature_cbox->IsChecked())
2000 urlStr << "T;";
2001 if (m_xygribPanel->m_cape_cbox->IsEnabled() &&
2002 m_xygribPanel->m_cape_cbox->IsChecked())
2003 urlStr << "c;";
2004 if (m_xygribPanel->m_reflectivity_cbox->IsEnabled() &&
2005 m_xygribPanel->m_reflectivity_cbox->IsChecked())
2006 urlStr << "r;";
2007 if (m_xygribPanel->m_gust_cbox->IsEnabled() &&
2008 m_xygribPanel->m_gust_cbox->IsChecked())
2009 urlStr << "G;";
2010
2011 // Wave model a data fields
2012 if ((m_selectedWaveModelIndex >= 0) &&
2013 (xygribWaveModelList[m_selectedWaveModelIndex] != nullptr)) {
2014 wxString modelStr = wxString::Format(
2015 "&wmdl=%s", xygribWaveModelList[m_selectedWaveModelIndex]->reqName);
2016 wxString wParams = "";
2017 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
2018 wParams << "s;";
2019 }
2020 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
2021 wParams << "h;d;p;";
2022 }
2023 if (wParams.length() > 0) {
2024 urlStr << wxString::Format("%s&wpar=%s", modelStr.c_str(),
2025 wParams.c_str());
2026 } else {
2027 urlStr << "&wmdl=none";
2028 }
2029 } else {
2030 urlStr << "&wmdl=none";
2031 }
2032
2033 return urlStr;
2034}
2035
2038wxString GribRequestSetting::BuildGribFileName() {
2039 wxString selStr = m_xygribPanel->m_resolution_choice->GetStringSelection();
2040 selStr.Replace(".", "P");
2041
2042 wxString fileName;
2043 if (m_selectedWaveModelIndex < 0) {
2044 fileName = wxString::Format(
2045 "XyGrib_%s_%s_%s.grb2", wxDateTime::Now().Format("%F-%H-%M"),
2046 m_xygribPanel->m_atmmodel_choice->GetStringSelection(), selStr);
2047 } else {
2048 fileName = wxString::Format(
2049 "XyGrib_%s_%s_%s_%s.grb2", wxDateTime::Now().Format("%F-%H-%M"),
2050 m_xygribPanel->m_atmmodel_choice->GetStringSelection(), selStr,
2051 m_xygribPanel->m_wavemodel_choice->GetStringSelection());
2052 }
2053
2054 return fileName;
2055}
2056
2057/*/ Handle action of Download/Cancel button.
2058 * This function gathers the current GRIB configuration and handles the
2059 * downloading of the GRIB file. If a transfer is already ongoing, it cancels
2060 * it.
2061 * @param event Event data from the GUI loop
2062 */
2063void GribRequestSetting::OnXyGribDownloadButton(wxCommandEvent &event) {
2064 // Check if we are already downloading a GRIB file
2065 if (m_downloading) {
2066 // Yes : it means that "Download" button has been changed to "Cancel"
2067 // button. So, let's cancel the on-going download
2068 OCPN_cancelDownloadFileBackground(m_download_handle);
2069 m_downloading = false;
2070 m_download_handle = 0;
2071 Disconnect(
2072 wxEVT_DOWNLOAD_EVENT,
2073 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2074 m_connected = false;
2075 m_xygribPanel->m_progress_gauge->SetValue(0);
2076 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2077 m_xygribPanel->m_status_text->SetLabelText(_("Download cancelled"));
2078 m_canceled = true;
2079 m_downloadType = GribDownloadType::NONE;
2080 EnableDownloadButtons();
2081 wxTheApp->ProcessPendingEvents();
2082 wxYieldIfNeeded();
2083 return;
2084 }
2085 // No : start a new download
2086 if (m_gribSizeEstimate > XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB * 1024 * 1024) {
2087 m_xygribPanel->m_status_text->SetLabelText(
2088 wxString::Format(_("Can't download GRIB file bigger than %d MB"),
2089 (int)XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB));
2090 return;
2091 }
2092
2093 // First we memorize the current configuration. This is the one which will be
2094 // saved in OpenCPN' config file at exit
2095 MemorizeXyGribConfiguration();
2096 m_canceled = false;
2097 m_downloading = true;
2098 m_downloadType = GribDownloadType::XYGRIB;
2099 EnableDownloadButtons();
2100 // Change "Download" button into "Cancel" button
2101 m_xygribPanel->m_download_button->SetLabelText(_("Cancel"));
2102 m_xygribPanel->m_status_text->SetLabelText(
2103 _("Preparing GRIB file on server..."));
2104 wxYieldIfNeeded();
2105
2106 // Build the XyGrib DownloadURL from the current GUI configuration
2107 wxString requestUrl = BuildXyGribUrl();
2108
2109 // First we download the temporary XML file that will tell us where to
2110 // download the file on the server Downloading the XML triggers the
2111 // construction of the GRIB file on the server.
2112 wxString filename = wxString::Format("ocpn_xygrib_%s.xml",
2113 wxDateTime::Now().Format("%F-%H-%M"));
2114 wxString path = m_parent.GetGribDir();
2115 path << wxFileName::GetPathSeparator();
2116 path << filename;
2117 if (!m_connected) {
2118 m_connected = true;
2119 Connect(
2120 wxEVT_DOWNLOAD_EVENT,
2121 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2122 }
2123 auto res = OCPN_downloadFileBackground(requestUrl.c_str(), path, this,
2124 &m_download_handle);
2125
2126 // Wait for the file to be downloaded. Note that it can take some time because
2127 // server will not send it to us until the GRIB file is ready, or an error
2128 // occured.
2129 while (m_downloading) {
2130 wxTheApp->ProcessPendingEvents();
2131 wxMilliSleep(10);
2132 }
2133
2134 if ((m_canceled) || (!m_bTransferSuccess)) {
2135 // Something went wrong : publish error on GUI
2136 m_xygribPanel->m_status_text->SetLabelText(_("Grib request failed"));
2137 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2138 m_downloadType = GribDownloadType::NONE;
2139 EnableDownloadButtons();
2140 wxRemoveFile(path);
2141 return;
2142 }
2143
2144 // Read the XML file in a wxString
2145 wxFile xmlFile;
2146 wxString strXml;
2147 bool readOk = xmlFile.Open(path);
2148 if (readOk) {
2149 readOk &= xmlFile.ReadAll(&strXml);
2150 if (readOk) {
2151 xmlFile.Close();
2152 }
2153 }
2154
2155 // Quick and dirty read of the XML file to check status (OK/NOK)
2156 wxString url;
2157 if (readOk && (((int)strXml.find("\"status\":true") == wxNOT_FOUND))) {
2158 // Status is NOK : stop download and report error to GUI
2159 wxString errorStr;
2160 int errPos = strXml.find("\"message\":\"");
2161 int errEnd = strXml.find("\"}");
2162 if ((errPos != wxNOT_FOUND) && (errEnd != wxNOT_FOUND)) {
2163 errPos += 11;
2164 errorStr = strXml.Mid(errPos, errEnd - errPos);
2165 } else {
2166 errorStr = "Unknown server error";
2167 }
2168
2169 m_xygribPanel->m_status_text->SetLabelText(
2170 wxString::Format("%s (%s)", _("Server Error"), errorStr));
2171 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2172 m_downloadType = GribDownloadType::NONE;
2173 EnableDownloadButtons();
2174 wxRemoveFile(path);
2175 return;
2176 } else {
2177 // Extract GRIB URL from XML
2178 int urlPos = strXml.find("\"url\":\"http:");
2179 int urlEnd = strXml.find(".grb2\"");
2180 if ((urlPos != wxNOT_FOUND) && (urlEnd != wxNOT_FOUND)) {
2181 urlPos += 7;
2182 urlEnd += 5;
2183 url = strXml.Mid(urlPos, urlEnd - urlPos);
2184 url.Replace("\\/", "/");
2185 } else {
2186 readOk = false;
2187 }
2188 }
2189
2190 wxRemoveFile(path);
2191
2192 // Check if there was any error in the previous phase
2193 if (!readOk) {
2194 // Yes : stop download and report error to GUI
2195 m_xygribPanel->m_status_text->SetLabelText(
2196 _("Error parsing XML file from server"));
2197 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2198 m_downloadType = GribDownloadType::NONE;
2199 EnableDownloadButtons();
2200 return;
2201 }
2202
2203 m_xygribPanel->m_status_text->SetLabelText(_("Downloading GRIB file"));
2204
2205 // Build name of the GRIB file for disk storage
2206 path = m_parent.GetGribDir();
2207 path << wxFileName::GetPathSeparator();
2208 path << BuildGribFileName();
2209
2210 // Start download
2211 m_canceled = false;
2212 m_downloading = true;
2213 if (!m_connected) {
2214 m_connected = true;
2215 Connect(
2216 wxEVT_DOWNLOAD_EVENT,
2217 (wxObjectEventFunction)(wxEventFunction)&GribRequestSetting::onDLEvent);
2218 }
2219 res =
2220 OCPN_downloadFileBackground(url.c_str(), path, this, &m_download_handle);
2221 // Wait for end of download. Note that the previously registered callback
2222 // "onDLEvent" will update the progress indicator on the GUI.
2223 while (m_downloading) {
2224 wxTheApp->ProcessPendingEvents();
2225 wxMilliSleep(10);
2226 }
2227
2228 // Download finished : restore "Download" button
2229 m_xygribPanel->m_download_button->SetLabelText(_("Download"));
2230
2231 if (!m_canceled) {
2232 if (m_bTransferSuccess) {
2233 // Transfer successfull : switch to GRIB display on chart
2234 m_xygribPanel->m_status_text->SetLabelText(_("Download complete"));
2235 wxFileName fn(path);
2236 m_parent.m_grib_dir = fn.GetPath();
2237 m_parent.m_file_names.Clear();
2238 m_parent.m_file_names.Add(path);
2239 m_parent.OpenFile();
2240 if (m_parent.pPlugIn) {
2241 if (m_parent.pPlugIn->m_bZoomToCenterAtInit) m_parent.DoZoomToCenter();
2242 }
2243 m_parent.SetDialogsStyleSizePosition(true);
2244 SaveConfig();
2245 Close();
2246 } else {
2247 // Download failed : report error to GUI
2248 m_xygribPanel->m_status_text->SetLabelText(_("Download failed"));
2249 }
2250 }
2251 m_downloadType = GribDownloadType::NONE;
2252 EnableDownloadButtons();
2253}
2254
2259 AtmModelDef_t *selectedAtmModel = nullptr;
2260
2261 // Find the model descriptor associated to the selected atmospheric model
2262 wxString atmModel = m_xygribPanel->m_atmmodel_choice->GetStringSelection();
2263 int modelIndex = 0;
2264 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) != nullptr) {
2265 if (selectedAtmModel->name.IsSameAs(atmModel, true)) {
2266 break;
2267 }
2268 modelIndex++;
2269 }
2270
2271 // If not found, use the first one. This is not supposed to happen.
2272 if (selectedAtmModel == nullptr) {
2273 selectedAtmModel = xygribAtmModelList[0];
2274 modelIndex = 0;
2275 }
2276
2277 // Enable or disable parameters according to the model definition
2278 if (selectedAtmModel->wind)
2279 m_xygribPanel->m_wind_cbox->Enable();
2280 else
2281 m_xygribPanel->m_wind_cbox->Disable();
2282
2283 if (selectedAtmModel->gust)
2284 m_xygribPanel->m_gust_cbox->Enable();
2285 else
2286 m_xygribPanel->m_gust_cbox->Disable();
2287
2288 if (selectedAtmModel->pressure)
2289 m_xygribPanel->m_pressure_cbox->Enable();
2290 else
2291 m_xygribPanel->m_pressure_cbox->Disable();
2292
2293 if (selectedAtmModel->temperature)
2294 m_xygribPanel->m_temperature_cbox->Enable();
2295 else
2296 m_xygribPanel->m_temperature_cbox->Disable();
2297
2298 if (selectedAtmModel->cape)
2299 m_xygribPanel->m_cape_cbox->Enable();
2300 else
2301 m_xygribPanel->m_cape_cbox->Disable();
2302
2303 if (selectedAtmModel->reflectivity)
2304 m_xygribPanel->m_reflectivity_cbox->Enable();
2305 else
2306 m_xygribPanel->m_reflectivity_cbox->Disable();
2307
2308 if (selectedAtmModel->cloudCover)
2309 m_xygribPanel->m_cloudcover_cbox->Enable();
2310 else
2311 m_xygribPanel->m_cloudcover_cbox->Disable();
2312
2313 if (selectedAtmModel->precipitation)
2314 m_xygribPanel->m_precipitation_cbox->Enable();
2315 else
2316 m_xygribPanel->m_precipitation_cbox->Disable();
2317
2318 // Fill the resolution choice selection
2319 m_xygribPanel->m_resolution_choice->Clear();
2320 for (int i = 0; i < selectedAtmModel->nbRes; i++) {
2321 m_xygribPanel->m_resolution_choice->Insert(selectedAtmModel->resolution[i],
2322 i);
2323 }
2324
2325 // Fill the duration choice selection
2326 m_xygribPanel->m_duration_choice->Clear();
2327 for (int i = 0; i < selectedAtmModel->duration; i++) {
2328 m_xygribPanel->m_duration_choice->Insert(wxString::Format("%d", i + 1), i);
2329 }
2330
2331 // Fill the interval choice selection
2332 m_xygribPanel->m_interval_choice->Clear();
2333 for (int i = 0; i < selectedAtmModel->nbInterval; i++) {
2334 m_xygribPanel->m_interval_choice->Insert(
2335 wxString::Format("%dh", selectedAtmModel->interval[i]), i);
2336 }
2337
2338 // Fill the run choice selection
2339 m_xygribPanel->m_run_choice->Clear();
2340 if (selectedAtmModel->runMask == XYGRIB_RUN_0_12) {
2341 m_xygribPanel->m_run_choice->Insert("0h", 0);
2342 m_xygribPanel->m_run_choice->Insert("12h", 1);
2343 m_xygribPanel->m_run_choice->Insert(_("Latest"), 2);
2344 } else {
2345 m_xygribPanel->m_run_choice->Insert("0h", 0);
2346 m_xygribPanel->m_run_choice->Insert("6h", 1);
2347 m_xygribPanel->m_run_choice->Insert("12h", 2);
2348 m_xygribPanel->m_run_choice->Insert("18h", 3);
2349 m_xygribPanel->m_run_choice->Insert(_("Latest"), 4);
2350 }
2351
2352 if (modelIndex == m_parent.xyGribConfig.atmModelIndex) {
2353 ApplyXyGribConfiguration();
2354 } else {
2355 m_selectedAtmModelIndex = modelIndex;
2356 m_xygribPanel->m_resolution_choice->SetSelection(0);
2357 m_xygribPanel->m_duration_choice->SetSelection(
2358 m_xygribPanel->m_duration_choice->GetCount() - 1);
2359 m_xygribPanel->m_interval_choice->SetSelection(0);
2360 m_xygribPanel->m_run_choice->SetSelection(
2361 m_xygribPanel->m_run_choice->GetCount() - 1);
2362 }
2363 MemorizeXyGribConfiguration();
2364}
2365
2370 WaveModelDef_t *selectedModel = nullptr;
2371
2372 // Find the model descriptor associated to the selected wave model
2373 wxString waveModel = m_xygribPanel->m_wavemodel_choice->GetStringSelection();
2374 int modelIndex = 0;
2375 while ((selectedModel = xygribWaveModelList[modelIndex]) != nullptr) {
2376 if (selectedModel->name.IsSameAs(waveModel, true)) {
2377 break;
2378 }
2379 modelIndex++;
2380 }
2381
2382 // Model found in the table ?
2383 if (selectedModel == nullptr) {
2384 // If the model is not found in the table, disable wave model downloading
2385 m_selectedWaveModelIndex = -1;
2386 m_xygribPanel->m_waveheight_cbox->Disable();
2387 m_xygribPanel->m_windwave_cbox->Disable();
2388 MemorizeXyGribConfiguration();
2389 return;
2390 }
2391
2392 m_selectedWaveModelIndex = modelIndex;
2393
2394 // Else configure parameters according to model definition
2395 if (selectedModel->significantHeight) {
2396 m_xygribPanel->m_waveheight_cbox->Enable();
2397 } else {
2398 m_xygribPanel->m_waveheight_cbox->Disable();
2399 }
2400
2401 if (selectedModel->windWaves) {
2402 m_xygribPanel->m_windwave_cbox->Enable();
2403 } else {
2404 m_xygribPanel->m_windwave_cbox->Disable();
2405 }
2406 MemorizeXyGribConfiguration();
2407}
2408
2412void GribRequestSetting::OnXyGribConfigChange(wxCommandEvent &event) {
2413 MemorizeXyGribConfiguration();
2414}
2415
2417void GribRequestSetting::InitializeXygribDialog() {
2418 AtmModelDef_t *selectedAtmModel = nullptr;
2419 WaveModelDef_t *selectedWaveModel = nullptr;
2420
2421 // Fill selection of atmospheric models with the ones found in the model table
2422 m_xygribPanel->m_atmmodel_choice->Clear();
2423 int modelIndex = 0;
2424 while ((selectedAtmModel = xygribAtmModelList[modelIndex]) != nullptr) {
2425 m_xygribPanel->m_atmmodel_choice->Insert(selectedAtmModel->name,
2426 modelIndex);
2427 modelIndex++;
2428 }
2429 // Select the initial value from configuration
2430 m_selectedAtmModelIndex = m_parent.xyGribConfig.atmModelIndex;
2431 selectedAtmModel = xygribAtmModelList[m_selectedAtmModelIndex];
2432
2433 // Fill selection of wave models with the ones found in the table
2434 m_xygribPanel->m_wavemodel_choice->Clear();
2435 modelIndex = 0;
2436 while ((selectedWaveModel = xygribWaveModelList[modelIndex]) != nullptr) {
2437 m_xygribPanel->m_wavemodel_choice->Insert(selectedWaveModel->name,
2438 modelIndex);
2439 modelIndex++;
2440 }
2441 // Add the "None" selection
2442 m_xygribPanel->m_wavemodel_choice->Insert("None", modelIndex);
2443 m_selectedWaveModelIndex = m_parent.xyGribConfig.waveModelIndex;
2444 selectedWaveModel = xygribWaveModelList[m_selectedWaveModelIndex];
2445 if (selectedWaveModel == nullptr) {
2446 m_selectedWaveModelIndex = -1;
2447 }
2448
2449 // Fill the resolution choice selection
2450 m_xygribPanel->m_resolution_choice->Clear();
2451 for (int i = 0; i < selectedAtmModel->nbRes; i++) {
2452 m_xygribPanel->m_resolution_choice->Insert(selectedAtmModel->resolution[i],
2453 i);
2454 }
2455
2456 // Fill the duration choice selection
2457 m_xygribPanel->m_duration_choice->Clear();
2458 for (int i = 0; i < selectedAtmModel->duration; i++) {
2459 m_xygribPanel->m_duration_choice->Insert(wxString::Format("%d", i + 1), i);
2460 }
2461
2462 // Fill the interval choice selection
2463 m_xygribPanel->m_interval_choice->Clear();
2464 for (int i = 0; i < selectedAtmModel->nbInterval; i++) {
2465 m_xygribPanel->m_interval_choice->Insert(
2466 wxString::Format("%dh", selectedAtmModel->interval[i]), i);
2467 }
2468
2469 // Fill the run choice selection
2470 m_xygribPanel->m_run_choice->Clear();
2471 if (selectedAtmModel->runMask == XYGRIB_RUN_0_12) {
2472 m_xygribPanel->m_run_choice->Insert("0h", 0);
2473 m_xygribPanel->m_run_choice->Insert("12h", 1);
2474 m_xygribPanel->m_run_choice->Insert(_("Latest"), 2);
2475 } else {
2476 m_xygribPanel->m_run_choice->Insert("0h", 0);
2477 m_xygribPanel->m_run_choice->Insert("6h", 1);
2478 m_xygribPanel->m_run_choice->Insert("12h", 2);
2479 m_xygribPanel->m_run_choice->Insert("18h", 3);
2480 m_xygribPanel->m_run_choice->Insert(_("Latest"), 4);
2481 }
2482
2483 if (selectedAtmModel->wind)
2484 m_xygribPanel->m_wind_cbox->Enable();
2485 else
2486 m_xygribPanel->m_wind_cbox->Disable();
2487
2488 if (selectedAtmModel->gust)
2489 m_xygribPanel->m_gust_cbox->Enable();
2490 else
2491 m_xygribPanel->m_gust_cbox->Disable();
2492
2493 if (selectedAtmModel->pressure)
2494 m_xygribPanel->m_pressure_cbox->Enable();
2495 else
2496 m_xygribPanel->m_pressure_cbox->Disable();
2497
2498 if (selectedAtmModel->temperature)
2499 m_xygribPanel->m_temperature_cbox->Enable();
2500 else
2501 m_xygribPanel->m_temperature_cbox->Disable();
2502
2503 if (selectedAtmModel->cape)
2504 m_xygribPanel->m_cape_cbox->Enable();
2505 else
2506 m_xygribPanel->m_cape_cbox->Disable();
2507
2508 if (selectedAtmModel->reflectivity)
2509 m_xygribPanel->m_reflectivity_cbox->Enable();
2510 else
2511 m_xygribPanel->m_reflectivity_cbox->Disable();
2512
2513 if (selectedAtmModel->cloudCover)
2514 m_xygribPanel->m_cloudcover_cbox->Enable();
2515 else
2516 m_xygribPanel->m_cloudcover_cbox->Disable();
2517
2518 if (selectedAtmModel->precipitation)
2519 m_xygribPanel->m_precipitation_cbox->Enable();
2520 else
2521 m_xygribPanel->m_precipitation_cbox->Disable();
2522
2523 if ((selectedWaveModel != nullptr) && (selectedWaveModel->significantHeight))
2524 m_xygribPanel->m_waveheight_cbox->Enable();
2525 else
2526 m_xygribPanel->m_waveheight_cbox->Disable();
2527
2528 if ((selectedWaveModel != nullptr) && (selectedWaveModel->windWaves))
2529 m_xygribPanel->m_windwave_cbox->Enable();
2530 else
2531 m_xygribPanel->m_windwave_cbox->Disable();
2532
2533 ApplyXyGribConfiguration();
2534}
2535
2540void GribRequestSetting::ApplyXyGribConfiguration() {
2541 m_xygribPanel->m_atmmodel_choice->SetSelection(
2542 m_parent.xyGribConfig.atmModelIndex);
2543 m_xygribPanel->m_wavemodel_choice->SetSelection(
2544 m_parent.xyGribConfig.waveModelIndex);
2545
2546 m_xygribPanel->m_wind_cbox->SetValue(m_parent.xyGribConfig.wind);
2547 m_xygribPanel->m_gust_cbox->SetValue(m_parent.xyGribConfig.gust);
2548 m_xygribPanel->m_pressure_cbox->SetValue(m_parent.xyGribConfig.pressure);
2549 m_xygribPanel->m_temperature_cbox->SetValue(
2550 m_parent.xyGribConfig.temperature);
2551 m_xygribPanel->m_cape_cbox->SetValue(m_parent.xyGribConfig.cape);
2552 m_xygribPanel->m_reflectivity_cbox->SetValue(
2553 m_parent.xyGribConfig.reflectivity);
2554 m_xygribPanel->m_cloudcover_cbox->SetValue(m_parent.xyGribConfig.cloudCover);
2555 m_xygribPanel->m_precipitation_cbox->SetValue(
2556 m_parent.xyGribConfig.precipitation);
2557 m_xygribPanel->m_waveheight_cbox->SetValue(m_parent.xyGribConfig.waveHeight);
2558 m_xygribPanel->m_windwave_cbox->SetValue(m_parent.xyGribConfig.windWaves);
2559 m_xygribPanel->m_resolution_choice->SetSelection(
2560 m_parent.xyGribConfig.resolutionIndex);
2561 m_xygribPanel->m_duration_choice->SetSelection(
2562 m_parent.xyGribConfig.durationIndex);
2563 m_xygribPanel->m_interval_choice->SetSelection(
2564 m_parent.xyGribConfig.intervalIndex);
2565 m_xygribPanel->m_run_choice->SetSelection(m_parent.xyGribConfig.runIndex);
2566
2567 UpdateGribSizeEstimate();
2568}
2569
2574void GribRequestSetting::MemorizeXyGribConfiguration() {
2575 m_parent.xyGribConfig.atmModelIndex =
2576 m_xygribPanel->m_atmmodel_choice->GetSelection();
2577 m_parent.xyGribConfig.waveModelIndex =
2578 m_xygribPanel->m_wavemodel_choice->GetSelection();
2579
2580 m_parent.xyGribConfig.wind = m_xygribPanel->m_wind_cbox->IsChecked();
2581 m_parent.xyGribConfig.gust = m_xygribPanel->m_gust_cbox->IsChecked();
2582 m_parent.xyGribConfig.pressure = m_xygribPanel->m_pressure_cbox->IsChecked();
2583 m_parent.xyGribConfig.temperature =
2584 m_xygribPanel->m_temperature_cbox->IsChecked();
2585 m_parent.xyGribConfig.cape = m_xygribPanel->m_cape_cbox->IsChecked();
2586 m_parent.xyGribConfig.reflectivity =
2587 m_xygribPanel->m_reflectivity_cbox->IsChecked();
2588 m_parent.xyGribConfig.cloudCover =
2589 m_xygribPanel->m_cloudcover_cbox->IsChecked();
2590 m_parent.xyGribConfig.precipitation =
2591 m_xygribPanel->m_precipitation_cbox->IsChecked();
2592 m_parent.xyGribConfig.waveHeight =
2593 m_xygribPanel->m_waveheight_cbox->IsChecked();
2594 m_parent.xyGribConfig.windWaves = m_xygribPanel->m_windwave_cbox->IsChecked();
2595
2596 m_parent.xyGribConfig.resolutionIndex =
2597 m_xygribPanel->m_resolution_choice->GetSelection();
2598 m_parent.xyGribConfig.durationIndex =
2599 m_xygribPanel->m_duration_choice->GetSelection();
2600 m_parent.xyGribConfig.intervalIndex =
2601 m_xygribPanel->m_interval_choice->GetSelection();
2602 m_parent.xyGribConfig.runIndex = m_xygribPanel->m_run_choice->GetSelection();
2603
2604 UpdateGribSizeEstimate();
2605}
2606
2610void GribRequestSetting::UpdateGribSizeEstimate() {
2611 double resolution;
2612 long days;
2613 long interval;
2614
2615 if (!m_xygribPanel->m_resolution_choice->GetStringSelection().ToCDouble(
2616 &resolution)) {
2617 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2618 return;
2619 }
2620 if (!m_xygribPanel->m_duration_choice->GetStringSelection().ToCLong(&days)) {
2621 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2622 return;
2623 }
2624 wxString intvStr = m_xygribPanel->m_interval_choice->GetStringSelection();
2625 intvStr.Replace("h", "");
2626 if (!intvStr.ToCLong(&interval)) {
2627 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2628 return;
2629 }
2630
2631 if (m_VpFocus == nullptr) {
2632 m_xygribPanel->m_sizeestimate_text->SetLabel("Unknown");
2633 return;
2634 }
2635
2636 double xmax = GetMaxLon();
2637 double xmin = GetMinLon();
2638 double ymax = GetMaxLat();
2639 double ymin = GetMinLat();
2640
2641 int npts = (int)(ceil(fabs(xmax - xmin) / resolution) *
2642 ceil(fabs(ymax - ymin) / resolution));
2643
2644 // Number of GribRecords
2645 int nbrec = (int)days * 24 / interval + 1;
2646
2647 int nbPress = (m_xygribPanel->m_pressure_cbox->IsChecked() &&
2648 m_xygribPanel->m_pressure_cbox->IsEnabled())
2649 ? nbrec
2650 : 0;
2651 int nbWind = (m_xygribPanel->m_wind_cbox->IsChecked() &&
2652 m_xygribPanel->m_wind_cbox->IsEnabled())
2653 ? 2 * nbrec
2654 : 0;
2655 int nbRain = (m_xygribPanel->m_precipitation_cbox->IsChecked() &&
2656 m_xygribPanel->m_precipitation_cbox->IsEnabled())
2657 ? nbrec - 1
2658 : 0;
2659 int nbCloud = (m_xygribPanel->m_cloudcover_cbox->IsChecked() &&
2660 m_xygribPanel->m_cloudcover_cbox->IsEnabled())
2661 ? nbrec - 1
2662 : 0;
2663 int nbTemp = (m_xygribPanel->m_temperature_cbox->IsChecked() &&
2664 m_xygribPanel->m_temperature_cbox->IsEnabled())
2665 ? nbrec
2666 : 0;
2667
2668 int nbCAPEsfc = (m_xygribPanel->m_cape_cbox->IsChecked() &&
2669 m_xygribPanel->m_cape_cbox->IsEnabled())
2670 ? nbrec
2671 : 0;
2672 int nbReflectivity = (m_xygribPanel->m_reflectivity_cbox->IsChecked() &&
2673 m_xygribPanel->m_reflectivity_cbox->IsEnabled())
2674 ? nbrec
2675 : 0;
2676 int nbGUSTsfc = (m_xygribPanel->m_gust_cbox->IsChecked() &&
2677 m_xygribPanel->m_gust_cbox->IsEnabled())
2678 ? nbrec
2679 : 0;
2680
2681 int head = 179;
2682 int estimate = 0;
2683 int nbits; // this can vary when c3 packing is used. Average numbers are used
2684 // here
2685
2686 nbits = 12;
2687 estimate += nbWind * (head + (nbits * npts) / 8 + 2);
2688
2689 nbits = 9;
2690 estimate += nbTemp * (head + (nbits * npts) / 8 + 2);
2691
2692 // estime += nbTempMin*(head+(nbits*npts)/8+2 );
2693 // estime += nbTempMax*(head+(nbits*npts)/8+2 );
2694
2695 nbits = 9;
2696 estimate += nbRain * (head + 24 + (nbits * npts) / 8 + 2);
2697
2698 nbits = 14;
2699 estimate += nbPress * (head + (nbits * npts) / 8 + 2);
2700
2701 nbits = 7;
2702 estimate += nbCloud * (head + 24 + (nbits * npts) / 8 + 2);
2703
2704 nbits = 11;
2705 estimate += nbReflectivity * (head + (nbits * npts) / 8 + 2);
2706
2707 nbits = 12;
2708 estimate += nbCAPEsfc * (head + (nbits * npts) / 8 + 2);
2709
2710 nbits = 9;
2711 estimate += nbGUSTsfc * (head + (nbits * npts) / 8 + 2);
2712 // estime += nbSUNSDsfc*(head+(nbits*npts)/8+2 );
2713
2714 // keep a record of the atmosphere estimate. if 0 nothing was selected
2715 int atmEstimate = estimate;
2716
2717 // and now the wave estimate
2718 // recalculate number of points based on which model is used
2719 if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2720 "WW3")) // 0.5 deg
2721 {
2722 npts = (int)(ceil(fabs(xmax - xmin) / 0.5) * ceil(fabs(ymax - ymin) / 0.5));
2723 nbrec = (int)fmin(8, days) * 24 / interval + 1;
2724 } else if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2725 "GWAM")) // 0.25 deg
2726 {
2727 npts =
2728 (int)(ceil(fabs(xmax - xmin) / 0.25) * ceil(fabs(ymax - ymin) / 0.25));
2729 nbrec = (int)fmin(8, days) * 24 / interval + 1;
2730 } else if (m_xygribPanel->m_wavemodel_choice->GetStringSelection().IsSameAs(
2731 "EWAM")) // 0.1 x 0.05 deg
2732 {
2733 npts =
2734 (int)(ceil(fabs(xmax - xmin) / 0.05) * ceil(fabs(ymax - ymin) / 0.1));
2735 nbrec = (int)fmin(4, days) * 24 / interval + 1;
2736 } else {
2737 npts = 0;
2738 nbrec = 0;
2739 }
2740
2741 if (m_xygribPanel->m_waveheight_cbox->IsChecked()) {
2742 nbits = 9;
2743 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2744 }
2745
2746 if (m_xygribPanel->m_windwave_cbox->IsChecked()) {
2747 nbits = 15;
2748 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2749 nbits = 8;
2750 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2751 nbits = 10;
2752 estimate += nbrec * (head + (nbits * npts) / 8 + 2);
2753 }
2754
2755 int wavEstimate = estimate - atmEstimate;
2756 // reduce wave estimate due to land overlapping by average of 40%
2757 wavEstimate = wavEstimate * 0.6;
2758 // now adjusted estimate is
2759 estimate = atmEstimate + wavEstimate;
2760
2761 // adjust for packing ~ 65%
2762 estimate = estimate * 0.65;
2763
2764 wxString warningStr = "";
2765 if (estimate / (1024 * 1024) > XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB) {
2766 warningStr = wxString::Format("(Warning GRIB exceeds %d MB limit)",
2767 XYGRIB_MAX_DOWNLOADABLE_GRIB_SIZE_MB);
2768 }
2769
2770 m_xygribPanel->m_sizeestimate_text->SetLabel(
2771 wxString::Format("%d kB %s", estimate / 1024, warningStr));
2772
2773 m_gribSizeEstimate = estimate;
2774}
2775
2777 if (m_rbManualSelect && m_rbManualSelect->GetValue()) {
2778 return m_spMinLat->GetValue();
2779 }
2780 return m_VpFocus->lat_min;
2781}
2782
2784 if (m_rbManualSelect && m_rbManualSelect->GetValue()) {
2785 return m_spMaxLat->GetValue();
2786 }
2787 return m_VpFocus->lat_max;
2788}
2789
2791 if (m_rbManualSelect && m_rbManualSelect->GetValue()) {
2792 return m_spMinLon->GetValue();
2793 }
2794 return m_VpFocus->lon_min;
2795}
2796
2798 if (m_rbManualSelect && m_rbManualSelect->GetValue()) {
2799 return m_spMaxLon->GetValue();
2800 }
2801 return m_VpFocus->lon_max;
2802}
void SetRequestButtonBitmap(int type)
Set the icon and tooltip for the download request button.
GribPi * pPlugIn
Plugin instance that owns this control bar.
wxString m_grib_dir
Directory containing GRIB files.
wxArrayString m_file_names
List of GRIB filenames being displayed.
Class GribRequestSettingBase.
wxButton * m_rButtonCancel
Button to Cancel a request to download, close the dialog without saving the configuration.
wxSpinCtrl * m_spMaxLon
A spinner for the max longitude of the bounding box for downloads.
wxSpinCtrl * m_spMaxLat
A spinner for the max latitude of the bounding box for downloads.
wxRadioButton * m_rbManualSelect
Radio button selected to indicate the download area is based on the area selected by the user.
wxRadioButton * m_rbCurrentView
Radio button selected to indicate the download area is based on the visible area of the chart in the ...
wxSpinCtrl * m_spMinLat
A spinner for the min latitude of the bounding box for downloads.
wxButton * m_rButtonApply
Button to Save the "download request" configuration.
wxButton * m_rButtonYes
Button to Send a download request through e-mail.
wxSpinCtrl * m_spMinLon
A spinner for the min longitude of the bounding box for downloads.
Manages GRIB file request configuration and downloads.
double m_StartLat
The latitude at the starting point of the bounding box.
void OnXyGribWaveModelChoice(wxCommandEvent &event) override
Handle action of changing wave model selection.
void OnSendMaiL(wxCommandEvent &event) override
Callback invoked when the user clicks the "Send" button in the "e-mail" tab.
double GetMinLat() const
Get the minimum latitude of the bounding box for the download request.
double GetMaxLat() const
Get the maximum latitude of the bounding box for the download request.
double m_Lat
The latitude at the mouse cursor while drawing a bounding box.
void OnVpUnderMouseChange(PlugIn_ViewPort *vp)
Callback invoked when the view port under mouse has changed.
bool RenderGlZoneOverlay()
Renders the GRIB area selection overlay using OpenGL.
bool RenderZoneOverlay(wxDC &dc)
Renders the GRIB area selection overlay using standard device context.
double m_Lon
The longitude at the mouse cursor while drawing a bounding box.
void OnXyGribAtmModelChoice(wxCommandEvent &event) override
Handle action of changing atmospheric model selection.
wxPoint m_StartPoint
Starting point of the bounding box in physical pixels.
bool DoRenderZoneOverlay()
Draws the GRIB area selection overlay on the chart.
bool MouseEventHook(wxMouseEvent &event)
Intercepts mouse events to handle GRIB area selection.
void OnVpWithFocusChange(PlugIn_ViewPort *vp)
Callback invoked when the focused view port has changed, such as in multi-chart mode when user switch...
PlugIn_ViewPort * m_VpMouse
The viewport under the mouse.
ZoneSelectionRenderState m_RenderSelectionZoneState
Current state of the bounding box overlay rendering.
void OnXyGribConfigChange(wxCommandEvent &event) override
Handle action of changing a GRIB configuration parameter.
double GetMaxLon() const
Get the maximum longitude of the bounding box for the download request.
PlugIn_ViewPort * m_VpFocus
The viewport currently in focus.
double m_StartLon
The longitude at the starting point of the bounding box.
double GetMinLon() const
Get the minimum longitude of the bounding box for the download request.
void OnOK(wxCommandEvent &event) override
Callback invoked when the user clicks the "OK" button in the "download" dialog.
Contains view parameters and status information for a chart display viewport.
double lon_max
Maximum longitude of the viewport.
double lat_max
Maximum latitude of the viewport.
double lon_min
Minimum longitude of the viewport.
double lat_min
Minimum latitude of the viewport.
The JSON parser.
Definition jsonreader.h:45
int Parse(const wxString &doc, wxJSONValue *val)
Parse the JSON document.
The JSON value class implementation.
Definition jsonval.h:79
int Size() const
Return the size of the array or map stored in this value.
Definition jsonval.cpp:1333
bool HasMember(unsigned index) const
Return TRUE if the object contains an element at the specified index.
Definition jsonval.cpp:1299
wxString AsString() const
Return the stored value as a wxWidget's string.
Definition jsonval.cpp:875
Email Request System for GRIB Data.
GRIB Data Visualization and Rendering Factory.
GRIB Weather Data Plugin for OpenCPN.
int m_SavedZoneSelMode
Persisted version of the GRIB area selection mode.
int m_ZoneSelMode
Tracks the current state of GRIB area selection for zone coordinates.
GRIB Weather Data 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.
@ AUTO_SELECTION
Area automatically set from current viewport bounds.
Definition grib_ui_dlg.h:87
@ DRAW_SELECTION
Manual mode has been selected.
@ START_SELECTION
User has clicked Shift + Left click and is drawing the bounding box by dragging the mouse.
Definition grib_ui_dlg.h:93
@ COMPLETE_SELECTION
Selection box completed in manual mode, coordinates have been captured after the user has released th...
@ SAVED_SELECTION
Area loaded from previously saved coordinates.
Definition grib_ui_dlg.h:88
#define SAVEDZONE
Save zone.
#define MANSELECT
Manual selection mode.
#define AUTOSELECT
Automatic selection mode.
@ OCPN_DL_EVENT_TYPE_PROGRESS
Download progress update.
@ OCPN_DL_EVENT_TYPE_END
Download has completed.
@ OCPN_DL_NO_ERROR
Download completed successfully.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
wxFileConfig * GetOCPNConfigObject()
Gets OpenCPN's configuration object.
void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
Converts lat/lon to canvas physical pixel coordinates.
void DimeWindow(wxWindow *win)
Applies system color scheme to window.
int GetCanvasIndexUnderMouse()
Gets index of chart canvas under mouse cursor.
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.
void RequestRefresh(wxWindow *win)
Requests window refresh.
void GetCanvasLLPix(PlugIn_ViewPort *vp, wxPoint p, double *plat, double *plon)
Converts canvas physical pixel coordinates to lat/lon.
OpenGL Platform Abstraction Layer.
void OCPN_cancelDownloadFileBackground(long handle)
Cancels a background download.
int OCPNMessageBox_PlugIn(wxWindow *parent, const wxString &message, const wxString &caption, int style, int x, int y)
Shows a message box dialog.
_OCPN_DLStatus OCPN_downloadFileBackground(const wxString &url, const wxString &outputFile, wxEvtHandler *handler, long *handle)
Asynchronously downloads a file in the background.
XyGrib Model Configuration and Definitions.