diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 2c774af032..8d672fd0a7 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 2c774af03285e57d0bdaf9f7ca60c71bb0c144bf +Subproject commit 8d672fd0a7c7ef0e6c48e1d43bacbddce1f0a10d diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/debris_shared.asset b/data/assets/scene/solarsystem/planets/earth/satellites/debris_shared.asset index 99f658c24d..54ac30a42f 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/debris_shared.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/debris_shared.asset @@ -59,7 +59,7 @@ local registerSatelliteGroupObjects = function(containingAsset, group, tleFolder -- The initialization with "-" is just a placeholder. -- (needed to be initialized) - Segments = 960, + Segments = 160, EccentricityColumn = "-", SemiMajorAxisColumn = "-", SemiMajorAxisUnit = 1, diff --git a/ext/ghoul b/ext/ghoul index 5600165bb3..9045871f1e 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 5600165bb3a2e009161d56f6dbf760fcf79e4e87 +Subproject commit 9045871f1e9a387708e8235c3bb809da7d860e6f diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index 89c71ea56f..c89110242d 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -25,8 +25,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/elonstest.h -# ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableplanet.h @@ -38,14 +37,14 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/translation/spicetranslation.h ${CMAKE_CURRENT_SOURCE_DIR}/translation/tletranslation.h ${CMAKE_CURRENT_SOURCE_DIR}/translation/horizonstranslation.h + ${CMAKE_CURRENT_SOURCE_DIR}/tasks/generatedebrisvolumetask.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/spicerotation.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/elonstest.cpp -# ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableplanet.cpp @@ -57,6 +56,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/translation/spicetranslation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/translation/tletranslation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/translation/horizonstranslation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tasks/generatedebrisvolumetask.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rotation/spicerotation.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/space/rendering/renderablegrid.cpp b/modules/space/rendering/renderablegrid.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/space/rendering/renderablegrid.h b/modules/space/rendering/renderablegrid.h new file mode 100644 index 0000000000..2f3a7bf617 --- /dev/null +++ b/modules/space/rendering/renderablegrid.h @@ -0,0 +1,37 @@ +// /**************************************************************************************** +// * * +// * OpenSpace * +// * * +// * Copyright (c) 2014-2018 * +// * * +// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * +// * software and associated documentation files (the "Software"), to deal in the Software * +// * without restriction, including without limitation the rights to use, copy, modify, * +// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +// * permit persons to whom the Software is furnished to do so, subject to the following * +// * conditions: * +// * * +// * The above copyright notice and this permission notice shall be included in all copies * +// * or substantial portions of the Software. * +// * * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +// ****************************************************************************************/ + + +#include + +namespace openspace { + + + class RenderableGrid : Renderable { + public: + protected: + private: + + }; +} \ No newline at end of file diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index ce11abf300..a1b0fb905e 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -59,6 +59,10 @@ namespace { constexpr const char* ProgramName = "RenderableSatellites"; constexpr const char* _loggerCat = "SpaceDebris"; + // constexpr const std::array UniformNames = { + // "modelViewTransform", "projectionTransform", + // "lineFade", "inGameTime", "color", "opacity" + // }; static const openspace::properties::Property::PropertyInfo PathInfo = { @@ -72,67 +76,14 @@ namespace { "Segments", "The number of segments to use for each orbit ellipse" }; - - static const openspace::properties::Property::PropertyInfo EccentricityColumnInfo = { - "EccentricityColumn", - "EccentricityColumn", - "The header of the column where the eccentricity is stored" - }; - - static const openspace::properties::Property::PropertyInfo SemiMajorAxisColumnInfo = { - "SemiMajorAxisColumn", - "SemiMajorAxisColumn", - "The header of the column where the semi-major axis is stored" - }; - - static const openspace::properties::Property::PropertyInfo SemiMajorAxisUnitInfo = { - "SemiMajorAxisUnit", - "SemiMajorAxisUnit", - "The unit of the semi major axis. For example: If specified in km, set this to 1000." - }; - - static const openspace::properties::Property::PropertyInfo InclinationColumnInfo = { - "InclinationColumn", - "InclinationColumn", - "The header of the column where the inclination is stored" - }; - - static const openspace::properties::Property::PropertyInfo AscendingNodeColumnInfo = { - "AscendingNodeColumn", - "AscendingNodeColumn", - "The header of the column where the ascending node is stored" - }; - - static const openspace::properties::Property::PropertyInfo ArgumentOfPeriapsisColumnInfo = { - "ArgumentOfPeriapsisColumn", - "ArgumentOfPeriapsisColumn", - "The header of the column where the argument of periapsis is stored" - }; - - static const openspace::properties::Property::PropertyInfo MeanAnomalyAtEpochColumnInfo = { - "MeanAnomalyAtEpochColumn", - "MeanAnomalyAtEpochColumn", - "The header of the column where the mean anomaly at epoch is stored" - }; - - static const openspace::properties::Property::PropertyInfo EpochColumnInfo = { - "EpochColumn", - "EpochColumn", - "The header of the column where the epoch is stored" - }; constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = { "LineWidth", "Line Width", "This value specifies the line width of the trail if the selected rendering " "method includes lines. If the rendering mode is set to Points, this value is " "ignored." -}; - constexpr openspace::properties::Property::PropertyInfo ColorInfo = { - "Color", - "Color", - "Färg." }; -constexpr openspace::properties::Property::PropertyInfo FadeInfo = { + constexpr openspace::properties::Property::PropertyInfo FadeInfo = { "Fade", "Line fade", "The fading factor that is applied to the trail if the 'EnableFade' value is " @@ -440,66 +391,13 @@ documentation::Documentation RenderableSatellites::Documentation() { Optional::No, PathInfo.description }, - { - EccentricityColumnInfo.identifier, - new StringVerifier, - Optional::No, - EccentricityColumnInfo.description - }, - { - SemiMajorAxisColumnInfo.identifier, - new StringVerifier, - Optional::No, - SemiMajorAxisColumnInfo.description - }, - { - SemiMajorAxisUnitInfo.identifier, - new DoubleVerifier, - Optional::No, - SemiMajorAxisUnitInfo.description - }, - { - InclinationColumnInfo.identifier, - new StringVerifier, - Optional::No, - InclinationColumnInfo.description - }, - { - AscendingNodeColumnInfo.identifier, - new StringVerifier, - Optional::No, - AscendingNodeColumnInfo.description - }, - { - ArgumentOfPeriapsisColumnInfo.identifier, - new StringVerifier, - Optional::No, - ArgumentOfPeriapsisColumnInfo.description - }, - { - MeanAnomalyAtEpochColumnInfo.identifier, - new StringVerifier, - Optional::No, - MeanAnomalyAtEpochColumnInfo.description - }, - { - EpochColumnInfo.identifier, - new StringVerifier, - Optional::No, - EpochColumnInfo.description - }, { LineWidthInfo.identifier, new DoubleVerifier, Optional::Yes, LineWidthInfo.description }, - { - ColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ColorInfo.description - }, + { FadeInfo.identifier, new DoubleVerifier, @@ -514,15 +412,6 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _path(PathInfo) , _nSegments(SegmentsInfo) - , _eccentricityColumnName(EccentricityColumnInfo) - , _semiMajorAxisColumnName(SemiMajorAxisColumnInfo) - , _semiMajorAxisUnit(SemiMajorAxisUnitInfo) - , _inclinationColumnName(InclinationColumnInfo) - , _ascendingNodeColumnName(AscendingNodeColumnInfo) - , _argumentOfPeriapsisColumnName(ArgumentOfPeriapsisColumnInfo) - , _meanAnomalyAtEpochColumnName(MeanAnomalyAtEpochColumnInfo) - , _epochColumnName(EpochColumnInfo) - , _color(ColorInfo) , _lineFade(FadeInfo) { @@ -536,34 +425,17 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) dictionary.value(PathInfo.identifier); _nSegments = static_cast(dictionary.value(SegmentsInfo.identifier)); - _eccentricityColumnName = - dictionary.value(EccentricityColumnInfo.identifier); - _semiMajorAxisColumnName = - dictionary.value(SemiMajorAxisColumnInfo.identifier); - _semiMajorAxisUnit = - dictionary.value(SemiMajorAxisUnitInfo.identifier); - _inclinationColumnName = - dictionary.value(InclinationColumnInfo.identifier); - _ascendingNodeColumnName = - dictionary.value(AscendingNodeColumnInfo.identifier); - _argumentOfPeriapsisColumnName = - dictionary.value(ArgumentOfPeriapsisColumnInfo.identifier); - _meanAnomalyAtEpochColumnName = - dictionary.value(MeanAnomalyAtEpochColumnInfo.identifier); - _epochColumnName = - dictionary.value(EpochColumnInfo.identifier); - _color = - dictionary.value(ColorInfo.identifier); _lineFade = static_cast(dictionary.value(FadeInfo.identifier)); addPropertySubOwner(_appearance); addProperty(_path); addProperty(_nSegments); + addProperty(_lineFade); } -void RenderableSatellites::readTLEFile(const std::string& filename) { +std::vector RenderableSatellites::readTLEFile(const std::string& filename) { ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); std::ifstream file; @@ -674,7 +546,7 @@ void RenderableSatellites::readTLEFile(const std::string& filename) { } // !for loop file.close(); - + return _TLEData; } @@ -686,7 +558,6 @@ RenderableSatellites::~RenderableSatellites() { void RenderableSatellites::initialize() { - readTLEFile(_path); updateBuffers(); //_path.onChange([this]() { @@ -733,6 +604,8 @@ void RenderableSatellites::initializeGL() { updateBuffers(); + //ghoul::opengl::updateUniformLocations(*_programObject, _uniformCache, UniformNames); + setRenderBin(Renderable::RenderBin::Overlay); } @@ -779,7 +652,7 @@ void RenderableSatellites::render(const RenderData& data, RendererTasks&) { _programObject->setUniform(_uniformCache.projection, data.camera.projectionMatrix()); _programObject->setUniform(_uniformCache.color, _appearance.lineColor); - _programObject->setUniform(_uniformCache.lineFade, _appearance.lineFade); + _programObject->setUniform(_uniformCache.lineFade, _appearance.lineFade); //!!! WHY DOES _lineFade NOT WORK? //glEnableVertexAttribArray(0); // We like submitting vertices on stream 0 for no special reason //glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(TrailVBOLayout), 0); @@ -803,6 +676,7 @@ void RenderableSatellites::render(const RenderData& data, RendererTasks&) { } void RenderableSatellites::updateBuffers() { + _TLEData = readTLEFile(_path); const size_t nVerticesPerOrbit = _nSegments + 1; _vertexBufferData.resize(_TLEData.size() * nVerticesPerOrbit); diff --git a/modules/space/rendering/renderablesatellites.h b/modules/space/rendering/renderablesatellites.h index ca6170e6d8..ae6b943c4a 100644 --- a/modules/space/rendering/renderablesatellites.h +++ b/modules/space/rendering/renderablesatellites.h @@ -75,6 +75,22 @@ namespace openspace { void update(const UpdateData& data) override; static documentation::Documentation Documentation(); + /** + * Reads the provided TLE file and calles the KeplerTranslation::setKeplerElments + * method with the correct values. If \p filename is a valid TLE file but contains + * disallowed values (see KeplerTranslation::setKeplerElements), a + * KeplerTranslation::RangeError is thrown. + * + * \param filename The path to the file that contains the TLE file. + * \param lineNum The line number in the file where the set of 3 TLE lines starts + * + * \throw std::system_error if the TLE file is malformed (does not contain at least + * two lines that start with \c 1 and \c 2. + * \throw KeplerTranslation::RangeError If the Keplerian elements are outside of + * the valid range supported by Kepler::setKeplerElements + * \pre The \p filename must exist + */ + std::vector readTLEFile(const std::string& filename); private: /// The layout of the VBOs @@ -109,15 +125,6 @@ namespace openspace { properties::StringProperty _path; properties::UIntProperty _nSegments; - properties::StringProperty _eccentricityColumnName; - properties::StringProperty _semiMajorAxisColumnName; - properties::DoubleProperty _semiMajorAxisUnit; - properties::StringProperty _inclinationColumnName; - properties::StringProperty _ascendingNodeColumnName; - properties::StringProperty _argumentOfPeriapsisColumnName; - properties::StringProperty _meanAnomalyAtEpochColumnName; - properties::StringProperty _epochColumnName; - properties::Vec3Property _color; properties::DoubleProperty _lineFade; RenderableTrail::Appearance _appearance; @@ -126,28 +133,11 @@ namespace openspace { double _inGameTime = 0.0; - UniformCache(opacity, modelView, projection, color, useLineFade, lineFade, - segments, position, vertexIDs, numberOfOrbits, inGameTime) + UniformCache(modelView, projection, lineFade, inGameTime, color, opacity) _uniformCache; - /** - * Reads the provided TLE file and calles the KeplerTranslation::setKeplerElments - * method with the correct values. If \p filename is a valid TLE file but contains - * disallowed values (see KeplerTranslation::setKeplerElements), a - * KeplerTranslation::RangeError is thrown. - * - * \param filename The path to the file that contains the TLE file. - * \param lineNum The line number in the file where the set of 3 TLE lines starts - * - * \throw std::system_error if the TLE file is malformed (does not contain at least - * two lines that start with \c 1 and \c 2. - * \throw KeplerTranslation::RangeError If the Keplerian elements are outside of - * the valid range supported by Kepler::setKeplerElements - * \pre The \p filename must exist - */ - void readTLEFile(const std::string& filename); }; +} #endif // __OPENSPACE_MODULE_BASE___RenderableSatellites___H__ -} diff --git a/modules/space/spacemodule.cpp b/modules/space/spacemodule.cpp index d52212073e..e36881acec 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -32,12 +32,12 @@ #include #include #include -#include s -#include +#include #include #include #include #include +#include #include #include #include @@ -96,6 +96,10 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary&) { fTranslation->registerClass("TLETranslation"); fTranslation->registerClass("HorizonsTranslation"); + auto fTasks = FactoryManager::ref().factory(); + ghoul_assert(fTask, "No task factory existed"); + fTasks->registerClass("GenerateDebrisVolumeTask"); + auto fRotation = FactoryManager::ref().factory(); ghoul_assert(fRotation, "Rotation factory was not created"); diff --git a/modules/space/tasks/generatedebrisvolumetask.cpp b/modules/space/tasks/generatedebrisvolumetask.cpp new file mode 100644 index 0000000000..9f9b2fc5da --- /dev/null +++ b/modules/space/tasks/generatedebrisvolumetask.cpp @@ -0,0 +1,476 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ +#include + +#include +#include +//#include + +#include + + +#include +#include +//#include +//#include + +#include + + +namespace { + constexpr const char* KeyRawVolumeOutput = "RawVolumeOutput"; + constexpr const char* KeyDictionaryOutput = "DictionaryOutput"; + constexpr const char* KeyDimensions = "Dimensions"; + constexpr const char* KeyStartTime = "StartTime"; + constexpr const char* KeyEndTime = "EndTime"; + constexpr const char* KeyInputPath = "InputPath"; + + +} + +namespace openspace{ +namespace volume { +// The list of leap years only goes until 2056 as we need to touch this file then +// again anyway ;) +const std::vector LeapYears = { + 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036, 2040, + 2044, 2048, 2052, 2056 +}; +// Count the number of full days since the beginning of 2000 to the beginning of +// the parameter 'year' +int countDays(int year) { + // Find the position of the current year in the vector, the difference + // between its position and the position of 2000 (for J2000) gives the + // number of leap years + constexpr const int Epoch = 2000; + constexpr const int DaysRegularYear = 365; + constexpr const int DaysLeapYear = 366; + + if (year == Epoch) { + return 0; + } + + // Get the position of the most recent leap year + const auto lb = std::lower_bound(LeapYears.begin(), LeapYears.end(), year); + + // Get the position of the epoch + const auto y2000 = std::find(LeapYears.begin(), LeapYears.end(), Epoch); + + // The distance between the two iterators gives us the number of leap years + const int nLeapYears = static_cast(std::abs(std::distance(y2000, lb))); + + const int nYears = std::abs(year - Epoch); + const int nRegularYears = nYears - nLeapYears; + + // Get the total number of days as the sum of leap years + non leap years + const int result = nRegularYears * DaysRegularYear + nLeapYears * DaysLeapYear; + return result; +} + +// Returns the number of leap seconds that lie between the {year, dayOfYear} +// time point and { 2000, 1 } +int countLeapSeconds(int year, int dayOfYear) { + // Find the position of the current year in the vector; its position in + // the vector gives the number of leap seconds + struct LeapSecond { + int year; + int dayOfYear; + bool operator<(const LeapSecond& rhs) const { + return std::tie(year, dayOfYear) < std::tie(rhs.year, rhs.dayOfYear); + } + }; + + const LeapSecond Epoch = { 2000, 1 }; + + // List taken from: https://www.ietf.org/timezones/data/leap-seconds.list + static const std::vector LeapSeconds = { + { 1972, 1 }, + { 1972, 183 }, + { 1973, 1 }, + { 1974, 1 }, + { 1975, 1 }, + { 1976, 1 }, + { 1977, 1 }, + { 1978, 1 }, + { 1979, 1 }, + { 1980, 1 }, + { 1981, 182 }, + { 1982, 182 }, + { 1983, 182 }, + { 1985, 182 }, + { 1988, 1 }, + { 1990, 1 }, + { 1991, 1 }, + { 1992, 183 }, + { 1993, 182 }, + { 1994, 182 }, + { 1996, 1 }, + { 1997, 182 }, + { 1999, 1 }, + { 2006, 1 }, + { 2009, 1 }, + { 2012, 183 }, + { 2015, 182 }, + { 2017, 1 } + }; + + // Get the position of the last leap second before the desired date + LeapSecond date { year, dayOfYear }; + const auto it = std::lower_bound(LeapSeconds.begin(), LeapSeconds.end(), date); + + // Get the position of the Epoch + const auto y2000 = std::lower_bound( + LeapSeconds.begin(), + LeapSeconds.end(), + Epoch + ); + + // The distance between the two iterators gives us the number of leap years + const int nLeapSeconds = static_cast(std::abs(std::distance(y2000, it))); + return nLeapSeconds; +} + +double calculateSemiMajorAxis(double meanMotion) { + constexpr const double GravitationalConstant = 6.6740831e-11; + constexpr const double MassEarth = 5.9721986e24; + constexpr const double muEarth = GravitationalConstant * MassEarth; + + // Use Kepler's 3rd law to calculate semimajor axis + // a^3 / P^2 = mu / (2pi)^2 + // <=> a = ((mu * P^2) / (2pi^2))^(1/3) + // with a = semimajor axis + // P = period in seconds + // mu = G*M_earth + double period = std::chrono::seconds(std::chrono::hours(24)).count() / meanMotion; + + const double pisq = glm::pi() * glm::pi(); + double semiMajorAxis = pow((muEarth * period*period) / (4 * pisq), 1.0 / 3.0); + + // We need the semi major axis in km instead of m + return semiMajorAxis / 1000.0; +} + +double epochFromSubstring(const std::string& epochString) { + // The epochString is in the form: + // YYDDD.DDDDDDDD + // With YY being the last two years of the launch epoch, the first DDD the day + // of the year and the remaning a fractional part of the day + + // The main overview of this function: + // 1. Reconstruct the full year from the YY part + // 2. Calculate the number of seconds since the beginning of the year + // 2.a Get the number of full days since the beginning of the year + // 2.b If the year is a leap year, modify the number of days + // 3. Convert the number of days to a number of seconds + // 4. Get the number of leap seconds since January 1st, 2000 and remove them + // 5. Adjust for the fact the epoch starts on 1st Januaray at 12:00:00, not + // midnight + + // According to https://celestrak.com/columns/v04n03/ + // Apparently, US Space Command sees no need to change the two-line element + // set format yet since no artificial earth satellites existed prior to 1957. + // By their reasoning, two-digit years from 57-99 correspond to 1957-1999 and + // those from 00-56 correspond to 2000-2056. We'll see each other again in 2057! + + // 1. Get the full year + std::string yearPrefix = [y = epochString.substr(0, 2)](){ + int year = std::atoi(y.c_str()); + return year >= 57 ? "19" : "20"; + }(); + const int year = std::atoi((yearPrefix + epochString.substr(0, 2)).c_str()); + const int daysSince2000 = countDays(year); + + // 2. + // 2.a + double daysInYear = std::atof(epochString.substr(2).c_str()); + + // 2.b + const bool isInLeapYear = std::find( + LeapYears.begin(), + LeapYears.end(), + year + ) != LeapYears.end(); + if (isInLeapYear && daysInYear >= 60) { + // We are in a leap year, so we have an effective day more if we are + // beyond the end of february (= 31+29 days) + --daysInYear; + } + + // 3 + using namespace std::chrono; + const int SecondsPerDay = static_cast(seconds(hours(24)).count()); + //Need to subtract 1 from daysInYear since it is not a zero-based count + const double nSecondsSince2000 = (daysSince2000 + daysInYear - 1) * SecondsPerDay; + + // 4 + // We need to remove additionbal leap seconds past 2000 and add them prior to + // 2000 to sync up the time zones + const double nLeapSecondsOffset = -countLeapSeconds( + year, + static_cast(std::floor(daysInYear)) + ); + + // 5 + const double nSecondsEpochOffset = static_cast( + seconds(hours(12)).count() + ); + + // Combine all of the values + const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset; + return epoch; +} + +std::vector readTLEFile(const std::string& filename){ + ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); + + std::vector data; + + std::ifstream file; + file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + file.open(filename); + + int numberOfLines = std::count(std::istreambuf_iterator(file), + std::istreambuf_iterator(), '\n' ); + file.seekg(std::ios_base::beg); // reset iterator to beginning of file + + // 3 because a TLE has 3 lines per element/ object. + int numberOfObjects = numberOfLines/3; + + std::string line = "-"; + for (int i = 0; i < numberOfObjects; i++) { + + std::getline(file, line); // get rid of title + + KeplerParameters keplerElements; + + std::getline(file, line); + if (line[0] == '1') { + // First line + // Field Columns Content + // 1 01-01 Line number + // 2 03-07 Satellite number + // 3 08-08 Classification (U = Unclassified) + // 4 10-11 International Designator (Last two digits of launch year) + // 5 12-14 International Designator (Launch number of the year) + // 6 15-17 International Designator(piece of the launch) A + // 7 19-20 Epoch Year(last two digits of year) + // 8 21-32 Epoch(day of the year and fractional portion of the day) + // 9 34-43 First Time Derivative of the Mean Motion divided by two + // 10 45-52 Second Time Derivative of Mean Motion divided by six + // 11 54-61 BSTAR drag term(decimal point assumed)[10] - 11606 - 4 + // 12 63-63 The "Ephemeris type" + // 13 65-68 Element set number.Incremented when a new TLE is generated + // 14 69-69 Checksum (modulo 10) + keplerElements.epoch = epochFromSubstring(line.substr(18, 14)); + } + else { + throw ghoul::RuntimeError(fmt::format( + "File {} @ line {} does not have '1' header", filename // linNum + 1 + )); + } + + std::getline(file, line); + if (line[0] == '2') { + // Second line + // Field Columns Content + // 1 01-01 Line number + // 2 03-07 Satellite number + // 3 09-16 Inclination (degrees) + // 4 18-25 Right ascension of the ascending node (degrees) + // 5 27-33 Eccentricity (decimal point assumed) + // 6 35-42 Argument of perigee (degrees) + // 7 44-51 Mean Anomaly (degrees) + // 8 53-63 Mean Motion (revolutions per day) + // 9 64-68 Revolution number at epoch (revolutions) + // 10 69-69 Checksum (modulo 10) + + std::stringstream stream; + stream.exceptions(std::ios::failbit); + + // Get inclination + stream.str(line.substr(8, 8)); + stream >> keplerElements.inclination; + stream.clear(); + + // Get Right ascension of the ascending node + stream.str(line.substr(17, 8)); + stream >> keplerElements.ascendingNode; + stream.clear(); + + // Get Eccentricity + stream.str("0." + line.substr(26, 7)); + stream >> keplerElements.eccentricity; + stream.clear(); + + // Get argument of periapsis + stream.str(line.substr(34, 8)); + stream >> keplerElements.argumentOfPeriapsis; + stream.clear(); + + // Get mean anomaly + stream.str(line.substr(43, 8)); + stream >> keplerElements.meanAnomaly; + stream.clear(); + + // Get mean motion + stream.str(line.substr(52, 11)); + stream >> keplerElements.meanMotion; + } + else { + throw ghoul::RuntimeError(fmt::format( + "File {} @ line {} does not have '2' header", filename // , lineNum + 2 + )); + } + + // Calculate the semi major axis based on the mean motion using kepler's laws + keplerElements.semiMajorAxis = calculateSemiMajorAxis(keplerElements.meanMotion); + + using namespace std::chrono; + double period = seconds(hours(24)).count() / keplerElements.meanMotion; + keplerElements.period = period; + + data.push_back(keplerElements); + + } // !for loop + file.close(); + return data; +} + +std::vector getPositionBuffer(std::vector tleData) { + + + +} + +GenerateDebrisVolumeTask::GenerateDebrisVolumeTask(const ghoul::Dictionary& dictionary) +{ + openspace::documentation::testSpecificationAndThrow( + documentation(), + dictionary, + "GenerateDebrisVolumeTask" + ); + + _rawVolumeOutputPath = absPath(dictionary.value(KeyRawVolumeOutput)); + _dictionaryOutputPath = absPath(dictionary.value(KeyDictionaryOutput)); + _dimensions = glm::uvec3(dictionary.value(KeyDimensions)); + _startTime = dictionary.value(KeyStartTime); + _endTime = dictionary.value(KeyEndTime); + _inputPath = dictionary.value(KeyInputPath); + _TLEDataVector = {}; +} + +std::string GenerateDebrisVolumeTask::description() { + return "todo:: description"; +} + +void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCallback) { + + // create object rawVolume + volume::RawVolume rawVolume(_dimensions); + + //1. read TLE-data and position of debris elements. + _TLEDataVector = readTLEFile(_inputPath); + std::vector positionBuffer = getPositionBuffer(_TLEDataVector); + //2. create a grid using dimensions and other .task-parameters. + + //3. calculate what voxel each debris is within for each time step. + // and increment density with one for each debris in that voxel. + + //4. + + + + + + + + + + + + + + + + + + +} + +documentation::Documentation GenerateDebrisVolumeTask::documentation() { + using namespace documentation; + return { + "GenerateDebrisVolumeTask", + "generate_debris_volume_task", + { + { + "Type", + new StringEqualVerifier("GenerateDebrisVolumeTask"), + Optional::No, + "The type of this task", + }, + // { + // KeyValueFunction, + // new StringAnnotationVerifier("A lua expression that returns a function " + // "taking three numbers as arguments (x, y, z) and returning a number."), + // Optional::No, + // "The lua function used to compute the cell values", + // }, + { + KeyRawVolumeOutput, + new StringAnnotationVerifier("A valid filepath"), + Optional::No, + "The raw volume file to export data to", + }, + { + KeyDictionaryOutput, + new StringAnnotationVerifier("A valid filepath"), + Optional::No, + "The lua dictionary file to export metadata to", + }, + { + KeyDimensions, + new DoubleVector3Verifier, + Optional::No, + "A vector representing the number of cells in each dimension", + }, + // { + // KeyLowerDomainBound, + // new DoubleVector3Verifier, + // Optional::No, + // "A vector representing the lower bound of the domain" + // }, + // { + // KeyUpperDomainBound, + // new DoubleVector3Verifier, + // Optional::No, + // "A vector representing the upper bound of the domain" + // } + } + }; +} + +} // namespace volume +} // namespace openspace diff --git a/modules/space/tasks/generatedebrisvolumetask.h b/modules/space/tasks/generatedebrisvolumetask.h new file mode 100644 index 0000000000..72da256248 --- /dev/null +++ b/modules/space/tasks/generatedebrisvolumetask.h @@ -0,0 +1,67 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ +#ifndef __OPENSPACE_MODULE_SPACE___GENERATERDEBRISVOLUMETASK___H__ +#define __OPENSPACE_MODULE_SPACE___GENERATERDEBRISVOLUMETASK___H__ + +#include +#include + +#include + +#include +#include + +namespace openspace { +namespace volume { + + +class GenerateDebrisVolumeTask : public Task { +public: + GenerateDebrisVolumeTask(const ghoul::Dictionary& dictionary); + std::string description() override; + void perform(const Task::ProgressCallback& progressCallback) override; + static documentation::Documentation documentation(); + +private: + std::string _rawVolumeOutputPath; + std::string _dictionaryOutputPath; + std::string _startTime; + std::string _endTime; + std::string _inputPath; + + glm::uvec3 _dimensions; + + std::vector _TLEDataVector; + + // not sure if it should be local function or hidden function. + //std::vector readTLEFile(const std::string& filename); + +}; + + + +} // namespace volume +} // namespace openspace + +#endif // __OPENSPACE_MODULE_SPACE___GENERATEDEBRISVOLUMETASK___H__