/[PAMELA software]/yodaUtility/sgp4/cTle.cpp
ViewVC logotype

Contents of /yodaUtility/sgp4/cTle.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1.1.1 - (show annotations) (download) (vendor branch)
Sun Apr 30 11:08:15 2006 UTC (18 years, 7 months ago) by kusanagi
Branch: MAIN
CVS Tags: yodaUtility2_0/00, yodaUtility1_0/00, yodaUtility2_2/00, yodaUtility2_1/00, HEAD
Changes since 1.1: +0 -0 lines
Various utilities for the yoda environment and its related softwares.
YFile 	   	- Inheriths from TFile     - Add custom features to a TFile object.
YException 	- Inheriths from exception - YODA specific Exceptions.
YMcmd	   	- Decoder for the Mcmd packets.
YSQLConnection 	- Singletn class for DB connections.
yodaUtility     - Various functions.
sgp4		- C++ NORAD SGP4/SDP4 Implementation - Developed by Michael F. Henry.

1 //
2 // cTle.cpp
3 // This class encapsulates a single set of standard NORAD two line elements.
4 //
5 // Copyright 1996-2005 Michael F. Henry
6 //
7 #include "stdafx.h"
8
9 #include "cTle.h"
10
11 // Note: The column offsets are ZERO based.
12
13 // Name
14 const int TLE_LEN_LINE_DATA = 69; const int TLE_LEN_LINE_NAME = 22;
15
16 // Line 1
17 const int TLE1_COL_SATNUM = 2; const int TLE1_LEN_SATNUM = 5;
18 const int TLE1_COL_INTLDESC_A = 9; const int TLE1_LEN_INTLDESC_A = 2;
19 const int TLE1_COL_INTLDESC_B = 11; const int TLE1_LEN_INTLDESC_B = 3;
20 const int TLE1_COL_INTLDESC_C = 14; const int TLE1_LEN_INTLDESC_C = 3;
21 const int TLE1_COL_EPOCH_A = 18; const int TLE1_LEN_EPOCH_A = 2;
22 const int TLE1_COL_EPOCH_B = 20; const int TLE1_LEN_EPOCH_B = 12;
23 const int TLE1_COL_MEANMOTIONDT = 33; const int TLE1_LEN_MEANMOTIONDT = 10;
24 const int TLE1_COL_MEANMOTIONDT2 = 44; const int TLE1_LEN_MEANMOTIONDT2 = 8;
25 const int TLE1_COL_BSTAR = 53; const int TLE1_LEN_BSTAR = 8;
26 const int TLE1_COL_EPHEMTYPE = 62; const int TLE1_LEN_EPHEMTYPE = 1;
27 const int TLE1_COL_ELNUM = 64; const int TLE1_LEN_ELNUM = 4;
28
29 // Line 2
30 const int TLE2_COL_SATNUM = 2; const int TLE2_LEN_SATNUM = 5;
31 const int TLE2_COL_INCLINATION = 8; const int TLE2_LEN_INCLINATION = 8;
32 const int TLE2_COL_RAASCENDNODE = 17; const int TLE2_LEN_RAASCENDNODE = 8;
33 const int TLE2_COL_ECCENTRICITY = 26; const int TLE2_LEN_ECCENTRICITY = 7;
34 const int TLE2_COL_ARGPERIGEE = 34; const int TLE2_LEN_ARGPERIGEE = 8;
35 const int TLE2_COL_MEANANOMALY = 43; const int TLE2_LEN_MEANANOMALY = 8;
36 const int TLE2_COL_MEANMOTION = 52; const int TLE2_LEN_MEANMOTION = 11;
37 const int TLE2_COL_REVATEPOCH = 63; const int TLE2_LEN_REVATEPOCH = 5;
38
39 /////////////////////////////////////////////////////////////////////////////
40 cTle::cTle(string& strName, string& strLine1, string& strLine2)
41 {
42 m_strName = strName;
43 m_strLine1 = strLine1;
44 m_strLine2 = strLine2;
45
46 Initialize();
47 }
48
49 /////////////////////////////////////////////////////////////////////////////
50 cTle::cTle(const cTle &tle)
51 {
52 m_strName = tle.m_strName;
53 m_strLine1 = tle.m_strLine1;
54 m_strLine2 = tle.m_strLine2;
55
56 for (int fld = FLD_FIRST; fld < FLD_LAST; fld++)
57 {
58 m_Field[fld] = tle.m_Field[fld];
59 }
60
61 m_mapCache = tle.m_mapCache;
62 }
63
64 /////////////////////////////////////////////////////////////////////////////
65 cTle::~cTle()
66 {
67 }
68
69 /////////////////////////////////////////////////////////////////////////////
70 // getField()
71 // Return requested field as a double (function return value) or as a text
72 // string (*pstr) in the units requested (eUnit). Set 'bStrUnits' to true
73 // to have units appended to text string.
74 //
75 // Note: numeric return values are cached; asking for the same field more
76 // than once incurs minimal overhead.
77 double cTle::getField(eField fld,
78 eUnits units, /* = U_NATIVE */
79 string *pstr /* = NULL */,
80 bool bStrUnits /* = false */) const
81 {
82 assert((FLD_FIRST <= fld) && (fld < FLD_LAST));
83 assert((U_FIRST <= units) && (units < U_LAST));
84
85 if (pstr)
86 {
87 // Return requested field in string form.
88 *pstr = m_Field[fld];
89
90 if (bStrUnits)
91 *pstr += getUnits(fld);
92
93 return 0.0;
94 }
95 else
96 {
97 // Return requested field in floating-point form.
98 // Return cache contents if it exists, else populate cache
99 FldKey key = Key(units, fld);
100
101 if (m_mapCache.find(key) == m_mapCache.end())
102 {
103 // Value not in cache; add it
104 double valNative = atof(m_Field[fld].c_str());
105 double valConv = ConvertUnits(valNative, fld, units);
106 m_mapCache[key] = valConv;
107
108 return valConv;
109 }
110 else
111 {
112 // return cached value
113 return m_mapCache[key];
114 }
115 }
116 }
117
118 //////////////////////////////////////////////////////////////////////////////
119 // Convert the given field into the requested units. It is assumed that
120 // the value being converted is in the TLE format's "native" form.
121 double cTle::ConvertUnits(double valNative, // value to convert
122 eField fld, // what field the value is
123 eUnits units) // what units to convert to
124 {
125 switch (fld)
126 {
127 case FLD_I:
128 case FLD_RAAN:
129 case FLD_ARGPER:
130 case FLD_M:
131 {
132 // The native TLE format is DEGREES
133 if (units == U_RAD)
134 return valNative * RADS_PER_DEG;
135 }
136 }
137
138 return valNative; // return value in unconverted native format
139 }
140
141 //////////////////////////////////////////////////////////////////////////////
142 string cTle::getUnits(eField fld) const
143 {
144 static const string strDegrees = " degrees";
145 static const string strRevsPerDay = " revs / day";
146 static const string strNull;
147
148 switch (fld)
149 {
150 case FLD_I:
151 case FLD_RAAN:
152 case FLD_ARGPER:
153 case FLD_M:
154 return strDegrees;
155
156 case FLD_MMOTION:
157 return strRevsPerDay;
158
159 default:
160 return strNull;
161 }
162 }
163
164 /////////////////////////////////////////////////////////////////////////////
165 // ExpToDecimal()
166 // Converts TLE-style exponential notation of the form [ |-]00000[+|-]0 to
167 // decimal notation. Assumes implied decimal point to the left of the first
168 // number in the string, i.e.,
169 // " 12345-3" = 0.00012345
170 // "-23429-5" = -0.0000023429
171 // " 40436+1" = 4.0436
172 string cTle::ExpToDecimal(const string &str)
173 {
174 const int COL_EXP_SIGN = 6;
175 const int LEN_EXP = 2;
176
177 const int LEN_BUFREAL = 32; // max length of buffer to hold floating point
178 // representation of input string.
179 int nMan;
180 int nExp;
181
182 // sscanf(%d) will read up to the exponent sign
183 sscanf(str.c_str(), "%d", &nMan);
184
185 double dblMan = nMan;
186 bool bNeg = (nMan < 0);
187
188 if (bNeg)
189 dblMan *= -1;
190
191 // Move decimal place to left of first digit
192 while (dblMan >= 1.0)
193 dblMan /= 10.0;
194
195 if (bNeg)
196 dblMan *= -1;
197
198 // now read exponent
199 sscanf(str.substr(COL_EXP_SIGN, LEN_EXP).c_str(), "%d", &nExp);
200
201 double dblVal = dblMan * pow(10.0, nExp);
202 char szVal[LEN_BUFREAL];
203
204 snprintf(szVal, sizeof(szVal), "%.9f", dblVal);
205
206 string strVal = szVal;
207
208 return strVal;
209
210 } // ExpToDecimal()
211
212 /////////////////////////////////////////////////////////////////////////////
213 // Initialize()
214 // Initialize the string array.
215 void cTle::Initialize()
216 {
217 // Have we already been initialized?
218 if (m_Field[FLD_NORADNUM].size())
219 return;
220
221 assert(!m_strName.empty());
222 assert(!m_strLine1.empty());
223 assert(!m_strLine2.empty());
224
225 m_Field[FLD_NORADNUM] = m_strLine1.substr(TLE1_COL_SATNUM, TLE1_LEN_SATNUM);
226 m_Field[FLD_INTLDESC] = m_strLine1.substr(TLE1_COL_INTLDESC_A,
227 TLE1_LEN_INTLDESC_A +
228 TLE1_LEN_INTLDESC_B +
229 TLE1_LEN_INTLDESC_C);
230 m_Field[FLD_EPOCHYEAR] =
231 m_strLine1.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A);
232
233 m_Field[FLD_EPOCHDAY] =
234 m_strLine1.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B);
235
236 if (m_strLine1[TLE1_COL_MEANMOTIONDT] == '-')
237 {
238 // value is negative
239 m_Field[FLD_MMOTIONDT] = "-0";
240 }
241 else
242 m_Field[FLD_MMOTIONDT] = "0";
243
244 m_Field[FLD_MMOTIONDT] += m_strLine1.substr(TLE1_COL_MEANMOTIONDT + 1,
245 TLE1_LEN_MEANMOTIONDT);
246
247 // decimal point assumed; exponential notation
248 m_Field[FLD_MMOTIONDT2] = ExpToDecimal(
249 m_strLine1.substr(TLE1_COL_MEANMOTIONDT2,
250 TLE1_LEN_MEANMOTIONDT2));
251 // decimal point assumed; exponential notation
252 m_Field[FLD_BSTAR] = ExpToDecimal(m_strLine1.substr(TLE1_COL_BSTAR,
253 TLE1_LEN_BSTAR));
254 //TLE1_COL_EPHEMTYPE
255 //TLE1_LEN_EPHEMTYPE
256 m_Field[FLD_SET] = m_strLine1.substr(TLE1_COL_ELNUM, TLE1_LEN_ELNUM);
257
258 TrimLeft(m_Field[FLD_SET]);
259
260 //TLE2_COL_SATNUM
261 //TLE2_LEN_SATNUM
262
263 m_Field[FLD_I] = m_strLine2.substr(TLE2_COL_INCLINATION,
264 TLE2_LEN_INCLINATION);
265 TrimLeft(m_Field[FLD_I]);
266
267 m_Field[FLD_RAAN] = m_strLine2.substr(TLE2_COL_RAASCENDNODE,
268 TLE2_LEN_RAASCENDNODE);
269 TrimLeft(m_Field[FLD_RAAN]);
270
271 // decimal point is assumed
272 m_Field[FLD_E] = "0.";
273 m_Field[FLD_E] += m_strLine2.substr(TLE2_COL_ECCENTRICITY,
274 TLE2_LEN_ECCENTRICITY);
275
276 m_Field[FLD_ARGPER] = m_strLine2.substr(TLE2_COL_ARGPERIGEE,
277 TLE2_LEN_ARGPERIGEE);
278 TrimLeft(m_Field[FLD_ARGPER]);
279
280 m_Field[FLD_M] = m_strLine2.substr(TLE2_COL_MEANANOMALY,
281 TLE2_LEN_MEANANOMALY);
282 TrimLeft(m_Field[FLD_M]);
283
284 m_Field[FLD_MMOTION] = m_strLine2.substr(TLE2_COL_MEANMOTION,
285 TLE2_LEN_MEANMOTION);
286 TrimLeft(m_Field[FLD_MMOTION]);
287
288 m_Field[FLD_ORBITNUM] = m_strLine2.substr(TLE2_COL_REVATEPOCH,
289 TLE2_LEN_REVATEPOCH);
290 TrimLeft(m_Field[FLD_ORBITNUM]);
291
292 } // InitStrVars()
293
294 /////////////////////////////////////////////////////////////////////////////
295 // IsTleFormat()
296 // Returns true if "str" is a valid data line of a two-line element set,
297 // else false.
298 //
299 // To be valid a line must:
300 // Have as the first character the line number
301 // Have as the second character a blank
302 // Be TLE_LEN_LINE_DATA characters long
303 // Have a valid checksum (note: no longer required as of 12/96)
304 //
305 bool cTle::IsValidLine(string& str, eTleLine line)
306 {
307 TrimLeft(str);
308 TrimRight(str);
309
310 size_t nLen = str.size();
311
312 if (nLen != TLE_LEN_LINE_DATA)
313 return false;
314
315 // First char in string must be line number
316 if ((str[0] - '0') != line)
317 return false;
318
319 // Second char in string must be blank
320 if (str[1] != ' ')
321 return false;
322
323 /*
324 NOTE: 12/96
325 The requirement that the last char in the line data must be a valid
326 checksum is too restrictive.
327
328 // Last char in string must be checksum
329 int nSum = CheckSum(str);
330
331 if (nSum != (str[TLE_LEN_LINE_DATA - 1] - '0'))
332 return false;
333 */
334
335 return true;
336
337 } // IsTleFormat()
338
339 /////////////////////////////////////////////////////////////////////////////
340 // CheckSum()
341 // Calculate the check sum for a given line of TLE data, the last character
342 // of which is the current checksum. (Although there is no check here,
343 // the current checksum should match the one we calculate.)
344 // The checksum algorithm:
345 // Each number in the data line is summed, modulo 10.
346 // Non-numeric characters are zero, except minus signs, which are 1.
347 //
348 int cTle::CheckSum(const string& str)
349 {
350 // The length is "- 1" because we don't include the current (existing)
351 // checksum character in the checksum calculation.
352 size_t len = str.size() - 1;
353 int xsum = 0;
354
355 for (size_t i = 0; i < len; i++)
356 {
357 char ch = str[i];
358 if (isdigit(ch))
359 xsum += (ch - '0');
360 else if (ch == '-')
361 xsum++;
362 }
363
364 return (xsum % 10);
365
366 } // CheckSum()
367
368 /////////////////////////////////////////////////////////////////////////////
369 void cTle::TrimLeft(string& s)
370 {
371 while (s[0] == ' ')
372 s.erase(0, 1);
373 }
374
375 /////////////////////////////////////////////////////////////////////////////
376 void cTle::TrimRight(string& s)
377 {
378 while (s[s.size() - 1] == ' ')
379 s.erase(s.size() - 1);
380 }
381

  ViewVC Help
Powered by ViewVC 1.1.23