OpenCPN Partial API docs
Loading...
Searching...
No Matches
altitude.cpp
1/******************************************************************************
2 * $Id: altitude.cpp, v0.2 $
3 *
4 * Project: OpenCPN
5 * Purpose: Dashboard Plugin, display altitude trace
6 * Author: derived from Jean-Eudes Onfray's depth.cpp by Andreas Merz
7 *
8 * Comment: since not every vessel is always on sea level, I found it
9 * sometimes intersting to observe the GPS altitude information.
10 * It can be extracted from the GGA nmea message.
11 *
12 ***************************************************************************
13 * Copyright (C) 2010 by David S. Register *
14 * *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
19 * *
20 * This program is distributed in the hope that it will be useful, *
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
23 * GNU General Public License for more details. *
24 * *
25 * You should have received a copy of the GNU General Public License *
26 * along with this program; if not, write to the *
27 * Free Software Foundation, Inc., *
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
29 ***************************************************************************
30 */
31
32#include <wx/wxprec.h>
33
34#ifndef WX_PRECOMP
35#include <wx/wx.h>
36#endif // precompiled headers
37
38#include "altitude.h"
39extern int g_iDashDepthUnit; // use same unit for altitude
40
41#ifdef __BORLANDC__
42#pragma hdrstop
43#endif
44
45int m_aDataHeight;
46int x_alabel, y_alabel, a_plotdown, a_plotup, a_plotheight;
47
48DashboardInstrument_Altitude::DashboardInstrument_Altitude(
49 wxWindow* parent, wxWindowID id, wxString title,
50 InstrumentProperties* Properties)
51 : DashboardInstrument(parent, id, title, OCPN_DBP_STC_ALTI, Properties) {
52 m_cap_flag.set(OCPN_DBP_STC_TMP);
53 m_MaxAltitude = 0;
54 m_Altitude = 0;
55 m_AltitudeUnit = getUsrDistanceUnit_Plugin(g_iDashDepthUnit);
56 m_Temp = _T("--");
57 for (int idx = 0; idx < ALTITUDE_RECORD_COUNT; idx++) {
58 m_ArrayAltitude[idx] = 0.0;
59 }
60}
61
62wxSize DashboardInstrument_Altitude::GetSize(int orient, wxSize hint) {
63 wxClientDC dc(this);
64 int w;
65 wxFont f;
66 if (m_Properties) {
67 f = m_Properties->m_TitleFont.GetChosenFont();
68 dc.GetTextExtent(m_title, &w, &m_TitleHeight, 0, 0, &f);
69 f = m_Properties->m_DataFont.GetChosenFont();
70 dc.GetTextExtent("15.7 Feet", &w, &m_aDataHeight, 0, 0, &f);
71 f = m_Properties->m_LabelFont.GetChosenFont();
72 dc.GetTextExtent("20.8 C", &x_alabel, &y_alabel, 0, 0, &f);
73 } else {
74 f = g_pFontTitle->GetChosenFont();
75 dc.GetTextExtent(m_title, &w, &m_TitleHeight, 0, 0, &f);
76 f = g_pFontData->GetChosenFont();
77 dc.GetTextExtent("15.7 Feet", &w, &m_aDataHeight, 0, 0, &f);
78 // Space for bottom(temp)text later.
79 f = g_pFontLabel->GetChosenFont();
80 dc.GetTextExtent("20.8 C", &x_alabel, &y_alabel, 0, 0, &f);
81 }
82 int y_total =
83 // Title Alt. data plot area air-temp
84 m_TitleHeight + m_aDataHeight + 4 * m_aDataHeight + y_alabel;
85 if (orient == wxHORIZONTAL) {
86 return wxSize(DefaultWidth, wxMax(y_total, hint.y));
87 } else {
88 return wxSize(wxMax(hint.x, DefaultWidth), y_total);
89 }
90}
91
92void DashboardInstrument_Altitude::SetData(DASH_CAP st, double data,
93 wxString unit) {
94 if (st == OCPN_DBP_STC_ALTI) {
95 m_Altitude = std::isnan(data) ? 0.0 : data;
96 // m_Altitude = m_Altitude*10.0 +1000; // inject fake testdata
97 // printf("Altitude = %3.3f\n", m_Altitude); // debug output
98
99 // save FLOPS by just accumulating the FIFO changes
100 m_meanAltitude += (m_Altitude - m_ArrayAltitude[0]) / ALTITUDE_RECORD_COUNT;
101 m_sum2Altitude +=
102 (m_Altitude * m_Altitude - m_ArrayAltitude[0] * m_ArrayAltitude[0]);
103
104 for (int idx = 1; idx < ALTITUDE_RECORD_COUNT; idx++) {
105 m_ArrayAltitude[idx - 1] = m_ArrayAltitude[idx]; // shift FIFO
106 }
107 m_ArrayAltitude[ALTITUDE_RECORD_COUNT - 1] = m_Altitude;
108 m_AltitudeUnit = unit;
109 } else if (st == OCPN_DBP_STC_ATMP) {
110 if (!std::isnan(data)) {
111 m_Temp = wxString::Format(_T("%.1f"), data) + DEGREE_SIGN + unit;
112 } else {
113 m_Temp = "---";
114 }
115 }
116}
117
118void DashboardInstrument_Altitude::setAttenuation(int steps) {
119 // fast int stuff
120 // increase the attenuation in 1 2 5 10 20 50 steps
121 if (steps > 0)
122 while (steps--) {
123 switch (m_Attenuation) {
124 case 1:
125 m_Attenuation = 2;
126 break;
127 case 2:
128 m_Attenuation = 5;
129 break;
130 default:
131 m_Attenuation = 1;
132 m_Decade *= 10;
133 }
134 }
135 // decrease the attenuation in 1 2 5 10 20 50 steps
136 else if (steps < 0)
137 while (steps++) {
138 switch (m_Attenuation) {
139 case 5:
140 m_Attenuation = 2;
141 break;
142 case 2:
143 m_Attenuation = 1;
144 break;
145 default:
146 m_Attenuation = 5;
147 m_Decade /= 10;
148 }
149 }
150 // bottom limit: unity
151 if (m_Decade < 1) {
152 m_Decade = 1;
153 m_Attenuation = 1;
154 }
155}
156
157int DashboardInstrument_Altitude::getAttenuation() {
158 return m_Attenuation * m_Decade;
159}
160
161void DashboardInstrument_Altitude::Draw(wxGCDC* dc) {
162 DrawBackground(dc);
163 DrawForeground(dc);
164}
165
166void DashboardInstrument_Altitude::DrawBackground(wxGCDC* dc) {
167 wxSize size = GetClientSize();
168 wxColour cl;
169 if (m_Properties) {
170 dc->SetTextForeground(
171 GetColourSchemeFont(m_Properties->m_LabelFont.GetColour()));
172 } else {
173 if (GetColourSchemeFont(g_pFontSmall->GetColour()) ==
174 GetColourSchemeFont(g_pFontLabel->GetColour())) {
175 GetGlobalColor(_T("DASHL"), &cl);
176 dc->SetTextForeground(cl);
177 } else
178 dc->SetTextForeground(GetColourSchemeFont(g_pFontLabel->GetColour()));
179 }
180
181 wxPen pen;
182 pen.SetStyle(wxPENSTYLE_SOLID);
183 if (m_Properties)
184 cl = GetColourSchemeFont(m_Properties->m_SmallFont.GetColour());
185 else
186 cl = GetColourSchemeFont(g_pFontSmall->GetColour());
187 // GetGlobalColor(_T("DASHF"), &cl);
188 pen.SetColour(cl);
189 pen.SetWidth(1);
190 dc->SetPen(pen);
191
192 a_plotup = m_TitleHeight + m_aDataHeight;
193 a_plotdown = size.y - y_alabel;
194 a_plotheight = a_plotdown - a_plotup;
195
196 // dc->DrawLine(3, 44, size.x - 3, 44);
197 dc->DrawLine(3, a_plotdown, size.x - 3, a_plotdown);
198
199#ifdef __WXMSW__
200 pen.SetStyle(wxPENSTYLE_SHORT_DASH);
201#else
202 pen.SetStyle(wxPENSTYLE_DOT);
203 pen.SetWidth(1);
204#endif
205
206 // Grid lines
207 dc->SetPen(pen);
208 dc->DrawLine(3, a_plotup, size.x - 3, a_plotup);
209 dc->DrawLine(3, a_plotup + a_plotheight / 4, size.x - 3,
210 a_plotup + a_plotheight / 4);
211 dc->DrawLine(3, a_plotup + a_plotheight * 2 / 4, size.x - 3,
212 a_plotup + a_plotheight * 2 / 4);
213 dc->DrawLine(3, a_plotup + a_plotheight * 3 / 4, size.x - 3,
214 a_plotup + a_plotheight * 3 / 4);
215 if (m_Properties) {
216 dc->SetFont(m_Properties->m_SmallFont.GetChosenFont());
217 dc->SetTextForeground(
218 GetColourSchemeFont(m_Properties->m_SmallFont.GetColour()));
219 } else {
220 dc->SetFont(g_pFontSmall->GetChosenFont());
221 dc->SetTextForeground(GetColourSchemeFont(g_pFontSmall->GetColour()));
222 }
223
224 // evaluate buffered data to determine its range
225 double MaxAltitude = m_ArrayAltitude[0];
226 double MinAltitude = m_ArrayAltitude[0];
227 for (int idx = 1; idx < ALTITUDE_RECORD_COUNT; idx++) {
228 MaxAltitude = std::max(MaxAltitude, m_ArrayAltitude[idx]);
229 MinAltitude = std::min(MinAltitude, m_ArrayAltitude[idx]);
230 }
231
232 // calculate 1st and 2nd Moments
233 double varAltitude =
234 m_sum2Altitude / (ALTITUDE_RECORD_COUNT - 1); // estimator for variance
235 varAltitude -= m_meanAltitude * m_meanAltitude;
236 if (varAltitude < 0.0) varAltitude = 0.0; // avoid nan when calling sqrt().
237
238 // do AGC to adjust scaling
239 double range = MaxAltitude - MinAltitude;
240 if (range > 1.1 * m_Range) setAttenuation(+1);
241 if (range < 0.3 * m_Range) setAttenuation(-1); // some hysteresis
242 double grid = getAttenuation();
243 m_Range = grid * c_GridLines;
244
245 // only update axes on major corridor changes
246 if ((MaxAltitude - m_MaxAltitude) / grid > 0.25 ||
247 (MaxAltitude - m_MaxAltitude) / grid < -0.75 * c_GridLines) {
248 m_MaxAltitude = (round(MaxAltitude / grid) + 1) * grid;
249 m_MinAltitude = m_MaxAltitude - m_Range;
250 }
251 if ((MinAltitude - m_MinAltitude) / grid < -0.25 ||
252 (MinAltitude - m_MinAltitude) / grid > 0.75 * c_GridLines) {
253 m_MinAltitude = (round(MinAltitude / grid) - 1) * grid;
254 m_MaxAltitude = m_MinAltitude + m_Range;
255 }
256 // debug output
257 // printf("m_MinAltitude=%7.1f m_MaxAltitude=%7.1f m_Range = %5.1f "
258 // " range = %5.1f att=%d , mean=%7.2f, std=%5.2f\n",
259 // m_MinAltitude, m_MaxAltitude, m_Range,
260 // range, getAttenuation(), m_meanAltitude, sqrt(varAltitude));
261
262 wxString label;
263 label.Printf(_T("+/-%.1f %8.0f ") + m_AltitudeUnit, sqrt(varAltitude),
264 m_MaxAltitude);
265 int width, height;
266 wxFont f;
267 if (m_Properties)
268 f = m_Properties->m_SmallFont.GetChosenFont();
269 else
270 f = g_pFontSmall->GetChosenFont();
271 dc->GetTextExtent(label, &width, &height, 0, 0, &f);
272 dc->DrawText(label, size.x - width - 1, a_plotup - height);
273
274 label.Printf(_T("%.1f/ %8.0f ") + m_AltitudeUnit, m_Range / c_GridLines,
275 m_MinAltitude);
276 if (m_Properties)
277 f = m_Properties->m_SmallFont.GetChosenFont();
278 else
279 f = g_pFontSmall->GetChosenFont();
280 dc->GetTextExtent(label, &width, &height, 0, 0, &f);
281 dc->DrawText(label, size.x - width - 1, a_plotdown);
282}
283
284void DashboardInstrument_Altitude::DrawForeground(wxGCDC* dc) {
285 wxSize size = GetClientSize();
286 wxColour cl;
287 if (m_Properties) {
288 cl = GetColourSchemeFont(m_Properties->m_LabelFont.GetColour());
289 } else {
290 if (GetColourSchemeFont(g_pFontSmall->GetColour()) ==
291 GetColourSchemeFont(g_pFontLabel->GetColour()))
292 GetGlobalColor(_T("DASH1"), &cl);
293 else
294 cl = GetColourSchemeFont(g_pFontLabel->GetColour());
295 }
296 // GetGlobalColor(_T("DASH1"), &cl);
297 wxBrush brush;
298 brush.SetStyle(wxBRUSHSTYLE_SOLID);
299 brush.SetColour(cl);
300 dc->SetBrush(brush);
301 dc->SetPen(*wxTRANSPARENT_PEN);
302
303 double ratioH = double(a_plotheight) / m_Range;
304 double ratioW = double(size.x - 6) / (ALTITUDE_RECORD_COUNT - 1);
305 wxPoint points[ALTITUDE_RECORD_COUNT + 2];
306#ifdef __OCPN__ANDROID__
307 int px = 3;
308 points[0].x = px;
309 points[0].y = a_plotdown;
310
311 for (int idx = 0; idx < ALTITUDE_RECORD_COUNT - 1; idx++) {
312 points[1].x = points[0].x;
313 if (m_ArrayAltitude[idx])
314 points[1].y =
315 a_plotdown - (m_ArrayAltitude[idx] - m_MinAltitude) * ratioH;
316 else
317 points[1].y = a_plotdown;
318
319 points[2].x = points[1].x + ratioW;
320 if (m_ArrayAltitude[idx + 1])
321 points[2].y =
322 a_plotdown - (m_ArrayAltitude[idx + 1] - m_MinAltitude) * ratioH;
323 else
324 points[2].y = a_plotdown;
325
326 points[3].x = points[2].x;
327 points[3].y = a_plotdown;
328 dc->DrawPolygon(4, points);
329
330 points[0].x = points[2].x;
331 points[0].y = a_plotdown;
332 }
333
334#else
335 for (int idx = 0; idx < ALTITUDE_RECORD_COUNT; idx++) {
336 points[idx].x = idx * ratioW + 3;
337 points[idx].y =
338 a_plotdown - (m_ArrayAltitude[idx] - m_MinAltitude) * ratioH;
339 }
340 points[ALTITUDE_RECORD_COUNT].x = size.x - 3;
341 points[ALTITUDE_RECORD_COUNT].y = a_plotdown;
342 points[ALTITUDE_RECORD_COUNT + 1].x = 3;
343 points[ALTITUDE_RECORD_COUNT + 1].y = a_plotdown;
344 dc->DrawPolygon(ALTITUDE_RECORD_COUNT + 2, points);
345#endif
346 if (m_Properties) {
347 dc->SetFont(m_Properties->m_DataFont.GetChosenFont());
348 dc->SetTextForeground(
349 GetColourSchemeFont(m_Properties->m_DataFont.GetColour()));
350 } else {
351 // GetGlobalColor(_T("DASHF"), &cl);
352 dc->SetTextForeground(GetColourSchemeFont(g_pFontData->GetColour()));
353 dc->SetFont(g_pFontData->GetChosenFont());
354 }
355 if (m_AltitudeUnit != _T("-")) { // Watchdog
356 wxString s_alti = wxString::Format(_T("%.1f"), m_meanAltitude);
357 dc->DrawText(s_alti + _T(" ") + m_AltitudeUnit, 10, m_TitleHeight);
358 } else
359 dc->DrawText(_T("---"), 10, m_TitleHeight);
360
361 // TODO: test display air temperature ID_DBP_I_ATMP
362 if (m_Properties)
363 dc->SetFont(m_Properties->m_LabelFont.GetChosenFont());
364 else
365 dc->SetFont(g_pFontLabel->GetChosenFont());
366 int width, height;
367 wxFont f;
368 if (m_Properties) {
369 f = m_Properties->m_LabelFont.GetChosenFont();
370 dc->GetTextExtent(m_Temp, &width, &height, 0, 0, &f);
371 } else {
372 f = g_pFontLabel->GetChosenFont();
373 dc->GetTextExtent(m_Temp, &width, &height, 0, 0, &f);
374 }
375 dc->DrawText(m_Temp, 3, a_plotdown);
376}
wxString getUsrDistanceUnit_Plugin(int unit)
Gets display string for user's preferred distance unit.