mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-27 14:39:20 -06:00
Merge pull request #951 from OpenSpace/feature/satellitesgroupednodes
Pull code from 2019 space debris thesis into Master
This commit is contained in:
@@ -35,4 +35,4 @@ local volume = {
|
||||
}
|
||||
|
||||
local objects = { volume }
|
||||
assetHelper.registerSceneGraphNodes(asset, objects)
|
||||
assetHelper.registerSceneGraphNodes(asset, objects)
|
||||
|
||||
29
data/assets/satellites.scene
Normal file
29
data/assets/satellites.scene
Normal file
@@ -0,0 +1,29 @@
|
||||
asset.require('./base')
|
||||
|
||||
asset.request('scene/solarsystem/planets/earth/satellites/navigation/gps')
|
||||
asset.request('scene/solarsystem/planets/earth/satellites/misc/spacestations')
|
||||
|
||||
asset.onInitialize(function ()
|
||||
local now = openspace.time.currentWallTime()
|
||||
-- Jump back one day to be able to show complete weather data on Earth.
|
||||
openspace.time.setTime(openspace.time.advancedTime(now, "-1d"))
|
||||
|
||||
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.globebrowsing.goToGeo("Earth", 58.5877, 16.1924, 20000000)
|
||||
|
||||
openspace.markInterestingNodes({ "Earth", "Sun" })
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
openspace.removeInterestingNodes({ "Earth", "Sun" })
|
||||
openspace.removeVirtualProperty("*Trail.Renderable.Enabled")
|
||||
end)
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,17 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local shared = asset.require('../debris_shared')
|
||||
|
||||
local group = {
|
||||
Title = "Indian ASAT test Debris",
|
||||
Url = "http://www.celestrak.com/NORAD/elements/2019-006.txt",
|
||||
TrailColor = { 0.25, 0.35, 0.45 }
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
@@ -1,5 +1,5 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local shared = asset.require('../satellites_shared')
|
||||
local shared = asset.require('../debris_shared')
|
||||
|
||||
local group = {
|
||||
Title = "Breeze-M Breakup",
|
||||
@@ -12,12 +12,4 @@ local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, true)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local shared = asset.require('../satellites_shared')
|
||||
local shared = asset.require('../debris_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)
|
||||
@@ -12,12 +12,4 @@ local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, true)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local shared = asset.require('../satellites_shared')
|
||||
local shared = asset.require('../debris_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)
|
||||
@@ -12,12 +12,4 @@ local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, true)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local shared = asset.require('../satellites_shared')
|
||||
local shared = asset.require('../debris_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)
|
||||
@@ -12,12 +12,4 @@ local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, true)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
-- This asset requires OpenSpace to be built with the OPENSPACE_MODULE_VOLUME enabled
|
||||
|
||||
-- Before using this asset,
|
||||
-- the volume data itself needs to be generated,
|
||||
-- using the task 'data/tasks/volume/debristasks/generate_debris_volume.task'
|
||||
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local transforms = asset.require("scene/solarsystem/planets/earth/transforms")
|
||||
|
||||
local maxApogee = 2 * 10946320;
|
||||
|
||||
local volume = {
|
||||
Identifier = "DebrisVolume - Cartesian",
|
||||
Parent = transforms.EarthInertial.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableTimeVaryingVolume",
|
||||
SourceDirectory = asset.localResource("generatedCartesian"),
|
||||
TransferFunction = asset.localResource("transferfunction.txt"),
|
||||
StepSize = 0.01,
|
||||
MinValue = 0,
|
||||
MaxValue = 1,
|
||||
GridType = "Cartesian",
|
||||
SecondsBefore = 50*365*24*60*60,
|
||||
SecondsAfter = 50*365*24*60*60
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Volumes"
|
||||
},
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = maxApogee -- do not multiply this. That will not show real representation.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local objects = { volume }
|
||||
assetHelper.registerSceneGraphNodes(asset, objects)
|
||||
@@ -0,0 +1,38 @@
|
||||
-- This asset requires OpenSpace to be built with the OPENSPACE_MODULE_VOLUME enabled
|
||||
|
||||
-- Before using this asset,
|
||||
-- the volume data itself needs to be generated,
|
||||
-- using the task 'data/tasks/volume/debristasks/generate_debris_volume.task'
|
||||
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local transforms = asset.require("scene/solarsystem/planets/earth/transforms")
|
||||
|
||||
local maxApogee = 10946320;
|
||||
|
||||
local volume = {
|
||||
Identifier = "DebrisVolume - Spherical",
|
||||
Parent = transforms.EarthInertial.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableTimeVaryingVolume",
|
||||
SourceDirectory = asset.localResource("generated"),
|
||||
TransferFunction = asset.localResource("transferfunction.txt"),
|
||||
StepSize = 0.01,
|
||||
MinValue = 0,
|
||||
MaxValue = 1,
|
||||
GridType = "Spherical",
|
||||
SecondsBefore = 50*365*24*60*60,
|
||||
SecondsAfter = 50*365*24*60*60
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Volumes"
|
||||
},
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = maxApogee --do not multiply this. That will not show real representation.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local objects = { volume }
|
||||
assetHelper.registerSceneGraphNodes(asset, objects)
|
||||
@@ -0,0 +1,6 @@
|
||||
width 1024
|
||||
lower 0.0
|
||||
upper 1.0
|
||||
mappingkey 0.02 40 160 40 0
|
||||
mappingkey 0.14 40 40 240 50
|
||||
mappingkey 0.3 200 80 0 250
|
||||
@@ -0,0 +1,74 @@
|
||||
local transforms = asset.require('scene/solarsystem/planets/earth/transforms')
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
local satImageFolder = asset.syncedResource({
|
||||
Name = "Satellite Image Files",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "tle_satellites_images",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
function downloadTLEFile(sceneAsset, url, name)
|
||||
local identifier = name
|
||||
identifier = identifier:gsub(" ", "")
|
||||
identifier = identifier:gsub("&", "")
|
||||
identifier = identifier:gsub("-", "")
|
||||
return sceneAsset.syncedResource({
|
||||
Name = "Satellite TLE Data (" .. name .. ")",
|
||||
Type = "UrlSynchronization",
|
||||
Identifier = "satellite_tle_data_" .. identifier,
|
||||
Url = url
|
||||
})
|
||||
end
|
||||
|
||||
local registerSatelliteGroupObjects = function(containingAsset, group, tleFolder, shouldAddDuplicates)
|
||||
local filename = group.Url:match("([^/]+)$")
|
||||
local filenameSansExt = filename:gsub(filename:match("(%.%w+)$"), "")
|
||||
|
||||
local path = tleFolder .. "/" .. filename
|
||||
|
||||
function numLinesInFile(filename)
|
||||
local ctr = 0
|
||||
for _ in io.lines(filename) do ctr = ctr + 1 end
|
||||
return ctr
|
||||
end
|
||||
|
||||
-- Check format of a set of 3 TLE file lines and return nonzero if there is a format error
|
||||
function isValidTLEFileFormat(lineArr)
|
||||
function isEmpty(s) return s == nil or s == '' end
|
||||
|
||||
if isEmpty(lineArr[1]) or isEmpty(lineArr[2]) or isEmpty(lineArr[3]) then
|
||||
return false
|
||||
end
|
||||
if string.sub(lineArr[2], 1, 2) ~= "1 " then
|
||||
return false
|
||||
end
|
||||
if string.sub(lineArr[3], 1, 2) ~= "2 " then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function debris(title, file, color)
|
||||
return {
|
||||
Identifier = title,
|
||||
Parent = transforms.EarthInertial.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableSatellites",
|
||||
Path = file,
|
||||
Segments = 160,
|
||||
Color = color,
|
||||
Fade = 0.5
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Solar System/Planets/Earth/Satellites"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
local Debris = debris(filenameSansExt, path, group.TrailColor)
|
||||
assetHelper.registerSceneGraphNodesAndExport(containingAsset, { Debris })
|
||||
end
|
||||
|
||||
asset.export("downloadTLEFile", downloadTLEFile)
|
||||
asset.export("registerSatelliteGroupObjects", registerSatelliteGroupObjects)
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, true)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -4,20 +4,8 @@ local shared = asset.require('../satellites_shared')
|
||||
local group = {
|
||||
Title = "SpaceStations",
|
||||
Url = "http://celestrak.com/NORAD/elements/stations.txt",
|
||||
TrailColor = { 0.9, 0.0, 0.0 }
|
||||
TrailColor = { 0.9, 0.1, 0.0 }
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, true)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
asset.request('./debris/debris_asat')
|
||||
asset.request('./debris/debris_breezem')
|
||||
asset.request('./debris/debris_fengyun')
|
||||
asset.request('./debris/debris_iridium33')
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local transforms = asset.require('scene/solarsystem/planets/earth/transforms')
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
local satImageFolder = asset.syncedResource({
|
||||
Name = "Satellite Image Files",
|
||||
@@ -20,7 +21,12 @@ function downloadTLEFile(sceneAsset, url, name)
|
||||
})
|
||||
end
|
||||
|
||||
local addSatelliteGroupObjects = function(group, tleFolder, shouldAddDuplicates)
|
||||
local registerSatelliteGroupObjects = function(containingAsset, group, tleFolder, shouldAddDuplicates)
|
||||
local filename = group.Url:match("([^/]+)$")
|
||||
local filenameSansExt = filename:gsub(filename:match("(%.%w+)$"), "")
|
||||
|
||||
local path = tleFolder .. "/" .. filename
|
||||
|
||||
function numLinesInFile(filename)
|
||||
local ctr = 0
|
||||
for _ in io.lines(filename) do ctr = ctr + 1 end
|
||||
@@ -43,127 +49,27 @@ local addSatelliteGroupObjects = function(group, tleFolder, shouldAddDuplicates)
|
||||
return true
|
||||
end
|
||||
|
||||
function getSat(title, file, lineNum, textureFile, group)
|
||||
function satellites(title, file, color)
|
||||
return {
|
||||
Identifier = title,
|
||||
Parent = transforms.EarthInertial.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderablePlaneImageLocal",
|
||||
Enabled = false,
|
||||
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
|
||||
},
|
||||
Identifier = title,
|
||||
Parent = transforms.EarthInertial.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableSatellites",
|
||||
Path = file,
|
||||
Segments = 160,
|
||||
Color = color,
|
||||
Period = per,
|
||||
Resolution = 160
|
||||
Fade = 0.5
|
||||
},
|
||||
Tag = { "earth_satellite_" .. group, "earth_satellite_" .. group .. "_trail"},
|
||||
--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+)$"), "")
|
||||
|
||||
local path = tleFolder .. "/" .. filename
|
||||
local texture = satImageFolder .. "/" .. "satB.png"
|
||||
|
||||
|
||||
local file = io.open(path, "r")
|
||||
assert(file, "File not found: " .. path)
|
||||
|
||||
local obj = {}
|
||||
|
||||
--now loop through the tle file and get each set of 3 lines
|
||||
for n = 1, numLinesInFile(path), 3 do
|
||||
local line = {
|
||||
file:read('*l'), --title line
|
||||
file:read('*l'),
|
||||
file:read('*l')
|
||||
}
|
||||
assert(isValidTLEFileFormat(line), "TLE file syntax error on line " .. n .. ": " .. path)
|
||||
|
||||
-- Trim string
|
||||
line[1] = line[1]:gsub("^%s*(.-)%s*$", "%1")
|
||||
line[1] = line[1]:gsub("%s+", "_")
|
||||
line[1] = line[1]:gsub("[%-()]", "")
|
||||
local title = line[1]
|
||||
|
||||
-- Get period from correct location of the string
|
||||
local per = tonumber(string.sub(line[3], 53, 63))
|
||||
-- Trail for 2x a single revolution
|
||||
per = 1.0 / per * 2.0
|
||||
|
||||
local satName = filenameSansExt .. "_" .. title
|
||||
|
||||
local shouldAddNotes = true
|
||||
if openspace.hasSceneGraphNode(satName) then
|
||||
if shouldAddDuplicates then
|
||||
local originalSatName = satName
|
||||
local i = 1
|
||||
while openspace.hasSceneGraphNode(satName) do
|
||||
satName = originalSatName .. "_" .. tostring(i)
|
||||
i = i + 1
|
||||
end
|
||||
else
|
||||
shouldAddNotes = false
|
||||
end
|
||||
end
|
||||
|
||||
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 satTrail_var = getSatTrail(satName, path, n, per, group.TrailColor, group.Title)
|
||||
openspace.addSceneGraphNode(satTrail_var)
|
||||
table.insert(obj, satTrail_var.Identifier)
|
||||
end
|
||||
end
|
||||
|
||||
return obj
|
||||
local SatelliteBatch = satellites(filenameSansExt, path, group.TrailColor)
|
||||
assetHelper.registerSceneGraphNodesAndExport(containingAsset, { SatelliteBatch })
|
||||
end
|
||||
|
||||
asset.export("satImageFolder", satImageFolder)
|
||||
asset.export("downloadTLEFile", downloadTLEFile)
|
||||
asset.export("addSatelliteGroupObjects", addSatelliteGroupObjects)
|
||||
asset.export("registerSatelliteGroupObjects", registerSatelliteGroupObjects)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,15 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
@@ -8,16 +8,4 @@ local group = {
|
||||
}
|
||||
|
||||
local tle = shared.downloadTLEFile(asset, group.Url, group.Title)
|
||||
|
||||
|
||||
local objectNames = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
objectNames = shared.addSatelliteGroupObjects(group, tle, false)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(objectNames) do
|
||||
openspace.removeSceneGraphNode(n)
|
||||
end
|
||||
end)
|
||||
shared.registerSatelliteGroupObjects(asset, group, tle, true)
|
||||
|
||||
28
data/assets/spaceDebris.scene
Normal file
28
data/assets/spaceDebris.scene
Normal file
@@ -0,0 +1,28 @@
|
||||
asset.require('./base')
|
||||
|
||||
--asset.request('scene/solarsystem/planets/earth/satellites/satellites_all')
|
||||
asset.request('scene/solarsystem/planets/earth/satellites/satellites_debris')
|
||||
|
||||
asset.onInitialize(function ()
|
||||
local now = openspace.time.currentWallTime()
|
||||
--local now = "2019-06-26T00:00:00"
|
||||
|
||||
-- Jump back one day to show a complete planet
|
||||
openspace.time.setTime(openspace.time.advancedTime(now, "-1d"))
|
||||
|
||||
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.globebrowsing.goToGeo(58.5877, 16.1924, 20000000)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
openspace.removeVirtualProperty("*Trail.Renderable.Enabled")
|
||||
end)
|
||||
13
data/tasks/volume/debristasks/generate_cartesian_volume.task
Normal file
13
data/tasks/volume/debristasks/generate_cartesian_volume.task
Normal file
@@ -0,0 +1,13 @@
|
||||
return {{
|
||||
Type = "GenerateDebrisVolumeTask",
|
||||
Dimensions = {48, 48, 48},
|
||||
LowerDomainBound = {-0.5, -0.5, -0.5},
|
||||
UpperDomainBound = {0.5, 0.5, 0.5},
|
||||
InputPath = "${SYNC}/url/satellite_tle_data_DebrisAll/files/allDebrisInOneTLE.txt",
|
||||
StartTime = "2019-07-27T10:00:00",
|
||||
TimeStep = "2",
|
||||
EndTime = "2019-07-27T12:00:00",
|
||||
GridType = "Cartesian",
|
||||
RawVolumeOutput = "${DATA}/assets/scene/solarsystem/planets/earth/satellites/debris/volume/generatedCartesian/singleDebris.rawvolume",
|
||||
DictionaryOutput = "${DATA}/assets/scene/solarsystem/planets/earth/satellites/debris/volume/generatedCartesian/singleDebris.dictionary"
|
||||
}}
|
||||
13
data/tasks/volume/debristasks/generate_spherical_volume.task
Normal file
13
data/tasks/volume/debristasks/generate_spherical_volume.task
Normal file
@@ -0,0 +1,13 @@
|
||||
return {{
|
||||
Type = "GenerateDebrisVolumeTask",
|
||||
Dimensions = {45, 30, 40},
|
||||
LowerDomainBound = {0, 0, 0},
|
||||
UpperDomainBound = {1, math.pi, 2 * math.pi},
|
||||
InputPath = "${SYNC}/url/satellite_tle_data_DebrisAll/files/allDebrisInOneTLE.txt",
|
||||
StartTime = "2019-07-27T10:00:00",
|
||||
TimeStep = "2",
|
||||
EndTime = "2019-07-27T12:00:00",
|
||||
GridType = "Spherical",
|
||||
RawVolumeOutput = "${DATA}/assets/scene/solarsystem/planets/earth/satellites/debris/volume/generated/singleDebris.rawvolume",
|
||||
DictionaryOutput = "${DATA}/assets/scene/solarsystem/planets/earth/satellites/debris/volume/generated/singleDebris.dictionary"
|
||||
}}
|
||||
@@ -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,17 +173,34 @@ documentation::Documentation RenderableTrail::Documentation() {
|
||||
};
|
||||
}
|
||||
|
||||
RenderableTrail::Appearance::Appearance()
|
||||
: properties::PropertyOwner(AppearanceInfo)
|
||||
, lineColor(LineColorInfo, glm::vec3(1.0f, 1.0f, 0.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)
|
||||
, _lineWidth(LineWidthInfo, 2.f, 1.f, 20.f)
|
||||
, _pointSize(PointSizeInfo, 1, 1, 64)
|
||||
, _renderingModes(
|
||||
RenderingModeInfo,
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
{
|
||||
addProperty(_opacity);
|
||||
registerUpdateRenderBinFromOpacity();
|
||||
@@ -186,32 +210,32 @@ RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary)
|
||||
);
|
||||
addPropertySubOwner(_translation.get());
|
||||
|
||||
_lineColor = dictionary.value<glm::vec3>(LineColorInfo.identifier);
|
||||
addProperty(_lineColor);
|
||||
_appearance.lineColor = dictionary.value<glm::vec3>(LineColorInfo.identifier);
|
||||
addProperty(_appearance.lineColor);
|
||||
|
||||
if (dictionary.hasKeyAndValue<bool>(EnableFadeInfo.identifier)) {
|
||||
_useLineFade = dictionary.value<bool>(EnableFadeInfo.identifier);
|
||||
_appearance.useLineFade = dictionary.value<bool>(EnableFadeInfo.identifier);
|
||||
}
|
||||
addProperty(_useLineFade);
|
||||
addProperty(_appearance.useLineFade);
|
||||
|
||||
if (dictionary.hasKeyAndValue<double>(FadeInfo.identifier)) {
|
||||
_lineFade = static_cast<float>(dictionary.value<double>(FadeInfo.identifier));
|
||||
_appearance.lineFade = static_cast<float>(dictionary.value<double>(FadeInfo.identifier));
|
||||
}
|
||||
addProperty(_lineFade);
|
||||
addProperty(_appearance.lineFade);
|
||||
|
||||
if (dictionary.hasKeyAndValue<double>(LineWidthInfo.identifier)) {
|
||||
_lineWidth = static_cast<float>(dictionary.value<double>(
|
||||
_appearance.lineWidth = static_cast<float>(dictionary.value<double>(
|
||||
LineWidthInfo.identifier
|
||||
));
|
||||
}
|
||||
addProperty(_lineWidth);
|
||||
addProperty(_appearance.lineWidth);
|
||||
|
||||
if (dictionary.hasKeyAndValue<double>(PointSizeInfo.identifier)) {
|
||||
_pointSize = static_cast<int>(dictionary.value<double>(PointSizeInfo.identifier));
|
||||
_appearance.pointSize = static_cast<int>(dictionary.value<double>(PointSizeInfo.identifier));
|
||||
}
|
||||
addProperty(_pointSize);
|
||||
addProperty(_appearance.pointSize);
|
||||
|
||||
_renderingModes.addOptions({
|
||||
_appearance.renderingModes.addOptions({
|
||||
{ RenderingModeLines, "Lines" },
|
||||
{ RenderingModePoints, "Points" },
|
||||
{ RenderingModeLinesPoints, "Lines+Points" }
|
||||
@@ -220,14 +244,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<std::string>(RenderingModeInfo.identifier)) {
|
||||
_renderingModes = RenderingModeConversion.at(
|
||||
_appearance.renderingModes = RenderingModeConversion.at(
|
||||
dictionary.value<std::string>(RenderingModeInfo.identifier)
|
||||
);
|
||||
}
|
||||
else {
|
||||
_renderingModes = RenderingModeLines;
|
||||
_appearance.renderingModes = RenderingModeLines;
|
||||
}
|
||||
addProperty(_renderingModes);
|
||||
addProperty(_appearance.renderingModes);
|
||||
}
|
||||
|
||||
void RenderableTrail::initializeGL() {
|
||||
@@ -270,10 +294,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<RenderInformation::VertexSorting, int> SortingMapping = {
|
||||
@@ -292,21 +316,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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/renderablerings.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablestars.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/simplespheregeometry.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/keplertranslation.h
|
||||
@@ -42,6 +43,7 @@ set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/planetgeometry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableconstellationbounds.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablerings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablesatellites.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablestars.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/simplespheregeometry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/keplertranslation.cpp
|
||||
@@ -55,6 +57,8 @@ source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/constellationbounds_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/constellationbounds_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/debrisViz_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/debrisViz_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/rings_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/star_fs.glsl
|
||||
|
||||
617
modules/space/rendering/renderablesatellites.cpp
Normal file
617
modules/space/rendering/renderablesatellites.cpp
Normal file
@@ -0,0 +1,617 @@
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* 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 <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 <fstream>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
constexpr const char* ProgramName = "RenderableSatellites";
|
||||
constexpr const char* _loggerCat = "Satellites";
|
||||
|
||||
static const openspace::properties::Property::PropertyInfo PathInfo = {
|
||||
"Path",
|
||||
"Path",
|
||||
"The file path to the TLE file to read"
|
||||
};
|
||||
|
||||
static const openspace::properties::Property::PropertyInfo SegmentsInfo = {
|
||||
"Segments",
|
||||
"Segments",
|
||||
"The number of segments to use for each orbit ellipse"
|
||||
};
|
||||
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 FadeInfo = {
|
||||
"Fade",
|
||||
"Line fade",
|
||||
"The fading factor that is applied to the trail if the 'EnableFade' value is "
|
||||
"'true'. If it is 'false', this setting has no effect. The higher the number, "
|
||||
"the less fading is applied."
|
||||
};
|
||||
constexpr openspace::properties::Property::PropertyInfo LineColorInfo = {
|
||||
"Color",
|
||||
"Color",
|
||||
"This value determines the RGB main color for the lines and points of the trail."
|
||||
};
|
||||
|
||||
constexpr const char* KeyFile = "Path";
|
||||
constexpr const char* KeyLineNum = "LineNumber";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
// The list of leap years only goes until 2056 as we need to touch this file then
|
||||
// again anyway ;)
|
||||
const std::vector<int> 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<int>(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<LeapSecond> 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<int>(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<double>() * glm::pi<double>();
|
||||
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<int>(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 additional leap seconds past 2000 and add them prior to
|
||||
// 2000 to sync up the time zones
|
||||
const double nLeapSecondsOffset = -countLeapSeconds(
|
||||
year,
|
||||
static_cast<int>(std::floor(daysInYear))
|
||||
);
|
||||
|
||||
// 5
|
||||
const double nSecondsEpochOffset = static_cast<double>(
|
||||
seconds(hours(12)).count()
|
||||
);
|
||||
|
||||
// Combine all of the values
|
||||
const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset;
|
||||
return epoch;
|
||||
}
|
||||
|
||||
documentation::Documentation RenderableSatellites::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableSatellites",
|
||||
"space_renderable_satellites",
|
||||
{
|
||||
{
|
||||
SegmentsInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::No,
|
||||
SegmentsInfo.description
|
||||
},
|
||||
{
|
||||
PathInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
PathInfo.description
|
||||
},
|
||||
{
|
||||
LineWidthInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LineWidthInfo.description
|
||||
},
|
||||
{
|
||||
FadeInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
FadeInfo.description
|
||||
},
|
||||
{
|
||||
LineColorInfo.identifier,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::No,
|
||||
LineColorInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
, _path(PathInfo)
|
||||
, _nSegments(SegmentsInfo)
|
||||
, _lineFade(FadeInfo)
|
||||
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableSatellites"
|
||||
);
|
||||
|
||||
_path = dictionary.value<std::string>(PathInfo.identifier);
|
||||
_nSegments = static_cast<int>(dictionary.value<double>(SegmentsInfo.identifier));
|
||||
_lineFade = static_cast<float>(dictionary.value<double>(FadeInfo.identifier));
|
||||
|
||||
if (dictionary.hasKeyAndValue<glm::vec3>(LineColorInfo.identifier)) {
|
||||
_appearance.lineColor = dictionary.value<glm::vec3>(LineColorInfo.identifier);
|
||||
}
|
||||
|
||||
addPropertySubOwner(_appearance);
|
||||
addProperty(_path);
|
||||
addProperty(_nSegments);
|
||||
addProperty(_lineFade);
|
||||
}
|
||||
|
||||
|
||||
void RenderableSatellites::readTLEFile(const std::string& filename) {
|
||||
if (!FileSys.fileExists(filename)) {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Satellite TLE file {} does not exist.", filename
|
||||
));
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 3 because a TLE has 3 lines per element/ object.
|
||||
std::streamoff numberOfObjects = numberOfLines / 3;
|
||||
|
||||
std::string line = "-";
|
||||
for (std::streamoff 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 {} 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;
|
||||
|
||||
_TLEData.push_back(keplerElements);
|
||||
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void RenderableSatellites::initializeGL() {
|
||||
glGenVertexArrays(1, &_vertexArray);
|
||||
glGenBuffers(1, &_vertexBuffer);
|
||||
|
||||
_programObject = SpaceModule::ProgramObjectManager.request(
|
||||
ProgramName,
|
||||
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
|
||||
return global::renderEngine.buildRenderProgram(
|
||||
ProgramName,
|
||||
absPath("${MODULE_SPACE}/shaders/debrisViz_vs.glsl"),
|
||||
absPath("${MODULE_SPACE}/shaders/debrisViz_fs.glsl")
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
_uniformCache.modelView = _programObject->uniformLocation("modelViewTransform");
|
||||
_uniformCache.projection = _programObject->uniformLocation("projectionTransform");
|
||||
_uniformCache.lineFade = _programObject->uniformLocation("lineFade");
|
||||
_uniformCache.inGameTime = _programObject->uniformLocation("inGameTime");
|
||||
_uniformCache.color = _programObject->uniformLocation("color");
|
||||
_uniformCache.opacity = _programObject->uniformLocation("opacity");
|
||||
|
||||
updateBuffers();
|
||||
setRenderBin(Renderable::RenderBin::Overlay);
|
||||
}
|
||||
|
||||
void RenderableSatellites::deinitializeGL() {
|
||||
glDeleteBuffers(1, &_vertexBuffer);
|
||||
glDeleteVertexArrays(1, &_vertexArray);
|
||||
|
||||
SpaceModule::ProgramObjectManager.release(
|
||||
ProgramName,
|
||||
[](ghoul::opengl::ProgramObject* p) {
|
||||
global::renderEngine.removeRenderProgram(p);
|
||||
}
|
||||
);
|
||||
_programObject = nullptr;
|
||||
}
|
||||
|
||||
bool RenderableSatellites::isReady() const {
|
||||
return _programObject != nullptr;
|
||||
}
|
||||
|
||||
void RenderableSatellites::render(const RenderData& data, RendererTasks&) {
|
||||
if (_TLEData.empty())
|
||||
return;
|
||||
|
||||
_programObject->activate();
|
||||
_programObject->setUniform(_uniformCache.opacity, _opacity);
|
||||
_programObject->setUniform(_uniformCache.inGameTime, data.time.j2000Seconds());
|
||||
|
||||
|
||||
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.lineFade, _appearance.lineFade);
|
||||
|
||||
glLineWidth(_appearance.lineWidth);
|
||||
|
||||
const size_t nrOrbits = _TLEData.size();
|
||||
gl::GLint vertices = 0;
|
||||
|
||||
//glDepthMask(false);
|
||||
//glBlendFunc(GL_SRC_ALPHA, GL_ONE)
|
||||
|
||||
glBindVertexArray(_vertexArray);
|
||||
for (size_t i = 0; i < nrOrbits; ++i) {
|
||||
glDrawArrays(GL_LINE_STRIP, vertices, _nSegments + 1);
|
||||
vertices = vertices + _nSegments + 1;
|
||||
}
|
||||
glBindVertexArray(0);
|
||||
|
||||
_programObject->deactivate();
|
||||
|
||||
}
|
||||
|
||||
void RenderableSatellites::updateBuffers() {
|
||||
readTLEFile(_path);
|
||||
|
||||
const size_t nVerticesPerOrbit = _nSegments + 1;
|
||||
_vertexBufferData.resize(_TLEData.size() * nVerticesPerOrbit);
|
||||
size_t orbitindex = 0;
|
||||
|
||||
for (const auto& orbit : _TLEData) {
|
||||
_keplerTranslator.setKeplerElements(
|
||||
orbit.eccentricity,
|
||||
orbit.semiMajorAxis,
|
||||
orbit.inclination,
|
||||
orbit.ascendingNode,
|
||||
orbit.argumentOfPeriapsis,
|
||||
orbit.meanAnomaly,
|
||||
orbit.period,
|
||||
orbit.epoch
|
||||
);
|
||||
|
||||
for (size_t i=0 ; i < nVerticesPerOrbit; ++i) {
|
||||
size_t index = orbitindex * nVerticesPerOrbit + i;
|
||||
|
||||
double timeOffset = orbit.period *
|
||||
static_cast<double>(i)/ static_cast<double>(_nSegments);
|
||||
|
||||
glm::dvec3 position = _keplerTranslator.position({
|
||||
{},
|
||||
Time(timeOffset + orbit.epoch),
|
||||
Time(0.0),
|
||||
false
|
||||
});
|
||||
|
||||
double positionX = position.x;
|
||||
double positionY = position.y;
|
||||
double positionZ = position.z;
|
||||
|
||||
_vertexBufferData[index].x = static_cast<float>(positionX);
|
||||
_vertexBufferData[index].y = static_cast<float>(positionY);
|
||||
_vertexBufferData[index].z = static_cast<float>(positionZ);
|
||||
_vertexBufferData[index].time = static_cast<float>(timeOffset);
|
||||
_vertexBufferData[index].epoch = orbit.epoch;
|
||||
_vertexBufferData[index].period = orbit.period;
|
||||
}
|
||||
|
||||
++orbitindex;
|
||||
}
|
||||
|
||||
glBindVertexArray(_vertexArray);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
_vertexBufferData.size() * sizeof(TrailVBOLayout),
|
||||
_vertexBufferData.data(),
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(TrailVBOLayout), (GLvoid*)0); // stride : 4*sizeof(GL_FLOAT) + 2*sizeof(GL_DOUBLE)
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, sizeof(TrailVBOLayout), (GLvoid*)(4*sizeof(GL_FLOAT)) );
|
||||
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
129
modules/space/rendering/renderablesatellites.h
Normal file
129
modules/space/rendering/renderablesatellites.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/****************************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_SPACE___RENDERABLESATELLITES___H__
|
||||
#define __OPENSPACE_MODULE_SPACE___RENDERABLESATELLITES___H__
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <modules/base/rendering/renderabletrail.h>
|
||||
#include <modules/space/translation/keplertranslation.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/uintproperty.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/misc/objectmanager.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class RenderableSatellites : public Renderable {
|
||||
public:
|
||||
RenderableSatellites(const ghoul::Dictionary& dictionary);
|
||||
|
||||
void initializeGL() override;
|
||||
void deinitializeGL() override;
|
||||
|
||||
bool isReady() const override;
|
||||
void render(const RenderData& data, RendererTasks& rendererTask) override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
/**
|
||||
* Reads the provided TLE file and calls 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.
|
||||
*
|
||||
* \throw ghoul::RuntimeError if the TLE file does not exist or there is a
|
||||
* problem with its format.
|
||||
* \pre The \p filename must exist
|
||||
*/
|
||||
void readTLEFile(const std::string& filename);
|
||||
|
||||
private:
|
||||
struct Vertex {
|
||||
glm::vec3 position;
|
||||
glm::vec3 color;
|
||||
glm::vec2 texcoord;
|
||||
};
|
||||
|
||||
struct KeplerParameters {
|
||||
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;
|
||||
double period = 0.0;
|
||||
};
|
||||
|
||||
/// The layout of the VBOs
|
||||
struct TrailVBOLayout {
|
||||
float x, y, z, time;
|
||||
double epoch, period;
|
||||
};
|
||||
|
||||
KeplerTranslation _keplerTranslator;
|
||||
std::vector<KeplerParameters> _TLEData;
|
||||
|
||||
/// The backend storage for the vertex buffer object containing all points for this
|
||||
/// trail.
|
||||
std::vector<TrailVBOLayout> _vertexBufferData;
|
||||
|
||||
/// The index array that is potentially used in the draw call. If this is empty, no
|
||||
/// element draw call is used.
|
||||
std::vector<unsigned int> _indexBufferData;
|
||||
|
||||
GLuint _vertexArray;
|
||||
GLuint _vertexBuffer;
|
||||
GLuint _indexBuffer;
|
||||
|
||||
//GLuint _vaoTest; // vertexArrayObject
|
||||
//GLuint _vboTest; // vertextBufferObject
|
||||
//GLuint _eboTest; // elementBufferObject/ indexBufferObject
|
||||
|
||||
void updateBuffers();
|
||||
|
||||
ghoul::opengl::ProgramObject* _programObject;
|
||||
|
||||
properties::StringProperty _path;
|
||||
properties::UIntProperty _nSegments;
|
||||
|
||||
properties::DoubleProperty _lineFade;
|
||||
|
||||
RenderableTrail::Appearance _appearance;
|
||||
|
||||
glm::vec3 _position;
|
||||
|
||||
UniformCache(modelView, projection, lineFade, inGameTime, color, opacity,
|
||||
numberOfSegments) _uniformCache;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_SPACE___RENDERABLESATELLITES___H__
|
||||
|
||||
88
modules/space/shaders/debrisViz_fs.glsl
Normal file
88
modules/space/shaders/debrisViz_fs.glsl
Normal file
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 float lineFade;
|
||||
// uniform int numberOfSegments;
|
||||
|
||||
|
||||
in vec4 viewSpacePosition;
|
||||
in float vs_position_w;
|
||||
|
||||
in float periodFraction_f;
|
||||
in float offsetPeriods;
|
||||
in float vertexID_f;
|
||||
|
||||
// debuggers :
|
||||
// in float offset;
|
||||
// in float epoch;
|
||||
// in float period;
|
||||
// in flat double tajm;
|
||||
Fragment getFragment() {
|
||||
// float offsetPeriods = offset / period;
|
||||
// This is now done in the fragment shader instead
|
||||
// to make smooth movement between vertecies.
|
||||
// We want vertexDistance to be double up to this point, I think.
|
||||
// (hence the unnessesary float to float conversion)
|
||||
float vertexDistance = periodFraction_f - offsetPeriods;
|
||||
float vertexDistance_f = float(vertexDistance);
|
||||
|
||||
// This is the alternative way of calculating
|
||||
// the offsetPeriods: (vertexID_perOrbit/nrOfSegments_f)
|
||||
// float vertexID_perOrbit = mod(vertexID_f, numberOfSegments);
|
||||
// float nrOfSegments_f = float(numberOfSegments);
|
||||
// float vertexDistance = periodFraction_f - (vertexID_perOrbit/nrOfSegments_f);
|
||||
|
||||
if (vertexDistance_f < 0.0) {
|
||||
vertexDistance_f += 1.0;
|
||||
}
|
||||
|
||||
float invert = 1.0 - vertexDistance_f;
|
||||
float fade = clamp(invert * lineFade, 0.0, 1.0);
|
||||
|
||||
Fragment frag;
|
||||
frag.color = vec4(color, fade * opacity);
|
||||
frag.depth = vs_position_w;
|
||||
frag.gPosition = viewSpacePosition;
|
||||
frag.gNormal = vec4(1, 1, 1, 0);
|
||||
// frag.blend = BLEND_MODE_ADDITIVE;
|
||||
|
||||
|
||||
// to debug using colors use this if-statment.
|
||||
// float ep = 0.01;
|
||||
// if( fract(vertexID_f) < ep ){ //periodFraction < ep
|
||||
// frag.color = vec4(1, 0, 0, 1);
|
||||
// }
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
100
modules/space/shaders/debrisViz_vs.glsl
Normal file
100
modules/space/shaders/debrisViz_vs.glsl
Normal file
@@ -0,0 +1,100 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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__
|
||||
|
||||
#include "PowerScaling/powerScalingMath.hglsl"
|
||||
|
||||
layout (location = 0) in vec4 vertex_data; // 1: x, 2: y, 3: z, 4: timeOffset,
|
||||
layout (location = 1) in vec2 orbit_data; // 1: epoch, 2: period
|
||||
|
||||
uniform dmat4 modelViewTransform;
|
||||
uniform mat4 projectionTransform;
|
||||
|
||||
//uniform float lineFade;
|
||||
uniform double inGameTime;
|
||||
|
||||
out vec4 viewSpacePosition;
|
||||
out float vs_position_w;
|
||||
|
||||
out float periodFraction_f;
|
||||
out float offsetPeriods;
|
||||
out float vertexID_f;
|
||||
|
||||
// debugers :
|
||||
// out float offset;
|
||||
// out float epoch;
|
||||
// out float period;
|
||||
// out double tajm;
|
||||
|
||||
void main() {
|
||||
|
||||
// tajm = inGameTime;
|
||||
/** The way the position and line fade is calculated is:
|
||||
* By using inGameTime, epoch and period of this orbit,
|
||||
* we get how many revolutions it has done since epoch.
|
||||
* The fract of that, is how far into a revolution it has traveld since epoch.
|
||||
* Similarly we do the same but for this vertex, but calculating offsetPeriods.
|
||||
* In the fragment shader the difference between
|
||||
* periodFraction_f and offsetPeriods is calculated to know how much to fade
|
||||
* that specific fragment.
|
||||
*/
|
||||
|
||||
// If orbit_data is doubles, cast to float first
|
||||
float offset = vertex_data.w;
|
||||
double epoch = orbit_data.x;
|
||||
double period = orbit_data.y;
|
||||
|
||||
// calculate nr of periods, get fractional part to know where
|
||||
// the vertex closest to the debris part is right now
|
||||
double nrOfRevolutions = (inGameTime - epoch) / period;
|
||||
//double periodFraction = fract(nrOfRevolutions); //mod(nrOfRevolutions, 1.0);
|
||||
int intfrac = int(nrOfRevolutions);
|
||||
double doublefrac = double(intfrac);
|
||||
double periodFraction = nrOfRevolutions - doublefrac;
|
||||
if (periodFraction < 0.0) {
|
||||
periodFraction += 1.0;
|
||||
}
|
||||
periodFraction_f = float(periodFraction);
|
||||
|
||||
// same procedure for the current vertex
|
||||
float period_f = float(period);
|
||||
offsetPeriods = offset / period_f;
|
||||
|
||||
// offsetPeriods can also be calculated by passing the vertexID as a float
|
||||
// to the fragment shader and deviding it by nrOfSegments.
|
||||
vertexID_f = float(gl_VertexID);
|
||||
dvec3 positions = dvec3(vertex_data.x, vertex_data.y, vertex_data.z);
|
||||
dvec4 vertexPosition = dvec4(positions, 1);
|
||||
viewSpacePosition = vec4(modelViewTransform * vertexPosition);
|
||||
vec4 vs_position = z_normalization( projectionTransform * viewSpacePosition);
|
||||
gl_Position = vs_position;
|
||||
vs_position_w = vs_position.w;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -24,10 +24,13 @@
|
||||
|
||||
#include <modules/space/spacemodule.h>
|
||||
|
||||
#include <modules/space/rendering/renderablesatellites.h>
|
||||
#include <modules/space/rendering/renderableconstellationbounds.h>
|
||||
#include <modules/space/rendering/renderablerings.h>
|
||||
#include <modules/space/rendering/renderablesatellites.h>
|
||||
#include <modules/space/rendering/renderablestars.h>
|
||||
#include <modules/space/rendering/simplespheregeometry.h>
|
||||
//#include <modules/space/tasks/generatedebrisvolumetask.h>
|
||||
#include <modules/space/translation/keplertranslation.h>
|
||||
#include <modules/space/translation/spicetranslation.h>
|
||||
#include <modules/space/translation/tletranslation.h>
|
||||
@@ -78,6 +81,7 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
);
|
||||
|
||||
fRenderable->registerClass<RenderableRings>("RenderableRings");
|
||||
fRenderable->registerClass<RenderableSatellites>("RenderableSatellites");
|
||||
fRenderable->registerClass<RenderableStars>("RenderableStars");
|
||||
|
||||
auto fTranslation = FactoryManager::ref().factory<Translation>();
|
||||
@@ -88,6 +92,10 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
fTranslation->registerClass<TLETranslation>("TLETranslation");
|
||||
fTranslation->registerClass<HorizonsTranslation>("HorizonsTranslation");
|
||||
|
||||
/*auto fTasks = FactoryManager::ref().factory<Task>();
|
||||
ghoul_assert(fTasks, "No task factory existed");
|
||||
fTasks->registerClass<volume::GenerateDebrisVolumeTask>("GenerateDebrisVolumeTask");*/
|
||||
|
||||
auto fRotation = FactoryManager::ref().factory<Rotation>();
|
||||
ghoul_assert(fRotation, "Rotation factory was not created");
|
||||
|
||||
@@ -106,6 +114,7 @@ std::vector<documentation::Documentation> SpaceModule::documentations() const {
|
||||
return {
|
||||
RenderableConstellationBounds::Documentation(),
|
||||
RenderableRings::Documentation(),
|
||||
RenderableSatellites::Documentation(),
|
||||
RenderableStars::Documentation(),
|
||||
SpiceRotation::Documentation(),
|
||||
SpiceTranslation::Documentation(),
|
||||
|
||||
811
modules/space/tasks/generatedebrisvolumetask.cpp
Normal file
811
modules/space/tasks/generatedebrisvolumetask.cpp
Normal file
@@ -0,0 +1,811 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <modules/space/tasks/generatedebrisvolumetask.h>
|
||||
|
||||
#include <modules/volume/rawvolume.h>
|
||||
#include <modules/volume/rawvolumemetadata.h>
|
||||
#include <modules/volume/rawvolumewriter.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
|
||||
#include <openspace/documentation/verifier.h>
|
||||
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
//#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <ghoul/misc/defer.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* ProgramName = "RenderableSatellites";
|
||||
constexpr const char* _loggerCat = "SpaceDebris";
|
||||
|
||||
constexpr const char* KeyRawVolumeOutput = "RawVolumeOutput";
|
||||
constexpr const char* KeyDictionaryOutput = "DictionaryOutput";
|
||||
constexpr const char* KeyDimensions = "Dimensions";
|
||||
constexpr const char* KeyStartTime = "StartTime";
|
||||
constexpr const char* KeyTimeStep = "TimeStep";
|
||||
constexpr const char* KeyEndTime = "EndTime";
|
||||
constexpr const char* KeyInputPath = "InputPath";
|
||||
constexpr const char* KeyGridType = "GridType";
|
||||
|
||||
// constexpr const char* KeyInputPath1 = "InputPath1";
|
||||
// constexpr const char* KeyInputPath2 = "InputPath2";
|
||||
// constexpr const char* KeyInputPath3 = "InputPath3";
|
||||
// constexpr const char* KeyInputPath4 = "InputPath4";
|
||||
|
||||
|
||||
constexpr const char* KeyLowerDomainBound = "LowerDomainBound";
|
||||
constexpr const char* KeyUpperDomainBound = "UpperDomainBound";
|
||||
|
||||
}
|
||||
|
||||
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<int> 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<int>(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<LeapSecond> 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<int>(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<double>() * glm::pi<double>();
|
||||
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<int>(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<int>(std::floor(daysInYear))
|
||||
);
|
||||
|
||||
// 5
|
||||
const double nSecondsEpochOffset = static_cast<double>(
|
||||
seconds(hours(12)).count()
|
||||
);
|
||||
|
||||
// Combine all of the values
|
||||
const double epoch = nSecondsSince2000 + nLeapSecondsOffset - nSecondsEpochOffset;
|
||||
return epoch;
|
||||
}
|
||||
|
||||
std::vector<KeplerParameters> readTLEFile(const std::string& filename){
|
||||
ghoul_assert(FileSys.fileExists(filename), "The filename must exist");
|
||||
|
||||
std::vector<KeplerParameters> data;
|
||||
|
||||
std::ifstream file;
|
||||
file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
file.open(filename);
|
||||
|
||||
int 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
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
glm::dvec3 cartesianToSphericalCoord(glm::dvec3 position){
|
||||
glm::dvec3 sphericalPosition;
|
||||
//sphericalPosition.x = pow(pow(position.x,2)+pow(position.y,2)+pow(position.z,2) , 0.5); //abs(position.x + position.y + position.z); // r
|
||||
//sphericalPosition.y = atan(position.y/position.x); // theta
|
||||
//sphericalPosition.z = atan(pow(pow(position.x,2)+pow(position.y,2),0.5)/position.z); // abs(position.x + position.y) // p
|
||||
|
||||
sphericalPosition.x = sqrt(pow(position.x,2)+pow(position.y,2)+pow(position.z,2)); // r [0, MaxApogee]
|
||||
sphericalPosition.y = acos(position.z/sphericalPosition.x); // theta [0, pi]
|
||||
sphericalPosition.z = atan2(position.y,position.x); // phi [-pi, pi] -> [0, 2*pi]
|
||||
// if(sphericalPosition.y < 0)
|
||||
sphericalPosition.z += 3.14159265358979323846264338327950288;
|
||||
return sphericalPosition;
|
||||
}
|
||||
|
||||
|
||||
std::vector<glm::dvec3> getPositionBuffer(std::vector<KeplerParameters> tleData, double timeInSeconds, std::string gridType) {
|
||||
|
||||
float minTheta = 0.0;
|
||||
float minPhi = 0.0;
|
||||
float maxTheta = 0.0;
|
||||
float maxPhi = 0.0;
|
||||
|
||||
std::vector<glm::dvec3> positionBuffer;
|
||||
for(const auto& orbit : tleData) {
|
||||
KeplerTranslation keplerTranslator;
|
||||
keplerTranslator.setKeplerElements(
|
||||
orbit.eccentricity,
|
||||
orbit.semiMajorAxis,
|
||||
orbit.inclination,
|
||||
orbit.ascendingNode,
|
||||
orbit.argumentOfPeriapsis,
|
||||
orbit.meanAnomaly,
|
||||
orbit.period,
|
||||
orbit.epoch
|
||||
);
|
||||
glm::dvec3 position = keplerTranslator.position({
|
||||
{},
|
||||
Time(timeInSeconds),
|
||||
Time(0.0),
|
||||
false
|
||||
});
|
||||
// LINFO(fmt::format("cart: {} ", position));
|
||||
glm::dvec3 sphPos;
|
||||
if( gridType == "Spherical"){
|
||||
sphPos = cartesianToSphericalCoord(position);
|
||||
|
||||
if(sphPos.y < minTheta){
|
||||
minTheta = sphPos.y;
|
||||
}
|
||||
if(sphPos.z < minPhi){
|
||||
minPhi = sphPos.z;
|
||||
}
|
||||
if(sphPos.y > maxTheta){
|
||||
maxTheta = sphPos.y;
|
||||
}
|
||||
if(sphPos.z > maxPhi){
|
||||
maxPhi = sphPos.z;
|
||||
}
|
||||
// LINFO(fmt::format("pos: {} ", sphPos));
|
||||
positionBuffer.push_back(sphPos);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
positionBuffer.push_back(position);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
LINFO(fmt::format("max theta: {} ", maxTheta));
|
||||
LINFO(fmt::format("max phi: {} ", maxPhi));
|
||||
LINFO(fmt::format("min theta: {} ", minTheta));
|
||||
LINFO(fmt::format("min phi: {} ", minPhi));
|
||||
|
||||
return positionBuffer;
|
||||
}
|
||||
|
||||
// std::vector<glm::dvec3> generatePositions(int numberOfPositions) {
|
||||
// std::vector<glm::dvec3> positions;
|
||||
|
||||
// float radius = 700000; // meter
|
||||
// float degreeStep = 360 / numberOfPositions;
|
||||
|
||||
// for(int i=0 ; i<= 360 ; i += degreeStep){
|
||||
// glm::dvec3 singlePosition = glm::dvec3(radius* sin(i), radius*cos(i), 0.0);
|
||||
// positions.push_back(singlePosition);
|
||||
// }
|
||||
// return positions;
|
||||
// }
|
||||
|
||||
float getDensityAt(glm::uvec3 cell, double* densityArray, RawVolume<float>& raw) {
|
||||
float value;
|
||||
// return value at position cell from _densityPerVoxel
|
||||
size_t index = raw.coordsToIndex(cell);
|
||||
value = static_cast<float>(densityArray[index]);
|
||||
//LINFO(fmt::format("indensity: {} ", index));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float getMaxApogee(std::vector<KeplerParameters> inData){
|
||||
double maxApogee = 0.0;
|
||||
for (const auto& dataElement : inData){
|
||||
double ah = dataElement.semiMajorAxis * (1 + dataElement.eccentricity);
|
||||
if (ah > maxApogee)
|
||||
maxApogee = ah;
|
||||
}
|
||||
|
||||
return static_cast<float>(maxApogee*1000); // * 1000 for meters
|
||||
}
|
||||
|
||||
int getIndexFromPosition(glm::dvec3 position, glm::uvec3 dim, float maxApogee, std::string gridType){
|
||||
// epsilon is to make sure that for example if newPosition.x/maxApogee = 1,
|
||||
// then the index for that dimension will not exceed the range of the grid.
|
||||
float epsilon = static_cast<float>(0.000000001);
|
||||
if(gridType == "Cartesian"){ //|| gridType == "Spherical"){
|
||||
glm::dvec3 newPosition = glm::dvec3(position.x + maxApogee
|
||||
,position.y + maxApogee
|
||||
,position.z + maxApogee);
|
||||
|
||||
glm::uvec3 coordinateIndex = glm::uvec3(static_cast<int>(newPosition.x * dim.x / (2 * (maxApogee + epsilon)))
|
||||
,static_cast<int>(newPosition.y * dim.y / (2 * (maxApogee + epsilon)))
|
||||
,static_cast<int>(newPosition.z * dim.z / (2 * (maxApogee + epsilon))));
|
||||
|
||||
|
||||
return coordinateIndex.z * (dim.x * dim.y) + coordinateIndex.y * dim.x + coordinateIndex.x;
|
||||
}
|
||||
else if(gridType == "Spherical"){
|
||||
|
||||
if(position.y >= 3.1415926535897932384626433832795028){
|
||||
position.y = 0;
|
||||
}
|
||||
if(position.z >= (2 * 3.1415926535897932384626433832795028)){
|
||||
position.z = 0;
|
||||
}
|
||||
|
||||
glm::uvec3 coordinateIndex = glm::uvec3(static_cast<int>(position.x * dim.x / (maxApogee))
|
||||
,static_cast<int>(position.y * dim.y / (3.14159265358979323846264338327950288))
|
||||
,static_cast<int>(position.z * dim.z / (2*3.14159265358979323846264338327950288)));
|
||||
|
||||
|
||||
// LINFO(fmt::format("index coords: {} ", coordinateIndex));
|
||||
// LINFO(fmt::format("index dim: {} ", dim));
|
||||
// LINFO(fmt::format("index va: {} ", coordinateIndex.y * (dim.x * dim.y) + coordinateIndex.z * dim.x + coordinateIndex.x));
|
||||
|
||||
return coordinateIndex.z * (dim.x * dim.y) + coordinateIndex.y * dim.x + coordinateIndex.x;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
double getVoxelVolume(int index, RawVolume<float>& raw, glm::uvec3 dim, float maxApogee){
|
||||
// get coords from index
|
||||
glm::uvec3 coords = raw.indexToCoords(index);
|
||||
|
||||
double rMax = maxApogee / dim.x;
|
||||
double thetaMax = 3.141592 / dim.y;
|
||||
double phiMax = (2 * 3.141592) / dim.z;
|
||||
//use coords to calc volume
|
||||
//integral(dTheta) * integral(r^2 dr) * integral(sin(phi) dPhi)
|
||||
double rIntegral = (pow(((coords.x + 1) * rMax),3) - pow(((coords.x) * rMax),3)) / 3;
|
||||
double thetaIntegral = -cos((coords.y + 1) * thetaMax) + cos(coords.y * thetaMax);
|
||||
double phiIntegral = ((coords.z + 1) - coords.z) * phiMax;
|
||||
|
||||
return rIntegral * thetaIntegral * phiIntegral;
|
||||
//return volume
|
||||
|
||||
}
|
||||
|
||||
double* mapDensityToVoxels(double* densityArray, std::vector<glm::dvec3> positions, glm::uvec3 dim, float maxApogee, std::string gridType, RawVolume<float>& raw) {
|
||||
|
||||
for(const glm::dvec3& position : positions) {
|
||||
//LINFO(fmt::format("pos: {} ", position));
|
||||
int index = getIndexFromPosition(position, dim, maxApogee, gridType);
|
||||
//LINFO(fmt::format("index: {} ", index));
|
||||
if(gridType == "Cartesian"){
|
||||
++densityArray[index];
|
||||
}
|
||||
else if(gridType == "Spherical"){
|
||||
double voxelVolume = getVoxelVolume(index, raw, dim, maxApogee); //something like this
|
||||
densityArray[index] += 1/voxelVolume;
|
||||
}
|
||||
}
|
||||
|
||||
return densityArray;
|
||||
}
|
||||
|
||||
GenerateDebrisVolumeTask::GenerateDebrisVolumeTask(const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"GenerateDebrisVolumeTask"
|
||||
);
|
||||
|
||||
_rawVolumeOutputPath = absPath(dictionary.value<std::string>(KeyRawVolumeOutput));
|
||||
_dictionaryOutputPath = absPath(dictionary.value<std::string>(KeyDictionaryOutput));
|
||||
_dimensions = dictionary.value<glm::vec3>(KeyDimensions); // must not be <glm::uvec3> for some reason.
|
||||
_startTime = dictionary.value<std::string>(KeyStartTime);
|
||||
_timeStep = dictionary.value<std::string>(KeyTimeStep); // Todo: send KeyTimeStep in as a int or float correctly.
|
||||
_endTime = dictionary.value<std::string>(KeyEndTime);
|
||||
// since _inputPath is past from task,
|
||||
// there will have to be either one task per dataset,
|
||||
// or you need to combine the datasets into one file.
|
||||
_inputPath = absPath(dictionary.value<std::string>(KeyInputPath));
|
||||
_gridType = dictionary.value<std::string>(KeyGridType);
|
||||
_lowerDomainBound = dictionary.value<glm::vec3>(KeyLowerDomainBound);
|
||||
_upperDomainBound = dictionary.value<glm::vec3>(KeyUpperDomainBound);
|
||||
|
||||
_TLEDataVector = readTLEFile(_inputPath);
|
||||
_maxApogee = getMaxApogee(_TLEDataVector);
|
||||
|
||||
}
|
||||
|
||||
std::string GenerateDebrisVolumeTask::description() {
|
||||
return "todo:: description";
|
||||
}
|
||||
|
||||
void GenerateDebrisVolumeTask::perform(const Task::ProgressCallback& progressCallback) {
|
||||
SpiceManager::KernelHandle kernel =
|
||||
SpiceManager::ref().loadKernel(absPath("${DATA}/assets/spice/naif0012.tls"));
|
||||
|
||||
defer {
|
||||
SpiceManager::ref().unloadKernel(kernel);
|
||||
};
|
||||
|
||||
//////////
|
||||
//1. read TLE-data and position of debris elements.
|
||||
// std::vector<KeplerParameters>TLEDataVector = readTLEFile(_inputPath);
|
||||
// std::vector<KeplerParameters>TLEDataVector1 = readTLEFile(_inputPath1);
|
||||
// std::vector<KeplerParameters>TLEDataVector2 = readTLEFile(_inputPath2);
|
||||
// std::vector<KeplerParameters>TLEDataVector3 = readTLEFile(_inputPath3);
|
||||
// std::vector<KeplerParameters>TLEDataVector4 = readTLEFile(_inputPath4);
|
||||
|
||||
// _TLEDataVector.reserve( TLEDataVector.size() + TLEDataVector1.size() + TLEDataVector2.size() + TLEDataVector3.size() + TLEDataVector4.size());
|
||||
// _TLEDataVector.insert(_TLEDataVector.end(), TLEDataVector.begin(), TLEDataVector.end());
|
||||
// _TLEDataVector.insert(_TLEDataVector.end(), TLEDataVector1.begin(), TLEDataVector1.end());
|
||||
// _TLEDataVector.insert(_TLEDataVector.end(), TLEDataVector2.begin(), TLEDataVector2.end());
|
||||
// _TLEDataVector.insert(_TLEDataVector.end(), TLEDataVector3.begin(), TLEDataVector3.end());
|
||||
// _TLEDataVector.insert(_TLEDataVector.end(), TLEDataVector4.begin(), TLEDataVector4.end());
|
||||
// ----- or ----- if only one
|
||||
|
||||
// _TLEDataVector = readTLEFile(_inputPath);
|
||||
|
||||
//////////
|
||||
VolumeGridType GridType = VolumeGridType::Cartesian;
|
||||
if(_gridType == "Spherical"){
|
||||
GridType = VolumeGridType::Spherical;
|
||||
}
|
||||
else if(_gridType != "Cartesian"){
|
||||
// TODO:: Error message
|
||||
return;
|
||||
}
|
||||
|
||||
// float maxApogee = getMaxApogee(_TLEDataVector);
|
||||
LINFO(fmt::format("Max Apogee: {} ", _maxApogee));
|
||||
|
||||
/** SEQUENCE
|
||||
* 1. handle timeStep
|
||||
* 1.1 either ignore last timeperiod from the latest whole timestep to _endTime
|
||||
* 1.2 or extend endTime to be equal to next full timestep
|
||||
* 2. loop to create a rawVolume for each timestep.
|
||||
*/
|
||||
|
||||
// 1 // todo: handle if endTime is earlyer than startTime
|
||||
double startTimeInSeconds = Time::convertTime(_startTime);
|
||||
double endTimeInSeconds = Time::convertTime(_endTime);
|
||||
double timeSpan = endTimeInSeconds - startTimeInSeconds;
|
||||
|
||||
float timeStep = std::stof(_timeStep);
|
||||
|
||||
// 1.1
|
||||
int numberOfIterations = static_cast<int>(timeSpan/timeStep);
|
||||
LINFO(fmt::format("timestep: {} ", numberOfIterations));
|
||||
|
||||
std::queue<volume::RawVolume<float>> rawVolumeQueue = {};
|
||||
const int size = _dimensions.x *_dimensions.y *_dimensions.z;
|
||||
float minVal = std::numeric_limits<float>::max();
|
||||
float maxVal = std::numeric_limits<float>::min();
|
||||
// 2.
|
||||
for(int i=0 ; i<=numberOfIterations ; ++i) {
|
||||
|
||||
std::vector<glm::dvec3> startPositionBuffer = getPositionBuffer(_TLEDataVector, startTimeInSeconds+(i*timeStep), _gridType); //+(i*timeStep)
|
||||
//LINFO(fmt::format("pos: {} ", startPositionBuffer[4]));
|
||||
|
||||
double *densityArrayp = new double[size]();
|
||||
//densityArrayp = mapDensityToVoxels(densityArrayp, generatedPositions, _dimensions, maxApogee);
|
||||
volume::RawVolume<float> rawVolume(_dimensions);
|
||||
|
||||
densityArrayp = mapDensityToVoxels(densityArrayp, startPositionBuffer, _dimensions, _maxApogee, _gridType, rawVolume);
|
||||
/*std::vector<glm::dvec3> testBuffer;
|
||||
testBuffer.push_back(glm::dvec3(0,0,0));
|
||||
testBuffer.push_back(glm::dvec3(1,1.5,1.5));
|
||||
testBuffer.push_back(glm::dvec3(1,3,3));
|
||||
testBuffer.push_back(glm::dvec3(3,5,3));
|
||||
//testBuffer.push_back(glm::dvec3(10000,1000000000,1000000000));
|
||||
|
||||
|
||||
densityArrayp = mapDensityToVoxels(densityArrayp, testBuffer, _dimensions, _maxApogee, _gridType);
|
||||
*/
|
||||
// create object rawVolume
|
||||
|
||||
//glm::vec3 domainSize = _upperDomainBound - _lowerDomainBound;
|
||||
|
||||
// TODO: Create a forEachSatallite and set(cell, value) to combine mapDensityToVoxel
|
||||
// and forEachVoxel for less time complexity.
|
||||
rawVolume.forEachVoxel([&](glm::uvec3 cell, float) {
|
||||
// glm::vec3 coord = _lowerDomainBound +
|
||||
// glm::vec3(cell) / glm::vec3(_dimensions) * domainSize;
|
||||
float value = getDensityAt(cell, densityArrayp, rawVolume); // (coord)
|
||||
|
||||
rawVolume.set(cell, value);
|
||||
|
||||
minVal = std::min(minVal, value);
|
||||
maxVal = std::max(maxVal, value);
|
||||
/*LINFO(fmt::format("min: {} ", minVal));
|
||||
LINFO(fmt::format("max: {} ", maxVal));*/
|
||||
});
|
||||
rawVolumeQueue.push(rawVolume);
|
||||
delete[] densityArrayp;
|
||||
}
|
||||
|
||||
// two loops is used to get a global min and max value for voxels.
|
||||
for(int i=0 ; i<=numberOfIterations ; ++i){
|
||||
// LINFO(fmt::format("raw file output name: {} ", _rawVolumeOutputPath));
|
||||
|
||||
size_t lastIndex = _rawVolumeOutputPath.find_last_of(".");
|
||||
std::string rawOutputName = _rawVolumeOutputPath.substr(0, lastIndex);
|
||||
rawOutputName += std::to_string(i) + ".rawvolume";
|
||||
|
||||
lastIndex = _dictionaryOutputPath.find_last_of(".");
|
||||
std::string dictionaryOutputName = _dictionaryOutputPath.substr(0, lastIndex);
|
||||
dictionaryOutputName += std::to_string(i) + ".dictionary";
|
||||
|
||||
ghoul::filesystem::File file(rawOutputName);
|
||||
const std::string directory = file.directoryName();
|
||||
if (!FileSys.directoryExists(directory)) {
|
||||
FileSys.createDirectory(directory, ghoul::filesystem::FileSystem::Recursive::Yes);
|
||||
}
|
||||
|
||||
volume::RawVolumeWriter<float> writer(rawOutputName);
|
||||
writer.write(rawVolumeQueue.front());
|
||||
rawVolumeQueue.pop();
|
||||
|
||||
RawVolumeMetadata metadata;
|
||||
// alternatively metadata.hasTime = false;
|
||||
metadata.time = Time::convertTime(_startTime)+(i*timeStep);
|
||||
metadata.dimensions = _dimensions;
|
||||
metadata.hasDomainUnit = false;
|
||||
metadata.hasValueUnit = false;
|
||||
metadata.gridType = GridType;
|
||||
metadata.hasDomainBounds = true;
|
||||
metadata.lowerDomainBound = _lowerDomainBound;
|
||||
metadata.upperDomainBound = _upperDomainBound;
|
||||
metadata.hasValueRange = true;
|
||||
metadata.minValue = minVal;
|
||||
metadata.maxValue = maxVal;
|
||||
|
||||
/*LINFO(fmt::format("min2: {} ", minVal));
|
||||
LINFO(fmt::format("max2: {} ", maxVal));*/
|
||||
|
||||
ghoul::Dictionary outputDictionary = metadata.dictionary();
|
||||
ghoul::DictionaryLuaFormatter formatter;
|
||||
std::string metadataString = formatter.format(outputDictionary);
|
||||
|
||||
std::fstream f(dictionaryOutputName, std::ios::out);
|
||||
f << "return " << metadataString;
|
||||
f.close();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
documentation::Documentation GenerateDebrisVolumeTask::documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"GenerateDebrisVolumeTask",
|
||||
"generate_debris_volume_task",
|
||||
{
|
||||
{
|
||||
"Type",
|
||||
new StringEqualVerifier("GenerateDebrisVolumeTask"),
|
||||
Optional::No,
|
||||
"The type of this task",
|
||||
},
|
||||
{
|
||||
KeyStartTime,
|
||||
new StringAnnotationVerifier("start time"),
|
||||
Optional::No,
|
||||
"start time",
|
||||
},
|
||||
{
|
||||
KeyInputPath,
|
||||
new StringAnnotationVerifier("A valid filepath"),
|
||||
Optional::No,
|
||||
"Input path to the TLE-data",
|
||||
},
|
||||
{
|
||||
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
|
||||
80
modules/space/tasks/generatedebrisvolumetask.h
Normal file
80
modules/space/tasks/generatedebrisvolumetask.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* 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 <openspace/util/task.h>
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
#include <modules/space/rendering/renderablesatellites.h>
|
||||
#include <modules/space/translation/keplertranslation.h>
|
||||
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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();
|
||||
|
||||
std::string _gridType;
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
std::string _rawVolumeOutputPath;
|
||||
std::string _dictionaryOutputPath;
|
||||
std::string _startTime;
|
||||
std::string _timeStep;
|
||||
std::string _endTime;
|
||||
std::string _inputPath;
|
||||
|
||||
glm::uvec3 _dimensions;
|
||||
glm::vec3 _lowerDomainBound;
|
||||
glm::vec3 _upperDomainBound;
|
||||
|
||||
std::vector<KeplerParameters> _TLEDataVector;
|
||||
|
||||
float _maxApogee;
|
||||
|
||||
// not sure if it should be local function or hidden function.
|
||||
//std::vector<KeplerParameters> readTLEFile(const std::string& filename);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace volume
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_SPACE___GENERATEDEBRISVOLUMETASK___H__
|
||||
@@ -290,7 +290,7 @@ glm::dvec3 KeplerTranslation::position(const UpdateData& data) const {
|
||||
_orbitPlaneDirty = false;
|
||||
}
|
||||
|
||||
const double t = data.time.j2000Seconds() - _epoch;
|
||||
const double t = data.time.j2000Seconds() -_epoch;
|
||||
const double meanMotion = glm::two_pi<double>() / _period;
|
||||
const double meanAnomaly = glm::radians(_meanAnomalyAtEpoch.value()) + t * meanMotion;
|
||||
const double e = eccentricAnomaly(meanAnomaly);
|
||||
|
||||
@@ -28,8 +28,10 @@
|
||||
#include <openspace/scene/translation.h>
|
||||
|
||||
#include <openspace/properties/scalar/doubleproperty.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/misc/exception.h>
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
@@ -76,11 +78,7 @@ public:
|
||||
* be passed to the constructor
|
||||
*/
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
protected:
|
||||
/// Default construct that initializes all the properties and member variables
|
||||
KeplerTranslation();
|
||||
|
||||
|
||||
/**
|
||||
* Sets the internal values for the Keplerian elements and the epoch as a string of
|
||||
* the form YYYY MM DD HH:mm:ss.
|
||||
@@ -122,11 +120,19 @@ protected:
|
||||
void setKeplerElements(double eccentricity, double semiMajorAxis, double inclination,
|
||||
double ascendingNode, double argumentOfPeriapsis, double meanAnomalyAtEpoch,
|
||||
double orbitalPeriod, double epoch);
|
||||
|
||||
/// Default construct that initializes all the properties and member variables
|
||||
KeplerTranslation();
|
||||
|
||||
private:
|
||||
/// Recombutes the rotation matrix used in the update method
|
||||
void computeOrbitPlane() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
/**
|
||||
* This method computes the eccentric anomaly (location of the space craft taking the
|
||||
* eccentricity into acount) based on the mean anomaly (location of the space craft
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <ghoul/misc/defer.h>
|
||||
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -53,6 +53,7 @@ Asset = "default"
|
||||
-- Asset = "insight"
|
||||
-- Asset = "apollo8"
|
||||
-- Asset = "apollo_sites"
|
||||
-- Asset = "satellites"
|
||||
|
||||
-- These scripts are executed after the initialization of each scene, thus making
|
||||
-- it possible to have global overrides to default values or execute other scripts
|
||||
|
||||
Reference in New Issue
Block a user