diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac3c0cf925..dfe4464edc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -148,7 +148,7 @@ if (APPLE)
find_library(COCOA_LIBRARY Carbon)
find_library(APP_SERVICES_LIBRARY ApplicationServices)
mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY APP_SERVICES_LIBRARY)
- target_link_libraries(openspace-core ${CARBON_LIBRARY} ${COREFOUNDATION_LIBRARY}
+ target_link_libraries(openspace-core PUBLIC ${CARBON_LIBRARY} ${COREFOUNDATION_LIBRARY}
${COCOA_LIBRARY} ${APP_SERVICES_LIBRARY})
end_dependency()
endif ()
diff --git a/data/assets/base.asset b/data/assets/base.asset
index 86bdf3cbd6..f0cb420c35 100644
--- a/data/assets/base.asset
+++ b/data/assets/base.asset
@@ -23,6 +23,8 @@ asset.require('scene/milkyway/milkyway/volume')
asset.require('scene/milkyway/constellations/constellation_art')
asset.require('scene/milkyway/constellations/constellation_keybinds')
+assetHelper.requireAll(asset, 'scene/milkyway/exoplanets')
+
assetHelper.requireAll(asset, 'scene/digitaluniverse')
-- Load default key bindings applicable to most scenes
diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset
new file mode 100644
index 0000000000..b49f091844
--- /dev/null
+++ b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset
@@ -0,0 +1,7 @@
+local DataPath = asset.syncedResource({
+ Name = "Exoplanet Data Files",
+ Type = "HttpSynchronization",
+ Identifier = "exoplanets_data",
+ Version = 1
+})
+asset.export("DataPath", DataPath)
diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset
new file mode 100644
index 0000000000..287b29d61e
--- /dev/null
+++ b/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset
@@ -0,0 +1,7 @@
+local TexturesPath = asset.syncedResource({
+ Name = "Exoplanet Textures",
+ Type = "HttpSynchronization",
+ Identifier = "exoplanets_textures",
+ Version = 1
+})
+asset.export("TexturesPath", TexturesPath)
diff --git a/data/assets/scene/milkyway/objects/orionnebula/cluster.asset b/data/assets/scene/milkyway/objects/orionnebula/cluster.asset
new file mode 100644
index 0000000000..843ca22825
--- /dev/null
+++ b/data/assets/scene/milkyway/objects/orionnebula/cluster.asset
@@ -0,0 +1,51 @@
+--orionnebula/cluster.asset
+local assetHelper = asset.require('util/asset_helper')
+local transforms = asset.require("./transforms")
+
+local sync = asset.syncedResource({
+ Name = "Orion Nebula Star Cluster",
+ Type = "HttpSynchronization",
+ Identifier = "orion_nebula_star_cluster",
+ Version = 1
+})
+
+local OrionClusterStars = {
+ Identifier = "OrionClusterStars",
+ Parent = transforms.NebulaPosition.Identifier,
+ Renderable = {
+ Type = "RenderableStars",
+ File = sync .. "/oricluster.speck",
+ Texture = sync .. "/halo.png",
+ Texture = sync .. "/colorbv.cmap",
+ MagnitudeExponent = 5.02,
+ SizeComposition = "Distance Modulus",
+ RenderMethod = "Texture Based"
+ },
+ GUI = {
+ Name = "Orion Nebula Star Cluster",
+ Path = "/Milky Way/Stars"
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, { OrionClusterStars })
+
+asset.meta = {
+ Name = "Orion Nebula Star Cluster",
+ Version = "1.0",
+ Description = [[ In order to have an accurate depiction of the Orion nebula, we need
+to include the star cluster that was birthed from it. We turned to a study of the
+cluster's stellar population by Lynne Hillenbrand, who was working at the University of
+California, Berkeley at the time. The catalog from her paper contains more than 1500
+stars, about half the stars in the actual cluster. The cluster is very crowded, with a
+peak density of 10000 stars per cubic parsec over a wide range of masses from a tenth the
+sun's mass up to 50 times its mass. We were presented with one problem: there are no
+distances. For the stellar distances, we needed to deduce them by statistical methods.
+Knowing the size of the cluster and approximating the shape to be roughly spherical, we
+placed each star along a line of sight through this imaginary sphere centered on the
+cluster. In this sense, these data are observed data and the view from Earth is accurate.
+But the distance of each star has been derived from this educated-guess approach for the
+cluster distribution. ]],
+ Author = "AMNH Digital Universe",
+ URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
+ License = "custom"
+}
diff --git a/data/assets/scene/milkyway/objects/orionnebula/nebula.asset b/data/assets/scene/milkyway/objects/orionnebula/nebula.asset
new file mode 100644
index 0000000000..24e8c2eaa3
--- /dev/null
+++ b/data/assets/scene/milkyway/objects/orionnebula/nebula.asset
@@ -0,0 +1,157 @@
+local assetHelper = asset.require('util/asset_helper')
+local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
+local transforms = asset.require('./transforms')
+
+local center = sunTransforms.SolarSystemBarycenter.Identifier;
+local LIGHTS = assetHelper.getDefaultLightSources(center);
+
+local sync = asset.syncedResource({
+ Name = "Orion Nebula Model",
+ Type = "HttpSynchronization",
+ Identifier = "orion_nebula_model",
+ Version = 1
+})
+
+local NebulaHolder = {
+ Identifier = "OrionNebulaHolder",
+ Parent = transforms.NebulaPosition.Identifier,
+ Transform = {
+ Scale = {
+ Type = "StaticScale",
+ Scale = 35999998699110400.000000
+ },
+ Rotation = {
+ Type = "FixedRotation",
+ Attached = "OrionNebulaHolder",
+ XAxis = {1.000000,1.000000,0.510000},
+ XAxisOrthogonal = true,
+ YAxis = "Sun",
+ YAxisInverted = false
+ }
+ },
+ GUI = {
+ Name = "Orion Nebula",
+ Path = "/Milky Way/Objects",
+ }
+}
+
+local OrionNebulaModel = {
+ Identifier = "OrionNebulaModel",
+ Parent = NebulaHolder.Identifier,
+ Transform = {
+ Scale = {
+ Type = "StaticScale",
+ Scale = 0.67500000
+ }
+ },
+ Renderable = {
+ Type = "RenderableModel",
+ Geometry = {{
+ Type = "MultiModelGeometry",
+ GeometryFile = sync .. "/orion_nebula.obj",
+ ColorTexture = sync .. "/heic0601a_masked.png"
+ }},
+ Opacity = 1.0,
+ DisableFaceCulling = false,
+ SpecularIntensity = 0.0,
+ AmbientIntensity = 0.45,
+ DiffuseIntensity = 0.0,
+ RotationVector = { 0.000000, 22.300000, 0.000000 },
+ LightSources = LIGHTS;
+ },
+ GUI = {
+ Name = "Orion Nebula Model",
+ Path = "/Milky Way/Objects",
+ Hidden = true
+ }
+}
+
+local OrionNebulaShocksModel = {
+ Identifier = "OrionNebulaShocksModel",
+ Parent = NebulaHolder.Identifier,
+ Transform = {
+ Scale = {
+ Type = "StaticScale",
+ Scale = 0.67500000
+ }
+ },
+ Renderable = {
+ Type = "RenderableModel",
+ Geometry = {{
+ Type = "MultiModelGeometry",
+ GeometryFile = sync .. "/orishocks.obj",
+ ColorTexture = "${DATA}/colors/pink.png"
+ }},
+ Opacity = 1.0,
+ DisableFaceCulling = false,
+ SpecularIntensity = 0.0,
+ AmbientIntensity = 0.19,
+ DiffuseIntensity = 0.4,
+ RotationVector = { 0.000000, 22.300000, 0.000000 },
+ LightSources = LIGHTS;
+ },
+ GUI = {
+ Name = "Orion Nebula Shocks",
+ Path = "/Milky Way/Objects",
+ Hidden = false
+ }
+}
+
+local OrionNebulaProplydsModel = {
+ Identifier = "OrionNebulaProplydsModel",
+ Parent = NebulaHolder.Identifier,
+ Transform = {
+ Scale = {
+ Type = "StaticScale",
+ Scale = 0.67500000
+ }
+ },
+ Renderable = {
+ Type = "RenderableModel",
+ Geometry = {{
+ Type = "MultiModelGeometry",
+ GeometryFile = sync .. "/proplyds.obj",
+ ColorTexture = "${DATA}/colors/pink.png"
+ }},
+ Opacity = 1.0,
+ DisableFaceCulling = false,
+ SpecularIntensity = 0.0,
+ AmbientIntensity = 1.0,
+ DiffuseIntensity = 1.0,
+ RotationVector = { 0.000000, 22.300000, 0.000000 },
+ LightSources = LIGHTS;
+ },
+ GUI = {
+ Name = "Orion Nebula Proplyds",
+ Path = "/Milky Way/Objects",
+ Hidden = false
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, {
+ NebulaHolder,
+ OrionNebulaModel,
+ OrionNebulaShocksModel,
+ OrionNebulaProplydsModel
+})
+
+asset.meta = {
+ Name = "Orion Nebula Model",
+ Version = "1.0",
+ Description = [[ In the Digital Universe model of the Orion Nebula, we depict the
+ionization front effectively as a terrain, with a flat Hubble image of the nebula mapped
+on the undulating surface. In reality, the ionization front has a slight thickness to
+it - about a third of a light year - but is quite thin compared to the overall size of
+the nebula, which stretches about ten light years from side to side.
Close into
+the center, we see small teardrop-shaped structures with their narrow ends pointing away
+from the bright star: these are protoplanetary disks, or proplyds, of dense gas and dust
+surrounding young stars. The larger formations that one sees farther away from the center
+of the nebula take on a cup-like shape, with the narrow end pointing away from the
+nebulas center. These enormous structures are bow shocks that delineate the region where
+highspeed winds from the central star slow from supersonic to subsonic speeds. You can
+think of an HII region as a sort of tremendous explosion, taking place over millennia,
+and the bow shocks are part of the outward rush of material. ]],
+ Author = "AMNH Digital Universe",
+ URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
+ License = "custom"
+}
diff --git a/data/assets/scene/milkyway/objects/orionnebula/orionnebula.asset b/data/assets/scene/milkyway/objects/orionnebula/orionnebula.asset
new file mode 100644
index 0000000000..34df0dacc9
--- /dev/null
+++ b/data/assets/scene/milkyway/objects/orionnebula/orionnebula.asset
@@ -0,0 +1,2 @@
+asset.require('./cluster')
+asset.require('./nebula')
diff --git a/data/assets/scene/milkyway/objects/orionnebula/transforms.asset b/data/assets/scene/milkyway/objects/orionnebula/transforms.asset
new file mode 100644
index 0000000000..15bc241234
--- /dev/null
+++ b/data/assets/scene/milkyway/objects/orionnebula/transforms.asset
@@ -0,0 +1,26 @@
+local assetHelper = asset.require('util/asset_helper')
+local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
+
+local PARSEC_CONSTANT = 3.0856776E16;
+
+local NebulaPosition = {
+ Identifier = "NebulaPosition",
+ Parent = sunTransforms.SolarSystemBarycenter.Identifier,
+ Transform = {
+ Translation = {
+ Type = "StaticTranslation",
+ Position = {
+ -329.915 * PARSEC_CONSTANT,
+ -183.153 * PARSEC_CONSTANT,
+ -132.706 * PARSEC_CONSTANT
+ }
+ },
+ },
+ GUI = {
+ Name = "Orion Nebula Position",
+ Path = "/Milky Way/Objects",
+ Hidden = true
+ }
+}
+
+assetHelper.registerSceneGraphNodesAndExport(asset, { NebulaPosition })
diff --git a/data/assets/scene/solarsystem/planets/earth/default_layers.asset b/data/assets/scene/solarsystem/planets/earth/default_layers.asset
index d1ad5753a3..21410493d5 100644
--- a/data/assets/scene/solarsystem/planets/earth/default_layers.asset
+++ b/data/assets/scene/solarsystem/planets/earth/default_layers.asset
@@ -7,7 +7,7 @@ local waterMasksPath = "./layers/watermasks"
-- Color layers
local colorLayer = asset.require(colorLayersPath .. "/esri_viirs_combo")
asset.require(colorLayersPath .. "/esri_world_imagery")
-asset.require(colorLayersPath .. "/esri_imagery_world_2d")
+asset.require(colorLayersPath .. "/esri_imagery_world_2D")
asset.require(colorLayersPath .. "/viirs_snpp_temporal")
asset.require(colorLayersPath .. "/aqua_modis_temporal")
asset.require(colorLayersPath .. "/terra_modis_temporal")
diff --git a/data/colors/pink.png b/data/colors/pink.png
new file mode 100644
index 0000000000..bcf3e40111
Binary files /dev/null and b/data/colors/pink.png differ
diff --git a/data/tasks/exoplanets/csvtobin.task b/data/tasks/exoplanets/csvtobin.task
new file mode 100644
index 0000000000..1ae7a44c6b
--- /dev/null
+++ b/data/tasks/exoplanets/csvtobin.task
@@ -0,0 +1,12 @@
+local dataFolder = "${BASE}/modules/exoplanets"
+return {
+ {
+ Type = "ExoplanetsCsvToBinTask",
+
+ InputCSV = dataFolder .. "/exoplanets.csv",
+ InputSPECK = "${SYNC}/http/digitaluniverse_exoplanets_speck/1/expl.speck",
+ TeffToBvFile = "${SYNC}/http/exoplanets_data/1/teff_bv.txt",
+ OutputBIN = dataFolder .. "/exoplanets_data.bin",
+ OutputLUT = dataFolder .. "/lookup.txt"
+ }
+}
diff --git a/data/web/documentation/scenelicense.hbs b/data/web/documentation/scenelicense.hbs
index ee9bce0479..b4b0828d8d 100644
--- a/data/web/documentation/scenelicense.hbs
+++ b/data/web/documentation/scenelicense.hbs
@@ -4,7 +4,7 @@
Asset - {{name}}
-
{{description}}
+
{{{description}}}
Version - {{version}}
Author - {{author}}
Associated URL - {{url}}
diff --git a/data/web/documentation/script.js b/data/web/documentation/script.js
index de1f726e0a..ba8e45eb4b 100644
--- a/data/web/documentation/script.js
+++ b/data/web/documentation/script.js
@@ -127,6 +127,15 @@ window.onload = function () {
}
}
+ if (documentation[i].identifier == "sceneLicense") {
+ for (var j = 0; j < documentation[i].data.length; j++) {
+ var escaped = documentation[i].data[j].description.replace(
+ /\\n/g, ""
+ );
+ documentation[i].data[j].description = escaped;
+ }
+ }
+
}
currentDocumentation = documentation[3];
diff --git a/ext/ghoul b/ext/ghoul
index 44420f45cb..f568acc5fe 160000
--- a/ext/ghoul
+++ b/ext/ghoul
@@ -1 +1 @@
-Subproject commit 44420f45cba1738847046b70b29b25e28c3284ef
+Subproject commit f568acc5fee29a5b0c654f183baddcb7a061e7a6
diff --git a/include/openspace/util/distanceconstants.h b/include/openspace/util/distanceconstants.h
index 8bb599cc04..e488cce1f9 100644
--- a/include/openspace/util/distanceconstants.h
+++ b/include/openspace/util/distanceconstants.h
@@ -27,6 +27,8 @@
namespace openspace::distanceconstants {
constexpr double EarthRadius = 6371;
+ constexpr double JupiterRadius = 7.1492E7;
+ constexpr double SolarRadius = 6.95700E8;
constexpr double LightYear = 9.4607304725808E15;
constexpr double LightMonth = LightYear / 12;
constexpr double LightDay = LightYear / 365;
diff --git a/include/openspace/util/memorymanager.h b/include/openspace/util/memorymanager.h
index 6d202f15ee..7fa289263c 100644
--- a/include/openspace/util/memorymanager.h
+++ b/include/openspace/util/memorymanager.h
@@ -26,7 +26,6 @@
#define __OPENSPACE_CORE___MEMORYMANAGER___H__
#include
-#include
namespace openspace {
diff --git a/modules/base/rendering/renderablelabels.cpp b/modules/base/rendering/renderablelabels.cpp
index 9ad0172359..c435137a97 100644
--- a/modules/base/rendering/renderablelabels.cpp
+++ b/modules/base/rendering/renderablelabels.cpp
@@ -206,12 +206,6 @@ documentation::Documentation RenderableLabels::Documentation() {
Optional::Yes,
LabelColorInfo.description,
},
- {
- LabelColorInfo.identifier,
- new DoubleVector4Verifier,
- Optional::Yes,
- LabelColorInfo.description,
- },
{
LabelTextInfo.identifier,
new StringVerifier,
@@ -397,7 +391,7 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary)
_labelColor.setViewOption(properties::Property::ViewOptions::Color);
if (dictionary.hasKey(LabelColorInfo.identifier)) {
- _labelColor = dictionary.value(LabelColorInfo.identifier);
+ _labelColor = dictionary.value(LabelColorInfo.identifier);
}
addProperty(_labelColor);
diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp
index dd6095e862..54a9dc6649 100644
--- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp
+++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp
@@ -850,7 +850,7 @@ void RenderableBillboardsCloud::renderBillboards(const RenderData& data,
if (_hasPolygon) {
glBindTexture(GL_TEXTURE_2D, _pTexture);
}
- else {
+ else if (_spriteTexture) {
_spriteTexture->bind();
}
_program->setUniform(_uniformCache.spriteTexture, textureUnit);
@@ -867,7 +867,6 @@ void RenderableBillboardsCloud::renderBillboards(const RenderData& data,
global::renderEngine.openglStateCache().resetBlendState();
global::renderEngine.openglStateCache().resetDepthState();
-
}
void RenderableBillboardsCloud::renderLabels(const RenderData& data,
@@ -902,7 +901,7 @@ void RenderableBillboardsCloud::renderLabels(const RenderData& data,
}
glm::vec4 textColor = glm::vec4(
- glm::vec3(_textColor),
+ glm::vec3(_textColor),
_textOpacity * fadeInVariable
);
diff --git a/modules/exoplanets/CMakeLists.txt b/modules/exoplanets/CMakeLists.txt
new file mode 100644
index 0000000000..3a1902cb9f
--- /dev/null
+++ b/modules/exoplanets/CMakeLists.txt
@@ -0,0 +1,55 @@
+##########################################################################################
+# #
+# OpenSpace #
+# #
+# Copyright (c) 2014-2020 #
+# #
+# 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(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
+
+set(HEADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetshelper.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetsmodule.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableorbitdisc.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/tasks/exoplanetscsvtobintask.h
+)
+source_group("Header Files" FILES ${HEADER_FILES})
+
+set(SOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetshelper.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetsmodule.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/exoplanetsmodule_lua.inl
+ ${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableorbitdisc.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/tasks/exoplanetscsvtobintask.cpp
+)
+source_group("Source Files" FILES ${SOURCE_FILES})
+
+set(SHADER_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/shaders/orbitdisc_fs.glsl
+ ${CMAKE_CURRENT_SOURCE_DIR}/shaders/orbitdisc_vs.glsl
+)
+source_group("Shader Files" FILES ${SHADER_FILES})
+
+create_new_module(
+ "Exoplanets"
+ exoplanets_module
+ STATIC
+ ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES}
+)
diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp
new file mode 100644
index 0000000000..62adafc80d
--- /dev/null
+++ b/modules/exoplanets/exoplanetshelper.cpp
@@ -0,0 +1,127 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this *
+ * software and associated documentation files (the "Software"), to deal in the Software *
+ * without restriction, including without limitation the rights to use, copy, modify, *
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to the following *
+ * conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in all copies *
+ * or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ ****************************************************************************************/
+
+#include
+
+#include
+
+namespace openspace::exoplanets {
+
+std::string_view speckStarName(std::string_view csvName) {
+ if (csvName == "HD 1237") { return "GJ 3021"; }
+ if (csvName == "MOA-2009-BLG-387L") { return "MOA 2009-BLG-387L"; }
+ if (csvName == "HD 126614 A") { return "HD 126614"; }
+ if (csvName == "epsilon Ret") { return "HD 27442"; }
+ if (csvName == "PH-1") { return "PH1"; }
+ if (csvName == "gamma Leo A") { return "gam 1 Leo"; }
+ if (csvName == "OGLE-2007-BLG-368L") { return "OGLE 2007-BLG-368L"; }
+ if (csvName == "alpha Ari") { return "alf Ari"; }
+ if (csvName == "mu Ara") { return "HD 160691"; }
+ if (csvName == "OGLE-05-169L") { return "OGLE 2005-BLG-169L"; }
+ if (csvName == "tau Gru") { return "HD 216435"; }
+ if (csvName == "iota Hor") { return "HR 810"; }
+ if (csvName == "OGLE-05-071L") { return "OGLE 2005-BLG-71L"; }
+ if (csvName == "OGLE235-MOA53") { return "OGLE 2003-BLG-235L"; }
+ if (csvName == "MOA-2008-BLG-310L") { return "MOA 2008-BLG-310L"; }
+ if (csvName == "KIC 11442793") { return "KOI-351"; }
+ if (csvName == "OGLE-2006-BLG-109L") { return "OGLE 2006-BLG-109L"; }
+ if (csvName == "HD 137388") { return "HD 137388 A"; }
+ if (csvName == "kappa CrB") { return "kap CrB"; }
+ if (csvName == "XO-2") { return "XO-2 N"; }
+ if (csvName == "epsilon Tau") { return "eps Tau"; }
+ if (csvName == "epsilon Eri") { return "eps Eri"; }
+ if (csvName == "Kepler-448") { return "KOI-12"; }
+ if (csvName == "omega Ser") { return "ome Ser"; }
+ if (csvName == "MOA-2010-BLG-477L") { return "MOA 2010-BLG-477L"; }
+ if (csvName == "GJ 176") { return "HD 285968"; }
+ if (csvName == "HIP 2247") { return "BD-17 63"; }
+ if (csvName == "MOA-2009-BLG-266L") { return "MOA 2009-BLG-266L"; }
+ if (csvName == "Kepler-89") { return "KOI-94"; }
+ if (csvName == "iota Dra") { return "HIP 75458"; }
+ if (csvName == "MOA-2007-BLG-400L") { return "MOA 2007-BLG-400L"; }
+ if (csvName == "upsilon And") { return "ups And"; }
+ if (csvName == "OGLE-2011-BLG-0251") { return "OGLE 2011-BLG-251L"; }
+ if (csvName == "OGLE-05-390L") { return "OGLE 2005-BLG-390L"; }
+ if (csvName == "Kepler-420") { return "KOI-1257"; }
+ if (csvName == "beta Pic") { return "bet Pic"; }
+ if (csvName == "gamma Cep") { return "gam Cep"; }
+ if (csvName == "MOA-2007-BLG-192L") { return "MOA 2007-BLG-192L"; }
+ if (csvName == "MOA-2009-BLG-319L") { return "MOA 2009-BLG-319L"; }
+ if (csvName == "omicron CrB") { return "omi CrB"; }
+ if (csvName == "beta Gem") { return "HD 62509"; }
+ if (csvName == "epsilon CrB") { return "eps CrB"; }
+ if (csvName == "omicron UMa") { return "omi UMa"; }
+ if (csvName == "HD 142022") { return "HD 142022 A"; }
+ return csvName;
+}
+
+std::string_view csvStarName(std::string_view name) {
+ if (name == "GJ 3021") { return "HD 1237"; }
+ if (name == "MOA 2009-BLG-387L") { return "MOA-2009-BLG-387L"; }
+ if (name == "HD 126614") { return "HD 126614 A"; }
+ if (name == "HD 27442") { return "epsilon Ret"; }
+ if (name == "PH1") { return "PH-1"; }
+ if (name == "gam 1 Leo") { return "gamma Leo A"; }
+ if (name == "OGLE 2007-BLG-368L") { return "OGLE-2007-BLG-368L"; }
+ if (name == "alf Ari") { return "alpha Ari"; }
+ if (name == "HD 160691") { return "mu Ara"; }
+ if (name == "OGLE 2005-BLG-169L") { return "OGLE-05-169L"; }
+ if (name == "HD 216435") { return "tau Gru"; }
+ if (name == "HR 810") { return "iota Hor"; }
+ if (name == "OGLE 2005-BLG-71L") { return "OGLE-05-071L"; }
+ if (name == "OGLE 2003-BLG-235L") { return "OGLE235-MOA53"; }
+ if (name == "MOA 2008-BLG-310L") { return "MOA-2008-BLG-310L"; }
+ if (name == "KOI-351") { return "KIC 11442793"; }
+ if (name == "OGLE 2006-BLG-109L") { return "OGLE-2006-BLG-109L"; }
+ if (name == "HD 137388 A") { return "HD 137388"; }
+ if (name == "kap CrB") { return "kappa CrB"; }
+ if (name == "XO-2 N") { return "XO-2"; }
+ if (name == "eps Tau") { return "epsilon Tau"; }
+ if (name == "eps Eri") { return "epsilon Eri"; }
+ if (name == "KOI-12") { return "Kepler-448"; }
+ if (name == "ome Ser") { return "omega Ser"; }
+ if (name == "MOA 2010-BLG-477L") { return "MOA-2010-BLG-477L"; }
+ if (name == "HD 285968") { return "GJ 176"; }
+ if (name == "BD-17 63") { return "HIP 2247"; }
+ if (name == "MOA 2009-BLG-266L") { return "MOA-2009-BLG-266L"; }
+ if (name == "KOI-94") { return "Kepler-89"; }
+ if (name == "HIP 75458") { return "iota Dra"; }
+ if (name == "MOA 2007-BLG-400L") { return "MOA-2007-BLG-400L"; }
+ if (name == "ups And") { return "upsilon And"; }
+ if (name == "OGLE 2011-BLG-251L") { return "OGLE-2011-BLG-0251"; }
+ if (name == "OGLE 2005-BLG-390L") { return "OGLE-05-390L"; }
+ if (name == "KOI-1257") { return "Kepler-420"; }
+ if (name == "bet Pic") { return "beta Pic"; }
+ if (name == "gam Cep") { return "gamma Cep"; }
+ if (name == "MOA 2007-BLG-192L") { return "MOA-2007-BLG-192L"; }
+ if (name == "MOA 2009-BLG-319L") { return "MOA-2009-BLG-319L"; }
+ if (name == "omi CrB") { return "omicron CrB"; }
+ if (name == "HD 62509") { return "beta Gem"; }
+ if (name == "eps CrB") { return "epsilon CrB"; }
+ if (name == "omi UMa") { return "omicron UMa"; }
+ if (name == "HD 142022 A") { return "HD 142022"; }
+ return name;
+}
+
+} // namespace openspace::exoplanets
diff --git a/modules/exoplanets/exoplanetshelper.h b/modules/exoplanets/exoplanetshelper.h
new file mode 100644
index 0000000000..948e802c41
--- /dev/null
+++ b/modules/exoplanets/exoplanetshelper.h
@@ -0,0 +1,85 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * 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_EXOPLANETS___EXOPLANET_HELPER___H__
+#define __OPENSPACE_MODULE_EXOPLANETS___EXOPLANET_HELPER___H__
+
+#include
+
+namespace openspace::exoplanets {
+
+struct Exoplanet {
+ float a; // Orbital semi-major axis in AU
+ double aUpper; // Upper uncertainty of orbital semi-major axis
+ double aLower; // Lower uncertainty of orbital semi-major axis
+ double ua; // Uncertainty of orbital semi-major axis
+ float bigOm; // Longitude of ascending node in degrees
+ float bigOmUpper; // Upper uncertainty of longitude of ascending node
+ float bigOmLower; // Lower uncertainty of longitude of ascending node
+ float uBigOm; // Uncertainty of longitude of ascending node
+ bool binary; // Star known to be binary?
+ float bmv; // B − V color
+ float ecc; // Orbital eccentricity
+ float eccUpper; // Upper uncertainty of orbital eccentricity
+ float eccLower; // Lower uncertainty of orbital eccentricity
+ float uEcc; // Uncertainty of orbital eccentricity
+ float i; // Orbital inclination in degrees (for transiting systems only)
+ float iUpper; // Upper uncertainty of orbital inclination
+ float iLower; // Lower uncertainty of orbital inclination
+ float ui; // Uncertainty of orbital inclination
+ int nComp; // Number of planetary companions known
+ float om; // Argument of periastron in degrees
+ float omUpper; // Upper uncertainty of argument of periastron
+ float omLower; // Lower uncertainty of argument of periastron
+ float uOm; // Uncertainty of argument of periastron
+ double per; // Orbital period in days
+ float perUpper; // Upper uncertainty of period
+ float perLower; // Lower uncertainty of period
+ float uPer; // Uncertainty of period
+ double r; // Radius of the planet in Jupiter radii
+ double rUpper; // Upper uncertainty of radius of the planet
+ double rLower; // Lower uncertainty of radius of the planet
+ double ur; // Uncertainty of radius of the planet
+ float rStar; // Estimated radius of the star in solar radii
+ float rStarUpper; // Upper uncertainty of estimated star radius
+ float rStarLower; // Lower uncertainty of estimated star radius
+ float urStar; // Uncertainty of estimated star radius
+ double tt; // Epoch of transit center in HJD-2440000
+ float ttUpper; // Upper uncertainty of epoch of transit center
+ float ttLower; // Lower uncertainty of epoch of transit center
+ float uTt; // Uncertainty of epoch of transit center
+ float positionX; // Star position's X-coordinate in parsec
+ float positionY; // Star position's Y-coordinate in parsec
+ float positionZ; // Star position's Z-coordinate in parsec
+};
+
+// Convert csv-file specific names to the corresponding name in the speck data file
+std::string_view speckStarName(std::string_view name);
+
+// Convert speck-file specific names to the corresponding name in the csv data file
+std::string_view csvStarName(std::string_view name);
+
+} // namespace openspace::exoplanets
+
+#endif // __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSMODULE___H__
diff --git a/modules/exoplanets/exoplanetsmodule.cpp b/modules/exoplanets/exoplanetsmodule.cpp
new file mode 100644
index 0000000000..b23e31f7f0
--- /dev/null
+++ b/modules/exoplanets/exoplanetsmodule.cpp
@@ -0,0 +1,93 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this *
+ * software and associated documentation files (the "Software"), to deal in the Software *
+ * without restriction, including without limitation the rights to use, copy, modify, *
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to the following *
+ * conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in all copies *
+ * or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ ****************************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "exoplanetsmodule_lua.inl"
+
+namespace openspace {
+
+using namespace exoplanets;
+
+ExoplanetsModule::ExoplanetsModule() : OpenSpaceModule(Name) {}
+
+scripting::LuaLibrary ExoplanetsModule::luaLibrary() const {
+ scripting::LuaLibrary res;
+ res.name = "exoplanets";
+ res.functions = {
+ {
+ "addExoplanetSystem",
+ &exoplanets::luascriptfunctions::addExoplanetSystem,
+ {},
+ "string",
+ "Add the exoplanet system specified by the input string, including "
+ "information about the host star and planets."
+ },
+ {
+ "removeExoplanetSystem",
+ &exoplanets::luascriptfunctions::removeExoplanetSystem,
+ {},
+ "string",
+ "Removes the nodes of the specified exoplanet system from the scene graph."
+ },
+ {
+ "listAvailableExoplanetSystems",
+ &exoplanets::luascriptfunctions::listAvailableExoplanetSystems,
+ {},
+ "",
+ "Prints a list with the names of all exoplanet systems that can be added to "
+ "the scene graph to the OpenSpace Log. "
+ }
+ };
+
+ return res;
+}
+
+void ExoplanetsModule::internalInitialize(const ghoul::Dictionary&) {
+ auto fTask = FactoryManager::ref().factory();
+ auto fRenderable = FactoryManager::ref().factory();
+ ghoul_assert(fTask, "No task factory existed");
+ fTask->registerClass("ExoplanetsCsvToBinTask");
+ fRenderable->registerClass("RenderableOrbitDisc");
+}
+
+std::vector ExoplanetsModule::documentations() const {
+ return {
+ ExoplanetsCsvToBinTask::documentation()
+ };
+}
+
+} // namespace openspace
diff --git a/modules/exoplanets/exoplanetsmodule.h b/modules/exoplanets/exoplanetsmodule.h
new file mode 100644
index 0000000000..3a9ea264f4
--- /dev/null
+++ b/modules/exoplanets/exoplanetsmodule.h
@@ -0,0 +1,50 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * 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_EXOPLANETS___EXOPLANETSMODULE___H__
+#define __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSMODULE___H__
+
+#include
+
+#include
+
+namespace openspace {
+
+class ExoplanetsModule : public OpenSpaceModule {
+public:
+ constexpr static const char* Name = "Exoplanets";
+
+ ExoplanetsModule();
+ virtual ~ExoplanetsModule() = default;
+
+ scripting::LuaLibrary luaLibrary() const override;
+ std::vector documentations() const override;
+
+protected:
+ void internalInitialize(const ghoul::Dictionary&) override;
+};
+
+} // namespace openspace
+
+#endif // __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSMODULE___H__
diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl
new file mode 100644
index 0000000000..dc4efc8345
--- /dev/null
+++ b/modules/exoplanets/exoplanetsmodule_lua.inl
@@ -0,0 +1,560 @@
+/*****************************************************************************************
+* *
+* OpenSpace *
+* *
+* Copyright (c) 2014-2020 *
+* *
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
+* software and associated documentation files (the "Software"), to deal in the Software *
+* without restriction, including without limitation the rights to use, copy, modify, *
+* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
+* permit persons to whom the Software is furnished to do so, subject to the following *
+* conditions: *
+* *
+* The above copyright notice and this permission notice shall be included in all copies *
+* or substantial portions of the Software. *
+* *
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
+* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
+* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
+* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
+* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+****************************************************************************************/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+ constexpr const char* _loggerCat = "ExoplanetsModule";
+} // namespace
+
+namespace openspace::exoplanets::luascriptfunctions {
+
+constexpr const char* ExoplanetsGuiPath = "/Milky Way/Exoplanets/Exoplanet Systems/";
+
+constexpr const char* LookUpTablePath = "${SYNC}/http/exoplanets_data/1/lookup.txt";
+constexpr const char* ExoplanetsDataPath =
+ "${SYNC}/http/exoplanets_data/1/exoplanets_data.bin";
+
+constexpr const char* StarTextureFile = "${SYNC}/http/exoplanets_textures/1/sun.jpg";
+constexpr const char* DiscTextureFile =
+ "${SYNC}/http/exoplanets_textures/1/disc_texture.png";
+
+constexpr const char* BvColormapPath = "${SYNC}/http/stars_colormap/2/colorbv.cmap";
+
+std::string starColor(float bv, std::ifstream& colormap) {
+ const int t = static_cast(round(((bv + 0.4) / (2.0 + 0.4)) * 255));
+ std::string color;
+ for (int i = 0; i < t + 12; i++) {
+ getline(colormap, color);
+ }
+ colormap.close();
+
+ std::istringstream colorStream(color);
+ std::string r, g, b;
+ getline(colorStream, r, ' ');
+ getline(colorStream, g, ' ');
+ getline(colorStream, b, ' ');
+
+ return fmt::format("{{ {}, {}, {} }}", r, g, b);
+}
+
+glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom, float om) {
+ // Exoplanet defined inclination changed to be used as Kepler defined inclination
+ const glm::dvec3 ascendingNodeAxisRot = glm::dvec3(0.0, 0.0, 1.0);
+ const glm::dvec3 inclinationAxisRot = glm::dvec3(1.0, 0.0, 0.0);
+ const glm::dvec3 argPeriapsisAxisRot = glm::dvec3(0.0, 0.0, 1.0);
+
+ const double asc = glm::radians(bigom);
+ const double inc = glm::radians(i);
+ const double per = glm::radians(om);
+
+ const glm::dmat4 orbitPlaneRotation =
+ glm::rotate(asc, glm::dvec3(ascendingNodeAxisRot)) *
+ glm::rotate(inc, glm::dvec3(inclinationAxisRot)) *
+ glm::rotate(per, glm::dvec3(argPeriapsisAxisRot));
+
+ return orbitPlaneRotation;
+}
+
+// Rotate the original coordinate system (where x is pointing to First Point of Aries)
+// so that x is pointing from star to the sun.
+// Modified from "http://www.opengl-tutorial.org/intermediate-tutorials/
+// tutorial-17-quaternions/ #how-do-i-find-the-rotation-between-2-vectors"
+glm::dmat3 exoplanetSystemRotation(glm::dvec3 start, glm::dvec3 end) {
+ glm::quat rotationQuat;
+ glm::dvec3 rotationAxis;
+ const float cosTheta = static_cast(glm::dot(start, end));
+ constexpr float Epsilon = 1E-3f;
+
+ if (cosTheta < -1.f + Epsilon) {
+ // special case when vectors in opposite directions:
+ // there is no "ideal" rotation axis
+ // So guess one; any will do as long as it's perpendicular to start vector
+ rotationAxis = glm::cross(glm::dvec3(0.0, 0.0, 1.0), start);
+ if (length2(rotationAxis) < 0.01f) {
+ // bad luck, they were parallel, try again!
+ rotationAxis = glm::cross(glm::dvec3(1.0, 0.0, 0.0), start);
+ }
+
+ rotationAxis = glm::normalize(rotationAxis);
+ rotationQuat = glm::quat(glm::radians(180.f), rotationAxis);
+ return glm::dmat3(toMat4(rotationQuat));
+ }
+
+ rotationAxis = glm::cross(start, end);
+
+ const float s = sqrt((1.f + cosTheta) * 2.f);
+ const float invs = 1.f / s;
+
+ rotationQuat = glm::quat(
+ s * 0.5f,
+ rotationAxis.x * invs,
+ rotationAxis.y * invs,
+ rotationAxis.z * invs
+ );
+
+ return glm::dmat3(glm::toMat4(rotationQuat));
+}
+
+// Create an identifier without whitespaces
+std::string createIdentifier(std::string name) {
+ std::replace(name.begin(), name.end(), ' ', '_');
+ return name;
+}
+
+int addExoplanetSystem(lua_State* L) {
+ const int StringLocation = -1;
+ const std::string starName = luaL_checkstring(L, StringLocation);
+
+ // If user have given name as in EOD, change it to speck-name
+ const std::string starNameSpeck = std::string(speckStarName(starName));
+
+ const std::string starIdentifier = createIdentifier(starNameSpeck);
+ const std::string guiPath = ExoplanetsGuiPath + starNameSpeck;
+
+ SceneGraphNode* existingStarNode = sceneGraphNode(starIdentifier);
+ if (existingStarNode) {
+ return ghoul::lua::luaError(
+ L,
+ "Adding of exoplanet system failed. The system has already been added."
+ );
+ }
+
+ std::ifstream data(absPath(ExoplanetsDataPath), std::ios::in | std::ios::binary);
+
+ if (!data.good()) {
+ return ghoul::lua::luaError(L, "Failed to open exoplanets data file");
+ }
+
+ std::ifstream lut(absPath(LookUpTablePath));
+ if (!lut.good()) {
+ return ghoul::lua::luaError(L, "Failed to open exoplanets look-up table file");
+ }
+
+ // 1. search lut for the starname and return the corresponding location
+ // 2. go to that location in the data file
+ // 3. read sizeof(exoplanet) bytes into an exoplanet object.
+ Exoplanet p;
+ std::string line;
+ bool found = false;
+
+ std::vector planetSystem;
+ std::vector planetNames;
+
+ while (getline(lut, line)) {
+ std::istringstream ss(line);
+ std::string name;
+ getline(ss, name, ',');
+
+ if (name.compare(0, name.length() - 2, starNameSpeck) == 0) {
+ std::string location_s;
+ getline(ss, location_s);
+ long location = std::stol(location_s.c_str());
+
+ data.seekg(location);
+ data.read(reinterpret_cast(&p), sizeof(Exoplanet));
+
+ planetNames.push_back(name);
+ planetSystem.push_back(p);
+ found = true;
+ }
+ }
+
+ data.close();
+ lut.close();
+
+ if (!found) {
+ return ghoul::lua::luaError(
+ L,
+ "No star with the provided name was found."
+ );
+ }
+
+ bool notEnoughData = isnan(p.positionX) || isnan(p.a) || isnan(p.per);
+
+ if (notEnoughData) {
+ return ghoul::lua::luaError(
+ L,
+ "Insufficient data available for representing the exoplanet system."
+ );
+ }
+
+ const glm::dvec3 starPosition = glm::dvec3(
+ p.positionX * distanceconstants::Parsec,
+ p.positionY * distanceconstants::Parsec,
+ p.positionZ * distanceconstants::Parsec
+ );
+
+ const glm::dvec3 sunPosition = glm::dvec3(0.0, 0.0, 0.0);
+ const glm::dvec3 starToSunVec = glm::normalize(sunPosition - starPosition);
+ const glm::dvec3 galacticNorth = glm::dvec3(0.0, 0.0, 1.0);
+
+ const glm::dmat3 galaxticToCelestialMatrix =
+ SpiceManager::ref().positionTransformMatrix("GALACTIC", "J2000", 0.0);
+
+ const glm::dvec3 celestialNorth = glm::normalize(
+ galaxticToCelestialMatrix * galacticNorth
+ );
+
+ // Earth's north vector projected onto the skyplane, the plane perpendicular to the
+ // viewing vector (starToSunVec)
+ const float celestialAngle = static_cast(glm::dot(
+ celestialNorth,
+ starToSunVec
+ ));
+ glm::dvec3 northProjected = glm::normalize(
+ celestialNorth - (celestialAngle / glm::length(starToSunVec)) * starToSunVec
+ );
+
+ const glm::dvec3 beta = glm::normalize(glm::cross(starToSunVec, northProjected));
+
+ const glm::dmat3 exoplanetSystemRotation = glm::dmat3(
+ northProjected.x,
+ northProjected.y,
+ northProjected.z,
+ beta.x,
+ beta.y,
+ beta.z,
+ starToSunVec.x,
+ starToSunVec.y,
+ starToSunVec.z
+ );
+
+ // Star renderable globe, if we have a radius
+ std::string starGlobeRenderableString;
+ const float starRadius = p.rStar;
+ if (!isnan(starRadius)) {
+ std::ifstream colorMap(absPath(BvColormapPath), std::ios::in);
+
+ if (!colorMap.good()) {
+ return ghoul::lua::luaError(L, "Failed to open colormap data file");
+ }
+
+ const std::string color = starColor(p.bmv, colorMap);
+ const float radiusInMeter = starRadius * static_cast(distanceconstants::SolarRadius);
+
+ starGlobeRenderableString = "Renderable = {"
+ "Type = 'RenderableGlobe',"
+ "Radii = " + std::to_string(radiusInMeter) + ","
+ "SegmentsPerPatch = 64,"
+ "PerformShading = false,"
+ "Layers = {"
+ "ColorLayers = {"
+ "{"
+ "Identifier = 'StarColor',"
+ "Type = 'SolidColor',"
+ "Color = " + color + ","
+ "BlendMode = 'Normal',"
+ "Enabled = true"
+ "},"
+ "{"
+ "Identifier = 'StarTexture',"
+ "FilePath = openspace.absPath('" + StarTextureFile +"'),"
+ "BlendMode = 'Color',"
+ "Enabled = true"
+ "}"
+ "}"
+ "}"
+ "},";
+ }
+
+ const std::string starParent = "{"
+ "Identifier = '" + starIdentifier + "',"
+ "Parent = 'SolarSystemBarycenter',"
+ "" + starGlobeRenderableString + ""
+ "Transform = {"
+ "Rotation = {"
+ "Type = 'StaticRotation',"
+ "Rotation = " + ghoul::to_string(exoplanetSystemRotation) + ""
+ "},"
+ "Translation = {"
+ "Type = 'StaticTranslation',"
+ "Position = " + ghoul::to_string(starPosition) + ""
+ "}"
+ "},"
+ "GUI = {"
+ "Name = '" + starNameSpeck + " (Star)',"
+ "Path = '" + guiPath + "'"
+ "}"
+ "}";
+
+ openspace::global::scriptEngine.queueScript(
+ "openspace.addSceneGraphNode(" + starParent + ");",
+ openspace::scripting::ScriptEngine::RemoteScripting::Yes
+ );
+
+ // Planets
+ for (size_t i = 0; i < planetSystem.size(); i++) {
+ Exoplanet planet = planetSystem[i];
+ const std::string planetName = planetNames[i];
+
+ if (isnan(planet.ecc)) {
+ planet.ecc = 0.f;
+ }
+ if (isnan(planet.i)) {
+ planet.i = 90.f;
+ }
+ if (isnan(planet.bigOm)) {
+ planet.bigOm = 180.f;
+ }
+ if (isnan(planet.om)) {
+ planet.om = 90.f;
+ }
+ Time epoch;
+ std::string sEpoch;
+ if (!isnan(planet.tt)) {
+ epoch.setTime("JD " + std::to_string(planet.tt));
+ sEpoch = std::string(epoch.ISO8601());
+ }
+ else {
+ sEpoch = "2009-05-19T07:11:34.080";
+ }
+
+ float planetRadius;
+ std::string enabled;
+
+ const float astronomicalUnit = static_cast(distanceconstants::AstronomicalUnit);
+ const float solarRadius = static_cast(distanceconstants::SolarRadius);
+ const float jupiterRadius = static_cast(distanceconstants::JupiterRadius);
+
+ if (isnan(planet.r)) {
+ if (isnan(planet.rStar)) {
+ planetRadius = planet.a * 0.001f * astronomicalUnit;
+ }
+ else {
+ planetRadius = planet.rStar * 0.1f * solarRadius;
+ }
+ enabled = "false";
+ }
+ else {
+ planetRadius = static_cast(planet.r) * jupiterRadius;
+ enabled = "true";
+ }
+
+ const float period = static_cast(planet.per * SecondsPerDay);
+ const float semiMajorAxisInMeter = planet.a * astronomicalUnit;
+ const float semiMajorAxisInKm = semiMajorAxisInMeter * 0.001f;
+
+ const std::string planetIdentifier = createIdentifier(planetName);
+
+ const std::string planetKeplerTranslation = "{"
+ "Type = 'KeplerTranslation',"
+ "Eccentricity = " + std::to_string(planet.ecc) + "," //ECC
+ "SemiMajorAxis = " + std::to_string(semiMajorAxisInKm) + ","
+ "Inclination = " + std::to_string(planet.i) + "," //I
+ "AscendingNode = " + std::to_string(planet.bigOm) + "," //BIGOM
+ "ArgumentOfPeriapsis = " + std::to_string(planet.om) + "," //OM
+ "MeanAnomaly = 0.0,"
+ "Epoch = '" + sEpoch + "'," //TT. JD to YYYY MM DD hh:mm:ss
+ "Period = " + std::to_string(period) + ""
+ "}";
+
+ const std::string planetNode = "{"
+ "Identifier = '" + planetIdentifier + "',"
+ "Parent = '" + starIdentifier + "',"
+ "Enabled = true,"
+ "Renderable = {"
+ "Type = 'RenderableGlobe',"
+ "Enabled = " + enabled + ","
+ "Radii = " + std::to_string(planetRadius) + "," //R. in meters.
+ "SegmentsPerPatch = 64,"
+ "PerformShading = false,"
+ "Layers = {}"
+ "},"
+ "Transform = { "
+ "Translation = " + planetKeplerTranslation + ""
+ "},"
+ "GUI = {"
+ "Name = '" + planetName + "',"
+ "Path = '" + guiPath + "'"
+ "}"
+ "}";
+
+ int trailResolution = 1000;
+
+ // increase the resolution for highly eccentric orbits
+ const float eccentricityThreshold = 0.85f;
+ if (planet.ecc > eccentricityThreshold) {
+ trailResolution *= 2;
+ }
+
+ openspace::global::scriptEngine.queueScript(
+ "openspace.addSceneGraphNode(" + planetNode + ");",
+ openspace::scripting::ScriptEngine::RemoteScripting::Yes
+ );
+
+ const std::string planetTrailNode = "{"
+ "Identifier = '" + planetIdentifier + "_Trail',"
+ "Parent = '" + starIdentifier + "',"
+ "Enabled = true,"
+ "Renderable = {"
+ "Type = 'RenderableTrailOrbit',"
+ "Period = " + std::to_string(planet.per) + ","
+ "Resolution = " + std::to_string(trailResolution) + ","
+ "Translation = " + planetKeplerTranslation + ","
+ "Color = { 1, 1, 1 }"
+ "},"
+ "GUI = {"
+ "Name = '" + planetName + " Trail',"
+ "Path = '" + guiPath + "'"
+ "}"
+ "}";
+
+ openspace::global::scriptEngine.queueScript(
+ "openspace.addSceneGraphNode(" + planetTrailNode + ");",
+ openspace::scripting::ScriptEngine::RemoteScripting::Yes
+ );
+
+ bool hasUpperAUncertainty = !isnan(planet.aUpper);
+ bool hasLowerAUncertainty = !isnan(planet.aLower);
+
+ if (hasUpperAUncertainty && hasLowerAUncertainty) {
+ // Get the orbit plane of the planet trail orbit from the KeplerTranslation
+ const glm::dmat4 orbitPlaneRotationMatrix = computeOrbitPlaneRotationMatrix(
+ planet.i,
+ planet.bigOm,
+ planet.om
+ );
+ const glm::dmat3 rotation = orbitPlaneRotationMatrix;
+
+ const std::string discNode = "{"
+ "Identifier = '" + planetIdentifier + "_Disc',"
+ "Parent = '" + starIdentifier + "',"
+ "Enabled = true,"
+ "Renderable = {"
+ "Type = 'RenderableOrbitDisc',"
+ "Texture = openspace.absPath('" + DiscTextureFile + "'),"
+ "Size = " + std::to_string(semiMajorAxisInMeter) + ","
+ "Eccentricity = " + std::to_string(planet.ecc) + ","
+ "Offset = { " +
+ std::to_string(planet.aLower) + ", " +
+ std::to_string(planet.aUpper) +
+ "}," //min / max extend
+ "Opacity = 0.3"
+ "},"
+ "Transform = {"
+ "Rotation = {"
+ "Type = 'StaticRotation',"
+ "Rotation = " + ghoul::to_string(rotation) + ""
+ "}"
+ "},"
+ "GUI = {"
+ "Name = '" + planetName + " Disc',"
+ "Path = '" + guiPath + "'"
+ "}"
+ "}";
+
+ openspace::global::scriptEngine.queueScript(
+ "openspace.addSceneGraphNode(" + discNode + ");",
+ openspace::scripting::ScriptEngine::RemoteScripting::Yes
+ );
+ }
+ }
+
+ return 0;
+}
+
+int removeExoplanetSystem(lua_State* L) {
+ const int StringLocation = -1;
+ const std::string starName = luaL_checkstring(L, StringLocation);
+ const std::string starNameSpeck = std::string(speckStarName(starName));
+ const std::string starIdentifier = createIdentifier(starNameSpeck);
+
+ openspace::global::scriptEngine.queueScript(
+ "openspace.removeSceneGraphNode('" + starIdentifier + "');",
+ scripting::ScriptEngine::RemoteScripting::Yes
+ );
+
+ return 0;
+}
+
+int listAvailableExoplanetSystems(lua_State* L) {
+ ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::listAvailableExoplanetSystems");
+
+ std::ifstream file(absPath(LookUpTablePath));
+
+ if (!file.good()) {
+ return ghoul::lua::luaError(
+ L,
+ fmt::format("Failed to open file '{}'", LookUpTablePath)
+ );
+ }
+
+ std::vector names;
+ // As of 2020 there are about 4000 confirmed exoplanets, so use this number
+ // as a guess for the vector size
+ const int nExoplanetsGuess = 4000;
+ names.reserve(nExoplanetsGuess);
+
+ std::string line;
+ while (getline(file, line)) {
+ std::stringstream ss(line);
+ std::string name;
+ getline(ss, name, ',');
+ // Remove the last two characters, that specify the planet
+ name = name.substr(0, name.size() - 2);
+
+ names.push_back(name);
+ }
+
+ // For easier read, sort by names and remove duplicates
+ std::sort(names.begin(), names.end());
+ names.erase(std::unique(names.begin(), names.end()), names.end());
+
+ std::string output;
+ for (auto it = names.begin(); it != names.end(); ++it) {
+ if (it != names.end()) {
+ output += *it + ", ";
+ }
+ }
+
+ LINFO(fmt::format(
+ "There is data available for the following {} exoplanet systems: {}",
+ names.size(),
+ output
+ ));
+
+ return 0;
+}
+} //namespace openspace::exoplanets::luascriptfunctions
diff --git a/modules/exoplanets/include.cmake b/modules/exoplanets/include.cmake
new file mode 100644
index 0000000000..ffea0ac430
--- /dev/null
+++ b/modules/exoplanets/include.cmake
@@ -0,0 +1 @@
+set(DEFAULT_MODULE ON)
diff --git a/modules/exoplanets/rendering/renderableorbitdisc.cpp b/modules/exoplanets/rendering/renderableorbitdisc.cpp
new file mode 100644
index 0000000000..150a4d0e3d
--- /dev/null
+++ b/modules/exoplanets/rendering/renderableorbitdisc.cpp
@@ -0,0 +1,325 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this *
+ * software and associated documentation files (the "Software"), to deal in the Software *
+ * without restriction, including without limitation the rights to use, copy, modify, *
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to the following *
+ * conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in all copies *
+ * or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ ****************************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+ static const openspace::properties::Property::PropertyInfo TextureInfo = {
+ "Texture",
+ "Texture",
+ "This value is the path to a texture on disk that contains a one-dimensional "
+ "texture which is used for these rings."
+ };
+
+ static const openspace::properties::Property::PropertyInfo SizeInfo = {
+ "Size",
+ "Size",
+ "This value specifies the semi-major axis of the orbit in meter."
+ };
+
+ static const openspace::properties::Property::PropertyInfo EccentricityInfo = {
+ "Eccentricity",
+ "Eccentricity",
+ "This value determines the eccentricity, that is the deviation from a perfect "
+ "sphere, for this orbit."
+ };
+
+ static const openspace::properties::Property::PropertyInfo OffsetInfo = {
+ "Offset",
+ "Offset",
+ "This value is used to limit the width of the rings. Each of the two values is "
+ "the lower and the upper uncertainties of the semi-major axis. "
+ };
+} // namespace
+
+namespace openspace {
+
+documentation::Documentation RenderableOrbitDisc::Documentation() {
+ using namespace documentation;
+ return {
+ "Renderable Orbit Disc",
+ "exoplanets_renderable_orbit_disc",
+ {
+ {
+ "Type",
+ new StringEqualVerifier("RenderableOrbitDisc"),
+ Optional::No
+ },
+ {
+ TextureInfo.identifier,
+ new StringVerifier,
+ Optional::No,
+ TextureInfo.description
+ },
+ {
+ SizeInfo.identifier,
+ new DoubleVerifier,
+ Optional::No,
+ SizeInfo.description
+ },
+ {
+ EccentricityInfo.identifier,
+ new DoubleVerifier,
+ Optional::No,
+ EccentricityInfo.description
+ },
+ {
+ OffsetInfo.identifier,
+ new DoubleVector2Verifier,
+ Optional::Yes,
+ OffsetInfo.description
+ }
+ }
+ };
+}
+
+RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary)
+ : Renderable(dictionary)
+ , _texturePath(TextureInfo)
+ , _size(SizeInfo, 1.f, 0.f, 3.0e12f)
+ , _eccentricity(EccentricityInfo, 0.f, 0.f, 1.f)
+ , _offset(OffsetInfo, glm::vec2(0.f, 1.f), glm::vec2(0.f), glm::vec2(1.f))
+{
+ using ghoul::filesystem::File;
+
+ documentation::testSpecificationAndThrow(
+ Documentation(),
+ dictionary,
+ "RenderableOrbitDisc"
+ );
+
+ if (dictionary.hasKey(OffsetInfo.identifier)) {
+ _offset = dictionary.value(OffsetInfo.identifier);
+ }
+ addProperty(_offset);
+
+ _size = static_cast(dictionary.value(SizeInfo.identifier));
+ _size = _size + (_offset.value().y * distanceconstants::AstronomicalUnit);
+ setBoundingSphere(_size);
+ _size.onChange([&]() { _planeIsDirty = true; });
+ addProperty(_size);
+
+ _texturePath = absPath(dictionary.value(TextureInfo.identifier));
+ _textureFile = std::make_unique(_texturePath);
+
+ _texturePath.onChange([&]() { _textureIsDirty = true; });
+ addProperty(_texturePath);
+
+ _textureFile->setCallback([&](const File&) { _textureIsDirty = true; });
+
+ _eccentricity = static_cast(
+ dictionary.value(EccentricityInfo.identifier)
+ );
+ _eccentricity.onChange([&]() { _planeIsDirty = true; });
+ addProperty(_eccentricity);
+
+ addProperty(_opacity);
+}
+
+bool RenderableOrbitDisc::isReady() const {
+ return _shader && _texture;
+}
+
+void RenderableOrbitDisc::initializeGL() {
+ _shader = global::renderEngine.buildRenderProgram(
+ "OrbitdiscProgram",
+ absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_vs.glsl"),
+ absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_fs.glsl")
+ );
+
+ _uniformCache.modelViewProjection = _shader->uniformLocation(
+ "modelViewProjectionTransform"
+ );
+ _uniformCache.textureOffset = _shader->uniformLocation("textureOffset");
+ _uniformCache.opacity = _shader->uniformLocation("opacity");
+ _uniformCache.texture = _shader->uniformLocation("discTexture");
+ _uniformCache.eccentricity = _shader->uniformLocation("eccentricity");
+ _uniformCache.semiMajorAxis = _shader->uniformLocation("semiMajorAxis");
+
+ glGenVertexArrays(1, &_quad);
+ glGenBuffers(1, &_vertexPositionBuffer);
+
+ createPlane();
+ loadTexture();
+}
+
+void RenderableOrbitDisc::deinitializeGL() {
+ glDeleteVertexArrays(1, &_quad);
+ _quad = 0;
+
+ glDeleteBuffers(1, &_vertexPositionBuffer);
+ _vertexPositionBuffer = 0;
+
+ _textureFile = nullptr;
+ _texture = nullptr;
+
+ global::renderEngine.removeRenderProgram(_shader.get());
+ _shader = nullptr;
+}
+
+void RenderableOrbitDisc::render(const RenderData& data, RendererTasks&) {
+ _shader->activate();
+
+ 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));
+
+ glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
+
+ _shader->setUniform(
+ _uniformCache.modelViewProjection,
+ data.camera.projectionMatrix() * glm::mat4(modelViewTransform)
+ );
+ _shader->setUniform(_uniformCache.textureOffset, _offset);
+ _shader->setUniform(_uniformCache.opacity, _opacity);
+ _shader->setUniform(_uniformCache.eccentricity, _eccentricity);
+ _shader->setUniform(_uniformCache.semiMajorAxis, _size);
+
+ ghoul::opengl::TextureUnit unit;
+ unit.activate();
+ _texture->bind();
+ _shader->setUniform(_uniformCache.texture, unit);
+
+ glEnablei(GL_BLEND, 0);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDepthMask(false);
+ glDisable(GL_CULL_FACE);
+
+ glBindVertexArray(_quad);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ _shader->deactivate();
+
+ // Restores GL State
+ global::renderEngine.openglStateCache().resetBlendState();
+ global::renderEngine.openglStateCache().resetDepthState();
+ global::renderEngine.openglStateCache().resetPolygonAndClippingState();
+}
+
+void RenderableOrbitDisc::update(const UpdateData& data) {
+ if (_shader->isDirty()) {
+ _shader->rebuildFromFile();
+ _uniformCache.modelViewProjection = _shader->uniformLocation(
+ "modelViewProjectionTransform"
+ );
+ _uniformCache.textureOffset = _shader->uniformLocation("textureOffset");
+ _uniformCache.opacity = _shader->uniformLocation("opacity");
+ _uniformCache.texture = _shader->uniformLocation("discTexture");
+ _uniformCache.eccentricity = _shader->uniformLocation("eccentricity");
+ _uniformCache.semiMajorAxis = _shader->uniformLocation("semiMajorAxis");
+ }
+
+ if (_planeIsDirty) {
+ createPlane();
+ _planeIsDirty = false;
+ }
+
+ if (_textureIsDirty) {
+ loadTexture();
+ _textureIsDirty = false;
+ }
+}
+
+void RenderableOrbitDisc::loadTexture() {
+ if (!_texturePath.value().empty()) {
+ std::unique_ptr texture =
+ ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath));
+
+ if (texture) {
+ LDEBUGC(
+ "RenderableOrbitDisc",
+ fmt::format("Loaded texture from '{}'", absPath(_texturePath))
+ );
+ _texture = std::move(texture);
+
+ _texture->uploadTexture();
+ _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap);
+
+ _textureFile = std::make_unique(_texturePath);
+ _textureFile->setCallback(
+ [&](const ghoul::filesystem::File&) { _textureIsDirty = true; }
+ );
+ }
+ }
+}
+
+void RenderableOrbitDisc::createPlane() {
+ const GLfloat size = _size * (1.f + _eccentricity);
+
+ struct VertexData {
+ GLfloat x;
+ GLfloat y;
+ GLfloat s;
+ GLfloat t;
+ };
+
+ VertexData data[] = {
+ { -size, -size, 0.f, 0.f },
+ { size, size, 1.f, 1.f },
+ { -size, size, 0.f, 1.f },
+ { -size, -size, 0.f, 0.f },
+ { size, -size, 1.f, 0.f },
+ { size, size, 1.f, 1.f },
+ };
+
+ glBindVertexArray(_quad);
+ glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(
+ 0,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(VertexData),
+ nullptr
+ );
+ glEnableVertexAttribArray(1);
+ glVertexAttribPointer(
+ 1,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(VertexData),
+ reinterpret_cast(offsetof(VertexData, s))
+ );
+}
+
+} // namespace openspace
diff --git a/modules/exoplanets/rendering/renderableorbitdisc.h b/modules/exoplanets/rendering/renderableorbitdisc.h
new file mode 100644
index 0000000000..3cae6e64c4
--- /dev/null
+++ b/modules/exoplanets/rendering/renderableorbitdisc.h
@@ -0,0 +1,82 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * 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_EXOPLENETS___RENDERABLEORBITDISC___H__
+#define __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEORBITDISC___H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ghoul::filesystem { class File; }
+namespace ghoul::opengl {
+ class ProgramObject;
+ class Texture;
+} // namespace ghoul::opengl
+
+namespace openspace {
+
+namespace documentation { struct Documentation; }
+
+class RenderableOrbitDisc : public Renderable {
+public:
+ RenderableOrbitDisc(const ghoul::Dictionary& dictionary);
+
+ void initializeGL() override;
+ void deinitializeGL() override;
+
+ bool isReady() const override;
+
+ void render(const RenderData& data, RendererTasks& rendererTask) override;
+ void update(const UpdateData& data) override;
+
+ static documentation::Documentation Documentation();
+
+private:
+ void loadTexture();
+ void createPlane();
+
+ properties::StringProperty _texturePath;
+ properties::FloatProperty _size;
+ properties::FloatProperty _eccentricity;
+ properties::Vec2Property _offset;
+
+ std::unique_ptr _shader = nullptr;
+ UniformCache(modelViewProjection, textureOffset, opacity,
+ texture, eccentricity, semiMajorAxis) _uniformCache;
+ std::unique_ptr _texture = nullptr;
+ std::unique_ptr _textureFile;
+
+ bool _textureIsDirty = false;
+ bool _planeIsDirty = false;
+ GLuint _quad = 0;
+ GLuint _vertexPositionBuffer = 0;
+};
+
+} // namespace openspace
+
+#endif // __OPENSPACE_MODULE_EXOPLENETS___RENDERABLEORBITDISC___H__
diff --git a/modules/exoplanets/shaders/orbitdisc_fs.glsl b/modules/exoplanets/shaders/orbitdisc_fs.glsl
new file mode 100644
index 0000000000..373ea936dc
--- /dev/null
+++ b/modules/exoplanets/shaders/orbitdisc_fs.glsl
@@ -0,0 +1,114 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * 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 "PowerScaling/powerScaling_fs.hglsl"
+#include "fragment.glsl"
+
+in vec2 vs_st;
+in vec4 vs_position;
+
+uniform sampler1D discTexture;
+uniform vec2 textureOffset;
+uniform float opacity;
+uniform float eccentricity;
+uniform float semiMajorAxis;
+
+const float AstronomicalUnit = 149597870700.0; // m
+const float Epsilon = 0.0000001;
+
+// Compute semi minor axis from major axis, a, and eccentricity, e
+float semiMinorAxis(float a, float e) {
+ return a * sqrt(1.0 - e * e);
+}
+
+// If returned value <= 1, the point is insdie or on the ellipse specified by the input:
+// a and b are the semi-major and semi-minor axes, respectively.
+// cx is the displacement of the center of the ellipse along the x-axis (for an orbit,
+// the y-displacement is always zero)
+float ellipseTest(vec2 point, float a, float b, float cx) {
+ float x = point.x;
+ float y = point.y;
+ return (pow(x - cx, 2.0) / (a*a)) + ((y*y) / (b*b));
+}
+
+Fragment getFragment() {
+ // Moving the origin to the center
+ vec2 st = (vs_st - vec2(0.5)) * 2.0;
+
+ float AUpper = semiMajorAxis;
+ float BUpper = semiMinorAxis(AUpper, eccentricity);
+ float CUpper = sqrt(AUpper*AUpper - BUpper*BUpper);
+ float outerApoapsisDistance = AUpper * (1 + eccentricity);
+
+ float ALower = AUpper - AstronomicalUnit * (textureOffset.x + textureOffset.y);
+ float BLower = semiMinorAxis(ALower, eccentricity);
+ float CLower = sqrt(ALower*ALower - BLower*BLower);
+ float innerApoapsisDistance = ALower * (1 + eccentricity);
+
+ // Normalize based on outer apoapsis distance (size of plane)
+ float AU_n = AUpper / outerApoapsisDistance;
+ float BU_n = BUpper / outerApoapsisDistance;
+ float CU_n = CUpper / outerApoapsisDistance;
+ float AL_n = ALower / outerApoapsisDistance;
+ float BL_n = BLower / outerApoapsisDistance;
+ float CL_n = CLower / outerApoapsisDistance;
+
+ if (eccentricity <= Epsilon) {
+ CU_n = 0.0;
+ CL_n = 0.0;
+ }
+
+ float outer = ellipseTest(st, AU_n, BU_n, -CU_n);
+ float inner = ellipseTest(st, AL_n, BL_n, -CL_n);
+ if (outer > 1.0 || inner < 1.0) {
+ // point is outside outer ellipse or inside inner eliipse
+ discard;
+ }
+
+ // Remapping the texture coordinates
+ vec2 dir = normalize(st);
+
+ // Find outer ellipse: where along the direction does the equation == 1?
+ float denominator = pow(BU_n * dir.x, 2.0) + pow(AU_n * dir.y, 2.0);
+ float first = -(pow(BU_n, 2.0) * dir.x * CU_n) / denominator;
+ float second = pow((pow(BU_n, 2.0) * dir.x * CU_n) / denominator, 2.0);
+ float third = (pow(BU_n * CU_n, 2.0) - pow(AU_n * BU_n, 2.0)) / denominator;
+
+ float scale = first + sqrt(second - third);
+
+ vec2 max = dir * scale;
+ vec2 min = max * (innerApoapsisDistance / outerApoapsisDistance);
+
+ float distance1 = distance(max, min);
+ float distance2 = distance(max, st);
+ float textureCoord = distance2 / distance1;
+
+ vec4 diffuse = texture(discTexture, textureCoord);
+ diffuse.a *= opacity;
+
+ Fragment frag;
+ frag.color = diffuse;
+ frag.depth = vs_position.w;
+ return frag;
+}
diff --git a/modules/exoplanets/shaders/orbitdisc_vs.glsl b/modules/exoplanets/shaders/orbitdisc_vs.glsl
new file mode 100644
index 0000000000..e998350ce7
--- /dev/null
+++ b/modules/exoplanets/shaders/orbitdisc_vs.glsl
@@ -0,0 +1,44 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * 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/powerScaling_vs.hglsl"
+
+layout(location = 0) in vec2 in_position;
+layout(location = 1) in vec2 in_st;
+
+out vec2 vs_st;
+out vec4 vs_position;
+
+uniform mat4 modelViewProjectionTransform;
+
+void main() {
+ vs_st = in_st;
+ vs_position = z_normalization(
+ modelViewProjectionTransform * vec4(in_position, 0.0, 1.0)
+ );
+
+ gl_Position = vs_position;
+}
diff --git a/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp b/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp
new file mode 100644
index 0000000000..6cb232fb79
--- /dev/null
+++ b/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp
@@ -0,0 +1,696 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this *
+ * software and associated documentation files (the "Software"), to deal in the Software *
+ * without restriction, including without limitation the rights to use, copy, modify, *
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
+ * permit persons to whom the Software is furnished to do so, subject to the following *
+ * conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in all copies *
+ * or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+ ****************************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+ constexpr const char* KeyInputCsv = "InputCSV";
+ constexpr const char* KeyInputSpeck = "InputSPECK";
+ constexpr const char* KeyOutputBin = "OutputBIN";
+ constexpr const char* KeyOutputLut = "OutputLUT";
+ constexpr const char* KeyTeffToBv = "TeffToBvFile";
+
+ constexpr const char* _loggerCat = "CsvToBinTask";
+} // namespace
+
+namespace openspace::exoplanets {
+
+ExoplanetsCsvToBinTask::ExoplanetsCsvToBinTask(const ghoul::Dictionary& dictionary) {
+ openspace::documentation::testSpecificationAndThrow(
+ documentation(),
+ dictionary,
+ "ExoplanetsCsvToBinTask"
+ );
+
+ _inputCsvPath = absPath(dictionary.value(KeyInputCsv));
+ _inputSpeckPath = absPath(dictionary.value(KeyInputSpeck));
+ _outputBinPath = absPath(dictionary.value(KeyOutputBin));
+ _outputLutPath = absPath(dictionary.value(KeyOutputLut));
+ _teffToBvFilePath = absPath(dictionary.value(KeyTeffToBv));
+}
+
+std::string ExoplanetsCsvToBinTask::description() {
+ return fmt::format(
+ "Extract metadata from csv-file '{}' and write as bin to '{}'",
+ _inputCsvPath,
+ _outputBinPath
+ );
+}
+
+void ExoplanetsCsvToBinTask::perform(const Task::ProgressCallback& progressCallback) {
+ std::ifstream csvFile(_inputCsvPath);
+ if (!csvFile.good()) {
+ LERROR(fmt::format("Failed to open CSV file '{}'", _inputCsvPath));
+ return;
+ }
+
+ std::ofstream binFile(_outputBinPath, std::ios::out | std::ios::binary);
+ std::ofstream lutFile(_outputLutPath);
+
+ int version = 1;
+ binFile.write(reinterpret_cast(&version), sizeof(int));
+
+ std::string planetRow;
+ getline(csvFile, planetRow); // The first line, containing the data names
+
+ int total = 0;
+ while (getline(csvFile, planetRow)) {
+ ++total;
+ }
+ csvFile.clear();
+ csvFile.seekg(0);
+ getline(csvFile, planetRow); // The first line, containing the data names
+ LINFOC("CSVTOBIN", fmt::format("Loading {} stars", total));
+
+ auto readFloatData = [](const std::string& str) -> float {
+ float result;
+ auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
+ if (ec == std::errc()) {
+ return result;
+ }
+ return NAN;
+ };
+
+ auto readDoubleData = [](const std::string& str) -> double {
+ double result;
+ auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
+ if (ec == std::errc()) {
+ return result;
+ }
+ return NAN;
+ };
+
+ auto readIntegerData = [](const std::string& str) -> int {
+ int result;
+ auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
+ if (ec == std::errc()) {
+ return result;
+ }
+ return -1;
+ };
+
+ Exoplanet p;
+ std::string data;
+ int count = 0;
+ while (getline(csvFile, planetRow)) {
+ ++count;
+ progressCallback(static_cast(count) / static_cast(total));
+
+ std::istringstream lineStream(planetRow);
+
+ getline(lineStream, data, ','); // A
+ p.a = readFloatData(data);
+
+ getline(lineStream, data, ','); // AUPPER
+ p.aUpper = readDoubleData(data);
+
+ getline(lineStream, data, ','); // ALOWER
+ p.aLower = readDoubleData(data);
+
+ getline(lineStream, data, ','); // UA
+ p.ua = readDoubleData(data);
+
+ getline(lineStream, data, ','); // AREF
+ getline(lineStream, data, ','); // AURL
+ getline(lineStream, data, ','); // AR
+ getline(lineStream, data, ','); // ARUPPER
+ getline(lineStream, data, ','); // ARLOWER
+ getline(lineStream, data, ','); // UAR
+ getline(lineStream, data, ','); // ARREF
+ getline(lineStream, data, ','); // ARURL
+ getline(lineStream, data, ','); // ASTROMETRY
+ getline(lineStream, data, ','); // B
+ getline(lineStream, data, ','); // BUPPER
+ getline(lineStream, data, ','); // BLOWER
+ getline(lineStream, data, ','); // UB
+ getline(lineStream, data, ','); // BREF
+ getline(lineStream, data, ','); // BURL
+ getline(lineStream, data, ','); // BIGOM
+ p.bigOm = readFloatData(data);
+
+ getline(lineStream, data, ','); // BIGOMUPPER
+ p.bigOmUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // BIGOMLOWER
+ p.bigOmLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // UBIGOM
+ p.uBigOm = readFloatData(data);
+
+ getline(lineStream, data, ','); // BIGOMREF
+ getline(lineStream, data, ','); // BIGOMURL
+ getline(lineStream, data, ','); // BINARY
+ p.binary = static_cast(readIntegerData(data));
+
+ getline(lineStream, data, ','); // BINARYREF
+ getline(lineStream, data, ','); // BINARYURL
+ getline(lineStream, data, ','); // BMV
+ p.bmv = readFloatData(data);
+
+ getline(lineStream, data, ','); // CHI2
+ getline(lineStream, data, ','); // COMP
+ std::string component = data;
+
+ getline(lineStream, data, ','); // DATE
+ getline(lineStream, data, ','); // DEC
+ getline(lineStream, data, ','); // DEC_STRING
+ getline(lineStream, data, ','); // DENSITY
+ getline(lineStream, data, ','); // DENSITYUPPER
+ getline(lineStream, data, ','); // DENSITYLOWER
+ getline(lineStream, data, ','); // UDENSITY
+ getline(lineStream, data, ','); // DENSITYREF
+ getline(lineStream, data, ','); // DENSITYURL
+ getline(lineStream, data, ','); // DEPTH
+ getline(lineStream, data, ','); // DEPTHUPPER
+ getline(lineStream, data, ','); // DEPTHLOWER
+ getline(lineStream, data, ','); // UDEPTH
+ getline(lineStream, data, ','); // DEPTHREF
+ getline(lineStream, data, ','); // DEPTHURL
+ getline(lineStream, data, ','); // DIST
+ getline(lineStream, data, ','); // DISTUPPER
+ getline(lineStream, data, ','); // DISTLOWER
+ getline(lineStream, data, ','); // UDIST
+ getline(lineStream, data, ','); // DISTREF
+ getline(lineStream, data, ','); // DISTURL
+ getline(lineStream, data, ','); // DR
+ getline(lineStream, data, ','); // DRUPPER
+ getline(lineStream, data, ','); // DRLOWER
+ getline(lineStream, data, ','); // UDR
+ getline(lineStream, data, ','); // DRREF
+ getline(lineStream, data, ','); // DRURL
+ getline(lineStream, data, ','); // DVDT
+ getline(lineStream, data, ','); // DVDTUPPER
+ getline(lineStream, data, ','); // DVDTLOWER
+ getline(lineStream, data, ','); // UDVDT
+ getline(lineStream, data, ','); // DVDTREF
+ getline(lineStream, data, ','); // DVDTURL
+ getline(lineStream, data, ','); // EANAME
+ getline(lineStream, data, ','); // EAURL
+ getline(lineStream, data, ','); // ECC
+ p.ecc = readFloatData(data);
+
+ getline(lineStream, data, ','); // ECCUPPER
+ p.eccUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // ECCLOWER
+ p.eccLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // UECC
+ p.uEcc = readFloatData(data);
+
+ getline(lineStream, data, ','); // ECCREF
+ getline(lineStream, data, ','); // ECCURL
+ getline(lineStream, data, ','); // EOD
+ getline(lineStream, data, ','); // ETDNAME
+ getline(lineStream, data, ','); // ETDURL
+ getline(lineStream, data, ','); // FE
+ getline(lineStream, data, ','); // FEUPPER
+ getline(lineStream, data, ','); // FELOWER
+ getline(lineStream, data, ','); // UFE
+ getline(lineStream, data, ','); // FEREF
+ getline(lineStream, data, ','); // FEURL
+ getline(lineStream, data, ','); // FIRSTREF
+ getline(lineStream, data, ','); // FIRSTURL
+ getline(lineStream, data, ','); // FREEZE_ECC
+ getline(lineStream, data, ','); // GAMMA
+ getline(lineStream, data, ','); // GAMMAUPPER
+ getline(lineStream, data, ','); // GAMMALOWER
+ getline(lineStream, data, ','); // UGAMMA
+ getline(lineStream, data, ','); // GAMMAREF
+ getline(lineStream, data, ','); // GAMMAURL
+ getline(lineStream, data, ','); // GL
+ getline(lineStream, data, ','); // GRAVITY
+ getline(lineStream, data, ','); // GRAVITYUPPER
+ getline(lineStream, data, ','); // GRAVITYLOWER
+ getline(lineStream, data, ','); // UGRAVITY
+ getline(lineStream, data, ','); // GRAVITYREF
+ getline(lineStream, data, ','); // GRAVITYURL
+ getline(lineStream, data, ','); // H
+ getline(lineStream, data, ','); // HD
+ getline(lineStream, data, ','); // HIPP
+ getline(lineStream, data, ','); // HR
+ getline(lineStream, data, ','); // I
+ p.i = readFloatData(data);
+
+ getline(lineStream, data, ','); // IUPPER
+ p.iUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // ILOWER
+ p.iLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // UI
+ p.ui = readFloatData(data);
+
+ getline(lineStream, data, ','); // IREF
+ getline(lineStream, data, ','); // IURL
+ getline(lineStream, data, ','); // IMAGING
+ getline(lineStream, data, ','); // J
+ getline(lineStream, data, ','); // JSNAME
+ getline(lineStream, data, ','); // EPEURL
+ getline(lineStream, data, ','); // K
+ getline(lineStream, data, ','); // KUPPER
+ getline(lineStream, data, ','); // KLOWER
+ getline(lineStream, data, ','); // UK
+ getline(lineStream, data, ','); // KREF
+ getline(lineStream, data, ','); // KURL
+ getline(lineStream, data, ','); // KOI
+ getline(lineStream, data, ','); // KS
+ getline(lineStream, data, ','); // KP
+ getline(lineStream, data, ','); // LAMBDA
+ getline(lineStream, data, ','); // LAMBDAUPPER
+ getline(lineStream, data, ','); // LAMBDALOWER
+ getline(lineStream, data, ','); // ULAMBDA
+ getline(lineStream, data, ','); // LAMBDAREF
+ getline(lineStream, data, ','); // LAMBDAURL
+ getline(lineStream, data, ','); // LOGG
+ getline(lineStream, data, ','); // LOGGUPPER
+ getline(lineStream, data, ','); // LOGGLOWER
+ getline(lineStream, data, ','); // ULOGG
+ getline(lineStream, data, ','); // LOGGREF
+ getline(lineStream, data, ','); // LOGGURL;
+ getline(lineStream, data, ','); // MASS
+ getline(lineStream, data, ','); // MASSUPPER
+ getline(lineStream, data, ','); // MASSLOWER
+ getline(lineStream, data, ','); // UMASS
+ getline(lineStream, data, ','); // MASSREF
+ getline(lineStream, data, ','); // MASSURL
+ getline(lineStream, data, ','); // MICROLENSING
+ getline(lineStream, data, ','); // MSINI
+ getline(lineStream, data, ','); // MSINIUPPER
+ getline(lineStream, data, ','); // MSINILOWER
+ getline(lineStream, data, ','); // UMSINI
+ getline(lineStream, data, ','); // MSINIREF
+ getline(lineStream, data, ','); // MSINIURL
+ getline(lineStream, data, ','); // MSTAR
+ getline(lineStream, data, ','); // MSTARUPPER
+ getline(lineStream, data, ','); // MSTARLOWER
+ getline(lineStream, data, ','); // UMSTAR
+ getline(lineStream, data, ','); // MSTARREF
+ getline(lineStream, data, ','); // MSTARURL
+ getline(lineStream, data, ','); // MULT
+ getline(lineStream, data, ','); // NAME
+ getline(lineStream, data, ','); // NCOMP
+ p.nComp = readIntegerData(data);
+
+ getline(lineStream, data, ','); // NOBS
+ getline(lineStream, data, ','); // OM
+ p.om = readFloatData(data);
+
+ getline(lineStream, data, ','); // OMUPPER
+ p.omUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // OMLOWER
+ p.omLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // UOM
+ p.uOm = readFloatData(data);
+
+ getline(lineStream, data, ','); // OMREF
+ getline(lineStream, data, ','); // OMURL
+ getline(lineStream, data, ','); // ORBREF
+ getline(lineStream, data, ','); // ORBURL
+ getline(lineStream, data, ','); // OTHERNAME
+ getline(lineStream, data, ','); // PAR
+ getline(lineStream, data, ','); // PARUPPER
+ getline(lineStream, data, ','); // PARLOWER
+ getline(lineStream, data, ','); // UPAR
+ getline(lineStream, data, ','); // PER
+ p.per = readDoubleData(data);
+
+ getline(lineStream, data, ','); // PERUPPER
+ p.perUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // PERLOWER
+ p.perLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // UPER
+ p.uPer = readFloatData(data);
+
+ getline(lineStream, data, ','); // PERREF
+ getline(lineStream, data, ','); // PERURL
+ getline(lineStream, data, ','); // PLANETDISCMETH
+ getline(lineStream, data, ','); // R
+ p.r = readDoubleData(data);
+
+ getline(lineStream, data, ','); // RUPPER
+ p.rUpper = readDoubleData(data);
+
+ getline(lineStream, data, ','); // RLOWER
+ p.rLower = readDoubleData(data);
+
+ getline(lineStream, data, ','); //UR
+ p.ur = readDoubleData(data);
+
+ getline(lineStream, data, ','); // RREF
+ getline(lineStream, data, ','); // RURL
+ getline(lineStream, data, ','); // RA
+ getline(lineStream, data, ','); // RA_STRING
+ getline(lineStream, data, ','); // RHK
+ getline(lineStream, data, ','); // RHOSTAR
+ getline(lineStream, data, ','); // RHOSTARUPPER
+ getline(lineStream, data, ','); // RHOSTARLOWER
+ getline(lineStream, data, ','); // URHOSTAR
+ getline(lineStream, data, ','); // RHOSTARREF
+ getline(lineStream, data, ','); // RHOSTARURL
+ getline(lineStream, data, ','); // RMS
+ getline(lineStream, data, ','); // RR
+ getline(lineStream, data, ','); // RRUPPER
+ getline(lineStream, data, ','); // RRLOWER
+ getline(lineStream, data, ','); // URR
+ getline(lineStream, data, ','); // RRREF
+ getline(lineStream, data, ','); // RRURL
+ getline(lineStream, data, ','); // RSTAR
+ p.rStar = readFloatData(data);
+
+ getline(lineStream, data, ','); // RSTARUPPER
+ p.rStarUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // RSTARLOWER
+ p.rStarLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // URSTAR
+ p.urStar = readFloatData(data);
+
+ getline(lineStream, data, ','); // RSTARREF
+ getline(lineStream, data, ','); // RSTARURL
+ getline(lineStream, data, ','); // SAO
+ getline(lineStream, data, ','); // SE
+ getline(lineStream, data, ','); // SEREF
+ getline(lineStream, data, ','); // SEURL
+ getline(lineStream, data, ','); // SEDEPTHJ
+ getline(lineStream, data, ','); // SEDEPTHJUPPER
+ getline(lineStream, data, ','); // SEDEPTHJLOWER
+ getline(lineStream, data, ','); // USEDEPTHJ
+ getline(lineStream, data, ','); // SEDEPTHJREF
+ getline(lineStream, data, ','); // SEDEPTHJURL
+ getline(lineStream, data, ','); // SEDEPTHH
+ getline(lineStream, data, ','); // SEDEPTHHUPPER
+ getline(lineStream, data, ','); // SEDEPTHHLOWER
+ getline(lineStream, data, ','); // USEDEPTHH
+ getline(lineStream, data, ','); // SEDEPTHHREF
+ getline(lineStream, data, ','); // SEDEPTHHURL
+ getline(lineStream, data, ','); // SEDEPTHKS
+ getline(lineStream, data, ','); // SEDEPTHKSUPPER
+ getline(lineStream, data, ','); // SEDEPTHKSLOWER
+ getline(lineStream, data, ','); // USEDEPTHKS
+ getline(lineStream, data, ','); // SEDEPTHKSREF
+ getline(lineStream, data, ','); // SEDEPTHKSURL
+ getline(lineStream, data, ','); // SEDEPTHKP
+ getline(lineStream, data, ','); // SEDEPTHKPUPPER
+ getline(lineStream, data, ','); // SEDEPTHKPLOWER
+ getline(lineStream, data, ','); // USEDEPTHKP
+ getline(lineStream, data, ','); // SEDEPTHKPREF
+ getline(lineStream, data, ','); // SEDEPTHKPURL
+ getline(lineStream, data, ','); // SEDEPTH36
+ getline(lineStream, data, ','); // SEDEPTH36UPPER
+ getline(lineStream, data, ','); // SEDEPTH36LOWER
+ getline(lineStream, data, ','); // USEDEPTH36
+ getline(lineStream, data, ','); // SEDEPTH36REFx
+ getline(lineStream, data, ','); // SEDEPTH36URLx
+ getline(lineStream, data, ','); // SEDEPTH45
+ getline(lineStream, data, ','); // SEDEPTH45UPPER
+ getline(lineStream, data, ','); // SEDEPTH45LOWER
+ getline(lineStream, data, ','); // USEDEPTH45
+ getline(lineStream, data, ','); // SEDEPTH45REF
+ getline(lineStream, data, ','); // SEDEPTH45URL
+ getline(lineStream, data, ','); // SEDEPTH58
+ getline(lineStream, data, ','); // SEDEPTH58UPPER
+ getline(lineStream, data, ','); // SEDEPTH58LOWER
+ getline(lineStream, data, ','); // USEDEPTH58
+ getline(lineStream, data, ','); // EDEPTH58REF
+ getline(lineStream, data, ','); // SEDEPTH58URL
+ getline(lineStream, data, ','); // SEDEPTH80
+ getline(lineStream, data, ','); // SEDEPTH80UPPER
+ getline(lineStream, data, ','); // SEDEPTH80LOWER
+ getline(lineStream, data, ','); // USEDEPTH80
+ getline(lineStream, data, ','); // SEDEPTH80REF
+ getline(lineStream, data, ','); // SEDEPTH80URL
+ getline(lineStream, data, ','); // SEP
+ getline(lineStream, data, ','); // SEPUPPER
+ getline(lineStream, data, ','); // SEPLOWER
+ getline(lineStream, data, ','); // USEP
+ getline(lineStream, data, ','); // SEPREF
+ getline(lineStream, data, ','); // SEPURL
+ getline(lineStream, data, ','); // SET
+ getline(lineStream, data, ','); // SETUPPER
+ getline(lineStream, data, ','); // SETLOWER
+ getline(lineStream, data, ','); // USET
+ getline(lineStream, data, ','); // SETREF
+ getline(lineStream, data, ','); // SETURL
+ getline(lineStream, data, ','); // SHK
+ getline(lineStream, data, ','); // SIMBADNAME
+ getline(lineStream, data, ','); // SIMBADURL
+ getline(lineStream, data, ','); // SPECREF
+ getline(lineStream, data, ','); // SPECURL
+ getline(lineStream, data, ','); // STAR
+ std::string speckStarname = std::string(speckStarName(data));
+ glm::vec3 position = starPosition(speckStarname);
+ p.positionX = position[0];
+ p.positionY = position[1];
+ p.positionZ = position[2];
+
+ getline(lineStream, data, ','); // STARDISCMETH
+ getline(lineStream, data, ','); // T0
+ getline(lineStream, data, ','); // T0UPPER
+ getline(lineStream, data, ','); // T0LOWER
+ getline(lineStream, data, ','); // UT0
+ getline(lineStream, data, ','); // T0REF
+ getline(lineStream, data, ','); // T0URL
+ getline(lineStream, data, ','); // T14
+ getline(lineStream, data, ','); // T14UPPER
+ getline(lineStream, data, ','); // T14LOWER
+ getline(lineStream, data, ','); // UT14
+ getline(lineStream, data, ','); // T14REF
+ getline(lineStream, data, ','); // T14URL
+ getline(lineStream, data, ','); // TEFF
+ float teff = readFloatData(data);
+
+ getline(lineStream, data, ','); // TEFFUPPER
+ getline(lineStream, data, ','); // TEFFLOWER
+ getline(lineStream, data, ','); // UTEFF
+ getline(lineStream, data, ','); // TEFFREF
+ getline(lineStream, data, ','); // TEFFURL
+ getline(lineStream, data, ','); // TIMING
+ getline(lineStream, data, ','); // TRANSIT
+ getline(lineStream, data, ','); // TRANSITREF
+ getline(lineStream, data, ','); // TRANSITURL
+ getline(lineStream, data, ','); // TREND
+ getline(lineStream, data, ','); // TT
+ p.tt = readDoubleData(data);
+
+ getline(lineStream, data, ','); // TTUPPER
+ p.ttUpper = readFloatData(data);
+
+ getline(lineStream, data, ','); // TTLOWER
+ p.ttLower = readFloatData(data);
+
+ getline(lineStream, data, ','); // UTT
+ p.uTt = readFloatData(data);
+
+ getline(lineStream, data, ','); // TTREF
+ getline(lineStream, data, ','); // TTURL
+ getline(lineStream, data, ','); // V
+ getline(lineStream, data, ','); // VREF
+ getline(lineStream, data, ','); // VURL
+ getline(lineStream, data, ','); // VSINI
+ getline(lineStream, data, ','); // VSINIUPPER
+ getline(lineStream, data, ','); // VSINILOWER
+ getline(lineStream, data, ','); // UVSINI
+ getline(lineStream, data, ','); // VSINIREF
+ getline(lineStream, data, ','); // VSINIURL
+ getline(lineStream, data, ','); // KEPID
+ bool isKeplerObject = false;
+ if (!data.empty()) {
+ isKeplerObject = true;
+ }
+ getline(lineStream, data); // KDE
+
+ if (!isKeplerObject) {
+ // calculate B-V from Teff if not exsisting
+ if (std::isnan(p.bmv)) {
+ p.bmv = bvFromTeff(teff);
+ }
+
+ // create look-up table
+ long pos = static_cast(binFile.tellp());
+ std::string planetName = speckStarname + " " + component;
+ lutFile << planetName << "," << pos << std::endl;
+ binFile.write(reinterpret_cast(&p), sizeof(Exoplanet));
+ }
+ }
+
+ progressCallback(1.f);
+}
+
+glm::vec3 ExoplanetsCsvToBinTask::starPosition(const std::string& starName) {
+ std::ifstream exoplanetsFile(_inputSpeckPath);
+ if (!exoplanetsFile) {
+ LERROR(fmt::format("Error opening file expl.speck"));
+ }
+
+ glm::vec3 position{ NAN };
+ std::string line;
+
+ while (getline(exoplanetsFile, line)) {
+ bool shouldSkipLine = (
+ line.empty() || line[0] == '#' || line.substr(0, 7) == "datavar" ||
+ line.substr(0, 10) == "texturevar" || line.substr(0, 7) == "texture"
+ );
+
+ if (shouldSkipLine) {
+ continue;
+ }
+
+ std::string data;
+ std::string name;
+ std::istringstream linestream(line);
+ getline(linestream, data, '#');
+ getline(linestream, name);
+ name.erase(0, 1);
+
+ std::string coord;
+ if (name == starName) {
+ std::stringstream dataStream(data);
+ getline(dataStream, coord, ' ');
+ position[0] = std::stof(coord.c_str(), nullptr);
+ getline(dataStream, coord, ' ');
+ position[1] = std::stof(coord.c_str(), nullptr);
+ getline(dataStream, coord, ' ');
+ position[2] = std::stof(coord.c_str(), nullptr);
+ break;
+ }
+ }
+
+ // Apply transformation matrix to pos
+ glm::dmat4 _transformationMatrix = glm::dmat4(1.0);
+ glm::vec3 transformedPosition = glm::vec3(
+ _transformationMatrix * glm::dvec4(position, 1.0)
+ );
+
+ return transformedPosition;
+}
+
+float ExoplanetsCsvToBinTask::bvFromTeff(float teff) {
+ if (std::isnan(teff)) {
+ return NAN;
+ }
+
+ std::ifstream teffToBvFile(_teffToBvFilePath);
+ if (!teffToBvFile.good()) {
+ LERROR(fmt::format("Failed to open teff_bv.txt file"));
+ return NAN;
+ }
+
+ float bv = 0.f;
+ float bvUpper = 0.f;
+ float bvLower = 0.f;
+ float teffLower, teffUpper;
+ std::string row, teffString, bvString;
+ while (getline(teffToBvFile, row)) {
+ std::istringstream lineStream(row);
+ getline(lineStream, teffString, ',');
+ getline(lineStream, bvString);
+
+ float teffCurrent = std::stof(teffString.c_str(), nullptr);
+ float bvCurrent = std::stof(bvString.c_str(), nullptr);
+
+ if (teff > teffCurrent) {
+ teffLower = teffCurrent;
+ bvLower = bvCurrent;
+ }
+ else {
+ teffUpper = teffCurrent;
+ bvUpper = bvCurrent;
+ if (bvLower == 0.f) {
+ bv = 2.f;
+ }
+ else {
+ float bvDiff = (bvUpper - bvLower);
+ float teffDiff = (teffUpper - teffLower);
+ bv = ((bvDiff * (teff - teffLower)) / teffDiff) + bvLower;
+ }
+ break;
+ }
+ }
+ return bv;
+}
+
+documentation::Documentation ExoplanetsCsvToBinTask::documentation() {
+ using namespace documentation;
+ return {
+ "ExoplanetsCsvToBinTask",
+ "exoplanets_csv_to_bin_task",
+ {
+ {
+ "Type",
+ new StringEqualVerifier("ExoplanetsCsvToBinTask"),
+ Optional::No,
+ ""
+ },
+ {
+ KeyInputCsv,
+ new StringAnnotationVerifier("A file path to a csv file"),
+ Optional::No,
+ "The csv file to extract data from"
+ },
+ {
+ KeyInputSpeck,
+ new StringAnnotationVerifier("A file path to a speck file"),
+ Optional::No,
+ "The speck file with star locations"
+ },
+ {
+ KeyOutputBin,
+ new StringAnnotationVerifier("A valid filepath"),
+ Optional::No,
+ "The bin file to export data into"
+ },
+ {
+ KeyOutputLut,
+ new StringAnnotationVerifier("A valid filepath"),
+ Optional::No,
+ "The txt file to write look-up table into"
+ },
+ {
+ KeyTeffToBv,
+ new StringAnnotationVerifier("A valid filepath"),
+ Optional::No,
+ "The path to a teff to bv conversion file"
+ }
+ }
+ };
+}
+
+} // namespace openspace::exoplanets
diff --git a/modules/exoplanets/tasks/exoplanetscsvtobintask.h b/modules/exoplanets/tasks/exoplanetscsvtobintask.h
new file mode 100644
index 0000000000..9bbebf74ed
--- /dev/null
+++ b/modules/exoplanets/tasks/exoplanetscsvtobintask.h
@@ -0,0 +1,56 @@
+/*****************************************************************************************
+ * *
+ * OpenSpace *
+ * *
+ * Copyright (c) 2014-2020 *
+ * *
+ * 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_EXOPLANETS___EXOPLANETSCSVTOBINTASK___H__
+#define __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSCSVTOBINTASK___H__
+
+#include
+#include
+#include
+
+namespace openspace::exoplanets {
+
+class ExoplanetsCsvToBinTask : public Task {
+public:
+ ExoplanetsCsvToBinTask(const ghoul::Dictionary& dictionary);
+ std::string description() override;
+ void perform(const Task::ProgressCallback& progressCallback) override;
+ static documentation::Documentation documentation();
+
+private:
+ std::string _inputCsvPath;
+ std::string _inputSpeckPath;
+ std::string _outputBinPath;
+ std::string _outputLutPath;
+ std::string _teffToBvFilePath;
+
+ glm::vec3 starPosition(const std::string& starName);
+
+ // Compute b-v color from teff value using a conversion file
+ float bvFromTeff(float teff);
+};
+
+} // namespace openspace::exoplanets
+
+#endif // __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSCSVTOBINTASK___H__
diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp
index a623939cc4..e52afba971 100644
--- a/modules/globebrowsing/src/renderableglobe.cpp
+++ b/modules/globebrowsing/src/renderableglobe.cpp
@@ -51,7 +51,14 @@
#include
#include
#include
+#ifndef __APPLE__
#include
+#else
+#include
+namespace std {
+ using namespace experimental;
+} // namespace std
+#endif // __APPLE__
namespace {
// Global flags to modify the RenderableGlobe
@@ -261,14 +268,22 @@ const Chunk& findChunkNode(const Chunk& node, const Geodetic2& location) {
return *n;
}
-std::pmr::vector>
-tilesAndSettingsUnsorted(const LayerGroup& layerGroup, const TileIndex& tileIndex)
+#ifndef __APPLE__
+using ChunkTileVector = std::pmr::vector>;
+#else // __APPLE__
+using ChunkTileVector = std::vector>;
+#endif // __APPLE__
+
+ChunkTileVector tilesAndSettingsUnsorted(const LayerGroup& layerGroup,
+ const TileIndex& tileIndex)
{
ZoneScoped
- std::pmr::vector> tilesAndSettings(
- &global::memoryManager.TemporaryMemory
- );
+#ifndef __APPLE__
+ ChunkTileVector tilesAndSettings(&global::memoryManager.TemporaryMemory);
+#else // __APPLE__
+ ChunkTileVector tilesAndSettings;
+#endif // __APPLE__
for (Layer* layer : layerGroup.activeLayers()) {
if (layer->tileProvider()) {
tilesAndSettings.emplace_back(
@@ -294,8 +309,10 @@ BoundingHeights boundingHeightsForChunk(const Chunk& chunk, const LayerManager&
const size_t HeightChannel = 0;
const LayerGroup& heightmaps = lm.layerGroup(layergroupid::GroupID::HeightLayers);
- std::pmr::vector chunkTileSettingPairs =
- tilesAndSettingsUnsorted(heightmaps, chunk.tileIndex);
+ ChunkTileVector chunkTileSettingPairs = tilesAndSettingsUnsorted(
+ heightmaps,
+ chunk.tileIndex
+ );
bool lastHadMissingData = true;
for (const ChunkTileSettingsPair& chunkTileSettingsPair : chunkTileSettingPairs) {
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 513db837e4..70f0d93979 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -453,7 +453,7 @@ configure_file(
if (APPLE)
find_library(APPKIT_LIBRARY AppKit REQUIRED)
- target_link_libraries(openspace-core ${APPKIT_LIBRARY})
+ target_link_libraries(openspace-core PUBLIC ${APPKIT_LIBRARY})
endif ()
set_openspace_compile_settings(openspace-core)
diff --git a/src/util/time.cpp b/src/util/time.cpp
index 203abb7778..e0be6096eb 100644
--- a/src/util/time.cpp
+++ b/src/util/time.cpp
@@ -108,8 +108,8 @@ std::string_view Time::ISO8601() const {
std::memset(b, 0, S);
SpiceManager::ref().dateFromEphemerisTime(_time, b, S, Format);
-
- return std::string_view(b, S);
+
+ return std::string_view(b, S-1);
}
void Time::ISO8601(char* buffer) const {