Merge pull request #951 from OpenSpace/feature/satellitesgroupednodes

Pull code from 2019 space debris thesis into Master
This commit is contained in:
Alexander Bock
2019-08-19 03:45:30 -06:00
committed by GitHub
71 changed files with 2261 additions and 743 deletions

View File

@@ -35,4 +35,4 @@ local volume = {
}
local objects = { volume }
assetHelper.registerSceneGraphNodes(asset, objects)
assetHelper.registerSceneGraphNodes(asset, objects)

View 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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -1,3 +1,4 @@
asset.request('./debris/debris_asat')
asset.request('./debris/debris_breezem')
asset.request('./debris/debris_fengyun')
asset.request('./debris/debris_iridium33')

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View 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)

View 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"
}}

View 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"
}}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View 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);
}
}

View 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__

View 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;
}

View 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;
}

View File

@@ -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(),

View 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

View 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__

View File

@@ -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);

View File

@@ -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

View File

@@ -40,6 +40,7 @@
#include <ghoul/misc/dictionaryluaformatter.h>
#include <ghoul/misc/defer.h>
#include <fstream>
namespace {

View File

@@ -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