OpenCPN Partial API docs
Loading...
Searching...
No Matches
gps.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#ifndef WX_PRECOMP
28#include <wx/wx.h>
29#endif
30
31#include "gps.h"
32
33// Required deg2rad
34#include "dial.h"
35
36DashboardInstrument_GPS::DashboardInstrument_GPS(
37 wxWindow* parent, wxWindowID id, wxString title,
38 InstrumentProperties* Properties)
39 : DashboardInstrument(parent, id, title, OCPN_DBP_STC_GPS, Properties) {
40 m_ref_dim = wxWindow::GetCharHeight() * 80 / 100;
41 m_ref_dim *= OCPN_GetWinDIPScaleFactor() < 1.0
43 : 1.0; // 1.5
44
45 m_cx = 35;
46 m_cy = static_cast<int>(m_ref_dim * 35 / 10);
47 m_radius = m_ref_dim * 2;
48 m_scale_delta = m_ref_dim / 2;
49 m_scale_base = (m_radius * 2) + (2 * m_ref_dim);
50
51 for (int idx = 0; idx < 12; idx++) {
52 m_sat_info[idx].SatNumber = 0;
53 m_sat_info[idx].ElevationDegrees = 0;
54 m_sat_info[idx].AzimuthDegreesTrue = 0;
55 m_sat_info[idx].SignalToNoiseRatio = 0;
56 }
57 m_sat_count = 0;
58 talker_id = wxEmptyString;
59 for (int i = 0; i < GNSS_SYSTEM; i++) {
60 m_gtime[i] = 10000;
61 }
62 m_last_shift = wxDateTime::Now();
63 b_shift = false;
64 m_talker = wxEmptyString;
65 m_master = 1; // Start with the GPS system
66 m_max_sat_count = 0;
67}
68
69wxSize DashboardInstrument_GPS::GetSize(int orient, wxSize hint) {
70 wxClientDC dc(this);
71 int w;
72 wxFont f;
73 if (m_Properties)
74 f = m_Properties->m_TitleFont.GetChosenFont();
75 else
76 f = g_pFontTitle->GetChosenFont();
77 dc.GetTextExtent(m_title, &w, &m_TitleHeight, nullptr, nullptr, &f);
78 w = (12 * m_ref_dim); // Max 12 vertical bars
79 if (orient == wxHORIZONTAL) {
80 m_cx = w / 2;
81 return wxSize(w, wxMax(hint.y, m_TitleHeight + (m_ref_dim * 84 / 10)));
82 } else {
83 w = wxMax(hint.x, w);
84 m_cx = w / 2;
85 return wxSize(w, m_TitleHeight + (m_ref_dim * 84 / 10));
86 }
87}
88
89void DashboardInstrument_GPS::SetSatInfo(int cnt, int seq, wxString talk,
90 SAT_INFO sats[4]) {
91 m_sat_count = cnt;
92 talker_id = talk;
93
94 /* Some GNSS receivers may emit more than (3*4)=12 sats info.
95 We read the three first only since our graphic is
96 is not adapted for more than 12 satellites*/
97 if (seq < 1 || seq > 3) return;
98
99 if (talker_id != wxEmptyString) {
100 /* Switch view between the six GNSS system
101 mentioned in NMEA0183, when available.
102 Show each system for 20 seconds.
103 Time to shift now? */
104 wxDateTime now = wxDateTime::Now();
105 wxTimeSpan sinceLastShift = now - m_last_shift;
106 if (sinceLastShift.GetSeconds() > 20) {
107 b_shift = true;
108 m_last_shift = now;
109 }
110 if (b_shift) {
111 // Who's here and in turn to show up next
112 bool secondturn = false;
113 int im = m_master == GNSS_SYSTEM - 1 ? 0 : m_master + 1;
114 for (int i = im; i < GNSS_SYSTEM; i++) {
115 wxTimeSpan lastUpdate = now - m_gtime[i];
116 if (lastUpdate.GetSeconds() < 6) {
117 m_master = i;
118 b_shift = false;
119 m_max_sat_count = 0;
120 break;
121 }
122 if (i == 5 && !secondturn) {
123 i = -1;
124 secondturn = true;
125 }
126 }
127 }
128 if (talker_id == "GP") {
129 m_gtime[1] = now;
130 if (m_master != 1) return;
131 // If two groups of messages in this sequence
132 // show only the first one with most(12) satellites
133 if (m_max_sat_count > m_sat_count)
134 return;
135 else
136 m_max_sat_count = m_sat_count;
137 m_talker = wxString::Format("GPS\n%d", m_sat_count);
138 } else if (talker_id == "GL") {
139 m_gtime[2] = now;
140 if (m_master != 2) return;
141 // See "GP" above
142 if (m_max_sat_count > m_sat_count)
143 return;
144 else
145 m_max_sat_count = m_sat_count;
146 m_talker = wxString::Format("GLONASS\n%d", m_sat_count);
147 } else if (talker_id == "GA") {
148 m_gtime[3] = now;
149 if (m_master != 3) return;
150 // See "GP" above
151 if (m_max_sat_count > m_sat_count)
152 return;
153 else
154 m_max_sat_count = m_sat_count;
155 m_talker = wxString::Format("Galileo\n%d", m_sat_count);
156 } else if (talker_id == "GB" || talker_id == "BD") { // BeiDou BDS
157 m_gtime[4] = now;
158 if (m_master != 4) return;
159 // See "GP" above
160 if (m_max_sat_count > m_sat_count)
161 return;
162 else
163 m_max_sat_count = m_sat_count;
164 m_talker = wxString::Format("BeiDou\n%d", m_sat_count);
165 } else if (talker_id == "GI") {
166 m_gtime[5] = now;
167 if (m_master != 5) return;
168 // See "GP" above
169 if (m_max_sat_count > m_sat_count)
170 return;
171 else
172 m_max_sat_count = m_sat_count;
173 m_talker = wxString::Format("NavIC\n%d", m_sat_count);
174 } else if (talker_id == "GQ") {
175 m_gtime[0] = now;
176 if (m_master != 0) return;
177 // See "GP" above
178 if (m_max_sat_count > m_sat_count)
179 return;
180 else
181 m_max_sat_count = m_sat_count;
182 m_talker = wxString::Format("QZSS\n%d", m_sat_count);
183 } else {
184 // Would be a not known N2k PGP type like "Combined GPS/GLONASS"
185 m_talker = wxString::Format("%s\n%d", talker_id, m_sat_count);
186 }
187 }
188
189 int lidx = (seq - 1) * 4;
190 for (int idx = 0; idx < 4; idx++) {
191 m_sat_info[lidx + idx].SatNumber = sats[idx].SatNumber;
192 m_sat_info[lidx + idx].ElevationDegrees = sats[idx].ElevationDegrees;
193 m_sat_info[lidx + idx].AzimuthDegreesTrue = sats[idx].AzimuthDegreesTrue;
194 m_sat_info[lidx + idx].SignalToNoiseRatio = sats[idx].SignalToNoiseRatio;
195 }
196 // Clean out possible leftovers.
197 for (int idx = m_sat_count; idx < 12; idx++) {
198 m_sat_info[idx].SatNumber = 0;
199 m_sat_info[idx].SignalToNoiseRatio = 0;
200 }
201}
202
203void DashboardInstrument_GPS::Draw(wxGCDC* dc) {
204 DrawFrame(dc);
205 DrawBackground(dc);
206 DrawForeground(dc);
207}
208
209void DashboardInstrument_GPS::DrawFrame(wxGCDC* dc) {
210 wxSize size = GetClientSize();
211 wxColour cb;
212 if (m_Properties)
213 cb = GetColourSchemeBackgroundColour(m_Properties->m_DataBackgroundColour);
214 else
215 GetGlobalColor("DASHB", &cb);
216 dc->SetTextBackground(cb);
217 dc->SetBackgroundMode(wxSOLID);
218
219 wxColour cl;
220 if (m_Properties)
221 cl = GetColourSchemeBackgroundColour(m_Properties->m_TitleBackgroundColour);
222 else
223 GetGlobalColor("DASHL", &cl);
224 dc->SetTextForeground(cl);
225 dc->SetBrush(*wxTRANSPARENT_BRUSH);
226
227 wxPen pen;
228 pen.SetStyle(wxPENSTYLE_SOLID);
229 wxColour cf;
230 GetGlobalColor("DASHF", &cf);
231 pen.SetColour(cf);
232 pen.SetWidth(1);
233 dc->SetPen(pen);
234
235 dc->DrawCircle(m_cx, m_cy, m_radius);
236 if (m_Properties)
237 dc->SetFont((m_Properties->m_SmallFont.GetChosenFont()));
238 else
239 dc->SetFont((g_pFontSmall->GetChosenFont()));
240
241 wxScreenDC sdc;
242 int height, width;
243 wxFont f;
244 if (m_Properties)
245 f = m_Properties->m_SmallFont.GetChosenFont();
246 else
247 f = g_pFontSmall->GetChosenFont();
248 sdc.GetTextExtent("W", &width, &height, nullptr, nullptr, &f);
249
250 wxBitmap tbm(width, height, -1);
251 wxMemoryDC tdc(tbm);
252 tdc.SetBackground(cb);
253 // tdc.SetTextForeground(cl);
254 tdc.SetTextBackground(cb);
255 tdc.SetBackgroundMode(wxSOLID);
256 if (m_Properties) {
257 tdc.SetFont(m_Properties->m_SmallFont.GetChosenFont());
258 tdc.SetTextForeground(
259 GetColourSchemeFont(m_Properties->m_SmallFont.GetColour()));
260 } else {
261 tdc.SetFont(g_pFontSmall->GetChosenFont());
262 tdc.SetTextForeground(GetColourSchemeFont(g_pFontSmall->GetColour()));
263 }
264 tdc.Clear();
265 tdc.DrawText(_("N"), 0, 0);
266 dc->Blit(m_cx - 3, m_cy - m_radius - 6, width, height, &tdc, 0, 0);
267
268 tdc.Clear();
269 tdc.DrawText(_("E"), 0, 0);
270 dc->Blit(m_cx + m_radius - 4, m_cy - 5, width, height, &tdc, 0, 0);
271
272 tdc.Clear();
273 tdc.DrawText(_("S"), 0, 0);
274 dc->Blit(m_cx - 3, m_cy + m_radius - 6, width, height, &tdc, 0, 0);
275
276 tdc.Clear();
277 tdc.DrawText(_("W"), 0, 0);
278 dc->Blit(m_cx - m_radius - 4, m_cy - 5, width, height, &tdc, 0, 0);
279
280 tdc.SelectObject(wxNullBitmap);
281
282 dc->SetBackgroundMode(wxTRANSPARENT);
283
284 dc->DrawLine(3, m_scale_base, size.x - 3, m_scale_base);
285 dc->DrawLine(3, m_scale_base + 4 * m_scale_delta, size.x - 3,
286 m_scale_base + 4 * m_scale_delta);
287
288 pen.SetStyle(wxPENSTYLE_DOT);
289 dc->SetPen(pen);
290 dc->DrawCircle(m_cx, m_cy, m_radius * sin(deg2rad(45)));
291 dc->DrawCircle(m_cx, m_cy, m_radius * sin(deg2rad(20)));
292
293 // wxSHORT_DASH is not supported on GTK, and it destroys the pen.
294#ifndef __WXGTK__
295 pen.SetStyle(wxPENSTYLE_SHORT_DASH);
296 dc->SetPen(pen);
297#endif
298 dc->DrawLine(3, m_scale_base + 1 * m_scale_delta, size.x - 3,
299 m_scale_base + 1 * m_scale_delta);
300 dc->DrawLine(3, m_scale_base + 2 * m_scale_delta, size.x - 3,
301 m_scale_base + 2 * m_scale_delta);
302 dc->DrawLine(3, m_scale_base + 3 * m_scale_delta, size.x - 3,
303 m_scale_base + 3 * m_scale_delta);
304}
305
306void DashboardInstrument_GPS::DrawBackground(wxGCDC* dc) {
307 // Draw SatID
308 wxFont f;
309 wxScreenDC sdc;
310 int height, width;
311 if (m_Properties)
312 f = m_Properties->m_SmallFont.GetChosenFont();
313 else
314 f = g_pFontSmall->GetChosenFont();
315 sdc.GetTextExtent("W", &width, &height, nullptr, nullptr, &f);
316
317 wxColour cl;
318 wxBitmap tbm(dc->GetSize().x, height, -1);
319 wxMemoryDC tdc(tbm);
320 wxColour c2;
321 if (m_Properties)
322 c2 = GetColourSchemeBackgroundColour(m_Properties->m_DataBackgroundColour);
323 else
324 GetGlobalColor("DASHB", &c2);
325 tdc.SetBackground(c2);
326 tdc.Clear();
327
328 if (m_Properties) {
329 tdc.SetFont(m_Properties->m_SmallFont.GetChosenFont());
330 cl = GetColourSchemeFont(m_Properties->m_SmallFont.GetColour());
331 } else {
332 tdc.SetFont(g_pFontSmall->GetChosenFont());
333 GetGlobalColor("DASHF", &cl);
334 }
335 tdc.SetTextForeground(cl);
336 tdc.SetTextBackground(c2);
337
338 int pitch = m_ref_dim;
339 int offset = m_ref_dim * 15 / 100;
340 for (int idx = 0; idx < 12; idx++) {
341 if (m_sat_info[idx].SatNumber) {
342 wxString satno = wxString::Format("%02d", m_sat_info[idx].SatNumber);
343 // Avoid three digit sat-number here. Especially for BeiDou(GB/BD)
344 satno = satno.Right(2);
345 tdc.DrawText(satno, idx * pitch + offset, 0);
346 } else
347 tdc.DrawText(" -", idx * pitch + offset, 0);
348 }
349
350 tdc.SelectObject(wxNullBitmap);
351
352 int scaleDelta = m_ref_dim / 2;
353 int scaleBase = (m_radius * 2) + (2 * m_ref_dim);
354
355 dc->DrawBitmap(tbm, 0, scaleBase + (scaleDelta * 45 / 10), false);
356}
357
358void DashboardInstrument_GPS::DrawForeground(wxGCDC* dc) {
359 wxColour cl;
360 if (m_Properties)
361 cl = GetColourSchemeFont(m_Properties->m_DataFont.GetColour());
362 else
363 cl = GetColourSchemeFont(g_pFontData->GetColour());
364 // GetGlobalColor("DASHL", &cl);
365 wxBrush brush(cl);
366 dc->SetBrush(brush);
367 dc->SetPen(*wxTRANSPARENT_PEN);
368 dc->SetTextBackground(cl);
369
370 wxColor cf;
371 GetGlobalColor("DASHF", &cf);
372 dc->SetTextForeground(cf);
373 dc->SetBackgroundMode(wxSOLID);
374
375 wxColour cb;
376 if (m_Properties)
377 cb = GetColourSchemeBackgroundColour(m_Properties->m_TitleBackgroundColour);
378 else
379 GetGlobalColor("DASHL", &cb);
380
381 dc->SetTextBackground(cb);
382
383 int m_scaleDelta = m_ref_dim / 2;
384 int m_scaleBase = (m_radius * 2) + (2 * m_ref_dim);
385 int pitch = m_ref_dim;
386 int offset = m_ref_dim * 12 / 100;
387
388 for (int idx = 0; idx < 12; idx++) {
389 if (m_sat_info[idx].SignalToNoiseRatio) {
390 int h = m_sat_info[idx].SignalToNoiseRatio * m_ref_dim / 24; // 0.4;
391 dc->DrawRectangle(idx * pitch + offset,
392 m_scaleBase + (4 * m_scaleDelta) - h, pitch * 60 / 100,
393 h);
394 }
395 }
396
397 wxString label = "00";
398 wxFont f;
399 int width, height;
400 wxScreenDC sdc;
401 if (m_Properties)
402 f = m_Properties->m_SmallFont.GetChosenFont();
403 else
404 f = g_pFontSmall->GetChosenFont();
405
406 sdc.GetTextExtent(label, &width, &height, nullptr, nullptr, &f);
407 dc->SetFont(f);
408 dc->SetBackgroundMode(wxTRANSPARENT);
409
410 for (int idx = 0; idx < 12; idx++) {
411 if (m_sat_info[idx].SignalToNoiseRatio) {
412 label.Printf("%02d", m_sat_info[idx].SatNumber);
413 int posx =
414 m_cx +
415 m_radius *
416 cos(deg2rad(m_sat_info[idx].AzimuthDegreesTrue - ANGLE_OFFSET)) *
417 sin(deg2rad(ANGLE_OFFSET - m_sat_info[idx].ElevationDegrees)) -
418 width / 2.0;
419 int posy =
420 m_cy +
421 m_radius *
422 sin(deg2rad(m_sat_info[idx].AzimuthDegreesTrue - ANGLE_OFFSET)) *
423 sin(deg2rad(ANGLE_OFFSET - m_sat_info[idx].ElevationDegrees)) -
424 height / 2.0;
425 dc->DrawText(label, posx, posy);
426 }
427 }
428 dc->SetBackgroundMode(wxSOLID);
429 if (talker_id != wxEmptyString) dc->DrawText(m_talker, 1, m_ref_dim * 3 / 2);
430}
Dashboard dial instrument.
Dashboard GPS instrument.
@ OCPN_DBP_STC_GPS
GPS status.
Definition instrument.h:98
double OCPN_GetWinDIPScaleFactor()
Gets Windows-specific DPI scaling factor.