OpenCPN Partial API docs
Loading...
Searching...
No Matches
wind.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 by Jean-Eudes Onfray *
3 * Copyright (C) 2010 by David S. Register *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
25#include <wx/wxprec.h>
26
27#include <cmath>
28
29#ifndef WX_PRECOMP
30#include <wx/wx.h>
31#endif
32
33#include <wx/tokenzr.h>
34
35#include "wind.h"
36
37// Display the arrow for MainValue (wind angle)
38// We also want the extra value (wind speed) displayed inside the dial
39
40DashboardInstrument_Wind::DashboardInstrument_Wind(
41 wxWindow* parent, wxWindowID id, wxString title,
42 InstrumentProperties* Properties, DASH_CAP cap_flag)
43 : DashboardInstrument_Dial(parent, id, std::move(title), Properties,
44 cap_flag, 0, 360, 0, 360) {
45 SetOptionMarker(10, DIAL_MARKER_REDGREENBAR, 3);
46 // Labels are set static because we've no logic to display them this way
47 wxString labels[] = {"", "30", "60", "90", "120", "150",
48 "", "150", "120", "90", "60", "30"};
49 SetOptionLabel(30, DIAL_LABEL_HORIZONTAL, wxArrayString(12, labels));
50}
51
52void DashboardInstrument_Wind::DrawBackground(wxGCDC* dc) {
53 DrawBoat(dc, m_cx, m_cy, m_radius);
54}
55
56DashboardInstrument_WindCompass::DashboardInstrument_WindCompass(
57 wxWindow* parent, wxWindowID id, wxString title,
58 InstrumentProperties* Properties, DASH_CAP cap_flag)
59 : DashboardInstrument_Dial(parent, id, std::move(title), Properties,
60 cap_flag, 0, 360, 0, 360) {
61 SetOptionMarker(5, DIAL_MARKER_SIMPLE, 2);
62 wxString labels[] = {_("N"), _("NE"), _("E"), _("SE"),
63 _("S"), _("SW"), _("W"), _("NW")};
64 SetOptionLabel(45, DIAL_LABEL_HORIZONTAL, wxArrayString(8, labels));
65}
66
67void DashboardInstrument_WindCompass::DrawBackground(wxGCDC* dc) {
68 DrawCompassRose(dc, m_cx, m_cy, static_cast<int>(m_radius * 0.85),
69 m_angle_start, false, m_Properties);
70}
71
72// Display the arrow for MainValue (wind angle)
73// We also want the extra value (wind speed) displayed inside the dial
74
75DashboardInstrument_TrueWindAngle::DashboardInstrument_TrueWindAngle(
76 wxWindow* parent, wxWindowID id, wxString title,
77 InstrumentProperties* Properties, DASH_CAP cap_flag)
78 : DashboardInstrument_Dial(parent, id, std::move(title), Properties,
79 cap_flag, 0, 360, 0, 360) {
80 SetOptionMarker(10, DIAL_MARKER_REDGREENBAR, 3);
81 // Labels are set static because we've no logic to display them this way
82 wxString labels[] = {"", "30", "60", "90", "120", "150",
83 "", "150", "120", "90", "60", "30"};
84 SetOptionLabel(30, DIAL_LABEL_HORIZONTAL, wxArrayString(12, labels));
85}
86
87void DashboardInstrument_TrueWindAngle::DrawBackground(wxGCDC* dc) {
88 DrawBoat(dc, m_cx, m_cy, m_radius);
89}
90
91/*****************************************************************************
92 Apparent & True wind angle combined in one dial instrument
93 Author: Thomas Rauch
94******************************************************************************/
95DashboardInstrument_AppTrueWindAngle::DashboardInstrument_AppTrueWindAngle(
96 wxWindow* parent, wxWindowID id, wxString title,
97 InstrumentProperties* Properties, DASH_CAP cap_flag)
98 : DashboardInstrument_Dial(parent, id, title, Properties, cap_flag, 0, 360,
99 0, 360) {
100 SetOptionMarker(10, DIAL_MARKER_REDGREENBAR, 3);
101 // Labels are set static because we've no logic to display them this way
102 wxString labels[] = {"", "30", "60", "90", "120", "150",
103 "", "150", "120", "90", "60", "30"};
104 SetOptionLabel(30, DIAL_LABEL_HORIZONTAL, wxArrayString(12, labels));
105}
106
107void DashboardInstrument_AppTrueWindAngle::DrawBackground(wxGCDC* dc) {
108 DrawBoat(dc, m_cx, m_cy, m_radius);
109}
110
111void DashboardInstrument_AppTrueWindAngle::SetData(DASH_CAP st, double data,
112 wxString unit) {
113 if (st == OCPN_DBP_STC_TWA) {
114 m_MainValueTrue = data;
115 m_MainValueTrueUnit = unit;
116 m_MainValueOption2 = DIAL_POSITION_BOTTOMLEFT;
117 } else if (st == OCPN_DBP_STC_AWA) {
118 m_MainValueApp = data;
119 m_MainValueAppUnit = unit;
120 m_MainValueOption1 = DIAL_POSITION_TOPLEFT;
121 } else if (st == OCPN_DBP_STC_AWS) {
122 m_ExtraValueApp = data;
123 m_ExtraValueAppUnit = unit;
124 m_ExtraValueOption1 = DIAL_POSITION_TOPRIGHT;
125 } else if (st == OCPN_DBP_STC_TWS) {
126 m_ExtraValueTrue = data;
127 m_ExtraValueTrueUnit = unit;
128 m_ExtraValueOption2 = DIAL_POSITION_BOTTOMRIGHT;
129 }
130 Refresh();
131}
132void DashboardInstrument_AppTrueWindAngle::Draw(wxGCDC* bdc) {
133 if (m_Properties) {
134 wxBrush b1(
135 GetColourSchemeBackgroundColour(m_Properties->m_DataBackgroundColour));
136 bdc->SetBackground(
137 GetColourSchemeBackgroundColour(m_Properties->m_DataBackgroundColour));
138 } else {
139 wxColour c1;
140 GetGlobalColor("DASHB", &c1);
141 wxBrush b1(c1);
142 bdc->SetBackground(b1);
143 }
144 bdc->Clear();
145
146 wxSize size = GetClientSize();
147 int width, height;
148 wxFont f;
149 if (m_Properties)
150 f = m_Properties->m_LabelFont.GetChosenFont();
151 else
152 f = g_pFontLabel->GetChosenFont();
153 bdc->GetTextExtent("000", &width, &height, nullptr, nullptr, &f);
154 m_cx = size.x / 2;
155 int availableHeight = GetDataBottom(size.y) - m_DataTop;
156 InitTitleAndDataPosition(availableHeight);
157 availableHeight -= height;
158 m_cy = m_DataTop + height / 2;
159 m_cy += availableHeight / 2;
160 m_radius = static_cast<int>(availableHeight / 2.0 * 0.95);
161
162 DrawLabels(bdc);
163 DrawFrame(bdc);
164 DrawMarkers(bdc);
165 DrawBackground(bdc);
166 DrawData(bdc, m_MainValueApp, m_MainValueAppUnit, m_main_value_format,
167 m_MainValueOption1);
168 DrawData(bdc, m_MainValueTrue, m_MainValueTrueUnit, m_main_value_format,
169 m_MainValueOption2);
170 DrawData(bdc, m_ExtraValueApp, m_ExtraValueAppUnit, m_extra_value_format,
171 m_ExtraValueOption1);
172 DrawData(bdc, m_ExtraValueTrue, m_ExtraValueTrueUnit, m_extra_value_format,
173 m_ExtraValueOption2);
174 DrawForeground(bdc);
175}
176void DashboardInstrument_AppTrueWindAngle::DrawForeground(wxGCDC* dc) {
177 wxPoint points[4];
178 double data;
179 double val;
180 double value;
181 // The default foreground is the arrow used in most dials
182 wxColour cl;
183 GetGlobalColor("DASH2", &cl);
184 wxPen pen1;
185 pen1.SetStyle(wxPENSTYLE_SOLID);
186 pen1.SetColour(cl);
187 pen1.SetWidth(2);
188 dc->SetPen(pen1);
189 GetGlobalColor("DASH1", &cl);
190 wxBrush brush1;
191 brush1.SetStyle(wxBRUSHSTYLE_SOLID);
192 brush1.SetColour(cl);
193 dc->SetBrush(brush1);
194 dc->DrawCircle(m_cx, m_cy, m_radius / 8);
195
196 /*True Wind*/
197 dc->SetPen(*wxTRANSPARENT_PEN);
198 if (m_Properties)
199 cl = GetColourSchemeFont(m_Properties->m_Arrow_Second_Colour);
200 else
201 GetGlobalColor("BLUE3", &cl);
202 wxBrush brush2;
203 brush2.SetStyle(wxBRUSHSTYLE_SOLID);
204 brush2.SetColour(cl);
205 dc->SetBrush(brush2);
206
207 /* this is fix for a +/-180? round instrument, when m_MainValue is supplied as
208 * <0..180><L | R> for example TWA & AWA */
209 if (m_MainValueTrueUnit == "\u00B0L")
210 data = 360 - m_MainValueTrue;
211 else
212 data = m_MainValueTrue;
213
214 // The arrow should stay inside fixed limits
215 if (data < m_main_value_min)
216 val = m_main_value_min;
217 else if (data > m_main_value_max)
218 val = m_main_value_max;
219 else
220 val = data;
221
222 value = deg2rad((val - m_main_value_min) * m_angle_range /
223 (m_main_value_max - m_main_value_min)) +
224 deg2rad(m_angle_start - ANGLE_OFFSET);
225
226 points[0].x = static_cast<int>(m_cx + (m_radius * 0.95 * cos(value - .010)));
227 points[0].y = static_cast<int>(m_cy + (m_radius * 0.95 * sin(value - .010)));
228 points[1].x = static_cast<int>(m_cx + (m_radius * 0.95 * cos(value + .015)));
229 points[1].y = static_cast<int>(m_cy + (m_radius * 0.95 * sin(value + .015)));
230 points[2].x = static_cast<int>(m_cx + (m_radius * 0.22 * cos(value + 2.8)));
231 points[2].y = static_cast<int>(m_cy + (m_radius * 0.22 * sin(value + 2.8)));
232 points[3].x = static_cast<int>(m_cx + (m_radius * 0.22 * cos(value - 2.8)));
233 points[3].y = static_cast<int>(m_cy + (m_radius * 0.22 * sin(value - 2.8)));
234 dc->DrawPolygon(4, points, 0, 0);
235
236 /* Apparent Wind*/
237 dc->SetPen(*wxTRANSPARENT_PEN);
238 if (m_Properties)
239 cl = GetColourSchemeFont(m_Properties->m_Arrow_First_Colour);
240 else
241 GetGlobalColor("DASHN", &cl);
242 wxBrush brush;
243 brush.SetStyle(wxBRUSHSTYLE_SOLID);
244 brush.SetColour(cl);
245 dc->SetBrush(brush);
246
247 /* this is fix for a +/-180? round instrument, when m_MainValue is supplied as
248 * <0..180><L | R> for example TWA & AWA */
249 if (m_MainValueAppUnit == "\u00B0L")
250 data = 360 - m_MainValueApp;
251 else
252 data = m_MainValueApp;
253
254 // The arrow should stay inside fixed limits
255 if (data < m_main_value_min)
256 val = m_main_value_min;
257 else if (data > m_main_value_max)
258 val = m_main_value_max;
259 else
260 val = data;
261
262 value = deg2rad((val - m_main_value_min) * m_angle_range /
263 (m_main_value_max - m_main_value_min)) +
264 deg2rad(m_angle_start - ANGLE_OFFSET);
265
266 points[0].x = static_cast<int>(m_cx + (m_radius * 0.95 * cos(value - .010)));
267 points[0].y = static_cast<int>(m_cy + (m_radius * 0.95 * sin(value - .010)));
268 points[1].x = static_cast<int>(m_cx + (m_radius * 0.95 * cos(value + .015)));
269 points[1].y = static_cast<int>(m_cy + (m_radius * 0.95 * sin(value + .015)));
270 points[2].x = static_cast<int>(m_cx + (m_radius * 0.22 * cos(value + 2.8)));
271 points[2].y = static_cast<int>(m_cy + (m_radius * 0.22 * sin(value + 2.8)));
272 points[3].x = static_cast<int>(m_cx + (m_radius * 0.22 * cos(value - 2.8)));
273 points[3].y = static_cast<int>(m_cy + (m_radius * 0.22 * sin(value - 2.8)));
274 dc->DrawPolygon(4, points, 0, 0);
275}
276void DashboardInstrument_AppTrueWindAngle::DrawData(
277 wxGCDC* dc, double value, wxString unit, wxString format,
278 DialPositionOption position) {
279 if (position == DIAL_POSITION_NONE) return;
280
281 wxColour cl;
282 if (m_Properties) {
283 dc->SetFont(m_Properties->m_LabelFont.GetChosenFont());
284 cl = GetColourSchemeFont(m_Properties->m_LabelFont.GetColour());
285 } else {
286 dc->SetFont(g_pFontLabel->GetChosenFont());
287 cl = GetColourSchemeFont(g_pFontLabel->GetColour());
288 }
289 // GetGlobalColor("DASHF", &cl);
290 dc->SetTextForeground(cl);
291
292 wxSize size = GetClientSize();
293
294 wxString text;
295 if (!std::isnan(value)) {
296 if (unit == "\u00B0")
297 text = wxString::Format(format, value) + DEGREE_SIGN;
298 else if (unit == "\u00B0L") // No special display for now, might be
299 // XX?< (as in text-only instrument)
300 text = wxString::Format(format, value) + DEGREE_SIGN;
301 else if (unit == "\u00B0R") // No special display for now, might be >XX?
302 text = wxString::Format(format, value) + DEGREE_SIGN;
303 else if (unit == "\u00B0T")
304 text = wxString::Format(format, value) + DEGREE_SIGN + "T";
305 else if (unit == "\u00B0M")
306 text = wxString::Format(format, value) + DEGREE_SIGN + "M";
307 else if (unit == "N") // Knots
308 text = wxString::Format(format, value) + " Kts";
309 else
310 text = wxString::Format(format, value) + " " + unit;
311 } else
312 text = "---";
313
314 int width, height;
315 wxFont f;
316 if (m_Properties)
317 f = m_Properties->m_LabelFont.GetChosenFont();
318 else
319 f = g_pFontLabel->GetChosenFont();
320 dc->GetMultiLineTextExtent(text, &width, &height, nullptr, &f);
321
322 wxRect TextPoint;
323 TextPoint.width = width;
324 TextPoint.height = height;
325 wxColour c3;
326
327 switch (position) {
328 case DIAL_POSITION_NONE:
329 // This case was already handled before, it's here just
330 // to avoid compiler warning.
331 return;
332 case DIAL_POSITION_INSIDE: {
333 TextPoint.x = m_cx - (width / 2) - 1;
334 TextPoint.y = ((size.y - m_InstrumentSpacing) * .75) - height;
335 if ((g_TitleAlignment & wxALIGN_BOTTOM) != 0)
336 TextPoint.y -= m_TitleHeight;
337 GetGlobalColor("DASHL", &cl);
338 int penwidth = size.x / 100;
339 wxPen* pen =
340 wxThePenList->FindOrCreatePen(cl, penwidth, wxPENSTYLE_SOLID);
341 dc->SetPen(*pen);
342 GetGlobalColor("DASHB", &cl);
343 dc->SetBrush(cl);
344 // There might be a background drawn below
345 // so we must clear it first.
346 dc->DrawRoundedRectangle(TextPoint.x - 2, TextPoint.y - 2, width + 4,
347 height + 4, 3);
348 break;
349 }
350 case DIAL_POSITION_TOPLEFT:
351 GetGlobalColor("DASHN", &c3);
352 TextPoint.x = 0;
353 TextPoint.y = m_DataTop;
354 text = "A:" + text;
355 break;
356 case DIAL_POSITION_TOPRIGHT:
357 GetGlobalColor("DASHN", &c3);
358 TextPoint.x = size.x - width - 1;
359 TextPoint.y = m_DataTop;
360 break;
361 case DIAL_POSITION_BOTTOMLEFT:
362 GetGlobalColor("BLUE3", &c3);
363 text = "T:" + text;
364 TextPoint.x = 0;
365 TextPoint.y = GetDataBottom(size.y) - height;
366 break;
367 case DIAL_POSITION_BOTTOMRIGHT:
368 GetGlobalColor("BLUE3", &c3);
369 TextPoint.x = size.x - width - 1;
370 TextPoint.y = GetDataBottom(size.y) - height;
371 break;
372 default:
373 break;
374 }
375 wxColour c2;
376 GetGlobalColor("DASHB", &c2);
377 wxStringTokenizer tkz(text, "\n");
378 wxString token;
379
380 token = tkz.GetNextToken();
381 while (token.Length()) {
382 if (m_Properties) {
383 f = m_Properties->m_LabelFont.GetChosenFont();
384 dc->GetTextExtent(token, &width, &height, nullptr, nullptr, &f);
385 } else {
386 f = g_pFontLabel->GetChosenFont();
387 dc->GetTextExtent(token, &width, &height, nullptr, nullptr, &f);
388 }
389 dc->DrawText(token, TextPoint.x, TextPoint.y);
390 TextPoint.y += height;
391 token = tkz.GetNextToken();
392 }
393}
DASH_CAP
Definition instrument.h:77
@ OCPN_DBP_STC_AWA
Apparent wind angle.
Definition instrument.h:88
@ OCPN_DBP_STC_AWS
Apparent wind speed.
Definition instrument.h:89
@ OCPN_DBP_STC_TWA
True wind angle.
Definition instrument.h:90
@ OCPN_DBP_STC_TWS
True wind speed.
Definition instrument.h:91
Dashboard wind instrument implementation.