mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-06 03:29:44 -06:00
Feature/gaia mission merge (#766)
* Add Adam Aslegård's module that renders Gaia mission stars * Add module for Gaia mission * Add CCfits and cfitsio submodules and the implemented fitsfilereader module from the OpenSpace-sun-earth-event branch * Add a TaskRunner to read from a fits file
This commit is contained in:
committed by
Alexander Bock
parent
4b696b2463
commit
0d2935c43b
@@ -39,6 +39,7 @@ set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lightsource/scenegraphlightsource.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/modelgeometry.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/multimodelgeometry.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableboxgrid.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablecartesianaxes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablemodel.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableplane.h
|
||||
@@ -82,6 +83,7 @@ set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lightsource/scenegraphlightsource.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/modelgeometry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/multimodelgeometry.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableboxgrid.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablecartesianaxes.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablemodel.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderableplane.cpp
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <modules/base/dashboard/dashboarditempropertyvalue.h>
|
||||
#include <modules/base/dashboard/dashboarditemsimulationincrement.h>
|
||||
#include <modules/base/dashboard/dashboarditemspacing.h>
|
||||
#include <modules/base/rendering/renderableboxgrid.h>
|
||||
#include <modules/base/dashboard/dashboarditemvelocity.h>
|
||||
#include <modules/base/lightsource/cameralightsource.h>
|
||||
#include <modules/base/lightsource/scenegraphlightsource.h>
|
||||
@@ -117,6 +118,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
auto fRenderable = FactoryManager::ref().factory<Renderable>();
|
||||
ghoul_assert(fRenderable, "Renderable factory was not created");
|
||||
|
||||
fRenderable->registerClass<RenderableBoxGrid>("RenderableBoxGrid");
|
||||
fRenderable->registerClass<RenderableCartesianAxes>("RenderableCartesianAxes");
|
||||
fRenderable->registerClass<RenderableModel>("RenderableModel");
|
||||
fRenderable->registerClass<RenderablePlaneImageLocal>("RenderablePlaneImageLocal");
|
||||
@@ -181,6 +183,7 @@ std::vector<documentation::Documentation> BaseModule::documentations() const {
|
||||
DashboardItemSpacing::Documentation(),
|
||||
DashboardItemVelocity::Documentation(),
|
||||
|
||||
RenderableBoxGrid::Documentation(),
|
||||
RenderableModel::Documentation(),
|
||||
RenderablePlane::Documentation(),
|
||||
RenderableSphere::Documentation(),
|
||||
|
||||
320
modules/base/rendering/renderableboxgrid.cpp
Normal file
320
modules/base/rendering/renderableboxgrid.cpp
Normal file
@@ -0,0 +1,320 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/base/rendering/renderableboxgrid.h>
|
||||
|
||||
#include <modules/base/basemodule.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/util/spicemanager.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/opengl/programobject.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* ProgramName = "GridProgram";
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo GridColorInfo = {
|
||||
"GridColor",
|
||||
"Grid Color",
|
||||
"This value determines the color of the grid lines that are rendered."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo GridMatrixInfo = {
|
||||
"GridMatrix",
|
||||
"Grid Matrix",
|
||||
"This value specifies the local transformation matrix that defines the "
|
||||
"orientation of this grid relative to the parent's rotation."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SegmentsInfo = {
|
||||
"Segments",
|
||||
"Number of Segments",
|
||||
"This value specifies the number of segments that are used to render the "
|
||||
"surrounding sphere."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo LineWidthInfo = {
|
||||
"LineWidth",
|
||||
"Line Width",
|
||||
"This value specifies the line width of the spherical grid."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SizeInfo = {
|
||||
"Size",
|
||||
"Grid Size",
|
||||
"This value species the size of each dimensions of the box"
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation RenderableBoxGrid::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableSphericalGrid",
|
||||
"base_renderable_sphericalgrid",
|
||||
{
|
||||
{
|
||||
GridMatrixInfo.identifier,
|
||||
new DoubleMatrix4x4Verifier,
|
||||
Optional::Yes,
|
||||
GridMatrixInfo.description
|
||||
},
|
||||
{
|
||||
GridColorInfo.identifier,
|
||||
new DoubleVector4Verifier,
|
||||
Optional::Yes,
|
||||
GridColorInfo.description
|
||||
},
|
||||
{
|
||||
SegmentsInfo.identifier,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
SegmentsInfo.description
|
||||
},
|
||||
{
|
||||
LineWidthInfo.identifier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
LineWidthInfo.description
|
||||
},
|
||||
{
|
||||
SizeInfo.identifier,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
SizeInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
RenderableBoxGrid::RenderableBoxGrid(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
, _gridMatrix(GridMatrixInfo, glm::mat4(1.f))
|
||||
, _gridColor(
|
||||
GridColorInfo,
|
||||
glm::vec4(0.5f, 0.5, 0.5f, 1.f),
|
||||
glm::vec4(0.f),
|
||||
glm::vec4(1.f)
|
||||
)
|
||||
, _segments(SegmentsInfo, 36, 4, 200)
|
||||
, _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f)
|
||||
, _size(SizeInfo, glm::vec3(1e20f), glm::vec3(1.f), glm::vec3(1e35f))
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"RenderableBoxGrid"
|
||||
);
|
||||
|
||||
addProperty(_opacity);
|
||||
registerUpdateRenderBinFromOpacity();
|
||||
|
||||
if (dictionary.hasKey(GridMatrixInfo.identifier)) {
|
||||
_gridMatrix = dictionary.value<glm::dmat4>(GridMatrixInfo.identifier);
|
||||
}
|
||||
addProperty(_gridMatrix);
|
||||
|
||||
if (dictionary.hasKey(GridColorInfo.identifier)) {
|
||||
_gridColor = dictionary.value<glm::vec4>(GridColorInfo.identifier);
|
||||
}
|
||||
_gridColor.setViewOption(properties::Property::ViewOptions::Color);
|
||||
addProperty(_gridColor);
|
||||
|
||||
if (dictionary.hasKey(SegmentsInfo.identifier)) {
|
||||
_segments = static_cast<int>(dictionary.value<double>(SegmentsInfo.identifier));
|
||||
}
|
||||
_segments.onChange([&]() { _gridIsDirty = true; });
|
||||
addProperty(_segments);
|
||||
|
||||
if (dictionary.hasKey(LineWidthInfo.identifier)) {
|
||||
_lineWidth = static_cast<float>(
|
||||
dictionary.value<double>(LineWidthInfo.identifier)
|
||||
);
|
||||
}
|
||||
addProperty(_lineWidth);
|
||||
|
||||
if (dictionary.hasKey(SizeInfo.identifier)) {
|
||||
_size = dictionary.value<glm::vec3>(SizeInfo.identifier);
|
||||
}
|
||||
_size.onChange([&]() { _gridIsDirty = true; });
|
||||
addProperty(_size);
|
||||
}
|
||||
|
||||
bool RenderableBoxGrid::isReady() const {
|
||||
return _gridProgram != nullptr;
|
||||
}
|
||||
|
||||
void RenderableBoxGrid::initializeGL() {
|
||||
_gridProgram = BaseModule::ProgramObjectManager.request(
|
||||
ProgramName,
|
||||
[]() -> std::unique_ptr<ghoul::opengl::ProgramObject> {
|
||||
return global::renderEngine.buildRenderProgram(
|
||||
ProgramName,
|
||||
absPath("${MODULE_BASE}/shaders/grid_vs.glsl"),
|
||||
absPath("${MODULE_BASE}/shaders/grid_fs.glsl")
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
glGenVertexArrays(1, &_vaoID);
|
||||
glGenBuffers(1, &_vBufferID);
|
||||
|
||||
glBindVertexArray(_vaoID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void RenderableBoxGrid::deinitializeGL() {
|
||||
glDeleteVertexArrays(1, &_vaoID);
|
||||
_vaoID = 0;
|
||||
|
||||
glDeleteBuffers(1, &_vBufferID);
|
||||
_vBufferID = 0;
|
||||
|
||||
BaseModule::ProgramObjectManager.release(
|
||||
ProgramName,
|
||||
[](ghoul::opengl::ProgramObject* p) {
|
||||
global::renderEngine.removeRenderProgram(p);
|
||||
}
|
||||
);
|
||||
_gridProgram = nullptr;
|
||||
}
|
||||
|
||||
void RenderableBoxGrid::render(const RenderData& data, RendererTasks&){
|
||||
_gridProgram->activate();
|
||||
|
||||
_gridProgram->setUniform("opacity", _opacity);
|
||||
|
||||
glm::dmat4 modelTransform =
|
||||
glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation
|
||||
glm::dmat4(data.modelTransform.rotation) * // Spice rotation
|
||||
glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale));
|
||||
|
||||
glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform;
|
||||
|
||||
_gridProgram->setUniform("modelViewTransform", glm::mat4(modelViewTransform));
|
||||
_gridProgram->setUniform("projectionTransform", data.camera.projectionMatrix());
|
||||
|
||||
_gridProgram->setUniform("gridColor", _gridColor);
|
||||
|
||||
glLineWidth(_lineWidth);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
glBindVertexArray(_vaoID);
|
||||
glDrawArrays(_mode, 0, _varray.size());
|
||||
glBindVertexArray(0);
|
||||
|
||||
_gridProgram->deactivate();
|
||||
}
|
||||
|
||||
void RenderableBoxGrid::update(const UpdateData&) {
|
||||
if (_gridIsDirty) {
|
||||
//_vsize = (_segments + 1) * (_segments + 1);
|
||||
//_varray.resize(_vsize);
|
||||
|
||||
const glm::vec3 llf = -_size.value() / 2.f;
|
||||
const glm::vec3 urb = _size.value() / 2.f;
|
||||
|
||||
// 7
|
||||
// -------------------- 6
|
||||
// / /
|
||||
// /| /|
|
||||
// 4 / | / |
|
||||
// x-------------------x |
|
||||
// | | |5 |
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 3/----------------|--/ 2
|
||||
// | / | /
|
||||
// |/ |/
|
||||
// x-------------------x
|
||||
// 0 1
|
||||
//
|
||||
//
|
||||
// For Line strip:
|
||||
// 0 -> 1 -> 2 -> 3 -> 0 -> 4 -> 5 -> 6 -> 7 -> 4 -> 5(d) -> 1 -> 2(d) -> 6
|
||||
// -> 7(d) -> 3
|
||||
|
||||
const glm::vec3 v0 = { llf.x, llf.y, llf.z };
|
||||
const glm::vec3 v1 = { urb.x, llf.y, llf.z };
|
||||
const glm::vec3 v2 = { urb.x, urb.y, llf.z };
|
||||
const glm::vec3 v3 = { llf.x, urb.y, llf.z };
|
||||
const glm::vec3 v4 = { llf.x, llf.y, urb.z };
|
||||
const glm::vec3 v5 = { urb.x, llf.y, urb.z };
|
||||
const glm::vec3 v6 = { urb.x, urb.y, urb.z };
|
||||
const glm::vec3 v7 = { llf.x, urb.y, urb.z };
|
||||
|
||||
// First add the bounds
|
||||
_varray.push_back({ v0.x, v0.y, v0.z });
|
||||
_varray.push_back({ v1.x, v1.y, v1.z });
|
||||
_varray.push_back({ v2.x, v2.y, v2.z });
|
||||
_varray.push_back({ v3.x, v3.y, v3.z });
|
||||
_varray.push_back({ v0.x, v0.y, v0.z });
|
||||
_varray.push_back({ v4.x, v4.y, v4.z });
|
||||
_varray.push_back({ v5.x, v5.y, v5.z });
|
||||
_varray.push_back({ v6.x, v6.y, v6.z });
|
||||
_varray.push_back({ v7.x, v7.y, v7.z });
|
||||
_varray.push_back({ v4.x, v4.y, v4.z });
|
||||
_varray.push_back({ v5.x, v5.y, v5.z });
|
||||
_varray.push_back({ v1.x, v1.y, v1.z });
|
||||
_varray.push_back({ v2.x, v2.y, v2.z });
|
||||
_varray.push_back({ v6.x, v6.y, v6.z });
|
||||
_varray.push_back({ v7.x, v7.y, v7.z });
|
||||
_varray.push_back({ v3.x, v3.y, v3.z });
|
||||
|
||||
|
||||
glBindVertexArray(_vaoID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
_varray.size() * sizeof(Vertex),
|
||||
_varray.data(),
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
|
||||
glVertexAttribPointer(
|
||||
0,
|
||||
3,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(Vertex),
|
||||
nullptr // = reinterpret_cast<const GLvoid*>(offsetof(Vertex, location))
|
||||
);
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
_gridIsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
83
modules/base/rendering/renderableboxgrid.h
Normal file
83
modules/base/rendering/renderableboxgrid.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEBOXGRID___H__
|
||||
#define __OPENSPACE_MODULE_BASE___RENDERABLEBOXGRID___H__
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/matrix/dmat4property.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/vector/vec3property.h>
|
||||
#include <openspace/properties/vector/vec4property.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
|
||||
namespace ghoul::opengl {
|
||||
class ProgramObject;
|
||||
} // namespace ghoul::opengl
|
||||
|
||||
namespace openspace::documentation { struct Documentation; }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class RenderableBoxGrid : public Renderable {
|
||||
public:
|
||||
RenderableBoxGrid(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();
|
||||
|
||||
protected:
|
||||
struct Vertex {
|
||||
float location[3];
|
||||
};
|
||||
|
||||
ghoul::opengl::ProgramObject* _gridProgram = nullptr;
|
||||
|
||||
properties::DMat4Property _gridMatrix;
|
||||
properties::Vec4Property _gridColor;
|
||||
properties::IntProperty _segments;
|
||||
properties::FloatProperty _lineWidth;
|
||||
properties::Vec3Property _size;
|
||||
|
||||
bool _gridIsDirty = true;
|
||||
|
||||
GLuint _vaoID = 0;
|
||||
GLuint _vBufferID = 0;
|
||||
|
||||
GLenum _mode = GL_LINE_STRIP;
|
||||
std::vector<Vertex> _varray;
|
||||
};
|
||||
|
||||
}// namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_BASE___RENDERABLEBOXGRID___H__
|
||||
@@ -217,6 +217,12 @@ documentation::Documentation FixedRotation::Documentation() {
|
||||
Optional::Yes,
|
||||
XAxisOrthogonalVectorInfo.description
|
||||
},
|
||||
{
|
||||
XAxisInvertObjectInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
XAxisInvertObjectInfo.description
|
||||
},
|
||||
{
|
||||
KeyYAxis,
|
||||
new OrVerifier({ new StringVerifier, new DoubleVector3Verifier, }),
|
||||
@@ -234,6 +240,12 @@ documentation::Documentation FixedRotation::Documentation() {
|
||||
Optional::Yes,
|
||||
YAxisOrthogonalVectorInfo.description
|
||||
},
|
||||
{
|
||||
YAxisInvertObjectInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
YAxisInvertObjectInfo.description
|
||||
},
|
||||
{
|
||||
KeyZAxis,
|
||||
new OrVerifier({ new StringVerifier, new DoubleVector3Verifier, }),
|
||||
@@ -251,6 +263,12 @@ documentation::Documentation FixedRotation::Documentation() {
|
||||
Optional::Yes,
|
||||
ZAxisOrthogonalVectorInfo.description
|
||||
},
|
||||
{
|
||||
ZAxisInvertObjectInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
ZAxisInvertObjectInfo.description
|
||||
},
|
||||
{
|
||||
AttachedInfo.identifier,
|
||||
new StringVerifier,
|
||||
@@ -454,6 +472,11 @@ bool FixedRotation::initialize() {
|
||||
if (_constructorDictionary.hasKey(KeyXAxisOrthogonal)) {
|
||||
_xAxis.isOrthogonal = _constructorDictionary.value<bool>(KeyXAxisOrthogonal);
|
||||
}
|
||||
if (_constructorDictionary.hasKey(XAxisInvertObjectInfo.identifier)) {
|
||||
_xAxis.invertObject = _constructorDictionary.value<bool>(
|
||||
XAxisInvertObjectInfo.identifier
|
||||
);
|
||||
}
|
||||
if (_xAxis.isOrthogonal) {
|
||||
_xAxis.type = Axis::Type::OrthogonalVector;
|
||||
}
|
||||
@@ -474,6 +497,11 @@ bool FixedRotation::initialize() {
|
||||
if (_constructorDictionary.hasKey(KeyYAxisOrthogonal)) {
|
||||
_yAxis.isOrthogonal = _constructorDictionary.value<bool>(KeyYAxisOrthogonal);
|
||||
}
|
||||
if (_constructorDictionary.hasKey(YAxisInvertObjectInfo.identifier)) {
|
||||
_yAxis.invertObject = _constructorDictionary.value<bool>(
|
||||
YAxisInvertObjectInfo.identifier
|
||||
);
|
||||
}
|
||||
if (_yAxis.isOrthogonal) {
|
||||
_yAxis.type = Axis::Type::OrthogonalVector;
|
||||
}
|
||||
@@ -494,12 +522,16 @@ bool FixedRotation::initialize() {
|
||||
if (_constructorDictionary.hasKey(KeyZAxisOrthogonal)) {
|
||||
_zAxis.isOrthogonal = _constructorDictionary.value<bool>(KeyZAxisOrthogonal);
|
||||
}
|
||||
if (_constructorDictionary.hasKey(ZAxisInvertObjectInfo.identifier)) {
|
||||
_yAxis.invertObject = _constructorDictionary.value<bool>(
|
||||
ZAxisInvertObjectInfo.identifier
|
||||
);
|
||||
}
|
||||
if (_zAxis.isOrthogonal) {
|
||||
_zAxis.type = Axis::Type::OrthogonalVector;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!hasXAxis && hasYAxis && hasZAxis) {
|
||||
_xAxis.type = Axis::Type::CoordinateSystemCompletion;
|
||||
}
|
||||
@@ -554,11 +586,14 @@ glm::vec3 FixedRotation::xAxis() const {
|
||||
return glm::vec3(1.f, 0.f, 0.f);
|
||||
case Axis::Type::Object:
|
||||
if (_xAxis.node && _attachedNode) {
|
||||
glm::vec3 dir = glm::vec3(glm::normalize(
|
||||
_xAxis.node->worldPosition() -
|
||||
_attachedNode->worldPosition()
|
||||
));
|
||||
return _xAxis.invertObject ? -dir : dir;
|
||||
glm::dvec3 dir = _xAxis.node->worldPosition() -
|
||||
_attachedNode->worldPosition();
|
||||
|
||||
if (dir == glm::dvec3(0.0)) {
|
||||
dir = glm::dvec3(1.0, 0.0, 0.0);
|
||||
}
|
||||
glm::vec3 dirNorm = glm::vec3(glm::normalize(dir));
|
||||
return _xAxis.invertObject ? -dirNorm : dirNorm;
|
||||
}
|
||||
else {
|
||||
if (_xAxis.node) {
|
||||
|
||||
56
modules/fitsfilereader/CMakeLists.txt
Normal file
56
modules/fitsfilereader/CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
##########################################################################################
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2018 #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
|
||||
# software and associated documentation files (the "Software"), to deal in the Software #
|
||||
# without restriction, including without limitation the rights to use, copy, modify, #
|
||||
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to #
|
||||
# permit persons to whom the Software is furnished to do so, subject to the following #
|
||||
# conditions: #
|
||||
# #
|
||||
# The above copyright notice and this permission notice shall be included in all copies #
|
||||
# or substantial portions of the Software. #
|
||||
# #
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
|
||||
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A #
|
||||
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF #
|
||||
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE #
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/fitsfilereadermodule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/fitsfilereader.h
|
||||
)
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/fitsfilereadermodule.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/fitsfilereader.cpp
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
create_new_module(
|
||||
"FitsFileReader"
|
||||
fitsfilereader
|
||||
${HEADER_FILES}
|
||||
${SOURCE_FILES})
|
||||
|
||||
# Set root directories for external libraries.
|
||||
set(CFITSIO_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/cfitsio/")
|
||||
set(CCFITS_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/CCfits/")
|
||||
set(INCLUDES_FOR_TARGET ${CCFITS_ROOT_DIR} "${CCFITS_ROOT_DIR}/../" ${CFITSIO_ROOT_DIR})
|
||||
set(MODULE_NAME openspace-module-fitsfilereader)
|
||||
|
||||
# CCfits is dependent on cfitsio, let it handle the internal linking
|
||||
add_subdirectory(${CFITSIO_ROOT_DIR})
|
||||
add_subdirectory(${CCFITS_ROOT_DIR})
|
||||
|
||||
TARGET_INCLUDE_DIRECTORIES(${MODULE_NAME} SYSTEM PUBLIC ${INCLUDES_FOR_TARGET})
|
||||
TARGET_LINK_LIBRARIES(${MODULE_NAME} CCfits)
|
||||
1
modules/fitsfilereader/ext/CCfits
Submodule
1
modules/fitsfilereader/ext/CCfits
Submodule
Submodule modules/fitsfilereader/ext/CCfits added at 48400ae262
1
modules/fitsfilereader/ext/cfitsio
Submodule
1
modules/fitsfilereader/ext/cfitsio
Submodule
Submodule modules/fitsfilereader/ext/cfitsio added at b267f17603
31
modules/fitsfilereader/fitsfilereadermodule.cpp
Normal file
31
modules/fitsfilereader/fitsfilereadermodule.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/fitsfilereader/fitsfilereadermodule.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
FitsFileReaderModule::FitsFileReaderModule() : OpenSpaceModule(Name) {}
|
||||
|
||||
} // namespace openspace
|
||||
41
modules/fitsfilereader/fitsfilereadermodule.h
Normal file
41
modules/fitsfilereader/fitsfilereadermodule.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_FITSFILEREADER___FITSFILEREADERMODULE___H__
|
||||
#define __OPENSPACE_MODULE_FITSFILEREADER___FITSFILEREADERMODULE___H__
|
||||
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class FitsFileReaderModule : public OpenSpaceModule {
|
||||
public:
|
||||
constexpr static const char* Name = "FitsFileReader";
|
||||
|
||||
FitsFileReaderModule();
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_FITSFILEREADER___FITSFILEREADERMODULE___H__
|
||||
0
modules/fitsfilereader/include.cmake
Normal file
0
modules/fitsfilereader/include.cmake
Normal file
116
modules/fitsfilereader/include/fitsfilereader.h
Normal file
116
modules/fitsfilereader/include/fitsfilereader.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_FITSFILEREADER___FITSFILEREADER___H__
|
||||
#define __OPENSPACE_MODULE_FITSFILEREADER___FITSFILEREADER___H__
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
namespace CCfits {
|
||||
class FITS;
|
||||
class PHDU;
|
||||
class ExtHDU;
|
||||
} // namespace CCfits
|
||||
|
||||
namespace ghoul::opengl { class Texture; }
|
||||
|
||||
namespace openspace {
|
||||
|
||||
template<typename T>
|
||||
struct ImageData {
|
||||
std::valarray<T> contents;
|
||||
long int width;
|
||||
long int height;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct TableData {
|
||||
std::unordered_map<std::string, std::vector<T>> contents;
|
||||
int readRows;
|
||||
long int optimalRowsize;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class FitsFileReader {
|
||||
public:
|
||||
FitsFileReader(bool verboseMode);
|
||||
~FitsFileReader();
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<ImageData<T>> readImage(const std::string& path);
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<std::unordered_map<std::string, T>> readHeader(
|
||||
std::vector<std::string>& keywords);
|
||||
template<typename T>
|
||||
std::shared_ptr<T> readHeaderValue(const std::string key);
|
||||
|
||||
/**
|
||||
* Read specified table columns from fits file.
|
||||
* If <code>readAll</code> is set to true the entire table will be read before the
|
||||
* selected columns, which makes the function take a lot longer if it's a big file.
|
||||
* If no HDU index is given the current Extension HDU will be read from.
|
||||
*/
|
||||
template<typename T>
|
||||
std::shared_ptr<TableData<T>> readTable(std::string& path,
|
||||
const std::vector<std::string>& columnNames, int startRow = 1, int endRow = 10,
|
||||
int hduIdx = 1, bool readAll = false);
|
||||
|
||||
/**
|
||||
* Reads a single FITS file with pre-defined columns (defined for Viennas TGAS-file).
|
||||
* Returns a vector with all read stars with <code>nValuesPerStar</code>.
|
||||
* If additional columns are given by <code>filterColumnNames</code>, they will be
|
||||
* read but it will slow doen the reading tremendously.
|
||||
*/
|
||||
std::vector<float> readFitsFile(std::string filePath, int& nValuesPerStar,
|
||||
int firstRow, int lastRow, std::vector<std::string> filterColumnNames,
|
||||
int multiplier = 1);
|
||||
|
||||
/**
|
||||
* Reads a single SPECK file and returns a vector with <code>nRenderValues</code>
|
||||
* per star. Reads data in pre-defined order based on AMNH's star data files.
|
||||
*/
|
||||
std::vector<float> readSpeckFile(std::string filePath, int& nRenderValues);
|
||||
|
||||
private:
|
||||
std::unique_ptr<CCfits::FITS> _infile;
|
||||
bool _verboseMode;
|
||||
|
||||
bool isPrimaryHDU();
|
||||
template<typename T>
|
||||
const std::shared_ptr<ImageData<T>> readImageInternal(CCfits::PHDU& image);
|
||||
template<typename T>
|
||||
const std::shared_ptr<ImageData<T>> readImageInternal(CCfits::ExtHDU& image);
|
||||
|
||||
mutable std::mutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_FITSFILEREADER___FITSFILEREADER___H__
|
||||
668
modules/fitsfilereader/src/fitsfilereader.cpp
Normal file
668
modules/fitsfilereader/src/fitsfilereader.cpp
Normal file
@@ -0,0 +1,668 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/fitsfilereader/include/fitsfilereader.h>
|
||||
|
||||
#include <openspace/util/distanceconversion.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <CCfits>
|
||||
#include <fstream>
|
||||
|
||||
using namespace CCfits;
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "FitsFileReader";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
FitsFileReader::FitsFileReader(bool verboseMode) {
|
||||
_verboseMode = verboseMode;
|
||||
FITS::setVerboseMode(_verboseMode);
|
||||
}
|
||||
|
||||
FitsFileReader::~FitsFileReader() {
|
||||
if (_infile) {
|
||||
_infile->destroy();
|
||||
_infile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool FitsFileReader::isPrimaryHDU() {
|
||||
return _infile->extension().size() == 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<ImageData<T>> FitsFileReader::readImage(const std::string& path) {
|
||||
try {
|
||||
_infile = std::make_unique<FITS>(path, Read, true);
|
||||
// Primary HDU Object
|
||||
if (isPrimaryHDU()) {
|
||||
return readImageInternal<T>(_infile->pHDU());
|
||||
}
|
||||
// Extension HDU Object
|
||||
return readImageInternal<T>(_infile->currentExtension());
|
||||
} catch (const FitsException& e){
|
||||
LERROR("Could not read FITS image from table. " + e.message() );
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<std::unordered_map<std::string, T>> FitsFileReader::readHeader(
|
||||
std::vector<std::string>& keywords)
|
||||
{
|
||||
try {
|
||||
HDU& image = isPrimaryHDU() ?
|
||||
static_cast<HDU&>(_infile->pHDU()) :
|
||||
static_cast<HDU&>(_infile->currentExtension());
|
||||
|
||||
std::vector<T> values;
|
||||
image.readKeys(keywords, values);
|
||||
|
||||
if (values.size() != keywords.size()) {
|
||||
LERROR("Number of keywords does not match number of values");
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, T> result;
|
||||
std::transform(
|
||||
keywords.begin(),
|
||||
keywords.end(),
|
||||
values.begin(),
|
||||
std::inserter(
|
||||
result,
|
||||
result.end()
|
||||
),
|
||||
[](std::string key, T value) { return std::make_pair(key, value); }
|
||||
);
|
||||
return std::make_shared<std::unordered_map<std::string, T>>(std::move(result));
|
||||
} catch (const FitsException& e) {
|
||||
LERROR("Could not read FITS header. " + e.message() );
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> FitsFileReader::readHeaderValue(const std::string key) {
|
||||
try {
|
||||
HDU& image = isPrimaryHDU() ?
|
||||
static_cast<HDU&>(_infile->pHDU()) :
|
||||
static_cast<HDU&>(_infile->currentExtension());
|
||||
|
||||
T value;
|
||||
image.readKey(key, value);
|
||||
return std::make_unique<T>(value);
|
||||
} catch (FitsException& e) {
|
||||
LERROR("Could not read FITS key. " + e.message() );
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<TableData<T>> FitsFileReader::readTable(std::string& path,
|
||||
const std::vector<std::string>& columnNames,
|
||||
int startRow,
|
||||
int endRow,
|
||||
int hduIdx,
|
||||
bool readAll)
|
||||
{
|
||||
// We need to lock reading when using multithreads because CCfits can't handle
|
||||
// multiple I/O drivers.
|
||||
std::lock_guard g(_mutex);
|
||||
|
||||
try {
|
||||
_infile = std::make_unique<FITS>(path, Read, readAll);
|
||||
|
||||
// Make sure FITS file is not a Primary HDU Object (aka an image).
|
||||
if (!isPrimaryHDU()) {
|
||||
ExtHDU& table = _infile->extension(hduIdx);
|
||||
int numCols = columnNames.size();
|
||||
int numRowsInTable = table.rows();
|
||||
std::unordered_map<string, std::vector<T>> contents;
|
||||
//LINFO("Read file: " + _infile->name());
|
||||
|
||||
int firstRow = std::max(startRow, 1);
|
||||
|
||||
if (endRow < firstRow) {
|
||||
endRow = numRowsInTable;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numCols; ++i) {
|
||||
std::vector<T> columnData;
|
||||
//LINFO("Read column: " + columnNames[i]);
|
||||
table.column(columnNames[i]).read(columnData, firstRow, endRow);
|
||||
contents[columnNames[i]] = columnData;
|
||||
}
|
||||
|
||||
// Create TableData object of table contents.
|
||||
TableData<T> loadedTable = {
|
||||
std::move(contents),
|
||||
static_cast<int>(table.rows()),
|
||||
table.getRowsize(),
|
||||
table.name()
|
||||
};
|
||||
|
||||
return std::make_shared<TableData<T>>(loadedTable);
|
||||
}
|
||||
}
|
||||
catch (FitsException& e) {
|
||||
LERROR(fmt::format(
|
||||
"Could not read FITS table from file '{}'. Make sure it's not an image file.",
|
||||
e.message()
|
||||
));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<float> FitsFileReader::readFitsFile(std::string filePath, int& nValuesPerStar,
|
||||
int firstRow, int lastRow,
|
||||
std::vector<std::string> filterColumnNames,
|
||||
int multiplier)
|
||||
{
|
||||
std::vector<float> fullData;
|
||||
srand(1234567890);
|
||||
if (firstRow <= 0) {
|
||||
firstRow = 1;
|
||||
}
|
||||
|
||||
// Define what columns to read.
|
||||
std::vector<std::string> allColumnNames = {
|
||||
"Position_X",
|
||||
"Position_Y",
|
||||
"Position_Z",
|
||||
"Velocity_X",
|
||||
"Velocity_Y",
|
||||
"Velocity_Z",
|
||||
"Gaia_Parallax",
|
||||
"Gaia_G_Mag",
|
||||
"Tycho_B_Mag",
|
||||
"Tycho_V_Mag",
|
||||
"Gaia_Parallax_Err",
|
||||
"Gaia_Proper_Motion_RA",
|
||||
"Gaia_Proper_Motion_RA_Err",
|
||||
"Gaia_Proper_Motion_Dec",
|
||||
"Gaia_Proper_Motion_Dec_Err",
|
||||
"Tycho_B_Mag_Err",
|
||||
"Tycho_V_Mag_Err"
|
||||
};
|
||||
|
||||
// Append additional filter parameters to default rendering parameters.
|
||||
allColumnNames.insert(
|
||||
allColumnNames.end(),
|
||||
filterColumnNames.begin(),
|
||||
filterColumnNames.end()
|
||||
);
|
||||
|
||||
std::string allNames = "Columns to read: \n";
|
||||
for (const std::string& colName : allColumnNames) {
|
||||
allNames += colName + "\n";
|
||||
}
|
||||
LINFO(allNames);
|
||||
|
||||
// Read columns from FITS file. If rows aren't specified then full table will be read.
|
||||
std::shared_ptr<TableData<float>> table = readTable<float>(
|
||||
filePath,
|
||||
allColumnNames,
|
||||
firstRow,
|
||||
lastRow
|
||||
);
|
||||
|
||||
if (!table) {
|
||||
throw ghoul::RuntimeError(fmt::format("Failed to open Fits file '{}'", filePath));
|
||||
}
|
||||
|
||||
int nStars = table->readRows - firstRow + 1;
|
||||
|
||||
int nNullArr = 0;
|
||||
size_t nColumnsRead = allColumnNames.size();
|
||||
size_t defaultCols = 17; // Number of columns that are copied by predefined code.
|
||||
if (nColumnsRead != defaultCols) {
|
||||
LINFO("Additional columns will be read! Consider add column in code for "
|
||||
"significant speedup!");
|
||||
}
|
||||
// Declare how many values to save per star
|
||||
nValuesPerStar = nColumnsRead + 1; // +1 for B-V color value.
|
||||
|
||||
// Copy columns to local variables.
|
||||
std::unordered_map<std::string, std::vector<float>>& tableContent = table->contents;
|
||||
|
||||
// Default render parameters!
|
||||
std::vector<float> posXcol = std::move(tableContent[allColumnNames[0]]);
|
||||
std::vector<float> posYcol = std::move(tableContent[allColumnNames[1]]);
|
||||
std::vector<float> posZcol = std::move(tableContent[allColumnNames[2]]);
|
||||
std::vector<float> velXcol = std::move(tableContent[allColumnNames[3]]);
|
||||
std::vector<float> velYcol = std::move(tableContent[allColumnNames[4]]);
|
||||
std::vector<float> velZcol = std::move(tableContent[allColumnNames[5]]);
|
||||
std::vector<float> parallax = std::move(tableContent[allColumnNames[6]]);
|
||||
std::vector<float> magCol = std::move(tableContent[allColumnNames[7]]);
|
||||
std::vector<float> tycho_b = std::move(tableContent[allColumnNames[8]]);
|
||||
std::vector<float> tycho_v = std::move(tableContent[allColumnNames[9]]);
|
||||
|
||||
// Default filter parameters
|
||||
// Additional filter parameters are handled as well but slows down reading
|
||||
std::vector<float> parallax_err = std::move(tableContent[allColumnNames[10]]);
|
||||
std::vector<float> pr_mot_ra = std::move(tableContent[allColumnNames[11]]);
|
||||
std::vector<float> pr_mot_ra_err = std::move(tableContent[allColumnNames[12]]);
|
||||
std::vector<float> pr_mot_dec = std::move(tableContent[allColumnNames[13]]);
|
||||
std::vector<float> pr_mot_dec_err = std::move(tableContent[allColumnNames[14]]);
|
||||
std::vector<float> tycho_b_err = std::move(tableContent[allColumnNames[15]]);
|
||||
std::vector<float> tycho_v_err = std::move(tableContent[allColumnNames[16]]);
|
||||
|
||||
// Construct data array. OBS: ORDERING IS IMPORTANT! This is where slicing happens.
|
||||
for (int i = 0; i < nStars * multiplier; ++i) {
|
||||
std::vector<float> values(nValuesPerStar);
|
||||
size_t idx = 0;
|
||||
|
||||
// Default order for rendering:
|
||||
// Position [X, Y, Z]
|
||||
// Absolute Magnitude
|
||||
// B-V Color
|
||||
// Velocity [X, Y, Z]
|
||||
|
||||
// Store positions.
|
||||
values[idx++] = posXcol[i % nStars];
|
||||
values[idx++] = posYcol[i % nStars];
|
||||
values[idx++] = posZcol[i % nStars];
|
||||
|
||||
// Return early if star doesn't have a measured position.
|
||||
if (values[0] == -999 && values[1] == -999 && values[2] == -999) {
|
||||
nNullArr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store color values.
|
||||
values[idx++] = magCol[i % nStars] == -999 ? 20.f : magCol[i % nStars];
|
||||
values[idx++] = tycho_b[i % nStars] - tycho_v[i % nStars];
|
||||
|
||||
// Store velocity. Convert it to m/s with help by parallax.
|
||||
values[idx++] = convertMasPerYearToMeterPerSecond(
|
||||
velXcol[i % nStars],
|
||||
parallax[i % nStars]
|
||||
);
|
||||
values[idx++] = convertMasPerYearToMeterPerSecond(
|
||||
velYcol[i % nStars],
|
||||
parallax[i % nStars]
|
||||
);
|
||||
values[idx++] = convertMasPerYearToMeterPerSecond(
|
||||
velZcol[i % nStars],
|
||||
parallax[i % nStars]
|
||||
);
|
||||
|
||||
// Store additional parameters to filter by.
|
||||
values[idx++] = parallax[i % nStars];
|
||||
values[idx++] = parallax_err[i % nStars];
|
||||
values[idx++] = pr_mot_ra[i % nStars];
|
||||
values[idx++] = pr_mot_ra_err[i % nStars];
|
||||
values[idx++] = pr_mot_dec[i % nStars];
|
||||
values[idx++] = pr_mot_dec_err[i % nStars];
|
||||
values[idx++] = tycho_b[i % nStars];
|
||||
values[idx++] = tycho_b_err[i % nStars];
|
||||
values[idx++] = tycho_v[i % nStars];
|
||||
values[idx++] = tycho_v_err[i % nStars];
|
||||
|
||||
// Read extra columns, if any. This will slow down the sorting tremendously!
|
||||
for (size_t col = defaultCols; col < nColumnsRead; ++col) {
|
||||
std::vector<float> vecData = std::move(tableContent[allColumnNames[col]]);
|
||||
values[idx++] = vecData[i];
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < nValuesPerStar; ++j) {
|
||||
// The astronomers in Vienna use -999 as default value. Change it to 0.
|
||||
if (values[j] == -999) {
|
||||
values[j] = 0.f;
|
||||
}
|
||||
else if (multiplier > 1) {
|
||||
values[j] *= static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
fullData.insert(fullData.end(), values.begin(), values.end());
|
||||
}
|
||||
|
||||
// Define what columns to read.
|
||||
/*auto allColumnNames = std::vector<std::string>({
|
||||
"ra",
|
||||
"dec",
|
||||
"parallax",
|
||||
"pmra",
|
||||
"pmdec",
|
||||
"phot_g_mean_mag",
|
||||
"phot_bp_mean_mag",
|
||||
"phot_rp_mean_mag",
|
||||
"radial_velocity",
|
||||
});
|
||||
// Append additional filter parameters to default rendering parameters.
|
||||
allColumnNames.insert(allColumnNames.end(), filterColumnNames.begin(),
|
||||
filterColumnNames.end());
|
||||
|
||||
std::string allNames = "Columns to read: \n";
|
||||
for (auto colName : allColumnNames) {
|
||||
allNames += colName + "\n";
|
||||
}
|
||||
LINFO(allNames);
|
||||
|
||||
// Read columns from FITS file. If rows aren't specified then full table will be read.
|
||||
auto table = readTable<float>(filePath, allColumnNames, firstRow, lastRow);
|
||||
|
||||
if (!table) {
|
||||
throw ghoul::RuntimeError(fmt::format("Failed to open Fits file '{}'", filePath));
|
||||
}
|
||||
|
||||
int nStars = table->readRows - firstRow + 1;
|
||||
|
||||
int nNullArr = 0;
|
||||
size_t nColumnsRead = allColumnNames.size();
|
||||
size_t defaultCols = 9; // Number of columns that are copied by predefined code.
|
||||
if (nColumnsRead != defaultCols) {
|
||||
LINFO("Additional columns will be read! Consider add column in code for "
|
||||
"significant speedup!");
|
||||
}
|
||||
// Declare how many values to save per star
|
||||
nValuesPerStar = 8;
|
||||
|
||||
// Copy columns to local variables.
|
||||
std::unordered_map<std::string, std::vector<float>>& tableContent = table->contents;
|
||||
|
||||
std::vector<float> ra = std::move(tableContent[allColumnNames[0]]);
|
||||
std::vector<float> dec = std::move(tableContent[allColumnNames[1]]);
|
||||
std::vector<float> parallax = std::move(tableContent[allColumnNames[2]]);
|
||||
std::vector<float> pmra = std::move(tableContent[allColumnNames[3]]);
|
||||
std::vector<float> pmdec = std::move(tableContent[allColumnNames[4]]);
|
||||
std::vector<float> meanMagG = std::move(tableContent[allColumnNames[5]]);
|
||||
std::vector<float> meanMagBp = std::move(tableContent[allColumnNames[6]]);
|
||||
std::vector<float> meanMagRp = std::move(tableContent[allColumnNames[7]]);
|
||||
std::vector<float> radial_vel = std::move(tableContent[allColumnNames[8]]);
|
||||
|
||||
// Construct data array. OBS: ORDERING IS IMPORTANT! This is where slicing happens.
|
||||
for (int i = 0; i < nStars; ++i) {
|
||||
std::vector<float> values(nValuesPerStar);
|
||||
size_t idx = 0;
|
||||
|
||||
// Default order for rendering:
|
||||
// Position [X, Y, Z]
|
||||
// Mean G-band Magnitude
|
||||
// Bp-Rp Color
|
||||
// Velocity [X, Y, Z]
|
||||
|
||||
// Return early if star doesn't have a measured position.
|
||||
if (std::isnan(ra[i]) || std::isnan(dec[i])) {
|
||||
nNullArr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store positions. Set to a default distance if parallax doesn't exist.
|
||||
float radiusInKiloParsec = 9.0;
|
||||
if (!std::isnan(parallax[i])) {
|
||||
// Parallax is in milliArcseconds -> distance in kiloParsecs
|
||||
// https://gea.esac.esa.int/archive/documentation/GDR2/Gaia_archive/
|
||||
// chap_datamodel/sec_dm_main_tables/ssec_dm_gaia_source.html
|
||||
radiusInKiloParsec = 1.0 / parallax[i];
|
||||
}
|
||||
// Convert to Galactic Coordinates from Galactic Lon & Lat.
|
||||
// https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/
|
||||
// chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1
|
||||
//values[idx++] = radiusInKiloParsec * cos(glm::radians(b_latitude[i])) *
|
||||
//cos(glm::radians(l_longitude[i])); // Pos X
|
||||
//values[idx++] = radiusInKiloParsec * cos(glm::radians(b_latitude[i])) *
|
||||
//sin(glm::radians(l_longitude[i])); // Pos Y
|
||||
//values[idx++] = radiusInKiloParsec * sin(glm::radians(b_latitude[i])); // Pos Z
|
||||
|
||||
|
||||
// Convert ICRS Equatorial Ra and Dec to Galactic latitude and longitude.
|
||||
glm::mat3 aPrimG = glm::mat3(
|
||||
// Col 0
|
||||
glm::vec3(-0.0548755604162154, 0.4941094278755837, -0.8676661490190047),
|
||||
// Col 1
|
||||
glm::vec3(-0.8734370902348850, -0.4448296299600112, -0.1980763734312015),
|
||||
// Col 2
|
||||
glm::vec3(-0.4838350155487132, 0.7469822444972189, 0.4559837761750669)
|
||||
);
|
||||
glm::vec3 rICRS = glm::vec3(
|
||||
cos(glm::radians(ra[i])) * cos(glm::radians(dec[i])),
|
||||
sin(glm::radians(ra[i])) * cos(glm::radians(dec[i])),
|
||||
sin(glm::radians(dec[i]))
|
||||
);
|
||||
glm::vec3 rGal = aPrimG * rICRS;
|
||||
values[idx++] = radiusInKiloParsec * rGal.x; // Pos X
|
||||
values[idx++] = radiusInKiloParsec * rGal.y; // Pos Y
|
||||
values[idx++] = radiusInKiloParsec * rGal.z; // Pos Z
|
||||
|
||||
// Store magnitude render value. (Set default to high mag = low brightness)
|
||||
values[idx++] = std::isnan(meanMagG[i]) ? 20.f : meanMagG[i]; // Mean G-band Mag
|
||||
|
||||
// Store color render value. (Default value is bluish stars)
|
||||
values[idx++] = std::isnan(meanMagBp[i]) && std::isnan(meanMagRp[i]) ? 0.f
|
||||
: meanMagBp[i] - meanMagRp[i]; // Bp-Rp Color
|
||||
|
||||
// Store velocity.
|
||||
if (std::isnan(pmra[i])) pmra[i] = 0.f;
|
||||
if (std::isnan(pmdec[i])) pmdec[i] = 0.f;
|
||||
|
||||
// Convert Proper Motion from ICRS [Ra,Dec] to Galactic Tanget Vector [l,b].
|
||||
glm::vec3 uICRS = glm::vec3(
|
||||
-sin(glm::radians(ra[i])) * pmra[i] -
|
||||
cos(glm::radians(ra[i])) * sin(glm::radians(dec[i])) * pmdec[i],
|
||||
cos(glm::radians(ra[i])) * pmra[i] -
|
||||
sin(glm::radians(ra[i])) * sin(glm::radians(dec[i])) * pmdec[i],
|
||||
cos(glm::radians(dec[i])) * pmdec[i]
|
||||
);
|
||||
glm::vec3 pmVecGal = aPrimG * uICRS;
|
||||
|
||||
// Convert to Tangential vector [m/s] from Proper Motion vector [mas/yr]
|
||||
float tanVelX = 1000.0 * 4.74 * radiusInKiloParsec * pmVecGal.x;
|
||||
float tanVelY = 1000.0 * 4.74 * radiusInKiloParsec * pmVecGal.y;
|
||||
float tanVelZ = 1000.0 * 4.74 * radiusInKiloParsec * pmVecGal.z;
|
||||
|
||||
// Calculate True Space Velocity [m/s] if we have the radial velocity
|
||||
if (!std::isnan(radial_vel[i])) {
|
||||
// Calculate Radial Velocity in the direction of the star.
|
||||
// radial_vel is given in [km/s] -> convert to [m/s].
|
||||
float radVelX = 1000.0 * radial_vel[i] * rGal.x;
|
||||
float radVelY = 1000.0 * radial_vel[i] * rGal.y;
|
||||
float radVelZ = 1000.0 * radial_vel[i] * rGal.z;
|
||||
|
||||
// Use Pythagoras theorem for the final Space Velocity [m/s].
|
||||
values[idx++] = sqrt(pow(radVelX, 2) + pow(tanVelX, 2)); // Vel X [U]
|
||||
values[idx++] = sqrt(pow(radVelY, 2) + pow(tanVelY, 2)); // Vel Y [V]
|
||||
values[idx++] = sqrt(pow(radVelZ, 2) + pow(tanVelZ, 2)); // Vel Z [W]
|
||||
}
|
||||
// Otherwise use the vector [m/s] we got from proper motion.
|
||||
else {
|
||||
radial_vel[i] = 0.f;
|
||||
values[idx++] = tanVelX; // Vel X [U]
|
||||
values[idx++] = tanVelY; // Vel Y [V]
|
||||
values[idx++] = tanVelZ; // Vel Z [W]
|
||||
}
|
||||
|
||||
fullData.insert(fullData.end(), values.begin(), values.end());
|
||||
}*/
|
||||
|
||||
LINFO(fmt::format("{} out of {} read stars were null arrays", nNullArr, nStars));
|
||||
LINFO(fmt::format("Multiplier: {}", multiplier));
|
||||
|
||||
return fullData;
|
||||
}
|
||||
|
||||
std::vector<float> FitsFileReader::readSpeckFile(std::string filePath, int& nRenderValues)
|
||||
{
|
||||
auto fullData = std::vector<float>();
|
||||
|
||||
std::ifstream fileStream(filePath);
|
||||
|
||||
if (!fileStream.good()) {
|
||||
LERROR(fmt::format("Failed to open Speck file '{}'", filePath));
|
||||
return fullData;
|
||||
}
|
||||
|
||||
int nValuesPerStar = 0;
|
||||
int nNullArr = 0;
|
||||
size_t nStars = 0;
|
||||
|
||||
// The beginning of the speck file has a header that either contains comments
|
||||
// (signaled by a preceding '#') or information about the structure of the file
|
||||
// (signaled by the keywords 'datavar', 'texturevar', 'texture' and 'maxcomment')
|
||||
std::string line = "";
|
||||
while (true) {
|
||||
std::streampos position = fileStream.tellg();
|
||||
std::getline(fileStream, line);
|
||||
|
||||
if (line[0] == '#' || line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.substr(0, 7) != "datavar" && line.substr(0, 10) != "texturevar" &&
|
||||
line.substr(0, 7) != "texture" && line.substr(0, 10) != "maxcomment")
|
||||
{
|
||||
// We read a line that doesn't belong to the header, so we have to jump back
|
||||
// before the beginning of the current line.
|
||||
fileStream.seekg(position);
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.substr(0, 7) == "datavar") {
|
||||
// datavar lines are structured as follows:
|
||||
// datavar # description
|
||||
// where # is the index of the data variable; so if we repeatedly overwrite
|
||||
// the 'nValues' variable with the latest index, we will end up with the total
|
||||
// number of values (+3 since X Y Z are not counted in the Speck file index)
|
||||
std::stringstream str(line);
|
||||
|
||||
std::string dummy;
|
||||
str >> dummy;
|
||||
str >> nValuesPerStar;
|
||||
nValuesPerStar += 1; // We want the number, but the index is 0 based
|
||||
}
|
||||
}
|
||||
|
||||
nValuesPerStar += 3; // X Y Z are not counted in the Speck file indices
|
||||
|
||||
// Order in DR1 file: DR2 - GaiaGroupMembers:
|
||||
// 0 BVcolor 0 color
|
||||
// 1 lum 1 lum
|
||||
// 2 Vabsmag 2 absmag
|
||||
// 3 Vappmag 3 Gmag
|
||||
// 4 distly 4 distpc
|
||||
// 5 distpcPctErr 5 plx
|
||||
// 6 U 6 ra
|
||||
// 7 V 7 dec
|
||||
// 8 W 8 RadVel
|
||||
// 9 speed 9 Teff
|
||||
// 10 sptypeindex 10 vx
|
||||
// 11 lumclassindex 11 vy
|
||||
// 12 catsource 12 vz
|
||||
// 13 texture 13 speed
|
||||
// 14 texture
|
||||
|
||||
do {
|
||||
std::vector<float> readValues(nValuesPerStar);
|
||||
nStars++;
|
||||
|
||||
std::getline(fileStream, line);
|
||||
std::stringstream str(line);
|
||||
|
||||
// Read values.
|
||||
for (int i = 0; i < nValuesPerStar; ++i) {
|
||||
str >> readValues[i];
|
||||
}
|
||||
|
||||
// Check if star is a nullArray.
|
||||
bool nullArray = true;
|
||||
for (size_t i = 0; i < readValues.size(); ++i) {
|
||||
if (readValues[i] != 0.0) {
|
||||
nullArray = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert to data if we found some values.
|
||||
if (!nullArray) {
|
||||
// Re-order data here because Octree expects the data in correct order when
|
||||
// read.
|
||||
// Default order for rendering:
|
||||
// Position [X, Y, Z]
|
||||
// Absolute Magnitude
|
||||
// B-V Color
|
||||
// Velocity [X, Y, Z]
|
||||
|
||||
nRenderValues = 8;
|
||||
std::vector<float> renderValues(nRenderValues);
|
||||
|
||||
// Gaia DR1 data from AMNH measures positions in Parsec, but
|
||||
// RenderableGaiaStars expects kiloParsec (because fits file from Vienna had
|
||||
// in kPc).
|
||||
// Thus we need to convert positions twice atm.
|
||||
renderValues[0] = readValues[0] / 1000.0; // PosX
|
||||
renderValues[1] = readValues[1] / 1000.0; // PosY
|
||||
renderValues[2] = readValues[2] / 1000.0; // PosZ
|
||||
renderValues[3] = readValues[6]; // AbsMag
|
||||
renderValues[4] = readValues[3]; // color
|
||||
renderValues[5] = readValues[13] * readValues[16]; // Vel X
|
||||
renderValues[6] = readValues[14] * readValues[16]; // Vel Y
|
||||
renderValues[7] = readValues[15] * readValues[16]; // Vel Z
|
||||
|
||||
fullData.insert(fullData.end(), renderValues.begin(), renderValues.end());
|
||||
}
|
||||
else {
|
||||
nNullArr++;
|
||||
}
|
||||
|
||||
} while (!fileStream.eof());
|
||||
|
||||
LINFO(fmt::format("{} out of {} read stars were null arrays", nNullArr, nStars));
|
||||
|
||||
return fullData;
|
||||
}
|
||||
|
||||
// This is pretty annoying, the read method is not derived from the HDU class
|
||||
// in CCfits - need to explicitly cast to the sub classes to access read
|
||||
template<typename T>
|
||||
const std::shared_ptr<ImageData<T>> FitsFileReader::readImageInternal(ExtHDU& image) {
|
||||
try {
|
||||
std::valarray<T> contents;
|
||||
image.read(contents);
|
||||
ImageData<T> im = { std::move(contents), image.axis(0), image.axis(1) };
|
||||
return std::make_shared<ImageData<T>>(im);
|
||||
} catch (const FitsException& e){
|
||||
LERROR("Could not read FITS image EXTHDU. " + e.message() );
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const std::shared_ptr<ImageData<T>> FitsFileReader::readImageInternal(PHDU& image) {
|
||||
try {
|
||||
std::valarray<T> contents;
|
||||
image.read(contents);
|
||||
ImageData<T> im = { std::move(contents), image.axis(0), image.axis(1) };
|
||||
return std::make_shared<ImageData<T>>(im);
|
||||
} catch (const FitsException& e){
|
||||
LERROR("Could not read FITS image PHDU. " + e.message() );
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
71
modules/gaia/CMakeLists.txt
Normal file
71
modules/gaia/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
##########################################################################################
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2018 #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
|
||||
# software and associated documentation files (the "Software"), to deal in the Software #
|
||||
# without restriction, including without limitation the rights to use, copy, modify, #
|
||||
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to #
|
||||
# permit persons to whom the Software is furnished to do so, subject to the following #
|
||||
# conditions: #
|
||||
# #
|
||||
# The above copyright notice and this permission notice shall be included in all copies #
|
||||
# or substantial portions of the Software. #
|
||||
# #
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
|
||||
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A #
|
||||
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT #
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF #
|
||||
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE #
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gaiamodule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablegaiastars.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreemanager.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreeculler.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfilejob.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfitstask.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/readspecktask.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/constructoctreetask.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/gaiaoptions.h
|
||||
)
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/gaiamodule.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablegaiastars.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreemanager.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rendering/octreeculler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfilejob.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/readfitstask.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/readspecktask.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tasks/constructoctreetask.cpp
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_vbo_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_ssbo_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_billboard_nofbo_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_billboard_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_billboard_ge.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_point_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_point_ge.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_tonemapping_vs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_tonemapping_point_fs.glsl
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/shaders/gaia_tonemapping_billboard_fs.glsl
|
||||
)
|
||||
source_group("Shader Files" FILES ${SHADER_FILES})
|
||||
|
||||
create_new_module(
|
||||
"Gaia"
|
||||
gaia
|
||||
STATIC
|
||||
${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES}
|
||||
)
|
||||
72
modules/gaia/gaiamodule.cpp
Normal file
72
modules/gaia/gaiamodule.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/gaia/gaiamodule.h>
|
||||
|
||||
#include <modules/gaia/tasks/constructoctreetask.h>
|
||||
#include <modules/gaia/rendering/renderablegaiastars.h>
|
||||
#include <modules/gaia/tasks/readfitstask.h>
|
||||
#include <modules/gaia/tasks/readspecktask.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
GaiaModule::GaiaModule() : OpenSpaceModule(Name) {}
|
||||
|
||||
void GaiaModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
auto fRenderable = FactoryManager::ref().factory<Renderable>();
|
||||
ghoul_assert(fRenderable, "No renderable factory existed");
|
||||
fRenderable->registerClass<RenderableGaiaStars>("RenderableGaiaStars");
|
||||
|
||||
auto fTask = FactoryManager::ref().factory<Task>();
|
||||
ghoul_assert(fRenderable, "No task factory existed");
|
||||
fTask->registerClass<ReadFitsTask>("ReadFitsTask");
|
||||
fTask->registerClass<ReadSpeckTask>("ReadSpeckTask");
|
||||
fTask->registerClass<ConstructOctreeTask>("ConstructOctreeTask");
|
||||
}
|
||||
|
||||
std::vector<documentation::Documentation> GaiaModule::documentations() const {
|
||||
return {
|
||||
RenderableGaiaStars::Documentation(),
|
||||
ReadFitsTask::Documentation(),
|
||||
ReadSpeckTask::Documentation(),
|
||||
ConstructOctreeTask::Documentation(),
|
||||
};
|
||||
}
|
||||
|
||||
scripting::LuaLibrary GaiaModule::luaLibrary() const {
|
||||
scripting::LuaLibrary res;
|
||||
res.name = "gaia";
|
||||
res.scripts = {
|
||||
absPath("${MODULE_GAIAMISSION}/scripts/filtering.lua")
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
50
modules/gaia/gaiamodule.h
Normal file
50
modules/gaia/gaiamodule.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___GAIAMODULE___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___GAIAMODULE___H__
|
||||
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class GaiaModule : public OpenSpaceModule {
|
||||
public:
|
||||
constexpr static const char* Name = "Gaia";
|
||||
|
||||
GaiaModule();
|
||||
virtual ~GaiaModule() = default;
|
||||
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
|
||||
private:
|
||||
void internalInitialize(const ghoul::Dictionary&) override;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___GAIAMODULE___H__
|
||||
4
modules/gaia/include.cmake
Normal file
4
modules/gaia/include.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
set (OPENSPACE_DEPENDENCIES
|
||||
fitsfilereader
|
||||
globebrowsing
|
||||
)
|
||||
54
modules/gaia/rendering/gaiaoptions.h
Normal file
54
modules/gaia/rendering/gaiaoptions.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___GAIAOPTIONS___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___GAIAOPTIONS___H__
|
||||
|
||||
namespace openspace::gaia {
|
||||
|
||||
enum RenderOption {
|
||||
Static = 0,
|
||||
Color = 1,
|
||||
Motion = 2
|
||||
};
|
||||
|
||||
enum FileReaderOption {
|
||||
Fits = 0,
|
||||
Speck = 1,
|
||||
BinaryRaw = 2,
|
||||
BinaryOctree = 3,
|
||||
StreamOctree = 4
|
||||
};
|
||||
|
||||
enum ShaderOption {
|
||||
Point_SSBO = 0,
|
||||
Point_VBO = 1,
|
||||
Billboard_SSBO = 2,
|
||||
Billboard_VBO = 3,
|
||||
Billboard_SSBO_noFBO = 4
|
||||
};
|
||||
|
||||
} // namespace openspace::gaiamission
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___GAIAOPTIONS___H__
|
||||
86
modules/gaia/rendering/octreeculler.cpp
Normal file
86
modules/gaia/rendering/octreeculler.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/gaia/rendering/octreeculler.h>
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "OctreeCuller";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace {
|
||||
bool intersects(const globebrowsing::AABB3& bb, const globebrowsing::AABB3& o) {
|
||||
return (bb.min.x <= o.max.x) && (o.min.x <= bb.max.x)
|
||||
&& (bb.min.y <= o.max.y) && (o.min.y <= bb.max.y)
|
||||
&& (bb.min.z <= o.max.z) && (o.min.z <= bb.max.z);
|
||||
}
|
||||
|
||||
void expand(globebrowsing::AABB3& bb, const glm::vec3& p) {
|
||||
bb.min = glm::min(bb.min, p);
|
||||
bb.max = glm::max(bb.max, p);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
OctreeCuller::OctreeCuller(globebrowsing::AABB3 viewFrustum)
|
||||
: _viewFrustum(std::move(viewFrustum))
|
||||
{}
|
||||
|
||||
bool OctreeCuller::isVisible(const std::vector<glm::dvec4>& corners,
|
||||
const glm::dmat4& mvp)
|
||||
{
|
||||
createNodeBounds(corners, mvp);
|
||||
return intersects(_viewFrustum, _nodeBounds);
|
||||
}
|
||||
|
||||
glm::vec2 OctreeCuller::getNodeSizeInPixels(const std::vector<glm::dvec4>& corners,
|
||||
const glm::dmat4& mvp,
|
||||
const glm::vec2& screenSize)
|
||||
{
|
||||
|
||||
createNodeBounds(corners, mvp);
|
||||
|
||||
// Screen space is mapped to [-1, 1] so divide by 2 and multiply with screen size.
|
||||
glm::vec3 size = (_nodeBounds.max - _nodeBounds.min) / 2.f;
|
||||
size = glm::abs(size);
|
||||
return glm::vec2(size.x * screenSize.x, size.y * screenSize.y);
|
||||
}
|
||||
|
||||
void OctreeCuller::createNodeBounds(const std::vector<glm::dvec4>& corners,
|
||||
const glm::dmat4& mvp)
|
||||
{
|
||||
// Create a bounding box in clipping space from node boundaries.
|
||||
_nodeBounds = globebrowsing::AABB3();
|
||||
|
||||
for (size_t i = 0; i < 8; ++i) {
|
||||
glm::dvec4 cornerClippingSpace = mvp * corners[i];
|
||||
glm::dvec4 ndc = (1.f / glm::abs(cornerClippingSpace.w)) * cornerClippingSpace;
|
||||
expand(_nodeBounds, glm::dvec3(ndc));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
76
modules/gaia/rendering/octreeculler.h
Normal file
76
modules/gaia/rendering/octreeculler.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___OCTREECULLER___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___OCTREECULLER___H__
|
||||
|
||||
#include <modules/globebrowsing/src/basictypes.h>
|
||||
#include <vector>
|
||||
|
||||
// TODO: Move /geometry/* to libOpenSpace so as not to depend on globebrowsing.
|
||||
|
||||
namespace openspace {
|
||||
|
||||
/**
|
||||
* Culls all octree nodes that are completely outside the view frustum.
|
||||
*
|
||||
* The frustum culling uses a 2D axis aligned bounding box for the OctreeNode in
|
||||
* screen space.
|
||||
*/
|
||||
|
||||
class OctreeCuller {
|
||||
public:
|
||||
|
||||
/**
|
||||
* \param viewFrustum is the view space in normalized device coordinates space.
|
||||
* Hence it is an axis aligned bounding box and not a real frustum.
|
||||
*/
|
||||
OctreeCuller(globebrowsing::AABB3 viewFrustum);
|
||||
|
||||
~OctreeCuller() = default;
|
||||
|
||||
/**
|
||||
* \return true if any part of the node is visible in the current view.
|
||||
*/
|
||||
bool isVisible(const std::vector<glm::dvec4>& corners, const glm::dmat4& mvp);
|
||||
|
||||
/**
|
||||
* \return the size [in pixels] of the node in clipping space.
|
||||
*/
|
||||
glm::vec2 getNodeSizeInPixels(const std::vector<glm::dvec4>& corners,
|
||||
const glm::dmat4& mvp, const glm::vec2& screenSize);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates an axis-aligned bounding box containing all \p corners in clipping space.
|
||||
*/
|
||||
void createNodeBounds(const std::vector<glm::dvec4>& corners, const glm::dmat4& mvp);
|
||||
|
||||
const globebrowsing::AABB3 _viewFrustum;
|
||||
globebrowsing::AABB3 _nodeBounds;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___OCTREECULLER___H__
|
||||
1415
modules/gaia/rendering/octreemanager.cpp
Normal file
1415
modules/gaia/rendering/octreemanager.cpp
Normal file
File diff suppressed because it is too large
Load Diff
391
modules/gaia/rendering/octreemanager.h
Normal file
391
modules/gaia/rendering/octreemanager.h
Normal file
@@ -0,0 +1,391 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___OCTREEMANAGER___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___OCTREEMANAGER___H__
|
||||
|
||||
#include <modules/gaia/rendering/gaiaoptions.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class OctreeCuller;
|
||||
|
||||
class OctreeManager {
|
||||
public:
|
||||
struct OctreeNode {
|
||||
std::shared_ptr<OctreeNode> Children[8];
|
||||
std::vector<float> posData;
|
||||
std::vector<float> colData;
|
||||
std::vector<float> velData;
|
||||
std::vector<std::pair<float, size_t>> magOrder;
|
||||
float originX;
|
||||
float originY;
|
||||
float originZ;
|
||||
float halfDimension;
|
||||
size_t numStars;
|
||||
bool isLeaf;
|
||||
bool isLoaded;
|
||||
bool hasLoadedDescendant;
|
||||
std::mutex loadingLock;
|
||||
int bufferIndex;
|
||||
unsigned long long octreePositionIndex;
|
||||
};
|
||||
|
||||
OctreeManager() = default;
|
||||
~OctreeManager();
|
||||
|
||||
/**
|
||||
* Initializes a one layer Octree with root and 8 children that covers all stars.
|
||||
*
|
||||
* \param maxDist together with \param maxstarsPerNode (if defined) determines the
|
||||
* depth of the tree as well as how many nodes will be created.
|
||||
*/
|
||||
void initOctree(long long cpuRamBudget = 0, int maxDist = 0, int maxStarsPerNode = 0);
|
||||
|
||||
/**
|
||||
* Initializes a stack of size \param maxNodes that keeps track of all free spot in
|
||||
* buffer stream. Can be used to trigger a rebuild of buffer(s).
|
||||
*
|
||||
* \param useVBO defines if VBO or SSBO is used as buffer(s)
|
||||
* \param datasetFitInMemory defines if streaming of nodes during runtime is used
|
||||
*/
|
||||
void initBufferIndexStack(long long maxNodes, bool useVBO, bool datasetFitInMemory);
|
||||
|
||||
/**
|
||||
* Inserts star values in correct position in Octree. Makes use of a recursive
|
||||
* traversal strategy. Internally calls <code>insertInNode()</code>
|
||||
*/
|
||||
void insert(const std::vector<float>& starValues);
|
||||
|
||||
/**
|
||||
* Slices LOD data so only the MAX_STARS_PER_NODE brightest stars are stored in inner
|
||||
* nodes. If \p branchIndex is defined then only that branch will be sliced.
|
||||
* Calls <code>sliceNodeLodCache()</code> internally.
|
||||
*/
|
||||
void sliceLodData(size_t branchIndex = 8);
|
||||
|
||||
/**
|
||||
* Prints the whole tree structure, including number of stars per node, number of
|
||||
* nodes, tree depth and if node is a leaf.
|
||||
* Calls <code>printStarsPerNode(node, prefix)</code> internally.
|
||||
*/
|
||||
void printStarsPerNode() const;
|
||||
|
||||
/**
|
||||
* Used while streaming nodes from files. Checks if any nodes need to be loaded or
|
||||
* unloaded. If entire dataset fits in RAM then the whole dataset will be loaded
|
||||
* asynchronously. Otherwise only nodes close to the camera will be fetched.
|
||||
* When RAM stars to fill up least-recently used nodes will start to unload.
|
||||
* Calls <code>findAndFetchNeighborNode()</code> and
|
||||
* <code>removeNodesFromRam()</code> internally.
|
||||
*/
|
||||
void fetchSurroundingNodes(const glm::dvec3& cameraPos, size_t chunkSizeInBytes,
|
||||
const glm::ivec2& additionalNodes);
|
||||
|
||||
/**
|
||||
* Builds render data structure by traversing the Octree and checking for intersection
|
||||
* with view frustum. Every vector in map contains data for one node.
|
||||
* The corresponding integer key is the index where chunk should be inserted into
|
||||
* streaming buffer. Calls <code>checkNodeIntersection()</code> for every branch.
|
||||
* \pdeltaStars keeps track of how many stars that were added/removed this render
|
||||
* call.
|
||||
*/
|
||||
std::map<int, std::vector<float>> traverseData(const glm::dmat4& mvp,
|
||||
const glm::vec2& screenSize, int& deltaStars, gaia::RenderOption option,
|
||||
float lodPixelThreshold);
|
||||
|
||||
/**
|
||||
* Builds full render data structure by traversing all leaves in the Octree.
|
||||
*/
|
||||
std::vector<float> getAllData(gaia::RenderOption option);
|
||||
|
||||
/**
|
||||
* Removes all data from Octree, or only from a specific branch if specified.
|
||||
* \param branchIndex defined which branch to clear if defined.
|
||||
*/
|
||||
void clearAllData(int branchIndex = -1);
|
||||
|
||||
/**
|
||||
* Write entire Octree structure to a binary file. \param writeData defines if data
|
||||
* should be included or if only structure should be written to the file.
|
||||
* Calls <code>writeNodeToFile()</code> which recursively writes all nodes.
|
||||
*/
|
||||
void writeToFile(std::ofstream& outFileStream, bool writeData);
|
||||
|
||||
/**
|
||||
* Read a constructed Octree from a file. \returns the total number of (distinct)
|
||||
* stars read.
|
||||
*
|
||||
* \param readData defines if full data or only structure should be read.
|
||||
* Calls <code>readNodeFromFile()</code> which recursively reads all nodes.
|
||||
*/
|
||||
int readFromFile(std::ifstream& inFileStream, bool readData,
|
||||
const std::string& folderPath = std::string());
|
||||
|
||||
/**
|
||||
* Write specified part of Octree to multiple files, including all data.
|
||||
* \param branchIndex defines which branch to write.
|
||||
* Clears specified branch after writing is done.
|
||||
* Calls <code>writeNodeToMultipleFiles()</code> for the specified branch.
|
||||
*/
|
||||
void writeToMultipleFiles(const std::string& outFolderPath, size_t branchIndex);
|
||||
|
||||
/**
|
||||
* Getters.
|
||||
*/
|
||||
size_t numLeafNodes() const;
|
||||
size_t numInnerNodes() const;
|
||||
size_t totalNodes() const;
|
||||
size_t totalDepth() const;
|
||||
size_t maxDist() const;
|
||||
size_t maxStarsPerNode() const;
|
||||
size_t biggestChunkIndexInUse() const;
|
||||
size_t numFreeSpotsInBuffer() const;
|
||||
bool isRebuildOngoing() const;
|
||||
|
||||
/**
|
||||
* \returns current CPU RAM budget in bytes.
|
||||
*/
|
||||
long long cpuRamBudget() const;
|
||||
|
||||
private:
|
||||
const size_t POS_SIZE = 3;
|
||||
const size_t COL_SIZE = 2;
|
||||
const size_t VEL_SIZE = 3;
|
||||
|
||||
// MAX_DIST [kPc] - Determines the depth of Octree together with MAX_STARS_PER_NODE.
|
||||
// A smaller distance is better (i.e. a smaller total depth) and a smaller MAX_STARS
|
||||
// is also better (i.e. finer borders and fewer nodes/less data needs to be uploaded
|
||||
// to the GPU), but MAX_STARS still needs to be big enough to be able to swallow all
|
||||
// stars that falls outside of top border nodes, otherwise it causes a stack overflow
|
||||
// when building Octree. However, fewer total nodes (i.e. bigger Stars/Node) reduces
|
||||
// traversing time which is preferable, especially with big datasets
|
||||
// DR1_TGAS [2M] - A MAX_DIST of 5 kPc works fine with down to 1 kSPN.
|
||||
// DR1_full [1.2B] - A MAX_DIST of 10 kPc works fine with most SPN.
|
||||
// DR2_rv [7.2M] - A MAX_DIST of 15 kPc works fine with down to 10 kSPN.
|
||||
// DR2_subset [42.9M] - A MAX_DIST of 100 kPc works fine with 20 kSPN.
|
||||
// DR2_full [1.7B] - A MAX_DIST of 250 kPc works fine with 150 kSPN.
|
||||
size_t MAX_DIST = 2; // [kPc]
|
||||
size_t MAX_STARS_PER_NODE = 2000;
|
||||
|
||||
const int DEFAULT_INDEX = -1;
|
||||
const std::string BINARY_SUFFIX = ".bin";
|
||||
|
||||
/**
|
||||
* \returns the correct index of child node. Maps [1,1,1] to 0 and [-1,-1,-1] to 7.
|
||||
*/
|
||||
size_t getChildIndex(float posX, float posY, float posZ, float origX = 0.f,
|
||||
float origY = 0.f, float origZ = 0.f);
|
||||
|
||||
/**
|
||||
* Private help function for <code>insert()</code>. Inserts star into node if leaf and
|
||||
* numStars < MAX_STARS_PER_NODE. If a leaf goes above the threshold it is subdivided
|
||||
* into 8 new nodes.
|
||||
* If node is an inner node, then star is stores in LOD cache if it is among the
|
||||
* brightest stars in all children.
|
||||
*/
|
||||
bool insertInNode(std::shared_ptr<OctreeNode> node,
|
||||
const std::vector<float>& starValues, int depth = 1);
|
||||
|
||||
/**
|
||||
* Slices LOD cache data in node to the MAX_STARS_PER_NODE brightest stars. This needs
|
||||
* to be called after the last star has been inserted into Octree but before it is
|
||||
* saved to file(s). Slices all descendants recursively.
|
||||
*/
|
||||
void sliceNodeLodCache(std::shared_ptr<OctreeNode> node);
|
||||
|
||||
/**
|
||||
* Private help function for <code>insertInNode()</code>. Stores star data in node and
|
||||
* keeps track of the brightest stars all children.
|
||||
*/
|
||||
void storeStarData(std::shared_ptr<OctreeNode> node,
|
||||
const std::vector<float>& starValues);
|
||||
|
||||
/**
|
||||
* Private help function for <code>printStarsPerNode()</code>. \returns an accumulated
|
||||
* string containing all descendant nodes.
|
||||
*/
|
||||
std::string printStarsPerNode(std::shared_ptr<OctreeNode> node,
|
||||
const std::string& prefix) const;
|
||||
|
||||
/**
|
||||
* Private help function for <code>traverseData()</code>. Recursively checks which
|
||||
* nodes intersect with the view frustum (interpreted as an AABB) and decides if data
|
||||
* should be optimized away or not. Keeps track of which nodes that are visible and
|
||||
* loaded (if streaming). \param deltaStars keeps track of how many stars that were
|
||||
* added/removed this render call.
|
||||
*/
|
||||
std::map<int, std::vector<float>> checkNodeIntersection(
|
||||
std::shared_ptr<OctreeNode> node, const glm::dmat4& mvp,
|
||||
const glm::vec2& screenSize, int& deltaStars, gaia::RenderOption option);
|
||||
|
||||
/**
|
||||
* Checks if specified node existed in cache, and removes it if that's the case.
|
||||
* If node is an inner node then all children will be checked recursively as well as
|
||||
* long as \param recursive is not set to false. \param deltaStars keeps track of how
|
||||
* many stars that were removed.
|
||||
*/
|
||||
std::map<int, std::vector<float>> removeNodeFromCache(
|
||||
std::shared_ptr<OctreeNode> node, int& deltaStars, bool recursive = true);
|
||||
|
||||
/**
|
||||
* Get data in node and its descendants regardless if they are visible or not.
|
||||
*/
|
||||
std::vector<float> getNodeData(std::shared_ptr<OctreeNode> node,
|
||||
gaia::RenderOption option);
|
||||
|
||||
/**
|
||||
* Clear data from node and its descendants and shrink vectors to deallocate memory.
|
||||
*/
|
||||
void clearNodeData(std::shared_ptr<OctreeNode> node);
|
||||
|
||||
/**
|
||||
* Contruct default children nodes for specified node.
|
||||
*/
|
||||
void createNodeChildren(std::shared_ptr<OctreeNode> node);
|
||||
|
||||
/**
|
||||
* Checks if node should be inserted into stream or not. \returns true if it should,
|
||||
* (i.e. it doesn't already exists, there is room for it in the buffer and node data
|
||||
* is loaded if streaming). \returns false otherwise.
|
||||
*/
|
||||
bool updateBufferIndex(std::shared_ptr<OctreeNode> node);
|
||||
|
||||
/**
|
||||
* Node should be inserted into stream. This function \returns the data to be
|
||||
* inserted. If VBOs are used then the chunks will be appended by zeros, otherwise
|
||||
* only the star data corresponding to RenderOption \param option will be inserted.
|
||||
*
|
||||
* \param deltaStars keeps track of how many stars that were added.
|
||||
*/
|
||||
std::vector<float> constructInsertData(std::shared_ptr<OctreeNode> node,
|
||||
gaia::RenderOption option, int& deltaStars);
|
||||
|
||||
/**
|
||||
* Write a node to outFileStream. \param writeData defines if data should be included
|
||||
* or if only structure should be written.
|
||||
*/
|
||||
void writeNodeToFile(std::ofstream& outFileStream, std::shared_ptr<OctreeNode> node,
|
||||
bool writeData);
|
||||
|
||||
/**
|
||||
* Read a node from file and its potential children. \param readData defines if full
|
||||
* data or only structure should be read.
|
||||
* \returns accumulated sum of all read stars in node and its descendants.
|
||||
*/
|
||||
int readNodeFromFile(std::ifstream& inFileStream, std::shared_ptr<OctreeNode> node,
|
||||
bool readData);
|
||||
|
||||
/**
|
||||
* Write node data to a file. \param outFilePrefix specifies the accumulated path
|
||||
* and name of the file. If \param threadWrites is set to true then one new thread
|
||||
* will be created for each child to write its descendents.
|
||||
*/
|
||||
void writeNodeToMultipleFiles(const std::string& outFilePrefix,
|
||||
std::shared_ptr<OctreeNode> node, bool threadWrites);
|
||||
|
||||
/**
|
||||
* Finds the neighboring node on the same level (or a higher level if there is no
|
||||
* corresponding level) in the specified direction. Also fetches data from found node
|
||||
* if it's not already loaded. \param additionalLevelsToFetch determines if any
|
||||
* descendants of the found node should be fetched as well (if they exists).
|
||||
*/
|
||||
void findAndFetchNeighborNode(unsigned long long firstParentId, int x, int y, int z,
|
||||
int additionalLevelsToFetch);
|
||||
|
||||
/**
|
||||
* Fetches data from all children of \param parentNode, as long as it's not already
|
||||
* fetched, it exists and it can fit in RAM.
|
||||
* \param additionalLevelsToFetch determines how many levels of descendants to fetch.
|
||||
* If it is set to 0 no additional level will be fetched.
|
||||
* If it is set to a negative value then all descendants will be fetched recursively.
|
||||
* Calls <code>fetchNodeDataFromFile()</code> for every child that passes the tests.
|
||||
*/
|
||||
void fetchChildrenNodes(std::shared_ptr<OctreeManager::OctreeNode> parentNode,
|
||||
int additionalLevelsToFetch);
|
||||
|
||||
/**
|
||||
* Fetches data for specified node from file.
|
||||
* OBS! Only call if node file exists (i.e. node has any data, node->numStars > 0)
|
||||
* and is not already loaded.
|
||||
*/
|
||||
void fetchNodeDataFromFile(std::shared_ptr<OctreeNode> node);
|
||||
|
||||
/**
|
||||
* Loops though all nodes in \param nodesToRemove and clears them from RAM.
|
||||
* Also checks if any ancestor should change the <code>hasLoadedDescendant</code> flag
|
||||
* by calling <code>propagateUnloadedNodes()</code> with all ancestors.
|
||||
*/
|
||||
void removeNodesFromRam(const std::vector<unsigned long long>& nodesToRemove);
|
||||
|
||||
/**
|
||||
* Removes data in specified node from main memory and updates RAM budget and flags
|
||||
* accordingly.
|
||||
*/
|
||||
void removeNode(std::shared_ptr<OctreeManager::OctreeNode> node);
|
||||
|
||||
/**
|
||||
* Loops through \param ancestorNodes backwards and checks if parent node has any
|
||||
* loaded descendants left. If not, then flag <code>hasLoadedDescendant</code> will be
|
||||
* set to false for that parent node and next parent in line will be checked.
|
||||
*/
|
||||
void propagateUnloadedNodes(std::vector<std::shared_ptr<OctreeNode>> ancestorNodes);
|
||||
|
||||
std::shared_ptr<OctreeNode> _root;
|
||||
std::unique_ptr<OctreeCuller> _culler;
|
||||
std::stack<int> _freeSpotsInBuffer;
|
||||
std::set<int> _removedKeysInPrevCall;
|
||||
std::queue<unsigned long long> _leastRecentlyFetchedNodes;
|
||||
std::mutex _leastRecentlyFetchedNodesMutex;
|
||||
|
||||
size_t _totalDepth = 0;
|
||||
size_t _numLeafNodes = 0;
|
||||
size_t _numInnerNodes = 0;
|
||||
size_t _biggestChunkIndexInUse = 0;
|
||||
size_t _valuesPerStar = 0;
|
||||
float _minTotalPixelsLod = 0.f;
|
||||
|
||||
size_t _maxStackSize = 0;
|
||||
bool _rebuildBuffer = false;
|
||||
bool _useVBO = false;
|
||||
bool _streamOctree = false;
|
||||
bool _datasetFitInMemory = false;
|
||||
long long _cpuRamBudget = 0;
|
||||
long long _maxCpuRamBudget = 0;
|
||||
unsigned long long _parentNodeOfCamera = 8;
|
||||
std::string _streamFolderPath;
|
||||
size_t _traversedBranchesInRenderCall = 0;
|
||||
|
||||
}; // class OctreeManager
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___OCTREEMANAGER___H__
|
||||
2529
modules/gaia/rendering/renderablegaiastars.cpp
Normal file
2529
modules/gaia/rendering/renderablegaiastars.cpp
Normal file
File diff suppressed because it is too large
Load Diff
216
modules/gaia/rendering/renderablegaiastars.h
Normal file
216
modules/gaia/rendering/renderablegaiastars.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___RENDERABLEGAIASTARS___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___RENDERABLEGAIASTARS___H__
|
||||
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <modules/gaia/rendering/octreemanager.h>
|
||||
#include <openspace/properties/optionproperty.h>
|
||||
#include <openspace/properties/stringlistproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/vector/vec2property.h>
|
||||
#include <openspace/properties/vector/ivec2property.h>
|
||||
#include <ghoul/opengl/bufferbinding.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/opengl/uniformcache.h>
|
||||
|
||||
namespace ghoul::filesystem { class File; }
|
||||
namespace ghoul::opengl {
|
||||
class ProgramObject;
|
||||
class Texture;
|
||||
} // namespace ghoul::opengl
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class RenderableGaiaStars : public Renderable {
|
||||
public:
|
||||
explicit RenderableGaiaStars(const ghoul::Dictionary& dictionary);
|
||||
virtual ~RenderableGaiaStars();
|
||||
|
||||
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:
|
||||
/**
|
||||
* Reads data file in format defined by FileReaderOption.
|
||||
*
|
||||
* \return true if data was successfully read.
|
||||
*/
|
||||
bool readDataFile();
|
||||
|
||||
/**
|
||||
* Reads a FITS file by using FitsFileReader.readFitsFile() and constructs an octree.
|
||||
*
|
||||
* \return the number of stars read.
|
||||
*/
|
||||
int readFitsFile(const std::string& filePath);
|
||||
|
||||
/**
|
||||
* Read a SPECK file by using FitsFileReader.readSpeckFile() and constructs an octree.
|
||||
*
|
||||
* \return the number of stars read.
|
||||
*/
|
||||
int readSpeckFile(const std::string& filePath);
|
||||
|
||||
/**
|
||||
* Reads a preprocessed binary file and constructs an octree.
|
||||
*
|
||||
* \return the number of stars read.
|
||||
*/
|
||||
int readBinaryRawFile(const std::string& filePath);
|
||||
|
||||
/**
|
||||
* Reads a pre-constructed octree, with all data, from a binary file.
|
||||
*
|
||||
* \return the number of stars read.
|
||||
*/
|
||||
int readBinaryOctreeFile(const std::string& filePath);
|
||||
|
||||
/**
|
||||
* Reads the structure of a pre-constructed octree from a binary file, without any
|
||||
* data.
|
||||
*
|
||||
* \return the number of stars read.
|
||||
*/
|
||||
int readBinaryOctreeStructureFile(const std::string& folderPath);
|
||||
|
||||
/**
|
||||
* Checks for any OpenGL errors and reports these to the log if _reportGlErrors is
|
||||
* set to true.
|
||||
*/
|
||||
void checkGlErrors(const std::string& identifier) const;
|
||||
|
||||
properties::StringProperty _filePath;
|
||||
std::unique_ptr<ghoul::filesystem::File> _dataFile;
|
||||
bool _dataIsDirty = true;
|
||||
bool _buffersAreDirty = true;
|
||||
bool _shadersAreDirty = false;
|
||||
|
||||
properties::StringProperty _pointSpreadFunctionTexturePath;
|
||||
std::unique_ptr<ghoul::opengl::Texture> _pointSpreadFunctionTexture;
|
||||
std::unique_ptr<ghoul::filesystem::File> _pointSpreadFunctionFile;
|
||||
bool _pointSpreadFunctionTextureIsDirty = true;
|
||||
|
||||
properties::StringProperty _colorTexturePath;
|
||||
std::unique_ptr<ghoul::opengl::Texture> _colorTexture;
|
||||
std::unique_ptr<ghoul::filesystem::File> _colorTextureFile;
|
||||
bool _colorTextureIsDirty = true;
|
||||
|
||||
properties::FloatProperty _luminosityMultiplier;
|
||||
properties::FloatProperty _magnitudeBoost;
|
||||
properties::FloatProperty _cutOffThreshold;
|
||||
properties::FloatProperty _sharpness;
|
||||
properties::FloatProperty _billboardSize;
|
||||
properties::FloatProperty _closeUpBoostDist;
|
||||
properties::IntProperty _tmPointFilterSize;
|
||||
properties::FloatProperty _tmPointSigma;
|
||||
properties::IVec2Property _additionalNodes;
|
||||
properties::FloatProperty _tmPointPixelWeightThreshold;
|
||||
properties::FloatProperty _lodPixelThreshold;
|
||||
|
||||
properties::Vec2Property _posXThreshold;
|
||||
properties::Vec2Property _posYThreshold;
|
||||
properties::Vec2Property _posZThreshold;
|
||||
properties::Vec2Property _gMagThreshold;
|
||||
properties::Vec2Property _bpRpThreshold;
|
||||
properties::Vec2Property _distThreshold;
|
||||
|
||||
properties::IntProperty _firstRow;
|
||||
properties::IntProperty _lastRow;
|
||||
properties::StringListProperty _columnNamesList;
|
||||
std::vector<std::string> _columnNames;
|
||||
properties::OptionProperty _fileReaderOption;
|
||||
properties::OptionProperty _renderOption;
|
||||
properties::OptionProperty _shaderOption;
|
||||
properties::IntProperty _nRenderedStars;
|
||||
// LongLongProperty doesn't show up in menu, use FloatProperty instead.
|
||||
properties::FloatProperty _cpuRamBudgetProperty;
|
||||
properties::FloatProperty _gpuStreamBudgetProperty;
|
||||
properties::FloatProperty _maxGpuMemoryPercent;
|
||||
properties::FloatProperty _maxCpuMemoryPercent;
|
||||
|
||||
properties::BoolProperty _reportGlErrors;
|
||||
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _program;
|
||||
UniformCache(model, view, cameraPos, cameraLookUp, viewScaling, projection,
|
||||
renderOption, luminosityMultiplier, magnitudeBoost, cutOffThreshold,
|
||||
sharpness, billboardSize, closeUpBoostDist, screenSize, psfTexture,
|
||||
time, colorTexture, nChunksToRender, valuesPerStar, maxStarsPerNode)
|
||||
_uniformCache;
|
||||
|
||||
UniformCache(posXThreshold, posYThreshold, posZThreshold, gMagThreshold,
|
||||
bpRpThreshold, distThreshold) _uniformFilterCache;
|
||||
|
||||
std::unique_ptr<ghoul::opengl::ProgramObject> _programTM;
|
||||
UniformCache(renderedTexture, screenSize, filterSize, sigma, pixelWeightThreshold,
|
||||
projection) _uniformCacheTM;
|
||||
std::unique_ptr<ghoul::opengl::Texture> _fboTexture;
|
||||
|
||||
OctreeManager _octreeManager;
|
||||
std::unique_ptr<ghoul::opengl::BufferBinding<
|
||||
ghoul::opengl::bufferbinding::Buffer::ShaderStorage>> _ssboIdxBinding;
|
||||
std::unique_ptr<ghoul::opengl::BufferBinding<
|
||||
ghoul::opengl::bufferbinding::Buffer::ShaderStorage>> _ssboDataBinding;
|
||||
|
||||
std::vector<int> _accumulatedIndices;
|
||||
size_t _nRenderValuesPerStar = 0;
|
||||
int _nStarsToRender = 0;
|
||||
bool _firstDrawCalls = true;
|
||||
glm::dquat _previousCameraRotation;
|
||||
bool _useVBO = false;
|
||||
long long _cpuRamBudgetInBytes = 0;
|
||||
long long _totalDatasetSizeInBytes = 0;
|
||||
long long _gpuMemoryBudgetInBytes = 0;
|
||||
long long _maxStreamingBudgetInBytes = 0;
|
||||
size_t _chunkSize = 0;
|
||||
|
||||
GLuint _vao = 0;
|
||||
GLuint _vaoEmpty = 0;
|
||||
GLuint _vboPos = 0;
|
||||
GLuint _vboCol = 0;
|
||||
GLuint _vboVel = 0;
|
||||
GLuint _ssboIdx = 0;
|
||||
GLuint _ssboData = 0;
|
||||
GLuint _vaoQuad = 0;
|
||||
GLuint _vboQuad = 0;
|
||||
GLuint _fbo = 0;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___RENDERABLEGAIASTARS___H__
|
||||
102
modules/gaia/scripts/filtering.lua
Normal file
102
modules/gaia/scripts/filtering.lua
Normal file
@@ -0,0 +1,102 @@
|
||||
openspace.gaia.documentation = {
|
||||
{
|
||||
Name = "addClippingBox",
|
||||
Arguments = "string, vec3, vec3",
|
||||
Documentation = "Creates a clipping box for the Gaia renderable in the first argument"
|
||||
},
|
||||
{
|
||||
Name = "removeClippingBox",
|
||||
Arguments = "",
|
||||
Documentation = ""
|
||||
},
|
||||
{
|
||||
Name = "addClippingSphere",
|
||||
Arguments = "string, float",
|
||||
Documentation = "Creates a clipping sphere for the Gaia renderable in the first argument"
|
||||
},
|
||||
{
|
||||
Name = "removeClippingBox",
|
||||
Arguments = "",
|
||||
Documentation = ""
|
||||
}
|
||||
}
|
||||
|
||||
openspace.gaia.addClippingBox = function (name, size, position)
|
||||
local grid_identifier = "Filtering_Box"
|
||||
local kilo_parsec_in_meter = 30856775814913700000
|
||||
|
||||
if openspace.hasSceneGraphNode(grid_identifier) then
|
||||
openspace.removeSceneGraphNode(grid_identifier)
|
||||
end
|
||||
|
||||
local grid = {
|
||||
Identifier = grid_identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "StaticTranslation",
|
||||
Position = { position[1] * kilo_parsec_in_meter, position[2] * kilo_parsec_in_meter, position[3] * kilo_parsec_in_meter }
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableBoxGrid",
|
||||
GridColor = { 0.6, 0.5, 0.7, 1.0 },
|
||||
LineWidth = 2.0,
|
||||
Size = { size[1] * kilo_parsec_in_meter, size[2] * kilo_parsec_in_meter, size[3] * kilo_parsec_in_meter}
|
||||
},
|
||||
GUI = {
|
||||
Name = "Filtering Grid",
|
||||
Path = "/Other/Grids"
|
||||
}
|
||||
}
|
||||
|
||||
openspace.addSceneGraphNode(grid)
|
||||
|
||||
openspace.setPropertyValue('Scene.' .. name .. '.renderable.FilterPosX', { (position[1] - size[1] / 2) * kilo_parsec_in_meter, (position[1] + size[1] / 2) * kilo_parsec_in_meter })
|
||||
openspace.setPropertyValue('Scene.' .. name .. '.renderable.FilterPosY', { (position[2] - size[2] / 2) * kilo_parsec_in_meter, (position[2] + size[2] / 2) * kilo_parsec_in_meter })
|
||||
openspace.setPropertyValue('Scene.' .. name .. '.renderable.FilterPosZ', { (position[3] - size[3] / 2) * kilo_parsec_in_meter, (position[3] + size[3] / 2) * kilo_parsec_in_meter })
|
||||
end
|
||||
|
||||
openspace.gaia.removeClippingBox = function()
|
||||
local grid_identifier = "Filtering_Box"
|
||||
|
||||
if openspace.hasSceneGraphNode(grid_identifier) then
|
||||
openspace.removeSceneGraphNode(grid_identifier)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
openspace.gaia.addClippingSphere = function (name, radius)
|
||||
local grid_identifier = "Filtering_Sphere"
|
||||
local kilo_parsec_in_meter = 30856775814913700000
|
||||
|
||||
|
||||
if openspace.hasSceneGraphNode(grid_identifier) then
|
||||
openspace.removeSceneGraphNode(grid_identifier)
|
||||
end
|
||||
|
||||
local grid = {
|
||||
Identifier = grid_identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableSphericalGrid",
|
||||
GridColor = { 0.6, 0.5, 0.7, 1.0 },
|
||||
LineWidth = 1.0,
|
||||
Radius = radius * kilo_parsec_in_meter
|
||||
},
|
||||
GUI = {
|
||||
Name = "Filtering Sphere",
|
||||
Path = "/Other/Grids"
|
||||
}
|
||||
}
|
||||
|
||||
openspace.addSceneGraphNode(grid)
|
||||
|
||||
openspace.setPropertyValue('Scene.' .. name .. '.renderable.FilterDist', radius * kilo_parsec_in_meter)
|
||||
end
|
||||
|
||||
openspace.gaia.removeClippingSphere = function()
|
||||
local grid_identifier = "Filtering_Sphere"
|
||||
|
||||
if openspace.hasSceneGraphNode(grid_identifier) then
|
||||
openspace.removeSceneGraphNode(grid_identifier)
|
||||
end
|
||||
end
|
||||
114
modules/gaia/shaders/gaia_billboard_fs.glsl
Normal file
114
modules/gaia/shaders/gaia_billboard_fs.glsl
Normal file
@@ -0,0 +1,114 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
// Keep in sync with gaiaoptions.h:RenderOption enum
|
||||
const int RENDEROPTION_STATIC = 0;
|
||||
const int RENDEROPTION_COLOR = 1;
|
||||
const int RENDEROPTION_MOTION = 2;
|
||||
const float ONE_PARSEC = 3.08567758e16; // 1 Parsec
|
||||
const float FLT_MAX = 3.402823466e38; // Max float constant in GLSL
|
||||
const float LUM_LOWER_CAP = 0.01;
|
||||
|
||||
in vec2 ge_brightness;
|
||||
in vec4 ge_gPosition;
|
||||
in vec2 texCoord;
|
||||
in float ge_starDistFromSun;
|
||||
in float ge_cameraDistFromSun;
|
||||
in float ge_observedDist;
|
||||
|
||||
uniform sampler2D psfTexture;
|
||||
uniform sampler1D colorTexture;
|
||||
uniform float luminosityMultiplier;
|
||||
uniform float sharpness;
|
||||
uniform int renderOption;
|
||||
|
||||
vec3 color2rgb(float color) {
|
||||
// BV is [-0.4, 2.0]
|
||||
float st = (color + 0.4) / (2.0 + 0.4);
|
||||
|
||||
// Bp-Rp[-2.0, 6.5], Bp-G[-2.1, 5.0], G-Rp[-1.0, 3.0]
|
||||
//float st = (color + 1.0) / (5.0 + 1.0);
|
||||
|
||||
return texture(colorTexture, st).rgb;
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
// Assume all stars has equal luminosity as the Sun when no magnitude is loaded.
|
||||
float luminosity = 0.05;
|
||||
vec3 color = vec3(luminosity);
|
||||
float ratioMultiplier = 0.05;
|
||||
|
||||
vec4 textureColor = texture(psfTexture, texCoord);
|
||||
textureColor.a = pow(textureColor.a, sharpness);
|
||||
if (textureColor.a < 0.001) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Calculate the color and luminosity if we have the magnitude and B-V color.
|
||||
if ( renderOption != RENDEROPTION_STATIC ) {
|
||||
color = color2rgb(ge_brightness.y);
|
||||
ratioMultiplier = 0.5;
|
||||
|
||||
// Absolute magnitude is brightness a star would have at 10 pc away.
|
||||
float absoluteMagnitude = ge_brightness.x;
|
||||
|
||||
// From formula: MagSun - MagStar = 2.5*log(LumStar / LumSun), it gives that:
|
||||
// LumStar = 10^(1.89 - 0.4*Magstar) , if LumSun = 1 and MagSun = 4.72
|
||||
luminosity = pow(10.0, 1.89 - 0.4 * absoluteMagnitude);
|
||||
|
||||
// If luminosity is really really small then set it to a static low number.
|
||||
if (luminosity < LUM_LOWER_CAP) {
|
||||
luminosity = LUM_LOWER_CAP;
|
||||
}
|
||||
}
|
||||
|
||||
// Luminosity decrease by {squared} distance [measured in Pc].
|
||||
float observedDistance = ge_observedDist / ONE_PARSEC;
|
||||
luminosity /= pow(observedDistance, 2.0);
|
||||
|
||||
// Multiply our color with the luminosity as well as a user-controlled property.
|
||||
color *= luminosity * pow(luminosityMultiplier, 3.0);
|
||||
|
||||
// Decrease contributing brightness for stars in central cluster.
|
||||
if ( ge_cameraDistFromSun > ge_starDistFromSun ) {
|
||||
float ratio = ge_starDistFromSun / ge_cameraDistFromSun;
|
||||
//color *= ratio * ratioMultiplier;
|
||||
}
|
||||
|
||||
// Use truncating tonemapping here so we don't overexposure individual stars.
|
||||
//color = 1.0 - 1.0 * exp(-5.0 * color.rgb);
|
||||
float maxVal = max(max(color.r, color.g), color.b);
|
||||
if (maxVal > 1.0) {
|
||||
color /= maxVal;
|
||||
}
|
||||
|
||||
outColor = vec4(color, textureColor.a);
|
||||
}
|
||||
132
modules/gaia/shaders/gaia_billboard_ge.glsl
Normal file
132
modules/gaia/shaders/gaia_billboard_ge.glsl
Normal file
@@ -0,0 +1,132 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
// Keep in sync with gaiaoptions.h:RenderOption enum
|
||||
const int RENDEROPTION_STATIC = 0;
|
||||
const int RENDEROPTION_COLOR = 1;
|
||||
const int RENDEROPTION_MOTION = 2;
|
||||
const float EPS = 1e-5;
|
||||
|
||||
layout(points) in;
|
||||
in vec2 vs_brightness[];
|
||||
in vec4 vs_gPosition[];
|
||||
in float vs_starDistFromSun[];
|
||||
in float vs_cameraDistFromSun[];
|
||||
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
out vec2 ge_brightness;
|
||||
out vec4 ge_gPosition;
|
||||
out vec2 texCoord;
|
||||
out float ge_starDistFromSun;
|
||||
out float ge_cameraDistFromSun;
|
||||
out float ge_observedDist;
|
||||
|
||||
uniform dmat4 view;
|
||||
uniform dmat4 projection;
|
||||
|
||||
uniform dvec3 cameraPos;
|
||||
uniform dvec3 cameraLookUp;
|
||||
uniform float viewScaling;
|
||||
uniform float cutOffThreshold;
|
||||
uniform float closeUpBoostDist;
|
||||
uniform float billboardSize;
|
||||
uniform int renderOption;
|
||||
uniform float magnitudeBoost;
|
||||
|
||||
const vec2 corners[4] = vec2[4](
|
||||
vec2(0.0, 1.0),
|
||||
vec2(0.0, 0.0),
|
||||
vec2(1.0, 1.0),
|
||||
vec2(1.0, 0.0)
|
||||
);
|
||||
|
||||
|
||||
void main() {
|
||||
|
||||
ge_brightness = vs_brightness[0];
|
||||
ge_starDistFromSun = vs_starDistFromSun[0];
|
||||
ge_cameraDistFromSun = vs_cameraDistFromSun[0];
|
||||
|
||||
vec4 viewPosition = vec4(view * vs_gPosition[0]);
|
||||
|
||||
// Make closer stars look a bit bigger.
|
||||
ge_observedDist = safeLength(viewPosition / viewScaling);
|
||||
float closeUpBoost = closeUpBoostDist / ge_observedDist;
|
||||
float initStarSize = billboardSize;
|
||||
|
||||
// Use magnitude for size boost as well.
|
||||
if ( renderOption != RENDEROPTION_STATIC ) {
|
||||
// DR1 magnitudes are [4, 20], but could be [-15, 20] according to this chart:
|
||||
// https://qph.fs.quoracdn.net/main-qimg-317a18e3b228efc7d7f67a1632a55961
|
||||
// Negative magnitude => Giants
|
||||
// Big positive magnitude => Dwarfs
|
||||
float absoluteMagnitude = vs_brightness[0].x;
|
||||
float normalizedMagnitude = (absoluteMagnitude - 20) / -1; // (-15 - 20);
|
||||
|
||||
// TODO: A linear scale is prabably not the best!
|
||||
initStarSize += normalizedMagnitude * (magnitudeBoost / 50);
|
||||
}
|
||||
|
||||
vec4 position = gl_in[0].gl_Position;
|
||||
vec2 starSize = vec2(initStarSize + closeUpBoost) * position.w / 1000.0;
|
||||
|
||||
float distThreshold = cutOffThreshold - log(ge_observedDist) / log(4.0);
|
||||
|
||||
// Discard geometry if star has no position (but wasn't a nullArray).
|
||||
// Or if observed distance is above threshold set by cutOffThreshold.
|
||||
// By discarding in gs instead of fs we save computations for when nothing is visible.
|
||||
if( length(position) < EPS || distThreshold <= 0){
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 centerWorldPos = vs_gPosition[0];
|
||||
|
||||
dvec3 cameraNormal = normalize(cameraPos - dvec3(centerWorldPos.xyz));
|
||||
dvec3 newRight = normalize(cross(cameraLookUp, cameraNormal));
|
||||
dvec3 newUp = cross(cameraNormal, newRight);
|
||||
vec4 wCameraRight = vec4(newRight, 0.0);
|
||||
vec4 wCameraUp = vec4(newUp, 0.0);
|
||||
|
||||
float multiplier = float(length(cameraPos));
|
||||
starSize *= float(multiplier/1E1);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// Always turn the billboard towards the camera (needed for warped screen).
|
||||
vec4 cornerPoint = centerWorldPos
|
||||
+ wCameraRight * starSize.x * (corners[i].x - 0.5)
|
||||
+ wCameraUp * starSize.y * (corners[i].y - 0.5);
|
||||
gl_Position = vec4(projection * view * cornerPoint);
|
||||
gl_Position.z = 0.0;
|
||||
texCoord = corners[i];
|
||||
ge_gPosition = viewPosition;
|
||||
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
123
modules/gaia/shaders/gaia_billboard_nofbo_fs.glsl
Normal file
123
modules/gaia/shaders/gaia_billboard_nofbo_fs.glsl
Normal file
@@ -0,0 +1,123 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "fragment.glsl"
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
// Keep in sync with gaiaoptions.h:RenderOption enum
|
||||
const int RENDEROPTION_STATIC = 0;
|
||||
const int RENDEROPTION_COLOR = 1;
|
||||
const int RENDEROPTION_MOTION = 2;
|
||||
const float ONE_PARSEC = 3.08567758e16; // 1 Parsec
|
||||
const float DEFAULT_DEPTH = 3.08567758e19; // 1000 Pc
|
||||
const float LUM_LOWER_CAP = 0.01;
|
||||
|
||||
in vec2 ge_brightness;
|
||||
in vec4 ge_gPosition;
|
||||
in vec2 texCoord;
|
||||
in float ge_starDistFromSun;
|
||||
in float ge_cameraDistFromSun;
|
||||
in float ge_observedDist;
|
||||
|
||||
uniform sampler2D psfTexture;
|
||||
uniform sampler1D colorTexture;
|
||||
uniform float luminosityMultiplier;
|
||||
uniform float sharpness;
|
||||
uniform int renderOption;
|
||||
|
||||
vec3 color2rgb(float color) {
|
||||
// BV is [-0.4, 2.0]
|
||||
float st = (color + 0.4) / (2.0 + 0.4);
|
||||
|
||||
// Bp-Rp[-2.0, 6.5], Bp-G[-2.1, 5.0], G-Rp[-1.0, 3.0]
|
||||
//float st = (color + 1.0) / (5.0 + 1.0);
|
||||
|
||||
return texture(colorTexture, st).rgb;
|
||||
}
|
||||
|
||||
Fragment getFragment() {
|
||||
|
||||
// Assume all stars has equal luminosity as the Sun when no magnitude is loaded.
|
||||
float luminosity = 1.0;
|
||||
vec3 color = vec3(luminosity);
|
||||
float ratioMultiplier = 0.03;
|
||||
|
||||
vec4 textureColor = texture(psfTexture, texCoord);
|
||||
textureColor.a = pow(textureColor.a, sharpness);
|
||||
if (textureColor.a < 0.001) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// Calculate the color and luminosity if we have the magnitude and B-V color.
|
||||
if ( renderOption != RENDEROPTION_STATIC ) {
|
||||
color = color2rgb(ge_brightness.y);
|
||||
ratioMultiplier = 0.5;
|
||||
|
||||
// Absolute magnitude is brightness a star would have at 10 pc away.
|
||||
float absoluteMagnitude = ge_brightness.x;
|
||||
|
||||
// From formula: MagSun - MagStar = 2.5*log(LumStar / LumSun), it gives that:
|
||||
// LumStar = 10^(1.89 - 0.4*Magstar) , if LumSun = 1 and MagSun = 4.72
|
||||
luminosity = pow(10.0, 1.89 - 0.4 * absoluteMagnitude);
|
||||
|
||||
// If luminosity is really really small then set it to a static low number.
|
||||
if (luminosity < LUM_LOWER_CAP) {
|
||||
luminosity = LUM_LOWER_CAP;
|
||||
}
|
||||
}
|
||||
|
||||
// Luminosity decrease by {squared} distance [measured in Pc].
|
||||
float observedDistance = ge_observedDist / ONE_PARSEC;
|
||||
luminosity /= pow(observedDistance, 2.0);
|
||||
|
||||
// Multiply our color with the luminosity as well as a user-controlled property.
|
||||
color *= luminosity * pow(luminosityMultiplier, 3.0);
|
||||
|
||||
// Decrease contributing brightness for stars in central cluster.
|
||||
if ( ge_cameraDistFromSun > ge_starDistFromSun ) {
|
||||
float ratio = ge_starDistFromSun / ge_cameraDistFromSun;
|
||||
//color *= ratio * ratioMultiplier;
|
||||
}
|
||||
|
||||
// Use truncating tonemapping here so we don't overexposure individual stars.
|
||||
//color = 1.0 - 1.0 * exp(-5.0 * color.rgb);
|
||||
float maxVal = max(max(color.r, color.g), color.b);
|
||||
if (maxVal > 1.0) {
|
||||
color /= maxVal;
|
||||
}
|
||||
|
||||
if (length(color) < 0.01) {
|
||||
discard;
|
||||
}
|
||||
|
||||
Fragment frag;
|
||||
frag.color = vec4(color, textureColor.a);;
|
||||
// Place stars at back to begin with.
|
||||
frag.depth = DEFAULT_DEPTH;
|
||||
frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
frag.blend = BLEND_MODE_NORMAL;
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
98
modules/gaia/shaders/gaia_point_fs.glsl
Normal file
98
modules/gaia/shaders/gaia_point_fs.glsl
Normal file
@@ -0,0 +1,98 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
// Keep in sync with gaiaoptions.h:RenderOption enum
|
||||
const int RENDEROPTION_STATIC = 0;
|
||||
const int RENDEROPTION_COLOR = 1;
|
||||
const int RENDEROPTION_MOTION = 2;
|
||||
const float ONE_PARSEC = 3.08567758e16; // 1 Parsec
|
||||
const float LUM_LOWER_CAP = 0.01;
|
||||
|
||||
in vec2 ge_brightness;
|
||||
in vec4 ge_gPosition;
|
||||
in float ge_starDistFromSun;
|
||||
in float ge_cameraDistFromSun;
|
||||
in float ge_observedDist;
|
||||
|
||||
uniform sampler1D colorTexture;
|
||||
uniform float luminosityMultiplier;
|
||||
uniform int renderOption;
|
||||
uniform float viewScaling;
|
||||
|
||||
vec3 color2rgb(float color) {
|
||||
// BV is [-0.4, 2.0]
|
||||
float st = (color + 0.4) / (2.0 + 0.4);
|
||||
|
||||
// Bp-Rp[-2.0, 6.5], Bp-G[-2.1, 5.0], G-Rp[-1.0, 3.0]
|
||||
//float st = (color + 1.0) / (5.0 + 1.0);
|
||||
|
||||
return texture(colorTexture, st).rgb;
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
// Assume all stars has equal luminosity as the Sun when no magnitude is loaded.
|
||||
float luminosity = 0.05;
|
||||
vec3 color = vec3(luminosity);
|
||||
float ratioMultiplier = 1.0;
|
||||
|
||||
// Calculate the color and luminosity if we have the magnitude and B-V color.
|
||||
if ( renderOption != RENDEROPTION_STATIC ) {
|
||||
color = color2rgb(ge_brightness.y);
|
||||
ratioMultiplier = 0.01;
|
||||
|
||||
// Absolute magnitude is brightness a star would have at 10 pc away.
|
||||
float absoluteMagnitude = ge_brightness.x;
|
||||
|
||||
// From formula: MagSun - MagStar = 2.5*log(LumStar / LumSun), it gives that:
|
||||
// LumStar = 10^(1.89 - 0.4*Magstar) , if LumSun = 1 and MagSun = 4.72
|
||||
luminosity = pow(10.0, 1.89 - 0.4 * absoluteMagnitude);
|
||||
|
||||
// If luminosity is really really small then set it to a static low number.
|
||||
if (luminosity < LUM_LOWER_CAP) {
|
||||
luminosity = LUM_LOWER_CAP;
|
||||
}
|
||||
}
|
||||
|
||||
// Luminosity decrease by {squared} distance [measured in Pc].
|
||||
float observedDistance = ge_observedDist / ONE_PARSEC;
|
||||
luminosity /= pow(observedDistance, 2.0);
|
||||
|
||||
// Multiply our color with the luminosity as well as a user-controlled property.
|
||||
color *= luminosity * pow(luminosityMultiplier, 3.0);
|
||||
|
||||
// Decrease contributing brightness for stars in central cluster.
|
||||
if ( ge_cameraDistFromSun > ge_starDistFromSun ) {
|
||||
float ratio = ge_starDistFromSun / ge_cameraDistFromSun;
|
||||
//color *= ratio * ratioMultiplier;
|
||||
}
|
||||
|
||||
outColor = vec4(color, 1.0f);
|
||||
}
|
||||
76
modules/gaia/shaders/gaia_point_ge.glsl
Normal file
76
modules/gaia/shaders/gaia_point_ge.glsl
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
const float EPS = 1e-5;
|
||||
|
||||
layout(points) in;
|
||||
in vec2 vs_brightness[];
|
||||
in vec4 vs_gPosition[];
|
||||
in float vs_starDistFromSun[];
|
||||
in float vs_cameraDistFromSun[];
|
||||
|
||||
layout(points, max_vertices = 1) out;
|
||||
out vec2 ge_brightness;
|
||||
out vec4 ge_gPosition;
|
||||
out float ge_starDistFromSun;
|
||||
out float ge_cameraDistFromSun;
|
||||
out float ge_observedDist;
|
||||
|
||||
uniform dmat4 view;
|
||||
uniform float viewScaling;
|
||||
uniform float cutOffThreshold;
|
||||
|
||||
void main() {
|
||||
|
||||
ge_brightness = vs_brightness[0];
|
||||
ge_starDistFromSun = vs_starDistFromSun[0];
|
||||
ge_cameraDistFromSun = vs_cameraDistFromSun[0];
|
||||
|
||||
vec4 viewPosition = vec4(view * vs_gPosition[0]);
|
||||
|
||||
ge_observedDist = safeLength(viewPosition / viewScaling);
|
||||
float distThreshold = cutOffThreshold - log(ge_observedDist) / log(4.0);
|
||||
|
||||
vec4 position = gl_in[0].gl_Position;
|
||||
|
||||
// Discard geometry if star has no position (but wasn't a nullArray).
|
||||
// Or if observed distance is above threshold set by cutOffThreshold.
|
||||
// By discarding in gs instead of fs we save computations for when nothing is visible.
|
||||
if( length(position) < EPS || distThreshold <= 0){
|
||||
return;
|
||||
}
|
||||
|
||||
//gl_PointSize = 1.0;
|
||||
gl_Position = position;
|
||||
gl_Position.z = 0.0;
|
||||
ge_gPosition = viewPosition;
|
||||
|
||||
EmitVertex();
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
186
modules/gaia/shaders/gaia_ssbo_vs.glsl
Normal file
186
modules/gaia/shaders/gaia_ssbo_vs.glsl
Normal file
@@ -0,0 +1,186 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
// Keep in sync with gaiaoptions.h:RenderOption enum
|
||||
const int RENDEROPTION_STATIC = 0;
|
||||
const int RENDEROPTION_COLOR = 1;
|
||||
const int RENDEROPTION_MOTION = 2;
|
||||
const float EPS = 1e-5;
|
||||
const float Parsec = 3.0856776e16;
|
||||
|
||||
layout (std430) buffer ssbo_idx_data {
|
||||
int starsPerChunk[];
|
||||
};
|
||||
|
||||
layout (std430) buffer ssbo_comb_data {
|
||||
float allData[];
|
||||
};
|
||||
|
||||
in int gl_VertexID;
|
||||
|
||||
out vec2 vs_brightness;
|
||||
out vec4 vs_gPosition;
|
||||
out float vs_starDistFromSun;
|
||||
out float vs_cameraDistFromSun;
|
||||
|
||||
uniform dmat4 model;
|
||||
uniform dmat4 view;
|
||||
uniform dmat4 projection;
|
||||
uniform float time;
|
||||
uniform int renderOption;
|
||||
|
||||
uniform int maxStarsPerNode;
|
||||
uniform int valuesPerStar;
|
||||
uniform int nChunksToRender;
|
||||
|
||||
uniform vec2 posXThreshold;
|
||||
uniform vec2 posYThreshold;
|
||||
uniform vec2 posZThreshold;
|
||||
uniform vec2 gMagThreshold;
|
||||
uniform vec2 bpRpThreshold;
|
||||
uniform vec2 distThreshold;
|
||||
|
||||
// Use binary search to find the chunk containing our star ID.
|
||||
int findChunkId(int left, int right, int id) {
|
||||
|
||||
while ( left <= right ) {
|
||||
int middle = (left + right) / 2;
|
||||
int firstStarInChunk = starsPerChunk[middle];
|
||||
if (left == right || (firstStarInChunk <= id && id < starsPerChunk[middle+1])) {
|
||||
return middle;
|
||||
}
|
||||
else if (id < firstStarInChunk) {
|
||||
// Go smaller
|
||||
right = middle - 1;
|
||||
}
|
||||
else {
|
||||
// Go bigger
|
||||
left = middle + 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// Fetch our data.
|
||||
int chunkId = findChunkId(0, nChunksToRender - 1, gl_VertexID);
|
||||
// Fail safe - this should never happen!
|
||||
if (chunkId == -1) {
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
int placeInChunk = gl_VertexID - starsPerChunk[chunkId];
|
||||
int firstStarInChunk = valuesPerStar * maxStarsPerNode * chunkId; // Chunk offset
|
||||
int nStarsInChunk = starsPerChunk[chunkId + 1] - starsPerChunk[chunkId]; // Stars in current chunk.
|
||||
// Remove possible duplicates.
|
||||
if (nStarsInChunk <= 0) {
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
int startOfPos = firstStarInChunk + placeInChunk * 3;
|
||||
vec3 in_position = vec3(allData[startOfPos], allData[startOfPos + 1], allData[startOfPos + 2]);
|
||||
vec2 in_brightness = vec2(0.0);
|
||||
vec3 in_velocity = vec3(0.0);
|
||||
|
||||
// Check if we should filter this star by position.
|
||||
if ( (abs(posXThreshold.x) > EPS && in_position.x < posXThreshold.x) ||
|
||||
(abs(posXThreshold.y) > EPS && in_position.x > posXThreshold.y) ||
|
||||
(abs(posYThreshold.x) > EPS && in_position.y < posYThreshold.x) ||
|
||||
(abs(posYThreshold.y) > EPS && in_position.y > posYThreshold.y) ||
|
||||
(abs(posZThreshold.x) > EPS && in_position.z < posZThreshold.x) ||
|
||||
(abs(posZThreshold.y) > EPS && in_position.z > posZThreshold.y) ||
|
||||
(abs(distThreshold.x - distThreshold.y) < EPS
|
||||
&& abs(length(in_position) - distThreshold.y) < EPS) ) {
|
||||
// Discard star in geometry shader.
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( renderOption != RENDEROPTION_STATIC ) {
|
||||
int startOfCol = firstStarInChunk + nStarsInChunk * 3 + placeInChunk * 2;
|
||||
in_brightness = vec2(allData[startOfCol], allData[startOfCol + 1]);
|
||||
|
||||
// Check if we should filter this star by magnitude or color.
|
||||
if ( (abs(gMagThreshold.x - gMagThreshold.y) < EPS && abs(gMagThreshold.x - in_brightness.x) < EPS) ||
|
||||
(abs(gMagThreshold.x - 20.0f) > EPS && in_brightness.x < gMagThreshold.x) ||
|
||||
(abs(gMagThreshold.y - 20.0f) > EPS && in_brightness.x > gMagThreshold.y) ||
|
||||
(abs(bpRpThreshold.x - bpRpThreshold.y) < EPS && abs(bpRpThreshold.x - in_brightness.y) < EPS) ||
|
||||
(abs(bpRpThreshold.x) > EPS && in_brightness.y < bpRpThreshold.x) ||
|
||||
(abs(bpRpThreshold.y) > EPS && in_brightness.y > bpRpThreshold.y) ) {
|
||||
// Discard star in geometry shader.
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( renderOption == RENDEROPTION_MOTION ) {
|
||||
int startOfVel = firstStarInChunk + nStarsInChunk * 5 + placeInChunk * 3;
|
||||
in_velocity = vec3(allData[startOfVel], allData[startOfVel + 1], allData[startOfVel + 2]);
|
||||
}
|
||||
}
|
||||
vs_brightness = in_brightness;
|
||||
|
||||
// Convert kiloParsec to meter.
|
||||
vec4 objectPosition = vec4(in_position * 1000 * Parsec, 1.0);
|
||||
|
||||
// Add velocity [m/s] if we've read any.
|
||||
objectPosition.xyz += time * in_velocity;
|
||||
|
||||
// Thres moving stars by their new position.
|
||||
float distPosition = length(objectPosition.xyz / (1000.0 * Parsec) );
|
||||
if ( (abs(distThreshold.x - distThreshold.y) > EPS &&
|
||||
((abs(distThreshold.x) > EPS && distPosition < distThreshold.x) ||
|
||||
(abs(distThreshold.y) > EPS && distPosition > distThreshold.y))) ) {
|
||||
// Discard star in geometry shader.
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply camera transforms.
|
||||
dvec4 viewPosition = view * model * objectPosition;
|
||||
vec4 sunPosition = vec4(view * model * dvec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
vs_starDistFromSun = safeLength(objectPosition);
|
||||
vs_cameraDistFromSun = safeLength(sunPosition);
|
||||
|
||||
// Remove stars without position, happens when VBO chunk is stuffed with zeros.
|
||||
// Has to be done in Geometry shader because Vertices cannot be discarded here.
|
||||
if ( length(in_position) > EPS ){
|
||||
vs_gPosition = vec4(model * objectPosition);
|
||||
gl_Position = vec4(projection * viewPosition);
|
||||
} else {
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
}
|
||||
}
|
||||
53
modules/gaia/shaders/gaia_tonemapping_billboard_fs.glsl
Normal file
53
modules/gaia/shaders/gaia_tonemapping_billboard_fs.glsl
Normal file
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "fragment.glsl"
|
||||
|
||||
in vec2 uv;
|
||||
|
||||
uniform sampler2D renderedTexture;
|
||||
|
||||
const float DEFAULT_DEPTH = 3.08567758e19; // 1000 Pc
|
||||
|
||||
|
||||
Fragment getFragment() {
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
// BILLBOARDS
|
||||
// Sample color. Tonemapping done in first shader pass.
|
||||
vec4 textureColor = texture( renderedTexture, uv );
|
||||
|
||||
// Use the following to check for any intensity at all.
|
||||
//color = (length(intensity.rgb) > 0.001) ? vec4(1.0) : vec4(0.0);
|
||||
|
||||
Fragment frag;
|
||||
frag.color = textureColor;
|
||||
// Place stars at back to begin with.
|
||||
frag.depth = DEFAULT_DEPTH;
|
||||
frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
frag.blend = BLEND_MODE_NORMAL;
|
||||
|
||||
return frag;
|
||||
}
|
||||
178
modules/gaia/shaders/gaia_tonemapping_point_fs.glsl
Normal file
178
modules/gaia/shaders/gaia_tonemapping_point_fs.glsl
Normal file
@@ -0,0 +1,178 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "fragment.glsl"
|
||||
|
||||
in vec2 uv;
|
||||
|
||||
uniform sampler2D renderedTexture;
|
||||
uniform dmat4 projection;
|
||||
uniform vec2 screenSize;
|
||||
uniform int filterSize;
|
||||
uniform float sigma;
|
||||
uniform float pixelWeightThreshold;
|
||||
|
||||
const float M_PI = 3.141592653589793238462;
|
||||
const float DEFAULT_DEPTH = 3.08567758e19; // 1000 Pc
|
||||
|
||||
Fragment getFragment() {
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
|
||||
// GL_POINTS
|
||||
|
||||
// Use frustum params to be able to compensate for a skewed frustum (in a dome).
|
||||
float near = float(projection[3][2] / (projection[2][2] - 1.0));
|
||||
float left = float(near * (projection[2][0] - 1.0) / projection[0][0]);
|
||||
float right = float(near * (projection[2][0] + 1.0) / projection[0][0]);
|
||||
float top = float(near * (projection[2][1] + 1.0) / projection[1][1]);
|
||||
float bottom = float(near * (projection[2][1] - 1.0) / projection[1][1]);
|
||||
|
||||
float xFactor = float(projection[0][0]);
|
||||
float yFactor = float(projection[1][1]);
|
||||
|
||||
float planeAspect = yFactor / xFactor; // Equals: (right - left) / (top - bottom)
|
||||
float screenAspect = screenSize.x / screenSize.y;
|
||||
float fullAspect = planeAspect / screenAspect;
|
||||
|
||||
// Find screenPos in skewed frustum. uv is [0, 1]
|
||||
vec2 screenPos = uv * vec2(right - left, top - bottom) + vec2(left, bottom);
|
||||
|
||||
// Find our elliptic scale factors by trigonometric approximation.
|
||||
float beta = atan(length(screenPos) / near);
|
||||
vec2 sigmaScaleFactor = vec2( 1.0 / cos(beta), 1.0 / pow(cos(beta), 2.0));
|
||||
|
||||
float defaultScreen = 1200.0;
|
||||
float scaling = screenSize.y / defaultScreen * yFactor;
|
||||
|
||||
// Scale filter size depending on screen pos.
|
||||
vec2 filterScaleFactor = vec2(
|
||||
pow(screenPos.x / near, 2.0) * fullAspect,
|
||||
pow(screenPos.y / near, 2.0)
|
||||
);
|
||||
|
||||
// Use to ignore scaling.
|
||||
//filterScaleFactor = vec2(0.0);
|
||||
//scaling = 1.0;
|
||||
//sigmaScaleFactor = vec2(1.0);
|
||||
|
||||
// Use the following to find the origo in a skewed frustum.
|
||||
//Fragment origoFrag;
|
||||
//vec2 screenOrigo = vec2(-left, -bottom) / vec2(right - left, top - bottom);
|
||||
//if (abs(screenOrigo.x - uv.x) > 0.0005 && abs(screenOrigo.y - uv.y) > 0.0005) {
|
||||
// origoFrag.color = vec4(0.0);
|
||||
//} else {
|
||||
// origoFrag.color = vec4(1.0);
|
||||
//}
|
||||
//return origoFrag;
|
||||
|
||||
// Uncomment to compare to original filterSize (assumes origo in center of screen).
|
||||
//screenPos = (uv - 0.5) * 2.0; // [-1, 1]
|
||||
//filterScaleFactor = vec2(
|
||||
// pow(screenPos.x, 2.0),
|
||||
// pow(screenPos.y, 2.0)
|
||||
//);
|
||||
|
||||
// Make use of the following flag this to toggle betweeen circular and elliptic distribution.
|
||||
bool useCircleDist = false;
|
||||
|
||||
// Apply scaling on bloom filter.
|
||||
vec2 newFilterSize = vec2(filterSize) * (1.0 + length(filterScaleFactor)) * scaling;
|
||||
|
||||
// Calculate params for a rotated Elliptic Gaussian distribution.
|
||||
float sigmaMajor;
|
||||
float sigmaMinor;
|
||||
float a;
|
||||
float b;
|
||||
float c;
|
||||
if (!useCircleDist) {
|
||||
float alpha = atan(screenPos.y, screenPos.x);
|
||||
// Apply scaling on sigma.
|
||||
sigmaMajor = sigma * sigmaScaleFactor.y * scaling;
|
||||
sigmaMinor = sigma * sigmaScaleFactor.x * scaling;
|
||||
|
||||
a = pow(cos(alpha), 2.0) / (2 * pow(sigmaMajor, 2.0))
|
||||
+ pow(sin(alpha), 2.0) / (2 * pow(sigmaMinor, 2.0)) ;
|
||||
b = sin(2 * alpha) / (4 * pow(sigmaMajor, 2.0))
|
||||
- sin(2 * alpha) / (4 * pow(sigmaMinor, 2.0)) ;
|
||||
c = pow(sin(alpha), 2.0) / (2 * pow(sigmaMajor, 2.0))
|
||||
+ pow(cos(alpha), 2.0) / (2 * pow(sigmaMinor, 2.0)) ;
|
||||
}
|
||||
|
||||
// Get a [newFilterSize x newFilterSize] filter around our pixel. UV is [0, 1]
|
||||
vec3 intensity = vec3(0.0);
|
||||
vec2 pixelSize = 1.0 / screenSize;
|
||||
ivec2 halfFilterSize = ivec2((newFilterSize - 1.0) / 2.0);
|
||||
for (int y = -halfFilterSize.y; y <= halfFilterSize.y; y += 1) {
|
||||
for (int x = -halfFilterSize.x; x <= halfFilterSize.x; x += 1) {
|
||||
vec2 sPoint = uv + (pixelSize * ivec2(x, y));
|
||||
|
||||
// Calculate the contribution of this pixel (elliptic gaussian distribution).
|
||||
float pixelWeight = exp(-(
|
||||
a * pow(x * fullAspect, 2.0)
|
||||
+ 2 * b * x * y * fullAspect
|
||||
+ c * pow(y, 2.0)
|
||||
));
|
||||
|
||||
// Only sample inside FBO texture and if the pixel will contribute to final color.
|
||||
if (all(greaterThan(sPoint, vec2(0.0))) && all(lessThan(sPoint, vec2(1.0)))
|
||||
&& pixelWeight > pixelWeightThreshold) {
|
||||
vec4 sIntensity = texture( renderedTexture, sPoint );
|
||||
|
||||
// Use normal distribution function for halo/bloom effect.
|
||||
if (useCircleDist) {
|
||||
float circleDist = sqrt(pow(x / (1 + length(filterScaleFactor)), 2.0)
|
||||
+ pow(y / (1 + length(filterScaleFactor)), 2.0));
|
||||
intensity += sIntensity.rgb * (1.0 / (sigma * sqrt(2.0 * M_PI))) *
|
||||
exp(-(pow(circleDist, 2.0) / (2.0 * pow(sigma, 2.0)))) / filterSize;
|
||||
}
|
||||
else {
|
||||
// Divide contribution by area of ellipse.
|
||||
intensity += sIntensity.rgb * pixelWeight * fullAspect;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tonemap intensity to color!
|
||||
//intensity = 1.0 - 1.0 * exp(-25.0 * intensity);
|
||||
intensity = pow(intensity, vec3(0.8));
|
||||
|
||||
if (length(intensity) < 0.01) {
|
||||
discard;
|
||||
}
|
||||
|
||||
color = vec4(intensity, 1.0f);
|
||||
|
||||
// Use the following to check for any intensity at all.
|
||||
//color = (length(intensity.rgb) > 0.001) ? vec4(1.0) : vec4(0.0);
|
||||
|
||||
Fragment frag;
|
||||
frag.color = color;
|
||||
// Place stars at back to begin with.
|
||||
frag.depth = DEFAULT_DEPTH;
|
||||
frag.gNormal = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
frag.blend = BLEND_MODE_NORMAL;
|
||||
|
||||
return frag;
|
||||
}
|
||||
34
modules/gaia/shaders/gaia_tonemapping_vs.glsl
Normal file
34
modules/gaia/shaders/gaia_tonemapping_vs.glsl
Normal file
@@ -0,0 +1,34 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
in vec3 in_position;
|
||||
|
||||
out vec2 uv;
|
||||
|
||||
void main() {
|
||||
uv = (in_position.xy + 1.0) / 2.0;
|
||||
gl_Position = vec4(in_position, 1.0);
|
||||
}
|
||||
119
modules/gaia/shaders/gaia_vbo_vs.glsl
Normal file
119
modules/gaia/shaders/gaia_vbo_vs.glsl
Normal file
@@ -0,0 +1,119 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "floatoperations.glsl"
|
||||
|
||||
// Keep in sync with gaiaoptions.h:RenderOption enum
|
||||
const int RENDEROPTION_STATIC = 0;
|
||||
const int RENDEROPTION_COLOR = 1;
|
||||
const int RENDEROPTION_MOTION = 2;
|
||||
const float EPS = 1e-5;
|
||||
const float Parsec = 3.0856776e16;
|
||||
|
||||
in vec3 in_position;
|
||||
in vec2 in_brightness;
|
||||
in vec3 in_velocity;
|
||||
|
||||
out vec2 vs_brightness;
|
||||
out vec4 vs_gPosition;
|
||||
out float vs_starDistFromSun;
|
||||
out float vs_cameraDistFromSun;
|
||||
|
||||
uniform dmat4 model;
|
||||
uniform dmat4 view;
|
||||
uniform dmat4 projection;
|
||||
uniform float time;
|
||||
uniform int renderOption;
|
||||
|
||||
uniform vec2 posXThreshold;
|
||||
uniform vec2 posYThreshold;
|
||||
uniform vec2 posZThreshold;
|
||||
uniform vec2 gMagThreshold;
|
||||
uniform vec2 bpRpThreshold;
|
||||
uniform vec2 distThreshold;
|
||||
|
||||
void main() {
|
||||
vs_brightness = in_brightness;
|
||||
|
||||
// Check if we should filter this star by position. Thres depending on original values.
|
||||
if ( (abs(posXThreshold.x) > EPS && in_position.x < posXThreshold.x) ||
|
||||
(abs(posXThreshold.y) > EPS && in_position.x > posXThreshold.y) ||
|
||||
(abs(posYThreshold.x) > EPS && in_position.y < posYThreshold.x) ||
|
||||
(abs(posYThreshold.y) > EPS && in_position.y > posYThreshold.y) ||
|
||||
(abs(posZThreshold.x) > EPS && in_position.z < posZThreshold.x) ||
|
||||
(abs(posZThreshold.y) > EPS && in_position.z > posZThreshold.y) ||
|
||||
(abs(distThreshold.x - distThreshold.y) < EPS
|
||||
&& abs(length(in_position) - distThreshold.y) < EPS) ||
|
||||
( renderOption != RENDEROPTION_STATIC && (
|
||||
(abs(gMagThreshold.x - gMagThreshold.y) < EPS && abs(gMagThreshold.x - in_brightness.x) < EPS) ||
|
||||
(abs(gMagThreshold.x - 20.0f) > EPS && in_brightness.x < gMagThreshold.x) ||
|
||||
(abs(gMagThreshold.y - 20.0f) > EPS && in_brightness.x > gMagThreshold.y) ||
|
||||
(abs(bpRpThreshold.x - bpRpThreshold.y) < EPS && abs(bpRpThreshold.x - in_brightness.y) < EPS) ||
|
||||
(abs(bpRpThreshold.x) > EPS && in_brightness.y < bpRpThreshold.x) ||
|
||||
(abs(bpRpThreshold.y) > EPS && in_brightness.y > bpRpThreshold.y))) ) {
|
||||
// Discard star in geometry shader.
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert kiloParsec to meter.
|
||||
vec4 objectPosition = vec4(in_position * 1000 * Parsec, 1.0);
|
||||
|
||||
// Add velocity if we've read any.
|
||||
if ( renderOption == RENDEROPTION_MOTION ) {
|
||||
// Velocity is already in [m/s].
|
||||
objectPosition.xyz += time * in_velocity;
|
||||
}
|
||||
|
||||
// Thres moving stars by their new position.
|
||||
float distPosition = length(objectPosition.xyz / (1000.0 * Parsec) );
|
||||
if ( (abs(distThreshold.x - distThreshold.y) > EPS &&
|
||||
((abs(distThreshold.x) > EPS && distPosition< distThreshold.x) ||
|
||||
(abs(distThreshold.y) > EPS && distPosition > distThreshold.y))) ) {
|
||||
// Discard star in geometry shader.
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply camera transforms.
|
||||
dvec4 viewPosition = view * model * objectPosition;
|
||||
vec4 sunPosition = vec4(view * model * vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
vs_starDistFromSun = safeLength(objectPosition);
|
||||
vs_cameraDistFromSun = safeLength(sunPosition);
|
||||
|
||||
// Remove stars without position, happens when VBO chunk is stuffed with zeros.
|
||||
// Has to be done in Geometry shader because Vertices cannot be discarded here.
|
||||
if ( length(in_position) > EPS ){
|
||||
vs_gPosition = vec4(model * objectPosition);
|
||||
gl_Position = vec4(projection * viewPosition);
|
||||
} else {
|
||||
vs_gPosition = vec4(0.0);
|
||||
gl_Position = vec4(0.0);
|
||||
}
|
||||
}
|
||||
817
modules/gaia/tasks/constructoctreetask.cpp
Normal file
817
modules/gaia/tasks/constructoctreetask.cpp
Normal file
@@ -0,0 +1,817 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/gaia/tasks/constructoctreetask.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/filesystem/directory.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath";
|
||||
constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath";
|
||||
constexpr const char* KeyMaxDist = "MaxDist";
|
||||
constexpr const char* KeyMaxStarsPerNode = "MaxStarsPerNode";
|
||||
constexpr const char* KeySingleFileInput = "SingleFileInput";
|
||||
|
||||
constexpr const char* KeyFilterPosX = "FilterPosX";
|
||||
constexpr const char* KeyFilterPosY = "FilterPosY";
|
||||
constexpr const char* KeyFilterPosZ = "FilterPosZ";
|
||||
constexpr const char* KeyFilterGMag = "FilterGMag";
|
||||
constexpr const char* KeyFilterBpRp = "FilterBpRp";
|
||||
constexpr const char* KeyFilterVelX = "FilterVelX";
|
||||
constexpr const char* KeyFilterVelY = "FilterVelY";
|
||||
constexpr const char* KeyFilterVelZ = "FilterVelZ";
|
||||
constexpr const char* KeyFilterBpMag = "FilterBpMag";
|
||||
constexpr const char* KeyFilterRpMag = "FilterRpMag";
|
||||
constexpr const char* KeyFilterBpG = "FilterBpG";
|
||||
constexpr const char* KeyFilterGRp = "FilterGRp";
|
||||
constexpr const char* KeyFilterRa = "FilterRa";
|
||||
constexpr const char* KeyFilterRaError = "FilterRaError";
|
||||
constexpr const char* KeyFilterDec = "FilterDec";
|
||||
constexpr const char* KeyFilterDecError = "FilterDecError";
|
||||
constexpr const char* KeyFilterParallax = "FilterParallax";
|
||||
constexpr const char* KeyFilterParallaxError = "FilterParallaxError";
|
||||
constexpr const char* KeyFilterPmra = "FilterPmra";
|
||||
constexpr const char* KeyFilterPmraError = "FilterPmraError";
|
||||
constexpr const char* KeyFilterPmdec = "FilterPmdec";
|
||||
constexpr const char* KeyFilterPmdecError = "FilterPmdecError";
|
||||
constexpr const char* KeyFilterRv = "FilterRv";
|
||||
constexpr const char* KeyFilterRvError = "FilterRvError";
|
||||
|
||||
constexpr const char* _loggerCat = "ConstructOctreeTask";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ConstructOctreeTask::ConstructOctreeTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"ConstructOctreeTask"
|
||||
);
|
||||
|
||||
_inFileOrFolderPath = absPath(dictionary.value<std::string>(KeyInFileOrFolderPath));
|
||||
_outFileOrFolderPath = absPath(dictionary.value<std::string>(KeyOutFileOrFolderPath));
|
||||
|
||||
if (dictionary.hasKey(KeyMaxDist)) {
|
||||
_maxDist = static_cast<int>(dictionary.value<double>(KeyMaxDist));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyMaxStarsPerNode)) {
|
||||
_maxStarsPerNode = static_cast<int>(dictionary.value<double>(KeyMaxStarsPerNode));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeySingleFileInput)) {
|
||||
_singleFileInput = dictionary.value<bool>(KeySingleFileInput);
|
||||
}
|
||||
|
||||
_octreeManager = std::make_shared<OctreeManager>();
|
||||
_indexOctreeManager = std::make_shared<OctreeManager>();
|
||||
|
||||
// Check for filter params.
|
||||
if (dictionary.hasKey(KeyFilterPosX)) {
|
||||
_posX = dictionary.value<glm::vec2>(KeyFilterPosX);
|
||||
_filterPosX = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPosY)) {
|
||||
_posY = dictionary.value<glm::vec2>(KeyFilterPosY);
|
||||
_filterPosY = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPosZ)) {
|
||||
_posZ = dictionary.value<glm::vec2>(KeyFilterPosZ);
|
||||
_filterPosZ = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterGMag)) {
|
||||
_gMag = dictionary.value<glm::vec2>(KeyFilterGMag);
|
||||
_filterGMag = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterBpRp)) {
|
||||
_bpRp = dictionary.value<glm::vec2>(KeyFilterBpRp);
|
||||
_filterBpRp = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterVelX)) {
|
||||
_velX = dictionary.value<glm::vec2>(KeyFilterVelX);
|
||||
_filterVelX = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterVelY)) {
|
||||
_velY = dictionary.value<glm::vec2>(KeyFilterVelY);
|
||||
_filterVelY = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterVelZ)) {
|
||||
_velZ = dictionary.value<glm::vec2>(KeyFilterVelZ);
|
||||
_filterVelZ = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterBpMag)) {
|
||||
_bpMag = dictionary.value<glm::vec2>(KeyFilterBpMag);
|
||||
_filterBpMag = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRpMag)) {
|
||||
_rpMag = dictionary.value<glm::vec2>(KeyFilterRpMag);
|
||||
_filterRpMag = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterBpG)) {
|
||||
_bpG = dictionary.value<glm::vec2>(KeyFilterBpG);
|
||||
_filterBpG = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterGRp)) {
|
||||
_gRp = dictionary.value<glm::vec2>(KeyFilterGRp);
|
||||
_filterGRp = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRa)) {
|
||||
_ra = dictionary.value<glm::vec2>(KeyFilterRa);
|
||||
_filterRa = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRaError)) {
|
||||
_raError = dictionary.value<glm::vec2>(KeyFilterRaError);
|
||||
_filterRaError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterDec)) {
|
||||
_dec = dictionary.value<glm::vec2>(KeyFilterDec);
|
||||
_filterDec = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterDecError)) {
|
||||
_decError = dictionary.value<glm::vec2>(KeyFilterDecError);
|
||||
_filterDecError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterParallax)) {
|
||||
_parallax = dictionary.value<glm::vec2>(KeyFilterParallax);
|
||||
_filterParallax = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterParallaxError)) {
|
||||
_parallaxError = dictionary.value<glm::vec2>(KeyFilterParallaxError);
|
||||
_filterParallaxError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmra)) {
|
||||
_pmra = dictionary.value<glm::vec2>(KeyFilterPmra);
|
||||
_filterPmra = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmraError)) {
|
||||
_pmraError = dictionary.value<glm::vec2>(KeyFilterPmraError);
|
||||
_filterPmraError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmdec)) {
|
||||
_pmdec = dictionary.value<glm::vec2>(KeyFilterPmdec);
|
||||
_filterPmdec = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterPmdecError)) {
|
||||
_pmdecError = dictionary.value<glm::vec2>(KeyFilterPmdecError);
|
||||
_filterPmdecError = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRv)) {
|
||||
_rv = dictionary.value<glm::vec2>(KeyFilterRv);
|
||||
_filterRv = true;
|
||||
}
|
||||
if (dictionary.hasKey(KeyFilterRvError)) {
|
||||
_rvError = dictionary.value<glm::vec2>(KeyFilterRvError);
|
||||
_filterRvError = true;
|
||||
}
|
||||
}
|
||||
|
||||
ConstructOctreeTask::~ConstructOctreeTask() {}
|
||||
|
||||
std::string ConstructOctreeTask::description() {
|
||||
return "Read bin file (or files in folder): " + _inFileOrFolderPath + "\n "
|
||||
"and write octree data file (or files) into: " + _outFileOrFolderPath + "\n";
|
||||
}
|
||||
|
||||
void ConstructOctreeTask::perform(const Task::ProgressCallback& progressCallback) {
|
||||
progressCallback(0.0f);
|
||||
|
||||
if (_singleFileInput) {
|
||||
constructOctreeFromSingleFile(progressCallback);
|
||||
}
|
||||
else {
|
||||
constructOctreeFromFolder(progressCallback);
|
||||
}
|
||||
|
||||
progressCallback(1.0f);
|
||||
}
|
||||
|
||||
void ConstructOctreeTask::constructOctreeFromSingleFile(
|
||||
const Task::ProgressCallback& progressCallback) {
|
||||
std::vector<float> fullData;
|
||||
int32_t nValues = 0;
|
||||
int32_t nValuesPerStar = 0;
|
||||
size_t nFilteredStars = 0;
|
||||
int nTotalStars = 0;
|
||||
|
||||
_octreeManager->initOctree(0, _maxDist, _maxStarsPerNode);
|
||||
|
||||
LINFO("Reading data file: " + _inFileOrFolderPath);
|
||||
|
||||
LINFO(fmt::format(
|
||||
"MAX DIST: {} - MAX STARS PER NODE: {}",
|
||||
_octreeManager->maxDist(), _octreeManager->maxStarsPerNode()
|
||||
));
|
||||
|
||||
// Use to generate a synthetic dataset
|
||||
/*for (float z = -1.0; z < 1.0; z += 0.05) {
|
||||
for (float y = -1.0; y < 1.0; y += 0.05) {
|
||||
for (float x = -1.0; x < 1.0; x += 0.05) {
|
||||
float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
|
||||
std::vector<float> renderValues(8);
|
||||
renderValues[0] = x; // + x * r;
|
||||
renderValues[2] = z; // + y * r;
|
||||
renderValues[1] = y; // + z * r;
|
||||
renderValues[3] = 5.0; // + 10 * r;
|
||||
renderValues[4] = 2.0; // + 10 * r;
|
||||
renderValues[5] = r;
|
||||
renderValues[6] = r;
|
||||
renderValues[7] = r;
|
||||
_octreeManager->insert(renderValues);
|
||||
nTotalStars++;
|
||||
nValues+=8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (float phi = -180.0; phi < 180.0; phi += 10.0) {
|
||||
for (float theta = -90.0; theta <= 90.0; theta += 10.0) {
|
||||
float r = 1.0;
|
||||
std::vector<float> renderValues(8);
|
||||
renderValues[0] = r * sin(glm::radians(theta)) * cos(glm::radians(phi));
|
||||
renderValues[2] = r * sin(glm::radians(theta)) * sin(glm::radians(phi));
|
||||
renderValues[1] = r * cos(glm::radians(theta));
|
||||
renderValues[3] = 5.0;
|
||||
renderValues[4] = 2.0;
|
||||
renderValues[5] = r;
|
||||
renderValues[6] = r;
|
||||
renderValues[7] = r;
|
||||
_octreeManager->insert(renderValues);
|
||||
nTotalStars++;
|
||||
nValues += 8;
|
||||
}
|
||||
}*/
|
||||
|
||||
std::ifstream inFileStream(_inFileOrFolderPath, std::ifstream::binary);
|
||||
if (inFileStream.good()) {
|
||||
inFileStream.read(reinterpret_cast<char*>(&nValues), sizeof(int32_t));
|
||||
inFileStream.read(reinterpret_cast<char*>(&nValuesPerStar), sizeof(int32_t));
|
||||
|
||||
fullData.resize(nValues);
|
||||
inFileStream.read(
|
||||
reinterpret_cast<char*>(fullData.data()),
|
||||
nValues * sizeof(fullData[0])
|
||||
);
|
||||
nTotalStars = nValues / nValuesPerStar;
|
||||
|
||||
progressCallback(0.3f);
|
||||
LINFO("Constructing Octree.");
|
||||
|
||||
// Insert star into octree. We assume the data already is in correct order.
|
||||
for (size_t i = 0; i < fullData.size(); i += nValuesPerStar) {
|
||||
auto first = fullData.begin() + i;
|
||||
auto last = fullData.begin() + i + nValuesPerStar;
|
||||
std::vector<float> filterValues(first, last);
|
||||
std::vector<float> renderValues(first, first + RENDER_VALUES);
|
||||
|
||||
// Filter data by parameters.
|
||||
if (checkAllFilters(filterValues)) {
|
||||
nFilteredStars++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If all filters passed then insert render values into Octree.
|
||||
_octreeManager->insert(renderValues);
|
||||
}
|
||||
inFileStream.close();
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file '{}' for loading preprocessed file!",
|
||||
_inFileOrFolderPath
|
||||
));
|
||||
}
|
||||
LINFO(fmt::format("{} of {} read stars were filtered", nFilteredStars, nTotalStars));
|
||||
|
||||
// Slice LOD data before writing to files.
|
||||
_octreeManager->sliceLodData();
|
||||
|
||||
LINFO("Writing octree to: " + _outFileOrFolderPath);
|
||||
std::ofstream outFileStream(_outFileOrFolderPath, std::ofstream::binary);
|
||||
if (outFileStream.good()) {
|
||||
if (nValues == 0) {
|
||||
LERROR("Error writing file - No values were read from file.");
|
||||
}
|
||||
_octreeManager->writeToFile(outFileStream, true);
|
||||
|
||||
outFileStream.close();
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file: {} as output data file.", _outFileOrFolderPath
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void ConstructOctreeTask::constructOctreeFromFolder(
|
||||
const Task::ProgressCallback& progressCallback)
|
||||
{
|
||||
int32_t nStars = 0;
|
||||
int32_t nValuesPerStar = 0;
|
||||
size_t nFilteredStars = 0;
|
||||
//float maxRadius = 0.0;
|
||||
//int starsOutside10 = 0;
|
||||
//int starsOutside25 = 0;
|
||||
//int starsOutside50 = 0;
|
||||
//int starsOutside75 = 0;
|
||||
//int starsOutside100 = 0;
|
||||
//int starsOutside200 = 0;
|
||||
//int starsOutside300 = 0;
|
||||
//int starsOutside400 = 0;
|
||||
//int starsOutside500 = 0;
|
||||
//int starsOutside750 = 0;
|
||||
//int starsOutside1000 = 0;
|
||||
//int starsOutside1500 = 0;
|
||||
//int starsOutside2000 = 0;
|
||||
//int starsOutside5000 = 0;
|
||||
|
||||
ghoul::filesystem::Directory currentDir(_inFileOrFolderPath);
|
||||
std::vector<std::string> allInputFiles = currentDir.readFiles();
|
||||
std::vector<float> filterValues;
|
||||
auto writeThreads = std::vector<std::thread>(8);
|
||||
|
||||
_indexOctreeManager->initOctree(0, _maxDist, _maxStarsPerNode);
|
||||
|
||||
float processOneFile = 1.f / allInputFiles.size();
|
||||
|
||||
LINFO(fmt::format(
|
||||
"MAX DIST: {} - MAX STARS PER NODE: {}",
|
||||
_indexOctreeManager->maxDist(), _indexOctreeManager->maxStarsPerNode()
|
||||
));
|
||||
|
||||
for (size_t idx = 0; idx < allInputFiles.size(); ++idx) {
|
||||
std::string inFilePath = allInputFiles[idx];
|
||||
int nStarsInfile = 0;
|
||||
|
||||
LINFO("Reading data file: " + inFilePath);
|
||||
|
||||
std::ifstream inFileStream(inFilePath, std::ifstream::binary);
|
||||
if (inFileStream.good()) {
|
||||
inFileStream.read(reinterpret_cast<char*>(&nValuesPerStar), sizeof(int32_t));
|
||||
filterValues.resize(nValuesPerStar, 0.f);
|
||||
|
||||
while (inFileStream.read(
|
||||
reinterpret_cast<char*>(filterValues.data()),
|
||||
nValuesPerStar * sizeof(filterValues[0])
|
||||
))
|
||||
{
|
||||
// Filter data by parameters.
|
||||
if (checkAllFilters(filterValues)) {
|
||||
nFilteredStars++;
|
||||
continue;
|
||||
}
|
||||
// Generate a 50/12,5 dataset (gMag <=13/>13).
|
||||
//if ((filterStar(glm::vec2(20.0), filterValues[3], 20.f)) ||
|
||||
// (filterStar(glm::vec2(0.0), filterValues[16])) ||
|
||||
// (filterValues[3] > 13.0 && filterValues[17] > 0.125) ||
|
||||
// (filterValues[3] <= 13.0 && filterValues[17] > 0.5)) {
|
||||
// nFilteredStars++;
|
||||
// continue;
|
||||
//}
|
||||
|
||||
// If all filters passed then insert render values into Octree.
|
||||
std::vector<float> renderValues(
|
||||
filterValues.begin(),
|
||||
filterValues.begin() + RENDER_VALUES
|
||||
);
|
||||
|
||||
_indexOctreeManager->insert(renderValues);
|
||||
nStarsInfile++;
|
||||
|
||||
//float maxVal = fmax(fmax(fabs(renderValues[0]), fabs(renderValues[1])),
|
||||
// fabs(renderValues[2]));
|
||||
//if (maxVal > maxRadius) maxRadius = maxVal;
|
||||
//// Calculate how many stars are outside of different thresholds.
|
||||
//if (maxVal > 10) starsOutside10++;
|
||||
//if (maxVal > 25) starsOutside25++;
|
||||
//if (maxVal > 50) starsOutside50++;
|
||||
//if (maxVal > 75) starsOutside75++;
|
||||
//if (maxVal > 100) starsOutside100++;
|
||||
//if (maxVal > 200) starsOutside200++;
|
||||
//if (maxVal > 300) starsOutside300++;
|
||||
//if (maxVal > 400) starsOutside400++;
|
||||
//if (maxVal > 500) starsOutside500++;
|
||||
//if (maxVal > 750) starsOutside750++;
|
||||
//if (maxVal > 1000) starsOutside1000++;
|
||||
//if (maxVal > 1500) starsOutside1500++;
|
||||
//if (maxVal > 2000) starsOutside2000++;
|
||||
//if (maxVal > 5000) starsOutside5000++;
|
||||
}
|
||||
inFileStream.close();
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file '{}' for loading preprocessed file!", inFilePath
|
||||
));
|
||||
}
|
||||
|
||||
// Slice LOD data.
|
||||
LINFO("Slicing LOD data!");
|
||||
_indexOctreeManager->sliceLodData(idx);
|
||||
|
||||
progressCallback((idx + 1) * processOneFile);
|
||||
nStars += nStarsInfile;
|
||||
|
||||
LINFO(fmt::format("Writing {} stars to octree files!", nStarsInfile));
|
||||
LINFO(fmt::format(
|
||||
"Number leaf nodes: {}\n Number inner nodes: {}\n Total depth of tree: {}",
|
||||
_indexOctreeManager->numLeafNodes(),
|
||||
_indexOctreeManager->numInnerNodes(),
|
||||
_indexOctreeManager->totalDepth()
|
||||
));
|
||||
|
||||
// Write to 8 separate files in a separate thread. Data will be cleared after it
|
||||
// has been written. Store joinable thread for later sync.
|
||||
std::thread t(
|
||||
&OctreeManager::writeToMultipleFiles,
|
||||
_indexOctreeManager,
|
||||
_outFileOrFolderPath,
|
||||
idx
|
||||
);
|
||||
writeThreads[idx] = std::move(t);
|
||||
}
|
||||
|
||||
LINFO(fmt::format(
|
||||
"A total of {} stars were read from files and distributed into {} total nodes",
|
||||
nStars, _indexOctreeManager->totalNodes()
|
||||
));
|
||||
LINFO(std::to_string(nFilteredStars) + " stars were filtered");
|
||||
|
||||
//LINFO("Max radius of dataset is: " + std::to_string(maxRadius) +
|
||||
// "\n Number of stars outside of:" +
|
||||
// " - 10kPc is " + std::to_string(starsOutside10) + "\n" +
|
||||
// " - 25kPc is " + std::to_string(starsOutside25) + "\n" +
|
||||
// " - 50kPc is " + std::to_string(starsOutside50) + "\n" +
|
||||
// " - 75kPc is " + std::to_string(starsOutside75) + "\n" +
|
||||
// " - 100kPc is " + std::to_string(starsOutside100) + "\n" +
|
||||
// " - 200kPc is " + std::to_string(starsOutside200) + "\n" +
|
||||
// " - 300kPc is " + std::to_string(starsOutside300) + "\n" +
|
||||
// " - 400kPc is " + std::to_string(starsOutside400) + "\n" +
|
||||
// " - 500kPc is " + std::to_string(starsOutside500) + "\n" +
|
||||
// " - 750kPc is " + std::to_string(starsOutside750) + "\n" +
|
||||
// " - 1000kPc is " + std::to_string(starsOutside1000) + "\n" +
|
||||
// " - 1500kPc is " + std::to_string(starsOutside1500) + "\n" +
|
||||
// " - 2000kPc is " + std::to_string(starsOutside2000) + "\n" +
|
||||
// " - 5000kPc is " + std::to_string(starsOutside5000));
|
||||
|
||||
// Write index file of Octree structure.
|
||||
std::string indexFileOutPath = _outFileOrFolderPath + "index.bin";
|
||||
std::ofstream outFileStream(indexFileOutPath, std::ofstream::binary);
|
||||
if (outFileStream.good()) {
|
||||
LINFO("Writing index file!");
|
||||
_indexOctreeManager->writeToFile(outFileStream, false);
|
||||
|
||||
outFileStream.close();
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file: {} as index output file.", indexFileOutPath
|
||||
));
|
||||
}
|
||||
|
||||
// Make sure all threads are done.
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
writeThreads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
bool ConstructOctreeTask::checkAllFilters(const std::vector<float>& filterValues) {
|
||||
// Return true if star is caught in any filter.
|
||||
return (_filterPosX && filterStar(_posX, filterValues[0])) ||
|
||||
(_filterPosY && filterStar(_posY, filterValues[1])) ||
|
||||
(_filterPosZ && filterStar(_posZ, filterValues[2])) ||
|
||||
(_filterGMag && filterStar(_gMag, filterValues[3], 20.f)) ||
|
||||
(_filterBpRp && filterStar(_bpRp, filterValues[4])) ||
|
||||
(_filterVelX && filterStar(_velX, filterValues[5])) ||
|
||||
(_filterVelY && filterStar(_velY, filterValues[6])) ||
|
||||
(_filterVelZ && filterStar(_velZ, filterValues[7])) ||
|
||||
(_filterBpMag && filterStar(_bpMag, filterValues[8], 20.f)) ||
|
||||
(_filterRpMag && filterStar(_rpMag, filterValues[9], 20.f)) ||
|
||||
(_filterBpG && filterStar(_bpG, filterValues[10])) ||
|
||||
(_filterGRp && filterStar(_gRp, filterValues[11])) ||
|
||||
(_filterRa && filterStar(_ra, filterValues[12])) ||
|
||||
(_filterRaError && filterStar(_raError, filterValues[13])) ||
|
||||
(_filterDec && filterStar(_dec, filterValues[14])) ||
|
||||
(_filterDecError && filterStar(_decError, filterValues[15])) ||
|
||||
(_filterParallax && filterStar(_parallax, filterValues[16])) ||
|
||||
(_filterParallaxError && filterStar(_parallaxError, filterValues[17])) ||
|
||||
(_filterPmra && filterStar(_pmra, filterValues[18])) ||
|
||||
(_filterPmraError && filterStar(_pmraError, filterValues[19])) ||
|
||||
(_filterPmdec && filterStar(_pmdec, filterValues[20])) ||
|
||||
(_filterPmdecError && filterStar(_pmdecError, filterValues[21])) ||
|
||||
(_filterRv && filterStar(_rv, filterValues[22])) ||
|
||||
(_filterRvError && filterStar(_rvError, filterValues[23]));
|
||||
}
|
||||
|
||||
bool ConstructOctreeTask::filterStar(const glm::vec2& range, float filterValue,
|
||||
float normValue)
|
||||
{
|
||||
// Return true if star should be filtered away, i.e. if min = max = filterValue or
|
||||
// if filterValue < min (when min != 0.0) or filterValue > max (when max != 0.0).
|
||||
return (fabs(range.x - range.y) < FLT_EPSILON &&
|
||||
fabs(range.x - filterValue) < FLT_EPSILON) ||
|
||||
(fabs(range.x - normValue) > FLT_EPSILON && filterValue < range.x) ||
|
||||
(fabs(range.y - normValue) > FLT_EPSILON && filterValue > range.y);
|
||||
}
|
||||
|
||||
documentation::Documentation ConstructOctreeTask::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ConstructOctreeTask",
|
||||
"gaiamission_constructoctreefrombin",
|
||||
{
|
||||
{
|
||||
"Type",
|
||||
new StringEqualVerifier("ConstructOctreeTask"),
|
||||
Optional::No
|
||||
},
|
||||
{
|
||||
KeyInFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileInput is set to true then this specifies the path to a "
|
||||
"single BIN file containing a full dataset. Otherwise this specifies the "
|
||||
"path to a folder with multiple BIN files containing subsets of sorted "
|
||||
"star data.",
|
||||
},
|
||||
{
|
||||
KeyOutFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileInput is set to true then this specifies the output file "
|
||||
"name (including full path). Otherwise this specifies the path to the "
|
||||
"folder which to save all files.",
|
||||
},
|
||||
{
|
||||
KeyMaxDist,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"If set it determines what MAX_DIST to use when creating Octree."
|
||||
},
|
||||
{
|
||||
KeyMaxStarsPerNode,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"If set it determines what MAX_STAR_PER_NODE to use when creating Octree."
|
||||
},
|
||||
{
|
||||
KeySingleFileInput,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If true then task will read from a single file and output a single "
|
||||
"binary file with the full Octree. If false then task will read all "
|
||||
"files in specified folder and output multiple files for the Octree."
|
||||
},
|
||||
{
|
||||
KeyFilterPosX,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Position X values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPosY,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Position Y values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPosZ,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Position Z values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterGMag,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with G mean magnitude values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 20.0 it is "
|
||||
"read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away. Default "
|
||||
"GMag = 20.0 if no value existed."
|
||||
},
|
||||
{
|
||||
KeyFilterBpRp,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Bp-Rp color values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterVelX,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Velocity X values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterVelY,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Velocity Y values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterVelZ,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Velocity Z values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterBpMag,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Bp mean magnitude values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 20.0 it is "
|
||||
"read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away. Default "
|
||||
"BpMag = 20.0 if no value existed."
|
||||
},
|
||||
{
|
||||
KeyFilterRpMag,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Rp mean magnitude values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 20.0 it is "
|
||||
"read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away. Default RpMag = "
|
||||
"20.0 if no value existed."
|
||||
},
|
||||
{
|
||||
KeyFilterBpG,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Bp-G color values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterGRp,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with G-Rp color values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRa,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with RA values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRaError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with RA Error values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterDec,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with DEC values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterDecError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with DEC Error values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterParallax,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Parallax values between [min, max] "
|
||||
"will be inserted into Octree (if min is set to 0.0 it is read as -Inf, "
|
||||
"if max is set to 0.0 it is read as +Inf). If min = max then all values "
|
||||
"equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterParallaxError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Parallax Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmra,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion RA values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmraError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion RA Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmdec,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion DEC values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterPmdecError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Proper Motion DEC Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRv,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Radial Velocity values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
{
|
||||
KeyFilterRvError,
|
||||
new Vector2Verifier<double>,
|
||||
Optional::Yes,
|
||||
"If defined then only stars with Radial Velocity Error values between "
|
||||
"[min, max] will be inserted into Octree (if min is set to 0.0 it is "
|
||||
"read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max "
|
||||
"then all values equal min|max will be filtered away."
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
143
modules/gaia/tasks/constructoctreetask.h
Normal file
143
modules/gaia/tasks/constructoctreetask.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___CONSTRUCTOCTREETASK___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___CONSTRUCTOCTREETASK___H__
|
||||
|
||||
#include <openspace/util/task.h>
|
||||
|
||||
#include <modules/gaia/rendering/octreeculler.h>
|
||||
#include <modules/gaia/rendering/octreemanager.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class ConstructOctreeTask : public Task {
|
||||
public:
|
||||
ConstructOctreeTask(const ghoul::Dictionary& dictionary);
|
||||
virtual ~ConstructOctreeTask();
|
||||
|
||||
std::string description() override;
|
||||
void perform(const Task::ProgressCallback& onProgress) override;
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
const int RENDER_VALUES = 8;
|
||||
|
||||
/**
|
||||
* Reads a single binary file with preprocessed star data and insert the render values
|
||||
* into an octree structure (if star data passed all defined filters).
|
||||
* Stores the entire octree in one binary file.
|
||||
*/
|
||||
void constructOctreeFromSingleFile(const Task::ProgressCallback& progressCallback);
|
||||
|
||||
/**
|
||||
* Reads binary star data from 8 preprocessed files (one per branch) in specified
|
||||
* folder, prepared by ReadFitsTask, and inserts star render data into an octree
|
||||
* (if star data passed all defined filters).
|
||||
* Stores octree structure in a binary index file and stores all render data
|
||||
* separate files, one file per node in the octree.
|
||||
*/
|
||||
void constructOctreeFromFolder(const Task::ProgressCallback& progressCallback);
|
||||
|
||||
/**
|
||||
* Checks all defined filter ranges and \returns true if any of the corresponding
|
||||
* <code>filterValues</code> are outside of the defined range.
|
||||
* \returns false if value should be inserted into Octree.
|
||||
* \param filterValues are all read filter values in binary file.
|
||||
*/
|
||||
bool checkAllFilters(const std::vector<float>& filterValues);
|
||||
|
||||
/**
|
||||
* \returns true if star should be filtered away and false if all filters passed.
|
||||
* \param range contains ]min, max[ and \param filterValue corresponding value in
|
||||
* star. Star is filtered either if min = max = filterValue or if filterValue < min
|
||||
* (when min != 0.0) or filterValue > max (when max != 0.0).
|
||||
*/
|
||||
bool filterStar(const glm::vec2& range, float filterValue, float normValue = 0.f);
|
||||
|
||||
std::string _inFileOrFolderPath;
|
||||
std::string _outFileOrFolderPath;
|
||||
int _maxDist = 0;
|
||||
int _maxStarsPerNode = 0;
|
||||
bool _singleFileInput = false;
|
||||
|
||||
std::shared_ptr<OctreeManager> _octreeManager;
|
||||
std::shared_ptr<OctreeManager> _indexOctreeManager;
|
||||
|
||||
// Filter params
|
||||
glm::vec2 _posX = glm::vec2(0.f);
|
||||
bool _filterPosX = false;
|
||||
glm::vec2 _posY = glm::vec2(0.f);
|
||||
bool _filterPosY = false;
|
||||
glm::vec2 _posZ = glm::vec2(0.f);
|
||||
bool _filterPosZ = false;
|
||||
glm::vec2 _gMag = glm::vec2(0.f);
|
||||
bool _filterGMag = false;
|
||||
glm::vec2 _bpRp = glm::vec2(0.f);
|
||||
bool _filterBpRp = false;
|
||||
glm::vec2 _velX = glm::vec2(0.f);
|
||||
bool _filterVelX = false;
|
||||
glm::vec2 _velY = glm::vec2(0.f);
|
||||
bool _filterVelY = false;
|
||||
glm::vec2 _velZ = glm::vec2(0.f);
|
||||
bool _filterVelZ = false;
|
||||
glm::vec2 _bpMag = glm::vec2(0.f);
|
||||
bool _filterBpMag = false;
|
||||
glm::vec2 _rpMag = glm::vec2(0.f);
|
||||
bool _filterRpMag = false;
|
||||
glm::vec2 _bpG = glm::vec2(0.f);
|
||||
bool _filterBpG = false;
|
||||
glm::vec2 _gRp = glm::vec2(0.f);
|
||||
bool _filterGRp = false;
|
||||
glm::vec2 _ra = glm::vec2(0.f);
|
||||
bool _filterRa = false;
|
||||
glm::vec2 _raError = glm::vec2(0.f);
|
||||
bool _filterRaError = false;
|
||||
glm::vec2 _dec = glm::vec2(0.f);
|
||||
bool _filterDec = false;
|
||||
glm::vec2 _decError = glm::vec2(0.f);
|
||||
bool _filterDecError = false;
|
||||
glm::vec2 _parallax = glm::vec2(0.f);
|
||||
bool _filterParallax = false;
|
||||
glm::vec2 _parallaxError = glm::vec2(0.f);
|
||||
bool _filterParallaxError = false;
|
||||
glm::vec2 _pmra = glm::vec2(0.f);
|
||||
bool _filterPmra = false;
|
||||
glm::vec2 _pmraError = glm::vec2(0.f);
|
||||
bool _filterPmraError = false;
|
||||
glm::vec2 _pmdec = glm::vec2(0.f);
|
||||
bool _filterPmdec = false;
|
||||
glm::vec2 _pmdecError = glm::vec2(0.f);
|
||||
bool _filterPmdecError = false;
|
||||
glm::vec2 _rv = glm::vec2(0.f);
|
||||
bool _filterRv = false;
|
||||
glm::vec2 _rvError = glm::vec2(0.f);
|
||||
bool _filterRvError = false;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___CONSTRUCTOCTREETASK___H__
|
||||
265
modules/gaia/tasks/readfilejob.cpp
Normal file
265
modules/gaia/tasks/readfilejob.cpp
Normal file
@@ -0,0 +1,265 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/gaia/tasks/readfilejob.h>
|
||||
|
||||
#include <openspace/util/distanceconversion.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/fmt.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "ReadFileJob";
|
||||
}
|
||||
|
||||
namespace openspace::gaia {
|
||||
|
||||
ReadFileJob::ReadFileJob(const std::string& filePath,
|
||||
const std::vector<std::string>& allColumns, int firstRow,
|
||||
int lastRow, size_t nDefaultCols, int nValuesPerStar,
|
||||
std::shared_ptr<FitsFileReader> fitsReader)
|
||||
: _inFilePath(filePath)
|
||||
, _allColumns(allColumns)
|
||||
, _firstRow(firstRow)
|
||||
, _lastRow(lastRow)
|
||||
, _nDefaultCols(nDefaultCols)
|
||||
, _nValuesPerStar(nValuesPerStar)
|
||||
, _fitsFileReader(fitsReader)
|
||||
, _octants(8)
|
||||
{}
|
||||
|
||||
void ReadFileJob::execute() {
|
||||
// Read columns from FITS file. If rows aren't specified then full table will be read.
|
||||
std::shared_ptr<TableData<float>> table = _fitsFileReader->readTable<float>(
|
||||
_inFilePath,
|
||||
_allColumns,
|
||||
_firstRow,
|
||||
_lastRow
|
||||
);
|
||||
|
||||
if (!table) {
|
||||
throw ghoul::RuntimeError(
|
||||
fmt::format("Failed to open Fits file '{}'", _inFilePath
|
||||
));
|
||||
}
|
||||
|
||||
int nStars = table->readRows - _firstRow + 1;
|
||||
|
||||
int nNullArr = 0;
|
||||
size_t nColumnsRead = _allColumns.size();
|
||||
if (nColumnsRead != _nDefaultCols) {
|
||||
LINFO("Additional columns will be read! Consider add column in code for "
|
||||
"significant speedup!");
|
||||
}
|
||||
|
||||
// Copy columns to local variables.
|
||||
std::unordered_map<std::string, std::vector<float>>& tableContent = table->contents;
|
||||
|
||||
// Default columns parameters.
|
||||
//std::vector<float> l_longitude = std::move(tableContent[_allColumns[0]]);
|
||||
//std::vector<float> b_latitude = std::move(tableContent[_allColumns[1]]);
|
||||
std::vector<float> ra = std::move(tableContent[_allColumns[0]]);
|
||||
std::vector<float> ra_err = std::move(tableContent[_allColumns[1]]);
|
||||
std::vector<float> dec = std::move(tableContent[_allColumns[2]]);
|
||||
std::vector<float> dec_err = std::move(tableContent[_allColumns[3]]);
|
||||
std::vector<float> parallax = std::move(tableContent[_allColumns[4]]);
|
||||
std::vector<float> parallax_err = std::move(tableContent[_allColumns[5]]);
|
||||
std::vector<float> pmra = std::move(tableContent[_allColumns[6]]);
|
||||
std::vector<float> pmra_err = std::move(tableContent[_allColumns[7]]);
|
||||
std::vector<float> pmdec = std::move(tableContent[_allColumns[8]]);
|
||||
std::vector<float> pmdec_err = std::move(tableContent[_allColumns[9]]);
|
||||
std::vector<float> meanMagG = std::move(tableContent[_allColumns[10]]);
|
||||
std::vector<float> meanMagBp = std::move(tableContent[_allColumns[11]]);
|
||||
std::vector<float> meanMagRp = std::move(tableContent[_allColumns[12]]);
|
||||
std::vector<float> bp_rp = std::move(tableContent[_allColumns[13]]);
|
||||
std::vector<float> bp_g = std::move(tableContent[_allColumns[14]]);
|
||||
std::vector<float> g_rp = std::move(tableContent[_allColumns[15]]);
|
||||
std::vector<float> radial_vel = std::move(tableContent[_allColumns[16]]);
|
||||
std::vector<float> radial_vel_err = std::move(tableContent[_allColumns[17]]);
|
||||
|
||||
|
||||
// Construct data array. OBS: ORDERING IS IMPORTANT! This is where slicing happens.
|
||||
for (int i = 0; i < nStars; ++i) {
|
||||
std::vector<float> values(_nValuesPerStar);
|
||||
size_t idx = 0;
|
||||
|
||||
// Default order for rendering:
|
||||
// Position [X, Y, Z]
|
||||
// Mean G-band Magnitude
|
||||
// -- Mean Bp-band Magnitude
|
||||
// -- Mean Rp-band Magnitude
|
||||
// Bp-Rp Color
|
||||
// -- Bp-G Color
|
||||
// -- G-Rp Color
|
||||
// Velocity [X, Y, Z]
|
||||
|
||||
// Return early if star doesn't have a measured position.
|
||||
if (std::isnan(ra[i]) || std::isnan(dec[i])) {
|
||||
nNullArr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store positions. Set to a default distance if parallax doesn't exist.
|
||||
float radiusInKiloParsec = 9.0;
|
||||
if (!std::isnan(parallax[i])) {
|
||||
// Parallax is in milliArcseconds -> distance in kiloParsecs
|
||||
// https://gea.esac.esa.int/archive/documentation/GDR2/Gaia_archive/
|
||||
// chap_datamodel/sec_dm_main_tables/ssec_dm_gaia_source.html
|
||||
//LINFO("Parallax: " + std::to_string(parallax[i]));
|
||||
radiusInKiloParsec = 1.0 / parallax[i];
|
||||
}
|
||||
/*// Convert to Galactic Coordinates from Galactic Lon & Lat.
|
||||
// https://gea.esac.esa.int/archive/documentation/GDR2/Data_processing/
|
||||
// chap_cu3ast/sec_cu3ast_intro/ssec_cu3ast_intro_tansforms.html#SSS1
|
||||
values[idx++] = radiusInKiloParsec * cos(glm::radians(b_latitude[i])) *
|
||||
cos(glm::radians(l_longitude[i])); // Pos X
|
||||
values[idx++] = radiusInKiloParsec * cos(glm::radians(b_latitude[i])) *
|
||||
sin(glm::radians(l_longitude[i])); // Pos Y
|
||||
values[idx++] = radiusInKiloParsec * sin(glm::radians(b_latitude[i])); // Pos Z
|
||||
*/
|
||||
|
||||
// Convert ICRS Equatorial Ra and Dec to Galactic latitude and longitude.
|
||||
glm::mat3 aPrimG = glm::mat3(
|
||||
// Col 0
|
||||
glm::vec3(-0.0548755604162154, 0.4941094278755837, -0.8676661490190047),
|
||||
// Col 1
|
||||
glm::vec3(-0.8734370902348850, -0.4448296299600112, -0.1980763734312015),
|
||||
// Col 2
|
||||
glm::vec3(-0.4838350155487132, 0.7469822444972189, 0.4559837761750669)
|
||||
);
|
||||
glm::vec3 rICRS = glm::vec3(
|
||||
cos(glm::radians(ra[i])) * cos(glm::radians(dec[i])),
|
||||
sin(glm::radians(ra[i])) * cos(glm::radians(dec[i])),
|
||||
sin(glm::radians(dec[i]))
|
||||
);
|
||||
glm::vec3 rGal = aPrimG * rICRS;
|
||||
values[idx++] = radiusInKiloParsec * rGal.x; // Pos X
|
||||
values[idx++] = radiusInKiloParsec * rGal.y; // Pos Y
|
||||
values[idx++] = radiusInKiloParsec * rGal.z; // Pos Z
|
||||
|
||||
/*if (abs(rGal.x - values[0]) > 1e-5 || abs(rGal.y - values[1]) > 1e-5 ||
|
||||
abs(rGal.z - values[2]) > 1e-5) {
|
||||
LINFO("rGal: " + std::to_string(rGal) +
|
||||
" - LB: [" + std::to_string(values[0]) + ", " + std::to_string(values[1]) +
|
||||
", " + std::to_string(values[2]) + "]");
|
||||
}*/
|
||||
|
||||
// Store magnitude render value. (Set default to high mag = low brightness)
|
||||
values[idx++] = std::isnan(meanMagG[i]) ? 20.f : meanMagG[i]; // Mean G-band Mag
|
||||
|
||||
// Store color render value. (Default value is bluish stars)
|
||||
values[idx++] = std::isnan(bp_rp[i]) ? 0.f : bp_rp[i]; // Bp-Rp Color
|
||||
|
||||
|
||||
// Store velocity.
|
||||
if (std::isnan(pmra[i])) {
|
||||
pmra[i] = 0.f;
|
||||
}
|
||||
if (std::isnan(pmdec[i])) {
|
||||
pmdec[i] = 0.f;
|
||||
}
|
||||
|
||||
// Convert Proper Motion from ICRS [Ra,Dec] to Galactic Tanget Vector [l,b].
|
||||
glm::vec3 uICRS = glm::vec3(
|
||||
-sin(glm::radians(ra[i])) * pmra[i] -
|
||||
cos(glm::radians(ra[i])) * sin(glm::radians(dec[i])) * pmdec[i],
|
||||
cos(glm::radians(ra[i])) * pmra[i] -
|
||||
sin(glm::radians(ra[i])) * sin(glm::radians(dec[i])) * pmdec[i],
|
||||
cos(glm::radians(dec[i])) * pmdec[i]
|
||||
);
|
||||
glm::vec3 pmVecGal = aPrimG * uICRS;
|
||||
|
||||
// Convert to Tangential vector [m/s] from Proper Motion vector [mas/yr]
|
||||
float tanVelX = 1000.0 * 4.74 * radiusInKiloParsec * pmVecGal.x;
|
||||
float tanVelY = 1000.0 * 4.74 * radiusInKiloParsec * pmVecGal.y;
|
||||
float tanVelZ = 1000.0 * 4.74 * radiusInKiloParsec * pmVecGal.z;
|
||||
|
||||
// Calculate True Space Velocity [m/s] if we have the radial velocity
|
||||
if (!std::isnan(radial_vel[i])) {
|
||||
// Calculate Radial Velocity in the direction of the star.
|
||||
// radial_vel is given in [km/s] -> convert to [m/s].
|
||||
float radVelX = 1000.0 * radial_vel[i] * rGal.x;
|
||||
float radVelY = 1000.0 * radial_vel[i] * rGal.y;
|
||||
float radVelZ = 1000.0 * radial_vel[i] * rGal.z;
|
||||
|
||||
// Use Pythagoras theorem for the final Space Velocity [m/s].
|
||||
values[idx++] = sqrt(pow(radVelX, 2) + pow(tanVelX, 2)); // Vel X [U]
|
||||
values[idx++] = sqrt(pow(radVelY, 2) + pow(tanVelY, 2)); // Vel Y [V]
|
||||
values[idx++] = sqrt(pow(radVelZ, 2) + pow(tanVelZ, 2)); // Vel Z [W]
|
||||
}
|
||||
// Otherwise use the vector [m/s] we got from proper motion.
|
||||
else {
|
||||
radial_vel[i] = 0.f;
|
||||
values[idx++] = tanVelX; // Vel X [U]
|
||||
values[idx++] = tanVelY; // Vel Y [V]
|
||||
values[idx++] = tanVelZ; // Vel Z [W]
|
||||
}
|
||||
|
||||
// Store additional parameters to filter by.
|
||||
values[idx++] = std::isnan(meanMagBp[i]) ? 20.f : meanMagBp[i];
|
||||
values[idx++] = std::isnan(meanMagRp[i]) ? 20.f : meanMagRp[i];
|
||||
values[idx++] = std::isnan(bp_g[i]) ? 0.f : bp_g[i];
|
||||
values[idx++] = std::isnan(g_rp[i]) ? 0.f : g_rp[i];
|
||||
values[idx++] = ra[i];
|
||||
values[idx++] = std::isnan(ra_err[i]) ? 0.f : ra_err[i];
|
||||
values[idx++] = dec[i];
|
||||
values[idx++] = std::isnan(dec_err[i]) ? 0.f : dec_err[i];
|
||||
values[idx++] = std::isnan(parallax[i]) ? 0.f : parallax[i];
|
||||
values[idx++] = std::isnan(parallax_err[i]) ? 0.f : parallax_err[i];
|
||||
values[idx++] = pmra[i];
|
||||
values[idx++] = std::isnan(pmra_err[i]) ? 0.f : pmra_err[i];
|
||||
values[idx++] = pmdec[i];
|
||||
values[idx++] = std::isnan(pmdec_err[i]) ? 0.f : pmdec_err[i];
|
||||
values[idx++] = radial_vel[i];
|
||||
values[idx++] = std::isnan(radial_vel_err[i]) ? 0.f : radial_vel_err[i];
|
||||
|
||||
// Read extra columns, if any. This will slow down the sorting tremendously!
|
||||
for (size_t col = _nDefaultCols; col < nColumnsRead; ++col) {
|
||||
std::vector<float> vecData = std::move(tableContent[_allColumns[col]]);
|
||||
values[idx++] = std::isnan(vecData[col]) ? 0.f : vecData[col];
|
||||
}
|
||||
|
||||
size_t index = 0;
|
||||
if (values[0] < 0.0) {
|
||||
index += 1;
|
||||
}
|
||||
if (values[1] < 0.0) {
|
||||
index += 2;
|
||||
}
|
||||
if (values[2] < 0.0) {
|
||||
index += 4;
|
||||
}
|
||||
|
||||
_octants[index].insert(_octants[index].end(), values.begin(), values.end());
|
||||
}
|
||||
|
||||
/*LINFO(std::to_string(nNullArr) + " out of " +
|
||||
std::to_string(nStars) + " read stars were nullArrays.");*/
|
||||
}
|
||||
|
||||
std::vector<std::vector<float>> ReadFileJob::product() {
|
||||
return _octants;
|
||||
}
|
||||
|
||||
} // namespace openspace::gaiamission
|
||||
71
modules/gaia/tasks/readfilejob.h
Normal file
71
modules/gaia/tasks/readfilejob.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___READFILEJOB___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___READFILEJOB___H__
|
||||
|
||||
#include <openspace/util/concurrentjobmanager.h>
|
||||
|
||||
#include <modules/fitsfilereader/include/fitsfilereader.h>
|
||||
|
||||
namespace openspace::gaia {
|
||||
|
||||
struct ReadFileJob : public Job<std::vector<std::vector<float>>> {
|
||||
/**
|
||||
* Constructs a Job that will read a single FITS file in a concurrent thread and
|
||||
* divide the star data into 8 octants depending on position.
|
||||
* \param allColumns define which columns that will be read, it should correspond
|
||||
* to the pre-defined order in the job. If additional columns are defined they will
|
||||
* be read but slow down the process.
|
||||
* Proper conversions of positions and velocities will take place and all values
|
||||
* will be checked for NaNs.
|
||||
* If \param firstRow is < 1 then reading will begin at first row in table.
|
||||
* If \param lastRow < firstRow then entire table will be read.
|
||||
* \param nValuesPerStar defines how many values that will be stored per star.
|
||||
*/
|
||||
ReadFileJob(const std::string& filePath, const std::vector<std::string>& allColumns,
|
||||
int firstRow, int lastRow, size_t nDefaultCols, int nValuesPerStar,
|
||||
std::shared_ptr<FitsFileReader> fitsReader);
|
||||
|
||||
~ReadFileJob() = default;
|
||||
|
||||
void execute() override;
|
||||
|
||||
std::vector<std::vector<float>> product() override;
|
||||
|
||||
private:
|
||||
std::string _inFilePath;
|
||||
int _firstRow;
|
||||
int _lastRow;
|
||||
size_t _nDefaultCols;
|
||||
int _nValuesPerStar;
|
||||
std::vector<std::string> _allColumns;
|
||||
|
||||
std::shared_ptr<FitsFileReader> _fitsFileReader;
|
||||
std::vector<std::vector<float>> _octants;
|
||||
};
|
||||
|
||||
} // namespace openspace::gaiamission
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___READFILEJOB___H__
|
||||
392
modules/gaia/tasks/readfitstask.cpp
Normal file
392
modules/gaia/tasks/readfitstask.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/gaia/tasks/readfitstask.h>
|
||||
|
||||
#include <modules/gaia/tasks/readfilejob.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/filesystem/directory.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/fmt.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath";
|
||||
constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath";
|
||||
constexpr const char* KeySingleFileProcess = "SingleFileProcess";
|
||||
constexpr const char* KeyThreadsToUse = "ThreadsToUse";
|
||||
constexpr const char* KeyFirstRow = "FirstRow";
|
||||
constexpr const char* KeyLastRow = "LastRow";
|
||||
constexpr const char* KeyFilterColumnNames = "FilterColumnNames";
|
||||
|
||||
constexpr const char* _loggerCat = "ReadFitsTask";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ReadFitsTask::ReadFitsTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"ReadFitsTask"
|
||||
);
|
||||
|
||||
_inFileOrFolderPath = absPath(dictionary.value<std::string>(KeyInFileOrFolderPath));
|
||||
_outFileOrFolderPath = absPath(dictionary.value<std::string>(KeyOutFileOrFolderPath));
|
||||
|
||||
if (dictionary.hasKey(KeySingleFileProcess)) {
|
||||
_singleFileProcess = dictionary.value<bool>(KeySingleFileProcess);
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyThreadsToUse)) {
|
||||
_threadsToUse = static_cast<size_t>(dictionary.value<double>(KeyThreadsToUse));
|
||||
if (_threadsToUse < 1) {
|
||||
LINFO(fmt::format(
|
||||
"User defined ThreadsToUse was: {}. Will be set to 1", _threadsToUse
|
||||
));
|
||||
_threadsToUse = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyFirstRow)) {
|
||||
_firstRow = static_cast<int>(dictionary.value<double>(KeyFirstRow));
|
||||
}
|
||||
|
||||
if (dictionary.hasKey(KeyLastRow)) {
|
||||
_lastRow = static_cast<int>(dictionary.value<double>(KeyLastRow));
|
||||
}
|
||||
|
||||
|
||||
if (dictionary.hasKey(KeyFilterColumnNames)) {
|
||||
ghoul::Dictionary d = dictionary.value<ghoul::Dictionary>(KeyFilterColumnNames);
|
||||
|
||||
// Ugly fix for ASCII sorting when there are more columns read than 10.
|
||||
std::set<int> intKeys;
|
||||
for (const std::string& key : d.keys()) {
|
||||
intKeys.insert(std::stoi(key));
|
||||
}
|
||||
|
||||
for (int key : intKeys) {
|
||||
_filterColumnNames.push_back(d.value<std::string>(std::to_string(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ReadFitsTask::description() {
|
||||
return fmt::format(
|
||||
"Read the specified fits file (or all fits files in specified folder): {}\n and "
|
||||
"write raw star data into: {}\nAll columns required for default rendering and "
|
||||
"filtering parameters will always be read but user can define additional filter "
|
||||
"columns to read.", _inFileOrFolderPath, _outFileOrFolderPath
|
||||
);
|
||||
}
|
||||
|
||||
void ReadFitsTask::perform(const Task::ProgressCallback& progressCallback) {
|
||||
progressCallback(0.f);
|
||||
|
||||
if (_singleFileProcess) {
|
||||
readSingleFitsFile(progressCallback);
|
||||
}
|
||||
else {
|
||||
readAllFitsFilesFromFolder(progressCallback);
|
||||
}
|
||||
|
||||
progressCallback(1.f);
|
||||
}
|
||||
|
||||
void ReadFitsTask::readSingleFitsFile(const Task::ProgressCallback& progressCallback) {
|
||||
int32_t nValuesPerStar = 0;
|
||||
|
||||
FitsFileReader fileReader(false);
|
||||
std::vector<float> fullData = fileReader.readFitsFile(
|
||||
_inFileOrFolderPath,
|
||||
nValuesPerStar,
|
||||
_firstRow,
|
||||
_lastRow,
|
||||
_filterColumnNames
|
||||
);
|
||||
|
||||
progressCallback(0.8f);
|
||||
|
||||
std::ofstream outFileStream(_outFileOrFolderPath, std::ofstream::binary);
|
||||
if (outFileStream.good()) {
|
||||
int32_t nValues = static_cast<int32_t>(fullData.size());
|
||||
LINFO(fmt::format("Writing {} values to file {}", nValues, _outFileOrFolderPath));
|
||||
LINFO("Number of values per star: " + std::to_string(nValuesPerStar));
|
||||
|
||||
if (nValues == 0) {
|
||||
LERROR("Error writing file - No values were read from file.");
|
||||
}
|
||||
outFileStream.write(
|
||||
reinterpret_cast<const char*>(&nValues),
|
||||
sizeof(int32_t)
|
||||
);
|
||||
outFileStream.write(
|
||||
reinterpret_cast<const char*>(&nValuesPerStar),
|
||||
sizeof(int32_t)
|
||||
);
|
||||
|
||||
size_t nBytes = nValues * sizeof(fullData[0]);
|
||||
outFileStream.write(reinterpret_cast<const char*>(fullData.data()), nBytes);
|
||||
|
||||
outFileStream.close();
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file: {} as output data file.", _outFileOrFolderPath
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void ReadFitsTask::readAllFitsFilesFromFolder(const Task::ProgressCallback&) {
|
||||
std::vector<std::vector<float>> octants(8);
|
||||
std::vector<bool> isFirstWrite(8, true);
|
||||
size_t finishedJobs = 0;
|
||||
int totalStars = 0;
|
||||
|
||||
_firstRow = std::max(_firstRow, 1);
|
||||
|
||||
// Create Threadpool and JobManager.
|
||||
LINFO("Threads in pool: " + std::to_string(_threadsToUse));
|
||||
ThreadPool threadPool(_threadsToUse);
|
||||
ConcurrentJobManager<std::vector<std::vector<float>>> jobManager(threadPool);
|
||||
|
||||
// Get all files in specified folder.
|
||||
ghoul::filesystem::Directory currentDir(_inFileOrFolderPath);
|
||||
std::vector<std::string> allInputFiles = currentDir.readFiles();
|
||||
size_t nInputFiles = allInputFiles.size();
|
||||
LINFO("Files to read: " + std::to_string(nInputFiles));
|
||||
|
||||
// Define what columns to read.
|
||||
_allColumnNames.clear();
|
||||
// Read in the order of table in file.
|
||||
std::vector<std::string> defaultColumnNames = {
|
||||
"ra",
|
||||
"ra_error",
|
||||
"dec",
|
||||
"dec_error",
|
||||
"parallax",
|
||||
"parallax_error",
|
||||
"pmra",
|
||||
"pmra_error",
|
||||
"pmdec",
|
||||
"pmdec_error",
|
||||
"phot_g_mean_mag",
|
||||
"phot_bp_mean_mag",
|
||||
"phot_rp_mean_mag",
|
||||
"bp_rp",
|
||||
"bp_g",
|
||||
"g_rp",
|
||||
"radial_velocity",
|
||||
"radial_velocity_error",
|
||||
};
|
||||
_allColumnNames.insert(
|
||||
_allColumnNames.end(),
|
||||
defaultColumnNames.begin(),
|
||||
defaultColumnNames.end()
|
||||
);
|
||||
// Append additional filter parameters to default rendering parameters.
|
||||
_allColumnNames.insert(
|
||||
_allColumnNames.end(),
|
||||
_filterColumnNames.begin(),
|
||||
_filterColumnNames.end()
|
||||
);
|
||||
|
||||
std::string allNames = "Columns to read: \n";
|
||||
for (const std::string& colName : _allColumnNames) {
|
||||
allNames += colName + "\n";
|
||||
}
|
||||
LINFO(allNames);
|
||||
|
||||
// Declare how many values to save for each star.
|
||||
int32_t nValuesPerStar = 24;
|
||||
size_t nDefaultColumns = defaultColumnNames.size();
|
||||
auto fitsFileReader = std::make_shared<FitsFileReader>(false);
|
||||
|
||||
// Divide all files into ReadFilejobs and then delegate them onto several threads!
|
||||
while (!allInputFiles.empty()) {
|
||||
std::string fileToRead = allInputFiles.back();
|
||||
allInputFiles.erase(allInputFiles.end() - 1);
|
||||
|
||||
// Add reading of file to jobmanager, which will distribute it to our threadpool.
|
||||
auto readFileJob = std::make_shared<gaia::ReadFileJob>(
|
||||
fileToRead,
|
||||
_allColumnNames,
|
||||
_firstRow,
|
||||
_lastRow,
|
||||
nDefaultColumns,
|
||||
nValuesPerStar,
|
||||
fitsFileReader
|
||||
);
|
||||
jobManager.enqueueJob(readFileJob);
|
||||
}
|
||||
|
||||
LINFO("All files added to queue!");
|
||||
|
||||
// Check for finished jobs.
|
||||
while (finishedJobs < nInputFiles) {
|
||||
if (jobManager.numFinishedJobs() > 0) {
|
||||
std::vector<std::vector<float>> newOctant =
|
||||
jobManager.popFinishedJob()->product();
|
||||
|
||||
finishedJobs++;
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
// Add read values to global octant and check if it's time to write!
|
||||
octants[i].insert(
|
||||
octants[i].end(),
|
||||
newOctant[i].begin(),
|
||||
newOctant[i].end()
|
||||
);
|
||||
if ((octants[i].size() > MAX_SIZE_BEFORE_WRITE) ||
|
||||
(finishedJobs == nInputFiles))
|
||||
{
|
||||
// Write to file!
|
||||
totalStars += writeOctantToFile(
|
||||
octants[i],
|
||||
i,
|
||||
isFirstWrite,
|
||||
nValuesPerStar
|
||||
);
|
||||
|
||||
octants[i].clear();
|
||||
octants[i].shrink_to_fit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LINFO(fmt::format("A total of {} stars were written to binary files.", totalStars));
|
||||
}
|
||||
|
||||
int ReadFitsTask::writeOctantToFile(const std::vector<float>& octantData, int index,
|
||||
std::vector<bool>& isFirstWrite, int nValuesPerStar)
|
||||
{
|
||||
std::string outPath = fmt::format("{}octant_{}.bin", _outFileOrFolderPath, index);
|
||||
std::ofstream fileStream(outPath, std::ofstream::binary | std::ofstream::app);
|
||||
if (fileStream.good()) {
|
||||
int32_t nValues = static_cast<int32_t>(octantData.size());
|
||||
LINFO("Write " + std::to_string(nValues) + " values to " + outPath);
|
||||
|
||||
if (nValues == 0) {
|
||||
LERROR("Error writing file - No values were read from file.");
|
||||
}
|
||||
// If this is the first write then write number of values per star!
|
||||
if (isFirstWrite[index]) {
|
||||
LINFO("First write for Octant_" + std::to_string(index));
|
||||
fileStream.write(
|
||||
reinterpret_cast<const char*>(&nValuesPerStar),
|
||||
sizeof(int32_t)
|
||||
);
|
||||
isFirstWrite[index] = false;
|
||||
}
|
||||
|
||||
size_t nBytes = nValues * sizeof(octantData[0]);
|
||||
fileStream.write(reinterpret_cast<const char*>(octantData.data()), nBytes);
|
||||
|
||||
fileStream.close();
|
||||
|
||||
// Return number of stars written.
|
||||
return nValues / nValuesPerStar;
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format("Error opening file: {} as output data file.", outPath));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
documentation::Documentation ReadFitsTask::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ReadFitsFile",
|
||||
"gaiamission_fitsfiletorawdata",
|
||||
{
|
||||
{
|
||||
"Type",
|
||||
new StringEqualVerifier("ReadFitsTask"),
|
||||
Optional::No
|
||||
},
|
||||
{
|
||||
KeyInFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileProcess is set to true then this specifies the path to a "
|
||||
"single FITS file that will be read. Otherwise it specifies the path to "
|
||||
"a folder with multiple FITS files that are to be read.",
|
||||
},
|
||||
{
|
||||
KeyOutFileOrFolderPath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"If SingleFileProcess is set to true then this specifies the name "
|
||||
"(including entire path) to the output file. Otherwise it specifies the "
|
||||
"path to the output folder which to export binary star data to.",
|
||||
},
|
||||
{
|
||||
KeySingleFileProcess,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"If true then task will read from a single FITS file and output a single "
|
||||
"binary file. If false then task will read all files in specified folder "
|
||||
"and output multiple files sorted by location."
|
||||
},
|
||||
{
|
||||
KeyThreadsToUse,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"Defines how many threads to use when reading from multiple files."
|
||||
},
|
||||
{
|
||||
KeyFirstRow,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"Defines the first row that will be read from the specified FITS "
|
||||
"file(s). If not defined then reading will start at first row.",
|
||||
},
|
||||
{
|
||||
KeyLastRow,
|
||||
new IntVerifier,
|
||||
Optional::Yes,
|
||||
"Defines the last row that will be read from the specified FITS file(s). "
|
||||
"If not defined (or less than FirstRow) then full file(s) will be read.",
|
||||
},
|
||||
{
|
||||
KeyFilterColumnNames,
|
||||
new StringListVerifier,
|
||||
Optional::Yes,
|
||||
"A list of strings with the names of all the additional columns that are "
|
||||
"to be read from the specified FITS file(s). These columns can be used "
|
||||
"for filtering while constructing Octree later.",
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
82
modules/gaia/tasks/readfitstask.h
Normal file
82
modules/gaia/tasks/readfitstask.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___READFITSTASK___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___READFITSTASK___H__
|
||||
|
||||
#include <openspace/util/task.h>
|
||||
#include <openspace/util/threadpool.h>
|
||||
#include <openspace/util/concurrentjobmanager.h>
|
||||
#include <modules/fitsfilereader/include/fitsfilereader.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class ReadFitsTask : public Task {
|
||||
public:
|
||||
ReadFitsTask(const ghoul::Dictionary& dictionary);
|
||||
virtual ~ReadFitsTask() = default;
|
||||
|
||||
std::string description() override;
|
||||
void perform(const Task::ProgressCallback& onProgress) override;
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
const size_t MAX_SIZE_BEFORE_WRITE = 48000000; // ~183MB -> 2M stars with 24 values
|
||||
//const size_t MAX_SIZE_BEFORE_WRITE = 9000000; // ~34MB -> 0,5 stars with 18 values
|
||||
|
||||
/**
|
||||
* Reads a single FITS file and stores ordered star data in one binary file.
|
||||
*/
|
||||
void readSingleFitsFile(const Task::ProgressCallback& progressCallback);
|
||||
|
||||
/**
|
||||
* Reads all FITS files in a folder with multiple threads and stores ordered star
|
||||
* data into 8 binary files.
|
||||
*/
|
||||
void readAllFitsFilesFromFolder(const Task::ProgressCallback& progressCallback);
|
||||
|
||||
/**
|
||||
* Writes \param data to octant [\param index] file.
|
||||
* \param isFirstWrite defines if this is the first write to specified octant, if so
|
||||
* the file is created, otherwise the accumulated data is appended to the end of the
|
||||
* file.
|
||||
*/
|
||||
int writeOctantToFile(const std::vector<float>& data, int index,
|
||||
std::vector<bool>& isFirstWrite, int nValuesPerStar);
|
||||
|
||||
std::string _inFileOrFolderPath;
|
||||
std::string _outFileOrFolderPath;
|
||||
bool _singleFileProcess = false;
|
||||
size_t _threadsToUse = 1;
|
||||
int _firstRow = 0;
|
||||
int _lastRow = 0;
|
||||
std::vector<std::string> _allColumnNames;
|
||||
std::vector<std::string> _filterColumnNames;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___READFITSTASK___H__
|
||||
122
modules/gaia/tasks/readspecktask.cpp
Normal file
122
modules/gaia/tasks/readspecktask.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/gaia/tasks/readspecktask.h>
|
||||
|
||||
#include <modules/fitsfilereader/include/fitsfilereader.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/dictionary.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyInFilePath = "InFilePath";
|
||||
constexpr const char* KeyOutFilePath = "OutFilePath";
|
||||
|
||||
constexpr const char* _loggerCat = "ReadSpeckTask";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
ReadSpeckTask::ReadSpeckTask(const ghoul::Dictionary& dictionary) {
|
||||
openspace::documentation::testSpecificationAndThrow(
|
||||
documentation(),
|
||||
dictionary,
|
||||
"ReadSpeckTask"
|
||||
);
|
||||
|
||||
_inFilePath = absPath(dictionary.value<std::string>(KeyInFilePath));
|
||||
_outFilePath = absPath(dictionary.value<std::string>(KeyOutFilePath));
|
||||
}
|
||||
|
||||
std::string ReadSpeckTask::description() {
|
||||
return fmt::format(
|
||||
"Read speck file {} and write raw star data into {}", _inFilePath, _outFilePath
|
||||
);
|
||||
}
|
||||
|
||||
void ReadSpeckTask::perform(const Task::ProgressCallback& progressCallback) {
|
||||
progressCallback(0.f);
|
||||
|
||||
int32_t nRenderValues = 0;
|
||||
|
||||
FitsFileReader fileReader(false);
|
||||
std::vector<float> fullData = fileReader.readSpeckFile(_inFilePath, nRenderValues);
|
||||
|
||||
progressCallback(0.9f);
|
||||
|
||||
std::ofstream fileStream(_outFilePath, std::ofstream::binary);
|
||||
if (fileStream.good()) {
|
||||
int32_t nValues = static_cast<int32_t>(fullData.size());
|
||||
LINFO("nValues: " + std::to_string(nValues));
|
||||
|
||||
if (nValues == 0) {
|
||||
LERROR("Error writing file - No values were read from file.");
|
||||
}
|
||||
fileStream.write(reinterpret_cast<const char*>(&nValues), sizeof(int32_t));
|
||||
fileStream.write(reinterpret_cast<const char*>(&nRenderValues), sizeof(int32_t));
|
||||
|
||||
size_t nBytes = nValues * sizeof(fullData[0]);
|
||||
fileStream.write(reinterpret_cast<const char*>(fullData.data()), nBytes);
|
||||
|
||||
fileStream.close();
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format("Error opening file: {} as output data file.", _outFilePath));
|
||||
}
|
||||
|
||||
progressCallback(1.f);
|
||||
}
|
||||
|
||||
documentation::Documentation ReadSpeckTask::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"ReadSpeckTask",
|
||||
"gaiamission_speckfiletorawdata",
|
||||
{
|
||||
{
|
||||
"Type",
|
||||
new StringEqualVerifier("ReadSpeckTask"),
|
||||
Optional::No
|
||||
},
|
||||
{
|
||||
KeyInFilePath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The path to the SPECK file that are to be read.",
|
||||
},
|
||||
{
|
||||
KeyOutFilePath,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The path to the file to export raw VBO data to.",
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
50
modules/gaia/tasks/readspecktask.h
Normal file
50
modules/gaia/tasks/readspecktask.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_GAIA___READSPECKTASK___H__
|
||||
#define __OPENSPACE_MODULE_GAIA___READSPECKTASK___H__
|
||||
|
||||
#include <openspace/util/task.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class ReadSpeckTask : public Task {
|
||||
public:
|
||||
ReadSpeckTask(const ghoul::Dictionary& dictionary);
|
||||
virtual ~ReadSpeckTask() = default;
|
||||
|
||||
std::string description() override;
|
||||
void perform(const Task::ProgressCallback& onProgress) override;
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
std::string _inFilePath;
|
||||
std::string _outFilePath;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_GAIA___READSPECKTASK___H__
|
||||
@@ -33,12 +33,6 @@ using json = nlohmann::json;
|
||||
|
||||
namespace openspace::properties {
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
void to_json(json& j, const Property& p) {
|
||||
std::string description = p.generateBaseJsonDescription();
|
||||
json desc = json::parse(description);
|
||||
|
||||
@@ -34,6 +34,7 @@ set(HEADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/keplertranslation.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/spicetranslation.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/tletranslation.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/horizonstranslation.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rotation/spicerotation.h
|
||||
)
|
||||
source_group("Header Files" FILES ${HEADER_FILES})
|
||||
@@ -48,6 +49,7 @@ set(SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/keplertranslation.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/spicetranslation.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/tletranslation.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/translation/horizonstranslation.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rotation/spicerotation.cpp
|
||||
)
|
||||
source_group("Source Files" FILES ${SOURCE_FILES})
|
||||
|
||||
@@ -120,4 +120,4 @@ Fragment getFragment() {
|
||||
}
|
||||
|
||||
return frag;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,4 +105,4 @@ void main() {
|
||||
}
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,4 +56,4 @@ void main() {
|
||||
position = vec4(1E-19, 1E-19, 1E-19, 1.0) * vs_gPosition;
|
||||
|
||||
gl_Position = position;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <modules/space/translation/keplertranslation.h>
|
||||
#include <modules/space/translation/spicetranslation.h>
|
||||
#include <modules/space/translation/tletranslation.h>
|
||||
#include <modules/space/translation/horizonstranslation.h>
|
||||
#include <modules/space/rotation/spicerotation.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
@@ -86,6 +87,7 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary&) {
|
||||
fTranslation->registerClass<KeplerTranslation>("KeplerTranslation");
|
||||
fTranslation->registerClass<SpiceTranslation>("SpiceTranslation");
|
||||
fTranslation->registerClass<TLETranslation>("TLETranslation");
|
||||
fTranslation->registerClass<HorizonsTranslation>("HorizonsTranslation");
|
||||
|
||||
auto fRotation = FactoryManager::ref().factory<Rotation>();
|
||||
ghoul_assert(fRotation, "Rotation factory was not created");
|
||||
@@ -111,6 +113,7 @@ std::vector<documentation::Documentation> SpaceModule::documentations() const {
|
||||
SpiceTranslation::Documentation(),
|
||||
KeplerTranslation::Documentation(),
|
||||
TLETranslation::Documentation(),
|
||||
HorizonsTranslation::Documentation(),
|
||||
planetgeometry::PlanetGeometry::Documentation(),
|
||||
planetgeometry::SimpleSphereGeometry::Documentation()
|
||||
};
|
||||
|
||||
189
modules/space/translation/horizonstranslation.cpp
Normal file
189
modules/space/translation/horizonstranslation.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/space/translation/horizonstranslation.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/lua/ghoul_lua.h>
|
||||
#include <ghoul/lua/lua_helper.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "HorizonsTranslation";
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
constexpr openspace::properties::Property::PropertyInfo HorizonsTextFileInfo = {
|
||||
"HorizonsTextFile",
|
||||
"Horizons Text File",
|
||||
"This value is the path to the text file generated by Horizons with observer "
|
||||
"range and Galactiv longitude and latitude for different timestamps."
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation HorizonsTranslation::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Horizons Translation",
|
||||
"base_transform_translation_horizons",
|
||||
{
|
||||
{
|
||||
"Type",
|
||||
new StringEqualVerifier("HorizonsTranslation"),
|
||||
Optional::No
|
||||
},
|
||||
{
|
||||
HorizonsTextFileInfo.identifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
HorizonsTextFileInfo.description
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
HorizonsTranslation::HorizonsTranslation()
|
||||
: _horizonsTextFile(HorizonsTextFileInfo)
|
||||
{
|
||||
addProperty(_horizonsTextFile);
|
||||
|
||||
_horizonsTextFile.onChange([&](){
|
||||
requireUpdate();
|
||||
_fileHandle = std::make_unique<ghoul::filesystem::File>(_horizonsTextFile);
|
||||
_fileHandle->setCallback([&](const ghoul::filesystem::File&) {
|
||||
requireUpdate();
|
||||
notifyObservers();
|
||||
});
|
||||
readHorizonsTextFile(_horizonsTextFile);
|
||||
});
|
||||
}
|
||||
|
||||
HorizonsTranslation::HorizonsTranslation(const ghoul::Dictionary& dictionary)
|
||||
: HorizonsTranslation()
|
||||
{
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"HorizonsTranslation"
|
||||
);
|
||||
|
||||
_horizonsTextFile = absPath(
|
||||
dictionary.value<std::string>(HorizonsTextFileInfo.identifier)
|
||||
);
|
||||
|
||||
// Read specified file and store it in memory.
|
||||
readHorizonsTextFile(_horizonsTextFile);
|
||||
}
|
||||
|
||||
glm::dvec3 HorizonsTranslation::position(const UpdateData& data) const {
|
||||
glm::dvec3 interpolatedPos = glm::dvec3(0.0);
|
||||
|
||||
auto lastBefore = _timeline.lastKeyframeBefore(data.time.j2000Seconds(), true);
|
||||
auto firstAfter = _timeline.firstKeyframeAfter(data.time.j2000Seconds(), false);
|
||||
if (lastBefore && firstAfter) {
|
||||
// We're inbetween first and last value.
|
||||
double timelineDiff = firstAfter->timestamp - lastBefore->timestamp;
|
||||
double timeDiff = data.time.j2000Seconds() - lastBefore->timestamp;
|
||||
double diff = (timelineDiff > DBL_EPSILON) ? timeDiff / timelineDiff : 0.0;
|
||||
|
||||
glm::dvec3 dir = firstAfter->data - lastBefore->data;
|
||||
interpolatedPos = lastBefore->data + dir * diff;
|
||||
}
|
||||
else if (lastBefore) {
|
||||
// Requesting a time after last value. Return last known position.
|
||||
interpolatedPos = lastBefore->data;
|
||||
}
|
||||
else if (firstAfter) {
|
||||
// Requesting a time before first value. Return last known position.
|
||||
interpolatedPos = firstAfter->data;
|
||||
}
|
||||
|
||||
return interpolatedPos;
|
||||
}
|
||||
|
||||
void HorizonsTranslation::readHorizonsTextFile(const std::string& horizonsTextFilePath) {
|
||||
std::ifstream fileStream(horizonsTextFilePath);
|
||||
|
||||
if (!fileStream.good()) {
|
||||
LERROR(fmt::format(
|
||||
"Failed to open Horizons text file '{}'", horizonsTextFilePath
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
// The beginning of a Horizons file has a header with a lot of information about the
|
||||
// query that we do not care about. Ignore everything until data starts, including
|
||||
// the row marked by $$SOE (i.e. Start Of Ephemerides).
|
||||
std::string line = "";
|
||||
while (line[0] != '$') {
|
||||
std::getline(fileStream, line);
|
||||
}
|
||||
|
||||
// Read data line by line until $$EOE (i.e. End Of Ephemerides).
|
||||
// Skip the rest of the file.
|
||||
std::getline(fileStream, line);
|
||||
while (line[0] != '$') {
|
||||
std::stringstream str(line);
|
||||
std::string date;
|
||||
std::string time;
|
||||
float range = 0;
|
||||
float gLon = 0;
|
||||
float gLat = 0;
|
||||
|
||||
// File is structured by:
|
||||
// YYYY-MM-DD
|
||||
// HH:MM:SS
|
||||
// Range-to-observer (km)
|
||||
// Range-delta (km/s) -- suppressed!
|
||||
// Galactic Longitude (degrees)
|
||||
// Galactic Latitude (degrees)
|
||||
str >> date >> time >> range >> gLon >> gLat;
|
||||
|
||||
// Convert date and time to seconds after 2000
|
||||
// and pos to Galactic positions in meter from Observer.
|
||||
std::string timeString = date + " " + time;
|
||||
double timeInJ2000 = Time::convertTime(timeString);
|
||||
glm::dvec3 gPos = glm::dvec3(
|
||||
1000 * range * cos(glm::radians(gLat)) * cos(glm::radians(gLon)),
|
||||
1000 * range * cos(glm::radians(gLat)) * sin(glm::radians(gLon)),
|
||||
1000 * range * sin(glm::radians(gLat))
|
||||
);
|
||||
|
||||
// Add position to stored timeline.
|
||||
_timeline.addKeyframe(timeInJ2000, gPos);
|
||||
|
||||
std::getline(fileStream, line);
|
||||
}
|
||||
fileStream.close();
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
72
modules/space/translation/horizonstranslation.h
Normal file
72
modules/space/translation/horizonstranslation.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_SPACE___HORIZONSTRANSLATION___H__
|
||||
#define __OPENSPACE_MODULE_SPACE___HORIZONSTRANSLATION___H__
|
||||
|
||||
#include <openspace/scene/translation.h>
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/util/timeline.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/lua/luastate.h>
|
||||
#include <memory>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
|
||||
/**
|
||||
* The HorizonsTranslation is based on text files generated from NASA JPL HORIZONS Website
|
||||
* (https://ssd.jpl.nasa.gov/horizons.cgi). The implementation expects a file with format:
|
||||
* TIME(YYYY-MM-DD HH:MM:SS) Range(km) GalLon(degrees) GalLat(degrees)
|
||||
* Range - The distance from target to observer. Chosen as "Observer range & range-rate"
|
||||
* in "Table Setting". This also generates a delta that can be suppressed under "Optional
|
||||
* observer-table settings" to limit file size. User must set output settings to
|
||||
* kilometers.
|
||||
* GalLon - Galactic Longitude. User must set output to Degrees in "Table Settings".
|
||||
* GalLat - Galactic Latitude. User must set output to Degrees in "Table Settings".
|
||||
*/
|
||||
class HorizonsTranslation : public Translation {
|
||||
public:
|
||||
HorizonsTranslation();
|
||||
HorizonsTranslation(const ghoul::Dictionary& dictionary);
|
||||
|
||||
glm::dvec3 position(const UpdateData& time) const override;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
void readHorizonsTextFile(const std::string& _horizonsTextFilePath);
|
||||
|
||||
properties::StringProperty _horizonsTextFile;
|
||||
std::unique_ptr<ghoul::filesystem::File> _fileHandle;
|
||||
ghoul::lua::LuaState _state;
|
||||
Timeline<glm::dvec3> _timeline;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_SPACE___HORIZONSTRANSLATION___H__
|
||||
@@ -36,6 +36,12 @@
|
||||
#include <openspace/util/synchronizationwatcher.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/lua/luastate.h>
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -92,7 +92,7 @@ void WebRenderHandler::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
// Add the dirty rect bounds to the GPU texture dirty rect.
|
||||
_lowerDirtyRectBound = glm::min(lowerUpdatingRectBound, _lowerDirtyRectBound);
|
||||
_upperDirtyRectBound = glm::max(upperUpdatingRectBound, _upperDirtyRectBound);
|
||||
_needsRepaint = false;
|
||||
_needsRepaint = false;
|
||||
}
|
||||
|
||||
void WebRenderHandler::updateTexture() {
|
||||
|
||||
Reference in New Issue
Block a user