mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2025-12-31 16:30:07 -06:00
264 lines
11 KiB
C++
264 lines
11 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2021 *
|
|
* *
|
|
* 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 <modules/space/rendering/renderablesatellites.h>
|
|
|
|
#include <modules/space/translation/keplertranslation.h>
|
|
#include <modules/space/translation/tletranslation.h>
|
|
#include <modules/space/spacemodule.h>
|
|
#include <openspace/engine/openspaceengine.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/documentation/documentation.h>
|
|
#include <openspace/documentation/verifier.h>
|
|
#include <openspace/util/time.h>
|
|
#include <openspace/util/updatestructures.h>
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/filesystem/file.h>
|
|
#include <ghoul/misc/csvreader.h>
|
|
#include <ghoul/opengl/programobject.h>
|
|
#include <ghoul/logging/logmanager.h>
|
|
#include <chrono>
|
|
#include <math.h>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <vector>
|
|
|
|
namespace {
|
|
constexpr const char* _loggerCat = "Satellites";
|
|
|
|
static const openspace::properties::Property::PropertyInfo SegmentsInfo = {
|
|
"Segments",
|
|
"Segments",
|
|
"The number of segments to use for each orbit ellipse"
|
|
};
|
|
|
|
struct [[codegen::Dictionary(RenderableSatellites)]] Parameters {
|
|
// [[codegen::verbatim(SegmentsInfo.description)]]
|
|
double segments;
|
|
};
|
|
#include "renderablesatellites_codegen.cpp"
|
|
}
|
|
|
|
namespace openspace {
|
|
|
|
documentation::Documentation RenderableSatellites::Documentation() {
|
|
documentation::Documentation doc = codegen::doc<Parameters>(
|
|
"space_renderablesatellites"
|
|
);
|
|
|
|
// Insert the parents documentation entries until we have a verifier that can deal
|
|
// with class hierarchy
|
|
documentation::Documentation parentDoc = RenderableOrbitalKepler::Documentation();
|
|
doc.entries.insert(
|
|
doc.entries.end(),
|
|
parentDoc.entries.begin(),
|
|
parentDoc.entries.end()
|
|
);
|
|
|
|
return doc;
|
|
}
|
|
|
|
RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary)
|
|
: RenderableOrbitalKepler(dictionary)
|
|
{
|
|
// Commented out right now as its not super clear how it works with inheritance. We'd
|
|
// probably want a codegen::check function that only does the checking without
|
|
// actually creating a Parameter objects
|
|
// codegen::bake<Parameters>(dictionary);
|
|
addProperty(_startRenderIdx);
|
|
addProperty(_sizeRender);
|
|
|
|
_updateStartRenderIdxSelect = [this]() {
|
|
if ((_numObjects - _startRenderIdx) < _sizeRender) {
|
|
_sizeRender = static_cast<unsigned int>(_numObjects - _startRenderIdx);
|
|
}
|
|
updateBuffers();
|
|
};
|
|
_updateRenderSizeSelect = [this]() {
|
|
if (_sizeRender > (_numObjects - _startRenderIdx)) {
|
|
_startRenderIdx = static_cast<unsigned int>(_numObjects - _sizeRender);
|
|
}
|
|
updateBuffers();
|
|
};
|
|
_startRenderIdxCallbackHandle = _startRenderIdx.onChange(_updateStartRenderIdxSelect);
|
|
_sizeRenderCallbackHandle = _sizeRender.onChange(_updateRenderSizeSelect);
|
|
}
|
|
|
|
void RenderableSatellites::readDataFile(const std::string& filename) {
|
|
if (!std::filesystem::is_regular_file(filename)) {
|
|
throw ghoul::RuntimeError(fmt::format(
|
|
"Satellite TLE file {} does not exist", filename
|
|
));
|
|
}
|
|
_data.clear();
|
|
_segmentSize.clear();
|
|
|
|
std::ifstream file;
|
|
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
|
file.open(filename);
|
|
|
|
std::streamoff numberOfLines = std::count(
|
|
std::istreambuf_iterator<char>(file),
|
|
std::istreambuf_iterator<char>(),
|
|
'\n'
|
|
);
|
|
file.seekg(std::ios_base::beg); // reset iterator to beginning of file
|
|
|
|
_numObjects = numberOfLines / nLineEntriesPerSatellite;
|
|
|
|
if (!_isFileReadinitialized) {
|
|
_isFileReadinitialized = true;
|
|
initializeFileReading();
|
|
}
|
|
|
|
std::string line = "-";
|
|
std::string name;
|
|
long long endElement = _startRenderIdx + _sizeRender - 1;
|
|
endElement = (endElement >= _numObjects) ? _numObjects - 1 : endElement;
|
|
//Burn lines if not starting at first element
|
|
for (unsigned int k = 0; k < _startRenderIdx; ++k) {
|
|
skipSingleEntryInFile(file);
|
|
}
|
|
for (std::streamoff i = _startRenderIdx; i <= endElement; i++) {
|
|
//Read title line
|
|
std::getline(file, name);
|
|
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
|
|
name += " " + line.substr(2, 15);
|
|
if (_startRenderIdx == i && _sizeRender == 1) {
|
|
LINFO(fmt::format(
|
|
"Set render block to start at object {}",
|
|
name
|
|
));
|
|
}
|
|
// 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 {} entry {} does not have '1' header", filename, i + 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 {} entry {} does not have '2' header", filename, i + 1
|
|
));
|
|
}
|
|
|
|
// 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);
|
|
_segmentSize.push_back(_segmentQuality * 16);
|
|
}
|
|
file.close();
|
|
}
|
|
|
|
void RenderableSatellites::initializeFileReading() {
|
|
_startRenderIdx.setMaxValue(static_cast<unsigned int>(_numObjects - 1));
|
|
_sizeRender.setMaxValue(static_cast<unsigned int>(_numObjects));
|
|
if (_sizeRender == 0u) {
|
|
_sizeRender = static_cast<unsigned int>(_numObjects);
|
|
}
|
|
}
|
|
|
|
void RenderableSatellites::skipSingleEntryInFile(std::ifstream& file) {
|
|
std::string line;
|
|
for (unsigned int i = 0; i < nLineEntriesPerSatellite; i++) {
|
|
std::getline(file, line);
|
|
}
|
|
}
|
|
|
|
}
|