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