OpenCPN Partial API docs
Loading...
Searching...
No Matches
CursorData.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
23#include "pi_gl.h"
24#include "grib_pi.h"
25
26#include "folder.xpm"
27
28extern int m_Altitude;
29extern double m_cursor_lat, m_cursor_lon;
30extern int m_DialogStyle;
31
32//---------------------------------------------------------------------------------------
33// GRIB Cursor Data implementation
34//---------------------------------------------------------------------------------------
35CursorData::CursorData(wxWindow *window, GRIBUICtrlBar &parent)
36 : CursorDataBase(window), m_gparent(parent) {
37 // transform checkboxes ID to have a formal link to data type and set the
38 // initial value
39 wxWindowListNode *node = this->GetChildren().GetFirst();
40 while (node) {
41 wxWindow *win = node->GetData();
42 if (dynamic_cast<wxCheckBox *>(win)) {
43 int winId = dynamic_cast<wxCheckBox *>(win)->GetId() - ID_CB_WIND;
44 if (m_gparent.InDataPlot(winId)) {
45 dynamic_cast<wxCheckBox *>(win)->SetId(winId);
46 dynamic_cast<wxCheckBox *>(win)->SetValue(m_gparent.m_bDataPlot[winId]);
47 }
48 }
49 node = node->GetNext();
50 }
51
52 m_bLeftDown = false;
53
54 m_tCursorTrackTimer.Connect(
55 wxEVT_TIMER, wxTimerEventHandler(CursorData::OnCursorTrackTimer), nullptr,
56 this);
57
58 DimeWindow(this);
59}
60
61void CursorData::OnCBAny(wxCommandEvent &event) {
62 int id = event.GetId();
63 wxWindow *win = this->FindWindow(id);
64 if (m_gparent.InDataPlot(id))
65 m_gparent.m_bDataPlot[id] = ((wxCheckBox *)win)->IsChecked();
66 ResolveDisplayConflicts(id);
67}
68
69void CursorData::ResolveDisplayConflicts(int Id) {
70 // allow multi selection only if there is no display type superposition
71 for (int i = 0; i < GribOverlaySettings::GEO_ALTITUDE; i++) {
72 if (i != Id && m_gparent.m_bDataPlot[i]) {
73 if ((m_gparent.m_OverlaySettings.Settings[Id].m_bBarbedArrows &&
74 m_gparent.m_OverlaySettings.Settings[i].m_bBarbedArrows) ||
75 (m_gparent.m_OverlaySettings.Settings[Id].m_bDirectionArrows &&
76 m_gparent.m_OverlaySettings.Settings[i].m_bDirectionArrows) ||
77 (m_gparent.m_OverlaySettings.Settings[Id].m_bIsoBars &&
78 m_gparent.m_OverlaySettings.Settings[i].m_bIsoBars) ||
79 (m_gparent.m_OverlaySettings.Settings[Id].m_bNumbers &&
80 m_gparent.m_OverlaySettings.Settings[i].m_bNumbers) ||
81 (m_gparent.m_OverlaySettings.Settings[Id].m_bOverlayMap &&
82 m_gparent.m_OverlaySettings.Settings[i].m_bOverlayMap) ||
83 (m_gparent.m_OverlaySettings.Settings[Id].m_bParticles &&
84 m_gparent.m_OverlaySettings.Settings[i].m_bParticles)) {
85 m_gparent.m_bDataPlot[i] = false;
86 wxWindow *win = FindWindow(i);
87 ((wxCheckBox *)win)->SetValue(false);
88 }
89 }
90 }
91 m_gparent.SetFactoryOptions(); // Reload the visibility options
92}
93
94void CursorData::AddTrackingControl(wxControl *ctrl1, wxControl *ctrl2,
95 wxControl *ctrl3, wxControl *ctrl4,
96 bool show, bool vertical, int wctrl2,
97 int wctrl3_4) {
98 if (show) {
99 m_fgTrackingControls->Add(ctrl1, 0, wxALL, 1);
100 ctrl1->Show();
101 if (ctrl2) {
102 m_fgTrackingControls->Add(ctrl2, 0, wxALL, 0);
103 ctrl2->SetMinSize(wxSize(wctrl2, -1));
104 ctrl2->Show();
105 } else
106 m_fgTrackingControls->Add(0, 0, 1, wxALL, 1); /* spacer */
107
108 if (ctrl3) {
109 long flag1 = wxALIGN_CENTER;
110 long flag = vertical ? flag1 : wxALL;
111 m_fgTrackingControls->Add(ctrl3, 0, flag, 0);
112 ctrl3->SetMinSize(wxSize(wctrl3_4, -1));
113 ctrl3->Show();
114 } else if (!vertical)
115 m_fgTrackingControls->Add(0, 0, 1, wxALL, 1); /* spacer */
116
117 if (ctrl4) {
118 m_fgTrackingControls->Add(ctrl4, 0, wxALL, 0);
119 ctrl4->SetMinSize(wxSize(vertical ? wctrl2 : wctrl3_4, -1));
120 ctrl4->Show();
121 } else if (!vertical)
122 m_fgTrackingControls->Add(0, 0, 1, wxALL, 1); /* spacer */
123
124 } else {
125 if (ctrl1) ctrl1->Hide();
126 if (ctrl2) ctrl2->Hide();
127 if (ctrl3) ctrl3->Hide();
128 if (ctrl4) ctrl4->Hide();
129 }
130}
131
132void CursorData::PopulateTrackingControls(bool vertical) {
133 m_fgTrackingControls->Clear();
134 if (!vertical) {
135 wxFlexGridSizer *ps = (wxFlexGridSizer *)(m_gparent.GetSizer());
136 if (ps && (ps->GetCols() == 1))
137 m_fgTrackingControls->SetCols(4); // compact mode
138 else
139 m_fgTrackingControls->SetCols(12);
140 } else
141 m_fgTrackingControls->SetCols(2);
142
143 this->Fit();
144 // Get text controls sizing data
145 wxFont *font = OCPNGetFont(_("Dialog"), 0);
146 int wn, wd, ws, wl;
147 GetTextExtent(_T("abcdefghihjk"), &wn, nullptr, 0, 0,
148 font); // normal width text control size
149 GetTextExtent(_T("abcdef"), &ws, nullptr, 0, 0,
150 font); // short width text control size for direction only
151 GetTextExtent(
152 _T("abcdefghijklmopq"), &wd, nullptr, 0, 0,
153 font); // long width text control size for double unit wind display
154 GetTextExtent(
155 _T("abcdefghijklm"), &wl, nullptr, 0, 0,
156 font); // long width text control size for double unit wave display
157 //
158 // create a dummy textCtrl to be used as a "space" in vertical display
159 wxTextCtrl *dummy =
160 new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
161 wxDefaultSize, wxTE_READONLY | wxNO_BORDER);
162 //
163 bool bf =
164 m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::WIND].m_Units ==
165 GribOverlaySettings::BFS;
166 wd = vertical ? wn : bf ? wn : wd;
167 wl = vertical ? wn : wl;
168
169 AddTrackingControl(m_cbWind, m_tcWindSpeed, m_tcWindSpeedBf,
170 m_tcWindDirection, false, vertical, 0,
171 0); // hide all wind's parameters
172 AddTrackingControl(
173 m_cbWind, m_tcWindSpeed,
174 vertical ? (bf ? dummy : m_tcWindSpeedBf) : m_tcWindDirection,
175 vertical ? m_tcWindDirection : 0,
176 m_gparent.m_pTimelineSet &&
177 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VX) !=
178 wxNOT_FOUND &&
179 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WIND_VY) !=
180 wxNOT_FOUND,
181 vertical, wd, ws);
182 AddTrackingControl(m_cbWindGust, m_tcWindGust, 0, 0,
183 m_gparent.m_pTimelineSet &&
184 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
185 Idx_WIND_GUST) != wxNOT_FOUND &&
186 m_Altitude == 0,
187 vertical, wn);
188 AddTrackingControl(m_cbPressure, m_tcPressure, 0, 0,
189 m_gparent.m_pTimelineSet &&
190 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
191 Idx_PRESSURE) != wxNOT_FOUND &&
192 m_Altitude == 0,
193 vertical, wn);
194
195 /* tracking for wave is funky */
196 AddTrackingControl(m_cbWave, m_tcWaveHeight, m_tcWavePeriode,
197 m_tcWaveDirection, false, vertical, 0,
198 0); // hide all waves's parameters
199 if (m_gparent.m_pTimelineSet &&
200 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_HTSIGW) !=
201 wxNOT_FOUND) {
202 if (m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WVDIR) !=
203 wxNOT_FOUND)
204 AddTrackingControl(m_cbWave, m_tcWaveHeight,
205 vertical ? m_tcWavePeriode : m_tcWaveDirection,
206 vertical ? m_tcWaveDirection : 0, m_Altitude == 0,
207 vertical, wl, ws);
208 else
209 AddTrackingControl(m_cbWave, m_tcWaveHeight, 0, 0, m_Altitude == 0,
210 vertical, wn);
211 } else {
212 if (m_gparent.m_pTimelineSet &&
213 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(Idx_WVDIR) !=
214 wxNOT_FOUND)
215 AddTrackingControl(m_cbWave, m_tcWaveDirection, 0, 0, m_Altitude == 0,
216 vertical, wn);
217 }
218
219 AddTrackingControl(m_cbCurrent, m_tcCurrentVelocity, m_tcCurrentDirection, 0,
220 false, vertical, 0, 0); // hide all current's parameters
221 AddTrackingControl(m_cbCurrent, m_tcCurrentVelocity,
222 vertical ? dummy : m_tcCurrentDirection,
223 vertical ? m_tcCurrentDirection : 0,
224 m_gparent.m_pTimelineSet &&
225 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
226 Idx_SEACURRENT_VX) != wxNOT_FOUND &&
227 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
228 Idx_SEACURRENT_VY) != wxNOT_FOUND &&
229 m_Altitude == 0,
230 vertical, wn, ws);
231 AddTrackingControl(m_cbPrecipitation, m_tcPrecipitation, 0, 0,
232 m_gparent.m_pTimelineSet &&
233 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
234 Idx_PRECIP_TOT) != wxNOT_FOUND &&
235 m_Altitude == 0,
236 vertical, wn);
237 AddTrackingControl(m_cbCloud, m_tcCloud, 0, 0,
238 m_gparent.m_pTimelineSet &&
239 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
240 Idx_CLOUD_TOT) != wxNOT_FOUND &&
241 m_Altitude == 0,
242 vertical, wn);
243 AddTrackingControl(m_cbAirTemperature, m_tcAirTemperature, 0, 0,
244 m_gparent.m_pTimelineSet &&
245 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
246 Idx_AIR_TEMP) != wxNOT_FOUND &&
247 m_Altitude == 0,
248 vertical, wn);
249 AddTrackingControl(m_cbSeaTemperature, m_tcSeaTemperature, 0, 0,
250 m_gparent.m_pTimelineSet &&
251 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
252 Idx_SEA_TEMP) != wxNOT_FOUND &&
253 m_Altitude == 0,
254 vertical, wn);
255 AddTrackingControl(m_cbCAPE, m_tcCAPE, 0, 0,
256 m_gparent.m_pTimelineSet &&
257 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
258 Idx_CAPE) != wxNOT_FOUND &&
259 m_Altitude == 0,
260 vertical, wn);
261 AddTrackingControl(m_cbReflC, m_tcReflC, 0, 0,
262 m_gparent.m_pTimelineSet &&
263 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
264 Idx_COMP_REFL) != wxNOT_FOUND &&
265 m_Altitude == 0,
266 vertical, wn);
267 //
268 // init and show extra parameters for altitude tracking if necessary
269 AddTrackingControl(m_cbAltitude, m_tcAltitude, 0, 0,
270 m_gparent.m_pTimelineSet &&
271 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
272 Idx_GEOP_HGT + m_Altitude) != wxNOT_FOUND &&
273 m_Altitude != 0,
274 vertical, wn);
275 AddTrackingControl(m_cbTemp, m_tcTemp, 0, 0,
276 m_gparent.m_pTimelineSet &&
277 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
278 Idx_AIR_TEMP + m_Altitude) != wxNOT_FOUND &&
279 m_Altitude != 0,
280 vertical, wn);
281 AddTrackingControl(m_cbRelHumid, m_tcRelHumid, 0, 0,
282 m_gparent.m_pTimelineSet &&
283 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
284 Idx_HUMID_RE + m_Altitude) != wxNOT_FOUND &&
285 m_Altitude != 0,
286 vertical, wn);
287 //
288 m_stTrackingText->SetLabel(_("Data at cursor position"));
289 // add tooltips
290 wxString t;
291 double lev;
292
293 lev = m_gparent.m_OverlaySettings.CalibrateValue(
294 GribOverlaySettings::GEO_ALTITUDE,
295 10); // convert 10m in current altitude unit
296 t.Printf(
297 m_Altitude
298 ? m_gparent.m_OverlaySettings
299 .GetAltitudeFromIndex(
300 m_Altitude, m_gparent.m_OverlaySettings
301 .Settings[GribOverlaySettings::PRESSURE]
302 .m_Units)
303 .Append(_T(" "))
304 .Append(m_gparent.m_OverlaySettings.GetUnitSymbol(
305 GribOverlaySettings::PRESSURE))
306 : wxString::Format(_T("%1.*f "), lev == (int)lev ? 0 : 1, lev)
307 .Append(m_gparent.m_OverlaySettings.GetUnitSymbol(
308 GribOverlaySettings::GEO_ALTITUDE)));
309 wxString pre = _T(" ");
310 if (m_Altitude) {
311 pre.Append(_("at Geopotential Height"));
312 pre.Append(_T(" "));
313 m_tcAltitude->SetToolTip(_("Altitude") + t);
314 m_tcTemp->SetToolTip(_("Temperature") + t);
315 m_tcRelHumid->SetToolTip(_("Relative Humidity") + t);
316 } else {
317 pre.Append(_("at"));
318 pre.Append(_T(" "));
319 }
320 t.Prepend(pre);
321
322 m_tcWindSpeed->SetToolTip(_("Wind Speed") + t);
323 m_tcWindSpeedBf->SetToolTip(_("Wind Speed in Bf") + t);
324 m_tcWindDirection->SetToolTip(_("Wind Direction") + t);
325
326 t.Printf(_T(" %1.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
327 GribOverlaySettings::GEO_ALTITUDE),
328 lev == (int)lev ? 0 : 1, lev);
329 m_tcWindGust->SetToolTip(_("Wind Gust at") + t);
330
331 if (m_gparent.m_pTimelineSet) {
332 wxString s[] = {_T(" "), _("Air Temperature at"), _("surface level"),
333 _("Sea Surface Temperature")};
334
335 lev = m_gparent.m_OverlaySettings.CalibrateValue(
336 GribOverlaySettings::GEO_ALTITUDE,
337 2); // convert 2m in current altitude unit
338 t.Printf(m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
339 1000 + NORWAY_METNO) != wxNOT_FOUND
340 ? s[0] + s[2]
341 : _T(" %1.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
342 GribOverlaySettings::GEO_ALTITUDE),
343 lev == (int)lev ? 0 : 1, lev);
344 m_tcAirTemperature->SetToolTip(s[1] + t);
345
346 m_tcSeaTemperature->SetToolTip(
347 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(1000 + NOAA_GFS) !=
348 wxNOT_FOUND
349 ? s[1] + s[0] + s[2]
350 : s[3]);
351 }
352 dummy->Show(false);
353}
354
355void CursorData::UpdateTrackingControls(void) {
356 if (!m_gparent.m_pTimelineSet) return;
357
358 GribRecord **RecordArray = m_gparent.m_pTimelineSet->m_GribRecordPtrArray;
359 // Update the wind control
360 double vkn, ang;
362 vkn, ang, RecordArray[Idx_WIND_VX + m_Altitude],
363 RecordArray[Idx_WIND_VY + m_Altitude], m_cursor_lon, m_cursor_lat)) {
364 double vk = m_gparent.m_OverlaySettings.CalibrateValue(
365 GribOverlaySettings::WIND, vkn);
366
367 m_tcWindSpeed->SetValue(
368 wxString::Format(_T("%3d ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
369 GribOverlaySettings::WIND),
370 (int)round(vk)));
371
372 // wind is a special case: if current unit is not bf ==> double speed
373 // display (current unit + bf)
374 if (m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::WIND]
375 .m_Units != GribOverlaySettings::BFS) {
376 vk = m_gparent.m_OverlaySettings.GetmstobfFactor(vkn) * vkn;
377 if (m_DialogStyle == SEPARATED_VERTICAL)
378 m_tcWindSpeedBf->SetValue(
379 wxString::Format(_T("%2d bf"), (int)round(vk)));
380 else
381 m_tcWindSpeed->SetValue(
382 m_tcWindSpeed->GetValue().Append(_T(" - ")).Append(
383 wxString::Format(_T("%2d bf"), (int)round(vk))));
384 }
385
386 m_tcWindDirection->SetValue(
387 wxString::Format(_T("%03d%c"), (int)(ang), 0x00B0));
388 } else {
389 m_tcWindSpeed->SetValue(_("N/A"));
390 m_tcWindSpeedBf->SetValue(_("N/A"));
391 m_tcWindDirection->SetValue(_("N/A"));
392 }
393
394 // Update the Wind gusts control
395 if (RecordArray[Idx_WIND_GUST]) {
396 double vkn = RecordArray[Idx_WIND_GUST]->getInterpolatedValue(
397 m_cursor_lon, m_cursor_lat, true);
398
399 if (vkn != GRIB_NOTDEF) {
400 vkn = m_gparent.m_OverlaySettings.CalibrateValue(
401 GribOverlaySettings::WIND_GUST, vkn);
402 m_tcWindGust->SetValue(wxString::Format(
403 _T("%2d ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
404 GribOverlaySettings::WIND_GUST),
405 (int)round(vkn)));
406 } else
407 m_tcWindGust->SetValue(_("N/A"));
408 }
409
410 // Update the Pressure control
411 if (RecordArray[Idx_PRESSURE]) {
412 double press = RecordArray[Idx_PRESSURE]->getInterpolatedValue(
413 m_cursor_lon, m_cursor_lat, true);
414
415 if (press != GRIB_NOTDEF) {
416 press = m_gparent.m_OverlaySettings.CalibrateValue(
417 GribOverlaySettings::PRESSURE, press);
418 int p =
419 (m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::PRESSURE]
420 .m_Units == 2)
421 ? 2
422 : 1; // if PRESSURE & inHG = two decimals
423 m_tcPressure->SetValue(wxString::Format(
424 _T("%2.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
425 GribOverlaySettings::PRESSURE),
426 p, (press)));
427 } else
428 m_tcPressure->SetValue(_("N/A"));
429 }
430
431 // Update the Sig Wave Height
432 if (RecordArray[Idx_HTSIGW]) {
433 double height = RecordArray[Idx_HTSIGW]->getInterpolatedValue(
434 m_cursor_lon, m_cursor_lat, true);
435
436 if (height != GRIB_NOTDEF) {
437 height = m_gparent.m_OverlaySettings.CalibrateValue(
438 GribOverlaySettings::WAVE, height);
439 wxString w(wxString::Format(
440 _T("%4.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
441 GribOverlaySettings::WAVE),
442 height));
443 if (RecordArray[Idx_WVPER]) {
444 double period = RecordArray[Idx_WVPER]->getInterpolatedValue(
445 m_cursor_lon, m_cursor_lat, true);
446 if (period != GRIB_NOTDEF) {
447 if (m_DialogStyle == SEPARATED_VERTICAL)
448 m_tcWavePeriode->SetValue(
449 wxString::Format(_T("%01ds"), (int)round(period)));
450 else
451 w.Append(wxString::Format(_T(" - %01ds"), (int)round(period)));
452 } else
453 m_tcWavePeriode->SetValue(_("N/A"));
454 } else
455 m_tcWavePeriode->SetValue(_("N/A"));
456
457 m_tcWaveHeight->SetValue(w);
458 } else
459 m_tcWaveHeight->SetValue(_("N/A"));
460 }
461
462 // Update the Wave direction
463 if (RecordArray[Idx_WVDIR]) {
464 double direction = RecordArray[Idx_WVDIR]->getInterpolatedValue(
465 m_cursor_lon, m_cursor_lat, true, true);
466 if (direction != GRIB_NOTDEF)
467 m_tcWaveDirection->SetValue(
468 wxString::Format(_T("%03d%c"), (int)direction, 0x00B0));
469 else
470 m_tcWaveDirection->SetValue(_("N/A"));
471 }
472
473 // Update the Current control
475 vkn, ang, RecordArray[Idx_SEACURRENT_VX],
476 RecordArray[Idx_SEACURRENT_VY], m_cursor_lon, m_cursor_lat)) {
477 // Current direction is generally reported as the "flow" direction,
478 // which is opposite from wind convention.
479 // So, adjust.
480 ang += 180;
481 if (ang >= 360) ang -= 360;
482 if (ang < 0) ang += 360;
483
484 vkn = m_gparent.m_OverlaySettings.CalibrateValue(
485 GribOverlaySettings::CURRENT, vkn);
486
487 m_tcCurrentVelocity->SetValue(wxString::Format(
488 _T("%4.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
489 GribOverlaySettings::CURRENT),
490 vkn));
491
492 m_tcCurrentDirection->SetValue(
493 wxString::Format(_T("%03d%c"), (int)(ang), 0x00B0));
494 } else {
495 m_tcCurrentVelocity->SetValue(_("N/A"));
496 m_tcCurrentDirection->SetValue(_("N/A"));
497 }
498
499 // Update total rainfall control
500 if (RecordArray[Idx_PRECIP_TOT]) {
501 double precip = RecordArray[Idx_PRECIP_TOT]->getInterpolatedValue(
502 m_cursor_lon, m_cursor_lat, true);
503
504 if (precip != GRIB_NOTDEF) {
505 precip = m_gparent.m_OverlaySettings.CalibrateValue(
506 GribOverlaySettings::PRECIPITATION, precip);
507 int p = precip < 10. ? 2 : precip < 100. ? 1 : 0;
508 p += m_gparent.m_OverlaySettings
509 .Settings[GribOverlaySettings::PRECIPITATION]
510 .m_Units == 1
511 ? 1
512 : 0; // if PRESSURE & in = one decimal more
513 m_tcPrecipitation->SetValue(wxString::Format(
514 _T("%4.*f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
515 GribOverlaySettings::PRECIPITATION),
516 p, precip));
517 } else
518 m_tcPrecipitation->SetValue(_("N/A"));
519 }
520
521 // Update total cloud control
522 if (RecordArray[Idx_CLOUD_TOT]) {
523 double cloud = RecordArray[Idx_CLOUD_TOT]->getInterpolatedValue(
524 m_cursor_lon, m_cursor_lat, true);
525
526 if (cloud != GRIB_NOTDEF) {
527 cloud = m_gparent.m_OverlaySettings.CalibrateValue(
528 GribOverlaySettings::CLOUD, cloud);
529 wxString val(wxString::Format(_T("%5.0f "), cloud));
530 m_tcCloud->SetValue(val + m_gparent.m_OverlaySettings.GetUnitSymbol(
531 GribOverlaySettings::CLOUD));
532 } else
533 m_tcCloud->SetValue(_("N/A"));
534 }
535
536 // Update the Air Temperature
537 if (RecordArray[Idx_AIR_TEMP]) {
538 double temp = RecordArray[Idx_AIR_TEMP]->getInterpolatedValue(
539 m_cursor_lon, m_cursor_lat, true);
540
541 if (temp != GRIB_NOTDEF) {
542 temp = m_gparent.m_OverlaySettings.CalibrateValue(
543 GribOverlaySettings::AIR_TEMPERATURE, temp);
544 m_tcAirTemperature->SetValue(wxString::Format(
545 _T("%5.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
546 GribOverlaySettings::AIR_TEMPERATURE),
547 temp));
548 } else
549 m_tcAirTemperature->SetValue(_("N/A"));
550 }
551
552 // Update the Sea Surface Temperature
553 if (RecordArray[Idx_SEA_TEMP]) {
554 double temp = RecordArray[Idx_SEA_TEMP]->getInterpolatedValue(
555 m_cursor_lon, m_cursor_lat, true);
556
557 if (temp != GRIB_NOTDEF) {
558 temp = m_gparent.m_OverlaySettings.CalibrateValue(
559 GribOverlaySettings::SEA_TEMPERATURE, temp);
560 m_tcSeaTemperature->SetValue(wxString::Format(
561 _T("%5.1f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
562 GribOverlaySettings::SEA_TEMPERATURE),
563 temp));
564 } else
565 m_tcSeaTemperature->SetValue(_("N/A"));
566 }
567
568 // Update the Convective Available Potential Energy (CAPE)
569 if (RecordArray[Idx_CAPE]) {
570 double cape = RecordArray[Idx_CAPE]->getInterpolatedValue(
571 m_cursor_lon, m_cursor_lat, true);
572
573 if (cape != GRIB_NOTDEF) {
574 cape = m_gparent.m_OverlaySettings.CalibrateValue(
575 GribOverlaySettings::CAPE, cape);
576 m_tcCAPE->SetValue(wxString::Format(
577 _T("%5.0f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
578 GribOverlaySettings::CAPE),
579 cape));
580 } else
581 m_tcCAPE->SetValue(_("N/A"));
582 }
583 if (RecordArray[Idx_COMP_REFL]) {
584 double c_refl = RecordArray[Idx_COMP_REFL]->getInterpolatedValue(
585 m_cursor_lon, m_cursor_lat, true);
586
587 if (c_refl != GRIB_NOTDEF) {
588 c_refl = m_gparent.m_OverlaySettings.CalibrateValue(
589 GribOverlaySettings::COMP_REFL, c_refl);
590 m_tcReflC->SetValue(wxString::Format(
591 _T("%5.0f ") + m_gparent.m_OverlaySettings.GetUnitSymbol(
592 GribOverlaySettings::COMP_REFL),
593 c_refl));
594 } else
595 m_tcReflC->SetValue(_("N/A"));
596 }
597 // Update extra data for altitude
598 // geopotential altitude
599 if (RecordArray[Idx_GEOP_HGT + m_Altitude]) {
600 double geop = RecordArray[Idx_GEOP_HGT + m_Altitude]->getInterpolatedValue(
601 m_cursor_lon, m_cursor_lat, true);
602
603 if (geop != GRIB_NOTDEF) {
604 geop = m_gparent.m_OverlaySettings.CalibrateValue(
605 GribOverlaySettings::GEO_ALTITUDE, geop);
606 m_tcAltitude->SetValue(wxString::Format(_T("%5.0f "), geop) +
607 m_gparent.m_OverlaySettings.GetUnitSymbol(
608 GribOverlaySettings::GEO_ALTITUDE));
609 } else
610 m_tcAltitude->SetValue(_("N/A"));
611 }
612
613 // temperature
614 if (RecordArray[Idx_AIR_TEMP + m_Altitude]) {
615 double temp = RecordArray[Idx_AIR_TEMP + m_Altitude]->getInterpolatedValue(
616 m_cursor_lon, m_cursor_lat, true);
617
618 if (temp != GRIB_NOTDEF) {
619 temp = m_gparent.m_OverlaySettings.CalibrateValue(
620 GribOverlaySettings::AIR_TEMPERATURE, temp);
621 m_tcTemp->SetValue(wxString::Format(_T("%5.1f "), temp) +
622 m_gparent.m_OverlaySettings.GetUnitSymbol(
623 GribOverlaySettings::AIR_TEMPERATURE));
624 } else
625 m_tcTemp->SetValue(_("N/A"));
626 }
627 // relative humidity
628 if (RecordArray[Idx_HUMID_RE + m_Altitude]) {
629 double humi = RecordArray[Idx_HUMID_RE + m_Altitude]->getInterpolatedValue(
630 m_cursor_lon, m_cursor_lat, true);
631
632 if (humi != GRIB_NOTDEF) {
633 humi = m_gparent.m_OverlaySettings.CalibrateValue(
634 GribOverlaySettings::REL_HUMIDITY, humi);
635 m_tcRelHumid->SetValue(wxString::Format(_T("%5.0f "), humi) +
636 m_gparent.m_OverlaySettings.GetUnitSymbol(
637 GribOverlaySettings::REL_HUMIDITY));
638 } else
639 m_tcRelHumid->SetValue(_("N/A"));
640 }
641}
642
643void CursorData::OnMenuCallBack(wxMouseEvent &event) {
644 // populate menu
645 wxMenu *menu = new wxMenu();
646 int id = event.GetId();
647 switch (id) {
648 case GribOverlaySettings::WIND:
649 MenuAppend(menu, B_ARROWS, _("Barbed Arrows"), id);
650 MenuAppend(menu, ISO_LINE, _("Display Isotachs"), id);
651 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
652 MenuAppend(menu, NUMBERS, _("Numbers"), id);
653 MenuAppend(menu, PARTICLES, _("Particle Map"), id);
654 break;
655 case GribOverlaySettings::WIND_GUST:
656 MenuAppend(menu, ISO_LINE, _("Display Isotachs"), id);
657 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
658 MenuAppend(menu, NUMBERS, _("Numbers"), id);
659 break;
660 case GribOverlaySettings::PRESSURE:
661 MenuAppend(menu, ISO_LINE, _("Display Isobars"), id);
662 MenuAppend(menu, ISO_ABBR, _("Abbreviated Isobars Numbers"), id);
663 MenuAppend(menu, NUMBERS, _("Numbers"), id);
664 break;
665 case GribOverlaySettings::AIR_TEMPERATURE:
666 case GribOverlaySettings::SEA_TEMPERATURE:
667 MenuAppend(menu, ISO_LINE, _("Display Isotherms"), id);
668 // fall through
669 case GribOverlaySettings::CLOUD:
670 case GribOverlaySettings::PRECIPITATION:
671 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
672 MenuAppend(menu, NUMBERS, _("Numbers"), id);
673 break;
674 case GribOverlaySettings::CAPE:
675 MenuAppend(menu, ISO_LINE, _("Display Iso CAPE"), id);
676 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
677 MenuAppend(menu, NUMBERS, _("Numbers"), id);
678 break;
679 case GribOverlaySettings::COMP_REFL:
680 MenuAppend(menu, ISO_LINE, _("Display Iso Reflectivity"), id);
681 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
682 MenuAppend(menu, NUMBERS, _("Numbers"), id);
683 break;
684 case GribOverlaySettings::WAVE:
685 MenuAppend(menu, D_ARROWS, _("Direction Arrows"), id);
686 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
687 MenuAppend(menu, NUMBERS, _("Numbers"), id);
688 break;
689 case GribOverlaySettings::CURRENT:
690 MenuAppend(menu, D_ARROWS, _("Direction Arrows"), id);
691 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
692 MenuAppend(menu, NUMBERS, _("Numbers"), id);
693 MenuAppend(menu, PARTICLES, _("Particle Map"), id);
694 }
695
696 PopupMenu(menu);
697
698 // apply new config
699 wxwxMenuItemListNode *node = menu->GetMenuItems().GetFirst();
700 while (node) {
701 wxMenuItem *it = node->GetData();
702 switch (it->GetId()) {
703 case B_ARROWS:
704 m_gparent.m_OverlaySettings.Settings[id].m_bBarbedArrows =
705 it->IsChecked();
706 break;
707 case ISO_LINE:
708 m_gparent.m_OverlaySettings.Settings[id].m_bIsoBars = it->IsChecked();
709 break;
710 case ISO_ABBR:
711 m_gparent.m_OverlaySettings.Settings[id].m_bAbbrIsoBarsNumbers =
712 it->IsChecked();
713 break;
714 case D_ARROWS:
715 m_gparent.m_OverlaySettings.Settings[id].m_bDirectionArrows =
716 it->IsChecked();
717 break;
718 case OVERLAY:
719 m_gparent.m_OverlaySettings.Settings[id].m_bOverlayMap =
720 it->IsChecked();
721 break;
722 case NUMBERS:
723 m_gparent.m_OverlaySettings.Settings[id].m_bNumbers = it->IsChecked();
724 break;
725 case PARTICLES:
726 m_gparent.m_OverlaySettings.Settings[id].m_bParticles = it->IsChecked();
727 }
728 node = node->GetNext();
729 }
730
731 // if the current parameter type is selected then resolve display conflicts
732 if (m_gparent.InDataPlot(id) && m_gparent.m_bDataPlot[id])
733 ResolveDisplayConflicts(id);
734
735 // save new config
736 m_gparent.m_OverlaySettings.Write();
737
738 delete menu;
739}
740
741void CursorData::MenuAppend(wxMenu *menu, int id, wxString label, int setting) {
742 wxMenuItem *item = new wxMenuItem(menu, id, label, _T(""), wxITEM_CHECK);
743
744#ifdef __WXMSW__
745 wxFont *qFont = OCPNGetFont(_("Menu"), 0);
746 item->SetFont(*qFont);
747#endif
748
749 menu->Append(item);
750
751 bool check;
752 if (id == B_ARROWS)
753 check = m_gparent.m_OverlaySettings.Settings[setting].m_bBarbedArrows;
754 else if (id == ISO_LINE)
755 check = m_gparent.m_OverlaySettings.Settings[setting].m_bIsoBars;
756 else if (id == ISO_ABBR)
757 check = m_gparent.m_OverlaySettings.Settings[setting].m_bAbbrIsoBarsNumbers;
758 else if (id == D_ARROWS)
759 check = m_gparent.m_OverlaySettings.Settings[setting].m_bDirectionArrows;
760 else if (id == OVERLAY)
761 check = m_gparent.m_OverlaySettings.Settings[setting].m_bOverlayMap;
762 else if (id == NUMBERS)
763 check = m_gparent.m_OverlaySettings.Settings[setting].m_bNumbers;
764 else if (id == PARTICLES)
765 check = m_gparent.m_OverlaySettings.Settings[setting].m_bParticles;
766 else
767 check = false;
768 item->Check(check);
769}
770
771void CursorData::OnMouseEvent(wxMouseEvent &event) {
772 if (event.RightDown()) {
773 if (m_DialogStyle >> 1 == ATTACHED) {
774 wxMouseEvent evt(event);
775 m_gparent.OnMouseEvent(evt);
776 }
777 return;
778 }
779
780 static wxPoint s_gspt;
781 int x, y;
782
783 event.GetPosition(&x, &y);
784 wxPoint spt = wxPoint(x, y);
785 if (event.GetId() != 1000)
786 spt = ClientToScreen(spt);
787 else
788 spt = GetParent()->ClientToScreen(spt);
789
790#ifdef __WXOSX__
791 if (!m_bLeftDown && event.LeftIsDown()) {
792 m_bLeftDown = true;
793 s_gspt = spt;
794 if (!HasCapture()) CaptureMouse();
795 } else if (m_bLeftDown && !event.LeftIsDown()) {
796 // GetParent()->Move( GetParent()->GetPosition() );
797 m_bLeftDown = false;
798 if (HasCapture()) ReleaseMouse();
799 }
800#else
801
802 if (event.LeftDown()) {
803 s_gspt = spt;
804 if (!HasCapture()) CaptureMouse();
805 }
806
807 if (event.LeftUp()) {
808 // GetParent()->Move( GetParent()->GetPosition() );
809 if (HasCapture()) ReleaseMouse();
810 }
811#endif
812
813 if (event.Dragging()) {
814 wxPoint par_pos_old = GetParent()->GetPosition();
815
816 wxPoint par_pos = par_pos_old;
817 par_pos.x += spt.x - s_gspt.x;
818 par_pos.y += spt.y - s_gspt.y;
819
820 wxPoint pos_in_parent = GetOCPNCanvasWindow()->ScreenToClient(par_pos);
821 wxPoint pos_in_parent_old =
822 GetOCPNCanvasWindow()->ScreenToClient(par_pos_old);
823
824 // X
825 if (pos_in_parent.x < pos_in_parent_old.x) { // moving left
826 if (pos_in_parent.x < 10) {
827 pos_in_parent.x = 0;
828 }
829 } else if (pos_in_parent.x > pos_in_parent_old.x) { // moving right
830 int max_right =
831 GetOCPNCanvasWindow()->GetClientSize().x - GetParent()->GetSize().x;
832 if (pos_in_parent.x > (max_right - 10)) {
833 pos_in_parent.x = max_right;
834 }
835 }
836
837 // Y
838 if (pos_in_parent.y < pos_in_parent_old.y) { // moving up
839 if (pos_in_parent.y < 10) {
840 pos_in_parent.y = 0;
841 }
842 } else if (pos_in_parent.y > pos_in_parent_old.y) { // moving dow
843 int max_down =
844 GetOCPNCanvasWindow()->GetClientSize().y - GetParent()->GetSize().y;
845 if (pos_in_parent.y > (max_down - 10)) {
846 pos_in_parent.y = max_down;
847 }
848 }
849
850 wxPoint final_pos = GetOCPNCanvasWindow()->ClientToScreen(pos_in_parent);
851
852 GetParent()->Move(final_pos);
853
854 s_gspt = spt;
855 }
856}
@ Idx_COMP_REFL
Composite radar reflectivity.
@ Idx_PRECIP_TOT
Total precipitation.
@ Idx_AIR_TEMP
Air temperature at 2m.
@ Idx_PRESSURE
Surface pressure.
@ Idx_WVDIR
Wave direction.
@ Idx_CLOUD_TOT
Total cloud cover.
@ Idx_WIND_GUST
Wind gust speed at surface.
@ Idx_WIND_VX
Surface wind velocity X component.
@ Idx_WVPER
Wave period.
@ Idx_HTSIGW
Significant wave height.
@ Idx_HUMID_RE
Surface relative humidity.
@ Idx_SEACURRENT_VY
Sea current velocity Y component.
@ Idx_GEOP_HGT
Surface geopotential height.
@ Idx_SEA_TEMP
Sea surface temperature.
@ Idx_WIND_VY
Surface wind velocity Y component.
@ Idx_SEACURRENT_VX
Sea current velocity X component.
@ Idx_CAPE
Convective Available Potential Energy.
Class CursorDataBase.
GribOverlaySettings m_OverlaySettings
Settings that control how GRIB data is displayed and overlaid.
GRIBFile * m_bGRIBActiveFile
Currently active GRIB file being displayed.
GribTimelineRecordSet * m_pTimelineSet
Current set of GRIB records for timeline playback.
GribRecord * m_GribRecordPtrArray[Idx_COUNT]
Array of pointers to GRIB records representing different meteorological parameters.
Represents a meteorological data grid from a GRIB (Gridded Binary) file.
Definition GribRecord.h:182
double getInterpolatedValue(double px, double py, bool numericalInterpolation=true, bool dir=false) const
Get spatially interpolated value at exact lat/lon position.
static bool getInterpolatedValues(double &M, double &A, const GribRecord *GRX, const GribRecord *GRY, double px, double py, bool numericalInterpolation=true)
Gets spatially interpolated wind or current vector values at a specific latitude/longitude point.
GRIB Weather Data Plugin for OpenCPN.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
OpenGL Platform Abstraction Layer.