OpenCPN Partial API docs
Loading...
Searching...
No Matches
baro_history.cpp
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (C) 2010 by David S. Register *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
16 *************************************************************************/
17
26#include <wx/wxprec.h>
27
28#ifndef WX_PRECOMP
29#include <wx/wx.h>
30#endif // precompiled headers
31
32#include "baro_history.h"
33
34//*************************************************************************
35// History of barometic pressure
36//*************************************************************************
37
38DashboardInstrument_BaroHistory::DashboardInstrument_BaroHistory(
39 wxWindow* parent, wxWindowID id, wxString title,
40 InstrumentProperties* Properties)
41 : DashboardInstrument(parent, id, title, OCPN_DBP_STC_MDA, Properties) {
42 SetDrawSoloInPane(true);
43
44 m_max_press = 0;
45 m_min_press = (double)1200;
46 m_total_max_press = 0;
47 m_total_min_press = 1200;
48 m_press = 0;
49 // Set top line height to leave space for pressure data
50 wxClientDC dc(this);
51 int w, h;
52 wxFont f;
53 if (m_Properties)
54 f = m_Properties->m_DataFont.GetChosenFont();
55 else
56 f = g_pFontData->GetChosenFont();
57 dc.GetTextExtent("hPa----", &w, &h, 0, 0, &f);
58 m_top_line_height = wxMax(30, h);
59 m_spd_rec_cnt = 0;
60 m_spd_start_val = -1;
61 m_is_running = false;
62 m_sample_count = 0;
63 m_set_new_data = 0;
64 m_left_legend = 3;
65 m_right_legend = 20;
66 for (int idx = 0; idx < BARO_RECORD_COUNT; idx++) {
67 m_array_press_history[idx] = -1;
68 m_exp_smooth_array_pressure[idx] = -1;
69 m_array_rec_time[idx] = wxDateTime::Now().GetTm();
70 m_array_rec_time[idx].year = 999;
71 }
72 alpha = 0.01; // smoothing constant
73 m_window_rect = GetClientRect();
74 m_draw_area_rect = GetClientRect();
75 m_draw_area_rect.SetHeight(m_window_rect.height - m_top_line_height -
76 m_TitleHeight);
77}
78
79wxSize DashboardInstrument_BaroHistory::GetSize(int orient, wxSize hint) {
80 wxClientDC dc(this);
81 int w;
82 wxFont f;
83 if (m_Properties)
84 f = m_Properties->m_TitleFont.GetChosenFont();
85 else
86 f = g_pFontTitle->GetChosenFont();
87 dc.GetTextExtent(m_title, &w, &m_TitleHeight, 0, 0, &f);
88 if (orient == wxHORIZONTAL) {
89 return wxSize(DefaultWidth, wxMax(m_TitleHeight + 140, hint.y));
90 } else {
91 return wxSize(wxMax(hint.x, DefaultWidth),
92 wxMax(m_TitleHeight + 140, hint.y));
93 }
94}
95void DashboardInstrument_BaroHistory::SetData(DASH_CAP st, double data,
96 wxString unit) {
97 if (st == OCPN_DBP_STC_MDA && data > 700.0 && data < 2000.0) {
98 if (m_set_new_data < 1) {
99 m_press = data;
100 if (m_spd_rec_cnt++ <= 5) m_spd_start_val += data;
101
102 if (m_spd_rec_cnt == 5) {
103 m_press = m_spd_start_val / 5;
104 }
105 // start working after we collected 5 records each, as start values for
106 // the smoothed curves
107 if (m_spd_rec_cnt > 5) {
108 m_is_running = true;
109 m_sample_count = m_sample_count < BARO_RECORD_COUNT ? m_sample_count + 1
110 : BARO_RECORD_COUNT;
111 m_max_press = 0;
112 ;
113 // data shifting
114 for (int idx = 1; idx < BARO_RECORD_COUNT; idx++) {
115 if (BARO_RECORD_COUNT - m_sample_count <= idx)
116 m_max_press = wxMax(m_array_press_history[idx - 1], m_max_press);
117 m_min_press = wxMin(m_array_press_history[idx - 1], m_min_press);
118 m_array_press_history[idx - 1] = m_array_press_history[idx];
119 m_exp_smooth_array_pressure[idx - 1] =
120 m_exp_smooth_array_pressure[idx];
121 m_array_rec_time[idx - 1] = m_array_rec_time[idx];
122 }
123 m_array_press_history[BARO_RECORD_COUNT - 1] = m_press;
124 if (m_sample_count < 2) {
125 m_array_press_history[BARO_RECORD_COUNT - 2] = m_press;
126 m_exp_smooth_array_pressure[BARO_RECORD_COUNT - 2] = m_press;
127 }
128 m_exp_smooth_array_pressure[BARO_RECORD_COUNT - 1] =
129 alpha * m_array_press_history[BARO_RECORD_COUNT - 2] +
130 (1 - alpha) * m_exp_smooth_array_pressure[BARO_RECORD_COUNT - 2];
131 m_array_rec_time[BARO_RECORD_COUNT - 1] = wxDateTime::Now().GetTm();
132 m_max_press = wxMax(m_press, m_max_press);
133
134 m_min_press = wxMin(m_min_press, m_press);
135 if (wxMin(m_press, m_min_press) == -1) {
136 m_min_press = wxMin(m_press, 1200); // to make a OK inital value
137 }
138 // get the overall max min pressure
139 m_total_max_press = wxMax(m_press, m_total_max_press);
140 m_total_min_press = wxMin(m_press, m_total_min_press);
141 // Wait two turns until new data.
142 m_set_new_data = 2;
143 }
144 } else
145 m_set_new_data--;
146 } else {
147 // Check for watchdog timeout
148 if (isnan(data)) m_press = data;
149 }
150}
151
152void DashboardInstrument_BaroHistory::Draw(wxGCDC* dc) {
153 m_window_rect = GetClientRect();
154 m_draw_area_rect = GetClientRect();
155 m_draw_area_rect.SetHeight(m_window_rect.height - m_top_line_height -
156 m_TitleHeight);
157 m_draw_area_rect.SetX(m_left_legend + 3);
158 DrawBackground(dc);
159 DrawForeground(dc);
160}
161
162//*********************************************************************************
163// draw pressure scale
164//*********************************************************************************
165void DashboardInstrument_BaroHistory::DrawWindSpeedScale(wxGCDC* dc) {
166 wxString label1, label2, label3, label4, label5;
167 wxColour cl;
168 int width, height;
169 cl = wxColour(61, 61, 204, 255);
170 if (m_Properties) {
171 dc->SetTextForeground(
172 GetColourSchemeFont(m_Properties->m_SmallFont.GetColour()));
173 dc->SetFont(m_Properties->m_SmallFont.GetChosenFont());
174 } else {
175 dc->SetTextForeground(GetColourSchemeFont(g_pFontSmall->GetColour()));
176 dc->SetFont(g_pFontSmall->GetChosenFont());
177 }
178 // round m_MaxPress up to the next hpa ...
179 if (m_max_press > 1100) m_max_press = 1100;
180
181 if (m_total_min_press < 930) m_total_min_press = 930;
182
183 m_max_press_scale = (int)((m_max_press + 15) - (m_total_min_press - 15));
184
185 if (!m_is_running) {
186 label1 = "-- hPa";
187 label2 = "-- hPa";
188 label3 = "-- hPa";
189 label4 = "-- hPa";
190 label5 = "-- hPa";
191 } else {
192 /*
193 The goal is to draw the legend with decimals only, if we really have them !
194 */
195 // top legend for max press
196 label1.Printf("%.0f hPa", m_max_press_scale + (m_total_min_press - 18));
197
198 // 3/4 legend
199
200 label2.Printf("%.0f hPa",
201 m_max_press_scale * 3. / 4 + (m_total_min_press - 18));
202
203 // center legend
204
205 label3.Printf("%.0f hPa", m_max_press_scale / 2 + (m_total_min_press - 18));
206
207 // 1/4 legend
208
209 label4.Printf("%.0f hPa", m_max_press_scale / 4 + (m_total_min_press - 18));
210
211 // bottom legend for min wind
212 label5.Printf("%.0f hPa", (m_total_min_press - 18));
213 }
214 wxFont f;
215 if (m_Properties)
216 f = m_Properties->m_SmallFont.GetChosenFont();
217 else
218 f = g_pFontSmall->GetChosenFont();
219 dc->GetTextExtent(label1, &m_left_legend, &height, 0, 0, &f);
220 dc->DrawText(label1, 4, (int)(m_top_line_height - height / 2));
221 if (m_Properties)
222 f = m_Properties->m_SmallFont.GetChosenFont();
223 else
224 f = g_pFontSmall->GetChosenFont();
225 dc->GetTextExtent(label2, &width, &height, 0, 0, &f);
226 dc->DrawText(
227 label2, 4,
228 (int)(m_top_line_height + m_draw_area_rect.height / 4 - height / 2));
229 m_left_legend = wxMax(width, m_left_legend);
230 if (m_Properties)
231 f = m_Properties->m_SmallFont.GetChosenFont();
232 else
233 f = g_pFontSmall->GetChosenFont();
234 dc->GetTextExtent(label3, &width, &height, 0, 0, &f);
235 dc->DrawText(
236 label3, 4,
237 (int)(m_top_line_height + m_draw_area_rect.height / 2 - height / 2));
238 m_left_legend = wxMax(width, m_left_legend);
239 if (m_Properties)
240 f = m_Properties->m_SmallFont.GetChosenFont();
241 else
242 f = g_pFontSmall->GetChosenFont();
243 dc->GetTextExtent(label4, &width, &height, 0, 0, &f);
244 dc->DrawText(
245 label4, 4,
246 (int)(m_top_line_height + m_draw_area_rect.height * 0.75 - height / 2));
247 m_left_legend = wxMax(width, m_left_legend);
248 if (m_Properties)
249 f = m_Properties->m_SmallFont.GetChosenFont();
250 else
251 f = g_pFontSmall->GetChosenFont();
252 dc->GetTextExtent(label5, &width, &height, 0, 0, &f);
253 dc->DrawText(label5, 4,
254 (int)(m_top_line_height + m_draw_area_rect.height - height / 2));
255 m_left_legend = wxMax(width, m_left_legend);
256 m_left_legend += 4;
257}
258
259//*********************************************************************************
260// draw background
261//*********************************************************************************
262void DashboardInstrument_BaroHistory::DrawBackground(wxGCDC* dc) {
263 wxString label, label1, label2, label3, label4, label5;
264 wxColour cl;
265 wxPen pen;
266 //---------------------------------------------------------------------------------
267 // draw legends for spressure
268 //---------------------------------------------------------------------------------
269
270 DrawWindSpeedScale(dc);
271
272 //---------------------------------------------------------------------------------
273 // horizontal lines
274 //---------------------------------------------------------------------------------
275 GetGlobalColor("UBLCK", &cl);
276 pen.SetColour(cl);
277 dc->SetPen(pen);
278 dc->DrawLine(m_left_legend + 3, m_top_line_height,
279 m_window_rect.width - 3 - m_right_legend,
280 m_top_line_height); // the upper line
281 dc->DrawLine(m_left_legend + 3,
282 (int)(m_top_line_height + m_draw_area_rect.height),
283 m_window_rect.width - 3 - m_right_legend,
284 (int)(m_top_line_height + m_draw_area_rect.height));
285 pen.SetStyle(wxPENSTYLE_DOT);
286 dc->SetPen(pen);
287 dc->DrawLine(m_left_legend + 3,
288 (int)(m_top_line_height + m_draw_area_rect.height * 0.25),
289 m_window_rect.width - 3 - m_right_legend,
290 (int)(m_top_line_height + m_draw_area_rect.height * 0.25));
291 dc->DrawLine(m_left_legend + 3,
292 (int)(m_top_line_height + m_draw_area_rect.height * 0.75),
293 m_window_rect.width - 3 - m_right_legend,
294 (int)(m_top_line_height + m_draw_area_rect.height * 0.75));
295#ifdef __WXMSW__
296 pen.SetStyle(wxPENSTYLE_SHORT_DASH);
297 dc->SetPen(pen);
298#endif
299 dc->DrawLine(m_left_legend + 3,
300 (int)(m_top_line_height + m_draw_area_rect.height * 0.5),
301 m_window_rect.width - 3 - m_right_legend,
302 (int)(m_top_line_height + m_draw_area_rect.height * 0.5));
303}
304
305//*********************************************************************************
306// draw foreground
307//*********************************************************************************
308void DashboardInstrument_BaroHistory::DrawForeground(wxGCDC* dc) {
309 wxColour col;
310 double ratioH;
311 int degw, degh;
312 int width, height, min, hour;
313 wxString WindAngle, WindSpeed;
314 wxPen pen;
315 wxString label;
316
317 //---------------------------------------------------------------------------------
318 // Pressure
319 //---------------------------------------------------------------------------------
320 // col = wxColour(61, 61, 204, 255); // blue, opaque
321 wxFont f;
322 if (m_Properties) {
323 dc->SetFont(m_Properties->m_DataFont.GetChosenFont());
324 dc->SetTextForeground(
325 GetColourSchemeFont(m_Properties->m_DataFont.GetColour()));
326 } else {
327 dc->SetFont(g_pFontData->GetChosenFont());
328 dc->SetTextForeground(GetColourSchemeFont(g_pFontData->GetColour()));
329 }
330 if (!std::isnan(m_press))
331 WindSpeed = wxString::Format("hPa %3.1f ", m_press);
332 else
333 WindSpeed = wxString::Format("hPa --- ");
334 if (m_Properties)
335 f = m_Properties->m_DataFont.GetChosenFont();
336 else
337 f = g_pFontData->GetChosenFont();
338 dc->GetTextExtent(WindSpeed, &degw, &degh, 0, 0, &f);
339
340 dc->DrawText(WindSpeed, m_left_legend + 3, 1);
341 if (m_Properties) {
342 dc->SetFont(m_Properties->m_LabelFont.GetChosenFont());
343 dc->SetTextForeground(
344 GetColourSchemeFont(m_Properties->m_LabelFont.GetColour()));
345 } else {
346 dc->SetFont(g_pFontLabel->GetChosenFont());
347 dc->SetTextForeground(GetColourSchemeFont(g_pFontLabel->GetColour()));
348 }
349 int labelw, labelh;
350 if (m_Properties)
351 f = m_Properties->m_LabelFont.GetChosenFont();
352 else
353 f = g_pFontLabel->GetChosenFont();
354 dc->GetTextExtent(WindSpeed, &labelw, &labelh, 0, 0, &f);
355 // determine the time range of the available data (=oldest data value)
356 int i = 0;
357 while (m_array_rec_time[i].year == 999 && i < BARO_RECORD_COUNT - 1) i++;
358 if (i == BARO_RECORD_COUNT - 1) {
359 min = 0;
360 hour = 0;
361
362 } else {
363 wxDateTime localTime(m_array_rec_time[i]);
364 min = localTime.GetMinute();
365 hour = localTime.GetHour();
366 }
367 m_draw_area_rect.SetWidth(m_window_rect.width - 3 - m_left_legend -
368 m_right_legend);
369 m_ratio_w = double(m_draw_area_rect.width) / (BARO_RECORD_COUNT - 1);
370
371 dc->DrawText(
372 wxString::Format(
373 _(" Max %.1f since %02d:%02d Overall Max %.1f Min %.1f "),
374 m_max_press, hour, min, m_total_max_press, m_total_min_press),
375 m_left_legend + 2 + degw, m_top_line_height - 2 - labelh);
376 pen.SetStyle(wxPENSTYLE_SOLID);
377 pen.SetColour(wxColour(61, 61, 204, 255)); // blue, opaque
378 pen.SetWidth(3);
379 dc->SetPen(pen);
380 ratioH = (double)m_draw_area_rect.height / (double)m_max_press_scale;
381
382 wxPoint pointsSpd[BARO_RECORD_COUNT + 2];
383 wxPoint bdDraw[BARO_RECORD_COUNT + 2];
384 int ls = 0;
385 bdDraw[ls].x = 1 * m_ratio_w + 3 + m_left_legend;
386 bdDraw[ls].y =
387 m_top_line_height + m_draw_area_rect.height -
388 ((m_array_press_history[1] - (double)m_total_min_press + 18) * ratioH);
389
390 //---------------------------------------------------------------------------------
391 // live pressure data
392 //---------------------------------------------------------------------------------
393
394 for (int idx = 1; idx < BARO_RECORD_COUNT; idx++) {
395 pointsSpd[idx].x = idx * m_ratio_w + 3 + m_left_legend;
396 // Print the smoothed value to avoid jumps in the single line.
397 pointsSpd[idx].y =
398 m_top_line_height + m_draw_area_rect.height -
399 ((m_exp_smooth_array_pressure[idx] - m_total_min_press + 18.0) *
400 ratioH);
401 if (BARO_RECORD_COUNT - m_sample_count <= idx &&
402 pointsSpd[idx].y > m_top_line_height &&
403 pointsSpd[idx].y <= m_top_line_height + m_draw_area_rect.height) {
404 bdDraw[ls] = pointsSpd[idx];
405 ls++;
406 }
407 }
408 if (ls > 1) dc->DrawLines(ls, bdDraw);
409
410 //---------------------------------------------------------------------------------
411 // exponential smoothing of barometric pressure
412 //---------------------------------------------------------------------------------
413 /*
414 // For now i cant see the reason for implementing smoothing for barometric
415 pressure. pen.SetStyle(wxSOLID); pen.SetColour(wxColour(61,61,204,255));
416 //blue, opaque pen.SetWidth(2); dc->SetPen( pen );
417 pointSpeed_old.x=m_LeftLegend+3;
418 pointSpeed_old.y = m_TopLineHeight+m_DrawAreaRect.height -
419 m_ExpSmoothArrayWindSpd[0] * ratioH;
420
421 for (int idx = 1; idx < BARO_RECORD_COUNT; idx++) {
422 pointsSpd[idx].x = idx * m_ratioW + 3 + m_LeftLegend;
423 pointsSpd[idx].y = m_ExpSmoothArrayWindSpd[idx] * ratioH;
424 if(BARO_RECORD_COUNT-m_SampleCount <= idx && pointsSpd[idx].y >
425 m_TopLineHeight && pointSpeed_old.y > m_TopLineHeight && pointsSpd[idx].y
426 <=m_TopLineHeight+m_DrawAreaRect.height &&
427 pointSpeed_old.y<=m_TopLineHeight+m_DrawAreaRect.height) dc->DrawLine(
428 pointSpeed_old.x, pointSpeed_old.y, pointsSpd[idx].x,pointsSpd[idx].y );
429 pointSpeed_old.x=pointsSpd[idx].x;
430 pointSpeed_old.y=pointsSpd[idx].y;
431 }
432
433 */
434 //---------------------------------------------------------------------------------
435 // Draw vertical timelines every 60 minutes
436 //---------------------------------------------------------------------------------
437 GetGlobalColor("DASHL", &col);
438 pen.SetColour(col);
439 pen.SetStyle(wxPENSTYLE_DOT);
440 dc->SetPen(pen);
441 dc->SetTextForeground(col);
442 dc->SetFont((g_pFontSmall->GetChosenFont()));
443 int done = -1;
444 wxPoint pointTime;
445 for (int idx = 0; idx < BARO_RECORD_COUNT; idx++) {
446 if (m_array_rec_time[idx].year != 999) {
447 wxDateTime localTime(m_array_rec_time[idx]);
448 hour = localTime.GetHour();
449 min = localTime.GetMinute();
450 if ((hour * 100 + min) != done && (min == 0)) {
451 pointTime.x = idx * m_ratio_w + 3 + m_left_legend;
452 dc->DrawLine(pointTime.x, m_top_line_height + 1, pointTime.x,
453 (m_top_line_height + m_draw_area_rect.height + 1));
454 label.Printf("%02d:%02d", hour, min);
455 f = g_pFontSmall->GetChosenFont();
456 dc->GetTextExtent(label, &width, &height, 0, 0, &f);
457 dc->DrawText(label, pointTime.x - width / 2,
458 m_window_rect.height - height);
459 done = hour * 100 + min;
460 }
461 }
462 }
463}
Dashboard barometer history instrument.
DASH_CAP
Definition instrument.h:77
@ OCPN_DBP_STC_MDA
Barometic pressure.
Definition instrument.h:109