diff --git a/Rewrite.vcxproj b/Rewrite.vcxproj
index 998bf96..26657a3 100644
--- a/Rewrite.vcxproj
+++ b/Rewrite.vcxproj
@@ -78,12 +78,14 @@
+
+
diff --git a/Rewrite.vcxproj.filters b/Rewrite.vcxproj.filters
index 7e3811e..0d3971e 100644
--- a/Rewrite.vcxproj.filters
+++ b/Rewrite.vcxproj.filters
@@ -30,6 +30,9 @@
Source Files
+
+ Source Files
+
@@ -44,5 +47,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/Tle.cpp b/Tle.cpp
new file mode 100644
index 0000000..9abccf2
--- /dev/null
+++ b/Tle.cpp
@@ -0,0 +1,289 @@
+#include "Tle.h"
+
+#include
+#include
+
+Tle::Tle(const std::string& name, const std::string& line_one, const std::string& line_two) {
+ name_ = name;
+ line_one_ = line_one;
+ line_two_ = line_two;
+
+ Initialize();
+}
+
+Tle::Tle(const Tle& tle) {
+ name_ = tle.name_;
+ line_one_ = tle.line_one_;
+ line_two_ = tle.line_two_;
+ date_ = tle.date_;
+
+ for (int fld = FLD_FIRST; fld < FLD_LAST; fld++) {
+ fields_[fld] = tle.fields_[fld];
+ }
+}
+
+Tle::~Tle() {
+}
+
+double Tle::GetField(TleField fld, TleUnits units) const {
+ assert((FLD_FIRST <= fld) && (fld < FLD_LAST));
+ assert((U_FIRST <= units) && (units < U_LAST));
+
+ double value = fields_[fld].second;
+ double converted = 0.0;
+
+ switch (fld) {
+ case FLD_I:
+ case FLD_RAAN:
+ case FLD_ARGPER:
+ case FLD_M:
+ {
+ /*
+ * native format is degrees
+ */
+ if (units == U_RAD)
+ converted = Globals::Deg2Rad(value);
+ break;
+ }
+ default:
+ {
+ converted = value;
+ break;
+ }
+ }
+
+ return converted;
+}
+
+/*
+ * get field represented as a string
+ */
+std::string Tle::GetFieldString(TleField fld, bool append_units) const {
+ assert((FLD_FIRST <= fld) && (fld < FLD_LAST));
+
+ std::string str = fields_[fld].first;
+
+ if (append_units)
+ str += GetUnits(fld);
+
+ return str;
+}
+
+/*
+ * get the units for a field
+ */
+std::string Tle::GetUnits(TleField field) const {
+ static const std::string strDegrees = " degrees";
+ static const std::string strRevsPerDay = " revs / day";
+ static const std::string strNull = "";
+
+ switch (field) {
+ case FLD_I:
+ case FLD_RAAN:
+ case FLD_ARGPER:
+ case FLD_M:
+ return strDegrees;
+
+ case FLD_MMOTION:
+ return strRevsPerDay;
+
+ default:
+ return strNull;
+ }
+}
+
+/*
+ * convert a raw string into an exponent string
+ */
+std::string Tle::ExpToDecimal(const std::string& str) {
+ static const int kColumnSign = 0;
+ static const int kLengthSign = 1;
+ static const int kColumnMantissa = 1;
+ static const int kLengthMantissa = 5;
+ static const int kColumnExp = 6;
+ static const int kLengthExp = 2;
+
+ assert(8 == str.length());
+
+ std::string value;
+ value = str.substr(kColumnSign, kLengthSign);
+ value += ".";
+ value += str.substr(kColumnMantissa, kLengthMantissa);
+ value += "e";
+ value += str.substr(kColumnExp, kLengthExp);
+
+ return value;
+}
+
+/*
+ * extract all variables
+ */
+void Tle::Initialize() {
+ assert(!name_.empty());
+ assert(!line_one_.empty());
+ assert(!line_two_.empty());
+
+ /*
+ * line 1
+ */
+
+ fields_[FLD_NORADNUM].first = line_one_.substr(TLE1_COL_SATNUM, TLE1_LEN_SATNUM);
+ fields_[FLD_INTLDESC].first = line_one_.substr(TLE1_COL_INTLDESC_A, TLE1_LEN_INTLDESC_A +
+ TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);
+ fields_[FLD_EPOCHYEAR].first = line_one_.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A);
+
+ fields_[FLD_EPOCHDAY].first = line_one_.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B);
+
+ if (line_one_[TLE1_COL_MEANMOTIONDT] == '-') {
+ // value is negative
+ fields_[FLD_MMOTIONDT].first = "-0";
+ } else
+ fields_[FLD_MMOTIONDT].first = "0";
+
+ fields_[FLD_MMOTIONDT].first += line_one_.substr(TLE1_COL_MEANMOTIONDT + 1, TLE1_LEN_MEANMOTIONDT);
+
+ // decimal point assumed; exponential notation
+ fields_[FLD_MMOTIONDT2].first = ExpToDecimal(line_one_.substr(TLE1_COL_MEANMOTIONDT2, TLE1_LEN_MEANMOTIONDT2));
+
+ // decimal point assumed; exponential notation
+ fields_[FLD_BSTAR].first = ExpToDecimal(line_one_.substr(TLE1_COL_BSTAR, TLE1_LEN_BSTAR));
+
+ fields_[FLD_SET].first = line_one_.substr(TLE1_COL_ELNUM, TLE1_LEN_ELNUM);
+ TrimLeft(fields_[FLD_SET].first);
+
+ /*
+ * line 2
+ */
+
+ fields_[FLD_I].first = line_two_.substr(TLE2_COL_INCLINATION, TLE2_LEN_INCLINATION);
+ TrimLeft(fields_[FLD_I].first);
+
+ fields_[FLD_RAAN].first = line_two_.substr(TLE2_COL_RAASCENDNODE, TLE2_LEN_RAASCENDNODE);
+ TrimLeft(fields_[FLD_RAAN].first);
+
+ // decimal point is assumed
+ fields_[FLD_E].first = "0.";
+ fields_[FLD_E].first += line_two_.substr(TLE2_COL_ECCENTRICITY, TLE2_LEN_ECCENTRICITY);
+
+ fields_[FLD_ARGPER].first = line_two_.substr(TLE2_COL_ARGPERIGEE, TLE2_LEN_ARGPERIGEE);
+ TrimLeft(fields_[FLD_ARGPER].first);
+
+ fields_[FLD_M].first = line_two_.substr(TLE2_COL_MEANANOMALY, TLE2_LEN_MEANANOMALY);
+ TrimLeft(fields_[FLD_M].first);
+
+ fields_[FLD_MMOTION].first = line_two_.substr(TLE2_COL_MEANMOTION, TLE2_LEN_MEANMOTION);
+ TrimLeft(fields_[FLD_MMOTION].first);
+
+ fields_[FLD_ORBITNUM].first = line_two_.substr(TLE2_COL_REVATEPOCH, TLE2_LEN_REVATEPOCH);
+ TrimLeft(fields_[FLD_ORBITNUM].first);
+
+ // update double variables
+ for (int fld = FLD_FIRST; fld < FLD_LAST; fld++) {
+ fields_[fld].second = atof(fields_[fld].first.c_str());
+ }
+
+ int epochYear = (int) GetField(Tle::FLD_EPOCHYEAR);
+ double epochDay = GetField(Tle::FLD_EPOCHDAY);
+
+ if (epochYear < 57)
+ epochYear += 2000;
+ else
+ epochYear += 1900;
+
+ date_ = Julian(epochYear, epochDay);
+}
+
+/*
+ * validate a line
+ */
+bool Tle::IsValidLine(std::string& str, TleLine line) {
+ TrimLeft(str);
+ TrimRight(str);
+
+ const std::string line1_validation = "1 NNNNNC NNNNAAAA NNNNN.NNNNNNNN +.NNNNNNNN +NNNNN-N +NNNNN-N N NNNNN";
+ const std::string line2_validation = "2 NNNNN NNN.NNNN NNN.NNNN NNNNNNN NNN.NNNN NNN.NNNN NN.NNNNNNNNNNNNNN";
+
+ if (Tle::LINE_ONE == line) {
+ if (!ValidateLine(line1_validation, str))
+ return false;
+ } else if (Tle::LINE_TWO == line) {
+ if (!ValidateLine(line2_validation, str))
+ return false;
+ }
+
+ // Last char in string must be checksum
+ // int chk = CheckSum(str);
+ // if (chk != (str[TLE_LEN_LINE_DATA - 1] - '0'))
+ // return false;
+
+ return true;
+}
+
+/*
+ * validate line given a pattern
+ */
+bool Tle::ValidateLine(const std::string& pattern, const std::string& line) {
+ assert(pattern.length() == line.length());
+
+ std::string::size_type pos = 0;
+
+ while (pos != line.length() - 1) {
+ if (isdigit(pattern[pos]) || pattern[pos] == ' ' || pattern[pos] == '.') {
+ if (pattern[pos] != line[pos])
+ return false;
+ } else if (pattern[pos] == 'N') {
+ if (!isdigit(line[pos]) && line[pos] != ' ')
+ return false;
+ }
+ pos++;
+ }
+
+ return true;
+}
+
+/*
+ * compute checksum
+ */
+int Tle::CheckSum(const std::string& str) {
+ size_t len = str.size() - 1;
+ int xsum = 0;
+
+ for (size_t i = 0; i < len; i++) {
+ char ch = str[i];
+ if (isdigit(ch))
+ xsum += (ch - '0');
+ else if (ch == '-')
+ xsum++;
+ }
+
+ return (xsum % 10);
+}
+
+/*
+ * trim left of string
+ */
+void Tle::TrimLeft(std::string& s) {
+ if (!s.empty()) {
+ std::string::size_type pos = s.find_first_not_of(' ');
+
+ if (pos != std::string::npos)
+ s.erase(0, pos);
+ else
+ s.clear();
+ }
+}
+
+/*
+ * trim right of string
+ */
+void Tle::TrimRight(std::string& s) {
+ if (!s.empty()) {
+ std::string::size_type pos = s.find_last_not_of(' ');
+
+ if (pos != std::string::npos)
+ s.erase(pos + 1);
+ else
+ s.clear();
+ }
+}
+
diff --git a/Tle.h b/Tle.h
new file mode 100644
index 0000000..e5b41d2
--- /dev/null
+++ b/Tle.h
@@ -0,0 +1,182 @@
+#ifndef TLE_H_
+#define TLE_H_
+
+#include "Globals.h"
+#include "Julian.h"
+
+#include
+
+class Tle {
+public:
+ Tle(const std::string& name, const std::string& line_one, const std::string& line_two);
+ Tle(const Tle& tle);
+ virtual ~Tle();
+
+ enum TleLine {
+ LINE_ZERO,
+ LINE_ONE,
+ LINE_TWO
+ };
+
+ enum TleField {
+ FLD_FIRST,
+ FLD_NORADNUM = FLD_FIRST,
+ FLD_INTLDESC,
+ FLD_SET, // Tle set number
+ FLD_EPOCHYEAR, // Epoch: Last two digits of year
+ FLD_EPOCHDAY, // Epoch: Fractional Julian Day of year
+ FLD_ORBITNUM, // Orbit at epoch
+ FLD_I, // Inclination
+ FLD_RAAN, // R.A. ascending node
+ FLD_E, // Eccentricity
+ FLD_ARGPER, // Argument of perigee
+ FLD_M, // Mean anomaly
+ FLD_MMOTION, // Mean motion
+ FLD_MMOTIONDT, // First time derivative of mean motion
+ FLD_MMOTIONDT2, // Second time derivative of mean motion
+ FLD_BSTAR, // BSTAR Drag
+ FLD_LAST // MUST be last
+ };
+
+ enum TleUnits {
+ U_FIRST,
+ U_RAD = U_FIRST, // radians
+ U_DEG, // degrees
+ U_NATIVE, // Tle format native units (no conversion)
+ U_LAST // MUST be last
+ };
+
+ /*
+ * initialize from raw tle strings
+ */
+ void Initialize();
+
+ /*
+ * get field represented as a double
+ */
+ double GetField(TleField fld, TleUnits unit = U_NATIVE) const;
+ /*
+ * get field represented as a string
+ */
+ std::string GetFieldString(TleField fld, bool append_units) const;
+
+ /*
+ * get epoch of tle
+ */
+ Julian GetEpoch() const {
+ return date_;
+ }
+
+ /*
+ * compute checksum
+ */
+ static int CheckSum(const std::string& str);
+ static bool IsValidLine(std::string& str, TleLine line);
+ static void TrimLeft(std::string& str);
+ static void TrimRight(std::string& str);
+
+ std::string GetName() const {
+ return name_;
+ }
+
+ std::string GetLine1() const {
+ return line_one_;
+ }
+
+ std::string GetLine2() const {
+ return line_two_;
+ }
+
+ double GetNoradNumber() const {
+ return GetField(Tle::FLD_NORADNUM);
+ }
+
+private:
+ /*
+ * get units for a field
+ */
+ std::string GetUnits(TleField field) const;
+ /*
+ * get raw value for a field
+ */
+ double GetFieldNumeric(TleField) const;
+ /*
+ * convert a raw string into an exponent string
+ */
+ static std::string ExpToDecimal(const std::string&);
+ /*
+ * validate a line
+ */
+ static bool ValidateLine(const std::string& pattern, const std::string& line);
+
+ /*
+ * raw tle data
+ */
+ std::string name_;
+ std::string line_one_;
+ std::string line_two_;
+
+ /*
+ * epoch of tle
+ */
+ Julian date_;
+
+ // array of tle values in native string and double form
+ std::pair fields_[FLD_LAST];
+
+ /*
+ * name line
+ */
+ static const unsigned int TLE_LEN_LINE_DATA = 69;
+ static const unsigned int TLE_LEN_LINE_NAME = 22;
+
+ /*
+ * line 1
+ */
+ static const unsigned int TLE1_COL_SATNUM = 2;
+ static const unsigned int TLE1_LEN_SATNUM = 5;
+ static const unsigned int TLE1_COL_INTLDESC_A = 9;
+ static const unsigned int TLE1_LEN_INTLDESC_A = 2;
+ static const unsigned int TLE1_COL_INTLDESC_B = 11;
+ static const unsigned int TLE1_LEN_INTLDESC_B = 3;
+ static const unsigned int TLE1_COL_INTLDESC_C = 14;
+ static const unsigned int TLE1_LEN_INTLDESC_C = 3;
+ static const unsigned int TLE1_COL_EPOCH_A = 18;
+ static const unsigned int TLE1_LEN_EPOCH_A = 2;
+ static const unsigned int TLE1_COL_EPOCH_B = 20;
+ static const unsigned int TLE1_LEN_EPOCH_B = 12;
+ static const unsigned int TLE1_COL_MEANMOTIONDT = 33;
+ static const unsigned int TLE1_LEN_MEANMOTIONDT = 10;
+ static const unsigned int TLE1_COL_MEANMOTIONDT2 = 44;
+ static const unsigned int TLE1_LEN_MEANMOTIONDT2 = 8;
+ static const unsigned int TLE1_COL_BSTAR = 53;
+ static const unsigned int TLE1_LEN_BSTAR = 8;
+ static const unsigned int TLE1_COL_EPHEMTYPE = 62;
+ static const unsigned int TLE1_LEN_EPHEMTYPE = 1;
+ static const unsigned int TLE1_COL_ELNUM = 64;
+ static const unsigned int TLE1_LEN_ELNUM = 4;
+
+ /*
+ * line 2
+ */
+ static const unsigned int TLE2_COL_SATNUM = 2;
+ static const unsigned int TLE2_LEN_SATNUM = 5;
+ static const unsigned int TLE2_COL_INCLINATION = 8;
+ static const unsigned int TLE2_LEN_INCLINATION = 8;
+ static const unsigned int TLE2_COL_RAASCENDNODE = 17;
+ static const unsigned int TLE2_LEN_RAASCENDNODE = 8;
+ static const unsigned int TLE2_COL_ECCENTRICITY = 26;
+ static const unsigned int TLE2_LEN_ECCENTRICITY = 7;
+ static const unsigned int TLE2_COL_ARGPERIGEE = 34;
+ static const unsigned int TLE2_LEN_ARGPERIGEE = 8;
+ static const unsigned int TLE2_COL_MEANANOMALY = 43;
+ static const unsigned int TLE2_LEN_MEANANOMALY = 8;
+ static const unsigned int TLE2_COL_MEANMOTION = 52;
+ static const unsigned int TLE2_LEN_MEANMOTION = 11;
+ static const unsigned int TLE2_COL_REVATEPOCH = 63;
+ static const unsigned int TLE2_LEN_REVATEPOCH = 5;
+};
+
+#endif
+
+
diff --git a/main.cpp b/main.cpp
index c91bc2a..0683211 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,4 +1,5 @@
#include "Julian.h"
+#include "Tle.h"
#include