From ea4907dc42c12adc712b62f1b13a12a6e09c7d57 Mon Sep 17 00:00:00 2001 From: Elon Date: Fri, 15 Mar 2019 16:17:34 -0600 Subject: [PATCH 1/8] include debris in default scene --- data/assets/default.scene | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/assets/default.scene b/data/assets/default.scene index 2217ee6832..bfb74fa01a 100644 --- a/data/assets/default.scene +++ b/data/assets/default.scene @@ -19,6 +19,8 @@ asset.require('util/webgui') asset.request('customization/globebrowsing') +asset.request('scene/solarsystem/planets/earth/satellites/satellites_debris') + -- Keybindings that are specific for this scene local Keybindings = { { From b360c116615912bc4abb7c62538b029642904a9b Mon Sep 17 00:00:00 2001 From: Jonathan Fransson Date: Mon, 18 Mar 2019 16:09:02 -0600 Subject: [PATCH 2/8] added spaceDebris scene --- .../earth/satellites/satellites_debris.asset | 6 +- data/assets/spaceDebris.scene | 110 ++++++++++++++++++ openspace.cfg | 3 +- 3 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 data/assets/spaceDebris.scene diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset index e4902c1725..56cbcf1fad 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset @@ -1,4 +1,4 @@ asset.request('./debris/debris_breezem') -asset.request('./debris/debris_fengyun') -asset.request('./debris/debris_iridium33') -asset.request('./debris/debris_kosmos2251') +--asset.request('./debris/debris_fengyun') +--asset.request('./debris/debris_iridium33') +--asset.request('./debris/debris_kosmos2251') diff --git a/data/assets/spaceDebris.scene b/data/assets/spaceDebris.scene new file mode 100644 index 0000000000..aa0cfec58c --- /dev/null +++ b/data/assets/spaceDebris.scene @@ -0,0 +1,110 @@ +local assetHelper = asset.require('util/asset_helper') +local sceneHelper = asset.require('util/scene_helper') +local propertyHelper = asset.require('util/property_helper') + +-- Specifying which other assets should be loaded in this scene +asset.require('spice/base') +assetHelper.requestAll(asset, 'scene/solarsystem/sun') +asset.require('scene/solarsystem/planets/earth') +assetHelper.requestAll(asset, 'scene/digitaluniverse') +-- Load default key bindings applicable to most scenes +asset.require('util/default_keybindings') +asset.require('util/default_dashboard') +asset.require('util/default_joystick') + +asset.require('util/webgui') + +asset.request('customization/globebrowsing') + +asset.request('scene/solarsystem/planets/earth/satellites/satellites_debris') + +-- Keybindings that are specific for this scene +local Keybindings = { + { + Key = "s", + Command = propertyHelper.invert('Scene.Earth.Renderable.Layers.NightLayers.Earth at Night 2012.Enabled') .. + propertyHelper.invert('Scene.Earth.Renderable.PerformShading') .. + propertyHelper.invert('Scene.Earth.Renderable.Atmosphere') .. + propertyHelper.invert('Scene.Earth.Renderable.Layers.WaterMasks.MODIS_Water_Mask.Enabled'), + Name = "Night for earth", + Documentation = "Toggle night texture, shading, atmosphere, and water for Earth.", + GuiPath = "/Rendering", + Local = false + }, + { + Key = "b", + Name = "Toggle background", + Command = propertyHelper.invert('Scene.MilkyWay.Renderable.Enabled') .. + propertyHelper.invert('Scene.Stars.Renderable.Enabled'), + Documentation = "Toggle background (Stars and Milkyway).", + GuiPath = "/Rendering", + Local = false + }, + { + Key = "g", + Name = "Toggle background/shading", + Command = propertyHelper.invert('Scene.MilkyWay.Renderable.Enabled') .. + propertyHelper.invert('Scene.Stars.Renderable.Enabled') .. + propertyHelper.invert('Scene.Earth.Renderable.Layers.NightLayers.Earth_at_Night_2012.Enabled') .. + propertyHelper.invert('Scene.EarthAtmosphere.Renderable.Enabled') .. + propertyHelper.invert('Scene.MarsAtmosphere.Renderable.Enabled') .. + propertyHelper.invert('Scene.Earth.Renderable.Layers.WaterMasks.MODIS_Water_Mask.Enabled') .. + propertyHelper.invert('Scene.Moon.Renderable.Enabled') .. + propertyHelper.invert('Scene.Sun.Renderable.Enabled'), + Documentation = "Toogles background and shading mode on the Earth and Mars alongside visibility of the Moon and the Sun", + GuiPath = "/Rendering", + Local = false + }, + { + Key = "h", + Name="Hide Trails", + Command = "openspace.setPropertyValue('Scene.*Trail.Renderable.Enabled', false)", + Documentation = "Disables visibility of the trails", + GuiPath = "/Rendering", + Local = false + }, +} + +local earthAsset = asset.require('scene/solarsystem/planets/earth/earth') + +assetHelper.registerInterestingNodes(asset, { + "Earth", "Mars", "Moon", "Sun" +}) + +asset.onInitialize(function () + local now = openspace.time.currentWallTime() + -- Jump back one day to show a complete planet + openspace.time.setTime(openspace.time.advancedTime(now, "-1d")) + + sceneHelper.bindKeys(Keybindings) + + openspace.setDefaultGuiSorting() + + openspace.globebrowsing.loadWMSServersFromFile( + openspace.absPath("${DATA}/globebrowsing_servers.lua") + ) + + openspace.addVirtualProperty( + "BoolProperty", + "Show Trails", + "Scene.*Trail.Renderable.Enabled", + "Disable or enable all trails of the scene at the same time", + true, + nil, + nil + ) + + openspace.navigation.setCameraState({ + Anchor = earthAsset.Earth.Identifier, + Position = { 0, 0, 0 }, + Rotation = { 0.758797, 0.221490, -0.605693, -0.091135 }, + }) + + openspace.globebrowsing.goToGeo(58.5877, 16.1924, 20000000) +end) + +asset.onDeinitialize(function () + sceneHelper.unbindKeys(Keybindings) + + openspace.removeVirtualProperty("*Trail.Renderable.Enabled") +end) diff --git a/openspace.cfg b/openspace.cfg index 58e0446fca..2f8a59042c 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -37,7 +37,8 @@ SGCTConfig = sgct.config.single{} -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace -Asset = "default" +Asset = "spaceDebris" +-- Asset = "default" -- Asset = "default_full" -- Asset = "newhorizons" -- Asset = "rosetta" From cdf4a118487f1825d27eab19eb1389824003be5d Mon Sep 17 00:00:00 2001 From: Jonathan Fransson Date: Fri, 22 Mar 2019 10:53:35 -0600 Subject: [PATCH 3/8] scene setup --- data/assets/spaceDebris.scene | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/assets/spaceDebris.scene b/data/assets/spaceDebris.scene index aa0cfec58c..12e29d1510 100644 --- a/data/assets/spaceDebris.scene +++ b/data/assets/spaceDebris.scene @@ -5,7 +5,7 @@ local propertyHelper = asset.require('util/property_helper') -- Specifying which other assets should be loaded in this scene asset.require('spice/base') assetHelper.requestAll(asset, 'scene/solarsystem/sun') -asset.require('scene/solarsystem/planets/earth') +asset.require('scene/solarsystem/planets/earth/earth') assetHelper.requestAll(asset, 'scene/digitaluniverse') -- Load default key bindings applicable to most scenes asset.require('util/default_keybindings') @@ -14,7 +14,7 @@ asset.require('util/default_joystick') asset.require('util/webgui') -asset.request('customization/globebrowsing') +--asset.request('customization/globebrowsing') asset.request('scene/solarsystem/planets/earth/satellites/satellites_debris') From 95f1c5d2e7aaf434308406dfaa4603ff01a54b25 Mon Sep 17 00:00:00 2001 From: Elon Date: Fri, 22 Mar 2019 10:54:14 -0600 Subject: [PATCH 4/8] some code to test 1 sgn, more renderables --- .../satellites/debris/debris_breezem.asset | 2 +- .../satellites/debris/debris_fengyun.asset | 2 +- .../satellites/debris/debris_iridium33.asset | 2 +- .../satellites/debris/debris_kosmos2251.asset | 2 +- .../earth/satellites/satellites_debris.asset | 6 +- .../earth/satellites/satellites_shared.asset | 130 +-- data/assets/spaceDebris.scene | 1 + .../space/rendering/renderablesatellites.cpp | 740 ++++++++++++++++++ .../space/rendering/renderablesatellites.h | 119 +++ 9 files changed, 949 insertions(+), 55 deletions(-) create mode 100644 modules/space/rendering/renderablesatellites.cpp create mode 100644 modules/space/rendering/renderablesatellites.h diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_breezem.asset b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_breezem.asset index 755dbdc921..3b66226113 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_breezem.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_breezem.asset @@ -4,7 +4,7 @@ local shared = asset.require('../satellites_shared') local group = { Title = "Breeze-M Breakup", Url = "http://www.celestrak.com/NORAD/elements/2012-044.txt", - TrailColor = { 0.25, 0.35, 0.45 } + TrailColor = { 1.0, 0.98, 0.984 } } local tle = shared.downloadTLEFile(asset, group.Url, group.Title) diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_fengyun.asset b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_fengyun.asset index e7d80fa019..91bc094e67 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_fengyun.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_fengyun.asset @@ -4,7 +4,7 @@ local shared = asset.require('../satellites_shared') local group = { Title = "Fengyun Debris", Url = "http://www.celestrak.com/NORAD/elements/1999-025.txt", - TrailColor = { 0.25, 0.35, 0.45 } + TrailColor = { 0.784, 1.0, 0.737 } } local tle = shared.downloadTLEFile(asset, group.Url, group.Title) diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_iridium33.asset b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_iridium33.asset index 603d15b12b..6004054538 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_iridium33.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_iridium33.asset @@ -4,7 +4,7 @@ local shared = asset.require('../satellites_shared') local group = { Title = "Iridium 33 Debris", Url = "http://www.celestrak.com/NORAD/elements/iridium-33-debris.txt", - TrailColor = { 0.25, 0.35, 0.45 } + TrailColor = { 0.8, 0.0, 0.3 } } local tle = shared.downloadTLEFile(asset, group.Url, group.Title) diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_kosmos2251.asset b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_kosmos2251.asset index 847047bf67..2aa4c8dd1c 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_kosmos2251.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/debris/debris_kosmos2251.asset @@ -4,7 +4,7 @@ local shared = asset.require('../satellites_shared') local group = { Title = "Kosmos 2251 Debris", Url = "http://www.celestrak.com/NORAD/elements/cosmos-2251-debris.txt", - TrailColor = { 0.25, 0.35, 0.45 } + TrailColor = { 0.66, 0.8, 0.5 } } local tle = shared.downloadTLEFile(asset, group.Url, group.Title) diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset index 56cbcf1fad..8a27daa6b9 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_debris.asset @@ -1,4 +1,4 @@ asset.request('./debris/debris_breezem') ---asset.request('./debris/debris_fengyun') ---asset.request('./debris/debris_iridium33') ---asset.request('./debris/debris_kosmos2251') +-- asset.request('./debris/debris_fengyun') +asset.request('./debris/debris_iridium33') +asset.request('./debris/debris_kosmos2251') diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset index 7bd1566701..1b5e241edd 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset @@ -42,64 +42,94 @@ local addSatelliteGroupObjects = function(group, tleFolder, shouldAddDuplicates) end return true end +-- ------------------------------------------------------------------------------------- +-- function getSat(title, file, lineNum, textureFile, group) +-- return { +-- Identifier = title, +-- Parent = transforms.EarthInertial.Identifier, +-- Renderable = { +-- Type = "RenderablePlaneImageLocal", +-- Enabled = true, +-- Size = 3e4, +-- Origin = "Center", +-- Body = "TLE", +-- Billboard = true, +-- Texture = textureFile +-- }, +-- Transform = { +-- Translation = { +-- Type = "TLETranslation", +-- Body = title, +-- Observer = transforms.EarthInertial.Identifier, +-- File = file, +-- LineNumber = lineNum +-- }, +-- Scale = { +-- Type = "StaticScale", +-- Scale = 1 +-- } +-- }, +-- Tag = { "earth_satellite_" .. group, "earth_satellite_" .. group .. "_marker" }, +-- GUI = { +-- Path = "/Solar System/Planets/Earth/Satellites" +-- } +-- } +-- end - function getSat(title, file, lineNum, textureFile, group) +-- function getSatTrail(title, file, lineNum, per, color, group) +-- return { +-- Identifier = title .. "_trail", +-- Parent = transforms.EarthInertial.Identifier, +-- Renderable = { +-- Type = "RenderableTrailOrbit", +-- Translation = { +-- Type = "TLETranslation", +-- Body = title, +-- Observer = transforms.EarthInertial.Identifier, +-- File = file, +-- LineNumber = lineNum +-- }, +-- Color = color, +-- Period = per, +-- Resolution = 160 +-- }, +-- Tag = { "earth_satellite_" .. group, "earth_satellite_" .. group .. "_trail"}, +-- GUI = { +-- Path = "/Solar System/Planets/Earth/Satellites" +-- } +-- } +-- end +-- ------------------------------------------------------------------------------------- + function test(title, file, lineNum, per, color, group) return { Identifier = title, Parent = transforms.EarthInertial.Identifier, Renderable = { - Type = "RenderablePlaneImageLocal", - Enabled = false, + Type = "RenderableSatellite", + Color = color, + Period = per, + Resolution = 160, + Translation = { + Type = "TLETranslation", + Body = title, + Observer = transforms.EarthInertial.Identifier, + File = file, + LineNumber = lineNum + }, + Size = 3e4, Origin = "Center", Body = "TLE", Billboard = true, Texture = textureFile + }, - Transform = { - Translation = { - Type = "TLETranslation", - Body = title, - Observer = transforms.EarthInertial.Identifier, - File = file, - LineNumber = lineNum - }, - Scale = { - Type = "StaticScale", - Scale = 1 - } - }, - Tag = { "earth_satellite_" .. group, "earth_satellite_" .. group .. "_marker" }, GUI = { Path = "/Solar System/Planets/Earth/Satellites" } } end - - function getSatTrail(title, file, lineNum, per, color, group) - return { - Identifier = title .. "_trail", - Parent = transforms.EarthInertial.Identifier, - Renderable = { - Type = "RenderableTrailOrbit", - Translation = { - Type = "TLETranslation", - Body = title, - Observer = transforms.EarthInertial.Identifier, - File = file, - LineNumber = lineNum - }, - Color = color, - Period = per, - Resolution = 160 - }, - Tag = { "earth_satellite_" .. group, "earth_satellite_" .. group .. "_trail"}, - GUI = { - Path = "/Solar System/Planets/Earth/Satellites" - } - } - end - +-- ------------------------------------------------------------------------------------- local filename = group.Url:match("([^/]+)$") local filenameSansExt = filename:gsub(filename:match("(%.%w+)$"), "") @@ -151,13 +181,17 @@ local addSatelliteGroupObjects = function(group, tleFolder, shouldAddDuplicates) if shouldAddNotes then -- Register satellite object and trail - local sat_var = getSat(satName, path, n, texture, group.Title) - openspace.addSceneGraphNode(sat_var) - table.insert(obj, sat_var.Identifier) + local test_var = test(satName, path, n, per, group.TrailColor, group.Title) + openspace.addSceneGraphNode(test_var) + table.insert(obj, test_var.Identifier) - local satTrail_var = getSatTrail(satName, path, n, per, group.TrailColor, group.Title) - openspace.addSceneGraphNode(satTrail_var) - table.insert(obj, satTrail_var.Identifier) +-- local sat_var = getSat(satName, path, n, texture, group.Title) +-- openspace.addSceneGraphNode(sat_var) +-- table.insert(obj, sat_var.Identifier) + +-- local satTrail_var = getSatTrail(satName, path, n, per, group.TrailColor, group.Title) +-- openspace.addSceneGraphNode(satTrail_var) +-- table.insert(obj, satTrail_var.Identifier) end end diff --git a/data/assets/spaceDebris.scene b/data/assets/spaceDebris.scene index aa0cfec58c..d42ad574bf 100644 --- a/data/assets/spaceDebris.scene +++ b/data/assets/spaceDebris.scene @@ -16,6 +16,7 @@ asset.require('util/webgui') asset.request('customization/globebrowsing') +-- asset.request('scene/solarsystem/planets/earth/satellites/satellites_all') asset.request('scene/solarsystem/planets/earth/satellites/satellites_debris') -- Keybindings that are specific for this scene diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp new file mode 100644 index 0000000000..626faeca35 --- /dev/null +++ b/modules/space/rendering/renderablesatellites.cpp @@ -0,0 +1,740 @@ +/**************************************************************************************** + * * + * 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 + +#include + +#include +#include +#include +#include +#include + +#include +#include + +// Todo: +// Parse epoch correctly +// read distances using correct unit +// ... + +namespace { + constexpr const char* ProgramName = "KeplerTrails"; + constexpr const char* KeyFile = "File"; + constexpr const char* KeyLineNumber = "LineNumber"; + + + static const openspace::properties::Property::PropertyInfo PathInfo = { + "Path", + "Path", + "The file path to the CSV file to read" + }; + + static const openspace::properties::Property::PropertyInfo SegmentsInfo = { + "Segments", + "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" + }; +} + +namespace openspace { + +documentation::Documentation RenderableSatellites::Documentation() { + using namespace documentation; + return { + "Renderable Kepler Orbits", + "space_renderable_kepler_orbits", + { + { + SegmentsInfo.identifier, + new DoubleVerifier, + Optional::No, + SegmentsInfo.description + }, + { + PathInfo.identifier, + new StringVerifier, + 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 + } + } + }; +} + +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) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableSatellites" + ); + + _nSegments = + static_cast(dictionary.value(SegmentsInfo.identifier)); + _path = + dictionary.value(PathInfo.identifier); + _eccentricityColumnName = + dictionary.value(EccentricityColumnInfo.identifier); + _semiMajorAxisColumnName = + dictionary.value(SemiMajorAxisColumnInfo.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); + _semiMajorAxisUnit = + dictionary.value(SemiMajorAxisUnitInfo.identifier); + + addPropertySubOwner(_appearance); + addProperty(_path); + addProperty(_nSegments); + addProperty(_semiMajorAxisUnit); + +/* +* test +*/ + + const std::string& file = dictionary.value(KeyLineNumber) { + lineNumber = static_cast(dictionary.value(KeyLineNumber)); + } + readTLEFile(file, lineNumber); + +} + +void RenderableSatellites::readTLEFile(const std::string& filename, int lineNumber){ + ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); + + std::ifstream file; + file.exceptions(std::ofstream::failbit | std::ofstream::badbit); + file.open(filename); + + // All of the Kepler element information + struct { + double inclination = 0.0; + double semiMajorAxis = 0.0; + double ascendingNode = 0.0; + double eccentricity = 0.0; + double argumentOfPeriapsis = 0.0; + double meanAnomaly = 0.0; + double meanMotion = 0.0; + double epoch = 0.0; + } keplerElements; + + std::string line; + // Loop through and throw out lines until getting to the linNum of interest + for (int i = 1; i < lineNum; ++i) { + std::getline(file, line); + } + std::getline(file, line); // Throw out the TLE title line (1st) + + std::getline(file, line); // Get line 1 of TLE format + 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, lineNum + 1 + )); + } + + std::getline(file, line); // Get line 2 of TLE format + 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 + )); + } + file.close(); + + // Calculate the semi major axis based on the mean motion using kepler's laws + keplerElements.semiMajorAxis = calculateSemiMajorAxis(keplerElements.meanMotion); + + // Converting the mean motion (revolutions per day) to period (seconds per revolution) + using namespace std::chrono; + double period = seconds(hours(24)).count() / keplerElements.meanMotion; + + setKeplerElements( + keplerElements.eccentricity, + keplerElements.semiMajorAxis, + keplerElements.inclination, + keplerElements.ascendingNode, + keplerElements.argumentOfPeriapsis, + keplerElements.meanAnomaly, + period, + keplerElements.epoch + ); + +} + +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; + } + + // 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; + } +/* +* !test +*/ +RenderableSatellites::~RenderableSatellites() { + +} + +void RenderableSatellites::initialize() { + readFromCsvFile(); + updateBuffers(); + + _path.onChange([this]() { + readFromCsvFile(); + updateBuffers(); + }); + + _semiMajorAxisUnit.onChange([this]() { + readFromCsvFile(); + updateBuffers(); + }); + + _nSegments.onChange([this]() { + updateBuffers(); + }); +} + +void RenderableSatellites::deinitialize() { + +} + +void RenderableSatellites::initializeGL() { + glGenVertexArrays(1, &_vertexArray); + glGenBuffers(1, &_vertexBuffer); + glGenBuffers(1, &_indexBuffer); + + _programObject = BaseModule::ProgramObjectManager.requestProgramObject( + ProgramName, + []() -> std::unique_ptr { + return OsEng.renderEngine().buildRenderProgram( + ProgramName, + absPath("${MODULE_SPACE}/shaders/RenderableKeplerOrbits_vs.glsl"), + absPath("${MODULE_SPACE}/shaders/RenderableKeplerOrbits_fs.glsl") + ); + } + ); + + _uniformCache.opacity = _programObject->uniformLocation("opacity"); + _uniformCache.modelView = _programObject->uniformLocation("modelViewTransform"); + _uniformCache.projection = _programObject->uniformLocation("projectionTransform"); + _uniformCache.color = _programObject->uniformLocation("color"); + _uniformCache.useLineFade = _programObject->uniformLocation("useLineFade"); + _uniformCache.lineFade = _programObject->uniformLocation("lineFade"); + + setRenderBin(Renderable::RenderBin::Overlay); +} + +void RenderableSatellites::deinitializeGL() { + BaseModule::ProgramObjectManager.releaseProgramObject(ProgramName); + + glDeleteBuffers(1, &_vertexBuffer); + glDeleteBuffers(1, &_indexBuffer); + glDeleteVertexArrays(1, &_vertexArray); +} + + +bool RenderableSatellites::isReady() const { + return true; +} + +void RenderableSatellites::update(const UpdateData&) {} + +void RenderableSatellites::render(const RenderData& data, RendererTasks&) { + _programObject->activate(); + _programObject->setUniform(_uniformCache.opacity, _opacity); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + _programObject->setUniform( + _uniformCache.modelView, + data.camera.combinedViewMatrix() * modelTransform + ); + + _programObject->setUniform(_uniformCache.projection, data.camera.projectionMatrix()); + _programObject->setUniform(_uniformCache.color, _appearance.lineColor); + //_programObject->setUniform(_uniformCache.useLineFade, _appearance.useLineFade); + + /*if (_appearance.useLineFade) { + _programObject->setUniform(_uniformCache.lineFade, _appearance.lineFade); + }*/ + + glDepthMask(false); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + glBindVertexArray(_vertexArray); + glDrawElements(GL_LINES, + static_cast(_indexBufferData.size()), + GL_UNSIGNED_INT, + 0); + glBindVertexArray(0); + _programObject->deactivate(); +} + +void RenderableSatellites::updateBuffers() { + const size_t nVerticesPerOrbit = _nSegments + 1; + _vertexBufferData.resize(_orbits.size() * nVerticesPerOrbit); + _indexBufferData.resize(_orbits.size() * _nSegments * 2); + + size_t orbitIndex = 0; + size_t elementIndex = 0; + for (const auto& orbit : _orbits) { + KeplerTranslation keplerTranslation(orbit); + const double period = orbit.period(); + for (size_t i = 0; i <= _nSegments; ++i) { + size_t index = orbitIndex * nVerticesPerOrbit + i; + + double timeOffset = period * + static_cast(i) / static_cast(_nSegments); + glm::vec3 position = + keplerTranslation.position(Time(orbit.epoch + timeOffset)); + + _vertexBufferData[index].x = position.x; + _vertexBufferData[index].y = position.y; + _vertexBufferData[index].z = position.z; + _vertexBufferData[index].time = timeOffset; + if (i > 0) { + _indexBufferData[elementIndex++] = static_cast(index) - 1; + _indexBufferData[elementIndex++] = static_cast(index); + } + } + ++orbitIndex; + } + + glBindVertexArray(_vertexArray); + + glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, + _vertexBufferData.size() * sizeof(TrailVBOLayout), + _vertexBufferData.data(), + GL_STATIC_DRAW + ); + + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + _indexBufferData.size() * sizeof(int), + _indexBufferData.data(), + GL_STATIC_DRAW + ); + + glBindVertexArray(0); +} + +void RenderableSatellites::readFromCsvFile() { + std::vector columns = { + _eccentricityColumnName, + _semiMajorAxisColumnName, + _inclinationColumnName, + _ascendingNodeColumnName, + _argumentOfPeriapsisColumnName, + _meanAnomalyAtEpochColumnName, + _epochColumnName, + }; + + std::vector> data = + ghoul::loadCSVFile(_path, columns, false); + + _orbits.resize(data.size()); + + size_t i = 0; + for (const std::vector& line : data) { + _orbits[i++] = KeplerTranslation::KeplerOrbit{ + std::stof(line[0]), + _semiMajorAxisUnit * std::stof(line[1]) / 1000.0, + std::stof(line[2]), + std::stof(line[3]), + std::stof(line[4]), + std::stof(line[5]), + std::stof(line[6]) + }; + } +} + +} \ No newline at end of file diff --git a/modules/space/rendering/renderablesatellites.h b/modules/space/rendering/renderablesatellites.h new file mode 100644 index 0000000000..e9e3dae852 --- /dev/null +++ b/modules/space/rendering/renderablesatellites.h @@ -0,0 +1,119 @@ +/**************************************************************************************** + * * + * 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 + +#include +#include + +#include +#include +#include + +#include + +#ifndef __OPENSPACE_MODULE_BASE___RenderableSatellites___H__ +#define __OPENSPACE_MODULE_BASE___RenderableSatellites___H__ + +namespace openspace { + +class RenderableSatellites : public Renderable { +public: + RenderableSatellites(const ghoul::Dictionary& dictionary); + virtual ~RenderableSatellites(); + + void initialize() override; + void deinitialize() override; + void initializeGL() override; + void deinitializeGL() override; + + bool isReady() const override; + + void render(const RenderData& data, RendererTasks& rendererTask) override; + void update(const UpdateData& data) override; + + static documentation::Documentation Documentation(); + +private: + /// The layout of the VBOs + struct TrailVBOLayout { + float x, y, z, time; + }; + + /// The backend storage for the vertex buffer object containing all points for this + /// trail. + std::vector _vertexBufferData; + + /// The index array that is potentially used in the draw call. If this is empty, no + /// element draw call is used. + std::vector _indexBufferData; + + GLuint _vertexArray; + GLuint _vertexBuffer; + GLuint _indexBuffer; + + void readFromCsvFile(); + void updateBuffers(); + + std::vector _orbits; + ghoul::opengl::ProgramObject* _programObject; + + 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; + + RenderableTrail::Appearance _appearance; + + UniformCache(opacity, modelView, projection, color, useLineFade, lineFade) + _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, int lineNum); +}; + +#endif // __OPENSPACE_MODULE_BASE___RenderableSatellites___H__ + +} \ No newline at end of file From 31b1f7ea9add2e411d127e55959aeba6096bb8d4 Mon Sep 17 00:00:00 2001 From: Elon Date: Mon, 25 Mar 2019 14:34:56 -0600 Subject: [PATCH 5/8] appearance --- modules/base/rendering/renderabletrail.cpp | 83 +++++++++++++------ modules/base/rendering/renderabletrail.h | 22 +++++ modules/space/CMakeLists.txt | 6 +- .../space/rendering/renderablesatellites.cpp | 6 +- .../space/rendering/renderablesatellites.h | 2 +- .../shaders/renderablekeplerorbits_fs.glsl | 46 ++++++++++ .../shaders/renderablekeplerorbits_vs.glsl | 44 ++++++++++ modules/space/translation/keplertranslation.h | 21 +++++ 8 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 modules/space/shaders/renderablekeplerorbits_fs.glsl create mode 100644 modules/space/shaders/renderablekeplerorbits_vs.glsl diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index 7d2c7aba4f..5736c7033e 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -59,6 +59,13 @@ namespace { { "Points+Lines", RenderingModeLinesPoints } }; + static const openspace::properties::PropertyOwner::PropertyOwnerInfo + AppearanceInfo = { + "Appearance", + "Appearance", + "The appearance of the trail." + }; + constexpr openspace::properties::Property::PropertyInfo LineColorInfo = { "Color", "Color", @@ -166,8 +173,35 @@ documentation::Documentation RenderableTrail::Documentation() { }; } +RenderableTrail::Appearance::Appearance() + : properties::PropertyOwner(AppearanceInfo) + , lineColor(LineColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) + , useLineFade(EnableFadeInfo, true) + , lineFade(FadeInfo, 1.f, 0.f, 30.f) + , lineWidth(LineWidthInfo, 2.f, 1.f, 20.f) + , pointSize(PointSizeInfo, 1, 1, 64) + , renderingModes( + RenderingModeInfo, + properties::OptionProperty::DisplayType::Dropdown + ) +{ + renderingModes.addOptions({ + { RenderingModeLines, "Lines" }, + { RenderingModePoints, "Points" }, + { RenderingModeLinesPoints, "Lines+Points" } + }); + + addProperty(lineColor); + addProperty(useLineFade); + addProperty(lineFade); + addProperty(lineWidth); + addProperty(pointSize); + addProperty(renderingModes); +} + RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary) : Renderable(dictionary) + /* , _lineColor(LineColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) , _useLineFade(EnableFadeInfo, true) , _lineFade(FadeInfo, 1.f, 0.f, 30.f) @@ -177,6 +211,7 @@ RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary) RenderingModeInfo, properties::OptionProperty::DisplayType::Dropdown ) + */ { addProperty(_opacity); registerUpdateRenderBinFromOpacity(); @@ -186,32 +221,32 @@ RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary) ); addPropertySubOwner(_translation.get()); - _lineColor = dictionary.value(LineColorInfo.identifier); - addProperty(_lineColor); + _appearance.lineColor = dictionary.value(LineColorInfo.identifier); + addProperty(_appearance.lineColor); if (dictionary.hasKeyAndValue(EnableFadeInfo.identifier)) { - _useLineFade = dictionary.value(EnableFadeInfo.identifier); + _appearance.useLineFade = dictionary.value(EnableFadeInfo.identifier); } - addProperty(_useLineFade); + addProperty(_appearance.useLineFade); if (dictionary.hasKeyAndValue(FadeInfo.identifier)) { - _lineFade = static_cast(dictionary.value(FadeInfo.identifier)); + _appearance.lineFade = static_cast(dictionary.value(FadeInfo.identifier)); } - addProperty(_lineFade); + addProperty(_appearance.lineFade); if (dictionary.hasKeyAndValue(LineWidthInfo.identifier)) { - _lineWidth = static_cast(dictionary.value( + _appearance.lineWidth = static_cast(dictionary.value( LineWidthInfo.identifier )); } - addProperty(_lineWidth); + addProperty(_appearance.lineWidth); if (dictionary.hasKeyAndValue(PointSizeInfo.identifier)) { - _pointSize = static_cast(dictionary.value(PointSizeInfo.identifier)); + _appearance.pointSize = static_cast(dictionary.value(PointSizeInfo.identifier)); } - addProperty(_pointSize); + addProperty(_appearance.pointSize); - _renderingModes.addOptions({ + _appearance.renderingModes.addOptions({ { RenderingModeLines, "Lines" }, { RenderingModePoints, "Points" }, { RenderingModeLinesPoints, "Lines+Points" } @@ -220,14 +255,14 @@ RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary) // This map is not accessed out of order as long as the Documentation is adapted // whenever the map changes. The documentation will check for valid values if (dictionary.hasKeyAndValue(RenderingModeInfo.identifier)) { - _renderingModes = RenderingModeConversion.at( + _appearance.renderingModes = RenderingModeConversion.at( dictionary.value(RenderingModeInfo.identifier) ); } else { - _renderingModes = RenderingModeLines; + _appearance.renderingModes = RenderingModeLines; } - addProperty(_renderingModes); + addProperty(_appearance.renderingModes); } void RenderableTrail::initializeGL() { @@ -272,10 +307,10 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) { _programObject->setUniform(_uniformCache.projection, data.camera.projectionMatrix()); - _programObject->setUniform(_uniformCache.color, _lineColor); - _programObject->setUniform(_uniformCache.useLineFade, _useLineFade); - if (_useLineFade) { - _programObject->setUniform(_uniformCache.lineFade, _lineFade); + _programObject->setUniform(_uniformCache.color, _appearance.lineColor); + _programObject->setUniform(_uniformCache.useLineFade, _appearance.useLineFade); + if (_appearance.useLineFade) { + _programObject->setUniform(_uniformCache.lineFade, _appearance.lineFade); } static std::map SortingMapping = { @@ -294,21 +329,21 @@ void RenderableTrail::render(const RenderData& data, RendererTasks&) { //glBlendFunc(GL_SRC_ALPHA, GL_ONE); } - const bool renderLines = (_renderingModes == RenderingModeLines) | - (_renderingModes == RenderingModeLinesPoints); + const bool renderLines = (_appearance.renderingModes == RenderingModeLines) | + (_appearance.renderingModes == RenderingModeLinesPoints); - const bool renderPoints = (_renderingModes == RenderingModePoints) | - (_renderingModes == RenderingModeLinesPoints); + const bool renderPoints = (_appearance.renderingModes == RenderingModePoints) | + (_appearance.renderingModes == RenderingModeLinesPoints); if (renderLines) { - glLineWidth(_lineWidth); + glLineWidth(_appearance.lineWidth); } if (renderPoints) { glEnable(GL_PROGRAM_POINT_SIZE); } auto render = [renderLines, renderPoints, p = _programObject, &data, - &modelTransform, pointSize = _pointSize.value(), c = _uniformCache] + &modelTransform, pointSize = _appearance.pointSize.value(), c = _uniformCache] (RenderInformation& info, int nVertices, int offset) { // We pass in the model view transformation matrix as double in order to maintain diff --git a/modules/base/rendering/renderabletrail.h b/modules/base/rendering/renderabletrail.h index a12813832c..e3db456fa5 100644 --- a/modules/base/rendering/renderabletrail.h +++ b/modules/base/rendering/renderabletrail.h @@ -71,6 +71,23 @@ class Translation; */ class RenderableTrail : public Renderable { public: + +struct Appearance : properties::PropertyOwner { + Appearance(); + /// Specifies the base color of the line before fading + properties::Vec3Property lineColor; + /// Settings that enables or disables the line fading + properties::BoolProperty useLineFade; + /// Specifies a multiplicative factor that fades out the line + properties::FloatProperty lineFade; + /// Line width for the line rendering part + properties::FloatProperty lineWidth; + /// Point size for the point rendering part + properties::IntProperty pointSize; + /// The option determining which rendering method to use + properties::OptionProperty renderingModes; + }; + ~RenderableTrail() = default; void initializeGL() override; @@ -143,6 +160,8 @@ protected: RenderInformation _floatingRenderInformation; private: + +/* /// Specifies the base color of the line before fading properties::Vec3Property _lineColor; /// Settings that enables or disables the line fading @@ -156,6 +175,9 @@ private: /// The option determining which rendering method to use properties::OptionProperty _renderingModes; + */ + Appearance _appearance; + /// Program object used to render the data stored in RenderInformation ghoul::opengl::ProgramObject* _programObject = nullptr; diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index d17204258a..2e363159d5 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableplanet.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablerings.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablestars.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/simplespheregeometry.h @@ -41,8 +42,9 @@ source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableplanet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablerings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablestars.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/simplespheregeometry.cpp @@ -59,6 +61,8 @@ set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/constellationbounds_vs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/nighttexture_fs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/nighttexture_vs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/renderablekeplerorbits_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/renderablekeplerorbits_vs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/renderableplanet_fs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/renderableplanet_vs.glsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_vs.glsl diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index 626faeca35..9a341e9062 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -228,16 +228,16 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) * test */ - const std::string& file = dictionary.value(KeyFile); int lineNumber = 1; - if (dictionary.hasKeyAndValue)(KeyLineNumber) { + if (dictionary.hasKeyAndValue(KeyLineNumber)) { lineNumber = static_cast(dictionary.value(KeyLineNumber)); } readTLEFile(file, lineNumber); } -void RenderableSatellites::readTLEFile(const std::string& filename, int lineNumber){ +void RenderableSatellites::readTLEFile(const std::string& filename, int lineNum){ ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); std::ifstream file; diff --git a/modules/space/rendering/renderablesatellites.h b/modules/space/rendering/renderablesatellites.h index e9e3dae852..562648d2cd 100644 --- a/modules/space/rendering/renderablesatellites.h +++ b/modules/space/rendering/renderablesatellites.h @@ -27,7 +27,7 @@ #include #include -#include +// #include #include #include diff --git a/modules/space/shaders/renderablekeplerorbits_fs.glsl b/modules/space/shaders/renderablekeplerorbits_fs.glsl new file mode 100644 index 0000000000..cf095fb168 --- /dev/null +++ b/modules/space/shaders/renderablekeplerorbits_fs.glsl @@ -0,0 +1,46 @@ +/***************************************************************************************** + * * + * 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 "fragment.glsl" +#include "floatoperations.glsl" + +uniform vec3 color; +uniform float opacity = 1.0; +uniform bool useLineFade; +uniform float lineFade; + +in vec4 viewSpacePosition; + +Fragment getFragment() { + Fragment frag; + frag.color = vec4(color, opacity); + frag.depth = safeLength(viewSpacePosition); + frag.blend = BLEND_MODE_ADDITIVE; + frag.gPosition = viewSpacePosition; + + // There is no normal here + frag.gNormal = vec4(0.0, 0.0, -1.0, 1.0); + + return frag; +} \ No newline at end of file diff --git a/modules/space/shaders/renderablekeplerorbits_vs.glsl b/modules/space/shaders/renderablekeplerorbits_vs.glsl new file mode 100644 index 0000000000..9640dea8aa --- /dev/null +++ b/modules/space/shaders/renderablekeplerorbits_vs.glsl @@ -0,0 +1,44 @@ +/***************************************************************************************** + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout(location = 0) in vec4 vertexData; + +uniform dmat4 modelViewTransform; +uniform mat4 projectionTransform; +uniform bool useLineFade; +uniform float lineFade; +uniform int vertexSortingMethod; +uniform int pointSize; + +out vec4 viewSpacePosition; + +void main() { + dvec4 position = dvec4(vertexData.xyz, 1.0); + float timeOffset = vertexData.w; + + viewSpacePosition = vec4(modelViewTransform * position); + gl_Position = projectionTransform * viewSpacePosition; +} \ No newline at end of file diff --git a/modules/space/translation/keplertranslation.h b/modules/space/translation/keplertranslation.h index 5c9407eabc..85b4bf5453 100644 --- a/modules/space/translation/keplertranslation.h +++ b/modules/space/translation/keplertranslation.h @@ -47,6 +47,27 @@ public: std::string offender; }; + struct KeplerOrbit { + /// The period of the orbit in seconds + double period() const; + /// The eccentricity of the orbit in [0, 1) + double eccentricity; + /// The semi-major axis in km + double semiMajorAxis; + /// The inclination of the orbit in [0, 360] + double inclination; + /// The right ascension of the ascending node in [0, 360] + double ascendingNode; + /// The argument of periapsis in [0, 360] + double argumentOfPeriapsis; + /// The mean anomaly at the epoch in [0, 360] + double meanAnomalyAtEpoch; + /// The epoch in seconds relative to the J2000 epoch + double epoch; + /// The mass of the more massive body + double massiveBodyMass = 1.989E30; // Sun's mass in kg + }; + /** * The constructor that retrieves the required Keplerian elements from the passed * \p dictionary. These values are then apssed to the setKeplerElements method for From 7b33d9e9a628ac57dc4d2b782e4eb2ea3cfb33d7 Mon Sep 17 00:00:00 2001 From: Jonathan Fransson Date: Mon, 25 Mar 2019 14:37:10 -0600 Subject: [PATCH 6/8] merge --- modules/space/CMakeLists.txt | 3 +++ modules/space/rendering/renderablesatellites.cpp | 14 +++++++------- modules/space/rendering/renderablesatellites.h | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index d17204258a..dc2f0f7e79 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -25,6 +25,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES + ${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 @@ -36,10 +37,12 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/translation/tletranslation.h ${CMAKE_CURRENT_SOURCE_DIR}/translation/horizonstranslation.h ${CMAKE_CURRENT_SOURCE_DIR}/rotation/spicerotation.h + ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES + ${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 diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index 626faeca35..26c2d4ac83 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -228,16 +228,16 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) * test */ - const std::string& file = dictionary.value(KeyLineNumber) { - lineNumber = static_cast(dictionary.value(KeyLineNumber)); + const std::string& file = dictionary.value(KeyLineNum) { + lineNum = static_cast(dictionary.value(KeyLineNum)); } - readTLEFile(file, lineNumber); + readTLEFile(file, lineNum); } -void RenderableSatellites::readTLEFile(const std::string& filename, int lineNumber){ +void RenderableSatellites::readTLEFile(const std::string& filename, int lineNum){ ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); std::ifstream file; @@ -737,4 +737,4 @@ void RenderableSatellites::readFromCsvFile() { } } -} \ No newline at end of file +} diff --git a/modules/space/rendering/renderablesatellites.h b/modules/space/rendering/renderablesatellites.h index e9e3dae852..0eb815a630 100644 --- a/modules/space/rendering/renderablesatellites.h +++ b/modules/space/rendering/renderablesatellites.h @@ -27,7 +27,7 @@ #include #include -#include +//#include #include #include @@ -116,4 +116,4 @@ private: #endif // __OPENSPACE_MODULE_BASE___RenderableSatellites___H__ -} \ No newline at end of file +} From 219b69c4ea7bc83c806c35a23e402b538fc82ee1 Mon Sep 17 00:00:00 2001 From: Elon Date: Tue, 26 Mar 2019 11:31:57 -0600 Subject: [PATCH 7/8] correcting errors --- .../space/rendering/renderablesatellites.cpp | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index 9a341e9062..db2d95b21f 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -35,6 +35,9 @@ #include #include +#include + + // Todo: // Parse epoch correctly // read distances using correct unit @@ -348,16 +351,16 @@ void RenderableSatellites::readTLEFile(const std::string& filename, int lineNum) using namespace std::chrono; double period = seconds(hours(24)).count() / keplerElements.meanMotion; - setKeplerElements( - keplerElements.eccentricity, - keplerElements.semiMajorAxis, - keplerElements.inclination, - keplerElements.ascendingNode, - keplerElements.argumentOfPeriapsis, - keplerElements.meanAnomaly, - period, - keplerElements.epoch - ); + // setKeplerElements( + // keplerElements.eccentricity, + // keplerElements.semiMajorAxis, + // keplerElements.inclination, + // keplerElements.ascendingNode, + // keplerElements.argumentOfPeriapsis, + // keplerElements.meanAnomaly, + // period, + // keplerElements.epoch + // ); } From ba5afe3b652a203f8d1f81685d8b7b8497685038 Mon Sep 17 00:00:00 2001 From: Jonathan Fransson Date: Tue, 26 Mar 2019 14:11:35 -0600 Subject: [PATCH 8/8] working on renderableSatellites --- .../earth/satellites/satellites_shared.asset | 2 +- .../space/rendering/renderablesatellites.cpp | 407 +++++++++--------- .../space/rendering/renderablesatellites.h | 5 + 3 files changed, 213 insertions(+), 201 deletions(-) diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset index 1b5e241edd..02c252fbbe 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/satellites_shared.asset @@ -105,7 +105,7 @@ local addSatelliteGroupObjects = function(group, tleFolder, shouldAddDuplicates) Identifier = title, Parent = transforms.EarthInertial.Identifier, Renderable = { - Type = "RenderableSatellite", + Type = "RenderableSatellites", Color = color, Period = per, Resolution = 160, diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index 36bfccb8eb..22ebb94f28 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -21,8 +21,13 @@ * 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 @@ -33,6 +38,7 @@ #include #include +#include #include // Todo: @@ -43,7 +49,7 @@ namespace { constexpr const char* ProgramName = "KeplerTrails"; constexpr const char* KeyFile = "File"; - constexpr const char* KeyLineNumber = "LineNumber"; + constexpr const char* KeyLineNum = "LineNumber"; static const openspace::properties::Property::PropertyInfo PathInfo = { @@ -228,209 +234,14 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) * test */ - const std::string& file = dictionary.value(KeyFile); int lineNum = 1; - if (dictionary.hasKeyAndValue)(KeyLineNum) { + if (dictionary.hasKeyAndValue(KeyLineNum)) { lineNum = static_cast(dictionary.value(KeyLineNum)); readTLEFile(file, lineNum); - + } } - -void RenderableSatellites::readTLEFile(const std::string& filename, int lineNum){ - ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); - - std::ifstream file; - file.exceptions(std::ofstream::failbit | std::ofstream::badbit); - file.open(filename); - - // All of the Kepler element information - struct { - double inclination = 0.0; - double semiMajorAxis = 0.0; - double ascendingNode = 0.0; - double eccentricity = 0.0; - double argumentOfPeriapsis = 0.0; - double meanAnomaly = 0.0; - double meanMotion = 0.0; - double epoch = 0.0; - } keplerElements; - - std::string line; - // Loop through and throw out lines until getting to the linNum of interest - for (int i = 1; i < lineNum; ++i) { - std::getline(file, line); - } - std::getline(file, line); // Throw out the TLE title line (1st) - - std::getline(file, line); // Get line 1 of TLE format - 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, lineNum + 1 - )); - } - - std::getline(file, line); // Get line 2 of TLE format - 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 - )); - } - file.close(); - - // Calculate the semi major axis based on the mean motion using kepler's laws - keplerElements.semiMajorAxis = calculateSemiMajorAxis(keplerElements.meanMotion); - - // Converting the mean motion (revolutions per day) to period (seconds per revolution) - using namespace std::chrono; - double period = seconds(hours(24)).count() / keplerElements.meanMotion; - - setKeplerElements( - keplerElements.eccentricity, - keplerElements.semiMajorAxis, - keplerElements.inclination, - keplerElements.ascendingNode, - keplerElements.argumentOfPeriapsis, - keplerElements.meanAnomaly, - period, - keplerElements.epoch - ); - -} - -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; - } - - // The list of leap years only goes until 2056 as we need to touch this file then + // 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, @@ -551,6 +362,202 @@ double epochFromSubstring(const std::string& epochString) { // 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; + } + +void RenderableSatellites::readTLEFile(const std::string& filename, int lineNum){ + ghoul_assert(FileSys.fileExists(filename), "The filename must exist"); + + std::ifstream file; + file.exceptions(std::ofstream::failbit | std::ofstream::badbit); + file.open(filename); + + // All of the Kepler element information + struct { + double inclination = 0.0; + double semiMajorAxis = 0.0; + double ascendingNode = 0.0; + double eccentricity = 0.0; + double argumentOfPeriapsis = 0.0; + double meanAnomaly = 0.0; + double meanMotion = 0.0; + double epoch = 0.0; + } keplerElements; + + std::string line; + // Loop through and throw out lines until getting to the linNum of interest + for (int i = 1; i < lineNum; ++i) { + std::getline(file, line); + } + std::getline(file, line); // Throw out the TLE title line (1st) + + std::getline(file, line); // Get line 1 of TLE format + 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, lineNum + 1 + )); + } + + std::getline(file, line); // Get line 2 of TLE format + 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 + )); + } + file.close(); + + // Calculate the semi major axis based on the mean motion using kepler's laws + keplerElements.semiMajorAxis = calculateSemiMajorAxis(keplerElements.meanMotion); + + // Converting the mean motion (revolutions per day) to period (seconds per revolution) + using namespace std::chrono; + double period = seconds(hours(24)).count() / keplerElements.meanMotion; + + + setKeplerElements( + keplerElements.eccentricity, + keplerElements.semiMajorAxis, + keplerElements.inclination, + keplerElements.ascendingNode, + keplerElements.argumentOfPeriapsis, + keplerElements.meanAnomaly, + period, + keplerElements.epoch + ); + +} + /* * !test */ diff --git a/modules/space/rendering/renderablesatellites.h b/modules/space/rendering/renderablesatellites.h index 0eb815a630..c760f51cc8 100644 --- a/modules/space/rendering/renderablesatellites.h +++ b/modules/space/rendering/renderablesatellites.h @@ -52,6 +52,11 @@ public: void render(const RenderData& data, RendererTasks& rendererTask) override; void update(const UpdateData& data) override; + + void setKeplerElements(double eccentricity, double semiMajorAxis, double inclination, + double ascendingNode, double argumentOfPeriapsis, double meanAnomalyAtEpoch, + double orbitalPeriod, double epoch); + static documentation::Documentation Documentation();