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