4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "WaypointReaderWinPilot.hpp"
25 #include "Units/System.hpp"
26 #include "Waypoint/Waypoints.hpp"
27 #include "Util/NumberParser.hpp"
28 #include "Util/Macros.hpp"
31 ParseAngle(const TCHAR
* src
, Angle
& dest
, const bool lat
)
33 // Two format variants:
34 // 51:47.841N (DD:MM.mmm // the usual)
35 // 51:23:45N (DD:MM:SS)
39 long deg
= _tcstol(src
, &endptr
, 10);
40 if (endptr
== src
|| *endptr
!= _T(':') || deg
< 0)
43 // Limit angle to +/- 90 degrees for Latitude or +/- 180 degrees for Longitude
44 deg
= std::min(deg
, lat
? 90L : 180L);
47 long min
= _tcstol(src
, &endptr
, 10);
48 if (endptr
== src
|| min
< 0 || min
>= 60)
55 long l
= _tcstol(src
, &endptr
, 10);
56 if (endptr
== src
|| l
< 0 || l
>= 60)
59 sec
= fixed(l
) / 3600;
60 } else if (*endptr
== '.') {
62 long l
= _tcstol(src
, &endptr
, 10);
63 if (endptr
== src
+ 1 && l
>= 0 && l
< 100)
64 sec
= fixed(l
) / (60 * 10);
65 else if (endptr
== src
+ 2 && l
>= 0 && l
< 1000)
66 sec
= fixed(l
) / (60 * 100);
67 else if (endptr
== src
+ 3 && l
>= 0 && l
< 10000)
68 sec
= fixed(l
) / (60 * 1000);
74 fixed value
= fixed(deg
) + fixed(min
) / 60 + sec
;
77 if (sign
== 'W' || sign
== 'w' || sign
== 'S' || sign
== 's')
81 dest
= Angle::Degrees(value
);
86 ParseRunwayDirection(const TCHAR
* src
, Runway
&dest
)
88 // WELT2000 written files contain a 4-digit runway direction specification
89 // at the end of the comment, e.g. "123.50 0927"
91 TCHAR
const *start
= _tcsrchr(src
, _T(' '));
98 int value
= _tcstol(start
, &end
, 10);
99 if (start
== end
|| *end
!= _T('\0') || end
- start
!= 4 )
102 int a1
= (value
/ 100) * 10;
103 int a2
= (value
% 100) * 10;
104 if (a1
< 0 || a1
> 360 || a2
< 0 || a2
> 360)
111 // TODO: WELT2000 generates quite a few entries where
112 // a) a1 == a2 (accept those) and
113 // b) the angles are neither equal or reciprocal (discard those)
114 // Try finding a logic behind this behaviour.
115 if (a1
!= a2
&& (a1
+ 180) % 360 != a2
)
118 dest
.SetDirectionDegrees(a1
);
123 ParseAltitude(const TCHAR
* src
, fixed
& dest
)
127 double value
= _tcstod(src
, &endptr
);
133 // Convert to system unit if necessary
134 TCHAR unit
= *endptr
;
135 if (unit
== 'F' || unit
== 'f')
136 dest
= Units::ToSysUnit(dest
, Unit::FEET
);
143 ParseFlags(const TCHAR
* src
, Waypoint
&dest
)
154 for (unsigned i
= 0; src
[i
] != 0; i
++) {
158 dest
.type
= Waypoint::Type::AIRFIELD
;
162 dest
.flags
.turn_point
= true;
167 if (dest
.type
!= Waypoint::Type::AIRFIELD
)
168 dest
.type
= Waypoint::Type::OUTLANDING
;
172 dest
.flags
.home
= true;
176 dest
.flags
.start_point
= true;
180 dest
.flags
.finish_point
= true;
189 WaypointReaderWinPilot::ParseLine(const TCHAR
* line
, const unsigned linenum
,
190 Waypoints
&waypoints
)
193 const TCHAR
*params
[20];
194 static constexpr unsigned int max_params
= ARRAY_SIZE(params
);
195 static bool welt2000_format
= false;
199 welt2000_format
= false;
203 // -> return without error condition
207 if (line
[0] == _T('*')) {
209 welt2000_format
= (_tcsstr(line
, _T("WRITTEN BY WELT2000")) != NULL
);
210 // -> return without error condition
214 if (_tcslen(line
) >= ARRAY_SIZE(ctemp
))
215 /* line too long for buffer */
221 n_params
= ExtractParameters(line
, ctemp
, params
, max_params
, true);
225 // Latitude (e.g. 51:15.900N)
226 if (!ParseAngle(params
[1], location
.latitude
, true))
229 // Longitude (e.g. 00715.900W)
230 if (!ParseAngle(params
[2], location
.longitude
, false))
232 location
.Normalize(); // ensure longitude is within -180:180
234 Waypoint
new_waypoint(location
);
235 new_waypoint
.file_num
= file_num
;
236 new_waypoint
.original_id
= ParseUnsigned(params
[0], NULL
, 0);
238 // Name (e.g. KAMPLI)
239 if (*params
[5] == _T('\0'))
241 new_waypoint
.name
=params
[5];
243 // Altitude (e.g. 458M)
244 /// @todo configurable behaviour
245 if (!ParseAltitude(params
[3], new_waypoint
.elevation
) &&
246 !CheckAltitude(new_waypoint
))
250 // Description (e.g. 119.750 Airport)
251 new_waypoint
.comment
=params
[6];
253 ParseRunwayDirection(params
[6], new_waypoint
.runway
);
256 // Waypoint Flags (e.g. AT)
257 ParseFlags(params
[4], new_waypoint
);
259 waypoints
.Append(std::move(new_waypoint
));