1 /*
2 * Copyright 2013 Daniel Warner <contact@danrw.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <keplerian_toolbox/third_party/libsgp4/Tle.h>
18
19 #include <locale>
20
21 namespace
22 {
23 static const unsigned int TLE1_COL_NORADNUM = 2;
24 static const unsigned int TLE1_LEN_NORADNUM = 5;
25 static const unsigned int TLE1_COL_INTLDESC_A = 9;
26 static const unsigned int TLE1_LEN_INTLDESC_A = 2;
27 static const unsigned int TLE1_COL_INTLDESC_B = 11;
28 static const unsigned int TLE1_LEN_INTLDESC_B = 3;
29 static const unsigned int TLE1_COL_INTLDESC_C = 14;
30 static const unsigned int TLE1_LEN_INTLDESC_C = 3;
31 static const unsigned int TLE1_COL_EPOCH_A = 18;
32 static const unsigned int TLE1_LEN_EPOCH_A = 2;
33 static const unsigned int TLE1_COL_EPOCH_B = 20;
34 static const unsigned int TLE1_LEN_EPOCH_B = 12;
35 static const unsigned int TLE1_COL_MEANMOTIONDT2 = 33;
36 static const unsigned int TLE1_LEN_MEANMOTIONDT2 = 10;
37 static const unsigned int TLE1_COL_MEANMOTIONDDT6 = 44;
38 static const unsigned int TLE1_LEN_MEANMOTIONDDT6 = 8;
39 static const unsigned int TLE1_COL_BSTAR = 53;
40 static const unsigned int TLE1_LEN_BSTAR = 8;
41 static const unsigned int TLE1_COL_EPHEMTYPE = 62;
42 static const unsigned int TLE1_LEN_EPHEMTYPE = 1;
43 static const unsigned int TLE1_COL_ELNUM = 64;
44 static const unsigned int TLE1_LEN_ELNUM = 4;
45
46 static const unsigned int TLE2_COL_NORADNUM = 2;
47 static const unsigned int TLE2_LEN_NORADNUM = 5;
48 static const unsigned int TLE2_COL_INCLINATION = 8;
49 static const unsigned int TLE2_LEN_INCLINATION = 8;
50 static const unsigned int TLE2_COL_RAASCENDNODE = 17;
51 static const unsigned int TLE2_LEN_RAASCENDNODE = 8;
52 static const unsigned int TLE2_COL_ECCENTRICITY = 26;
53 static const unsigned int TLE2_LEN_ECCENTRICITY = 7;
54 static const unsigned int TLE2_COL_ARGPERIGEE = 34;
55 static const unsigned int TLE2_LEN_ARGPERIGEE = 8;
56 static const unsigned int TLE2_COL_MEANANOMALY = 43;
57 static const unsigned int TLE2_LEN_MEANANOMALY = 8;
58 static const unsigned int TLE2_COL_MEANMOTION = 52;
59 static const unsigned int TLE2_LEN_MEANMOTION = 11;
60 static const unsigned int TLE2_COL_REVATEPOCH = 63;
61 static const unsigned int TLE2_LEN_REVATEPOCH = 5;
62 }
63
64 /**
65 * Initialise the tle object.
66 * @exception TleException
67 */
Initialize()68 void Tle::Initialize()
69 {
70 if (!IsValidLineLength(line_one_)) {
71 throw TleException(std::string("Invalid length for line one: " + line_one_).c_str());
72 }
73
74 if (!IsValidLineLength(line_two_)) {
75 throw TleException(std::string("Invalid length for line two: " + line_two_).c_str());
76 }
77
78 if (line_one_[0] != '1') {
79 throw TleException("Invalid line beginning for line one");
80 }
81
82 if (line_two_[0] != '2') {
83 throw TleException("Invalid line beginning for line two");
84 }
85
86 unsigned int sat_number_1;
87 unsigned int sat_number_2;
88
89 ExtractInteger(line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM), sat_number_1);
90 ExtractInteger(line_two_.substr(TLE2_COL_NORADNUM, TLE2_LEN_NORADNUM), sat_number_2);
91
92 if (sat_number_1 != sat_number_2) {
93 throw TleException("Satellite numbers do not match");
94 }
95
96 norad_number_ = sat_number_1;
97
98 if (name_.empty()) {
99 name_ = line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM);
100 }
101
102 int_designator_
103 = line_one_.substr(TLE1_COL_INTLDESC_A, TLE1_LEN_INTLDESC_A + TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);
104
105 unsigned int year = 0;
106 double day = 0.0;
107
108 ExtractInteger(line_one_.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A), year);
109 ExtractDouble(line_one_.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B), 4, day);
110 ExtractDouble(line_one_.substr(TLE1_COL_MEANMOTIONDT2, TLE1_LEN_MEANMOTIONDT2), 2, mean_motion_dt2_);
111 ExtractExponential(line_one_.substr(TLE1_COL_MEANMOTIONDDT6, TLE1_LEN_MEANMOTIONDDT6), mean_motion_ddt6_);
112 ExtractExponential(line_one_.substr(TLE1_COL_BSTAR, TLE1_LEN_BSTAR), bstar_);
113
114 /*
115 * line 2
116 */
117 ExtractDouble(line_two_.substr(TLE2_COL_INCLINATION, TLE2_LEN_INCLINATION), 4, inclination_);
118 ExtractDouble(line_two_.substr(TLE2_COL_RAASCENDNODE, TLE2_LEN_RAASCENDNODE), 4, right_ascending_node_);
119 ExtractDouble(line_two_.substr(TLE2_COL_ECCENTRICITY, TLE2_LEN_ECCENTRICITY), -1, eccentricity_);
120 ExtractDouble(line_two_.substr(TLE2_COL_ARGPERIGEE, TLE2_LEN_ARGPERIGEE), 4, argument_perigee_);
121 ExtractDouble(line_two_.substr(TLE2_COL_MEANANOMALY, TLE2_LEN_MEANANOMALY), 4, mean_anomaly_);
122 ExtractDouble(line_two_.substr(TLE2_COL_MEANMOTION, TLE2_LEN_MEANMOTION), 3, mean_motion_);
123 ExtractInteger(line_two_.substr(TLE2_COL_REVATEPOCH, TLE2_LEN_REVATEPOCH), orbit_number_);
124
125 if (year < 57)
126 year += 2000;
127 else
128 year += 1900;
129 epoch_ = DateTime(year, day);
130 }
131
132 /**
133 * Check
134 * @param str The string to check
135 * @returns Whether true of the string has a valid length
136 */
IsValidLineLength(const std::string & str)137 bool Tle::IsValidLineLength(const std::string &str)
138 {
139 return str.length() == LineLength() ? true : false;
140 }
141
142 /**
143 * Convert a string containing an integer
144 * @param[in] str The string to convert
145 * @param[out] val The result
146 * @exception TleException on conversion error
147 */
ExtractInteger(const std::string & str,unsigned int & val)148 void Tle::ExtractInteger(const std::string &str, unsigned int &val)
149 {
150 bool found_digit = false;
151 unsigned int temp = 0;
152
153 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
154 if (isdigit(*i)) {
155 found_digit = true;
156 temp = (temp * 10) + (*i - '0');
157 } else if (found_digit) {
158 throw TleException("Unexpected non digit");
159 } else if (*i != ' ') {
160 throw TleException("Invalid character");
161 }
162 }
163
164 if (!found_digit) {
165 val = 0;
166 } else {
167 val = temp;
168 }
169 }
170
171 /**
172 * Convert a string containing an double
173 * @param[in] str The string to convert
174 * @param[in] point_pos The position of the decimal point. (-1 if none)
175 * @param[out] val The result
176 * @exception TleException on conversion error
177 */
ExtractDouble(const std::string & str,int point_pos,double & val)178 void Tle::ExtractDouble(const std::string &str, int point_pos, double &val)
179 {
180 std::string temp;
181 bool found_digit = false;
182
183 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
184 /*
185 * integer part
186 */
187 if (point_pos >= 0 && i < str.begin() + point_pos - 1) {
188 bool done = false;
189
190 if (i == str.begin()) {
191 if (*i == '-' || *i == '+') {
192 /*
193 * first character could be signed
194 */
195 temp += *i;
196 done = true;
197 }
198 }
199
200 if (!done) {
201 if (isdigit(*i)) {
202 found_digit = true;
203 temp += *i;
204 } else if (found_digit) {
205 throw TleException("Unexpected non digit");
206 } else if (*i != ' ') {
207 throw TleException("Invalid character");
208 }
209 }
210 }
211 /*
212 * decimal point
213 */
214 else if (point_pos >= 0 && i == str.begin() + point_pos - 1) {
215 if (temp.length() == 0) {
216 /*
217 * integer part is blank, so add a '0'
218 */
219 temp += '0';
220 }
221
222 if (*i == '.') {
223 /*
224 * decimal point found
225 */
226 temp += *i;
227 } else {
228 throw TleException("Failed to find decimal point");
229 }
230 }
231 /*
232 * fraction part
233 */
234 else {
235 if (i == str.begin() && point_pos == -1) {
236 /*
237 * no decimal point expected, add 0. beginning
238 */
239 temp += '0';
240 temp += '.';
241 }
242
243 /*
244 * should be a digit
245 */
246 if (isdigit(*i)) {
247 temp += *i;
248 } else {
249 throw TleException("Invalid digit");
250 }
251 }
252 }
253
254 if (!Util::FromString<double>(temp, val)) {
255 throw TleException("Failed to convert value to double");
256 }
257 }
258
259 /**
260 * Convert a string containing an exponential
261 * @param[in] str The string to convert
262 * @param[out] val The result
263 * @exception TleException on conversion error
264 */
ExtractExponential(const std::string & str,double & val)265 void Tle::ExtractExponential(const std::string &str, double &val)
266 {
267 std::string temp;
268
269 for (std::string::const_iterator i = str.begin(); i != str.end(); ++i) {
270 if (i == str.begin()) {
271 if (*i == '-' || *i == '+' || *i == ' ') {
272 if (*i == '-') {
273 temp += *i;
274 }
275 temp += '0';
276 temp += '.';
277 } else {
278 throw TleException("Invalid sign");
279 }
280 } else if (i == str.begin() + str.length() - 2) {
281 if (*i == '-' || *i == '+') {
282 temp += 'e';
283 temp += *i;
284 } else {
285 throw TleException("Invalid exponential sign");
286 }
287 } else {
288 if (isdigit(*i)) {
289 temp += *i;
290 } else {
291 throw TleException("Invalid digit");
292 }
293 }
294 }
295
296 if (!Util::FromString<double>(temp, val)) {
297 throw TleException("Failed to convert value to double");
298 }
299 }
300