OpenCPN Partial API docs
comm_appmsg.cpp
1 /***************************************************************************
2  *
3  * Project: OpenCPN
4  * Purpose: Implement comm_appmsg.h -- Decoded application messages.
5  * Author: David Register, Alec Leamas
6  *
7  ***************************************************************************
8  * Copyright (C) 2022 by David Register, Alec Leamas *
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  * This program is distributed in the hope that it will be useful, *
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18  * GNU General Public License for more details. *
19  * *
20  * You should have received a copy of the GNU General Public License *
21  * along with this program; if not, write to the *
22  * Free Software Foundation, Inc., *
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24  **************************************************************************/
25 
26 // For compilers that support precompilation, includes "wx.h".
27 #include <wx/wxprec.h>
28 
29 #ifndef WX_PRECOMP
30 #include <wx/wx.h>
31 #endif // precompiled headers
32 
33 #include <sstream>
34 #include <iomanip>
35 
36 #include "model/comm_appmsg.h"
37 #include "model/ocpn_utils.h"
38 
39 /* Free functions. */
40 
41 std::string TimeToString(const time_t t) {
42  char buff[30];
43 #ifdef _MSC_VER
44  errno_t e = ctime_s(buff, sizeof(buff), &t);
45  assert(e == 0 && "Huh? ctime_s returned an error");
46  return std::string(buff);
47 #else
48  const char* r = ctime_r(&t, buff);
49  assert(r != NULL && "ctime_r failed...");
50  return std::string(buff);
51 #endif
52 }
53 
54 std::string DegreesToString(double degrees) {
55  using namespace std;
56  std::stringstream buf;
57  buf << setw(2) << static_cast<int>(trunc(degrees)) << "\u00B0"
58  << static_cast<int>(trunc(degrees * 100)) % 100 << "," << setw(2)
59  << (static_cast<int>(trunc(degrees * 10000)) % 10000) % 100;
60  return buf.str();
61 }
62 
63 double PosPartsToDegrees(float degrees, float minutes,
64  float percent_of_minute) {
65  return degrees + minutes / 60 + percent_of_minute / 6000;
66 }
67 
68 
69 /* Position implementation */
70 
71 Position::Position(double _lat, double _lon, Type t)
72  : lat(TypeToLat(t, _lat)), lon(TypeToLong(t, _lon)), type(t) {}
73 
74 Position::Position(double _lat, double _lon)
75  : lat(_lat), lon(_lon), type(LatLongToType(_lat, _lon)) {};
76 
77 Position::Position() : lat(0), lon(0), type(Type::Undef) {};
78 
79 std::string Position::to_string() const {
80  std::stringstream buf;
81  const std::string NE(TypeToStr(type));
82  auto lat_s = DegreesToString(abs(lat));
83  auto lon_s = DegreesToString(abs(lon));
84  buf << lat_s << NE[0] << " " << lon_s << NE[1];
85  return buf.str();
86 }
87 
88 std::string Position::TypeToStr(const Type t) const {
89  switch (t) {
90  case Type::NE:
91  return "NE";
92  break;
93  case Type::NW:
94  return "NW";
95  break;
96  case Type::SE:
97  return "SE";
98  break;
99  case Type::SW:
100  return "SW";
101  break;
102  case Type::Undef:
103  return "Undefined";
104  break;
105  }
106  return "??"; // Not reached, but compiler complains.
107 }
108 
109 Position::Type Position::LatLongToType(double lat, double lon) {
110  if (lat >= 0)
111  return lon >= 0 ? Type::NE : Type::NW;
112  else
113  return lon >= 0 ? Type::SE : Type::SW;
114 }
115 
116 double Position::TypeToLat(Type t, double lat) {
117  return t == Type::SW || t == Type::SE ? -lat : lat;
118 }
119 
120 double Position::TypeToLong(Type t, double lon) {
121  return t == Type::NE || t == Type::SE ? lon : -lon;
122 }
123 
125 static double GgaPartToDouble(const std::string& s) {
126  size_t dotpos = s.find('.');
127  if (dotpos < 2) return nan("");
128  auto degrees = s.substr(0, dotpos - 2);
129  auto minutes = s.substr(dotpos - 2);
130  return std::stod(degrees) + std::stod(minutes)/60;
131 
132 }
133 
134 Position Position::ParseGGA(const std::string gga) {
135  auto parts = ocpn::split(gga.c_str(), ",");
136  if (parts.size() != 4) {
137  return Position();
138  }
139  double lat = GgaPartToDouble(parts[0]);
140  if (parts[1] == "S")
141  lat = -lat;
142  else if (parts[1] != "N")
143  lat = nan("");
144  double lon = GgaPartToDouble(parts[2]);
145  if (parts[3] == "W")
146  lon = -lon;
147  else if (parts[3] != "E")
148  lon = nan("");
149 
150  return lat != nan("") && lon != nan("") ? Position(lat, lon) : Position();
151 }
152 
153 
154 /* Appmsg implementation */
155 
156 std::string AppMsg::TypeToString(const AppMsg::Type t) const {
157  switch (t) {
158  case AppMsg::Type::AisData:
159  return "ais-data";
160  break;
161  case AppMsg::Type::BasicNavData:
162  return "basic-nav-data";
163  break;
164  case AppMsg::Type::CustomMsg:
165  return "custom-msg";
166  break;
167  case AppMsg::Type::DataPrioNeeded:
168  return "data-prio-needed";
169  break;
170  case AppMsg::Type::GnssFix:
171  return "gnss-fix";
172  break;
173  case AppMsg::Type::GPSWatchdog:
174  return "gps-watchdog";
175  break;
176  case AppMsg::Type::Undef:
177  return "??";
178  break;
179  }
180  return "????"; // Not reached, for the compiler.
181 }
Position()
Construct a (0,0) position, type == Undef.
Definition: comm_appmsg.cpp:77
static Position ParseGGA(const std::string gga)
Parse a GGA string like "5800.588,N,01145.776,E" as present in GGA and other n0183 messages.
std::string to_string() const
Return utf string like 65°25,11N 21°12,01E.
Definition: comm_appmsg.cpp:79