OpenCPN Partial API docs
Loading...
Searching...
No Matches
altitude.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
34#include <wx/wxprec.h>
35
36#ifndef WX_PRECOMP
37#include <wx/wx.h>
38#endif
39
40#include "altitude.h"
41extern int g_iDashDepthUnit; // use same unit for altitude
42
43int m_aDataHeight;
44int x_alabel, y_alabel, a_plotdown, a_plotup, a_plotheight;
45
46DashboardInstrument_Altitude::DashboardInstrument_Altitude(
47 wxWindow* parent, wxWindowID id, wxString title,
48 InstrumentProperties* Properties)
49 : DashboardInstrument(parent, id, title, OCPN_DBP_STC_ALTI, Properties) {
50 m_cap_flag.set(OCPN_DBP_STC_TMP);
51 m_max_altitude = 0;
52 m_altitude = 0;
53 m_altitude_unit = getUsrDistanceUnit_Plugin(g_iDashDepthUnit);
54 m_temp = "--";
55 for (int idx = 0; idx < ALTITUDE_RECORD_COUNT; idx++) {
56 m_array_altitude[idx] = 0.0;
57 }
58}
59
60wxSize DashboardInstrument_Altitude::GetSize(int orient, wxSize hint) {
61 wxClientDC dc(this);
62 int w;
63 wxFont f;
64 if (m_Properties) {
65 f = m_Properties->m_TitleFont.GetChosenFont();
66 dc.GetTextExtent(m_title, &w, &m_TitleHeight, nullptr, nullptr, &f);
67 f = m_Properties->m_DataFont.GetChosenFont();
68 dc.GetTextExtent("15.7 Feet", &w, &m_aDataHeight, nullptr, nullptr, &f);
69 f = m_Properties->m_LabelFont.GetChosenFont();
70 dc.GetTextExtent("20.8 C", &x_alabel, &y_alabel, nullptr, nullptr, &f);
71 } else {
72 f = g_pFontTitle->GetChosenFont();
73 dc.GetTextExtent(m_title, &w, &m_TitleHeight, nullptr, nullptr, &f);
74 f = g_pFontData->GetChosenFont();
75 dc.GetTextExtent("15.7 Feet", &w, &m_aDataHeight, nullptr, nullptr, &f);
76 // Space for bottom(temp)text later.
77 f = g_pFontLabel->GetChosenFont();
78 dc.GetTextExtent("20.8 C", &x_alabel, &y_alabel, nullptr, nullptr, &f);
79 }
80 int y_total =
81 // Title Alt. data plot area air-temp
82 m_TitleHeight + m_aDataHeight + 4 * m_aDataHeight + y_alabel;
83 if (orient == wxHORIZONTAL) {
84 return {DefaultWidth, wxMax(y_total, hint.y)};
85 } else {
86 return {wxMax(hint.x, DefaultWidth), y_total};
87 }
88}
89
90void DashboardInstrument_Altitude::SetData(DASH_CAP st, double data,
91 wxString unit) {
92 if (st == OCPN_DBP_STC_ALTI) {
93 if (std::isnan(data)) {
94 m_cnt_valid = 0;
95 m_altitude = 0.0;
96 } else {
97 m_altitude = data;
98 // m_Altitude = m_Altitude*10.0 +1000; // inject fake testdata
99 if (m_cnt_valid < ALTITUDE_RECORD_COUNT && data != 0.0) m_cnt_valid++;
100 }
101 // printf("Altitude = %3.3f # %2d ", m_Altitude, m_cntValid); // debug
102
103 if (m_cnt_valid == 1) {
104 for (int idx = 1; idx < ALTITUDE_RECORD_COUNT; idx++) {
105 m_array_altitude[idx - 1] =
106 m_altitude; // init FIFO with 1st valid data
107 }
108 } else {
109 for (int idx = 1; idx < ALTITUDE_RECORD_COUNT; idx++) {
110 m_array_altitude[idx - 1] = m_array_altitude[idx]; // shift FIFO
111 }
112 }
113 m_array_altitude[ALTITUDE_RECORD_COUNT - 1] = m_altitude;
114 m_altitude_unit = unit;
115 } else if (st == OCPN_DBP_STC_ATMP) { // Air Temperature
116 if (!std::isnan(data)) {
117 m_temp = wxString::Format("%.1f", data) + DEGREE_SIGN + unit;
118 } else {
119 m_temp = "---";
120 }
121 }
122}
123
124void DashboardInstrument_Altitude::SetAttenuation(int steps) {
125 // fast int stuff
126 // increase the attenuation in 1 2 5 10 20 50 steps
127 if (steps > 0)
128 while (steps--) {
129 switch (m_attenuation) {
130 case 1:
131 m_attenuation = 2;
132 break;
133 case 2:
134 m_attenuation = 5;
135 break;
136 default:
137 m_attenuation = 1;
138 m_decade *= 10;
139 }
140 }
141 // decrease the attenuation in 1 2 5 10 20 50 steps
142 else if (steps < 0)
143 while (steps++) {
144 switch (m_attenuation) {
145 case 5:
146 m_attenuation = 2;
147 break;
148 case 2:
149 m_attenuation = 1;
150 break;
151 default:
152 m_attenuation = 5;
153 m_decade /= 10;
154 }
155 }
156 // bottom limit: unity
157 if (m_decade < 1) {
158 m_decade = 1;
159 m_attenuation = 1;
160 }
161}
162
163int DashboardInstrument_Altitude::GetAttenuation() const {
164 return m_attenuation * m_decade;
165}
166
167void DashboardInstrument_Altitude::Draw(wxGCDC* dc) {
168 DrawBackground(dc);
169 DrawForeground(dc);
170}
171
172void DashboardInstrument_Altitude::DrawBackground(wxGCDC* dc) {
173 wxSize size = GetClientSize();
174 wxColour cl;
175 if (m_Properties) {
176 dc->SetTextForeground(
177 GetColourSchemeFont(m_Properties->m_LabelFont.GetColour()));
178 } else {
179 if (GetColourSchemeFont(g_pFontSmall->GetColour()) ==
180 GetColourSchemeFont(g_pFontLabel->GetColour())) {
181 GetGlobalColor("DASHL", &cl);
182 dc->SetTextForeground(cl);
183 } else
184 dc->SetTextForeground(GetColourSchemeFont(g_pFontLabel->GetColour()));
185 }
186
187 wxPen pen;
188 pen.SetStyle(wxPENSTYLE_SOLID);
189 if (m_Properties)
190 cl = GetColourSchemeFont(m_Properties->m_SmallFont.GetColour());
191 else
192 cl = GetColourSchemeFont(g_pFontSmall->GetColour());
193 // GetGlobalColor("DASHF", &cl);
194 pen.SetColour(cl);
195 pen.SetWidth(1);
196 dc->SetPen(pen);
197
198 a_plotup = m_TitleHeight + m_aDataHeight;
199 a_plotdown = size.y - y_alabel;
200 a_plotheight = a_plotdown - a_plotup;
201
202 // dc->DrawLine(3, 44, size.x - 3, 44);
203 dc->DrawLine(3, a_plotdown, size.x - 3, a_plotdown);
204
205#ifdef __WXMSW__
206 pen.SetStyle(wxPENSTYLE_SHORT_DASH);
207#else
208 pen.SetStyle(wxPENSTYLE_DOT);
209 pen.SetWidth(1);
210#endif
211
212 // Grid lines
213 dc->SetPen(pen);
214 dc->DrawLine(3, a_plotup, size.x - 3, a_plotup);
215 dc->DrawLine(3, a_plotup + a_plotheight / 4, size.x - 3,
216 a_plotup + a_plotheight / 4);
217 dc->DrawLine(3, a_plotup + a_plotheight * 2 / 4, size.x - 3,
218 a_plotup + a_plotheight * 2 / 4);
219 dc->DrawLine(3, a_plotup + a_plotheight * 3 / 4, size.x - 3,
220 a_plotup + a_plotheight * 3 / 4);
221 if (m_Properties) {
222 dc->SetFont(m_Properties->m_SmallFont.GetChosenFont());
223 dc->SetTextForeground(
224 GetColourSchemeFont(m_Properties->m_SmallFont.GetColour()));
225 } else {
226 dc->SetFont(g_pFontSmall->GetChosenFont());
227 dc->SetTextForeground(GetColourSchemeFont(g_pFontSmall->GetColour()));
228 }
229
230 // evaluate buffered data to determine its range, mean, variance
231 m_mean_altitude = m_array_altitude[0]; // moving average
232 double MaxAltitude = m_array_altitude[0];
233 double MinAltitude = m_array_altitude[0];
234 double sum2Altitude = m_array_altitude[0] * m_array_altitude[0]; // sum^2
235 for (int idx = 1; idx < ALTITUDE_RECORD_COUNT; idx++) {
236 MaxAltitude = std::max(MaxAltitude, m_array_altitude[idx]);
237 MinAltitude = std::min(MinAltitude, m_array_altitude[idx]);
238 m_mean_altitude += m_array_altitude[idx];
239 sum2Altitude += m_array_altitude[idx] * m_array_altitude[idx];
240 }
241 m_mean_altitude /= ALTITUDE_RECORD_COUNT;
242
243 // calculate 2nd Moment
244 double varAltitude = sum2Altitude / ALTITUDE_RECORD_COUNT;
245 varAltitude -= m_mean_altitude * m_mean_altitude;
246 // estimator bias correction
247 varAltitude *= (ALTITUDE_RECORD_COUNT / (ALTITUDE_RECORD_COUNT - 1.0));
248 // printf("varAltitude = %5.3f\n", varAltitude); // debug output
249 if (varAltitude < 0.0) varAltitude = 0.0; // avoid nan when calling sqrt().
250
251 // do AGC to adjust scaling
252 double range = MaxAltitude - MinAltitude;
253 if (range > 1.1 * m_range) SetAttenuation(+1);
254 if (range < 0.3 * m_range) SetAttenuation(-1); // some hysteresis
255 double grid = GetAttenuation();
256 m_range = grid * c_grid_lines;
257
258 // only update axes on major corridor changes
259 if ((MaxAltitude - m_max_altitude) / grid > 0.25 ||
260 (MaxAltitude - m_max_altitude) / grid < -0.75 * c_grid_lines) {
261 m_max_altitude = (round(MaxAltitude / grid) + 1) * grid;
262 m_min_altitude = m_max_altitude - m_range;
263 }
264 if ((MinAltitude - m_min_altitude) / grid < -0.25 ||
265 (MinAltitude - m_min_altitude) / grid > 0.75 * c_grid_lines) {
266 m_min_altitude = (round(MinAltitude / grid) - 1) * grid;
267 m_max_altitude = m_min_altitude + m_range;
268 }
269 // debug output
270 // printf("m_MinAltitude=%7.1f m_MaxAltitude=%7.1f m_Range = %5.1f "
271 // " range = %5.1f att=%d , mean=%7.2f, std=%5.2f\n",
272 // m_MinAltitude, m_MaxAltitude, m_Range,
273 // range, getAttenuation(), m_meanAltitude, sqrt(varAltitude));
274
275 wxString label;
276 label.Printf("+/-%.1f %8.0f " + m_altitude_unit, sqrt(varAltitude),
277 m_max_altitude);
278 int width, height;
279 wxFont f;
280 if (m_Properties)
281 f = m_Properties->m_SmallFont.GetChosenFont();
282 else
283 f = g_pFontSmall->GetChosenFont();
284 dc->GetTextExtent(label, &width, &height, 0, 0, &f);
285 dc->DrawText(label, size.x - width - 1, a_plotup - height);
286
287 label.Printf("%.1f/ %8.0f " + m_altitude_unit, m_range / c_grid_lines,
288 m_min_altitude);
289 if (m_Properties)
290 f = m_Properties->m_SmallFont.GetChosenFont();
291 else
292 f = g_pFontSmall->GetChosenFont();
293 dc->GetTextExtent(label, &width, &height, 0, 0, &f);
294 dc->DrawText(label, size.x - width - 1, a_plotdown);
295}
296
297void DashboardInstrument_Altitude::DrawForeground(wxGCDC* dc) {
298 wxSize size = GetClientSize();
299 wxColour cl;
300 if (m_Properties) {
301 cl = GetColourSchemeFont(m_Properties->m_LabelFont.GetColour());
302 } else {
303 if (GetColourSchemeFont(g_pFontSmall->GetColour()) ==
304 GetColourSchemeFont(g_pFontLabel->GetColour()))
305 GetGlobalColor("DASH1", &cl);
306 else
307 cl = GetColourSchemeFont(g_pFontLabel->GetColour());
308 }
309 // GetGlobalColor("DASH1", &cl);
310 wxBrush brush;
311 brush.SetStyle(wxBRUSHSTYLE_SOLID);
312 brush.SetColour(cl);
313 dc->SetBrush(brush);
314 dc->SetPen(*wxTRANSPARENT_PEN);
315
316 double ratioH = double(a_plotheight) / m_range;
317 double ratioW = double(size.x - 6) / (ALTITUDE_RECORD_COUNT - 1);
318 wxPoint points[ALTITUDE_RECORD_COUNT + 2];
319#ifdef __ANDROID__
320 int px = 3;
321 points[0].x = px;
322 points[0].y = a_plotdown;
323
324 for (int idx = 0; idx < ALTITUDE_RECORD_COUNT - 1; idx++) {
325 points[1].x = points[0].x;
326 if (m_array_altitude[idx])
327 points[1].y =
328 a_plotdown - (m_array_altitude[idx] - m_min_altitude) * ratioH;
329 else
330 points[1].y = a_plotdown;
331
332 points[2].x = points[1].x + ratioW;
333 if (m_array_altitude[idx + 1])
334 points[2].y =
335 a_plotdown - (m_array_altitude[idx + 1] - m_min_altitude) * ratioH;
336 else
337 points[2].y = a_plotdown;
338
339 points[3].x = points[2].x;
340 points[3].y = a_plotdown;
341 dc->DrawPolygon(4, points);
342
343 points[0].x = points[2].x;
344 points[0].y = a_plotdown;
345 }
346
347#else
348 for (int idx = 0; idx < ALTITUDE_RECORD_COUNT; idx++) {
349 points[idx].x = idx * ratioW + 3;
350 points[idx].y =
351 a_plotdown - (m_array_altitude[idx] - m_min_altitude) * ratioH;
352 }
353 points[ALTITUDE_RECORD_COUNT].x = size.x - 3;
354 points[ALTITUDE_RECORD_COUNT].y = a_plotdown;
355 points[ALTITUDE_RECORD_COUNT + 1].x = 3;
356 points[ALTITUDE_RECORD_COUNT + 1].y = a_plotdown;
357 dc->DrawPolygon(ALTITUDE_RECORD_COUNT + 2, points);
358#endif
359 if (m_Properties) {
360 dc->SetFont(m_Properties->m_DataFont.GetChosenFont());
361 dc->SetTextForeground(
362 GetColourSchemeFont(m_Properties->m_DataFont.GetColour()));
363 } else {
364 // GetGlobalColor("DASHF", &cl);
365 dc->SetTextForeground(GetColourSchemeFont(g_pFontData->GetColour()));
366 dc->SetFont(g_pFontData->GetChosenFont());
367 }
368 if (m_altitude_unit != "-") { // Watchdog
369 wxString s_alti = wxString::Format("%.1f", m_mean_altitude);
370 dc->DrawText(s_alti + " " + m_altitude_unit, 10, m_TitleHeight);
371 } else
372 dc->DrawText("---", 10, m_TitleHeight);
373
374 // TODO: test display air temperature ID_DBP_I_ATMP
375 if (m_Properties)
376 dc->SetFont(m_Properties->m_LabelFont.GetChosenFont());
377 else
378 dc->SetFont(g_pFontLabel->GetChosenFont());
379 int width, height;
380 wxFont f;
381 if (m_Properties) {
382 f = m_Properties->m_LabelFont.GetChosenFont();
383 dc->GetTextExtent(m_temp, &width, &height, 0, 0, &f);
384 } else {
385 f = g_pFontLabel->GetChosenFont();
386 dc->GetTextExtent(m_temp, &width, &height, 0, 0, &f);
387 }
388 dc->DrawText(m_temp, 3, a_plotdown);
389}
Dashboard altitude instrument.
DASH_CAP
Definition instrument.h:77
@ OCPN_DBP_STC_ALTI
Altitude.
Definition instrument.h:113
@ OCPN_DBP_STC_ATMP
Air Temperature.
Definition instrument.h:103
@ OCPN_DBP_STC_TMP
Water temperature.
Definition instrument.h:93
wxString getUsrDistanceUnit_Plugin(int unit)
Gets display string for user's preferred distance unit.