From f442dd4f7c5f24fcf19b1d9793b999f9fee4de09 Mon Sep 17 00:00:00 2001 From: Oskar Carlbaum Date: Fri, 22 Sep 2017 04:30:44 +0200 Subject: [PATCH] Add functionality for coloring lines by different quantities --- .../renderablefieldlinessequence.cpp | 233 +++++++++++++++--- .../rendering/renderablefieldlinessequence.h | 55 +++-- .../shaders/fieldlinessequence_vs.glsl | 46 +++- .../util/fieldlinesstate.cpp | 13 + .../fieldlinessequence/util/fieldlinesstate.h | 30 ++- 5 files changed, 303 insertions(+), 74 deletions(-) diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp index bbf6fec31f..8a79820554 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.cpp @@ -29,9 +29,9 @@ #include #include - #include #include +#include using std::string; @@ -44,6 +44,8 @@ namespace { 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 ------------- // @@ -51,8 +53,26 @@ namespace { const char* VALUE_INPUT_FILE_TYPE_JSON = "json"; const char* VALUE_INPUT_FILE_TYPE_OSFLS = "osfls"; - static const openspace::properties::Property::PropertyInfo LineColorInfo = { - "lineColor", "Line Color", "Color of lines." + static const openspace::properties::Property::PropertyInfo ColorMethodInfo = { + "colorMethod", "Color Method", "Color lines uniformly or using color tables based on extra variables like e.g. temperature or particle density." + }; + static const openspace::properties::Property::PropertyInfo ColorQuantityInfo = { + "colorQuantity", "Quantity to Color By", "Quantity/variable 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", @@ -70,29 +90,37 @@ namespace { static const openspace::properties::Property::PropertyInfo FlowSpeedInfo = { "speed", "Speed", "Speed of the flow." }; - static const openspace::properties::Property::PropertyInfo FlowColorInfo = { - "color", "Color", "Color of particles." - }; + + enum ColorMethod { UNIFORM = 0, BY_QUANTITY }; } // namespace namespace openspace { RenderableFieldlinesSequence::RenderableFieldlinesSequence(const ghoul::Dictionary& dictionary) : Renderable(dictionary), - _lineColor(LineColorInfo, glm::vec4(0.75f, 0.5f, 0.0f, 0.5f), glm::vec4(0.f), glm::vec4(1.f)), - _flowGroup({ "Flow" }), + _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), - _flowReversed(ReverseFlowInfo, false), + _flowGroup({ "Flow" }), _flowParticleSize(ParticleSizeInfo, 5, 0, 500), _flowParticleSpacing(ParticleSpacingInfo, 60, 0, 500), - _flowSpeed(FlowSpeedInfo, 20, 0, 1000), - _flowColor(FlowColorInfo, glm::vec4(0.8f, 0.7f, 0.0f, 0.6f), - glm::vec4(0.f), glm::vec4(1.f)) { + _flowReversed(ReverseFlowInfo, false), + _flowSpeed(FlowSpeedInfo, 20, 0, 1000) { + + // Set the default color table, just in case user defined paths are corrupt! + _transferFunction = std::make_shared(absPath(_colorTablePaths[0])); if(!extractInfoFromDictionary(dictionary)) { _sourceFileType = INVALID; } - } void RenderableFieldlinesSequence::initialize() { @@ -133,16 +161,27 @@ void RenderableFieldlinesSequence::initialize() { break; } - // No need to store source paths in memory if their states are already in RAM! + // 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 - addProperty(_lineColor); + // --------------------- HANDLE PROPERTIES --------------------- // + // Add Property Groups + addPropertySubOwner(_colorGroup); addPropertySubOwner(_flowGroup); + + // 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); @@ -150,6 +189,52 @@ void RenderableFieldlinesSequence::initialize() { _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 variables as there are extra variables. We also assume that all states in the + // given sequence have the same extra variables! + const size_t N_EXTRA_QUANTITIES = _states[0].nExtraVariables(); + auto EXTRA_VARIABLE_NAMES_VEC = _states[0].extraVariableNames(); + 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); + }); + // Setup shader program _shaderProgram = OsEng.renderEngine().buildRenderProgram( "FieldlinesSequence", @@ -165,6 +250,7 @@ void RenderableFieldlinesSequence::initialize() { //------------------ Initialize OpenGL VBOs and VAOs-------------------------------// glGenVertexArrays(1, &_vertexArrayObject); glGenBuffers(1, &_vertexPositionBuffer); + glGenBuffers(1, &_vertexColorBuffer); } void RenderableFieldlinesSequence::deinitialize() { @@ -194,6 +280,7 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks& if (_activeTriggerTimeIndex != -1) { _shaderProgram->activate(); + // Calculate Model View MatrixProjection const glm::dmat4 ROT_MAT = glm::dmat4(data.modelTransform.rotation); // const glm::mat4 SCALE_TRANSFORM = glm::mat4(1.0); // TODO remove if no use const glm::dmat4 MODEL_MAT = @@ -205,7 +292,19 @@ void RenderableFieldlinesSequence::render(const RenderData& data, RendererTasks& _shaderProgram->setUniform("modelViewProjection", data.camera.sgctInternal.projectionMatrix() * glm::mat4(MODEL_VIEW_MAT)); - _shaderProgram->setUniform("lineColor", _lineColor); + + _shaderProgram->setUniform("colorMethod", _colorMethod); + _shaderProgram->setUniform("lineColor", _colorUniform); + + if (_colorMethod == ColorMethod::BY_QUANTITY) { + ghoul::opengl::TextureUnit textureUnit; + textureUnit.activate(); + _transferFunction->bind(); // Calls update internally + _shaderProgram->setUniform("colorTable", textureUnit); + _shaderProgram->setUniform("colorTableRange", + _colorTableRanges[_colorQuantity]); + } + // Flow/Particles _shaderProgram->setUniform("usingParticles", _flowEnabled); _shaderProgram->setUniform("flowColor", _flowColor); @@ -238,8 +337,8 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) { // Check if current time in OpenSpace is within sequence interval if (isWithinSequenceInterval(CURRENT_TIME)) { const int NEXT_IDX = _activeTriggerTimeIndex + 1; - if (_activeTriggerTimeIndex < 0 // true => Previous frame was not within the sequence interval - || CURRENT_TIME < _startTimes[_activeTriggerTimeIndex] // true => OpenSpace has stepped back to a time represented by another state + if (_activeTriggerTimeIndex < 0 // true => Previous frame was not within the sequence interval + || CURRENT_TIME < _startTimes[_activeTriggerTimeIndex] // true => OpenSpace has stepped back to a time represented by another state || (NEXT_IDX < _nStates && CURRENT_TIME >= _startTimes[NEXT_IDX])) { // true => OpenSpace has stepped forward to a time represented by another state updateActiveTriggerTimeIndex(CURRENT_TIME); @@ -275,30 +374,27 @@ void RenderableFieldlinesSequence::update(const UpdateData& data) { _states[0] = std::move(_newState); } - glBindVertexArray(_vertexArrayObject); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + updateVertexPositionBuffer(); - const std::vector& VERTEX_POS_VEC = - _states[_activeStateIndex].vertexPositions(); - - glBufferData(GL_ARRAY_BUFFER, VERTEX_POS_VEC.size() * sizeof(glm::vec3), - &VERTEX_POS_VEC.front(), GL_STATIC_DRAW); - - glEnableVertexAttribArray(_vertAttrVertexPos); - glVertexAttribPointer(_vertAttrVertexPos, 3, GL_FLOAT, GL_FALSE, 0, 0); - - // UNBIND - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + if (_states[_activeStateIndex].nExtraVariables() > 0) { + _shouldUpdateColorBuffer = true; + } else { + _colorMethod = ColorMethod::UNIFORM; + } // Everything is set and ready for rendering! - _needsUpdate = false; + _needsUpdate = false; _newStateIsReady = false; } + + if (_shouldUpdateColorBuffer) { + updateVertexColorBuffer(); + _shouldUpdateColorBuffer = false; + } } } -inline bool RenderableFieldlinesSequence::isWithinSequenceInterval(const double CURRENT_TIME) { +inline bool RenderableFieldlinesSequence::isWithinSequenceInterval(const double CURRENT_TIME) const { return (CURRENT_TIME >= _startTimes[0]) && (CURRENT_TIME < _sequenceEndTime); } @@ -327,6 +423,47 @@ void RenderableFieldlinesSequence::readNewState(const std::string& FILEPATH) { _isLoadingStateFromDisk = false; } +// Unbind buffers and arrays +inline void unbindGL() { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); +} + +void RenderableFieldlinesSequence::updateVertexPositionBuffer() { + glBindVertexArray(_vertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + + const std::vector& VERTEX_POS_VEC = + _states[_activeStateIndex].vertexPositions(); + + glBufferData(GL_ARRAY_BUFFER, VERTEX_POS_VEC.size() * sizeof(glm::vec3), + &VERTEX_POS_VEC.front(), GL_STATIC_DRAW); + + glEnableVertexAttribArray(_VA_POSITION); + glVertexAttribPointer(_VA_POSITION, 3, GL_FLOAT, GL_FALSE, 0, 0); + + unbindGL(); +} + +void RenderableFieldlinesSequence::updateVertexColorBuffer() { + glBindVertexArray(_vertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER, _vertexColorBuffer); + + bool isSuccessful; + const std::vector& QUANTITY_VEC = + _states[_activeStateIndex].extraVariable(_colorQuantity, isSuccessful); + + if (isSuccessful) { + glBufferData(GL_ARRAY_BUFFER, QUANTITY_VEC.size() * sizeof(float), + &QUANTITY_VEC.front(), GL_STATIC_DRAW); + + glEnableVertexAttribArray(_VA_COLOR); + glVertexAttribPointer(_VA_COLOR, 1, GL_FLOAT, GL_FALSE, 0, 0); + + unbindGL(); + } +} + bool RenderableFieldlinesSequence::extractInfoFromDictionary( const ghoul::Dictionary& dictionary) { @@ -390,6 +527,32 @@ bool RenderableFieldlinesSequence::extractInfoFromDictionary( 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::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( 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!"); diff --git a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h index 455c4f1f9a..06aff5c4e2 100644 --- a/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h +++ b/modules/fieldlinessequence/rendering/renderablefieldlinessequence.h @@ -27,8 +27,12 @@ #include +#include #include +#include #include +#include + #include @@ -59,8 +63,9 @@ private: int _activeStateIndex = -1; int _activeTriggerTimeIndex = -1; bool _isLoadingStatesAtRuntime = true; // False => loading osfls at runtime - bool _mustLoadNewStateFromDisk = false; // If still in same state as previous frame == false + 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; @@ -69,39 +74,53 @@ private: std::atomic _isLoadingStateFromDisk{false}; std::atomic _newStateIsReady{false}; - + std::shared_ptr _transferFunction; // Transfer funtion (tf) std::unique_ptr _shaderProgram; + std::string* _activeColorTable; + std::vector _colorTablePaths {"${OPENSPACE_DATA}/colortables/kroyw.txt"}; // Default in case user doesn't specify otherwise + std::vector _sourceFiles; // Stored in RAM if files are loaded at runtime, else emptied after initialization std::vector _startTimes; std::vector _states; - std::vector _sourceFiles; // Stored in RAM if files are loaded at runtime, else emptied after initialization + std::vector _colorTableRanges; // Values represents min & max values represented in the color table GLuint _vertexArrayObject = 0; GLuint _vertexPositionBuffer = 0; + GLuint _vertexColorBuffer = 0; // THESE MUST CORRESPOND TO THE SHADER PROGRAM // TODO: THIS CAN BE DETERMINED BY ASKING THE SHADER PROGRAM TOO - GLuint _vertAttrVertexPos = 0; + const GLuint _VA_POSITION = 0; + const GLuint _VA_COLOR = 1; // ----------------------------- Properties ----------------------------- - properties::Vec4Property _lineColor; // Uniform Field Line Color + properties::PropertyOwner _colorGroup; // Group to hold the color properties + properties::OptionProperty _colorMethod; // Uniform/transfer function/topology? + properties::OptionProperty _colorQuantity; // Index of the extra variable 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 _flowGroup; - properties::BoolProperty _flowEnabled; // Toggle flow [ON/OFF] - properties::BoolProperty _flowReversed; // Toggle flow direction [FORWARDS/BACKWARDS] - properties::IntProperty _flowParticleSize; // Size of simulated flow particles - properties::IntProperty _flowParticleSpacing; // Size of simulated flow particles - properties::IntProperty _flowSpeed; // Speed of simulated flow - properties::Vec4Property _flowColor; // Simulated particles' 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 - void computeSequenceEndTime(); - bool extractInfoFromDictionary(const ghoul::Dictionary& dictionary); - void extractTriggerTimesFromFileNames(); - void readNewState(const std::string& FILEPATH); + void computeSequenceEndTime(); + bool extractInfoFromDictionary(const ghoul::Dictionary& dictionary); + void extractTriggerTimesFromFileNames(); + void readNewState(const std::string& FILEPATH); - inline bool isWithinSequenceInterval(const double CURRENT_TIME); - inline void updateActiveTriggerTimeIndex(const double CURRENT_TIME); + inline bool isWithinSequenceInterval(const double CURRENT_TIME) const; + + void updateActiveTriggerTimeIndex(const double CURRENT_TIME); + void updateVertexPositionBuffer(); + void updateVertexColorBuffer(); }; } // namespace openspace diff --git a/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl b/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl index 906953c7b7..de0bd246a6 100644 --- a/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl +++ b/modules/fieldlinessequence/shaders/fieldlinessequence_vs.glsl @@ -24,21 +24,42 @@ #version __CONTEXT__ -uniform mat4 modelViewProjection; -uniform bool usingParticles; -uniform double time; -uniform int particleSize; -uniform int particleSpeed; -uniform int particleSpacing; -uniform vec4 flowColor; -uniform vec4 lineColor; +#include "PowerScaling/powerScaling_vs.hglsl" -layout(location = 0) in vec3 in_position; // in meters +// General Uniforms that's always needed +uniform vec4 lineColor; +uniform mat4 modelViewProjection; + +// Uniforms needed to color by quantity +uniform int colorMethod; +uniform sampler1D colorTable; +uniform vec2 colorTableRange; + +// Uniforms needed for Particle Flow +uniform vec4 flowColor; +uniform int particleSize; +uniform int particleSpeed; +uniform int particleSpacing; +uniform double time; +uniform bool usingParticles; + +layout(location = 0) in vec3 in_position; // Should be provided in meters +layout(location = 1) in float in_color_scalar; // The extra value used to color lines. Location must correspond to _VA_COLOR in renderablefieldlinessequence.h + +// These should correspond to the enum 'ColorMethod' in renderablefieldlinesequence.cpp +const int UNIFORM_COLOR = 0; +const int COLOR_BY_QUANTITY = 1; out vec4 vs_color; out float vs_depth; -#include "PowerScaling/powerScaling_vs.hglsl" + +vec4 getTransferFunctionColor() { + // Remap the color scalar to a [0,1] range + const float LOOK_UP_VAL = (in_color_scalar - colorTableRange.x) / + (colorTableRange.y - colorTableRange.x); + return texture(colorTable, LOOK_UP_VAL); +} bool isPartOfParticle(const double TIME, const int VERTEX_ID, const int PARTICLE_SIZE, const int PARTICLE_SPEED, const int PARTICLE_SPACING) { @@ -59,6 +80,11 @@ void main() { vs_color = lineColor; } + if (colorMethod == COLOR_BY_QUANTITY) { + const vec4 QUANTITY_COLOR = getTransferFunctionColor(); + vs_color = vec4(QUANTITY_COLOR.xyz, vs_color.a * QUANTITY_COLOR.a); + } + vec4 position_in_meters = vec4(in_position, 1); vec4 positionClipSpace = modelViewProjection * position_in_meters; gl_Position = z_normalization(positionClipSpace); diff --git a/modules/fieldlinessequence/util/fieldlinesstate.cpp b/modules/fieldlinessequence/util/fieldlinesstate.cpp index 6336736d58..89aa58ba06 100644 --- a/modules/fieldlinessequence/util/fieldlinesstate.cpp +++ b/modules/fieldlinessequence/util/fieldlinesstate.cpp @@ -108,4 +108,17 @@ bool FieldlinesState::loadStateFromOsfls(const std::string& PATH_TO_OSFLS_FILE) return true; } +// Returns one of the extra variable vectors, _extraVariables[INDEX]. +// If INDEX is out of scope an empty vector is returned and the referenced bool will be false. +const vector& FieldlinesState::extraVariable(const size_t INDEX, + bool& isSuccessful) const { + if (INDEX < _extraVariables.size()) { + isSuccessful = true; + return _extraVariables[INDEX]; + } + isSuccessful = false; + // return empty vector which goes out of scope hence unusable! + return std::vector(); +} + } // namespace openspace diff --git a/modules/fieldlinessequence/util/fieldlinesstate.h b/modules/fieldlinessequence/util/fieldlinesstate.h index e2145df1cf..b4088ccefd 100644 --- a/modules/fieldlinessequence/util/fieldlinesstate.h +++ b/modules/fieldlinessequence/util/fieldlinesstate.h @@ -31,6 +31,8 @@ #include #include +using std::vector; + namespace openspace { class FieldlinesState { @@ -46,23 +48,29 @@ public: bool loadStateFromOsfls(const std::string& PATH_TO_OSFLS_FILE); - // Getters - double triggerTime() { return _triggerTime; } - Model model() { return _model; } - const std::vector& vertexPositions() { return _vertexPositions; } - const std::vector& lineStart() { return _lineStart; } - const std::vector& lineCount() { return _lineCount; } + // ------------------------------GETTERS-----------------------------------------// + const vector>& extraVariables() const { return _extraVariables; } + const vector& extraVariableNames() const { return _extraVariableNames; } + const vector& lineCount() const { return _lineCount; } + const vector& lineStart() const { return _lineStart; } + size_t nExtraVariables() const { return _extraVariables.size(); } + Model model() const { return _model; } + double triggerTime() const { return _triggerTime; } + const vector& vertexPositions() const { return _vertexPositions; } + + // Special getter. Returns extraVariables[INDEX]. + const vector& extraVariable(const size_t INDEX, bool& isSuccesful) const; private: bool _isMorphable = false; double _triggerTime = -1.0; Model _model; - std::vector _vertexPositions; - std::vector _lineStart; - std::vector _lineCount; - std::vector> _extraVariables; - std::vector _extraVariableNames; + vector _vertexPositions; + vector _lineStart; + vector _lineCount; + vector> _extraVariables; + vector _extraVariableNames; // TODO: Maybe introduce a vector containing seed point indices };