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