license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / geolocation.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2010 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published
7 ** by the Free Software Foundation; either version 3 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 Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** File: geolocation.cpp
20 **
21 **/
22
23 #include "libnetxms.h"
24 #include <geolocation.h>
25 #include <math.h>
26
27 static const double ROUND_OFF = 0.00000001;
28
29
30 //
31 // Default constructor - create location of type UNSET
32 //
33
34 GeoLocation::GeoLocation()
35 {
36 m_type = GL_UNSET;
37 m_lat = 0;
38 m_lon = 0;
39 posToString(true, 0);
40 posToString(false, 0);
41 m_isValid = true;
42 }
43
44
45 //
46 // Constructor - create location from double lat/lon values
47 //
48
49 GeoLocation::GeoLocation(int type, double lat, double lon)
50 {
51 m_type = type;
52 m_lat = lat;
53 m_lon = lon;
54 posToString(true, lat);
55 posToString(false, lon);
56 m_isValid = true;
57 }
58
59
60 //
61 // Constructor - create location from string lat/lon values
62 //
63
64 GeoLocation::GeoLocation(int type, const TCHAR *lat, const TCHAR *lon)
65 {
66 m_type = type;
67 m_isValid = parseLatitude(lat) && parseLongitude(lon);
68 posToString(true, m_lat);
69 posToString(false, m_lon);
70 }
71
72
73 //
74 // Copy constructor
75 //
76
77 GeoLocation::GeoLocation(const GeoLocation &src)
78 {
79 m_type = src.m_type;
80 m_lat = src.m_lat;
81 m_lon = src.m_lon;
82 nx_strncpy(m_latStr, src.m_latStr, 20);
83 nx_strncpy(m_lonStr, src.m_lonStr, 20);
84 m_isValid = src.m_isValid;
85 }
86
87
88 //
89 // Create geolocation object from data in NXCP message
90 //
91
92 GeoLocation::GeoLocation(CSCPMessage &msg)
93 {
94 m_type = (int)msg.GetVariableShort(VID_GEOLOCATION_TYPE);
95 m_lat = msg.GetVariableDouble(VID_LATITUDE);
96 m_lon = msg.GetVariableDouble(VID_LONGITUDE);
97 posToString(true, m_lat);
98 posToString(false, m_lon);
99 m_isValid = true;
100 }
101
102
103 //
104 // Destructor
105 //
106
107 GeoLocation::~GeoLocation()
108 {
109 }
110
111
112 //
113 // Assignment operator
114 //
115
116 GeoLocation& GeoLocation::operator =(const GeoLocation &src)
117 {
118 m_type = src.m_type;
119 m_lat = src.m_lat;
120 m_lon = src.m_lon;
121 nx_strncpy(m_latStr, src.m_latStr, 20);
122 nx_strncpy(m_lonStr, src.m_lonStr, 20);
123 m_isValid = src.m_isValid;
124 return *this;
125 }
126
127
128 //
129 // Fill NXCP message
130 //
131
132 void GeoLocation::fillMessage(CSCPMessage &msg)
133 {
134 msg.SetVariable(VID_GEOLOCATION_TYPE, (WORD)m_type);
135 msg.SetVariable(VID_LATITUDE, m_lat);
136 msg.SetVariable(VID_LONGITUDE, m_lon);
137 }
138
139
140 //
141 // Getters for degree, minutes, and seconds from double value
142 //
143
144 int GeoLocation::getIntegerDegree(double pos)
145 {
146 return (int)(fabs(pos) + ROUND_OFF);
147 }
148
149 int GeoLocation::getIntegerMinutes(double pos)
150 {
151 double d = fabs(pos) + ROUND_OFF;
152 return (int)((d - (double)((int)d)) * 60.0);
153 }
154
155 double GeoLocation::getDecimalSeconds(double pos)
156 {
157 double d = fabs(pos) * 60.0 + ROUND_OFF;
158 return (d - (double)((int)d)) * 60.0;
159 }
160
161
162 //
163 // Convert position to string
164 //
165
166 void GeoLocation::posToString(bool isLat, double pos)
167 {
168 TCHAR *buffer = isLat ? m_latStr : m_lonStr;
169
170 // Chack range
171 if ((pos < -180.0) || (pos > 180.0))
172 {
173 _tcscpy(buffer, _T("<invalid>"));
174 return;
175 }
176
177 // Encode hemisphere
178 if (isLat)
179 {
180 *buffer = (pos < 0) ? _T('S') : _T('N');
181 }
182 else
183 {
184 *buffer = (pos < 0) ? _T('W') : _T('E');
185 }
186 buffer++;
187 *buffer++ = _T(' ');
188
189 _sntprintf(buffer, 18, _T("%02d° %02d' %02.3f\""), getIntegerDegree(pos), getIntegerMinutes(pos), getDecimalSeconds(pos));
190 }
191
192
193 //
194 // Parse latitude/longitude string
195 //
196
197 double GeoLocation::parse(const TCHAR *str, bool isLat, bool *isValid)
198 {
199 *isValid = false;
200
201 // Prepare input string
202 TCHAR *in = _tcsdup(str);
203 StrStrip(in);
204
205 // Check if string given is just double value
206 TCHAR *eptr;
207 double value = _tcstod(in, &eptr);
208 if (*eptr == 0)
209 {
210 *isValid = true;
211 }
212 else // If not a valid double, check if it's in DMS form
213 {
214 // Check for invalid characters
215 if (_tcsspn(in, isLat ? _T("0123456789.°'\" NS") : _T("0123456789.°'\" EW")) == _tcslen(in))
216 {
217 TCHAR *curr = in;
218
219 int sign = 0;
220 if ((*curr == _T('N')) || (*curr == _T('E')))
221 {
222 sign = 1;
223 curr++;
224 }
225 else if ((*curr == _T('S')) || (*curr == _T('W')))
226 {
227 sign = -1;
228 curr++;
229 }
230
231 while(*curr == _T(' '))
232 curr++;
233
234 double deg = 0.0, min = 0.0, sec = 0.0;
235
236 deg = _tcstod(curr, &eptr);
237 if (*eptr == 0) // End of string
238 goto finish_parsing;
239 if ((*eptr != _T('°')) && (*eptr != _T(' ')))
240 goto cleanup; // Unexpected character
241 curr = eptr + 1;
242 while(*curr == _T(' '))
243 curr++;
244
245 min = _tcstod(curr, &eptr);
246 if (*eptr == 0) // End of string
247 goto finish_parsing;
248 if (*eptr != _T('\''))
249 goto cleanup; // Unexpected character
250 curr = eptr + 1;
251 while(*curr == _T(' '))
252 curr++;
253
254 sec = _tcstod(curr, &eptr);
255 if (*eptr == 0) // End of string
256 goto finish_parsing;
257 if (*eptr != _T('"'))
258 goto cleanup; // Unexpected character
259 curr = eptr + 1;
260 while(*curr == _T(' '))
261 curr++;
262
263 if ((*curr == _T('N')) || (*curr == _T('E')))
264 {
265 sign = 1;
266 curr++;
267 }
268 else if ((*curr == _T('S')) || (*curr == _T('W')))
269 {
270 sign = -1;
271 curr++;
272 }
273
274 if (sign == 0)
275 goto cleanup; // Hemisphere was not specified
276
277 finish_parsing:
278 value = sign * (deg + min / 60.0 + sec / 3600.0);
279 *isValid = true;
280 }
281 }
282
283 cleanup:
284 free(in);
285 return value;
286 }
287
288
289 //
290 // Parse latitude
291 //
292
293 bool GeoLocation::parseLatitude(const TCHAR *lat)
294 {
295 bool isValid;
296
297 m_lat = parse(lat, true, &isValid);
298 if (!isValid)
299 m_lat = 0.0;
300 return isValid;
301 }
302
303
304 //
305 // Parse longitude
306 //
307
308 bool GeoLocation::parseLongitude(const TCHAR *lon)
309 {
310 bool isValid;
311
312 m_lon = parse(lon, false, &isValid);
313 if (!isValid)
314 m_lon = 0.0;
315 return isValid;
316 }