1 /******************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: GRIB Object
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 ***************************************************************************
25 *
26 */
27
28 #include "wx/wx.h"
29 #include "wx/tokenzr.h"
30 #include "wx/datetime.h"
31 #include "wx/sound.h"
32 #include <wx/wfstream.h>
33 #include <wx/dir.h>
34 #include <wx/filename.h>
35 #include <wx/debug.h>
36 #include <wx/graphics.h>
37 #include <wx/regex.h>
38
39 #include <wx/stdpaths.h>
40
41 #include <stdlib.h>
42 #include <math.h>
43 #include <time.h>
44
45 #include "grib_pi.h"
46 #include "GribTable.h"
47 #include "email.h"
48 #include "folder.xpm"
49 #include "GribUIDialog.h"
50 #include <wx/arrimpl.cpp>
51
52 //general variables
53 double m_cursor_lat, m_cursor_lon;
54 int m_Altitude;
55 int m_DialogStyle;
56 int m_SavedZoneSelMode;
57 int m_ZoneSelMode;
58
59 #ifdef __MSVC__
60 #if _MSC_VER < 1700
round(double x)61 int round (double x) {
62 int i = (int) x;
63 if (x >= 0.0) {
64 return ((x-i) >= 0.5) ? (i + 1) : (i);
65 } else {
66 return (-x+i >= 0.5) ? (i - 1) : (i);
67 }
68 }
69 #endif
70 #endif
71
72 #ifdef __WXQT__
73 #include "qdebug.h"
74 #endif
75
76 #if wxCHECK_VERSION(2,9,4) /* to work with wx 2.8 */
77 #define SetBitmapLabelLabel SetBitmap
78 #endif
79
80
81 #define DEFAULT_STYLE = wxCAPTION|wxCLOSE_BOX|wxSYSTEM_MENU|wxTAB_TRAVERSAL
82
83 WX_DEFINE_OBJARRAY( ArrayOfGribRecordSets );
84
85 // Sort compare function for File Modification Time
CompareFileStringTime(const wxString & first,const wxString & second)86 static int CompareFileStringTime( const wxString& first, const wxString& second )
87 {
88 wxFileName f( first );
89 wxFileName s( second );
90 wxTimeSpan sp = s.GetModificationTime() - f.GetModificationTime();
91 return sp.GetMinutes();
92
93 // return ::wxFileModificationTime(first) - ::wxFileModificationTime(second);
94 }
95
96 //date/time in the desired time zone format
TToString(const wxDateTime date_time,const int time_zone)97 static wxString TToString( const wxDateTime date_time, const int time_zone )
98 {
99 wxDateTime t( date_time );
100 switch( time_zone ) {
101 case 0:
102 if( (wxDateTime::Now() == (wxDateTime::Now().ToGMT())) && t.IsDST() ) //bug in wxWingets 3.0 for UTC meridien ?
103 t.Add( wxTimeSpan( 1, 0, 0, 0 ) );
104 return t.Format( _T(" %a %d-%b-%Y %H:%M "), wxDateTime::Local ) + _T("LOC");
105 case 1:
106 default: return t.Format( _T(" %a %d-%b-%Y %H:%M "), wxDateTime::UTC ) + _T("UTC");
107 }
108 }
109
GetGRIBCanvas()110 wxWindow *GetGRIBCanvas()
111 {
112 wxWindow *wx;
113 // If multicanvas are active, render the overlay on the right canvas only
114 if(GetCanvasCount() > 1) // multi?
115 wx = GetCanvasByIndex(1);
116 else
117 wx = GetOCPNCanvasWindow();
118 return wx;
119 }
120
121 //---------------------------------------------------------------------------------------
122 // GRIB Control Implementation
123 //---------------------------------------------------------------------------------------
124 /* interpolating constructor
125 as a possible optimization, write this function to also
126 take latitude longitude boundaries so the resulting record can be
127 a subset of the input, but also would need to be recomputed when panning the screen */
GribTimelineRecordSet(unsigned int cnt)128 GribTimelineRecordSet::GribTimelineRecordSet(unsigned int cnt): GribRecordSet(cnt)
129 {
130 for(int i=0; i<Idx_COUNT; i++)
131 m_IsobarArray[i] = NULL;
132 }
133
~GribTimelineRecordSet()134 GribTimelineRecordSet::~GribTimelineRecordSet()
135 {
136 // RemoveGribRecords();
137 ClearCachedData();
138 }
139
ClearCachedData()140 void GribTimelineRecordSet::ClearCachedData()
141 {
142 for(int i=0; i<Idx_COUNT; i++) {
143 if(m_IsobarArray[i]) {
144 // Clear out the cached isobars
145 for( unsigned int j = 0; j < m_IsobarArray[i]->GetCount(); j++ ) {
146 IsoLine *piso = (IsoLine *) m_IsobarArray[i]->Item( j );
147 delete piso;
148 }
149 delete m_IsobarArray[i];
150 m_IsobarArray[i] = NULL;
151 }
152 }
153 }
154
155 //---------------------------------------------------------------------------------------
156 // GRIB CtrlBar Implementation
157 //---------------------------------------------------------------------------------------
158
GRIBUICtrlBar(wxWindow * parent,wxWindowID id,const wxString & title,const wxPoint & pos,const wxSize & size,long style,grib_pi * ppi)159 GRIBUICtrlBar::GRIBUICtrlBar(wxWindow *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ,grib_pi *ppi )
160 : GRIBUICtrlBarBase(parent, id, title, pos, size, style )
161 {
162 pParent = parent;
163 pPlugIn = ppi;
164 m_vp = 0;
165 pReq_Dialog = NULL;
166 m_bGRIBActiveFile = NULL;
167 m_pTimelineSet = NULL;
168 m_gCursorData = NULL;
169 m_gGRIBUICData = NULL;
170 wxFileConfig *pConf = GetOCPNConfigObject();
171
172 m_gGrabber = new GribGrabberWin( this ); //add the grabber to the dialog
173 m_fgCtrlGrabberSize->Add( m_gGrabber, 0, wxALL, 0 );
174
175 this->SetSizer( m_fgCtrlBarSizer );
176 this->Layout();
177 m_fgCtrlBarSizer->Fit( this );
178
179
180 if(pConf) {
181 pConf->SetPath ( _T ( "/Settings/GRIB" ) );
182 pConf->Read( _T ( "WindPlot" ), &m_bDataPlot[GribOverlaySettings::WIND], true );
183 pConf->Read( _T ( "WindGustPlot" ), &m_bDataPlot[GribOverlaySettings::WIND_GUST], false );
184 pConf->Read( _T ( "PressurePlot" ), &m_bDataPlot[GribOverlaySettings::PRESSURE], false );
185 pConf->Read( _T ( "WavePlot" ), &m_bDataPlot[GribOverlaySettings::WAVE], false );
186 pConf->Read( _T ( "CurrentPlot" ), &m_bDataPlot[GribOverlaySettings::CURRENT], false );
187 pConf->Read( _T ( "PrecipitationPlot" ), &m_bDataPlot[GribOverlaySettings::PRECIPITATION], false );
188 pConf->Read( _T ( "CloudPlot" ), &m_bDataPlot[GribOverlaySettings::CLOUD], false );
189 pConf->Read( _T ( "AirTemperaturePlot" ), &m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE], false );
190 pConf->Read( _T ( "SeaTemperaturePlot" ), &m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE], false );
191 pConf->Read( _T ( "CAPEPlot" ), &m_bDataPlot[GribOverlaySettings::CAPE], false );
192 pConf->Read( _T ( "CompReflectivityPlot" ), &m_bDataPlot[GribOverlaySettings::COMP_REFL], false );
193
194 pConf->Read( _T ( "CursorDataShown" ), &m_CDataIsShown, true );
195
196 pConf->Read ( _T ( "lastdatatype" ), &m_lastdatatype, 0);
197
198 pConf->SetPath ( _T ( "/Settings/GRIB/FileNames" ) );
199 m_file_names.Clear();
200 if( pConf->GetNumberOfEntries() ) {
201 wxString str, val;
202 long dummy;
203 bool bCont = pConf->GetFirstEntry( str, dummy );
204 while( bCont ) {
205 pConf->Read( str, &val ); // Get a file name
206 m_file_names.Add(val);
207 bCont = pConf->GetNextEntry( str, dummy );
208 }
209 }
210
211 wxStandardPathsBase& spath = wxStandardPaths::Get();
212
213 pConf->SetPath ( _T ( "/Directories" ) );
214 pConf->Read ( _T ( "GRIBDirectory" ), &m_grib_dir, spath.GetDocumentsDir() );
215
216 pConf->SetPath ( _T( "/PlugIns/GRIB" ) );
217 pConf->Read ( _T( "ManualRequestZoneSizing" ), &m_SavedZoneSelMode, 0 );
218 }
219 //init zone selection parameters
220 m_ZoneSelMode = m_SavedZoneSelMode;
221
222 //connect Timer
223 m_tPlayStop.Connect(wxEVT_TIMER, wxTimerEventHandler( GRIBUICtrlBar::OnPlayStopTimer ), NULL, this);
224 //connect functions
225 Connect( wxEVT_MOVE, wxMoveEventHandler( GRIBUICtrlBar::OnMove ) );
226
227 m_OverlaySettings.Read();
228
229 DimeWindow( this );
230
231 Fit();
232 SetMinSize( GetBestSize() );
233
234 }
235
~GRIBUICtrlBar()236 GRIBUICtrlBar::~GRIBUICtrlBar()
237 {
238 wxFileConfig *pConf = GetOCPNConfigObject();;
239
240 if(pConf) {
241 pConf->SetPath ( _T ( "/Settings/GRIB" ) );
242 pConf->Write( _T ( "WindPlot" ), m_bDataPlot[GribOverlaySettings::WIND]);
243 pConf->Write( _T ( "WindGustPlot" ), m_bDataPlot[GribOverlaySettings::WIND_GUST]);
244 pConf->Write( _T ( "PressurePlot" ), m_bDataPlot[GribOverlaySettings::PRESSURE]);
245 pConf->Write( _T ( "WavePlot" ), m_bDataPlot[GribOverlaySettings::WAVE]);
246 pConf->Write( _T ( "CurrentPlot" ), m_bDataPlot[GribOverlaySettings::CURRENT]);
247 pConf->Write( _T ( "PrecipitationPlot" ), m_bDataPlot[GribOverlaySettings::PRECIPITATION]);
248 pConf->Write( _T ( "CloudPlot" ), m_bDataPlot[GribOverlaySettings::CLOUD]);
249 pConf->Write( _T ( "AirTemperaturePlot" ), m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE]);
250 pConf->Write( _T ( "SeaTemperaturePlot" ), m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE]);
251 pConf->Write( _T ( "CAPEPlot" ), m_bDataPlot[GribOverlaySettings::CAPE]);
252 pConf->Write( _T ( "CompReflectivityPlot" ), m_bDataPlot[GribOverlaySettings::COMP_REFL]);
253
254 pConf->Write( _T ( "CursorDataShown" ), m_CDataIsShown );
255
256 pConf->Write( _T ( "lastdatatype" ), m_lastdatatype);
257
258 pConf->SetPath ( _T ( "/Settings/GRIB/FileNames" ) );
259 int iFileMax = pConf->GetNumberOfEntries();
260 if ( iFileMax ) {
261 wxString key;
262 long dummy;
263 for( int i = 0; i < iFileMax; i++ ) {
264 if (pConf->GetFirstEntry( key, dummy ))
265 pConf->DeleteEntry( key, false );
266 }
267 }
268
269 for( unsigned int i = 0 ; i < m_file_names.GetCount() ; i++ ) {
270 wxString key;
271 key.Printf(_T("Filename%d"), i);
272 pConf->Write ( key, m_file_names[i] );
273 }
274
275 pConf->SetPath ( _T ( "/Directories" ) );
276 pConf->Write ( _T ( "GRIBDirectory" ), m_grib_dir );
277 }
278 delete m_vp;
279 delete m_pTimelineSet;
280 }
281
GetScaledBitmap(wxBitmap bitmap,const wxString svgFileName,double scale_factor)282 wxBitmap GRIBUICtrlBar::GetScaledBitmap(wxBitmap bitmap, const wxString svgFileName, double scale_factor)
283 {
284 int margin = 4; //there is a small margin around the bitmap drawn by the wxBitmapButton
285 int w = bitmap.GetWidth() - margin;
286 int h = bitmap.GetHeight() - margin;
287 w *= scale_factor;
288 h *= scale_factor;
289
290 #ifdef ocpnUSE_SVG
291 wxString shareLocn = *GetpSharedDataLocation() +
292 _T("plugins") + wxFileName::GetPathSeparator() +
293 _T("grib_pi") + wxFileName::GetPathSeparator()
294 + _T("data") + wxFileName::GetPathSeparator();
295 wxString filename = shareLocn + svgFileName + _T(".svg");
296
297 wxBitmap svgbm = GetBitmapFromSVGFile(filename, w, h);
298 if(svgbm.GetWidth() > 0 && svgbm.GetHeight() > 0)
299 return svgbm;
300 else
301 #endif // ocpnUSE_SVG
302 {
303 wxImage a = bitmap.ConvertToImage();
304 return wxBitmap(a.Scale(w, h), wxIMAGE_QUALITY_HIGH);
305 }
306 }
307
SetScaledBitmap(double factor)308 void GRIBUICtrlBar::SetScaledBitmap( double factor )
309 {
310 // Round to the nearest "quarter", to avoid rendering artifacts
311 m_ScaledFactor = wxRound(factor * 4.0) / 4.0;
312 //set buttons bitmap
313 m_bpPrev->SetBitmapLabel(GetScaledBitmap(wxBitmap(prev), _T("prev"), m_ScaledFactor));
314 m_bpNext->SetBitmapLabel(GetScaledBitmap(wxBitmap(next), _T("next"), m_ScaledFactor));
315 m_bpAltitude->SetBitmapLabel(GetScaledBitmap(wxBitmap(altitude), _T("altitude"), m_ScaledFactor));
316 m_bpNow->SetBitmapLabel(GetScaledBitmap(wxBitmap(now), _T("now"), m_ScaledFactor));
317 m_bpZoomToCenter->SetBitmapLabel(GetScaledBitmap(wxBitmap(zoomto), _T("zoomto"), m_ScaledFactor));
318 m_bpPlay->SetBitmapLabel(GetScaledBitmap(wxBitmap(play), _T("play"), m_ScaledFactor));
319 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
320 m_CDataIsShown ? _T("curdata") : _T("ncurdata"), m_ScaledFactor));
321 if(m_bpOpenFile)
322 m_bpOpenFile->SetBitmapLabel(GetScaledBitmap(wxBitmap(openfile), _T("openfile"), m_ScaledFactor));
323 m_bpSettings->SetBitmapLabel(GetScaledBitmap(wxBitmap(setting), _T("setting"), m_ScaledFactor));
324
325 SetRequestBitmap( m_ZoneSelMode );
326
327 // Careful here, this MinSize() sets the final width of the control bar, overriding the width of the wxChoice above it.
328 #ifdef __OCPN__ANDROID__
329 m_sTimeline->SetSize( wxSize( 20 * m_ScaledFactor , -1 ) );
330 m_sTimeline->SetMinSize( wxSize( 20 * m_ScaledFactor , -1 ) );
331 #else
332 m_sTimeline->SetSize( wxSize( 90 * m_ScaledFactor , -1 ) );
333 m_sTimeline->SetMinSize( wxSize( 90 * m_ScaledFactor , -1 ) );
334 #endif
335
336 }
337
SetRequestBitmap(int type)338 void GRIBUICtrlBar::SetRequestBitmap( int type )
339 {
340 if(NULL == m_bpRequest)
341 return;
342
343 switch( type ) {
344 case AUTO_SELECTION:
345 case SAVED_SELECTION:
346 case START_SELECTION:
347 m_bpRequest->SetBitmapLabel(GetScaledBitmap(wxBitmap(request), _T("request"), m_ScaledFactor));
348 m_bpRequest->SetToolTip(_("Start a request"));
349 break;
350 case DRAW_SELECTION:
351 m_bpRequest->SetBitmapLabel(GetScaledBitmap(wxBitmap(selzone), _T("selzone"),m_ScaledFactor));
352 m_bpRequest->SetToolTip(_("Draw requested Area\nor Click here to stop request"));
353 break;
354 case COMPLETE_SELECTION:
355 m_bpRequest->SetBitmapLabel(GetScaledBitmap(wxBitmap(request_end), _T("request_end"), m_ScaledFactor));
356 m_bpRequest->SetToolTip(_("Valid Area and Continue"));
357 break;
358 }
359 }
360
OpenFile(bool newestFile)361 void GRIBUICtrlBar::OpenFile(bool newestFile)
362 {
363 m_bpPlay->SetBitmapLabel(GetScaledBitmap(wxBitmap(play), _T("play"), m_ScaledFactor));
364 m_cRecordForecast->Clear();
365 pPlugIn->GetGRIBOverlayFactory()->ClearParticles();
366 m_Altitude = 0;
367 m_FileIntervalIndex = m_OverlaySettings.m_SlicesPerUpdate;
368 delete m_bGRIBActiveFile;
369 delete m_pTimelineSet;
370 m_pTimelineSet = NULL;
371 m_sTimeline->SetValue(0);
372 m_TimeLineHours = 0;
373 m_InterpolateMode = false;
374 m_pNowMode = false;
375 m_SelectionIsSaved = false;
376 m_HasAltitude = false;
377
378 //get more recent file in default directory if necessary
379 wxFileName f;
380 if( newestFile )
381 m_file_names.Clear(); //file names list must be cleared if we expect only the newest file! otherwise newest file is
382 //added to the previously recorded, what we don't want
383 if( m_file_names.IsEmpty() ) { //in any case were there is no filename previously recorded, we must take the newest
384 m_file_names = GetFilesInDirectory();
385 newestFile = true;
386 }
387
388 m_bGRIBActiveFile = new GRIBFile( m_file_names,
389 pPlugIn->GetCopyFirstCumRec(),
390 pPlugIn->GetCopyMissWaveRec(),
391 newestFile );
392
393 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
394 wxString title;
395
396 if( m_bGRIBActiveFile->IsOK() ) {
397 wxFileName fn( m_bGRIBActiveFile->GetFileNames()[0] );
398 title = ( _("File: ") );
399 title.Append( fn.GetFullName() );
400 if( rsa->GetCount() == 0 ) { //valid but empty file
401 delete m_bGRIBActiveFile;
402 m_bGRIBActiveFile = NULL;
403 title.Prepend( _("Error! ") ).Append( _(" contains no valid data!") );
404 } else {
405 PopulateComboDataList();
406 title.append( _T(" (") + TToString( m_bGRIBActiveFile->GetRefDateTime(), pPlugIn->GetTimeZone()) + _T(" )"));
407
408 if( rsa->GetCount() > 1 ) {
409 GribRecordSet &first=rsa->Item(0), &second = rsa->Item(1), &last = rsa->Item(rsa->GetCount()-1);
410
411 //compute ntotal time span
412 wxTimeSpan span = wxDateTime(last.m_Reference_Time) - wxDateTime(first.m_Reference_Time);
413 m_TimeLineHours = span.GetHours();
414
415 //get file interval index and update intervale choice if necessary
416 int halfintermin(wxTimeSpan(wxDateTime(second.m_Reference_Time) - wxDateTime(first.m_Reference_Time)).GetMinutes() / 2);
417 for( m_FileIntervalIndex = 0;; m_FileIntervalIndex++){
418 if(m_OverlaySettings.GetMinFromIndex(m_FileIntervalIndex) > halfintermin) break;
419 }
420 if (m_FileIntervalIndex > 0)
421 m_FileIntervalIndex--;
422 if(m_OverlaySettings.m_SlicesPerUpdate > m_FileIntervalIndex) m_OverlaySettings.m_SlicesPerUpdate = m_FileIntervalIndex;
423 }
424 }
425 } else {
426 delete m_bGRIBActiveFile;
427 m_bGRIBActiveFile = NULL;
428 title = _("No valid GRIB file");
429 }
430 pPlugIn->GetGRIBOverlayFactory()->SetMessage( title );
431 SetTitle( title );
432 SetTimeLineMax(false);
433 SetFactoryOptions();
434 if( pPlugIn->GetStartOptions() && m_TimeLineHours != 0) //fix a crash for one date files
435 ComputeBestForecastForNow();
436 else
437 TimelineChanged();
438
439 //populate altitude choice and show if necessary
440 if (m_pTimelineSet && m_bGRIBActiveFile) for( int i = 1; i<5; i++) {
441 if( m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VX + i) != wxNOT_FOUND
442 && m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VY + i) != wxNOT_FOUND )
443 m_HasAltitude = true;
444 }
445 m_Altitude = 0; //set altitude at std
446
447 //enable buttons according with file contents to ovoid crashes
448 #ifdef __OCPN__ANDROID__
449 m_bpSettings->Enable(true);
450 #else
451 m_bpSettings->Enable(m_pTimelineSet != NULL);
452 #endif
453 m_bpZoomToCenter->Enable(m_pTimelineSet != NULL);
454
455 m_sTimeline->Enable(m_pTimelineSet != NULL && m_TimeLineHours);
456 m_bpPlay->Enable(m_pTimelineSet != NULL && m_TimeLineHours);
457
458 m_bpPrev->Enable(m_pTimelineSet != NULL && m_TimeLineHours);
459 m_bpNext->Enable(m_pTimelineSet != NULL && m_TimeLineHours);
460 m_bpNow->Enable(m_pTimelineSet != NULL && m_TimeLineHours);
461
462 SetCanvasContextMenuItemViz( pPlugIn->m_MenuItem, m_TimeLineHours != 0);
463
464 //
465 if( m_bGRIBActiveFile == NULL)
466 {
467 // there's no data we can use in this file
468 return;
469 }
470 // Try to verify that there will be at least one parameter in the GRIB file that is enabled for display
471 // This will ensure that at least "some" data is displayed on file change,
472 // and so avoid user confusion of no data shown.
473 // This is especially important if cursor tracking of data is disabled.
474
475 bool bconfigOK = false;
476 if(m_bDataPlot[GribOverlaySettings::WIND] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VX) != wxNOT_FOUND))
477 bconfigOK = true;
478 if(m_bDataPlot[GribOverlaySettings::WIND_GUST] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_GUST) != wxNOT_FOUND))
479 bconfigOK = true;
480 if(m_bDataPlot[GribOverlaySettings::PRESSURE] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_PRESSURE) != wxNOT_FOUND))
481 bconfigOK = true;
482 if(m_bDataPlot[GribOverlaySettings::WAVE] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WVDIR) != wxNOT_FOUND))
483 bconfigOK = true;
484 if(m_bDataPlot[GribOverlaySettings::WAVE] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_HTSIGW) != wxNOT_FOUND))
485 bconfigOK = true;
486 if(m_bDataPlot[GribOverlaySettings::CURRENT] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_SEACURRENT_VX) != wxNOT_FOUND))
487 bconfigOK = true;
488 if(m_bDataPlot[GribOverlaySettings::PRECIPITATION] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_PRECIP_TOT) != wxNOT_FOUND))
489 bconfigOK = true;
490 if(m_bDataPlot[GribOverlaySettings::CLOUD] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_CLOUD_TOT) != wxNOT_FOUND))
491 bconfigOK = true;
492 if(m_bDataPlot[GribOverlaySettings::AIR_TEMPERATURE] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_AIR_TEMP) != wxNOT_FOUND))
493 bconfigOK = true;
494 if(m_bDataPlot[GribOverlaySettings::SEA_TEMPERATURE] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_SEA_TEMP) != wxNOT_FOUND))
495 bconfigOK = true;
496 if(m_bDataPlot[GribOverlaySettings::CAPE] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_CAPE) != wxNOT_FOUND))
497 bconfigOK = true;
498 if(m_bDataPlot[GribOverlaySettings::COMP_REFL] && (m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_COMP_REFL) != wxNOT_FOUND))
499 bconfigOK = true;
500
501 // If no parameter seems to be enabled by config, enable them all just to be sure something shows.
502 if(!bconfigOK){
503 for(int i=0 ; i < (int)GribOverlaySettings::GEO_ALTITUDE ; i++){
504 if (InDataPlot(i)) {
505 m_bDataPlot[i] = true;
506 }
507 }
508 }
509 }
510
GetGribZoneLimits(GribTimelineRecordSet * timelineSet,double * latmin,double * latmax,double * lonmin,double * lonmax)511 bool GRIBUICtrlBar::GetGribZoneLimits(GribTimelineRecordSet *timelineSet, double *latmin, double *latmax, double *lonmin, double *lonmax)
512 {
513 //calculate the largest overlay size
514 GribRecord **pGR = timelineSet->m_GribRecordPtrArray;
515 double ltmi = -GRIB_NOTDEF, ltma = GRIB_NOTDEF, lnmi = -GRIB_NOTDEF, lnma = GRIB_NOTDEF;
516 for( unsigned int i = 0; i < Idx_COUNT; i++){
517 GribRecord *pGRA = pGR[i];
518 if(!pGRA) continue;
519 if(pGRA->getLatMin() < ltmi) ltmi = pGRA->getLatMin();
520 if(pGRA->getLatMax() > ltma) ltma = pGRA->getLatMax();
521 if(pGRA->getLonMin() < lnmi) lnmi = pGRA->getLonMin();
522 if(pGRA->getLonMax() > lnma) lnma = pGRA->getLonMax();
523 }
524 if( ltmi == -GRIB_NOTDEF || lnmi == -GRIB_NOTDEF ||
525 ltma == GRIB_NOTDEF || lnma == GRIB_NOTDEF)
526 return false;
527
528 if(latmin) *latmin = ltmi;
529 if(latmax) *latmax = ltma;
530 if(lonmin) *lonmin = lnmi;
531 if(lonmax) *lonmax = lnma;
532 return true;
533 }
534
535 class FileCollector : public wxDirTraverser
536 {
537 public:
FileCollector(wxArrayString & files,const wxRegEx & pattern)538 FileCollector(wxArrayString& files, const wxRegEx& pattern) : m_files(files), m_pattern(pattern) { }
OnFile(const wxString & filename)539 virtual wxDirTraverseResult OnFile(const wxString& filename) {
540 if( m_pattern.Matches(filename) )
541 m_files.Add(filename);
542 return wxDIR_CONTINUE;
543 }
OnDir(const wxString & WXUNUSED (dirname))544 virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) {
545 return wxDIR_IGNORE;
546 }
547 private:
548 wxArrayString& m_files;
549 const wxRegEx& m_pattern;
550 };
551
GetFilesInDirectory()552 wxArrayString GRIBUICtrlBar::GetFilesInDirectory()
553 {
554 if( !wxDir::Exists( m_grib_dir ) ) {
555 wxStandardPathsBase& path = wxStandardPaths::Get();
556 m_grib_dir = path.GetDocumentsDir();
557 }
558 // Get an array of GRIB file names in the target directory, not descending into subdirs
559 wxArrayString file_array;
560 wxRegEx pattern( _T(".+\\.gri?b2?(\\.(bz2|gz))?$"), wxRE_EXTENDED|wxRE_ICASE|wxRE_NOSUB );
561 FileCollector collector( file_array, pattern );
562 wxDir dir( m_grib_dir );
563 dir.Traverse( collector );
564 file_array.Sort( CompareFileStringTime ); //sort the files by File Modification Date
565 return file_array;
566 }
567
SetCursorLatLon(double lat,double lon)568 void GRIBUICtrlBar::SetCursorLatLon( double lat, double lon )
569 {
570 m_cursor_lon = lon;
571 m_cursor_lat = lat;
572
573 if(m_vp &&
574 ((lat > m_vp->lat_min) && (lat < m_vp->lat_max))&&
575 ((lon > m_vp->lon_min) && (lon < m_vp->lon_max)) )
576 UpdateTrackingControl();
577 }
578
UpdateTrackingControl()579 void GRIBUICtrlBar::UpdateTrackingControl()
580 {
581 if( !m_CDataIsShown ) return;
582
583 if( m_DialogStyle >> 1== SEPARATED ) {
584 if( m_gGRIBUICData ) {
585 if( !m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.IsRunning() )
586 m_gGRIBUICData->m_gCursorData->m_tCursorTrackTimer.Start(50, wxTIMER_ONE_SHOT );
587
588 }
589 } else {
590 if( m_gCursorData ) {
591 if(!m_gCursorData->m_tCursorTrackTimer.IsRunning())
592 m_gCursorData->m_tCursorTrackTimer.Start(50, wxTIMER_ONE_SHOT );
593 }
594 }
595 }
596
OnShowCursorData(wxCommandEvent & event)597 void GRIBUICtrlBar::OnShowCursorData( wxCommandEvent& event )
598 {
599 m_CDataIsShown = !m_CDataIsShown;
600 m_bpShowCursorData->SetBitmapLabel(GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata),
601 m_CDataIsShown ? _T("curdata") : _T("ncurdata"), m_ScaledFactor));
602 SetDialogsStyleSizePosition( true );
603 }
604
SetDialogsStyleSizePosition(bool force_recompute)605 void GRIBUICtrlBar::SetDialogsStyleSizePosition( bool force_recompute )
606 {
607 /*Not all plateforms accept the dynamic window style changes.
608 So these changes are applied only after exit from the plugin and re-opening it*/
609
610 if( !force_recompute && (m_old_DialogStyle == m_DialogStyle //recompute only if necessary
611 || (m_old_DialogStyle >> 1 == ATTACHED && m_DialogStyle >> 1 == ATTACHED)) )
612 return;
613
614
615 bool m_HasCaption = GetWindowStyleFlag() == (wxCAPTION|wxCLOSE_BOX|wxSYSTEM_MENU|wxTAB_TRAVERSAL);
616
617 /* first hide grabber, detach cursordata and set ctrl/buttons visibility to have CtrlBar in his "alone" version
618 altitude button visibility is a special case ( i == 0 ) */
619 int state = (m_DialogStyle >> 1 == ATTACHED && m_CDataIsShown) ? 0 : 1;
620 for( unsigned i = 0; i < m_OverlaySettings.m_iCtrlBarCtrlVisible[state].Len(); i++ ) {
621 bool vis = i > 0 ? true : m_HasAltitude ? true : false;
622 if(FindWindow( i + ID_CTRLALTITUDE ))
623 FindWindow( i + ID_CTRLALTITUDE )->Show( m_OverlaySettings.m_iCtrlBarCtrlVisible[state].GetChar(i) == _T('X') && vis );
624 }
625 //initiate tooltips
626 m_bpShowCursorData->SetToolTip( m_CDataIsShown ? _("Hide data at cursor" ) : _("Show data at cursor" ) );
627 m_bpPlay->SetToolTip(_("Start play back"));
628
629 m_gGrabber->Hide();
630 //then hide and detach cursor data window
631 if( m_gCursorData ) {
632 m_gCursorData->Hide();
633 m_fgCDataSizer->Detach(m_gCursorData);
634 }
635
636 SetMinSize( wxSize(0, 0));
637
638 //then cancel eventually Cursor data dialog (to be re-created later if necessary )
639 if( m_gGRIBUICData ) {
640 m_gGRIBUICData->Destroy();
641 m_gGRIBUICData = NULL;
642 }
643
644 if( (m_DialogStyle >> 1 == SEPARATED || !m_CDataIsShown) && !m_HasCaption ) { // Size and show grabber if necessary
645 Fit(); // each time CtrlData dialog will be alone
646 m_gGrabber->Size( m_ScaledFactor ); // or separated
647 m_gGrabber->Show();
648 }
649
650 if( m_CDataIsShown ) {
651
652 if( m_DialogStyle >> 1 == ATTACHED ) { //dialogs attached
653 //generate CursorData
654 if( !m_gCursorData )
655 m_gCursorData = new CursorData( this, *this );
656 pPlugIn->SetDialogFont( m_gCursorData );
657 m_gCursorData->PopulateTrackingControls( false );
658 //attach CursorData to CtrlBar if necessary
659 if( m_fgCDataSizer->GetItem( m_gCursorData ) == NULL )
660 m_fgCDataSizer->Add(m_gCursorData,0);
661 m_gCursorData->Show();
662
663 } else if( m_DialogStyle >> 1 == SEPARATED ) { //dialogs isolated
664 //create cursor data dialog
665 m_gGRIBUICData = new GRIBUICData( *this );
666 m_gGRIBUICData->m_gCursorData->PopulateTrackingControls( m_DialogStyle == SEPARATED_VERTICAL );
667 pPlugIn->SetDialogFont( m_gGRIBUICData->m_gCursorData );
668 m_gGRIBUICData->Fit();
669 m_gGRIBUICData->Update();
670 m_gGRIBUICData->Show();
671 pPlugIn->MoveDialog(m_gGRIBUICData, pPlugIn->GetCursorDataXY() );
672 }
673
674 }
675 Layout();
676 Fit();
677 wxSize sd = GetSize();
678 #ifdef __WXGTK__
679 if( m_HasCaption && sd.y == GetClientSize().y ) sd.y += 30;
680 #endif
681 SetSize( wxSize( sd.x, sd.y ) );
682 SetMinSize( wxSize( sd.x, sd.y ) );
683
684 #ifdef __OCPN__ANDROID__
685 wxRect tbRect = GetMasterToolbarRect();
686 //qDebug() << "TBR" << tbRect.x << tbRect.y << tbRect.width << tbRect.height << pPlugIn->GetCtrlBarXY().x << pPlugIn->GetCtrlBarXY().y;
687
688 if( 1 ){
689 wxPoint pNew = pPlugIn->GetCtrlBarXY();
690 pNew.x = tbRect.x + tbRect.width + 4;
691 pNew.y = 0; //tbRect.y;
692 pPlugIn->SetCtrlBarXY( pNew );
693 //qDebug() << "pNew" << pNew.x;
694
695 int widthAvail = GetCanvasByIndex(0)->GetClientSize().x - (tbRect.x +tbRect.width);
696
697 if(sd.x > widthAvail){
698 //qDebug() << "Too big" << widthAvail << sd.x;
699
700 int target_char_width = (float)widthAvail / 28;
701 wxScreenDC dc;
702 bool bOK = false;
703 int pointSize = 20;
704 int width, height;
705 wxFont *sFont;
706 while(!bOK){
707 //qDebug() << "PointSize" << pointSize;
708 sFont = FindOrCreateFont_PlugIn( pointSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, FALSE );
709 dc.GetTextExtent (_T("W"), &width, &height, NULL, NULL, sFont);
710 if(width <= target_char_width)
711 bOK = true;
712 pointSize--;
713 if(pointSize <= 10)
714 bOK = true;
715 }
716
717
718 m_cRecordForecast->SetFont(*sFont);
719
720 Layout();
721 Fit();
722 Hide();
723 SetSize( wxSize( widthAvail, sd.y ) );
724 SetMinSize( wxSize( widthAvail, sd.y ) );
725 Show();
726
727 }
728 }
729 wxPoint pNow = pPlugIn->GetCtrlBarXY();
730 pNow.y = 0;
731 pPlugIn->SetCtrlBarXY( pNow );
732
733 #endif
734
735 pPlugIn->MoveDialog( this, pPlugIn->GetCtrlBarXY() );
736 m_old_DialogStyle = m_DialogStyle;
737 }
738
OnAltitude(wxCommandEvent & event)739 void GRIBUICtrlBar::OnAltitude( wxCommandEvent& event )
740 {
741 if( !m_HasAltitude ) return;
742
743 wxMenu* amenu = new wxMenu();
744 amenu->Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent), NULL, this );
745
746 #ifdef __WXMSW__
747 const wxString l[] = { _T(" "), wxString::Format( _T("\u2022") ) };
748 #endif
749 for( int i = 0; i<5; i++) {
750 if( (( m_pTimelineSet && m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VX + i) != wxNOT_FOUND
751 && m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VY + i) != wxNOT_FOUND )) || i == 0 ) {
752 MenuAppend( amenu, ID_CTRLALTITUDE + 1000 + i ,
753 #ifdef __WXMSW__
754 (i == m_Altitude ? l[1] : l[0]) +
755 #endif
756 m_OverlaySettings.GetAltitudeFromIndex( i , m_OverlaySettings.Settings[GribOverlaySettings::PRESSURE].m_Units),
757 wxITEM_RADIO );
758 }
759 }
760
761 amenu->Check( ID_CTRLALTITUDE + 1000 + m_Altitude, true );
762
763 PopupMenu( amenu );
764
765 delete amenu;
766 }
767
OnMove(wxMoveEvent & event)768 void GRIBUICtrlBar::OnMove( wxMoveEvent& event )
769 {
770 int w, h;
771 GetScreenPosition( &w, &h );
772 pPlugIn->SetCtrlBarXY ( wxPoint( w, h ) );
773 }
774
OnMenuEvent(wxMenuEvent & event)775 void GRIBUICtrlBar::OnMenuEvent( wxMenuEvent& event )
776 {
777 int id = event.GetId();
778 wxCommandEvent evt;
779 evt.SetId( id );
780 int alt = m_Altitude;
781 switch( id ) {
782 //sub menu altitude data
783 case ID_CTRLALTITUDE + 1000:
784 m_Altitude = 0;
785 break;
786 case ID_CTRLALTITUDE + 1001:
787 m_Altitude = 1;
788 break;
789 case ID_CTRLALTITUDE + 1002:
790 m_Altitude = 2;
791 break;
792 case ID_CTRLALTITUDE + 1003:
793 m_Altitude = 3;
794 break;
795 case ID_CTRLALTITUDE + 1004:
796 m_Altitude = 4;
797 break;
798 // end sub menu
799 case ID_BTNNOW:
800 OnNow( evt );
801 break;
802 case ID_BTNZOOMTC:
803 OnZoomToCenterClick( evt );
804 break;
805 case ID_BTNSHOWCDATA:
806 OnShowCursorData( evt );
807 break;
808 case ID_BTNPLAY:
809 OnPlayStop( evt );
810 break;
811 case ID_BTNOPENFILE:
812 OnOpenFile( evt );
813 break;
814 case ID_BTNSETTING:
815 OnSettings( evt );
816 break;
817 case ID_BTNREQUEST:
818 OnRequest( evt );
819 }
820 if( alt != m_Altitude ) {
821 SetDialogsStyleSizePosition( true );
822 SetFactoryOptions(); // Reload the visibility options
823 }
824 }
825
MenuAppend(wxMenu * menu,int id,wxString label,wxItemKind kind,wxBitmap bitmap,wxMenu * submenu)826 void GRIBUICtrlBar::MenuAppend( wxMenu *menu, int id, wxString label, wxItemKind kind, wxBitmap bitmap , wxMenu *submenu )
827 {
828 wxMenuItem *item = new wxMenuItem(menu, id, label, _T(""), kind, submenu );
829
830 #ifdef __WXMSW__
831 wxFont *qFont = OCPNGetFont( _("Menu"), 10 );
832 item->SetFont(*qFont);
833 #endif
834
835 #if defined(__WXMSW__) || defined( __WXGTK__)
836 if( !bitmap.IsSameAs( wxNullBitmap ) )
837 item->SetBitmap( bitmap );
838 #endif
839
840 menu->Append( item );
841
842 }
843
OnMouseEvent(wxMouseEvent & event)844 void GRIBUICtrlBar::OnMouseEvent( wxMouseEvent& event )
845 {
846 if( event.RightDown() ) {
847 //populate menu
848 wxMenu* xmenu = new wxMenu();
849 xmenu->Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent), NULL, this );
850
851 if( m_HasAltitude ) { //eventually populate altitude choice
852 wxMenu* smenu = new wxMenu();
853 smenu->Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler(GRIBUICtrlBar::OnMenuEvent), NULL, this );
854
855 #ifdef __WXMSW__
856 const wxString l[] = { _T(" "), wxString::Format( _T("\u2022") ) };
857 #endif
858 for( int i = 0; i<5; i++) {
859 if( (( m_pTimelineSet && m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VX + i) != wxNOT_FOUND
860 && m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VY + i) != wxNOT_FOUND )) || i == 0 ) {
861 MenuAppend( smenu, ID_CTRLALTITUDE + 1000 + i ,
862 #ifdef __WXMSW__
863 (i == m_Altitude ? l[1] : l[0]) +
864 #endif
865 m_OverlaySettings.GetAltitudeFromIndex( i , m_OverlaySettings.Settings[GribOverlaySettings::PRESSURE].m_Units),
866 wxITEM_RADIO );
867 }
868 }
869 smenu->Check( ID_CTRLALTITUDE + 1000 + m_Altitude, true );
870 MenuAppend(xmenu, wxID_ANY, _("Select geopotential altitude"), wxITEM_NORMAL, GetScaledBitmap(wxBitmap(altitude), _T("altitude"), m_ScaledFactor));
871 }
872 MenuAppend(xmenu, ID_BTNNOW, _("Now"), wxITEM_NORMAL, GetScaledBitmap(wxBitmap(now), _T("now"), m_ScaledFactor));
873 MenuAppend(xmenu, ID_BTNZOOMTC, _("Zoom To Center"), wxITEM_NORMAL, GetScaledBitmap(wxBitmap(zoomto), _T("zoomto"), m_ScaledFactor));
874 MenuAppend( xmenu, ID_BTNSHOWCDATA, m_CDataIsShown ? _("Hide data at cursor") : _("Show data at cursor"), wxITEM_NORMAL,
875 GetScaledBitmap(wxBitmap(m_CDataIsShown ? curdata : ncurdata), m_CDataIsShown ? _T("curdata") : _T("ncurdata"),
876 m_ScaledFactor));
877 MenuAppend( xmenu, ID_BTNPLAY, m_tPlayStop.IsRunning() ? _("Stop play back") : _("Start play back"), wxITEM_NORMAL,
878 GetScaledBitmap(wxBitmap(m_tPlayStop.IsRunning() ? stop : play), m_tPlayStop.IsRunning() ? _T("stop") : _T("play"),
879 m_ScaledFactor) );
880 MenuAppend(xmenu, ID_BTNOPENFILE, _("Open a new file"), wxITEM_NORMAL, GetScaledBitmap(wxBitmap(openfile), _T("openfile"), m_ScaledFactor));
881 MenuAppend(xmenu, ID_BTNSETTING, _("Settings"), wxITEM_NORMAL, GetScaledBitmap(wxBitmap(setting), _T("setting"), m_ScaledFactor));
882 bool requeststate1 = m_ZoneSelMode == AUTO_SELECTION || m_ZoneSelMode == SAVED_SELECTION || m_ZoneSelMode == START_SELECTION;
883 bool requeststate3 = m_ZoneSelMode == DRAW_SELECTION;
884 MenuAppend(xmenu, ID_BTNREQUEST, requeststate1 ? _("Start a request") : requeststate3 ?
885 _("Draw requested Area or Click here to stop request") : _("Valid Area and Continue"),
886 wxITEM_NORMAL, GetScaledBitmap(wxBitmap(requeststate1 ? request : requeststate3 ? selzone : request_end),
887 requeststate1 ? _T("request") : requeststate3 ? _T("selzone") : _T("request_end"), m_ScaledFactor));
888
889 PopupMenu( xmenu );
890
891 delete xmenu;
892
893 return;
894 }
895
896 if( m_DialogStyle >> 1 == SEPARATED ) return;
897 wxMouseEvent evt(event);
898 evt.SetId( 1000 );
899
900 #ifndef __OCPN__ANDROID__
901 if( m_gCursorData && m_CDataIsShown ){
902 m_gCursorData->OnMouseEvent (evt );
903 }
904 #endif
905 }
906
ContextMenuItemCallback(int id)907 void GRIBUICtrlBar::ContextMenuItemCallback(int id)
908 {
909 //deactivate cursor data update during menu callback
910 bool dataisshown = m_CDataIsShown;
911 m_CDataIsShown = false;
912 //
913 wxFileConfig *pConf = GetOCPNConfigObject();
914
915 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
916 GRIBTable *table = new GRIBTable(*this);
917
918 table->InitGribTable(pPlugIn->GetTimeZone(), rsa, GetNearestIndex( GetNow(), 0));
919 table->SetTableSizePosition(m_vp->pix_width, m_vp->pix_height);
920
921 table->ShowModal();
922
923 //re-activate cursor data
924 m_CDataIsShown = dataisshown;
925 delete table;
926 }
927
SetViewPort(PlugIn_ViewPort * vp)928 void GRIBUICtrlBar::SetViewPort( PlugIn_ViewPort *vp )
929 {
930 if(m_vp == vp) return;
931
932 delete m_vp;
933 m_vp = new PlugIn_ViewPort(*vp);
934
935 if(pReq_Dialog)
936 if(pReq_Dialog->IsShown()) pReq_Dialog->OnVpChange(vp);
937 }
938
OnClose(wxCloseEvent & event)939 void GRIBUICtrlBar::OnClose( wxCloseEvent& event )
940 {
941 StopPlayBack();
942 if( m_gGRIBUICData ) m_gGRIBUICData->Hide();
943 if(pReq_Dialog)
944 if( m_ZoneSelMode > START_SELECTION ) {
945 pReq_Dialog->StopGraphicalZoneSelection();
946 m_ZoneSelMode = START_SELECTION;
947 //SetRequestBitmap( m_ZoneSelMode );
948 }
949 pPlugIn->SendTimelineMessage(wxInvalidDateTime );
950
951 pPlugIn->OnGribCtrlBarClose();
952 }
953
OnSize(wxSizeEvent & event)954 void GRIBUICtrlBar::OnSize( wxSizeEvent& event )
955 {
956 // Record the dialog size
957 wxSize p = event.GetSize();
958 pPlugIn->SetCtrlBarSizeXY( p );
959
960 event.Skip();
961 }
962
OnPaint(wxPaintEvent & event)963 void GRIBUICtrlBar::OnPaint( wxPaintEvent& event )
964 {
965 wxWindowListNode *node = this->GetChildren().GetFirst();
966 wxPaintDC dc( this );
967 while( node ) {
968 wxWindow *win = node->GetData();
969 if( win->IsKindOf(CLASSINFO(wxBitmapButton)) )
970 #if wxCHECK_VERSION(3,0,0)
971 dc.DrawBitmap(((wxBitmapButton*) win)->GetBitmap() , 5, 5, false );
972 #else
973 dc.DrawBitmap(((wxBitmapButton*) win)->GetBitmapSelected() , 5, 5, false );
974 #endif
975 node = node->GetNext();
976 }
977 }
978
OnRequest(wxCommandEvent & event)979 void GRIBUICtrlBar::OnRequest( wxCommandEvent& event )
980 {
981 if( m_tPlayStop.IsRunning() ) return; // do nothing when play back is running !
982
983 /*if there is one instance of the dialog already visible, do nothing*/
984 if(pReq_Dialog && pReq_Dialog->IsShown() ) return;
985
986 /*a second click without selection cancel the process*/
987 if( m_ZoneSelMode == DRAW_SELECTION ) {
988 assert(pReq_Dialog);
989 m_ZoneSelMode = START_SELECTION;
990 pReq_Dialog->StopGraphicalZoneSelection();
991 SetRequestBitmap( m_ZoneSelMode );
992 return;
993 }
994
995 /*create new request dialog*/
996 if( m_ZoneSelMode == AUTO_SELECTION || m_ZoneSelMode == SAVED_SELECTION || m_ZoneSelMode == START_SELECTION ) {
997
998 ::wxBeginBusyCursor();
999
1000 delete pReq_Dialog; //delete to be re-created
1001
1002 pReq_Dialog = new GribRequestSetting( *this );
1003 pPlugIn->SetDialogFont( pReq_Dialog );
1004 pPlugIn->SetDialogFont( pReq_Dialog->m_sScrolledDialog );
1005 pReq_Dialog->OnVpChange(m_vp);
1006 pReq_Dialog->SetRequestDialogSize();
1007 //need to set a position at start
1008 int w;
1009 ::wxDisplaySize( &w, NULL);
1010 pReq_Dialog->Move( (w - pReq_Dialog->GetSize().GetX() ) / 2, 30 );
1011
1012 } //end create new request dialog
1013
1014 pReq_Dialog->Show( m_ZoneSelMode == AUTO_SELECTION || m_ZoneSelMode == SAVED_SELECTION || m_ZoneSelMode == COMPLETE_SELECTION );
1015 m_ZoneSelMode = m_ZoneSelMode == START_SELECTION ? DRAW_SELECTION : m_ZoneSelMode == COMPLETE_SELECTION ? START_SELECTION : m_ZoneSelMode;
1016 if( m_ZoneSelMode == START_SELECTION ) pReq_Dialog->StopGraphicalZoneSelection();
1017 SetRequestBitmap( m_ZoneSelMode ); //set appopriate bitmap
1018
1019 if ( ::wxIsBusy() )::wxEndBusyCursor();
1020
1021 }
1022
OnSettings(wxCommandEvent & event)1023 void GRIBUICtrlBar::OnSettings( wxCommandEvent& event )
1024 {
1025 if( m_tPlayStop.IsRunning() ) return; // do nothing when play back is running !
1026
1027 ::wxBeginBusyCursor();
1028
1029 GribOverlaySettings initSettings = m_OverlaySettings;
1030 GribSettingsDialog *dialog = new GribSettingsDialog( *this, m_OverlaySettings, m_lastdatatype, m_FileIntervalIndex);
1031 //set font
1032 pPlugIn->SetDialogFont( dialog );
1033 for( size_t i = 0; i < dialog->m_nSettingsBook->GetPageCount(); i++ ) {
1034 wxScrolledWindow *sc = ((wxScrolledWindow*) dialog->m_nSettingsBook->GetPage( i ));
1035 pPlugIn->SetDialogFont( sc );
1036 } //end set font
1037
1038 dialog->m_nSettingsBook->ChangeSelection( dialog->GetPageIndex() );
1039 dialog->SetSettingsDialogSize();
1040 //need to set a position at start
1041 int w;
1042 ::wxDisplaySize( &w, NULL);
1043 dialog->Move( (w - dialog->GetSize().GetX() ) / 2, 30 );
1044 // end set position
1045
1046 ::wxEndBusyCursor();
1047
1048 if(dialog->ShowModal() == wxID_OK)
1049 {
1050 dialog->WriteSettings();
1051 m_OverlaySettings.Write();
1052 if( m_OverlaySettings.Settings[GribOverlaySettings::WIND].m_Units != initSettings.Settings[GribOverlaySettings::WIND].m_Units
1053 && (m_OverlaySettings.Settings[GribOverlaySettings::WIND].m_Units == GribOverlaySettings::BFS
1054 || initSettings.Settings[GribOverlaySettings::WIND].m_Units == GribOverlaySettings::BFS) )
1055 m_old_DialogStyle = STARTING_STATE_STYLE; //must recompute dialogs size if wind unit have been changed
1056 } else {
1057 m_OverlaySettings = initSettings;
1058 m_DialogStyle = initSettings.m_iCtrlandDataStyle;
1059 }
1060 ::wxBeginBusyCursor();
1061
1062 dialog->SaveLastPage();
1063 if( !m_OverlaySettings.m_bInterpolate ) m_InterpolateMode = false; //Interpolate could have been unchecked
1064 SetTimeLineMax(true);
1065 SetFactoryOptions();
1066
1067 SetDialogsStyleSizePosition(true);
1068 delete dialog;
1069
1070 event.Skip();
1071 }
1072
1073 #ifdef __OCPN__ANDROID__
1074 wxString callActivityMethod_ss(const char *method, wxString parm);
1075 #endif
1076
OnCompositeDialog(wxCommandEvent & event)1077 void GRIBUICtrlBar::OnCompositeDialog( wxCommandEvent& event )
1078 {
1079 // Grab the current settings values
1080 GribOverlaySettings initSettings = m_OverlaySettings;
1081 initSettings.Read();
1082
1083 wxString json;
1084 wxString json_begin = initSettings.SettingsToJSON(json);
1085 wxLogMessage(json_begin);
1086
1087
1088 // Pick up the required options from the Request dialog
1089 // and add them to the JSON object
1090 // Really, this just means the current viewport coordinates.
1091 // Everything else is stored in Android app preferences bundle.
1092
1093 PlugIn_ViewPort current_vp = pPlugIn->GetCurrentViewPort();
1094
1095 double lon_min = wxRound(current_vp.lon_min) - 1;
1096 double lon_max = wxRound(current_vp.lon_max) + 1;
1097 double lat_min = wxRound(current_vp.lat_min) - 1;
1098 double lat_max = wxRound(current_vp.lat_max) + 1;
1099
1100 wxJSONValue v;
1101 wxJSONReader reader;
1102 int numErrors = reader.Parse( json_begin, &v );
1103 if ( numErrors > 0 ){
1104 return;
1105 }
1106
1107 v[_T("latMin")] = lat_min;
1108 v[_T("latMax")] = lat_max;
1109 v[_T("lonMin")] = lon_min;
1110 v[_T("lonMax")] = lon_max;
1111
1112 // Clear the file name field, so that a retrieved or selected file name can be returned
1113 v[_T("grib_file")] = _T("");
1114
1115 wxJSONWriter w;
1116 wxString json_final;
1117 w.Write(v, json_final);
1118 wxLogMessage(json_final);
1119
1120
1121 #ifdef __OCPN__ANDROID__
1122 wxString ret = callActivityMethod_ss("doGRIBActivity", json_final);
1123 wxLogMessage(ret);
1124 #endif
1125
1126
1127 event.Skip();
1128
1129
1130 }
1131
OpenFileFromJSON(wxString json)1132 void GRIBUICtrlBar::OpenFileFromJSON( wxString json)
1133 {
1134 // construct the JSON root object
1135 wxJSONValue root;
1136 // construct a JSON parser
1137 wxJSONReader reader;
1138
1139 int numErrors = reader.Parse( json, &root );
1140 if ( numErrors > 0 ) {
1141 return;
1142 }
1143
1144 wxString file = root[( _T("grib_file") )].AsString();
1145
1146 if(file.Length() && wxFileExists( file )){
1147 wxFileName fn(file);
1148 m_grib_dir = fn.GetPath();
1149 m_file_names.Clear();
1150 m_file_names.Add(file);
1151 OpenFile();
1152 }
1153 }
1154
1155
1156
OnPlayStop(wxCommandEvent & event)1157 void GRIBUICtrlBar::OnPlayStop( wxCommandEvent& event )
1158 {
1159 if( m_tPlayStop.IsRunning() ) {
1160 StopPlayBack();
1161 } else {
1162 m_bpPlay->SetBitmapLabel(GetScaledBitmap(wxBitmap(stop), _T("stop"), m_ScaledFactor));
1163 m_bpPlay->SetToolTip( _("Stop play back") );
1164 m_tPlayStop.Start( 3000/m_OverlaySettings.m_UpdatesPerSecond, wxTIMER_CONTINUOUS );
1165 m_InterpolateMode = m_OverlaySettings.m_bInterpolate;
1166 }
1167 }
1168
OnPlayStopTimer(wxTimerEvent & event)1169 void GRIBUICtrlBar::OnPlayStopTimer( wxTimerEvent & event )
1170 {
1171 if(m_sTimeline->GetValue() >= m_sTimeline->GetMax()) {
1172 if(m_OverlaySettings.m_bLoopMode) {
1173 if(m_OverlaySettings.m_LoopStartPoint) {
1174 ComputeBestForecastForNow();
1175 if(m_sTimeline->GetValue() >= m_sTimeline->GetMax()) StopPlayBack(); //will stop playback
1176 return;
1177 } else
1178 m_sTimeline->SetValue(0);
1179 } else {
1180 StopPlayBack(); //will stop playback
1181 return;
1182 }
1183 } else {
1184 int value = m_pNowMode ? m_OverlaySettings.m_bInterpolate ?
1185 GetNearestValue(GetNow(), 1) : GetNearestIndex(GetNow(), 2) : m_sTimeline->GetValue();
1186 m_sTimeline->SetValue(value + 1);
1187 }
1188
1189 m_pNowMode = false;
1190 if(!m_InterpolateMode) m_cRecordForecast->SetSelection( m_sTimeline->GetValue() );
1191 TimelineChanged();
1192 }
1193
StopPlayBack()1194 void GRIBUICtrlBar::StopPlayBack()
1195 {
1196 if( m_tPlayStop.IsRunning() ) {
1197 m_tPlayStop.Stop();
1198 m_bpPlay->SetBitmapLabel(GetScaledBitmap(wxBitmap(play), _T("play"), m_ScaledFactor));
1199 m_bpPlay->SetToolTip( _("Start play back") );
1200 }
1201 }
1202
TimelineChanged()1203 void GRIBUICtrlBar::TimelineChanged()
1204 {
1205 if( !m_bGRIBActiveFile || (m_bGRIBActiveFile && !m_bGRIBActiveFile->IsOK()) ) {
1206 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(NULL);
1207 return;
1208 }
1209
1210 RestaureSelectionString(); //eventually restaure the previousely saved time label
1211
1212 wxDateTime time = TimelineTime();
1213 SetGribTimelineRecordSet(GetTimeLineRecordSet(time));
1214
1215 if( !m_InterpolateMode ){
1216 /* get closest value to update timeline */
1217 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1218 GribRecordSet &sel=rsa->Item(m_cRecordForecast->GetCurrentSelection());
1219 wxDateTime t = sel.m_Reference_Time;
1220 m_sTimeline->SetValue(
1221 m_OverlaySettings.m_bInterpolate ?
1222 wxTimeSpan(t - MinTime()).GetMinutes() / m_OverlaySettings.GetMinFromIndex(m_OverlaySettings.m_SlicesPerUpdate)
1223 : m_cRecordForecast->GetCurrentSelection()
1224 );
1225 } else {
1226 m_cRecordForecast->SetSelection(GetNearestIndex(time, 2));
1227 SaveSelectionString(); //memorize index and label
1228 m_cRecordForecast->SetString( m_Selection_index, TToString(time, pPlugIn->GetTimeZone()) );//replace it by the interpolated time label
1229 m_cRecordForecast->SetStringSelection( TToString(time, pPlugIn->GetTimeZone()) ); //ensure it's visible in the box
1230 }
1231
1232 UpdateTrackingControl();
1233
1234 pPlugIn->SendTimelineMessage(time);
1235 RequestRefresh( GetGRIBCanvas() );
1236 }
1237
RestaureSelectionString()1238 void GRIBUICtrlBar::RestaureSelectionString()
1239 {
1240 if( !m_SelectionIsSaved ) return;
1241
1242 int sel = m_cRecordForecast->GetSelection();
1243 m_cRecordForecast->SetString( m_Selection_index, m_Selection_label );
1244 m_cRecordForecast->SetSelection( sel );
1245 m_SelectionIsSaved = false;
1246 }
1247
GetNearestIndex(wxDateTime time,int model)1248 int GRIBUICtrlBar::GetNearestIndex(wxDateTime time, int model)
1249 {
1250 /* get closest index to update combo box */
1251 size_t i;
1252 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1253
1254 wxDateTime itime, ip1time;
1255 for(i=0; i<rsa->GetCount()-1; i++) {
1256 itime = rsa->Item(i).m_Reference_Time;
1257 ip1time = rsa->Item(i+1).m_Reference_Time;
1258 if(ip1time >= time)
1259 break;
1260 }
1261 if(!model) return (time - itime > (ip1time - time)*3) ? i+1 : i;
1262
1263 return model == 1 ? time == ip1time ? i : i+1 : time == ip1time ? i+1 : i;
1264 }
1265
GetNearestValue(wxDateTime time,int model)1266 int GRIBUICtrlBar::GetNearestValue(wxDateTime time, int model)
1267 {
1268 /* get closest value to update Time line */
1269 if(m_TimeLineHours == 0) return 0;
1270 wxDateTime itime, ip1time;
1271 int stepmin = m_OverlaySettings.GetMinFromIndex(m_OverlaySettings.m_SlicesPerUpdate);
1272 wxTimeSpan span = time - MinTime();
1273 int t = span.GetMinutes()/stepmin;
1274 itime = MinTime() + wxTimeSpan( t * stepmin / 60, (t * stepmin) % 60 ); //time at t
1275 ip1time = itime + wxTimeSpan( stepmin / 60, stepmin % 60 ); //time at t+1
1276
1277 if(model == 1) return time == ip1time ? t+1 : t;
1278
1279 return (time - itime > (ip1time - time)*3) ? t+1 : t;
1280 }
1281
GetNow()1282 wxDateTime GRIBUICtrlBar::GetNow()
1283 {
1284 wxDateTime now = wxDateTime::Now();
1285 now.GetSecond(0);
1286
1287 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1288
1289 //verifie if we are outside of the file time range
1290 now = (now > rsa->Item(rsa->GetCount()-1).m_Reference_Time) ? rsa->Item(rsa->GetCount()-1).m_Reference_Time :
1291 (now < rsa->Item(0).m_Reference_Time) ? rsa->Item(0).m_Reference_Time : now;
1292 return now;
1293 }
1294
TimelineTime()1295 wxDateTime GRIBUICtrlBar::TimelineTime()
1296 {
1297 if(m_InterpolateMode) {
1298 int tl = (m_TimeLineHours == 0) ? 0 : m_sTimeline->GetValue();
1299 int stepmin = m_OverlaySettings.GetMinFromIndex(m_OverlaySettings.m_SlicesPerUpdate);
1300 return MinTime() + wxTimeSpan( tl * stepmin / 60, (tl * stepmin) % 60 );
1301 }
1302
1303 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1304 unsigned int index = m_cRecordForecast->GetCurrentSelection() < 1 ? 0 : m_cRecordForecast->GetCurrentSelection();
1305 if(rsa && index<rsa->GetCount())
1306 return rsa->Item(index).m_Reference_Time;
1307
1308 return wxDateTime::Now();
1309 }
1310
MinTime()1311 wxDateTime GRIBUICtrlBar::MinTime()
1312 {
1313 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1314 if(rsa && rsa->GetCount()) {
1315 GribRecordSet &first = rsa->Item(0);
1316 return first.m_Reference_Time;
1317 }
1318 return wxDateTime::Now();
1319 }
1320
GetTimeLineRecordSet(wxDateTime time)1321 GribTimelineRecordSet* GRIBUICtrlBar::GetTimeLineRecordSet(wxDateTime time)
1322 {
1323 if (m_bGRIBActiveFile == NULL)
1324 return NULL;
1325 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1326
1327 if(rsa->GetCount() == 0)
1328 return NULL;
1329
1330 GribTimelineRecordSet *set = new GribTimelineRecordSet(m_bGRIBActiveFile->GetCounter());
1331 for(int i=0; i<Idx_COUNT; i++) {
1332 GribRecordSet *GRS1 = NULL, *GRS2 = NULL;
1333 GribRecord *GR1 = NULL, *GR2 = NULL;
1334 wxDateTime GR1time, GR2time;
1335
1336 // already computed using polar interpolation from first axis
1337 if(set->m_GribRecordPtrArray[i])
1338 continue;
1339
1340 unsigned int j;
1341 for(j=0; j<rsa->GetCount(); j++) {
1342 GribRecordSet *GRS = &rsa->Item(j);
1343 GribRecord *GR = GRS->m_GribRecordPtrArray[i];
1344 if(!GR)
1345 continue;
1346
1347 wxDateTime curtime = GRS->m_Reference_Time;
1348 if(curtime <= time)
1349 GR1time = curtime, GRS1 = GRS, GR1 = GR;
1350
1351 if(curtime >= time) {
1352 GR2time = curtime, GRS2 = GRS, GR2 = GR;
1353 break;
1354 }
1355 }
1356
1357 if(!GR1 || !GR2)
1358 continue;
1359
1360 wxDateTime mintime = MinTime();
1361 double minute2 = (GR2time - mintime).GetMinutes();
1362 double minute1 = (GR1time - mintime).GetMinutes();
1363 double nminute = (time - mintime).GetMinutes();
1364
1365 if(minute2<minute1 || nminute < minute1 || nminute > minute2)
1366 continue;
1367
1368 double interp_const;
1369 if(minute1 == minute2) {
1370 // with big grib a copy is slow use a reference.
1371 set->m_GribRecordPtrArray[i] = GR1;
1372 continue;
1373 } else
1374 interp_const = (nminute-minute1) / (minute2-minute1);
1375
1376 /* if this is a vector interpolation use the 2d method */
1377 if(i < Idx_WIND_VY) {
1378 GribRecord *GR1y = GRS1->m_GribRecordPtrArray[i + Idx_WIND_VY];
1379 GribRecord *GR2y = GRS2->m_GribRecordPtrArray[i + Idx_WIND_VY];
1380 if(GR1y && GR2y) {
1381 GribRecord *Ry;
1382 set->SetUnRefGribRecord(i, GribRecord::Interpolated2DRecord(Ry, *GR1, *GR1y, *GR2, *GR2y, interp_const));
1383 set->SetUnRefGribRecord(i + Idx_WIND_VY, Ry);
1384 continue;
1385 }
1386 } else if(i <= Idx_WIND_VY300)
1387 continue;
1388 else if(i == Idx_SEACURRENT_VX) {
1389 GribRecord *GR1y = GRS1->m_GribRecordPtrArray[Idx_SEACURRENT_VY];
1390 GribRecord *GR2y = GRS2->m_GribRecordPtrArray[Idx_SEACURRENT_VY];
1391 if(GR1y && GR2y) {
1392 GribRecord *Ry;
1393 set->SetUnRefGribRecord(i, GribRecord::Interpolated2DRecord(Ry, *GR1, *GR1y, *GR2, *GR2y, interp_const));
1394 set->SetUnRefGribRecord(Idx_SEACURRENT_VY, Ry);
1395 continue;
1396 }
1397 } else if(i == Idx_SEACURRENT_VY)
1398 continue;
1399
1400 set->SetUnRefGribRecord(i, GribRecord::InterpolatedRecord(*GR1, *GR2, interp_const, i == Idx_WVDIR));
1401 }
1402
1403 set->m_Reference_Time = time.GetTicks();
1404 //(1-interp_const)*GRS1.m_Reference_Time + interp_const*GRS2.m_Reference_Time;
1405 return set;
1406 }
1407
getTimeInterpolatedValue(int idx,double lon,double lat,wxDateTime time)1408 double GRIBUICtrlBar::getTimeInterpolatedValue ( int idx, double lon, double lat, wxDateTime time)
1409 {
1410 if (m_bGRIBActiveFile == nullptr)
1411 return GRIB_NOTDEF;
1412 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1413
1414 if(rsa->GetCount() == 0)
1415 return GRIB_NOTDEF;
1416
1417 GribRecord *before = nullptr, *after = nullptr;
1418
1419 unsigned int j;
1420 time_t t = time.GetTicks();
1421 for(j=0; j<rsa->GetCount(); j++) {
1422 GribRecordSet *GRS = &rsa->Item(j);
1423 GribRecord *GR = GRS->m_GribRecordPtrArray[idx];
1424 if(!GR)
1425 continue;
1426
1427 time_t curtime = GR->getRecordCurrentDate();
1428 if (curtime == t)
1429 return GR->getInterpolatedValue(lon, lat);
1430
1431 if(curtime < t)
1432 before = GR;
1433
1434 if(curtime > t) {
1435 after = GR;
1436 break;
1437 }
1438 }
1439 // time_t wxDateTime::GetTicks();
1440 if(!before || !after)
1441 return GRIB_NOTDEF;
1442
1443 time_t t1 = before->getRecordCurrentDate();
1444 time_t t2 = after->getRecordCurrentDate();
1445 if (t1 == t2)
1446 return before->getInterpolatedValue(lon, lat);
1447
1448 double v1 = before->getInterpolatedValue(lon, lat);
1449 double v2 = after->getInterpolatedValue(lon, lat);
1450 if (v1 != GRIB_NOTDEF && v2 != GRIB_NOTDEF) {
1451 double k = fabs( (double)(t-t1)/(t2-t1) );
1452 return (1.0-k)*v1 + k*v2;
1453 }
1454
1455 return GRIB_NOTDEF;
1456 }
1457
getTimeInterpolatedValues(double & M,double & A,int idx1,int idx2,double lon,double lat,wxDateTime time)1458 bool GRIBUICtrlBar::getTimeInterpolatedValues( double &M, double &A, int idx1, int idx2, double lon, double lat, wxDateTime time)
1459 {
1460 M = GRIB_NOTDEF;
1461 A = GRIB_NOTDEF;
1462
1463 if (m_bGRIBActiveFile == nullptr)
1464 return false;
1465 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1466
1467 if(rsa->GetCount() == 0)
1468 return false;
1469
1470 GribRecord *beforeX = nullptr, *afterX = nullptr;
1471 GribRecord *beforeY = nullptr, *afterY = nullptr;
1472
1473 unsigned int j;
1474 time_t t = time.GetTicks();
1475 for(j=0; j<rsa->GetCount(); j++) {
1476 GribRecordSet *GRS = &rsa->Item(j);
1477 GribRecord *GX = GRS->m_GribRecordPtrArray[idx1];
1478 GribRecord *GY = GRS->m_GribRecordPtrArray[idx2];
1479 if(!GX || !GY)
1480 continue;
1481
1482 time_t curtime = GX->getRecordCurrentDate();
1483 if (curtime == t) {
1484 return GribRecord::getInterpolatedValues(M, A, GX, GY, lon, lat, true);
1485 }
1486 if(curtime < t) {
1487 beforeX = GX;
1488 beforeY = GY;
1489 }
1490 if(curtime > t) {
1491 afterX = GX;
1492 afterY = GY;
1493 break;
1494 }
1495 }
1496 // time_t wxDateTime::GetTicks();
1497 if(!beforeX || !afterX)
1498 return false;
1499
1500 time_t t1 = beforeX->getRecordCurrentDate();
1501 time_t t2 = afterX->getRecordCurrentDate();
1502 if (t1 == t2) {
1503 return GribRecord::getInterpolatedValues(M, A, beforeX, beforeY, lon, lat, true);
1504 }
1505 double v1m, v2m, v1a, v2a;
1506 if (!GribRecord::getInterpolatedValues(v1m, v1a, beforeX, beforeY, lon, lat, true))
1507 return false;
1508
1509 if (!GribRecord::getInterpolatedValues(v2m, v2a, afterX, afterY, lon, lat, true))
1510 return false;
1511
1512 if (v1m == GRIB_NOTDEF || v2m == GRIB_NOTDEF || v1a == GRIB_NOTDEF || v2a == GRIB_NOTDEF )
1513 return false;
1514
1515 double k = fabs( (double)(t-t1)/(t2-t1) );
1516 M = (1.0-k)*v1m + k*v2m;
1517 A = (1.0-k)*v1a + k*v2a;
1518 return true;
1519 }
1520
OnTimeline(wxScrollEvent & event)1521 void GRIBUICtrlBar::OnTimeline( wxScrollEvent& event )
1522 {
1523 StopPlayBack();
1524 m_InterpolateMode = m_OverlaySettings.m_bInterpolate;
1525 if(!m_InterpolateMode) m_cRecordForecast->SetSelection(m_sTimeline->GetValue());
1526 m_pNowMode = false;
1527 TimelineChanged();
1528 }
1529
OnOpenFile(wxCommandEvent & event)1530 void GRIBUICtrlBar::OnOpenFile( wxCommandEvent& event )
1531 {
1532 if( m_tPlayStop.IsRunning() ) return; // do nothing when play back is running !
1533
1534 #ifndef __OCPN__ANDROID__
1535 if( !wxDir::Exists( m_grib_dir ) ) {
1536 wxStandardPathsBase& path = wxStandardPaths::Get();
1537 m_grib_dir = path.GetDocumentsDir();
1538 }
1539
1540 wxFileDialog *dialog = new wxFileDialog(NULL, _("Select a GRIB file"), m_grib_dir,
1541 _T(""), wxT ( "Grib files (*.grb;*.bz2;*.gz;*.grib2;*.grb2)|*.grb;*.bz2;*.gz;*.grib2;*.grb2|All files (*)|*.*"), wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE
1542 , wxDefaultPosition, wxDefaultSize, _T("File Dialog") );
1543
1544 if( dialog->ShowModal() == wxID_OK ) {
1545
1546 ::wxBeginBusyCursor();
1547
1548 m_grib_dir = dialog->GetDirectory();
1549 dialog->GetPaths(m_file_names);
1550 OpenFile();
1551 DoZoomToCenter();
1552 SetDialogsStyleSizePosition( true );
1553 }
1554 delete dialog;
1555 #else
1556 if( !wxDir::Exists( m_grib_dir ) ) {
1557 wxStandardPathsBase& path = wxStandardPaths::Get();
1558 m_grib_dir = path.GetDocumentsDir();
1559 }
1560
1561 wxString file;
1562 int response = PlatformFileSelectorDialog( NULL, &file, _("Select a GRIB file"),
1563 m_grib_dir, _T(""), _T("*.*") );
1564
1565 if( response == wxID_OK ) {
1566 wxFileName fn(file);
1567 m_grib_dir = fn.GetPath();
1568 m_file_names.Clear();
1569 m_file_names.Add(file);
1570 OpenFile();
1571 SetDialogsStyleSizePosition( true );
1572 }
1573 #endif
1574 }
1575
CreateActiveFileFromNames(const wxArrayString & filenames)1576 void GRIBUICtrlBar::CreateActiveFileFromNames( const wxArrayString &filenames )
1577 {
1578 if( filenames.GetCount() != 0 ) {
1579 m_bGRIBActiveFile = NULL;
1580 m_bGRIBActiveFile = new GRIBFile( filenames , pPlugIn->GetCopyFirstCumRec(),
1581 pPlugIn->GetCopyMissWaveRec() );
1582 }
1583 }
1584
PopulateComboDataList()1585 void GRIBUICtrlBar::PopulateComboDataList()
1586 {
1587 int index = 0;
1588 if( m_cRecordForecast->GetCount() ){
1589 index = m_cRecordForecast->GetCurrentSelection();
1590 m_cRecordForecast->Clear();
1591 }
1592
1593 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1594 for( size_t i = 0; i < rsa->GetCount(); i++ ) {
1595 wxDateTime t( rsa->Item( i ).m_Reference_Time );
1596
1597 m_cRecordForecast->Append( TToString( t, pPlugIn->GetTimeZone() ) );
1598 }
1599 m_cRecordForecast->SetSelection( index );
1600 }
1601
OnZoomToCenterClick(wxCommandEvent & event)1602 void GRIBUICtrlBar::OnZoomToCenterClick( wxCommandEvent& event )
1603 {
1604 DoZoomToCenter();
1605 #if 0
1606 if(!m_pTimelineSet) return;
1607
1608 double latmin,latmax,lonmin,lonmax;
1609 if(!GetGribZoneLimits(m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax ))
1610 return;
1611
1612 //::wxBeginBusyCursor();
1613
1614 //calculate overlay size
1615 double width = lonmax - lonmin;
1616 double height = latmax - latmin;
1617
1618 // Calculate overlay center
1619 double clat = latmin + height / 2;
1620 double clon = lonmin + width / 2;
1621
1622 //try to limit the ppm at a reasonable value
1623 if(width > 120.){
1624 lonmin = clon - 60.;
1625 lonmax = clon + 60.;
1626 }
1627 if(height > 120.){
1628 latmin = clat - 60.;
1629 latmax = clat + 60.;
1630 }
1631
1632
1633 //Calculate overlay width & height in nm (around the center)
1634 double ow, oh;
1635 DistanceBearingMercator_Plugin(clat, lonmin, clat, lonmax, NULL, &ow );
1636 DistanceBearingMercator_Plugin( latmin, clon, latmax, clon, NULL, &oh );
1637
1638 //calculate screen size
1639 int w = pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetWidth();
1640 int h = pPlugIn->GetGRIBOverlayFactory()->m_ParentSize.GetHeight();
1641
1642 //calculate final ppm scale to use
1643 double ppm;
1644 ppm = wxMin(w/(ow*1852), h/(oh*1852)) * ( 100 - fabs( clat ) ) / 90;
1645
1646 ppm = wxMin(ppm, 1.0);
1647
1648 JumpToPosition(clat, clon, ppm);
1649
1650 RequestRefresh( pParent );
1651 #endif
1652
1653 }
1654
DoZoomToCenter()1655 void GRIBUICtrlBar::DoZoomToCenter( )
1656 {
1657 if(!m_pTimelineSet) return;
1658
1659 double latmin,latmax,lonmin,lonmax;
1660 if(!GetGribZoneLimits(m_pTimelineSet, &latmin, &latmax, &lonmin, &lonmax ))
1661 return;
1662
1663 //::wxBeginBusyCursor();
1664
1665 //calculate overlay size
1666 double width = lonmax - lonmin;
1667 double height = latmax - latmin;
1668
1669 // Calculate overlay center
1670 double clat = latmin + height / 2;
1671 double clon = lonmin + width / 2;
1672
1673 //try to limit the ppm at a reasonable value
1674 if(width > 120.){
1675 lonmin = clon - 60.;
1676 lonmax = clon + 60.;
1677 }
1678 if(height > 120.){
1679 latmin = clat - 60.;
1680 latmax = clat + 60.;
1681 }
1682
1683
1684 //Calculate overlay width & height in nm (around the center)
1685 double ow, oh;
1686 DistanceBearingMercator_Plugin(clat, lonmin, clat, lonmax, NULL, &ow );
1687 DistanceBearingMercator_Plugin( latmin, clon, latmax, clon, NULL, &oh );
1688
1689 wxWindow *wx = GetGRIBCanvas();
1690 //calculate screen size
1691 int w = wx->GetSize().x;
1692 int h = wx->GetSize().y;
1693
1694 //calculate final ppm scale to use
1695 double ppm;
1696 ppm = wxMin(w/(ow*1852), h/(oh*1852)) * ( 100 - fabs( clat ) ) / 90;
1697
1698 ppm = wxMin(ppm, 1.0);
1699
1700 CanvasJumpToPosition(wx, clat, clon, ppm);
1701
1702 }
1703
OnPrev(wxCommandEvent & event)1704 void GRIBUICtrlBar::OnPrev( wxCommandEvent& event )
1705 {
1706 if( m_tPlayStop.IsRunning() ) return; // do nothing when play back is running !
1707
1708 RestaureSelectionString();
1709
1710 int selection;
1711 if(m_pNowMode)
1712 selection = GetNearestIndex(GetNow(), 1);
1713 else if(m_InterpolateMode)
1714 selection = GetNearestIndex(TimelineTime(), 1); /* set to interpolated entry */
1715 else
1716 selection = m_cRecordForecast->GetCurrentSelection();
1717
1718 m_pNowMode = false;
1719 m_InterpolateMode = false;
1720
1721 m_cRecordForecast->SetSelection( selection < 1 ? 0: selection - 1 );
1722
1723 TimelineChanged();
1724
1725 }
1726
OnNext(wxCommandEvent & event)1727 void GRIBUICtrlBar::OnNext( wxCommandEvent& event )
1728 {
1729 if( m_tPlayStop.IsRunning() ) return; // do nothing when play back is running !
1730
1731 RestaureSelectionString();
1732
1733 int selection;
1734 if(m_pNowMode)
1735 selection = GetNearestIndex(GetNow(), 2);
1736 else if(m_InterpolateMode)
1737 selection = GetNearestIndex(TimelineTime(), 2); /* set to interpolated entry */
1738 else
1739 selection = m_cRecordForecast->GetCurrentSelection();
1740
1741 m_cRecordForecast->SetSelection( selection );
1742
1743 m_pNowMode = false;
1744 m_InterpolateMode = false;
1745
1746 if( selection == (int)m_cRecordForecast->GetCount() - 1 ) return; //end of list
1747
1748 m_cRecordForecast->SetSelection( selection + 1 );
1749
1750 TimelineChanged();
1751 }
1752
ComputeBestForecastForNow()1753 void GRIBUICtrlBar::ComputeBestForecastForNow()
1754 {
1755 if( !m_bGRIBActiveFile || (m_bGRIBActiveFile && !m_bGRIBActiveFile->IsOK()) ) {
1756 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(NULL);
1757 return;
1758 }
1759
1760 wxDateTime now = GetNow();
1761
1762 if( m_OverlaySettings.m_bInterpolate )
1763 m_sTimeline->SetValue(GetNearestValue(now, 0));
1764 else{
1765 m_cRecordForecast->SetSelection(GetNearestIndex(now, 0));
1766 m_sTimeline->SetValue(m_cRecordForecast->GetCurrentSelection());
1767 }
1768
1769 if( pPlugIn->GetStartOptions() != 2 ) { //no interpolation at start : take the nearest forecast
1770 m_InterpolateMode = m_OverlaySettings.m_bInterpolate;
1771 TimelineChanged();
1772 return;
1773 }
1774 //interpolation on 'now' at start
1775 m_InterpolateMode = true;
1776 m_pNowMode = true;
1777 SetGribTimelineRecordSet(GetTimeLineRecordSet(now)); //take current time & interpolate forecast
1778
1779 RestaureSelectionString(); //eventually restaure the previousely saved wxChoice date time label
1780 m_cRecordForecast->SetSelection(GetNearestIndex(now, 2));
1781 SaveSelectionString(); //memorize the new selected wxChoice date time label
1782 m_cRecordForecast->SetString( m_Selection_index, TToString(now, pPlugIn->GetTimeZone()) ); //write the now date time label in the right place in wxChoice
1783 m_cRecordForecast->SetStringSelection( TToString(now, pPlugIn->GetTimeZone()) ); //put it in the box
1784
1785 UpdateTrackingControl();
1786
1787 pPlugIn->SendTimelineMessage(now);
1788 RequestRefresh( GetGRIBCanvas());
1789 }
1790
SetGribTimelineRecordSet(GribTimelineRecordSet * pTimelineSet)1791 void GRIBUICtrlBar::SetGribTimelineRecordSet(GribTimelineRecordSet *pTimelineSet)
1792 {
1793 delete m_pTimelineSet;
1794 m_pTimelineSet = pTimelineSet;
1795
1796 if(!pPlugIn->GetGRIBOverlayFactory())
1797 return;
1798
1799 pPlugIn->GetGRIBOverlayFactory()->SetGribTimelineRecordSet(m_pTimelineSet);
1800 }
1801
SetTimeLineMax(bool SetValue)1802 void GRIBUICtrlBar::SetTimeLineMax( bool SetValue )
1803 {
1804 int oldmax = wxMax(m_sTimeline->GetMax(), 1), oldval = m_sTimeline->GetValue(); //memorize the old range and value
1805
1806 if(m_OverlaySettings.m_bInterpolate){
1807 int stepmin = m_OverlaySettings.GetMinFromIndex(m_OverlaySettings.m_SlicesPerUpdate);
1808 m_sTimeline->SetMax(m_TimeLineHours * 60 / stepmin );
1809 } else {
1810 if(m_bGRIBActiveFile && m_bGRIBActiveFile->IsOK()) {
1811 ArrayOfGribRecordSets *rsa = m_bGRIBActiveFile->GetRecordSetArrayPtr();
1812 m_sTimeline->SetMax(rsa->GetCount()-1);
1813 }
1814 }
1815 //try to retrieve a coherent timeline value with the new timeline range if it has changed
1816 if( SetValue && m_sTimeline->GetMax() != 0 ) {
1817 if( m_pNowMode )
1818 ComputeBestForecastForNow();
1819 else
1820 m_sTimeline->SetValue( m_sTimeline->GetMax() * oldval / oldmax );
1821 }
1822 }
1823
SetFactoryOptions()1824 void GRIBUICtrlBar::SetFactoryOptions()
1825 {
1826 if(m_pTimelineSet)
1827 m_pTimelineSet->ClearCachedData();
1828
1829 pPlugIn->GetGRIBOverlayFactory()->ClearCachedData();
1830
1831 UpdateTrackingControl();
1832 RequestRefresh( GetGRIBCanvas() );
1833 }
1834
1835 //----------------------------------------------------------------------------------------------------------
1836 // GRIBFile Object Implementation
1837 //----------------------------------------------------------------------------------------------------------
1838 unsigned int GRIBFile::ID = 0;
1839
GRIBFile(const wxArrayString & file_names,bool CumRec,bool WaveRec,bool newestFile)1840 GRIBFile::GRIBFile( const wxArrayString & file_names, bool CumRec, bool WaveRec, bool newestFile ): m_counter(++ID)
1841 {
1842 m_bOK = false; // Assume ok until proven otherwise
1843 m_pGribReader = NULL;
1844 m_last_message = wxEmptyString;
1845 for (unsigned int i = 0; i < file_names.GetCount(); i++) {
1846 wxString file_name = file_names[i];
1847 if( ::wxFileExists( file_name ) )
1848 m_bOK = true;
1849 }
1850
1851 if ( m_bOK == false) {
1852 m_last_message = _( " files don't exist!" );
1853 return;
1854 }
1855 // Use the zyGrib support classes, as (slightly) modified locally....
1856 m_pGribReader = new GribReader();
1857
1858 // Read and ingest the entire GRIB file.......
1859 m_bOK = false;
1860 wxString file_name;
1861 for (unsigned int i = 0; i < file_names.GetCount(); i++) {
1862 file_name = file_names[i];
1863 m_pGribReader->openFile( file_name );
1864
1865 if( m_pGribReader->isOk() ) {
1866 m_bOK = true;
1867 if( newestFile ) {
1868 break;
1869 }
1870 }
1871 }
1872 if ( m_bOK == false) {
1873 m_last_message = _( " can't be read!" );
1874 return;
1875 }
1876
1877 if( newestFile ) {
1878 m_FileNames.Clear();
1879 m_FileNames.Add(file_name);
1880 } else {
1881 m_FileNames = file_names;
1882 }
1883
1884 // fixup Accumulation records
1885 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_TOT, LV_GND_SURF, 0);
1886 m_pGribReader->computeAccumulationRecords(GRB_PRECIP_RATE,LV_GND_SURF, 0);
1887 m_pGribReader->computeAccumulationRecords(GRB_CLOUD_TOT, LV_ATMOS_ALL, 0);
1888
1889 if( CumRec ) m_pGribReader->copyFirstCumulativeRecord(); //add missing records if option selected
1890 if( WaveRec ) m_pGribReader->copyMissingWaveRecords (); // "" ""
1891
1892 m_nGribRecords = m_pGribReader->getTotalNumberOfGribRecords();
1893
1894 // Walk the GribReader date list to populate our array of GribRecordSets
1895
1896 std::set<time_t>::iterator iter;
1897 std::set<time_t> date_list = m_pGribReader->getListDates();
1898 for( iter = date_list.begin(); iter != date_list.end(); iter++ ) {
1899 GribRecordSet *t = new GribRecordSet(m_counter);
1900 time_t reftime = *iter;
1901 t->m_Reference_Time = reftime;
1902 m_GribRecordSetArray.Add( t );
1903 }
1904
1905 // Convert from zyGrib organization by data type/level to our organization by time.
1906
1907 GribRecord *pRec;
1908 bool isOK(false);
1909 bool polarWind(false);
1910 bool polarCurrent(false);
1911 bool sigWave(false);
1912 bool sigH(false);
1913 // Get the map of GribRecord vectors
1914 std::map<std::string, std::vector<GribRecord *>*> *p_map = m_pGribReader->getGribMap();
1915
1916 // Iterate over the map to get vectors of related GribRecords
1917 std::map<std::string, std::vector<GribRecord *>*>::iterator it;
1918 for( it = p_map->begin(); it != p_map->end(); it++ ) {
1919 std::vector<GribRecord *> *ls = ( *it ).second;
1920 for( zuint i = 0; i < ls->size(); i++ ) {
1921 pRec = ls->at( i );
1922 isOK = true;
1923 time_t thistime = pRec->getRecordCurrentDate();
1924
1925 // Search the GribRecordSet array for a GribRecordSet with matching time
1926 for( unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++ ) {
1927 if( m_GribRecordSetArray.Item( j ).m_Reference_Time == thistime ) {
1928 int idx = -1, mdx = -1;
1929 switch(pRec->getDataType()) {
1930 case GRB_WIND_DIR:
1931 polarWind = true;
1932 // fall through
1933 case GRB_WIND_VX:
1934 if(pRec->getLevelType() == LV_ISOBARIC){
1935 switch(pRec->getLevelValue()){
1936 case 300: idx = Idx_WIND_VX300;break;
1937 case 500: idx = Idx_WIND_VX500;break;
1938 case 700: idx = Idx_WIND_VX700;break;
1939 case 850: idx = Idx_WIND_VX850;break;
1940 }
1941 } else
1942 idx = Idx_WIND_VX;
1943 break;
1944 case GRB_WIND_SPEED:
1945 polarWind = true;
1946 // fall through
1947 case GRB_WIND_VY:
1948 if(pRec->getLevelType() == LV_ISOBARIC){
1949 switch(pRec->getLevelValue()){
1950 case 300: idx = Idx_WIND_VY300;break;
1951 case 500: idx = Idx_WIND_VY500;break;
1952 case 700: idx = Idx_WIND_VY700;break;
1953 case 850: idx = Idx_WIND_VY850;break;
1954 }
1955 } else
1956 idx = Idx_WIND_VY;
1957 break;
1958 case GRB_CUR_DIR:
1959 polarCurrent = true;
1960 // fall through
1961 case GRB_UOGRD:
1962 idx = Idx_SEACURRENT_VX;
1963 break;
1964 case GRB_CUR_SPEED:
1965 polarCurrent = true;
1966 // fall through
1967 case GRB_VOGRD:
1968 idx = Idx_SEACURRENT_VY;
1969 break;
1970 case GRB_WIND_GUST: idx = Idx_WIND_GUST; break;
1971 case GRB_PRESSURE: idx = Idx_PRESSURE; break;
1972 case GRB_HTSGW:
1973 sigH = true;
1974 idx = Idx_HTSIGW;
1975 break;
1976 case GRB_PER:
1977 sigWave = true;
1978 idx = Idx_WVPER;
1979 break;
1980 case GRB_DIR:
1981 sigWave = true;
1982 idx = Idx_WVDIR;
1983 break;
1984 case GRB_WVHGT: idx = Idx_HTSIGW; break; // Translation from NOAA WW3
1985 case GRB_WVPER: idx = Idx_WVPER; break;
1986 case GRB_WVDIR: idx = Idx_WVDIR; break;
1987 case GRB_PRECIP_RATE:
1988 case GRB_PRECIP_TOT: idx = Idx_PRECIP_TOT; break;
1989 case GRB_CLOUD_TOT: idx = Idx_CLOUD_TOT; break;
1990 case GRB_TEMP:
1991 if(pRec->getLevelType() == LV_ISOBARIC){
1992 switch(pRec->getLevelValue()){
1993 case 300: idx = Idx_AIR_TEMP300;break;
1994 case 500: idx = Idx_AIR_TEMP500;break;
1995 case 700: idx = Idx_AIR_TEMP700;break;
1996 case 850: idx = Idx_AIR_TEMP850;break;
1997 }
1998 } else
1999 idx = Idx_AIR_TEMP;
2000 if(pRec->getDataCenterModel() == NORWAY_METNO ) mdx = 1000 + NORWAY_METNO;
2001 break;
2002 case GRB_WTMP:
2003 idx = Idx_SEA_TEMP;
2004 if(pRec->getDataCenterModel() == NOAA_GFS ) mdx = 1000 + NOAA_GFS;
2005 break;
2006 case GRB_CAPE: idx = Idx_CAPE;break;
2007 case GRB_COMP_REFL: idx = Idx_COMP_REFL;break;
2008 case GRB_HUMID_REL:
2009 if(pRec->getLevelType() == LV_ISOBARIC){
2010 switch(pRec->getLevelValue()){
2011 case 300: idx = Idx_HUMID_RE300;break;
2012 case 500: idx = Idx_HUMID_RE500;break;
2013 case 700: idx = Idx_HUMID_RE700;break;
2014 case 850: idx = Idx_HUMID_RE850;break;
2015 }
2016 }
2017 break;
2018 case GRB_GEOPOT_HGT:
2019 if(pRec->getLevelType() == LV_ISOBARIC){
2020 switch(pRec->getLevelValue()){
2021 case 300: idx = Idx_GEOP_HGT300;break;
2022 case 500: idx = Idx_GEOP_HGT500;break;
2023 case 700: idx = Idx_GEOP_HGT700;break;
2024 case 850: idx = Idx_GEOP_HGT850;break;
2025 }
2026 }
2027 break;
2028
2029 }
2030 if(idx == -1) {
2031 // XXX bug ?
2032 break;
2033 }
2034
2035 bool skip = false;
2036
2037 if (m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[idx]) {
2038 // already one
2039 GribRecord *oRec = m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[idx];
2040 if (idx == Idx_PRESSURE) {
2041 skip = (oRec->getLevelType() == LV_MSL);
2042 }
2043 else {
2044 // we favor UV over DIR/SPEED
2045 if (polarWind) {
2046 if (oRec->getDataType() == GRB_WIND_VY || oRec->getDataType() == GRB_WIND_VX)
2047 skip = true;
2048 }
2049 if (polarCurrent) {
2050 if (oRec->getDataType() == GRB_UOGRD || oRec->getDataType() == GRB_VOGRD)
2051 skip = true;
2052 }
2053 // favor average aka timeRange == 3 (HRRR subhourly subsets have both 3 and 0 records for winds)
2054 if (!skip && (oRec->getTimeRange() == 3)) {
2055 skip = true;
2056 }
2057 // we favor significant Wave other wind wave.
2058 if (sigH) {
2059 if (oRec->getDataType() == GRB_HTSGW)
2060 skip = true;
2061 }
2062 if (sigWave) {
2063 if (oRec->getDataType() == GRB_DIR || oRec->getDataType() == GRB_PER)
2064 skip = true;
2065 }
2066 }
2067 }
2068 if (!skip) {
2069 m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[idx]= pRec;
2070 if(m_GribIdxArray.Index(idx) == wxNOT_FOUND ) m_GribIdxArray.Add(idx, 1);
2071 if(mdx != -1 && m_GribIdxArray.Index(mdx) == wxNOT_FOUND ) m_GribIdxArray.Add(mdx, 1);
2072 }
2073 break;
2074 }
2075 }
2076 }
2077 }
2078
2079 if (polarWind || polarCurrent) {
2080 for( unsigned int j = 0; j < m_GribRecordSetArray.GetCount(); j++ ) {
2081 for(unsigned int i=0; i<Idx_COUNT; i++) {
2082 int idx = -1;
2083 if (polarWind) {
2084 GribRecord *pRec = m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[i];
2085
2086 if ( pRec != nullptr && pRec->getDataType() == GRB_WIND_DIR) {
2087 switch( i ) {
2088 case Idx_WIND_VX300:
2089 idx = Idx_WIND_VY300;
2090 break;
2091 case Idx_WIND_VX500:
2092 idx = Idx_WIND_VY500;
2093 break;
2094 case Idx_WIND_VX700:
2095 idx = Idx_WIND_VY700;
2096 break;
2097 case Idx_WIND_VX850:
2098 idx = Idx_WIND_VY850;
2099 break;
2100 case Idx_WIND_VX:
2101 idx = Idx_WIND_VY;
2102 break;
2103 default:
2104 break;
2105 }
2106 if (idx != -1) {
2107 GribRecord *pRec1 = m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[idx];
2108 if (pRec1 != nullptr && pRec1->getDataType() == GRB_WIND_SPEED)
2109 GribRecord::Polar2UV(pRec, pRec1);
2110 }
2111 }
2112 }
2113 if (polarCurrent) {
2114 idx = -1;
2115 GribRecord *pRec = m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[i];
2116
2117 if ( pRec != nullptr && pRec->getDataType() == GRB_CUR_DIR) {
2118 switch( i ) {
2119 case Idx_SEACURRENT_VX:
2120 idx = Idx_SEACURRENT_VY;
2121 break;
2122 default:
2123 break;
2124 }
2125 if (idx != -1) {
2126 GribRecord *pRec1 = m_GribRecordSetArray.Item( j ).m_GribRecordPtrArray[idx];
2127 if (pRec1 != nullptr && pRec1->getDataType() == GRB_CUR_SPEED)
2128 GribRecord::Polar2UV(pRec, pRec1);
2129 }
2130 }
2131 }
2132 }
2133 }
2134 }
2135
2136 if(isOK) m_pRefDateTime = pRec->getRecordRefDate(); //to ovoid crash with some bad files
2137 }
2138
~GRIBFile()2139 GRIBFile::~GRIBFile()
2140 {
2141 delete m_pGribReader;
2142 }
2143
2144 //---------------------------------------------------------------------------------------
2145 // GRIB Cursor Data Ctrl & Display implementation
2146 //---------------------------------------------------------------------------------------
GRIBUICData(GRIBUICtrlBar & parent)2147 GRIBUICData::GRIBUICData( GRIBUICtrlBar &parent )
2148 #ifdef __WXOSX__
2149 : GRIBUICDataBase( parent.pParent, CURSOR_DATA, _("GRIB Display Control"), wxDefaultPosition, wxDefaultSize, wxSYSTEM_MENU|wxNO_BORDER|wxSTAY_ON_TOP)
2150 #else
2151 : GRIBUICDataBase( &parent, CURSOR_DATA, _("GRIB Display Control"), wxDefaultPosition, wxDefaultSize, wxSYSTEM_MENU|wxNO_BORDER)
2152 #endif
2153 , m_gpparent(parent)
2154 {
2155 // m_gGrabber = new GribGrabberWin( this );
2156 // fgSizer58->Add( m_gGrabber, 0, wxALL, 0 );
2157
2158 m_gCursorData = new CursorData( this, m_gpparent );
2159 m_fgCdataSizer->Add( m_gCursorData, 0, wxALL, 0 );
2160
2161 Connect( wxEVT_MOVE, wxMoveEventHandler( GRIBUICData::OnMove ) );
2162 }
2163
OnMove(wxMoveEvent & event)2164 void GRIBUICData::OnMove( wxMoveEvent& event )
2165 {
2166 int w, h;
2167 GetScreenPosition( &w, &h );
2168 m_gpparent.pPlugIn->SetCursorDataXY ( wxPoint(w, h) );
2169 }
2170
2171
2172 //---------------------------------------------------------------------------------------
2173 // Android Utility Methods
2174 //---------------------------------------------------------------------------------------
2175 #ifdef __OCPN__ANDROID__
2176
2177 #include <QtAndroidExtras/QAndroidJniObject>
2178
2179 extern JavaVM *java_vm; // found in androidUtil.cpp, accidentally exported....
2180 JNIEnv* jenv;
2181
2182 #if 0 // need this for the solib?
2183 jint JNI_OnLoad(JavaVM *vm, void *reserved)
2184 {
2185 //qDebug() << "JNI_OnLoad";
2186 java_vm = vm;
2187
2188 // Get JNI Env for all function calls
2189 if (vm->GetEnv( (void **) &jenv, JNI_VERSION_1_6) != JNI_OK) {
2190 //qDebug() << "GetEnv failed.";
2191 return -1;
2192 }
2193
2194 }
2195 #endif
2196
CheckPendingJNIException()2197 bool CheckPendingJNIException()
2198 {
2199 if(!java_vm){
2200 //qDebug() << "java_vm is NULL.";
2201 return true;
2202 }
2203
2204 if (java_vm->GetEnv( (void **) &jenv, JNI_VERSION_1_6) != JNI_OK) {
2205 //qDebug() << "GetEnv failed.";
2206 return true;
2207 }
2208
2209 if( (jenv)->ExceptionCheck() == JNI_TRUE ) {
2210 //qDebug() << "Found JNI Exception Pending.";
2211 return true;
2212 }
2213
2214 return false;
2215
2216 }
2217
2218
callActivityMethod_ss(const char * method,wxString parm)2219 wxString callActivityMethod_ss(const char *method, wxString parm)
2220 {
2221 if(CheckPendingJNIException())
2222 return _T("NOK");
2223
2224 wxString return_string;
2225 QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative",
2226 "activity", "()Landroid/app/Activity;");
2227 if(CheckPendingJNIException())
2228 return _T("NOK");
2229
2230 if ( !activity.isValid() ){
2231 //qDebug() << "Activity is not valid";
2232 return return_string;
2233 }
2234
2235 // Need a Java environment to decode the resulting string
2236 if (java_vm &&(java_vm->GetEnv( (void **) &jenv, JNI_VERSION_1_6) != JNI_OK) ){
2237 //qDebug() << "GetEnv failed.";
2238 return _T("jenv Error");
2239 }
2240
2241 jstring p = (jenv)->NewStringUTF(parm.c_str());
2242
2243
2244 // Call the desired method
2245 //qDebug() << "Calling method_ss";
2246 //qDebug() << method;
2247
2248 QAndroidJniObject data = activity.callObjectMethod(method, "(Ljava/lang/String;)Ljava/lang/String;", p);
2249 if(CheckPendingJNIException())
2250 return _T("NOK");
2251
2252 //qDebug() << "Back from method_ss";
2253
2254 jstring s = data.object<jstring>();
2255
2256 if( (jenv)->GetStringLength( s )){
2257 const char *ret_string = (jenv)->GetStringUTFChars(s, NULL);
2258 return_string = wxString(ret_string, wxConvUTF8);
2259 }
2260
2261 return return_string;
2262
2263 }
2264
2265
2266
2267 #endif
2268
2269
2270