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"));
146 int wn, wd, ws, wl;
147 GetTextExtent("abcdefghihjk", &wn, nullptr, 0, 0,
148 font); // normal width text control size
149 GetTextExtent("abcdef", &ws, nullptr, 0, 0,
150 font); // short width text control size for direction only
151 GetTextExtent(
152 "abcdefghijklmopq", &wd, nullptr, 0, 0,
153 font); // long width text control size for double unit wind display
154 GetTextExtent(
155 "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(m_Altitude ? m_gparent.m_OverlaySettings
297 .GetAltitudeFromIndex(
298 m_Altitude,
299 m_gparent.m_OverlaySettings
300 .Settings[GribOverlaySettings::PRESSURE]
301 .m_Units)
302 .Append(" ")
303 .Append(m_gparent.m_OverlaySettings.GetUnitSymbol(
304 GribOverlaySettings::PRESSURE))
305 : wxString::Format("%1.*f ", lev == (int)lev ? 0 : 1, lev)
306 .Append(m_gparent.m_OverlaySettings.GetUnitSymbol(
307 GribOverlaySettings::GEO_ALTITUDE)));
308 wxString pre = " ";
309 if (m_Altitude) {
310 pre.Append(_("at Geopotential Height"));
311 pre.Append(" ");
312 m_tcAltitude->SetToolTip(_("Altitude") + t);
313 m_tcTemp->SetToolTip(_("Temperature") + t);
314 m_tcRelHumid->SetToolTip(_("Relative Humidity") + t);
315 } else {
316 pre.Append(_("at"));
317 pre.Append(" ");
318 }
319 t.Prepend(pre);
320
321 m_tcWindSpeed->SetToolTip(_("Wind Speed") + t);
322 m_tcWindSpeedBf->SetToolTip(_("Wind Speed in Bf") + t);
323 m_tcWindDirection->SetToolTip(_("Wind Direction") + t);
324
325 t.Printf(" %1.*f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
326 GribOverlaySettings::GEO_ALTITUDE),
327 lev == (int)lev ? 0 : 1, lev);
328 m_tcWindGust->SetToolTip(_("Wind Gust at") + t);
329
330 if (m_gparent.m_pTimelineSet) {
331 wxString s[] = {" ", _("Air Temperature at"), _("surface level"),
332 _("Sea Surface Temperature")};
333
334 lev = m_gparent.m_OverlaySettings.CalibrateValue(
335 GribOverlaySettings::GEO_ALTITUDE,
336 2); // convert 2m in current altitude unit
337 t.Printf(m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(
338 1000 + NORWAY_METNO) != wxNOT_FOUND
339 ? s[0] + s[2]
340 : " %1.*f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
341 GribOverlaySettings::GEO_ALTITUDE),
342 lev == (int)lev ? 0 : 1, lev);
343 m_tcAirTemperature->SetToolTip(s[1] + t);
344
345 m_tcSeaTemperature->SetToolTip(
346 m_gparent.m_bGRIBActiveFile->m_GribIdxArray.Index(1000 + NOAA_GFS) !=
347 wxNOT_FOUND
348 ? s[1] + s[0] + s[2]
349 : s[3]);
350 }
351 dummy->Show(false);
352}
353
354void CursorData::UpdateTrackingControls(void) {
355 if (!m_gparent.m_pTimelineSet) return;
356
357 GribRecord **RecordArray = m_gparent.m_pTimelineSet->m_GribRecordPtrArray;
358 // Update the wind control
359 double vkn, ang;
361 vkn, ang, RecordArray[Idx_WIND_VX + m_Altitude],
362 RecordArray[Idx_WIND_VY + m_Altitude], m_cursor_lon, m_cursor_lat)) {
363 double vk = m_gparent.m_OverlaySettings.CalibrateValue(
364 GribOverlaySettings::WIND, vkn);
365
366 m_tcWindSpeed->SetValue(
367 wxString::Format("%3d " + m_gparent.m_OverlaySettings.GetUnitSymbol(
368 GribOverlaySettings::WIND),
369 (int)round(vk)));
370
371 // wind is a special case: if current unit is not bf ==> double speed
372 // display (current unit + bf)
373 if (m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::WIND]
374 .m_Units != GribOverlaySettings::BFS) {
375 vk = m_gparent.m_OverlaySettings.GetmstobfFactor(vkn) * vkn;
376 if (m_DialogStyle == SEPARATED_VERTICAL)
377 m_tcWindSpeedBf->SetValue(wxString::Format("%2d bf", (int)round(vk)));
378 else
379 m_tcWindSpeed->SetValue(m_tcWindSpeed->GetValue().Append(" - ").Append(
380 wxString::Format("%2d bf", (int)round(vk))));
381 }
382
383 m_tcWindDirection->SetValue(wxString::Format("%03d%c", (int)(ang), 0x00B0));
384 } else {
385 m_tcWindSpeed->SetValue(_("N/A"));
386 m_tcWindSpeedBf->SetValue(_("N/A"));
387 m_tcWindDirection->SetValue(_("N/A"));
388 }
389
390 // Update the Wind gusts control
391 if (RecordArray[Idx_WIND_GUST]) {
392 double vkn = RecordArray[Idx_WIND_GUST]->getInterpolatedValue(
393 m_cursor_lon, m_cursor_lat, true);
394
395 if (vkn != GRIB_NOTDEF) {
396 vkn = m_gparent.m_OverlaySettings.CalibrateValue(
397 GribOverlaySettings::WIND_GUST, vkn);
398 m_tcWindGust->SetValue(
399 wxString::Format("%2d " + m_gparent.m_OverlaySettings.GetUnitSymbol(
400 GribOverlaySettings::WIND_GUST),
401 (int)round(vkn)));
402 } else
403 m_tcWindGust->SetValue(_("N/A"));
404 }
405
406 // Update the Pressure control
407 if (RecordArray[Idx_PRESSURE]) {
408 double press = RecordArray[Idx_PRESSURE]->getInterpolatedValue(
409 m_cursor_lon, m_cursor_lat, true);
410
411 if (press != GRIB_NOTDEF) {
412 press = m_gparent.m_OverlaySettings.CalibrateValue(
413 GribOverlaySettings::PRESSURE, press);
414 int p =
415 (m_gparent.m_OverlaySettings.Settings[GribOverlaySettings::PRESSURE]
416 .m_Units == 2)
417 ? 2
418 : 1; // if PRESSURE & inHG = two decimals
419 m_tcPressure->SetValue(
420 wxString::Format("%2.*f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
421 GribOverlaySettings::PRESSURE),
422 p, (press)));
423 } else
424 m_tcPressure->SetValue(_("N/A"));
425 }
426
427 // Update the Sig Wave Height
428 if (RecordArray[Idx_HTSIGW]) {
429 double height = RecordArray[Idx_HTSIGW]->getInterpolatedValue(
430 m_cursor_lon, m_cursor_lat, true);
431
432 if (height != GRIB_NOTDEF) {
433 height = m_gparent.m_OverlaySettings.CalibrateValue(
434 GribOverlaySettings::WAVE, height);
435 wxString w(
436 wxString::Format("%4.1f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
437 GribOverlaySettings::WAVE),
438 height));
439 if (RecordArray[Idx_WVPER]) {
440 double period = RecordArray[Idx_WVPER]->getInterpolatedValue(
441 m_cursor_lon, m_cursor_lat, true);
442 if (period != GRIB_NOTDEF) {
443 if (m_DialogStyle == SEPARATED_VERTICAL)
444 m_tcWavePeriode->SetValue(
445 wxString::Format("%01ds", (int)round(period)));
446 else
447 w.Append(wxString::Format(" - %01ds", (int)round(period)));
448 } else
449 m_tcWavePeriode->SetValue(_("N/A"));
450 } else
451 m_tcWavePeriode->SetValue(_("N/A"));
452
453 m_tcWaveHeight->SetValue(w);
454 } else
455 m_tcWaveHeight->SetValue(_("N/A"));
456 }
457
458 // Update the Wave direction
459 if (RecordArray[Idx_WVDIR]) {
460 double direction = RecordArray[Idx_WVDIR]->getInterpolatedValue(
461 m_cursor_lon, m_cursor_lat, true, true);
462 if (direction != GRIB_NOTDEF)
463 m_tcWaveDirection->SetValue(
464 wxString::Format("%03d%c", (int)direction, 0x00B0));
465 else
466 m_tcWaveDirection->SetValue(_("N/A"));
467 }
468
469 // Update the Current control
471 vkn, ang, RecordArray[Idx_SEACURRENT_VX],
472 RecordArray[Idx_SEACURRENT_VY], m_cursor_lon, m_cursor_lat)) {
473 // Current direction is generally reported as the "flow" direction,
474 // which is opposite from wind convention.
475 // So, adjust.
476 ang += 180;
477 if (ang >= 360) ang -= 360;
478 if (ang < 0) ang += 360;
479
480 vkn = m_gparent.m_OverlaySettings.CalibrateValue(
481 GribOverlaySettings::CURRENT, vkn);
482
483 m_tcCurrentVelocity->SetValue(
484 wxString::Format("%4.1f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
485 GribOverlaySettings::CURRENT),
486 vkn));
487
488 m_tcCurrentDirection->SetValue(
489 wxString::Format("%03d%c", (int)(ang), 0x00B0));
490 } else {
491 m_tcCurrentVelocity->SetValue(_("N/A"));
492 m_tcCurrentDirection->SetValue(_("N/A"));
493 }
494
495 // Update total rainfall control
496 if (RecordArray[Idx_PRECIP_TOT]) {
497 double precip = RecordArray[Idx_PRECIP_TOT]->getInterpolatedValue(
498 m_cursor_lon, m_cursor_lat, true);
499
500 if (precip != GRIB_NOTDEF) {
501 precip = m_gparent.m_OverlaySettings.CalibrateValue(
502 GribOverlaySettings::PRECIPITATION, precip);
503 int p = precip < 10. ? 2 : precip < 100. ? 1 : 0;
504 p += m_gparent.m_OverlaySettings
505 .Settings[GribOverlaySettings::PRECIPITATION]
506 .m_Units == 1
507 ? 1
508 : 0; // if PRESSURE & in = one decimal more
509 m_tcPrecipitation->SetValue(
510 wxString::Format("%4.*f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
511 GribOverlaySettings::PRECIPITATION),
512 p, precip));
513 } else
514 m_tcPrecipitation->SetValue(_("N/A"));
515 }
516
517 // Update total cloud control
518 if (RecordArray[Idx_CLOUD_TOT]) {
519 double cloud = RecordArray[Idx_CLOUD_TOT]->getInterpolatedValue(
520 m_cursor_lon, m_cursor_lat, true);
521
522 if (cloud != GRIB_NOTDEF) {
523 cloud = m_gparent.m_OverlaySettings.CalibrateValue(
524 GribOverlaySettings::CLOUD, cloud);
525 wxString val(wxString::Format("%5.0f ", cloud));
526 m_tcCloud->SetValue(val + m_gparent.m_OverlaySettings.GetUnitSymbol(
527 GribOverlaySettings::CLOUD));
528 } else
529 m_tcCloud->SetValue(_("N/A"));
530 }
531
532 // Update the Air Temperature
533 if (RecordArray[Idx_AIR_TEMP]) {
534 double temp = RecordArray[Idx_AIR_TEMP]->getInterpolatedValue(
535 m_cursor_lon, m_cursor_lat, true);
536
537 if (temp != GRIB_NOTDEF) {
538 temp = m_gparent.m_OverlaySettings.CalibrateValue(
539 GribOverlaySettings::AIR_TEMPERATURE, temp);
540 m_tcAirTemperature->SetValue(
541 wxString::Format("%5.1f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
542 GribOverlaySettings::AIR_TEMPERATURE),
543 temp));
544 } else
545 m_tcAirTemperature->SetValue(_("N/A"));
546 }
547
548 // Update the Sea Surface Temperature
549 if (RecordArray[Idx_SEA_TEMP]) {
550 double temp = RecordArray[Idx_SEA_TEMP]->getInterpolatedValue(
551 m_cursor_lon, m_cursor_lat, true);
552
553 if (temp != GRIB_NOTDEF) {
554 temp = m_gparent.m_OverlaySettings.CalibrateValue(
555 GribOverlaySettings::SEA_TEMPERATURE, temp);
556 m_tcSeaTemperature->SetValue(
557 wxString::Format("%5.1f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
558 GribOverlaySettings::SEA_TEMPERATURE),
559 temp));
560 } else
561 m_tcSeaTemperature->SetValue(_("N/A"));
562 }
563
564 // Update the Convective Available Potential Energy (CAPE)
565 if (RecordArray[Idx_CAPE]) {
566 double cape = RecordArray[Idx_CAPE]->getInterpolatedValue(
567 m_cursor_lon, m_cursor_lat, true);
568
569 if (cape != GRIB_NOTDEF) {
570 cape = m_gparent.m_OverlaySettings.CalibrateValue(
571 GribOverlaySettings::CAPE, cape);
572 m_tcCAPE->SetValue(
573 wxString::Format("%5.0f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
574 GribOverlaySettings::CAPE),
575 cape));
576 } else
577 m_tcCAPE->SetValue(_("N/A"));
578 }
579 if (RecordArray[Idx_COMP_REFL]) {
580 double c_refl = RecordArray[Idx_COMP_REFL]->getInterpolatedValue(
581 m_cursor_lon, m_cursor_lat, true);
582
583 if (c_refl != GRIB_NOTDEF) {
584 c_refl = m_gparent.m_OverlaySettings.CalibrateValue(
585 GribOverlaySettings::COMP_REFL, c_refl);
586 m_tcReflC->SetValue(
587 wxString::Format("%5.0f " + m_gparent.m_OverlaySettings.GetUnitSymbol(
588 GribOverlaySettings::COMP_REFL),
589 c_refl));
590 } else
591 m_tcReflC->SetValue(_("N/A"));
592 }
593 // Update extra data for altitude
594 // geopotential altitude
595 if (RecordArray[Idx_GEOP_HGT + m_Altitude]) {
596 double geop = RecordArray[Idx_GEOP_HGT + m_Altitude]->getInterpolatedValue(
597 m_cursor_lon, m_cursor_lat, true);
598
599 if (geop != GRIB_NOTDEF) {
600 geop = m_gparent.m_OverlaySettings.CalibrateValue(
601 GribOverlaySettings::GEO_ALTITUDE, geop);
602 m_tcAltitude->SetValue(wxString::Format("%5.0f ", geop) +
603 m_gparent.m_OverlaySettings.GetUnitSymbol(
604 GribOverlaySettings::GEO_ALTITUDE));
605 } else
606 m_tcAltitude->SetValue(_("N/A"));
607 }
608
609 // temperature
610 if (RecordArray[Idx_AIR_TEMP + m_Altitude]) {
611 double temp = RecordArray[Idx_AIR_TEMP + m_Altitude]->getInterpolatedValue(
612 m_cursor_lon, m_cursor_lat, true);
613
614 if (temp != GRIB_NOTDEF) {
615 temp = m_gparent.m_OverlaySettings.CalibrateValue(
616 GribOverlaySettings::AIR_TEMPERATURE, temp);
617 m_tcTemp->SetValue(wxString::Format("%5.1f ", temp) +
618 m_gparent.m_OverlaySettings.GetUnitSymbol(
619 GribOverlaySettings::AIR_TEMPERATURE));
620 } else
621 m_tcTemp->SetValue(_("N/A"));
622 }
623 // relative humidity
624 if (RecordArray[Idx_HUMID_RE + m_Altitude]) {
625 double humi = RecordArray[Idx_HUMID_RE + m_Altitude]->getInterpolatedValue(
626 m_cursor_lon, m_cursor_lat, true);
627
628 if (humi != GRIB_NOTDEF) {
629 humi = m_gparent.m_OverlaySettings.CalibrateValue(
630 GribOverlaySettings::REL_HUMIDITY, humi);
631 m_tcRelHumid->SetValue(wxString::Format("%5.0f ", humi) +
632 m_gparent.m_OverlaySettings.GetUnitSymbol(
633 GribOverlaySettings::REL_HUMIDITY));
634 } else
635 m_tcRelHumid->SetValue(_("N/A"));
636 }
637}
638
639void CursorData::OnMenuCallBack(wxMouseEvent &event) {
640 // populate menu
641 wxMenu *menu = new wxMenu();
642 int id = event.GetId();
643 switch (id) {
644 case GribOverlaySettings::WIND:
645 MenuAppend(menu, B_ARROWS, _("Barbed Arrows"), id);
646 MenuAppend(menu, ISO_LINE, _("Display Isotachs"), id);
647 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
648 MenuAppend(menu, NUMBERS, _("Numbers"), id);
649 MenuAppend(menu, PARTICLES, _("Particle Map"), id);
650 break;
651 case GribOverlaySettings::WIND_GUST:
652 MenuAppend(menu, ISO_LINE, _("Display Isotachs"), id);
653 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
654 MenuAppend(menu, NUMBERS, _("Numbers"), id);
655 break;
656 case GribOverlaySettings::PRESSURE:
657 MenuAppend(menu, ISO_LINE, _("Display Isobars"), id);
658 MenuAppend(menu, ISO_ABBR, _("Abbreviated Isobars Numbers"), id);
659 MenuAppend(menu, NUMBERS, _("Numbers"), id);
660 break;
661 case GribOverlaySettings::AIR_TEMPERATURE:
662 case GribOverlaySettings::SEA_TEMPERATURE:
663 MenuAppend(menu, ISO_LINE, _("Display Isotherms"), id);
664 // fall through
665 case GribOverlaySettings::CLOUD:
666 case GribOverlaySettings::PRECIPITATION:
667 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
668 MenuAppend(menu, NUMBERS, _("Numbers"), id);
669 break;
670 case GribOverlaySettings::CAPE:
671 MenuAppend(menu, ISO_LINE, _("Display Iso CAPE"), id);
672 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
673 MenuAppend(menu, NUMBERS, _("Numbers"), id);
674 break;
675 case GribOverlaySettings::COMP_REFL:
676 MenuAppend(menu, ISO_LINE, _("Display Iso Reflectivity"), id);
677 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
678 MenuAppend(menu, NUMBERS, _("Numbers"), id);
679 break;
680 case GribOverlaySettings::WAVE:
681 MenuAppend(menu, D_ARROWS, _("Direction Arrows"), id);
682 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
683 MenuAppend(menu, NUMBERS, _("Numbers"), id);
684 break;
685 case GribOverlaySettings::CURRENT:
686 MenuAppend(menu, D_ARROWS, _("Direction Arrows"), id);
687 MenuAppend(menu, OVERLAY, _("OverlayMap"), id);
688 MenuAppend(menu, NUMBERS, _("Numbers"), id);
689 MenuAppend(menu, PARTICLES, _("Particle Map"), id);
690 }
691
692 PopupMenu(menu);
693
694 // apply new config
695 wxwxMenuItemListNode *node = menu->GetMenuItems().GetFirst();
696 while (node) {
697 wxMenuItem *it = node->GetData();
698 switch (it->GetId()) {
699 case B_ARROWS:
700 m_gparent.m_OverlaySettings.Settings[id].m_bBarbedArrows =
701 it->IsChecked();
702 break;
703 case ISO_LINE:
704 m_gparent.m_OverlaySettings.Settings[id].m_bIsoBars = it->IsChecked();
705 break;
706 case ISO_ABBR:
707 m_gparent.m_OverlaySettings.Settings[id].m_bAbbrIsoBarsNumbers =
708 it->IsChecked();
709 break;
710 case D_ARROWS:
711 m_gparent.m_OverlaySettings.Settings[id].m_bDirectionArrows =
712 it->IsChecked();
713 break;
714 case OVERLAY:
715 m_gparent.m_OverlaySettings.Settings[id].m_bOverlayMap =
716 it->IsChecked();
717 break;
718 case NUMBERS:
719 m_gparent.m_OverlaySettings.Settings[id].m_bNumbers = it->IsChecked();
720 break;
721 case PARTICLES:
722 m_gparent.m_OverlaySettings.Settings[id].m_bParticles = it->IsChecked();
723 }
724 node = node->GetNext();
725 }
726
727 // if the current parameter type is selected then resolve display conflicts
728 if (m_gparent.InDataPlot(id) && m_gparent.m_bDataPlot[id])
729 ResolveDisplayConflicts(id);
730
731 // save new config
732 m_gparent.m_OverlaySettings.Write();
733
734 delete menu;
735}
736
737void CursorData::MenuAppend(wxMenu *menu, int id, wxString label, int setting) {
738 wxMenuItem *item = new wxMenuItem(menu, id, label, "", wxITEM_CHECK);
739
740#ifdef __WXMSW__
741 wxFont *qFont = OCPNGetFont(_("Menu"));
742 item->SetFont(*qFont);
743#endif
744
745 menu->Append(item);
746
747 bool check;
748 if (id == B_ARROWS)
749 check = m_gparent.m_OverlaySettings.Settings[setting].m_bBarbedArrows;
750 else if (id == ISO_LINE)
751 check = m_gparent.m_OverlaySettings.Settings[setting].m_bIsoBars;
752 else if (id == ISO_ABBR)
753 check = m_gparent.m_OverlaySettings.Settings[setting].m_bAbbrIsoBarsNumbers;
754 else if (id == D_ARROWS)
755 check = m_gparent.m_OverlaySettings.Settings[setting].m_bDirectionArrows;
756 else if (id == OVERLAY)
757 check = m_gparent.m_OverlaySettings.Settings[setting].m_bOverlayMap;
758 else if (id == NUMBERS)
759 check = m_gparent.m_OverlaySettings.Settings[setting].m_bNumbers;
760 else if (id == PARTICLES)
761 check = m_gparent.m_OverlaySettings.Settings[setting].m_bParticles;
762 else
763 check = false;
764 item->Check(check);
765}
766
767void CursorData::OnMouseEvent(wxMouseEvent &event) {
768 if (event.RightDown()) {
769 if (m_DialogStyle >> 1 == ATTACHED) {
770 wxMouseEvent evt(event);
771 m_gparent.OnMouseEvent(evt);
772 }
773 return;
774 }
775
776 static wxPoint s_gspt;
777 int x, y;
778
779 event.GetPosition(&x, &y);
780 wxPoint spt = wxPoint(x, y);
781 if (event.GetId() != 1000)
782 spt = ClientToScreen(spt);
783 else
784 spt = GetParent()->ClientToScreen(spt);
785
786#ifdef __WXOSX__
787 if (!m_bLeftDown && event.LeftIsDown()) {
788 m_bLeftDown = true;
789 s_gspt = spt;
790 if (!HasCapture()) CaptureMouse();
791 } else if (m_bLeftDown && !event.LeftIsDown()) {
792 // GetParent()->Move( GetParent()->GetPosition() );
793 m_bLeftDown = false;
794 if (HasCapture()) ReleaseMouse();
795 }
796#else
797
798 if (event.LeftDown()) {
799 s_gspt = spt;
800 if (!HasCapture()) CaptureMouse();
801 }
802
803 if (event.LeftUp()) {
804 // GetParent()->Move( GetParent()->GetPosition() );
805 if (HasCapture()) ReleaseMouse();
806 }
807#endif
808
809 if (event.Dragging()) {
810 wxPoint par_pos_old = GetParent()->GetPosition();
811
812 wxPoint par_pos = par_pos_old;
813 par_pos.x += spt.x - s_gspt.x;
814 par_pos.y += spt.y - s_gspt.y;
815
816 wxPoint pos_in_parent = GetOCPNCanvasWindow()->ScreenToClient(par_pos);
817 wxPoint pos_in_parent_old =
818 GetOCPNCanvasWindow()->ScreenToClient(par_pos_old);
819
820 // X
821 if (pos_in_parent.x < pos_in_parent_old.x) { // moving left
822 if (pos_in_parent.x < 10) {
823 pos_in_parent.x = 0;
824 }
825 } else if (pos_in_parent.x > pos_in_parent_old.x) { // moving right
826 int max_right =
827 GetOCPNCanvasWindow()->GetClientSize().x - GetParent()->GetSize().x;
828 if (pos_in_parent.x > (max_right - 10)) {
829 pos_in_parent.x = max_right;
830 }
831 }
832
833 // Y
834 if (pos_in_parent.y < pos_in_parent_old.y) { // moving up
835 if (pos_in_parent.y < 10) {
836 pos_in_parent.y = 0;
837 }
838 } else if (pos_in_parent.y > pos_in_parent_old.y) { // moving dow
839 int max_down =
840 GetOCPNCanvasWindow()->GetClientSize().y - GetParent()->GetSize().y;
841 if (pos_in_parent.y > (max_down - 10)) {
842 pos_in_parent.y = max_down;
843 }
844 }
845
846 wxPoint final_pos = GetOCPNCanvasWindow()->ClientToScreen(pos_in_parent);
847
848 GetParent()->Move(final_pos);
849
850 s_gspt = spt;
851 }
852}
@ Idx_COMP_REFL
Composite radar reflectivity in dBZ (decibel relative to Z)
@ Idx_PRECIP_TOT
Precipitation data in millimeters per hour.
@ Idx_AIR_TEMP
Air temperature at 2m in Kelvin (K)
@ Idx_PRESSURE
Surface pressure in Pascal (Pa)
@ Idx_WVDIR
Wave direction.
@ Idx_CLOUD_TOT
Total cloud cover in % (percent, range 0-100%)
@ Idx_WIND_GUST
Wind gust speed at surface in m/s.
@ Idx_WIND_VX
Surface wind velocity X component in m/s.
@ Idx_WVPER
Wave period.
@ Idx_HTSIGW
Significant wave height in meters.
@ Idx_HUMID_RE
Surface relative humidity in % (percent, range 0-100%)
@ Idx_SEACURRENT_VY
Sea current velocity Y component in m/s.
@ Idx_GEOP_HGT
Surface geopotential height in gpm (geopotential meters)
@ Idx_SEA_TEMP
Sea surface temperature in Kelvin (K)
@ Idx_WIND_VY
Surface wind velocity Y component in m/s.
@ Idx_SEACURRENT_VX
Sea current velocity X component in m/s.
@ Idx_CAPE
Convective Available Potential Energy in J/kg (Joules per kilogram)
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.
wxWindow * GetOCPNCanvasWindow()
Gets OpenCPN's main canvas window.
wxFont * OCPNGetFont(wxString TextElement, int default_size)
Gets a font for UI elements.
void DimeWindow(wxWindow *win)
Applies system color scheme to window.
OpenGL Platform Abstraction Layer.