REFACTOR: split renderablefieldlinessequence.cpp into two files and give propertiy variables a 'p' as prefix

This commit is contained in:
Oskar Carlbaum
2017-10-04 03:34:23 +02:00
parent 3c9d48315c
commit dc597f59c4
7 changed files with 597 additions and 464 deletions
@@ -27,11 +27,13 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablefieldlinessequence.h
${CMAKE_CURRENT_SOURCE_DIR}/util/fieldlinesstate.h
${CMAKE_CURRENT_SOURCE_DIR}/util/commons.h
)
source_group("Header Files" FILES ${HEADER_FILES})
set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablefieldlinessequence.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rendering/renderablefieldlinessequencesetup.cpp
${CMAKE_CURRENT_SOURCE_DIR}/util/fieldlinesstate.cpp
)
source_group("Source Files" FILES ${SOURCE_FILES})
@@ -25,268 +25,19 @@
#include <modules/fieldlinessequence/rendering/renderablefieldlinessequence.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/timemanager.h>
#include <openspace/util/updatestructures.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/opengl/programobject.h>
#include <ghoul/opengl/textureunit.h>
using std::string;
namespace {
std::string _loggerCat = "RenderableFieldlinesSequence";
// ----- KEYS POSSIBLE IN MODFILE. EXPECTED DATA TYPE OF VALUE IN [BRACKETS] ----- //
// ---------------------------- MANDATORY MODFILE KEYS ---------------------------- //
const char* KEY_INPUT_FILE_TYPE = "InputFileType"; // [STRING]
const char* KEY_SOURCE_FOLDER = "SourceFolder"; // [STRING]
// ---------------------------- OPTIONAL MODFILE KEYS ---------------------------- //
const char* KEY_COLOR_TABLE_PATHS = "ColorTablePaths"; // [STRING ARRAY] Values should be paths to .txt files
const char* KEY_COLOR_TABLE_RANGES = "ColorTableRanges";// [VEC2 ARRAY] Values should be paths to .txt files
const char* KEY_OSLFS_LOAD_AT_RUNTIME = "LoadAtRuntime"; // [BOOLEAN] If value False => Load in initializing step and store in RAM
// ------------- POSSIBLE STRING VALUES FOR CORRESPONDING MODFILE KEY ------------- //
const char* VALUE_INPUT_FILE_TYPE_CDF = "cdf";
const char* VALUE_INPUT_FILE_TYPE_JSON = "json";
const char* VALUE_INPUT_FILE_TYPE_OSFLS = "osfls";
static const openspace::properties::Property::PropertyInfo ColorMethodInfo = {
"colorMethod", "Color Method", "Color lines uniformly or using color tables based on extra quantities like e.g. temperature or particle density."
};
static const openspace::properties::Property::PropertyInfo ColorQuantityInfo = {
"colorQuantity", "Quantity to Color By", "Quantity used to color lines if the \"By Quantity\" color method is selected."
};
static const openspace::properties::Property::PropertyInfo ColorQuantityMinInfo = {
"colorQuantityMin", "ColorTable Min Value", "Value to map to the lowest end of the color table."
};
static const openspace::properties::Property::PropertyInfo ColorQuantityMaxInfo = {
"colorQuantityMax", "ColorTable Max Value", "Value to map to the highest end of the color table."
};
static const openspace::properties::Property::PropertyInfo ColorTablePathInfo = {
"colorTablePath", "Path to Color Table", "Color Table/Transfer Function to use for \"By Quantity\" coloring."
};
static const openspace::properties::Property::PropertyInfo ColorUniformInfo = {
"uniform", "Uniform Line Color", "The uniform color of lines shown when \"Color Method\" is set to \"Uniform\"."
};
static const openspace::properties::Property::PropertyInfo FlowColorInfo = {
"color", "Color", "Color of particles."
};
static const openspace::properties::Property::PropertyInfo EnableFlowInfo = {
"Enable", "ON/OFF",
"Toggles the rendering of moving particles along the lines. Can e.g. illustrate magnetic flow."
};
static const openspace::properties::Property::PropertyInfo ReverseFlowInfo = {
"reversed", "Reversed Flow", "Toggle to make the flow move in the opposite direction."
};
static const openspace::properties::Property::PropertyInfo ParticleSizeInfo = {
"particleSize", "Particle Size", "Size of the particles."
};
static const openspace::properties::Property::PropertyInfo ParticleSpacingInfo = {
"particleSpacing", "Particle Spacing", "Spacing inbetween particles."
};
static const openspace::properties::Property::PropertyInfo FlowSpeedInfo = {
"speed", "Speed", "Speed of the flow."
};
static const openspace::properties::Property::PropertyInfo OriginButtonInfo = {
"focusCameraOnParent", "Focus Camera", "Focus camera on parent."
};
static const openspace::properties::Property::PropertyInfo TimeJumpButtonInfo = {
"timeJumpToStart", "Jump to Start Time", "Performs a time jump to the start of the sequence."
};
enum ColorMethod { UNIFORM = 0, BY_QUANTITY };
} // namespace
namespace openspace {
RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary)
: Renderable(dictionary),
_colorGroup({ "Color" }),
_colorMethod(ColorMethodInfo, properties::OptionProperty::DisplayType::Radio),
_colorQuantity(ColorQuantityInfo, properties::OptionProperty::DisplayType::Dropdown),
_colorQuantityMin(ColorQuantityMinInfo),
_colorQuantityMax(ColorQuantityMaxInfo),
_colorTablePath(ColorTablePathInfo),
_colorUniform(ColorUniformInfo, glm::vec4(0.75f, 0.5f, 0.0f, 0.5f),
glm::vec4(0.f), glm::vec4(1.f)),
_flowColor(FlowColorInfo, glm::vec4(0.8f, 0.7f, 0.0f, 0.6f),
glm::vec4(0.f), glm::vec4(1.f)),
_flowEnabled(EnableFlowInfo, true),
_flowGroup({ "Flow" }),
_flowParticleSize(ParticleSizeInfo, 5, 0, 500),
_flowParticleSpacing(ParticleSpacingInfo, 60, 0, 500),
_flowReversed(ReverseFlowInfo, false),
_flowSpeed(FlowSpeedInfo, 20, 0, 1000),
_focusOnOriginBtn(OriginButtonInfo),
_jumpToStartBtn(TimeJumpButtonInfo) {
// Set the default color table, just in case user defined paths are corrupt!
_transferFunction = std::make_shared<TransferFunction>(absPath(_colorTablePaths[0]));
if(!extractInfoFromDictionary(dictionary)) {
_sourceFileType = INVALID;
}
}
void RenderableFieldlinesSequence::initialize() {
switch (_sourceFileType) {
case CDF:
LERROR("CDF NOT YET IMPLEMENTED!");
break;
case JSON:
LERROR("JSON NOT YET IMPLEMENTED!");
break;
case OSFLS:
if (_isLoadingStatesAtRuntime) {
extractTriggerTimesFromFileNames();
FieldlinesState newState;
bool loadedSuccessfully = newState.loadStateFromOsfls(_sourceFiles[0]);
if (loadedSuccessfully) {
_states.push_back(newState);
_nStates = _startTimes.size();
_activeStateIndex = 0;
} else {
LERROR("The provided .osfls files seem to be corrupt!");
_sourceFileType = INVALID;
}
} else {
// Load states into RAM!
for (string filePath : _sourceFiles) {
FieldlinesState newState;
bool loadedSuccessfully = newState.loadStateFromOsfls(filePath);
if (loadedSuccessfully) {
_states.push_back(newState);
_startTimes.push_back(newState.triggerTime());
_nStates++;
}
}
}
break;
default:
break;
}
// At this point there's at least one state loaded into memory!
// No need to store source paths in memory if they are already in RAM!
if (!_isLoadingStatesAtRuntime) {
_sourceFiles.clear();
}
computeSequenceEndTime();
// --------------------- HANDLE PROPERTIES --------------------- //
// Add Property Groups
addPropertySubOwner(_colorGroup);
addPropertySubOwner(_flowGroup);
// Add non-grouped properties
addProperty(_focusOnOriginBtn);
addProperty(_jumpToStartBtn);
// Add Properties to the groups
_colorGroup.addProperty(_colorMethod);
_colorGroup.addProperty(_colorQuantity);
_colorGroup.addProperty(_colorQuantityMin);
_colorGroup.addProperty(_colorQuantityMax);
_colorGroup.addProperty(_colorTablePath);
_colorGroup.addProperty(_colorUniform);
_flowGroup.addProperty(_flowEnabled);
_flowGroup.addProperty(_flowReversed);
_flowGroup.addProperty(_flowColor);
_flowGroup.addProperty(_flowParticleSize);
_flowGroup.addProperty(_flowParticleSpacing);
_flowGroup.addProperty(_flowSpeed);
// Add Options to OptionProperties
_colorMethod.addOption(ColorMethod::UNIFORM, "Uniform");
_colorMethod.addOption(ColorMethod::BY_QUANTITY, "By Quantity");
// Add option for each extra quantity. We assume that there are just as many names to
// extra quantities as there are extra quantities. We also assume that all states in
// the given sequence have the same extra quantities!
const size_t N_EXTRA_QUANTITIES = _states[0].nExtraQuantities();
auto EXTRA_VARIABLE_NAMES_VEC = _states[0].extraQuantityNames();
for (size_t i = 0; i < N_EXTRA_QUANTITIES; ++i) {
_colorQuantity.addOption(i, EXTRA_VARIABLE_NAMES_VEC[i]);
}
// Each quantity should have its own color table and color table range, no more, no less
_colorTablePaths.resize(N_EXTRA_QUANTITIES, _colorTablePaths.back());
_colorTableRanges.resize(N_EXTRA_QUANTITIES, _colorTableRanges.back());
// Add Property Callback Functions
_colorQuantity.onChange([this] {
LDEBUG("CHANGED COLORING QUANTITY");
_shouldUpdateColorBuffer = true;
_colorQuantityMin = std::to_string(_colorTableRanges[_colorQuantity].x);
_colorQuantityMax = std::to_string(_colorTableRanges[_colorQuantity].y);
_activeColorTable = &_colorTablePaths[_colorQuantity];
_colorTablePath = *_activeColorTable;
});
_colorTablePath.onChange([this] {
// TOGGLE ACTIVE SHADER PROGRAM
_transferFunction->setPath(_colorTablePath);
*_activeColorTable = _colorTablePath;
});
_colorQuantityMin.onChange([this] {
LDEBUG("CHANGED MIN VALUE");
// TODO CHECK IF VALID NUMBER!
// _updateTransferFunctionMin = true;
_colorTableRanges[_colorQuantity].x = std::stof(_colorQuantityMin);
});
_colorQuantityMax.onChange([this] {
LDEBUG("CHANGED MAX VALUE");
// TODO CHECK IF VALID NUMBER!
// _updateTransferFunctionMin = true;
_colorTableRanges[_colorQuantity].y = std::stof(_colorQuantityMax);
});
_focusOnOriginBtn.onChange([this] {
LDEBUG("SET FOCUS NODE TO PARENT");
// TODO CHECK IF VALID NUMBER!
// _updateTransferFunctionMin = true;
//OsEng.navigationHandler().setFocusNode();
SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(_name);
if (!node) {
LWARNING("Could not find a node in scenegraph called '" << _name << "'");
return;
}
OsEng.navigationHandler().setFocusNode(node->parent());
OsEng.navigationHandler().resetCameraDirection();
});
_jumpToStartBtn.onChange([this] {
LDEBUG("Jump in time to start of sequence!");
OsEng.timeManager().time().setTime(_startTimes[0]);
});
// Setup shader program
_shaderProgram = OsEng.renderEngine().buildRenderProgram(
"FieldlinesSequence",
"${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_vs.glsl",
"${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_fs.glsl"
);
if (!_shaderProgram) {
LERROR("Shader program failed initialization!");
_sourceFileType = INVALID;
}
//------------------ Initialize OpenGL VBOs and VAOs-------------------------------//
glGenVertexArrays(1, &_vertexArrayObject);
glGenBuffers(1, &_vertexPositionBuffer);
glGenBuffers(1, &_vertexColorBuffer);
}
void RenderableFieldlinesSequence::deinitialize() {
glDeleteVertexArrays(1, &_vertexArrayObject);
_vertexArrayObject = 0;
@@ -294,6 +45,9 @@ void RenderableFieldlinesSequence::deinitialize() {
glDeleteBuffers(1, &_vertexPositionBuffer);
_vertexPositionBuffer = 0;
glDeleteBuffers(1, &_vertexColorBuffer);
_vertexColorBuffer = 0;
RenderEngine& renderEngine = OsEng.renderEngine();
if (_shaderProgram) {
renderEngine.removeRenderProgram(_shaderProgram);
@@ -326,26 +80,25 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks&
_shaderProgram->setUniform("modelViewProjection",
data.camera.sgctInternal.projectionMatrix() * glm::mat4(MODEL_VIEW_MAT));
_shaderProgram->setUniform("colorMethod", _pColorMethod);
_shaderProgram->setUniform("lineColor", _pColorUniform);
_shaderProgram->setUniform("colorMethod", _colorMethod);
_shaderProgram->setUniform("lineColor", _colorUniform);
if (_colorMethod == ColorMethod::BY_QUANTITY) {
if (_pColorMethod == ColorMethod::BY_QUANTITY) {
ghoul::opengl::TextureUnit textureUnit;
textureUnit.activate();
_transferFunction->bind(); // Calls update internally
_shaderProgram->setUniform("colorTable", textureUnit);
_shaderProgram->setUniform("colorTableRange",
_colorTableRanges[_colorQuantity]);
_colorTableRanges[_pColorQuantity]);
}
// Flow/Particles
_shaderProgram->setUniform("usingParticles", _flowEnabled);
_shaderProgram->setUniform("flowColor", _flowColor);
_shaderProgram->setUniform("particleSize", _flowParticleSize);
_shaderProgram->setUniform("particleSpeed", _flowSpeed);
_shaderProgram->setUniform("particleSpacing", _flowParticleSpacing);
_shaderProgram->setUniform("time", OsEng.runTime() * (_flowReversed ? -1 : 1));
_shaderProgram->setUniform("flowColor", _pFlowColor);
_shaderProgram->setUniform("usingParticles", _pFlowEnabled);
_shaderProgram->setUniform("particleSize", _pFlowParticleSize);
_shaderProgram->setUniform("particleSpacing", _pFlowParticleSpacing);
_shaderProgram->setUniform("particleSpeed", _pFlowSpeed);
_shaderProgram->setUniform("time", OsEng.runTime() * (_pFlowReversed ? -1 : 1));
glBindVertexArray(_vertexArrayObject);
glMultiDrawArrays(
@@ -377,7 +130,7 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
updateActiveTriggerTimeIndex(CURRENT_TIME);
if (_isLoadingStatesAtRuntime) {
if (_loadingStatesDynamically) {
_mustLoadNewStateFromDisk = true;
} else {
_needsUpdate = true;
@@ -404,7 +157,7 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
}
if (_needsUpdate || _newStateIsReady) {
if (_isLoadingStatesAtRuntime) {
if (_loadingStatesDynamically) {
_states[0] = std::move(_newState);
}
@@ -413,7 +166,7 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) {
if (_states[_activeStateIndex].nExtraQuantities() > 0) {
_shouldUpdateColorBuffer = true;
} else {
_colorMethod = ColorMethod::UNIFORM;
_pColorMethod = ColorMethod::UNIFORM;
}
// Everything is set and ready for rendering!
@@ -437,7 +190,8 @@ void RenderableFieldlinesSequence::updateActiveTriggerTimeIndex(const double CUR
auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), CURRENT_TIME);
if (iter != _startTimes.end()) {
if ( iter != _startTimes.begin()) {
_activeTriggerTimeIndex = std::distance(_startTimes.begin(), iter) - 1;
_activeTriggerTimeIndex =
static_cast<int>(std::distance(_startTimes.begin(), iter)) - 1;
} else {
_activeTriggerTimeIndex = 0;
}
@@ -485,7 +239,7 @@ void RenderableFieldlinesSequence::updateVertexColorBuffer() {
bool isSuccessful;
const std::vector<float>& QUANTITY_VEC =
_states[_activeStateIndex].extraQuantity(_colorQuantity, isSuccessful);
_states[_activeStateIndex].extraQuantity(_pColorQuantity, isSuccessful);
if (isSuccessful) {
glBufferData(GL_ARRAY_BUFFER, QUANTITY_VEC.size() * sizeof(float),
@@ -498,150 +252,7 @@ void RenderableFieldlinesSequence::updateVertexColorBuffer() {
}
}
bool RenderableFieldlinesSequence::extractInfoFromDictionary(
const ghoul::Dictionary& dictionary) {
string name;
dictionary.getValue(SceneGraphNode::KeyName, name);
_name = name;
name += ": ";
// ------------------- EXTRACT MANDATORY VALUES FROM DICTIONARY ------------------- //
string inputFileTypeValue;
if(!dictionary.getValue(KEY_INPUT_FILE_TYPE, inputFileTypeValue)) {
LERROR(name << "The field " << string(KEY_INPUT_FILE_TYPE) << " is missing!");
return false;
} else {
std::transform(inputFileTypeValue.begin(), inputFileTypeValue.end(),
inputFileTypeValue.begin(), ::tolower);
// Verify that the input type is correct
if (inputFileTypeValue == VALUE_INPUT_FILE_TYPE_CDF) {
_sourceFileType = CDF;
} else if (inputFileTypeValue == VALUE_INPUT_FILE_TYPE_JSON) {
_sourceFileType = JSON;
} else if (inputFileTypeValue == VALUE_INPUT_FILE_TYPE_OSFLS) {
_sourceFileType = OSFLS;
} else {
LERROR(name << inputFileTypeValue << " is not a recognised "
<< KEY_INPUT_FILE_TYPE);
_sourceFileType = INVALID;
return false;
}
}
string sourceFolderPath;
if(!dictionary.getValue(KEY_SOURCE_FOLDER, sourceFolderPath)) {
LERROR(name << "The field " << string(KEY_SOURCE_FOLDER) << " is missing!");
return false;
}
// Ensure that the source folder exists and then extract
// the files with the same extension as <inputFileTypeValue>
ghoul::filesystem::Directory sourceFolder(sourceFolderPath);
if (FileSys.directoryExists(sourceFolder)) {
// Extract all file paths from the provided folder (Non-recursively! Sorted!)
_sourceFiles = sourceFolder.readFiles(ghoul::Boolean::No, ghoul::Boolean::Yes);
// Remove all files that don't have <inputFileTypeValue> as extension
_sourceFiles.erase(std::remove_if(_sourceFiles.begin(), _sourceFiles.end(),
[inputFileTypeValue] (string str) {
const size_t EXT_LENGTH = inputFileTypeValue.length();
string sub = str.substr(str.length() - EXT_LENGTH, EXT_LENGTH);
std::transform(sub.begin(), sub.end(), sub.begin(), ::tolower);
return sub != inputFileTypeValue;
}), _sourceFiles.end());
// Ensure that there are available and valid source files left
if (_sourceFiles.empty()) {
LERROR(name << sourceFolderPath << " contains no ." << inputFileTypeValue
<< " files!");
return false;
}
} else {
LERROR(name << "FieldlinesSequence" << sourceFolderPath
<< " is not a valid directory!");
return false;
}
// Extract optional info from modfile
ghoul::Dictionary colorTablesPathsDictionary;
if (dictionary.getValue(KEY_COLOR_TABLE_PATHS, colorTablesPathsDictionary)) {
const size_t N_PROVIDED_PATHS = colorTablesPathsDictionary.size();
if (N_PROVIDED_PATHS > 0) {
// Clear the default! It is already specified in the transferFunction
_colorTablePaths.clear();
for (size_t i = 1; i <= N_PROVIDED_PATHS; ++i) {
_colorTablePaths.push_back(
colorTablesPathsDictionary.value<std::string>( std::to_string(i) ) );
}
}
}
ghoul::Dictionary colorTablesRangesDictionary;
if (dictionary.getValue(KEY_COLOR_TABLE_RANGES, colorTablesRangesDictionary)) {
const size_t N_PROVIDED_RANGES = colorTablesRangesDictionary.size();
for (size_t i = 1; i <= N_PROVIDED_RANGES; ++i) {
_colorTableRanges.push_back(
colorTablesRangesDictionary.value<glm::vec2>( std::to_string(i) ) );
}
} else {
_colorTableRanges.push_back(glm::vec2(0, 1));
}
// Extract info specific to each inputType
switch (_sourceFileType) {
case CDF:
LERROR(name << "CDF NOT YET IMPLEMENTED!");
break;
case JSON:
LERROR(name << "JSON NOT YET IMPLEMENTED!");
break;
case OSFLS: {
bool shouldLoadInRealtime = false;
if (dictionary.getValue(KEY_OSLFS_LOAD_AT_RUNTIME, shouldLoadInRealtime)) {
_isLoadingStatesAtRuntime = shouldLoadInRealtime;
} else {
LWARNING(name << KEY_OSLFS_LOAD_AT_RUNTIME <<
" isn't specified! OSFLS files will be loaded during runtime!");
}
} break;
default:
break;
}
}
// Calculate expected end time.
void RenderableFieldlinesSequence::computeSequenceEndTime() {
if (_nStates > 1) {
const double LAST_TRIGGER_TIME = _startTimes[_nStates - 1];
const double SEQUENCE_DURATION = LAST_TRIGGER_TIME - _startTimes[0];
const double AVERAGE_STATE_DURATION = SEQUENCE_DURATION / (static_cast<double>(_nStates) - 1.0);
_sequenceEndTime = LAST_TRIGGER_TIME + AVERAGE_STATE_DURATION;
} else {
// If there's just one state it should never disappear!
_sequenceEndTime = DBL_MAX;
}
}
// Extract J2000 time from file names
// Requires files to be named as such: 'YYYY-MM-DDTHH-MM-SS-XXX.osfls'
void RenderableFieldlinesSequence::extractTriggerTimesFromFileNames() {
const size_t FILENAME_SIZE = 23; // number of characters in filename (excluding '.osfls')
const size_t EXT_SIZE = 6; // size(".osfls")
for (const std::string& FILEPATH : _sourceFiles) {
const size_t STR_LENGTH = FILEPATH.size();
// Extract the filename from the path (without extension)
std::string timeString = FILEPATH.substr(STR_LENGTH - FILENAME_SIZE - EXT_SIZE,
FILENAME_SIZE - 1);
// Ensure the separators are correct
timeString.replace( 4, 1, "-");
timeString.replace( 7, 1, "-");
timeString.replace(13, 1, ":");
timeString.replace(16, 1, ":");
timeString.replace(19, 1, ".");
const double TRIGGER_TIME = Time::convertTime(timeString);
_startTimes.push_back(TRIGGER_TIME);
}
}
} // namespace openspace
@@ -34,13 +34,14 @@
#include <openspace/properties/vector/vec4property.h>
#include <openspace/rendering/transferfunction.h>
#include <modules/fieldlinessequence/util/fieldlinesstate.h>
#include <atomic>
namespace openspace {
class ghoul::Dictionary;
class RenderableFieldlinesSequence : public Renderable {
public:
RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary);
@@ -54,6 +55,11 @@ public:
void render(const RenderData& data, RendererTasks& rendererTask) override;
void update(const UpdateData& data) override;
private:
enum ColorMethod : int {
UNIFORM = 0,
BY_QUANTITY
};
enum SourceFileType : int {
CDF = 0,
JSON,
@@ -63,12 +69,12 @@ private:
std::string _name;
int _activeStateIndex = -1;
int _activeTriggerTimeIndex = -1;
bool _isLoadingStatesAtRuntime = true; // False => loading osfls at runtime
bool _mustLoadNewStateFromDisk = false;
bool _needsUpdate = false; // If still in same state as previous frame == false
bool _shouldUpdateColorBuffer = false;
int _activeStateIndex = -1;
int _activeTriggerTimeIndex = -1;
bool _loadingStatesDynamically = false; // False => loading osfls files into RAM in initializing step
bool _mustLoadNewStateFromDisk = false;
bool _needsUpdate = false; // If still in same state as previous frame == false
bool _shouldUpdateColorBuffer = false;
FieldlinesState _newState;
size_t _nStates = 0;
double _sequenceEndTime;
@@ -77,10 +83,10 @@ private:
std::atomic<bool> _isLoadingStateFromDisk{false};
std::atomic<bool> _newStateIsReady{false};
std::unique_ptr<ghoul::Dictionary> _dictionary;
std::shared_ptr<TransferFunction> _transferFunction; // Transfer funtion (tf)
std::unique_ptr<ghoul::opengl::ProgramObject> _shaderProgram;
std::string* _activeColorTable;
std::vector<std::string> _colorTablePaths {"${OPENSPACE_DATA}/colortables/kroyw.txt"}; // Default in case user doesn't specify otherwise
std::vector<std::string> _sourceFiles; // Stored in RAM if files are loaded at runtime, else emptied after initialization
std::vector<double> _startTimes;
@@ -97,24 +103,24 @@ private:
const GLuint _VA_COLOR = 1;
// ----------------------------- Properties -----------------------------
properties::PropertyOwner _colorGroup; // Group to hold the color properties
properties::OptionProperty _colorMethod; // Uniform/transfer function/topology?
properties::OptionProperty _colorQuantity; // Index of the extra quantity to color lines by
properties::StringProperty _colorQuantityMin; // Color table/transfer function min
properties::StringProperty _colorQuantityMax; // Color table/transfer function max
properties::StringProperty _colorTablePath; // Color table/transfer function for "By Quantity" coloring
properties::Vec4Property _colorUniform; // Uniform Field Line Color
properties::PropertyOwner _pColorGroup; // Group to hold the color properties
properties::OptionProperty _pColorMethod; // Uniform/transfer function/topology?
properties::OptionProperty _pColorQuantity; // Index of the extra quantity to color lines by
properties::StringProperty _pColorQuantityMin; // Color table/transfer function min
properties::StringProperty _pColorQuantityMax; // Color table/transfer function max
properties::StringProperty _pColorTablePath; // Color table/transfer function for "By Quantity" coloring
properties::Vec4Property _pColorUniform; // Uniform Field Line Color
properties::Vec4Property _flowColor; // Simulated particles' color
properties::BoolProperty _flowEnabled; // Toggle flow [ON/OFF]
properties::PropertyOwner _flowGroup; // Gropu to hold the flow/particle properties
properties::IntProperty _flowParticleSize; // Size of simulated flow particles
properties::IntProperty _flowParticleSpacing; // Size of simulated flow particles
properties::BoolProperty _flowReversed; // Toggle flow direction [FORWARDS/BACKWARDS]
properties::IntProperty _flowSpeed; // Speed of simulated flow
properties::Vec4Property _pFlowColor; // Simulated particles' color
properties::BoolProperty _pFlowEnabled; // Toggle flow [ON/OFF]
properties::PropertyOwner _pFlowGroup; // Group to hold the flow/particle properties
properties::IntProperty _pFlowParticleSize; // Size of simulated flow particles
properties::IntProperty _pFlowParticleSpacing; // Size of simulated flow particles
properties::BoolProperty _pFlowReversed; // Toggle flow direction [FORWARDS/BACKWARDS]
properties::IntProperty _pFlowSpeed; // Speed of simulated flow
properties::TriggerProperty _focusOnOriginBtn; // Button which sets camera focus to parent node of the renderable
properties::TriggerProperty _jumpToStartBtn; // Button which executes a time jump to start of sequence
properties::TriggerProperty _pFocusOnOriginBtn; // Button which sets camera focus to parent node of the renderable
properties::TriggerProperty _pJumpToStartBtn; // Button which executes a time jump to start of sequence
void computeSequenceEndTime();
bool extractInfoFromDictionary(const ghoul::Dictionary& dictionary);
@@ -126,6 +132,10 @@ private:
void updateActiveTriggerTimeIndex(const double CURRENT_TIME);
void updateVertexPositionBuffer();
void updateVertexColorBuffer();
void updateVertexMaskingBuffer();
void definePropertyCallbackFunctions();
void setupProperties();
};
} // namespace openspace
@@ -0,0 +1,460 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* 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/fieldlinessequence/rendering/renderablefieldlinessequence.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/scene/scene.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/opengl/programobject.h>
namespace {
std::string _loggerCat = "RenderableFieldlinesSequence";
// ----- KEYS POSSIBLE IN MODFILE. EXPECTED DATA TYPE OF VALUE IN [BRACKETS] ----- //
// ---------------------------- MANDATORY MODFILE KEYS ---------------------------- //
const char* KEY_INPUT_FILE_TYPE = "InputFileType"; // [STRING]
const char* KEY_SOURCE_FOLDER = "SourceFolder"; // [STRING]
// ---------------------------- OPTIONAL MODFILE KEYS ---------------------------- //
const char* KEY_COLOR_TABLE_PATHS = "ColorTablePaths"; // [STRING ARRAY] Values should be paths to .txt files
const char* KEY_COLOR_TABLE_RANGES = "ColorTableRanges";// [VEC2 ARRAY] Values should be entered as {X, Y}, where X & Y are numbers
const char* KEY_OSLFS_LOAD_AT_RUNTIME = "LoadAtRuntime"; // [BOOLEAN] If value False => Load in initializing step and store in RAM
// ------------- POSSIBLE STRING VALUES FOR CORRESPONDING MODFILE KEY ------------- //
const char* VALUE_INPUT_FILE_TYPE_CDF = "cdf";
const char* VALUE_INPUT_FILE_TYPE_JSON = "json";
const char* VALUE_INPUT_FILE_TYPE_OSFLS = "osfls";
// --------------------------------- Property Info -------------------------------- //
static const openspace::properties::Property::PropertyInfo ColorMethodInfo = {
"colorMethod", "Color Method", "Color lines uniformly or using color tables based on extra quantities like e.g. temperature or particle density."
};
static const openspace::properties::Property::PropertyInfo ColorQuantityInfo = {
"colorQuantity", "Quantity to Color By", "Quantity used to color lines if the \"By Quantity\" color method is selected."
};
static const openspace::properties::Property::PropertyInfo ColorQuantityMinInfo = {
"colorQuantityMin", "ColorTable Min Value", "Value to map to the lowest end of the color table."
};
static const openspace::properties::Property::PropertyInfo ColorQuantityMaxInfo = {
"colorQuantityMax", "ColorTable Max Value", "Value to map to the highest end of the color table."
};
static const openspace::properties::Property::PropertyInfo ColorTablePathInfo = {
"colorTablePath", "Path to Color Table", "Color Table/Transfer Function to use for \"By Quantity\" coloring."
};
static const openspace::properties::Property::PropertyInfo ColorUniformInfo = {
"uniform", "Uniform Line Color", "The uniform color of lines shown when \"Color Method\" is set to \"Uniform\"."
};
static const openspace::properties::Property::PropertyInfo FlowColorInfo = {
"color", "Color", "Color of particles."
};
static const openspace::properties::Property::PropertyInfo FlowEnabledInfo = {
"flowEnabled", "Flow Direction",
"Toggles the rendering of moving particles along the lines. Can e.g. illustrate magnetic flow."
};
static const openspace::properties::Property::PropertyInfo FlowReversedInfo = {
"reversed", "Reversed Flow", "Toggle to make the flow move in the opposite direction."
};
static const openspace::properties::Property::PropertyInfo FlowParticleSizeInfo = {
"particleSize", "Particle Size", "Size of the particles."
};
static const openspace::properties::Property::PropertyInfo FlowParticleSpacingInfo = {
"particleSpacing", "Particle Spacing", "Spacing inbetween particles."
};
static const openspace::properties::Property::PropertyInfo FlowSpeedInfo = {
"speed", "Speed", "Speed of the flow."
};
static const openspace::properties::Property::PropertyInfo OriginButtonInfo = {
"focusCameraOnParent", "Focus Camera", "Focus camera on parent."
};
static const openspace::properties::Property::PropertyInfo TimeJumpButtonInfo = {
"timeJumpToStart", "Jump to Start Of Sequence", "Performs a time jump to the start of the sequence."
};
float stringToFloat(const std::string INPUT, const float BACKUP_VALUE = 0.f) {
float tmp;
try {
tmp = std::stof(INPUT);
} catch (const std::invalid_argument& ia) {
LWARNING("Invalid argument: " << ia.what() << ". '" << INPUT <<
"' is NOT a valid number!");
return BACKUP_VALUE;
}
return tmp;
}
} // namespace
namespace openspace {
RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary)
: Renderable(dictionary),
_pColorGroup({ "Color" }),
_pColorMethod(ColorMethodInfo, properties::OptionProperty::DisplayType::Radio),
_pColorQuantity(ColorQuantityInfo, properties::OptionProperty::DisplayType::Dropdown),
_pColorQuantityMin(ColorQuantityMinInfo),
_pColorQuantityMax(ColorQuantityMaxInfo),
_pColorTablePath(ColorTablePathInfo),
_pColorUniform(ColorUniformInfo, glm::vec4(0.75f, 0.5f, 0.0f, 0.5f),
glm::vec4(0.f), glm::vec4(1.f)),
_pFlowColor(FlowColorInfo, glm::vec4(0.8f, 0.7f, 0.0f, 0.6f),
glm::vec4(0.f), glm::vec4(1.f)),
_pFlowEnabled(FlowEnabledInfo, true),
_pFlowGroup({ "Flow" }),
_pFlowParticleSize(FlowParticleSizeInfo, 5, 0, 500),
_pFlowParticleSpacing(FlowParticleSpacingInfo, 60, 0, 500),
_pFlowReversed(FlowReversedInfo, false),
_pFlowSpeed(FlowSpeedInfo, 20, 0, 1000),
_pFocusOnOriginBtn(OriginButtonInfo),
_pJumpToStartBtn(TimeJumpButtonInfo) {
_dictionary = std::make_unique<ghoul::Dictionary>(dictionary);
// Set the default color table, just in case user defined paths are corrupt!
_transferFunction = std::make_shared<TransferFunction>(absPath(_colorTablePaths[0]));
}
void RenderableFieldlinesSequence::initialize() {
LINFO("RenderableFieldlinesSequence::initialize()");
if (!extractInfoFromDictionary(*_dictionary)) {
_sourceFileType = SourceFileType::INVALID;
}
// dictionary is no longer necessary as everything is extracted
_dictionary.reset();
switch (_sourceFileType) {
case CDF:
LERROR("CDF NOT YET IMPLEMENTED!"); return;
break;
case JSON:
LERROR("JSON NOT YET IMPLEMENTED!"); return;
break;
case OSFLS:
if (_loadingStatesDynamically) {
extractTriggerTimesFromFileNames();
FieldlinesState newState;
bool loadedSuccessfully = newState.loadStateFromOsfls(_sourceFiles[0]);
if (loadedSuccessfully) {
_states.push_back(newState);
_nStates = _startTimes.size();
_activeStateIndex = 0;
} else {
LERROR("The provided .osfls files seem to be corrupt!");
_sourceFileType = SourceFileType::INVALID;
}
} else {
// Load states into RAM!
for (std::string filePath : _sourceFiles) {
FieldlinesState newState;
bool loadedSuccessfully = newState.loadStateFromOsfls(filePath);
if (loadedSuccessfully) {
_states.push_back(newState);
_startTimes.push_back(newState.triggerTime());
_nStates++;
}
}
}
break;
default:
return;
}
// At this point there's at least one state loaded into memory!
// No need to store source paths in memory if they are already in RAM!
if (!_loadingStatesDynamically) {
_sourceFiles.clear();
}
computeSequenceEndTime();
setupProperties();
// Setup shader program
_shaderProgram = OsEng.renderEngine().buildRenderProgram(
"FieldlinesSequence",
"${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_vs.glsl",
"${MODULE_FIELDLINESSEQUENCE}/shaders/fieldlinessequence_fs.glsl"
);
if (!_shaderProgram) {
LERROR("Shader program failed initialization!");
_sourceFileType = SourceFileType::INVALID;
}
//------------------ Initialize OpenGL VBOs and VAOs-------------------------------//
glGenVertexArrays(1, &_vertexArrayObject);
glGenBuffers(1, &_vertexPositionBuffer);
glGenBuffers(1, &_vertexColorBuffer);
}
bool RenderableFieldlinesSequence::extractInfoFromDictionary(
const ghoul::Dictionary& dictionary) {
std::string name;
dictionary.getValue(SceneGraphNode::KeyName, name);
_name = name;
name += ": ";
// ------------------- EXTRACT MANDATORY VALUES FROM DICTIONARY ------------------- //
std::string inputFileTypeString;
if (!dictionary.getValue(KEY_INPUT_FILE_TYPE, inputFileTypeString)) {
LERROR(name << "The field " << std::string(KEY_INPUT_FILE_TYPE) << " is missing!");
return false;
} else {
std::transform(inputFileTypeString.begin(), inputFileTypeString.end(),
inputFileTypeString.begin(), ::tolower);
// Verify that the input type is correct
if (inputFileTypeString == VALUE_INPUT_FILE_TYPE_CDF) {
_sourceFileType = CDF;
} else if (inputFileTypeString == VALUE_INPUT_FILE_TYPE_JSON) {
_sourceFileType = JSON;
} else if (inputFileTypeString == VALUE_INPUT_FILE_TYPE_OSFLS) {
_sourceFileType = OSFLS;
} else {
LERROR(name << inputFileTypeString << " is not a recognised "
<< KEY_INPUT_FILE_TYPE);
_sourceFileType = INVALID;
return false;
}
}
std::string sourceFolderPath;
if (!dictionary.getValue(KEY_SOURCE_FOLDER, sourceFolderPath)) {
LERROR(name << "The field " << std::string(KEY_SOURCE_FOLDER) << " is missing!");
return false;
}
// Ensure that the source folder exists and then extract
// the files with the same extension as <inputFileTypeString>
ghoul::filesystem::Directory sourceFolder(sourceFolderPath);
if (FileSys.directoryExists(sourceFolder)) {
// Extract all file paths from the provided folder (Non-recursively! Sorted!)
_sourceFiles = sourceFolder.readFiles(ghoul::Boolean::No, ghoul::Boolean::Yes);
// Remove all files that don't have <inputFileTypeString> as extension
_sourceFiles.erase(std::remove_if(_sourceFiles.begin(), _sourceFiles.end(),
[inputFileTypeString](std::string str) {
const size_t EXT_LENGTH = inputFileTypeString.length();
std::string sub = str.substr(str.length() - EXT_LENGTH, EXT_LENGTH);
std::transform(sub.begin(), sub.end(), sub.begin(), ::tolower);
return sub != inputFileTypeString;
}), _sourceFiles.end());
// Ensure that there are available and valid source files left
if (_sourceFiles.empty()) {
LERROR(name << sourceFolderPath << " contains no ." << inputFileTypeString
<< " files!");
return false;
}
} else {
LERROR(name << "FieldlinesSequence" << sourceFolderPath
<< " is not a valid directory!");
return false;
}
// ------------------- EXTRACT OPTIONAL VALUES FROM DICTIONARY ------------------- //
ghoul::Dictionary colorTablesPathsDictionary;
if (dictionary.getValue(KEY_COLOR_TABLE_PATHS, colorTablesPathsDictionary)) {
const size_t N_PROVIDED_PATHS = colorTablesPathsDictionary.size();
if (N_PROVIDED_PATHS > 0) {
// Clear the default! It is already specified in the transferFunction
_colorTablePaths.clear();
for (size_t i = 1; i <= N_PROVIDED_PATHS; ++i) {
_colorTablePaths.push_back(
colorTablesPathsDictionary.value<std::string>(std::to_string(i)));
}
}
}
ghoul::Dictionary colorTablesRangesDictionary;
if (dictionary.getValue(KEY_COLOR_TABLE_RANGES, colorTablesRangesDictionary)) {
const size_t N_PROVIDED_RANGES = colorTablesRangesDictionary.size();
for (size_t i = 1; i <= N_PROVIDED_RANGES; ++i) {
_colorTableRanges.push_back(
colorTablesRangesDictionary.value<glm::vec2>(std::to_string(i)));
}
} else {
_colorTableRanges.push_back(glm::vec2(0, 1));
}
// Extract info specific to each inputType
switch (_sourceFileType) {
case CDF:
LERROR(name << "CDF NOT YET IMPLEMENTED!");
break;
case JSON:
LERROR(name << "JSON NOT YET IMPLEMENTED!");
break;
case OSFLS: {
bool shouldLoadInRealtime = false;
if (dictionary.getValue(KEY_OSLFS_LOAD_AT_RUNTIME, shouldLoadInRealtime)) {
_loadingStatesDynamically = shouldLoadInRealtime;
} else {
LWARNING(name << KEY_OSLFS_LOAD_AT_RUNTIME <<
" isn't specified! States from OSFLS files will be stored in RAM!");
}
} break;
default:
break;
}
return true;
}
void RenderableFieldlinesSequence::setupProperties() {
// -------------- Add non-grouped properties (enablers and buttons) -------------- //
addProperty(_pFlowEnabled);
addProperty(_pFocusOnOriginBtn);
addProperty(_pJumpToStartBtn);
// ----------------------------- Add Property Groups ----------------------------- //
addPropertySubOwner(_pColorGroup);
addPropertySubOwner(_pFlowGroup);
// ------------------------- Add Properties to the groups ------------------------- //
_pColorGroup.addProperty(_pColorMethod);
_pColorGroup.addProperty(_pColorQuantity);
_pColorGroup.addProperty(_pColorQuantityMin);
_pColorGroup.addProperty(_pColorQuantityMax);
_pColorGroup.addProperty(_pColorTablePath);
_pColorGroup.addProperty(_pColorUniform);
_pFlowGroup.addProperty(_pFlowReversed);
_pFlowGroup.addProperty(_pFlowColor);
_pFlowGroup.addProperty(_pFlowParticleSize);
_pFlowGroup.addProperty(_pFlowParticleSpacing);
_pFlowGroup.addProperty(_pFlowSpeed);
// ----------------------- Add Options to OptionProperties ----------------------- //
_pColorMethod.addOption(ColorMethod::UNIFORM, "Uniform");
_pColorMethod.addOption(ColorMethod::BY_QUANTITY, "By Quantity");
/* Add option for each extra quantity. We assume that there are just as many names to
extra quantities as there are extra quantities. We also assume that all states in
the given sequence have the same extra quantities! */
const size_t N_EXTRA_QUANTITIES = _states[0].nExtraQuantities();
auto EXTRA_VARIABLE_NAMES_VEC = _states[0].extraQuantityNames();
for (int i = 0; i < N_EXTRA_QUANTITIES; ++i) {
_pColorQuantity.addOption(i, EXTRA_VARIABLE_NAMES_VEC[i]);
}
// Each quantity should have its own color table and color table range, no more, no less
_colorTablePaths.resize(N_EXTRA_QUANTITIES, _colorTablePaths.back());
_colorTableRanges.resize(N_EXTRA_QUANTITIES, _colorTableRanges.back());
definePropertyCallbackFunctions();
// Set defaults
_pColorQuantity = 0;
_pColorQuantityMin = std::to_string(_colorTableRanges[_pColorQuantity].x);
_pColorQuantityMax = std::to_string(_colorTableRanges[_pColorQuantity].y);
_pColorTablePath = _colorTablePaths[_pColorQuantity];
}
void RenderableFieldlinesSequence::definePropertyCallbackFunctions() {
// Add Property Callback Functions
_pColorQuantity.onChange([this] {
LDEBUG("CHANGED COLORING QUANTITY");
_shouldUpdateColorBuffer = true;
_pColorQuantityMin = std::to_string(_colorTableRanges[_pColorQuantity].x);
_pColorQuantityMax = std::to_string(_colorTableRanges[_pColorQuantity].y);
_pColorTablePath = _colorTablePaths[_pColorQuantity];
});
_pColorTablePath.onChange([this] {
_transferFunction->setPath(_pColorTablePath);
_colorTablePaths[_pColorQuantity] = _pColorTablePath;
});
_pColorQuantityMin.onChange([this] {
LDEBUG("CHANGED MIN VALUE");
float f = stringToFloat(_pColorQuantityMin, _colorTableRanges[_pColorQuantity].x);
_pColorQuantityMin = std::to_string(f);
_colorTableRanges[_pColorQuantity].x = f;
});
_pColorQuantityMax.onChange([this] {
LDEBUG("CHANGED MAX VALUE");
float f = stringToFloat(_pColorQuantityMax, _colorTableRanges[_pColorQuantity].y);
_pColorQuantityMax = std::to_string(f);
_colorTableRanges[_pColorQuantity].y = f;
});
_pFocusOnOriginBtn.onChange([this] {
LDEBUG("SET FOCUS NODE TO PARENT");
SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(_name);
if (!node) {
LWARNING("Could not find a node in scenegraph called '" << _name << "'");
return;
}
OsEng.navigationHandler().setFocusNode(node->parent());
OsEng.navigationHandler().resetCameraDirection();
});
_pJumpToStartBtn.onChange([this] {
LDEBUG("Jump in time to start of sequence!");
OsEng.timeManager().time().setTime(_startTimes[0]);
});
}
// Calculate expected end time.
void RenderableFieldlinesSequence::computeSequenceEndTime() {
if (_nStates > 1) {
const double LAST_TRIGGER_TIME = _startTimes[_nStates - 1];
const double SEQUENCE_DURATION = LAST_TRIGGER_TIME - _startTimes[0];
const double AVERAGE_STATE_DURATION = SEQUENCE_DURATION /
(static_cast<double>(_nStates) - 1.0);
_sequenceEndTime = LAST_TRIGGER_TIME + AVERAGE_STATE_DURATION;
} else {
// If there's just one state it should never disappear!
_sequenceEndTime = DBL_MAX;
}
}
// Extract J2000 time from file names
// Requires files to be named as such: 'YYYY-MM-DDTHH-MM-SS-XXX.osfls'
void RenderableFieldlinesSequence::extractTriggerTimesFromFileNames() {
const size_t FILENAME_SIZE = 23; // number of characters in filename (excluding '.osfls')
const size_t EXT_SIZE = 6; // size(".osfls")
for (const std::string& FILEPATH : _sourceFiles) {
const size_t STR_LENGTH = FILEPATH.size();
// Extract the filename from the path (without extension)
std::string timeString = FILEPATH.substr(STR_LENGTH - FILENAME_SIZE - EXT_SIZE,
FILENAME_SIZE - 1);
// Ensure the separators are correct
timeString.replace(4, 1, "-");
timeString.replace(7, 1, "-");
timeString.replace(13, 1, ":");
timeString.replace(16, 1, ":");
timeString.replace(19, 1, ".");
const double TRIGGER_TIME = Time::convertTime(timeString);
_startTimes.push_back(TRIGGER_TIME);
}
}
} // namespace openspace
+49
View File
@@ -0,0 +1,49 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2017 *
* *
* 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_FIELDLINESSEQUENCE___COMMONS___H__
#define __OPENSPACE_MODULE_FIELDLINESSEQUENCE___COMMONS___H__
#include <string>
namespace openspace {
namespace fls { // (F)ield(L)ines(S)equence
enum Model : int {
BATSRUS = 0,
ENLIL,
PFSS,
INVALID
};
const float A_U_TO_METER = 149597870700.f; // Astronomical Units
const float R_E_TO_METER = 6371000.f; // Earth radius
const float R_S_TO_METER = 695700000.f; // Sun radius
} // namespace fls
} // namespace openspace
#endif // __OPENSPACE_MODULE_FIELDLINESSEQUENCE___COMMONS___H__
@@ -28,6 +28,11 @@
#include <fstream>
namespace {
std::string _loggerCat = "FieldlinesState";
const int CURRENT_VERSION = 0;
}
namespace openspace {
FieldlinesState::FieldlinesState() {}
@@ -56,37 +61,37 @@ bool FieldlinesState::loadStateFromOsfls(const std::string& PATH_TO_OSFLS_FILE)
}
// Define tmp variables to store meta data in
size_t numLines;
size_t numPoints;
size_t numExtras;
size_t nLines;
size_t nPoints;
size_t nExtras;
size_t byteSizeAllNames;
// Read single value variables
ifs.read( reinterpret_cast<char*>(&_triggerTime), sizeof(double));
ifs.read( reinterpret_cast<char*>(&_model), sizeof(int));
ifs.read( reinterpret_cast<char*>(&_isMorphable), sizeof(bool));
ifs.read( reinterpret_cast<char*>(&numLines), sizeof(size_t));
ifs.read( reinterpret_cast<char*>(&numPoints), sizeof(size_t));
ifs.read( reinterpret_cast<char*>(&numExtras), sizeof(size_t));
ifs.read( reinterpret_cast<char*>(&nLines), sizeof(size_t));
ifs.read( reinterpret_cast<char*>(&nPoints), sizeof(size_t));
ifs.read( reinterpret_cast<char*>(&nExtras), sizeof(size_t));
ifs.read( reinterpret_cast<char*>(&byteSizeAllNames), sizeof(size_t));
// RESERVE/RESIZE vectors
// TODO: Do this without initializing values? Resize is slower than just using reserve, due to initialization of all values
_lineStart.resize(numLines);
_lineCount.resize(numLines);
_vertexPositions.resize(numPoints);
_extraQuantities.resize(numExtras);
_extraQuantityNames.reserve(numExtras);
_lineStart.resize(nLines);
_lineCount.resize(nLines);
_vertexPositions.resize(nPoints);
_extraQuantities.resize(nExtras);
_extraQuantityNames.reserve(nExtras);
// Read vertex position data
ifs.read( reinterpret_cast<char*>(_lineStart.data()), sizeof(GLint)*numLines);
ifs.read( reinterpret_cast<char*>(_lineCount.data()), sizeof(GLsizei)*numLines);
ifs.read( reinterpret_cast<char*>(_vertexPositions.data()), sizeof(glm::vec3)*numPoints);
ifs.read( reinterpret_cast<char*>(_lineStart.data()), sizeof(GLint)*nLines);
ifs.read( reinterpret_cast<char*>(_lineCount.data()), sizeof(GLsizei)*nLines);
ifs.read( reinterpret_cast<char*>(_vertexPositions.data()), sizeof(glm::vec3)*nPoints);
// Read all extra quantities
for (std::vector<float>& vec : _extraQuantities) {
vec.resize(numPoints);
ifs.read( reinterpret_cast<char*>(vec.data()), sizeof(float) * numPoints);
vec.resize(nPoints);
ifs.read( reinterpret_cast<char*>(vec.data()), sizeof(float) * nPoints);
}
// Read all extra quantities' names. Stored as multiple c-strings
@@ -97,7 +102,7 @@ bool FieldlinesState::loadStateFromOsfls(const std::string& PATH_TO_OSFLS_FILE)
delete[] s;
size_t offset = 0;
for (size_t i = 0; i < numExtras; ++i) {
for (size_t i = 0; i < nExtras; ++i) {
auto endOfVarName = allNamesInOne.find('\0', offset);
endOfVarName -= offset;
std::string varName = allNamesInOne.substr(offset, endOfVarName);
@@ -25,6 +25,8 @@
#ifndef __OPENSPACE_MODULE_FIELDLINESSEQUENCE___FIELDLINESSTATE___H__
#define __OPENSPACE_MODULE_FIELDLINESSEQUENCE___FIELDLINESSTATE___H__
#include <modules/fieldlinessequence/util/commons.h>
#include <ghoul/opengl/ghoul_gl.h>
#include <ghoul/glm.h>
@@ -37,12 +39,6 @@ namespace openspace {
class FieldlinesState {
public:
enum Model : int {
batsrus = 0,
enlil = 1,
pfss = 2
};
FieldlinesState();
FieldlinesState(const std::string& PATH_TO_OSFLS_FILE, bool& loadSucessful);
@@ -54,7 +50,7 @@ public:
const vector<GLsizei>& lineCount() const { return _lineCount; }
const vector<GLint>& lineStart() const { return _lineStart; }
size_t nExtraQuantities() const { return _extraQuantities.size(); }
Model model() const { return _model; }
fls::Model model() const { return _model; }
double triggerTime() const { return _triggerTime; }
const vector<glm::vec3>& vertexPositions() const { return _vertexPositions; }
@@ -62,15 +58,15 @@ public:
const vector<float>& extraQuantity(const size_t INDEX, bool& isSuccesful) const;
private:
bool _isMorphable = false;
double _triggerTime = -1.0;
Model _model;
bool _isMorphable = false;
double _triggerTime = -1.0;
fls::Model _model;
vector<glm::vec3> _vertexPositions;
vector<GLint> _lineStart;
vector<GLsizei> _lineCount;
vector<vector<float>> _extraQuantities;
vector<std::string> _extraQuantityNames;
vector<glm::vec3> _vertexPositions;
vector<GLint> _lineStart;
vector<GLsizei> _lineCount;
vector<vector<float>> _extraQuantities;
vector<std::string> _extraQuantityNames;
// TODO: Maybe introduce a vector containing seed point indices
};