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