diff --git a/data/scene/default.scene b/data/scene/default.scene index 3469171d1f..994cc7e3b4 100644 --- a/data/scene/default.scene +++ b/data/scene/default.scene @@ -26,6 +26,8 @@ function postInitialization() openspace.setPropertyValue("MilkyWay.renderable.segments", 50) openspace.printInfo("Done setting default values") + + openspace.iswa.addCdfFiles("${OPENSPACE_DATA}/cdflist.json"); end @@ -47,7 +49,7 @@ return { "uranus", "neptune", "stars", - -- "stars-denver", + --"stars-denver", "milkyway", -- "milkyway-eso", "constellationbounds", diff --git a/data/scene/iswa/tfs/ccmc-cdf.tf b/data/scene/iswa/tfs/ccmc-cdf.tf new file mode 100644 index 0000000000..0451db6977 --- /dev/null +++ b/data/scene/iswa/tfs/ccmc-cdf.tf @@ -0,0 +1,15 @@ +${SCENE}/iswa/tfs/red.jpg +${SCENE}/iswa/tfs/green.jpg +${SCENE}/iswa/tfs/blue.jpg +${SCENE}/iswa/tfs/red.jpg +${SCENE}/iswa/tfs/green.jpg +${SCENE}/iswa/tfs/blue.jpg +${SCENE}/iswa/tfs/red.jpg +${SCENE}/iswa/tfs/green.jpg +${SCENE}/iswa/tfs/blue.jpg +${SCENE}/iswa/tfs/red.jpg +${SCENE}/iswa/tfs/green.jpg +${SCENE}/iswa/tfs/blue.jpg +${SCENE}/iswa/tfs/colormap_hot.jpg +${SCENE}/iswa/tfs/colormap_hot.jpg +${SCENE}/iswa/tfs/colormap_hot.jpg \ No newline at end of file diff --git a/data/scene/iswa/tfs/default.tf b/data/scene/iswa/tfs/default.tf new file mode 100644 index 0000000000..98b5ef56b7 --- /dev/null +++ b/data/scene/iswa/tfs/default.tf @@ -0,0 +1 @@ +${SCENE}/iswa/tfs/colormap_hot.png \ No newline at end of file diff --git a/include/openspace/engine/downloadmanager.h b/include/openspace/engine/downloadmanager.h index bccf6aa963..ad9f6ec105 100644 --- a/include/openspace/engine/downloadmanager.h +++ b/include/openspace/engine/downloadmanager.h @@ -94,11 +94,6 @@ public: DownloadProgressCallback progressCallback = DownloadProgressCallback() ); - std::shared_ptr downloadToMemory( - const std::string& url, std::string& memoryBuffer, - DownloadFinishedCallback finishedCallback = DownloadFinishedCallback() - ); - std::future fetchFile( const std::string& url, SuccessCallback successCallback = SuccessCallback(), ErrorCallback errorCallback = ErrorCallback()); diff --git a/modules/iswa/CMakeLists.txt b/modules/iswa/CMakeLists.txt index f8688eed9f..a745fdb920 100644 --- a/modules/iswa/CMakeLists.txt +++ b/modules/iswa/CMakeLists.txt @@ -27,32 +27,40 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/util/iswamanager.h ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessor.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/cygnetplane.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessortext.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessorjson.h + ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessorkameleon.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswacygnet.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/dataplane.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/textureplane.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/kameleonplane.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/cygnetsphere.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/datasphere.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspacecygnet.h - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswagroup.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswabasegroup.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswadatagroup.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswakameleongroup.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/texturecygnet.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/datacygnet.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/util/iswamanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessortext.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessorjson.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/util/dataprocessorkameleon.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswacygnet.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/cygnetplane.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/dataplane.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/textureplane.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/kameleonplane.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/cygnetsphere.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/datasphere.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/screenspacecygnet.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswagroup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswabasegroup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswadatagroup.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/iswakameleongroup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/texturecygnet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/datacygnet.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/iswa/rendering/cygnetplane.cpp b/modules/iswa/rendering/cygnetplane.cpp deleted file mode 100644 index add4407c54..0000000000 --- a/modules/iswa/rendering/cygnetplane.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * -// * software and associated documentation files (the "Software"), to deal in the Software * -// * without restriction, including without limitation the rights to use, copy, modify, * -// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -// * permit persons to whom the Software is furnished to do so, subject to the following * -// * conditions: * -// * * -// * The above copyright notice and this permission notice shall be included in all copies * -// * or substantial portions of the Software. * -// * * -// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -// ****************************************************************************************/ - -#include -#include -#include -#include -#include - -namespace openspace{ - -CygnetPlane::CygnetPlane(const ghoul::Dictionary& dictionary) - :IswaCygnet(dictionary) - ,_quad(0) - ,_vertexPositionBuffer(0) -{} - -CygnetPlane::~CygnetPlane(){} - -bool CygnetPlane::createGeometry() { - glGenVertexArrays(1, &_quad); // generate array - glGenBuffers(1, &_vertexPositionBuffer); // generate buffer - - // ============================ - // GEOMETRY (quad) - // ============================ - // GLfloat x,y, z; - float s = _data->spatialScale.x; - const GLfloat x = s*_data->scale.x/2.0; - const GLfloat y = s*_data->scale.y/2.0; - const GLfloat z = s*_data->scale.z/2.0; - const GLfloat w = _data->spatialScale.w; - - const GLfloat vertex_data[] = { // square of two triangles (sigh) - // x y z w s t - -x, -y, -z, w, 0, 1, - x, y, z, w, 1, 0, - -x, ((x>0)?y:-y), z, w, 0, 0, - -x, -y, -z, w, 0, 1, - x, ((x>0)?-y:y), -z, w, 1, 1, - x, y, z, w, 1, 0, - }; - - glBindVertexArray(_quad); // bind array - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); // bind buffer - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); - - return true; -} - -bool CygnetPlane::destroyGeometry(){ - glDeleteVertexArrays(1, &_quad); - _quad = 0; - - glDeleteBuffers(1, &_vertexPositionBuffer); - _vertexPositionBuffer = 0; - - return true; -} - -void CygnetPlane::renderGeometry() const { - glBindVertexArray(_quad); - glDrawArrays(GL_TRIANGLES, 0, 6); -} - - - -} //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/cygnetsphere.cpp b/modules/iswa/rendering/cygnetsphere.cpp deleted file mode 100644 index 7a2df6d29c..0000000000 --- a/modules/iswa/rendering/cygnetsphere.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * -// * software and associated documentation files (the "Software"), to deal in the Software * -// * without restriction, including without limitation the rights to use, copy, modify, * -// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -// * permit persons to whom the Software is furnished to do so, subject to the following * -// * conditions: * -// * * -// * The above copyright notice and this permission notice shall be included in all copies * -// * or substantial portions of the Software. * -// * * -// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -// ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openspace{ - -CygnetSphere::CygnetSphere(const ghoul::Dictionary& dictionary) - :IswaCygnet(dictionary) - ,_sphere(nullptr) -{ - float radius; - dictionary.getValue("Radius", radius); - _radius = radius; - -} - -CygnetSphere::~CygnetSphere(){} - -bool CygnetSphere::createGeometry(){ - PowerScaledScalar radius = PowerScaledScalar(6.371f*_radius, 6.0); - int segments = 100; - _sphere = std::make_shared(radius, segments); - _sphere->initialize(); - return true; -} - -bool CygnetSphere::destroyGeometry(){ - _sphere = nullptr; - return true; -} - -void CygnetSphere::renderGeometry() const { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - _sphere->render(); -} - - - -} //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/datacygnet.cpp b/modules/iswa/rendering/datacygnet.cpp index c943966da1..9641cd7c2a 100644 --- a/modules/iswa/rendering/datacygnet.cpp +++ b/modules/iswa/rendering/datacygnet.cpp @@ -24,6 +24,12 @@ #include +#include +#include +#include +#include +#include + namespace { const std::string _loggerCat = "DataCygnet"; } @@ -32,8 +38,184 @@ namespace openspace{ DataCygnet::DataCygnet(const ghoul::Dictionary& dictionary) :IswaCygnet(dictionary) -{} + ,_dataProcessor(nullptr) + ,_dataOptions("dataOptions", "Data Options") +{ + addProperty(_dataOptions); + registerProperties(); +} DataCygnet::~DataCygnet(){} +bool DataCygnet::updateTexture(){ + + std::vector data = textureData(); + + if(data.empty()) + return false; + + bool texturesReady = false; + std::vector selectedOptions = _dataOptions.value(); + + for(int option: selectedOptions){ + float* values = data[option]; + if(!values) continue; + + if(!_textures[option]){ + std::unique_ptr texture = std::make_unique( + values, + _textureDimensions, + ghoul::opengl::Texture::Format::Red, + GL_RED, + GL_FLOAT, + ghoul::opengl::Texture::FilterMode::Linear, + ghoul::opengl::Texture::WrappingMode::ClampToEdge + ); + + if(texture){ + texture->uploadTexture(); + texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + _textures[option] = std::move(texture); + } + }else{ + _textures[option]->setPixelData(values); + _textures[option]->uploadTexture(); + } + texturesReady = true; + } + return texturesReady; +} + +bool DataCygnet::downloadTextureResource(){ + if(_futureObject.valid()) + return false; + + std::future future = IswaManager::ref().fetchDataCygnet(_data->id); + + if(future.valid()){ + _futureObject = std::move(future); + return true; + } + + return false; +} + +bool DataCygnet::updateTextureResource(){ + DownloadManager::MemoryFile dataFile = _futureObject.get(); + + if(dataFile.corrupted) + return false; + + _dataBuffer = std::string(dataFile.buffer, dataFile.size); + delete[] dataFile.buffer; + + return true; +} + +bool DataCygnet::readyToRender() const{ + return (!_textures.empty() && !_transferFunctions.empty()); +} + +/** + * Set both transfer function textures and data textures in same function so that they bind to + * the right texture units. If separate in to two functions a list of ghoul::TextureUnit + * needs to be passed as an argument to both. + */ +void DataCygnet::setTextureUniforms(){ + std::vector selectedOptions = _dataOptions.value(); + int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); + int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); + + // Set Textures + ghoul::opengl::TextureUnit txUnits[MAX_TEXTURES]; + int j = 0; + for(int option : selectedOptions){ + if(_textures[option]){ + txUnits[j].activate(); + _textures[option]->bind(); + _shader->setUniform( + "textures[" + std::to_string(j) + "]", + txUnits[j] + ); + + j++; + if(j >= MAX_TEXTURES) break; + } + } + + if(activeTextures > 0 && selectedOptions.back()>=(int)_transferFunctions.size()) + activeTransferfunctions = 1; + + ghoul::opengl::TextureUnit tfUnits[MAX_TEXTURES]; + j = 0; + + if((activeTransferfunctions == 1)){ + tfUnits[0].activate(); + _transferFunctions[0]->bind(); + _shader->setUniform( + "transferFunctions[0]", + tfUnits[0] + ); + }else{ + for(int option : selectedOptions){ + + if(_transferFunctions[option]){ + tfUnits[j].activate(); + _transferFunctions[option]->bind(); + _shader->setUniform( + "transferFunctions[" + std::to_string(j) + "]", + tfUnits[j] + ); + + j++; + if(j >= MAX_TEXTURES) break; + } + } + } + + _shader->setUniform("numTransferFunctions", activeTransferfunctions); + _shader->setUniform("numTextures", activeTextures); +} + + +void DataCygnet::readTransferFunctions(std::string tfPath){ + std::string line; + std::ifstream tfFile(absPath(tfPath)); + + std::vector> tfs; + + if(tfFile.is_open()){ + while(getline(tfFile, line)){ + std::shared_ptr tf = std::make_shared(absPath(line)); + if(tf){ + tfs.push_back(tf); + } + } + + tfFile.close(); + } + + if(!tfs.empty()){ + _transferFunctions.clear(); + _transferFunctions = tfs; + } +} + +void DataCygnet::fillOptions(std::string& source){ + std::vector options = _dataProcessor->readMetadata(source); + + for(int i=0; i(_group)->registerOptions(_dataOptions.options()); + _dataOptions.setValue(std::dynamic_pointer_cast(_group)->dataOptionsValue()); + } else { + _dataOptions.setValue(std::vector(1,0)); + } +} + + } //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/datacygnet.h b/modules/iswa/rendering/datacygnet.h index beeab0ecf3..4926948a1f 100644 --- a/modules/iswa/rendering/datacygnet.h +++ b/modules/iswa/rendering/datacygnet.h @@ -26,14 +26,67 @@ #define __DATACYGNET_H__ #include +#include + +namespace { + const int MAX_TEXTURES = 6; +} namespace openspace{ +/** + * This class abstracts away the the loading of data and creation of + * textures for all data cygnets. It specifies the interface that needs to + * be implemented for all concrete subclasses + */ class DataCygnet : public IswaCygnet { public: DataCygnet(const ghoul::Dictionary& dictionary); ~DataCygnet(); protected: + bool updateTexture() override; + void fillOptions(std::string& source); + + /** + * loads the transferfunctions specified in tfPath into + * _transferFunctions list. + * + * @param tfPath Path to transfer function file + */ + void readTransferFunctions(std::string tfPath); + + /** + * This function binds and sets all textures that should go to the + * shader program, this includes both the data and transferfunctions. + */ + void setTextureUniforms(); + /** + * Optional interface method. this has an implementation + * in datacygnet.cpp, but needs to be overriden for kameleonplane + */ + virtual bool updateTextureResource() override; + + // Subclass interface. + // =================== + virtual bool createGeometry() = 0; + virtual bool destroyGeometry() = 0; + virtual void renderGeometry() const = 0; + /** + * This function should return the processed data that + * will populate the texture + */ + virtual std::vector textureData() = 0; + // This function can call parent setTextureUniforms() + virtual void setUniforms() = 0; + + properties::SelectionProperty _dataOptions; + std::shared_ptr _dataProcessor; + std::string _dataBuffer; + glm::size3_t _textureDimensions; + +private: + bool readyToRender() const override; + bool downloadTextureResource() override; }; } //namespace openspace diff --git a/modules/iswa/rendering/dataplane.cpp b/modules/iswa/rendering/dataplane.cpp index df8587ae4d..fb721d080e 100644 --- a/modules/iswa/rendering/dataplane.cpp +++ b/modules/iswa/rendering/dataplane.cpp @@ -22,42 +22,23 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace { const std::string _loggerCat = "DataPlane"; - const int MAX_TEXTURES = 6; } namespace openspace { DataPlane::DataPlane(const ghoul::Dictionary& dictionary) - :CygnetPlane(dictionary) + :DataCygnet(dictionary) ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", true) + ,_useHistogram("useHistogram", "Auto Contrast", false) ,_autoFilter("autoFilter", "Auto Filter", true) ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) - ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") - ,_dataOptions("dataOptions", "Data Options") - ,_dataProcessor(nullptr) + ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/default.tf") { - std::string name; - dictionary.getValue("Name", name); - setName(name); - - registerProperties(); addProperty(_useLog); addProperty(_useHistogram); @@ -65,9 +46,6 @@ DataPlane::DataPlane(const ghoul::Dictionary& dictionary) addProperty(_normValues); addProperty(_backgroundValues); addProperty(_transferFunctionsFile); - addProperty(_dataOptions); - - _type = IswaManager::CygnetType::Data; _programName = "DataPlaneProgram"; _vsPath = "${MODULE_ISWA}/shaders/dataplane_vs.glsl"; @@ -81,59 +59,7 @@ bool DataPlane::initialize(){ if(_group){ _dataProcessor = _group->dataProcessor(); - - _groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ - LDEBUG(name() + " Event useLogChanged"); - _useLog.setValue(dict.value("useLog")); - }); - - _groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event normValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("normValues", values); - if(success){ - _normValues.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event useHistogramChanged"); - _useHistogram.setValue(dict.value("useHistogram")); - }); - - _groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event dataOptionsChanged"); - std::shared_ptr > values; - bool success = dict.getValue("dataOptions", values); - if(success){ - _dataOptions.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event transferFunctionsChanged"); - _transferFunctionsFile.setValue(dict.value("transferFunctions")); - }); - - _groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event backgroundValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("backgroundValues", values); - if(success){ - _backgroundValues.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event autoFilterChanged"); - _autoFilter.setValue(dict.value("autoFilter")); - }); - - _groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event updateGroup"); - loadTexture(); - }); - + subscribeToGroup(); }else{ OsEng.gui()._iswa.registerProperty(&_useLog); OsEng.gui()._iswa.registerProperty(&_useHistogram); @@ -142,225 +68,188 @@ bool DataPlane::initialize(){ OsEng.gui()._iswa.registerProperty(&_backgroundValues); OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_dataOptions); - _dataProcessor = std::make_shared( - _useLog.value(), - _useHistogram.value(), - _normValues - ); + _dataProcessor = std::make_shared(); + + //If autofiler is on, background values property should be hidden + _autoFilter.onChange([this](){ + // If autofiler is selected, use _dataProcessor to set backgroundValues + // and unregister backgroundvalues property. + if(_autoFilter.value()){ + _backgroundValues.setValue(_dataProcessor->filterValues()); + OsEng.gui()._iswa.unregisterProperty(&_backgroundValues); + // else if autofilter is turned off, register backgroundValues + } else { + OsEng.gui()._iswa.registerProperty(&_backgroundValues, &_autoFilter); + } + }); } - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); _normValues.onChange([this](){ _dataProcessor->normValues(_normValues.value()); - loadTexture(); + updateTexture(); }); _useLog.onChange([this](){ _dataProcessor->useLog(_useLog.value()); - loadTexture(); + updateTexture(); }); _useHistogram.onChange([this](){ _dataProcessor->useHistogram(_useHistogram.value()); - loadTexture(); + updateTexture(); + if(_autoFilter.value()) + _backgroundValues.setValue(_dataProcessor->filterValues()); }); _dataOptions.onChange([this](){ if(_dataOptions.value().size() > MAX_TEXTURES) LWARNING("Too many options chosen, max is " + std::to_string(MAX_TEXTURES)); - loadTexture(); + updateTexture(); }); _transferFunctionsFile.onChange([this](){ - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); }); + _autoFilter.setValue(true); + return true; } -bool DataPlane::loadTexture() { - // if The future is done then get the new dataFile - if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ - DownloadManager::MemoryFile dataFile = _futureObject.get(); - - if(dataFile.corrupted) - return false; - - _dataBuffer = ""; - _dataBuffer.append(dataFile.buffer, dataFile.size); - delete[] dataFile.buffer; - } - - // if the buffer in the datafile is empty, do not proceed - if(_dataBuffer.empty()) - return false; - - if(!_dataOptions.options().size()){ // load options for value selection - fillOptions(); - _dataProcessor->addValues(_dataBuffer, _dataOptions); - - if(_group) - _group->updateGroup(); - } - - std::vector data = _dataProcessor->readData2(_dataBuffer, _dataOptions); - - if(data.empty()) - return false; - - if(_autoFilter.value()) - _backgroundValues.setValue(_dataProcessor->filterValues()); +bool DataPlane::createGeometry() { + glGenVertexArrays(1, &_quad); // generate array + glGenBuffers(1, &_vertexPositionBuffer); // generate buffer - bool texturesReady = false; - std::vector selectedOptions = _dataOptions.value(); + // ============================ + // GEOMETRY (quad) + // ============================ + // GLfloat x,y, z; + float s = _data->spatialScale.x; + const GLfloat x = s*_data->scale.x/2.0; + const GLfloat y = s*_data->scale.y/2.0; + const GLfloat z = s*_data->scale.z/2.0; + const GLfloat w = _data->spatialScale.w; - for(int option: selectedOptions){ - float* values = data[option]; - if(!values) continue; + const GLfloat vertex_data[] = { // square of two triangles (sigh) + // x y z w s t + -x, -y, -z, w, 0, 1, + x, y, z, w, 1, 0, + -x, ((x>0)?y:-y), z, w, 0, 0, + -x, -y, -z, w, 0, 1, + x, ((x>0)?-y:y), -z, w, 1, 1, + x, y, z, w, 1, 0, + }; - if(!_textures[option]){ - std::unique_ptr texture = std::make_unique( - values, - _dataProcessor->dimensions(), - ghoul::opengl::Texture::Format::Red, - GL_RED, - GL_FLOAT, - ghoul::opengl::Texture::FilterMode::Linear, - ghoul::opengl::Texture::WrappingMode::ClampToEdge - ); - - if(texture){ - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - _textures[option] = std::move(texture); - } - }else{ - _textures[option]->setPixelData(values); - _textures[option]->uploadTexture(); - } - texturesReady = true; - } - - return texturesReady; + glBindVertexArray(_quad); // bind array + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); + return true; } -bool DataPlane::updateTexture(){ - if(_futureObject.valid()) - return false; +bool DataPlane::destroyGeometry(){ + glDeleteVertexArrays(1, &_quad); + _quad = 0; - std::future future = IswaManager::ref().fetchDataCygnet(_data->id); + glDeleteBuffers(1, &_vertexPositionBuffer); + _vertexPositionBuffer = 0; - if(future.valid()){ - _futureObject = std::move(future); - return true; - } - - return false; + return true; } -bool DataPlane::readyToRender() const { - return (!_textures.empty()); +void DataPlane::renderGeometry() const { + glBindVertexArray(_quad); + glDrawArrays(GL_TRIANGLES, 0, 6); } -void DataPlane::setUniformAndTextures(){ - std::vector selectedOptions = _dataOptions.value(); - int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); - int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); - - ghoul::opengl::TextureUnit txUnits[6]; - int j = 0; - for(int option : selectedOptions){ - if(_textures[option]){ - txUnits[j].activate(); - _textures[option]->bind(); - _shader->setUniform( - "textures[" + std::to_string(j) + "]", - txUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - - if(activeTextures > 0){ - if(selectedOptions.back()>=activeTransferfunctions) - activeTransferfunctions = 1; - } - - ghoul::opengl::TextureUnit tfUnits[6]; - j = 0; - - if((activeTransferfunctions == 1)){ - tfUnits[0].activate(); - _transferFunctions[0]->bind(); - _shader->setUniform( - "transferFunctions[0]", - tfUnits[0] - ); - }else{ - for(int option : selectedOptions){ - // std::cout << option << std::endl; - // if(option >= activeTransferfunctions){ - // // LWARNING("No transfer function for this value."); - // break; - // } - - if(_transferFunctions[option]){ - tfUnits[j].activate(); - _transferFunctions[option]->bind(); - _shader->setUniform( - "transferFunctions[" + std::to_string(j) + "]", - tfUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - } - - _shader->setUniform("numTextures", activeTextures); - _shader->setUniform("numTransferFunctions", activeTransferfunctions); +void DataPlane::setUniforms(){ + // set both data texture and transfer function texture + setTextureUniforms(); _shader->setUniform("backgroundValues", _backgroundValues.value()); _shader->setUniform("transparency", _alpha.value()); } -void DataPlane::setTransferFunctions(std::string tfPath){ - std::string line; - std::ifstream tfFile(absPath(tfPath)); +std::vector DataPlane::textureData(){ + // if the buffer in the datafile is empty, do not proceed + if(_dataBuffer.empty()) + return std::vector(); - std::vector> tfs; + if(!_dataOptions.options().size()){ // load options for value selection + fillOptions(_dataBuffer); + _dataProcessor->addDataValues(_dataBuffer, _dataOptions); - if(tfFile.is_open()){ - while(getline(tfFile, line)){ - std::shared_ptr tf = std::make_shared(absPath(line)); - if(tf){ - tfs.push_back(tf); - } + // if this datacygnet has added new values then reload texture + // for the whole group, including this datacygnet, and return after. + if(_group){ + _group->updateGroup(); + return std::vector(); } - - tfFile.close(); - } - - - if(!tfs.empty()){ - _transferFunctions.clear(); - _transferFunctions = tfs; } + _textureDimensions = _dataProcessor->dimensions(); + return _dataProcessor->processData(_dataBuffer, _dataOptions); } -void DataPlane::fillOptions(){ - std::vector options = _dataProcessor->readHeader(_dataBuffer); - for(int i=0; i(1,0)); - if(_group) - _group->registerOptions(_dataOptions.options()); +void DataPlane::subscribeToGroup(){ + auto groupEvent = _group->groupEvent(); + groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ + LDEBUG(name() + " Event useLogChanged"); + _useLog.setValue(dict.value("useLog")); + }); + + groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event normValuesChanged"); + glm::vec2 values; + bool success = dict.getValue("normValues", values); + if(success){ + _normValues.setValue(values); + } + }); + + groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event useHistogramChanged"); + _useHistogram.setValue(dict.value("useHistogram")); + }); + + groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event dataOptionsChanged"); + std::vector values; + bool success = dict.getValue >("dataOptions", values); + if(success){ + _dataOptions.setValue(values); + } + }); + + groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event transferFunctionsChanged"); + _transferFunctionsFile.setValue(dict.value("transferFunctions")); + }); + + groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event backgroundValuesChanged"); + glm::vec2 values; + bool success = dict.getValue("backgroundValues", values); + if(success){ + _backgroundValues.setValue(values); + } + }); + + groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event autoFilterChanged"); + _autoFilter.setValue(dict.value("autoFilter")); + }); + + groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event updateGroup"); + if(_autoFilter.value()) + _backgroundValues.setValue(_dataProcessor->filterValues()); + updateTexture(); + }); } }// namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/dataplane.h b/modules/iswa/rendering/dataplane.h index 6e38bbd832..59fb144e31 100644 --- a/modules/iswa/rendering/dataplane.h +++ b/modules/iswa/rendering/dataplane.h @@ -25,49 +25,47 @@ #ifndef __DATAPLANE_H__ #define __DATAPLANE_H__ -#include -#include +#include #include #include -#include namespace openspace{ -class IswaGroup; - -class DataPlane : public CygnetPlane { -friend class IswaGroup; - public: +/** + * DataPlane is a concrete IswaCygnet with data files as its input source. + * The class handles creation, destruction and rendering of a plane geometry. + * It also specifies what uniforms to use and what GUI properties it needs. + */ +class DataPlane : public DataCygnet { +friend class IswaBaseGroup; +public: DataPlane(const ghoul::Dictionary& dictionary); ~DataPlane(); bool initialize() override; - private: - virtual bool loadTexture() override; - virtual bool updateTexture() override; +private: - virtual bool readyToRender() const override; - virtual void setUniformAndTextures() override; + /** + * Creates a plane geometry + */ + bool createGeometry() override; + bool destroyGeometry() override; + void renderGeometry() const override; + void setUniforms() override; + std::vector textureData() override; + void subscribeToGroup(); - void setTransferFunctions(std::string tfPath); - void fillOptions(); - - properties::SelectionProperty _dataOptions; properties::StringProperty _transferFunctionsFile; properties::Vec2Property _backgroundValues; - properties::Vec2Property _normValues; - properties::BoolProperty _useLog; properties::BoolProperty _useHistogram; properties::BoolProperty _autoFilter; - std::string _dataBuffer; + GLuint _quad; + GLuint _vertexPositionBuffer; +}; - std::shared_ptr _dataProcessor; - - }; - - } // namespace openspace +} // namespace openspace #endif //__DATAPLANE_H__ \ No newline at end of file diff --git a/modules/iswa/rendering/datasphere.cpp b/modules/iswa/rendering/datasphere.cpp index 454efc6dd8..f68a267101 100644 --- a/modules/iswa/rendering/datasphere.cpp +++ b/modules/iswa/rendering/datasphere.cpp @@ -23,35 +23,28 @@ ****************************************************************************************/ #include -#include -#include -#include -#include -#include - +#include +#include namespace { const std::string _loggerCat = "DataSphere"; - const int MAX_TEXTURES = 6; } namespace openspace { DataSphere::DataSphere(const ghoul::Dictionary& dictionary) - :CygnetSphere(dictionary) + :DataCygnet(dictionary) ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", true) - ,_autoFilter("autoFilter", "Auto Filter", true) + ,_useHistogram("useHistogram", "Auto Contrast", false) + ,_autoFilter("autoFilter", "Auto Filter", false) ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) - ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") - ,_dataOptions("dataOptions", "Data Options") + ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/default.tf") + ,_sphere(nullptr) { - std::string name; - dictionary.getValue("Name", name); - setName(name); - - registerProperties(); + float radius; + dictionary.getValue("Radius", radius); + _radius = radius; addProperty(_useLog); addProperty(_useHistogram); @@ -59,9 +52,6 @@ DataSphere::DataSphere(const ghoul::Dictionary& dictionary) addProperty(_normValues); addProperty(_backgroundValues); addProperty(_transferFunctionsFile); - addProperty(_dataOptions); - - _type = IswaManager::CygnetType::Data; _programName = "DataSphereProgram"; _vsPath = "${MODULE_ISWA}/shaders/datasphere_vs.glsl"; @@ -75,311 +65,164 @@ bool DataSphere::initialize(){ if(_group){ _dataProcessor = _group->dataProcessor(); - - _groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ - LDEBUG(name() + " Event useLogChanged"); - _useLog.setValue(dict.value("useLog")); - }); - - _groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event normValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("normValues", values); - if(success){ - _normValues.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event useHistogramChanged"); - _useHistogram.setValue(dict.value("useHistogram")); - }); - - _groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event dataOptionsChanged"); - std::shared_ptr > values; - bool success = dict.getValue("dataOptions", values); - if(success){ - _dataOptions.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event transferFunctionsChanged"); - _transferFunctionsFile.setValue(dict.value("transferFunctions")); - }); - - _groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event backgroundValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("backgroundValues", values); - if(success){ - _backgroundValues.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event autoFilterChanged"); - _autoFilter.setValue(dict.value("autoFilter")); - }); - - _groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event updateGroup"); - loadTexture(); - }); - + subscribeToGroup(); }else{ OsEng.gui()._iswa.registerProperty(&_useLog); OsEng.gui()._iswa.registerProperty(&_useHistogram); OsEng.gui()._iswa.registerProperty(&_autoFilter); - OsEng.gui()._iswa.registerProperty(&_normValues); OsEng.gui()._iswa.registerProperty(&_backgroundValues); + OsEng.gui()._iswa.registerProperty(&_normValues); OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_dataOptions); - _dataProcessor = std::make_shared( - _useLog.value(), - _useHistogram.value(), - _normValues - ); + + _dataProcessor = std::make_shared(); + //If autofiler is on, background values property should be hidden + _autoFilter.onChange([this](){ + // If autofiler is selected, use _dataProcessor to set backgroundValues + // and unregister backgroundvalues property. + if(_autoFilter.value()){ + _backgroundValues.setValue(_dataProcessor->filterValues()); + // else if autofilter is turned off, register backgroundValues + } else { + OsEng.gui()._iswa.registerProperty(&_backgroundValues, &_autoFilter); + } + }); } - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); _normValues.onChange([this](){ _dataProcessor->normValues(_normValues.value()); - loadTexture(); + updateTexture(); }); _useLog.onChange([this](){ _dataProcessor->useLog(_useLog.value()); - loadTexture(); + updateTexture(); }); _useHistogram.onChange([this](){ - _dataProcessor->useHistogram(_useHistogram.value()); - loadTexture(); + _dataProcessor->useHistogram(_useHistogram.value()); + updateTexture(); + if(_autoFilter.value()) + _backgroundValues.setValue(_dataProcessor->filterValues()); }); _dataOptions.onChange([this](){ if(_dataOptions.value().size() > MAX_TEXTURES) LWARNING("Too many options chosen, max is " + std::to_string(MAX_TEXTURES)); - loadTexture(); + updateTexture(); }); _transferFunctionsFile.onChange([this](){ - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); }); + _useHistogram.setValue(true); + _autoFilter.setValue(true); + return true; } -bool DataSphere::loadTexture(){ - - // if The future is done then get the new dataFile - if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ - DownloadManager::MemoryFile dataFile = _futureObject.get(); +bool DataSphere::createGeometry(){ + PowerScaledScalar radius = PowerScaledScalar(6.371f*_radius, 6.0); + int segments = 100; + _sphere = std::make_shared(radius, segments); + _sphere->initialize(); + return true; +} - if(dataFile.corrupted) - return false; +bool DataSphere::destroyGeometry(){ + _sphere = nullptr; + return true; +} - _dataBuffer = ""; - _dataBuffer.append(dataFile.buffer, dataFile.size); - delete[] dataFile.buffer; - } +void DataSphere::renderGeometry() const { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + _sphere->render(); +} +std::vector DataSphere::textureData(){ // if the buffer in the datafile is empty, do not proceed if(_dataBuffer.empty()) - return false; + return std::vector(); if(!_dataOptions.options().size()){ // load options for value selection - fillOptions(); - _dataProcessor->addValuesFromJSON(_dataBuffer, _dataOptions); + fillOptions(_dataBuffer); + _dataProcessor->addDataValues(_dataBuffer, _dataOptions); - if(_group) + // if this datacygnet has added new values then reload texture + // for the whole group, including this datacygnet, and return after. + if(_group){ _group->updateGroup(); - } - - std::vector data = _dataProcessor->readJSONData2(_dataBuffer, _dataOptions); - - if(data.empty()) - return false; - - if(_autoFilter.value()) - _backgroundValues.setValue(_dataProcessor->filterValues()); - - bool texturesReady = false; - std::vector selectedOptions = _dataOptions.value(); - - for(int option: selectedOptions){ - float* values = data[option]; - if(!values) continue; - - if(!_textures[option]){ - std::unique_ptr texture = std::make_unique( - values, - _dataProcessor->dimensions(), - ghoul::opengl::Texture::Format::Red, - GL_RED, - GL_FLOAT, - ghoul::opengl::Texture::FilterMode::Linear, - ghoul::opengl::Texture::WrappingMode::ClampToEdge - ); - - if(texture){ - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - _textures[option] = std::move(texture); - } - }else{ - _textures[option]->setPixelData(values); - _textures[option]->uploadTexture(); - } - texturesReady = true; - } - - // _dataBuffer = ""; - return texturesReady; -} - -bool DataSphere::updateTexture(){ - - if(_futureObject.valid()) - return false; - - std::future future = IswaManager::ref().fetchDataCygnet(_data->id); - - if(future.valid()){ - _futureObject = std::move(future); - return true; - } - - return false; -} - - -bool DataSphere::readyToRender() const { - return (!_textures.empty()); - - bool ready = isReady(); - ready &= (!_textures.empty() && _textures[0]); - ready &= (_sphere != nullptr); - return ready; -} - - -void DataSphere::setUniformAndTextures(){ - std::vector selectedOptions = _dataOptions.value(); - int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); - int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); - - ghoul::opengl::TextureUnit txUnits[10]; - int j = 0; - for(int option : selectedOptions){ - if(_textures[option]){ - txUnits[j].activate(); - _textures[option]->bind(); - _shader->setUniform( - "textures[" + std::to_string(j) + "]", - txUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - + return std::vector(); } } + _textureDimensions = _dataProcessor->dimensions(); + return _dataProcessor->processData(_dataBuffer, _dataOptions); +} - if(activeTextures > 0){ - if(selectedOptions.back()>=activeTransferfunctions) - activeTransferfunctions = 1; - } - - ghoul::opengl::TextureUnit tfUnits[10]; - j = 0; - - if((activeTransferfunctions == 1)){ - tfUnits[0].activate(); - _transferFunctions[0]->bind(); - _shader->setUniform( - "transferFunctions[0]", - tfUnits[0] - ); - }else{ - for(int option : selectedOptions){ - // std::cout << option << std::endl; - // if(option >= activeTransferfunctions){ - // // LWARNING("No transfer function for this value."); - // break; - // } - - if(_transferFunctions[option]){ - tfUnits[j].activate(); - _transferFunctions[option]->bind(); - _shader->setUniform( - "transferFunctions[" + std::to_string(j) + "]", - tfUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - } - - _shader->setUniform("numTextures", activeTextures); - _shader->setUniform("numTransferFunctions", activeTransferfunctions); +void DataSphere::setUniforms(){ + // set both data texture and transfer function texture + setTextureUniforms(); _shader->setUniform("backgroundValues", _backgroundValues.value()); _shader->setUniform("transparency", _alpha.value()); } +void DataSphere::subscribeToGroup(){ + auto groupEvent = _group->groupEvent(); + groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ + LDEBUG(name() + " Event useLogChanged"); + _useLog.setValue(dict.value("useLog")); + }); -// bool DataSphere::createShader(){ -// if (_shader == nullptr) { -// // Plane Program -// RenderEngine& renderEngine = OsEng.renderEngine(); -// _shader = renderEngine.buildRenderProgram( -// "DataSphereProgram", -// "${MODULE_ISWA}/shaders/datasphere_vs.glsl", -// "${MODULE_ISWA}/shaders/datasphere_fs.glsl"); -// if (!_shader) -// return false; -// } -// return true; -// } - -void DataSphere::setTransferFunctions(std::string tfPath){ - std::string line; - std::ifstream tfFile(absPath(tfPath)); - - std::vector> tfs; - - if(tfFile.is_open()){ - while(getline(tfFile, line)){ - std::shared_ptr tf = std::make_shared(absPath(line)); - if(tf){ - tfs.push_back(tf); - } + groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event normValuesChanged"); + glm::vec2 values; + bool success = dict.getValue("normValues", values); + if(success){ + _normValues.setValue(values); } - tfFile.close(); - } + }); + groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event useHistogramChanged"); + _useHistogram.setValue(dict.value("useHistogram")); + }); - if(!tfs.empty()){ - _transferFunctions.clear(); - _transferFunctions = tfs; - } -} + groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event dataOptionsChanged"); + std::vector values; + bool success = dict.getValue >("dataOptions", values); + if(success){ + _dataOptions.setValue(values); + } + }); -void DataSphere::fillOptions(){ - std::vector options = _dataProcessor->readJSONHeader(_dataBuffer); - for(int i=0; i(1,0)); - if(_group) - _group->registerOptions(_dataOptions.options()); - // IswaManager::ref().registerOptionsToGroup(_data->groupName, _dataOptions.options()); + groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event transferFunctionsChanged"); + _transferFunctionsFile.setValue(dict.value("transferFunctions")); + }); + + groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event backgroundValuesChanged"); + glm::vec2 values; + bool success = dict.getValue("backgroundValues", values); + if(success){ + _backgroundValues.setValue(values); + } + }); + + groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event autoFilterChanged"); + _autoFilter.setValue(dict.value("autoFilter")); + }); + + groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event updateGroup"); + updateTexture(); + }); } } //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/datasphere.h b/modules/iswa/rendering/datasphere.h index 094dd83335..6c96e263da 100644 --- a/modules/iswa/rendering/datasphere.h +++ b/modules/iswa/rendering/datasphere.h @@ -25,45 +25,45 @@ #ifndef __DATASPHERE_H__ #define __DATASPHERE_H__ -#include +#include #include #include -#include - namespace openspace{ class PowerScaledSphere; -class DataSphere : public CygnetSphere { -friend class IswaGroup; + +/** + * DataSphere is a concrete IswaCygnet with data files as its input source. + * The class handles creation, destruction and rendering of a sphere geometry. + * It also specifies what uniforms to use and what GUI properties it needs. + */ +class DataSphere : public DataCygnet { public: DataSphere(const ghoul::Dictionary& dictionary); ~DataSphere(); bool initialize() override; +protected: -private: - virtual bool loadTexture() override; - virtual bool updateTexture() override; + /** + * Creates a sphere geometry + */ + bool createGeometry() override; + bool destroyGeometry() override; + void renderGeometry() const override; + void setUniforms() override; + std::vector textureData() override; + void subscribeToGroup(); - virtual bool readyToRender() const override; - virtual void setUniformAndTextures() override; - - void setTransferFunctions(std::string tfPath); - void fillOptions(); - - properties::SelectionProperty _dataOptions; properties::StringProperty _transferFunctionsFile; properties::Vec2Property _backgroundValues; - properties::Vec2Property _normValues; - properties::BoolProperty _useLog; properties::BoolProperty _useHistogram; properties::BoolProperty _autoFilter; - - std::string _dataBuffer; - std::shared_ptr _dataProcessor; + std::shared_ptr _sphere; + float _radius; }; diff --git a/modules/iswa/rendering/iswabasegroup.cpp b/modules/iswa/rendering/iswabasegroup.cpp new file mode 100644 index 0000000000..e7fb9de70d --- /dev/null +++ b/modules/iswa/rendering/iswabasegroup.cpp @@ -0,0 +1,117 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +namespace { + const std::string _loggerCat = "IswaBaseGroup"; + using json = nlohmann::json; +} + +namespace openspace { +IswaBaseGroup::IswaBaseGroup(std::string name, std::string type) + :_enabled("enabled", "Enabled", true) + ,_alpha("alpha", "Alpha", 0.9f, 0.0f, 1.0f) + ,_delete("delete", "Delete") + ,_registered(false) + ,_type(type) + ,_dataProcessor(nullptr) +{ + setName(name); + + addProperty(_enabled); + addProperty(_alpha); + addProperty(_delete); + + _groupEvent = std::make_shared >(); + registerProperties(); +} + +IswaBaseGroup::~IswaBaseGroup(){} + +bool IswaBaseGroup::isType(std::string type){ + return (_type == type); +} + +void IswaBaseGroup::updateGroup(){ + LDEBUG("Group " + name() + " published updateGroup"); + _groupEvent->publish("updateGroup", ghoul::Dictionary()); + +} + +void IswaBaseGroup::clearGroup(){ + _groupEvent->publish("clearGroup", ghoul::Dictionary()); + LDEBUG("Group " + name() + " published clearGroup"); + unregisterProperties(); +} + +std::shared_ptr IswaBaseGroup::dataProcessor(){ + return _dataProcessor; +} + +std::shared_ptr > IswaBaseGroup::groupEvent(){ + return _groupEvent; +}; + + +void IswaBaseGroup::registerProperties(){ + OsEng.gui()._iswa.registerProperty(&_enabled); + OsEng.gui()._iswa.registerProperty(&_alpha); + + _enabled.onChange([this]{ + LDEBUG("Group " + name() + " published enabledChanged"); + _groupEvent->publish("enabledChanged", ghoul::Dictionary({{"enabled", _enabled.value()}})); + }); + + _alpha.onChange([this]{ + LDEBUG("Group " + name() + " published alphaChanged"); + _groupEvent->publish("alphaChanged", ghoul::Dictionary({{"alpha", _alpha.value()}})); + }); + + + OsEng.gui()._iswa.registerProperty(&_delete); + _delete.onChange([this]{ + clearGroup(); + }); + + _registered = true; +} + +void IswaBaseGroup::unregisterProperties(){ + OsEng.gui()._iswa.unregisterProperties(name()); + _registered = false; +} + +} //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/iswabasegroup.h b/modules/iswa/rendering/iswabasegroup.h new file mode 100644 index 0000000000..b69e75f3e9 --- /dev/null +++ b/modules/iswa/rendering/iswabasegroup.h @@ -0,0 +1,71 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* 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 __ISWAGROUP_H__ +#define __ISWAGROUP_H__ + +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include + + +namespace openspace{ +class IswaCygnet; + +class IswaBaseGroup : public properties::PropertyOwner{ +public: + IswaBaseGroup(std::string name, std::string type); + ~IswaBaseGroup(); + bool isType(std::string type); + + void updateGroup(); + virtual void clearGroup(); + + std::shared_ptr dataProcessor(); + std::shared_ptr > groupEvent(); + +protected: + void registerProperties(); + void unregisterProperties(); + + properties::BoolProperty _enabled; + properties::FloatProperty _alpha; + properties::TriggerProperty _delete; + + std::shared_ptr > _groupEvent; + std::shared_ptr _dataProcessor; + + bool _registered; + std::string _type; +}; + +} //namespace openspace +#endif \ No newline at end of file diff --git a/modules/iswa/rendering/iswacygnet.cpp b/modules/iswa/rendering/iswacygnet.cpp index 976d6c81ab..816b88ff42 100644 --- a/modules/iswa/rendering/iswacygnet.cpp +++ b/modules/iswa/rendering/iswacygnet.cpp @@ -24,10 +24,10 @@ #include #include #include -#include -#include #include #include +#include + namespace { const std::string _loggerCat = "IswaCygnet"; @@ -38,13 +38,15 @@ namespace openspace{ IswaCygnet::IswaCygnet(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _delete("delete", "Delete") - ,_alpha("alpha", "Alpha", 0.9f, 0.0f, 1.0f) + , _alpha("alpha", "Alpha", 0.9f, 0.0f, 1.0f) , _shader(nullptr) - ,_type(IswaManager::CygnetType::NoType) - ,_groupEvent() - ,_group(nullptr) - ,_textureDirty(false) + , _group(nullptr) + , _textureDirty(false) { + std::string name; + dictionary.getValue("Name", name); + setName(name); + _data = std::make_shared(); // dict.getValue can only set strings in _data directly @@ -86,26 +88,11 @@ IswaCygnet::IswaCygnet(const ghoul::Dictionary& dictionary) _data->scale = scale; _data->offset = offset; - // std::cout << std::to_string(min) << std::endl; - // std::cout << std::to_string(max) << std::endl; - // std::cout << std::to_string(_data->scale) << std::endl; - // std::cout << std::to_string(_data->offset) << std::endl; - addProperty(_alpha); addProperty(_delete); - // if(dictionary.hasValue("Group")){ dictionary.getValue("Group", _data->groupName); - // } - // _data->groupId = groupId; - // std::cout << _data->id << std::endl; - // std::cout << _data->frame << std::endl; - // std::cout << std::to_string(_data->offset) << std::endl; - // std::cout << std::to_string(_data->scale) << std::endl; - // std::cout << std::to_string(_data->max) << std::endl; - // std::cout << std::to_string(_data->min) << std::endl; - // std::cout << std::to_string(_data->spatialScale) << std::endl; - // OsEng.gui()._iswa.registerProperty(&_enabled); + } IswaCygnet::~IswaCygnet(){} @@ -127,16 +114,14 @@ bool IswaCygnet::initialize(){ initializeTime(); createGeometry(); createShader(); - updateTexture(); + downloadTextureResource(); return true; } bool IswaCygnet::deinitialize(){ if(!_data->groupName.empty()) - _groupEvent->unsubscribe(name()); - // IswaManager::ref().unregisterFromGroup(_data->groupName, this); - + _group->groupEvent()->unsubscribe(name()); unregisterProperties(); destroyGeometry(); @@ -178,7 +163,7 @@ void IswaCygnet::render(const RenderData& data){ setPscUniforms(*_shader.get(), data.camera, position); - setUniformAndTextures(); + setUniforms(); renderGeometry(); glEnable(GL_CULL_FACE); @@ -194,18 +179,20 @@ void IswaCygnet::update(const UpdateData& data){ (_realTime.count()-_lastUpdateRealTime.count()) > _minRealTimeUpdateInterval); if( _data->updateTime != 0 && (Time::ref().timeJumped() || timeToUpdate )){ - updateTexture(); + downloadTextureResource(); _lastUpdateRealTime = _realTime; _lastUpdateOpenSpaceTime = _openSpaceTime; } if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)) { - _textureDirty = true; + bool success = updateTextureResource(); + if(success) + _textureDirty = true; } if(_textureDirty) { - loadTexture(); + updateTexture(); _textureDirty = false; } @@ -245,7 +232,6 @@ void IswaCygnet::initializeTime(){ bool IswaCygnet::createShader(){ if (_shader == nullptr) { - // Plane Program RenderEngine& renderEngine = OsEng.renderEngine(); _shader = renderEngine.buildRenderProgram(_programName, _vsPath, @@ -257,21 +243,21 @@ bool IswaCygnet::createShader(){ } void IswaCygnet::initializeGroup(){ - _groupEvent = IswaManager::ref().groupEvent(_data->groupName, _type); - _group = IswaManager::ref().registerToGroup(_data->groupName, _type); + _group = IswaManager::ref().iswaGroup(_data->groupName); - //Subscribe to enable propert and delete - _groupEvent->subscribe(name(), "enabledChanged", [&](const ghoul::Dictionary& dict){ + //Subscribe to enable and delete property + auto groupEvent = _group->groupEvent(); + groupEvent->subscribe(name(), "enabledChanged", [&](const ghoul::Dictionary& dict){ LDEBUG(name() + " Event enabledChanged"); _enabled.setValue(dict.value("enabled")); }); - _groupEvent->subscribe(name(), "alphaChanged", [&](const ghoul::Dictionary& dict){ + groupEvent->subscribe(name(), "alphaChanged", [&](const ghoul::Dictionary& dict){ LDEBUG(name() + " Event alphaChanged"); _alpha.setValue(dict.value("alpha")); }); - _groupEvent->subscribe(name(), "clearGroup", [&](ghoul::Dictionary dict){ + groupEvent->subscribe(name(), "clearGroup", [&](ghoul::Dictionary dict){ LDEBUG(name() + " Event clearGroup"); OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + name() + "')"); }); diff --git a/modules/iswa/rendering/iswacygnet.h b/modules/iswa/rendering/iswacygnet.h index 13afd16813..8ee87f1ce4 100644 --- a/modules/iswa/rendering/iswacygnet.h +++ b/modules/iswa/rendering/iswacygnet.h @@ -30,26 +30,21 @@ #include #include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include +#include +#include #include #include +#include +#include +#include namespace openspace{ -class IswaGroup; +class IswaBaseGroup; struct Metadata { int id; @@ -69,7 +64,7 @@ struct Metadata { class IswaCygnet : public Renderable, public std::enable_shared_from_this { - friend class IswaGroup; + friend class IswaBaseGroup; public: IswaCygnet(const ghoul::Dictionary& dictionary); @@ -85,21 +80,51 @@ protected: void enabled(bool enabled){_enabled.setValue(enabled);}; + /** + * Registers the properties that are equal in all IswaCygnets + * regardless of being part of a group or not + */ void registerProperties(); void unregisterProperties(); void initializeTime(); void initializeGroup(); - bool destroyShader(); + /** + * Creates the shader program. Concrete IswaCygnets must set + * _vsPath, _fsPath and _programName before this function in called. + * @return true if successful creation + */ bool createShader(); + // Subclass interface + // ================== virtual bool createGeometry() = 0; virtual bool destroyGeometry() = 0; virtual void renderGeometry() const = 0; - - virtual bool loadTexture() = 0; + + /** + * Should create a new texture and populate the _textures vector + * @return true if update was successfull + */ virtual bool updateTexture() = 0; + /** + * Is called before updateTexture. For IswaCygnets getting data + * from a http request, this function should get the dataFile + * from the future object. + * @return true if update was successfull + */ + virtual bool updateTextureResource() = 0; + /** + * should send a http request to get the resource it needs to create + * a texture. For Texture cygnets, this should be an image. For DataCygnets, + * this should be the data file. + * @return true if update was successfull + */ + virtual bool downloadTextureResource() = 0; virtual bool readyToRender() const = 0; - virtual void setUniformAndTextures() = 0; + /** + * should set all uniforms needed to render + */ + virtual void setUniforms() = 0; properties::FloatProperty _alpha; properties::TriggerProperty _delete; @@ -121,16 +146,17 @@ protected: std::vector> _transferFunctions; std::future _futureObject; - std::shared_ptr > _groupEvent; + std::shared_ptr _group; - std::shared_ptr _group; - - IswaManager::CygnetType _type; bool _textureDirty; std::string _vsPath; std::string _fsPath; std::string _programName; + +private: + bool destroyShader(); + }; }//namespace openspace diff --git a/modules/iswa/rendering/iswadatagroup.cpp b/modules/iswa/rendering/iswadatagroup.cpp new file mode 100644 index 0000000000..fbe7bb9723 --- /dev/null +++ b/modules/iswa/rendering/iswadatagroup.cpp @@ -0,0 +1,154 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace { + const std::string _loggerCat = "IswaDataGroup"; + using json = nlohmann::json; +} + +namespace openspace{ +IswaDataGroup::IswaDataGroup(std::string name, std::string type) + :IswaBaseGroup(name, type) + ,_useLog("useLog","Use Logarithm", false) + + ,_useHistogram("useHistogram", "Auto Contrast", false) + ,_autoFilter("autoFilter", "Auto Filter", true) + ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) + ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) + ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/default.tf") + ,_dataOptions("dataOptions", "Data Options") +{ + addProperty(_useLog); + addProperty(_useHistogram); + addProperty(_autoFilter); + addProperty(_normValues); + addProperty(_backgroundValues); + addProperty(_transferFunctionsFile); + addProperty(_dataOptions); + + createDataProcessor(); + registerProperties(); +} + +IswaDataGroup::~IswaDataGroup(){} + +void IswaDataGroup::registerProperties(){ + OsEng.gui()._iswa.registerProperty(&_useLog); + OsEng.gui()._iswa.registerProperty(&_useHistogram); + OsEng.gui()._iswa.registerProperty(&_autoFilter); + if(!_autoFilter.value()) + OsEng.gui()._iswa.registerProperty(&_backgroundValues); + // OsEng.gui()._iswa.registerProperty(&_autoFilter); + OsEng.gui()._iswa.registerProperty(&_normValues); + OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); + OsEng.gui()._iswa.registerProperty(&_dataOptions); + + + _useLog.onChange([this]{ + LDEBUG("Group " + name() + " published useLogChanged"); + _groupEvent->publish("useLogChanged", ghoul::Dictionary({{"useLog", _useLog.value()}})); + }); + + _useHistogram.onChange([this]{ + LDEBUG("Group " + name() + " published useHistogramChanged"); + _groupEvent->publish("useHistogramChanged", ghoul::Dictionary({{"useHistogram", _useHistogram.value()}})); + }); + + //If autofiler is on, background values property should be hidden + _autoFilter.onChange([this](){ + LDEBUG("Group " + name() + " published autoFilterChanged"); + // If autofiler is selected, use _dataProcessor to set backgroundValues + // and unregister backgroundvalues property. + if(_autoFilter.value()){ + _backgroundValues.setValue(_dataProcessor->filterValues()); + OsEng.gui()._iswa.unregisterProperty(&_backgroundValues); + // else if autofilter is turned off, register backgroundValues + } else { + OsEng.gui()._iswa.registerProperty(&_backgroundValues, &_autoFilter); + } + _groupEvent->publish("autoFilterChanged", ghoul::Dictionary({{"autoFilter", _autoFilter.value()}})); + }); + + _normValues.onChange([this]{ + LDEBUG("Group " + name() + " published normValuesChanged"); + _groupEvent->publish("normValuesChanged", ghoul::Dictionary({{"normValues", _normValues.value()}})); + }); + + _backgroundValues.onChange([this]{ + LDEBUG("Group " + name() + " published backgroundValuesChanged"); + _groupEvent->publish("backgroundValuesChanged", ghoul::Dictionary({{"backgroundValues", _backgroundValues.value()}})); + }); + + _transferFunctionsFile.onChange([this]{ + LDEBUG("Group " + name() + " published transferFunctionsChanged"); + _groupEvent->publish("transferFunctionsChanged", ghoul::Dictionary({{"transferFunctions", _transferFunctionsFile.value()}})); + }); + + _dataOptions.onChange([this]{ + LDEBUG("Group " + name() + " published dataOptionsChanged"); + ghoul::Dictionary dict; + dict.setValue>("dataOptions", _dataOptions.value()); + _groupEvent->publish("dataOptionsChanged", dict); + }); +} + +void IswaDataGroup::registerOptions(const std::vector& options){ + if(!_registered) + registerProperties(); + + if(_dataOptions.options().empty()){ + for(auto option : options){ + _dataOptions.addOption({option.value, option.description}); + } + _dataOptions.setValue(std::vector(1,0)); + } +} + +void IswaDataGroup::createDataProcessor(){ + if(_type == typeid(DataPlane).name()){ + _dataProcessor = std::make_shared(); + }else if(_type == typeid(DataSphere).name()){ + _dataProcessor = std::make_shared(); + }else if(_type == typeid(KameleonPlane).name()){ + _dataProcessor = std::make_shared(); + } +} + +std::vector IswaDataGroup::dataOptionsValue(){ + return _dataOptions.value(); +} + +} //namespace openspace diff --git a/modules/iswa/rendering/iswadatagroup.h b/modules/iswa/rendering/iswadatagroup.h new file mode 100644 index 0000000000..d08b16506a --- /dev/null +++ b/modules/iswa/rendering/iswadatagroup.h @@ -0,0 +1,56 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* 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 __ISWADATAGROUP_H__ +#define __ISWADATAGROUP_H__ +#include + +namespace openspace{ +class IswaDataGroup : public IswaBaseGroup{ +public: + IswaDataGroup(std::string name, std::string type); + ~IswaDataGroup(); + + void registerOptions(const std::vector& options); + std::vector dataOptionsValue(); + +protected: + void registerProperties(); + void createDataProcessor(); + + // void readFieldlinePaths(std::string indexFile); + // void updateFieldlineSeeds(); + // void clearFieldlines(); + + properties::BoolProperty _useLog; + properties::BoolProperty _useHistogram; + properties::BoolProperty _autoFilter; + properties::Vec2Property _normValues; + properties::Vec2Property _backgroundValues; + properties::StringProperty _transferFunctionsFile; + properties::SelectionProperty _dataOptions; + +}; + +} //namespace openspace +#endif // __ISWADATAGROUP_H__ \ No newline at end of file diff --git a/modules/iswa/rendering/iswagroup.cpp b/modules/iswa/rendering/iswagroup.cpp index 79d72f6174..44fe7c20a9 100644 --- a/modules/iswa/rendering/iswagroup.cpp +++ b/modules/iswa/rendering/iswagroup.cpp @@ -21,97 +21,72 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include +#include #include #include -namespace { - const std::string _loggerCat = "IswaGroup"; - using json = nlohmann::json; +#include +#include +#include +#include +#include +#include + + +namespace { + const std::string _loggerCat = "IswaBaseGroup"; + using json = nlohmann::json; } namespace openspace { - -IswaGroup::IswaGroup(std::string name, IswaManager::CygnetType type) +IswaBaseGroup::IswaBaseGroup(std::string name, std::string type) :_enabled("enabled", "Enabled", true) ,_alpha("alpha", "Alpha", 0.9f, 0.0f, 1.0f) - ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", false) - ,_autoFilter("autoFilter", "Auto Filter", true) - ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) - ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) - ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") ,_delete("delete", "Delete") - ,_dataOptions("dataOptions", "Data Options") - ,_fieldlines("fieldlineSeedsIndexFile", "Fieldline Seedpoints") - ,_fieldlineIndexFile("") - ,_type(type) ,_registered(false) + ,_type(type) + ,_dataProcessor(nullptr) { setName(name); addProperty(_enabled); addProperty(_alpha); - - addProperty(_useLog); - addProperty(_useHistogram); - addProperty(_autoFilter); - addProperty(_normValues); - addProperty(_backgroundValues); - addProperty(_transferFunctionsFile); - addProperty(_dataOptions); - addProperty(_fieldlines); - addProperty(_delete); - _dataProcessor = std::make_shared( - _useLog.value(), - _useHistogram.value(), - _normValues - ); _groupEvent = std::make_shared >(); registerProperties(); + + _autoFilter.setValue(true); } -IswaGroup::~IswaGroup(){} +IswaBaseGroup::~IswaBaseGroup(){} - -void IswaGroup::registerOptions(const std::vector& options){ - if(!_registered){ - registerProperties(); } - if(_type == IswaManager::CygnetType::Data){ - if(_dataOptions.options().empty()){ - for(auto option : options){ - _dataOptions.addOption({option.value, option.description}); - } - _dataOptions.setValue(std::vector(1,0)); - } - } -} - -void IswaGroup::setFieldlineInfo(std::string fieldlineIndexFile, std::string kameleonPath){ - - if(fieldlineIndexFile != _fieldlineIndexFile){ - _fieldlineIndexFile = fieldlineIndexFile; - readFieldlinePaths(_fieldlineIndexFile); - } - - if(kameleonPath != _kameleonPath){ - _kameleonPath = kameleonPath; - clearFieldlines(); - updateFieldlineSeeds(); - } -} - -bool IswaGroup::isType(IswaManager::CygnetType type){ - if(_type == IswaManager::CygnetType::NoType) return true; +bool IswaBaseGroup::isType(std::string type){ return (_type == type); } -void IswaGroup::registerProperties(){ +void IswaBaseGroup::updateGroup(){ + _groupEvent->publish("updateGroup", ghoul::Dictionary()); +} + +void IswaBaseGroup::clearGroup(){ + _groupEvent->publish("clearGroup", ghoul::Dictionary()); + LDEBUG("Group " + name() + " published clearGroup"); + unregisterProperties(); +} + +std::shared_ptr IswaBaseGroup::dataProcessor(){ + return _dataProcessor; +} + +std::shared_ptr > IswaBaseGroup::groupEvent(){ + return _groupEvent; +}; + + +void IswaBaseGroup::registerProperties(){ OsEng.gui()._iswa.registerProperty(&_enabled); OsEng.gui()._iswa.registerProperty(&_alpha); @@ -125,146 +100,17 @@ void IswaGroup::registerProperties(){ _groupEvent->publish("alphaChanged", ghoul::Dictionary({{"alpha", _alpha.value()}})); }); - - if(_type == IswaManager::CygnetType::Data){ - OsEng.gui()._iswa.registerProperty(&_useLog); - OsEng.gui()._iswa.registerProperty(&_useHistogram); - OsEng.gui()._iswa.registerProperty(&_autoFilter); - OsEng.gui()._iswa.registerProperty(&_normValues); - OsEng.gui()._iswa.registerProperty(&_backgroundValues); - OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); - OsEng.gui()._iswa.registerProperty(&_fieldlines); - OsEng.gui()._iswa.registerProperty(&_dataOptions); - - _useLog.onChange([this]{ - LDEBUG("Group " + name() + " published useLogChanged"); - _groupEvent->publish("useLogChanged", ghoul::Dictionary({{"useLog", _useLog.value()}})); - }); - - _useHistogram.onChange([this]{ - LDEBUG("Group " + name() + " published useHistogramChanged"); - _groupEvent->publish("useHistogramChanged", ghoul::Dictionary({{"useHistogram", _useHistogram.value()}})); - }); - - _autoFilter.onChange([this]{ - LDEBUG("Group " + name() + " published autoFilterChanged"); - _groupEvent->publish("autoFilterChanged", ghoul::Dictionary({{"autoFilter", _autoFilter.value()}})); - }); - - _normValues.onChange([this]{ - LDEBUG("Group " + name() + " published normValuesChanged"); - _groupEvent->publish("normValuesChanged", ghoul::Dictionary({{"normValues", std::make_shared(_normValues.value())}})); - }); - - _backgroundValues.onChange([this]{ - LDEBUG("Group " + name() + " published backgroundValuesChanged"); - _groupEvent->publish("backgroundValuesChanged", ghoul::Dictionary({{"backgroundValues", std::make_shared(_backgroundValues.value())}})); - }); - - _transferFunctionsFile.onChange([this]{ - LDEBUG("Group " + name() + " published transferFunctionsChanged"); - _groupEvent->publish("transferFunctionsChanged", ghoul::Dictionary({{"transferFunctions", _transferFunctionsFile.value()}})); - }); - - _dataOptions.onChange([this]{ - LDEBUG("Group " + name() + " published dataOptionsChanged"); - _groupEvent->publish("dataOptionsChanged", ghoul::Dictionary({{"dataOptions", std::make_shared >(_dataOptions.value())}})); - }); - - _fieldlines.onChange([this]{ - updateFieldlineSeeds(); - // LDEBUG("Group " + name() + " published fieldlinesChanged"); - // _groupEvent->publish("fieldlinesChanged", ghoul::Dictionary({{"fieldlines", std::make_shared >(_fieldlines.value())}})); - }); - } - OsEng.gui()._iswa.registerProperty(&_delete); _delete.onChange([this]{ clearGroup(); }); + _registered = true; } -void IswaGroup::unregisterProperties(){ +void IswaBaseGroup::unregisterProperties(){ OsEng.gui()._iswa.unregisterProperties(name()); _registered = false; } -void IswaGroup::updateGroup(){ - _groupEvent->publish("updateGroup", ghoul::Dictionary()); -} - -void IswaGroup::clearGroup(){ - _groupEvent->publish("clearGroup", ghoul::Dictionary()); - LDEBUG("Group " + name() + " published clearGroup"); - unregisterProperties(); - clearFieldlines(); - -} - -std::shared_ptr IswaGroup::dataProcessor(){ - return _dataProcessor; -} - -void IswaGroup::updateFieldlineSeeds(){ - std::vector selectedOptions = _fieldlines.value(); - - // SeedPath == map > - for (auto& seedPath: _fieldlineState) { - // if this option was turned off - if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)==selectedOptions.end() && std::get<2>(seedPath.second)){ - LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second)); - OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')"); - std::get<2>(seedPath.second) = false; - // if this option was turned on - } else if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)!=selectedOptions.end() && !std::get<2>(seedPath.second)) { - LDEBUG("Created fieldlines: " + std::get<0>(seedPath.second)); - IswaManager::ref().createFieldline(std::get<0>(seedPath.second), _kameleonPath, std::get<1>(seedPath.second)); - std::get<2>(seedPath.second) = true; - } - } -} - -void IswaGroup::readFieldlinePaths(std::string indexFile){ - LINFO("Reading seed points paths from file '" << indexFile << "'"); - - // Read the index file from disk - std::ifstream seedFile(indexFile); - if (!seedFile.good()) - LERROR("Could not open seed points file '" << indexFile << "'"); - else { - std::string line; - std::string fileContent; - while (std::getline(seedFile, line)) { - fileContent += line; - } - - try{ - //Parse and add each fieldline as an selection - json fieldlines = json::parse(fileContent); - int i = 0; - - for (json::iterator it = fieldlines.begin(); it != fieldlines.end(); ++it) { - _fieldlines.addOption({i, name()+"/"+it.key()}); - _fieldlineState[i] = std::make_tuple(name()+"/"+it.key(), it.value(), false); - i++; - } - - } catch(const std::exception& e) { - LERROR("Error when reading json file with paths to seedpoints: " + std::string(e.what())); - } - } -} - -void IswaGroup::clearFieldlines(){ - // SeedPath == map > - for (auto& seedPath: _fieldlineState) { - if(std::get<2>(seedPath.second)){ - LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second)); - OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')"); - std::get<2>(seedPath.second) = false; - } - } -} - } //namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/iswagroup.h b/modules/iswa/rendering/iswagroup.h index 19a848e14d..b69e75f3e9 100644 --- a/modules/iswa/rendering/iswagroup.h +++ b/modules/iswa/rendering/iswagroup.h @@ -40,68 +40,31 @@ namespace openspace{ class IswaCygnet; -class IswaGroup : public properties::PropertyOwner{ +class IswaBaseGroup : public properties::PropertyOwner{ public: - IswaGroup(std::string name, IswaManager::CygnetType type); - ~IswaGroup(); - //void registerCygnet(IswaCygnet* cygnet, IswaManager::CygnetType type); - //void unregisterCygnet(IswaCygnet* cygnet); - void registerOptions(const std::vector& options); - void registerFieldLineOptions(const std::vector& options); - bool isType(IswaManager::CygnetType type); + IswaBaseGroup(std::string name, std::string type); + ~IswaBaseGroup(); + bool isType(std::string type); - void clearGroup(); void updateGroup(); + virtual void clearGroup(); - std::shared_ptr > groupEvent(){ return _groupEvent; }; std::shared_ptr dataProcessor(); - std::vector fieldlineValue() {return _fieldlines.value();} - std::vector dataOptionsValue() {return _dataOptions.value();} - void setFieldlineInfo(std::string fieldlineIndexFile, std::string kameleonPath); - // bool useLog(){return _useLog.value();}; - // glm::vec2 normValues(){return _normValues.value();}; - // bool useHistogram(){return _useHistogram.value();}; - // std::vector dataOptions(){return _dataOptions.value();}; - // std::string transferFunctionsFile(){return _transferFunctionsFile.value();}; - // glm::vec2 backgroundValues(){return _backgroundValues.value();}; -private: + std::shared_ptr > groupEvent(); + +protected: void registerProperties(); void unregisterProperties(); - void readFieldlinePaths(std::string indexFile); - void updateFieldlineSeeds(); - void clearFieldlines(); - properties::BoolProperty _enabled; properties::FloatProperty _alpha; - properties::BoolProperty _useLog; - properties::BoolProperty _useHistogram; - properties::BoolProperty _autoFilter; - properties::Vec2Property _normValues; - properties::Vec2Property _backgroundValues; - properties::StringProperty _transferFunctionsFile; - properties::SelectionProperty _dataOptions; - properties::SelectionProperty _fieldlines; - properties::TriggerProperty _delete; - // properties::SelectionProperty _dataOptions; - // properties::StringProperty _transferFunctionsFile; - // properties::Vec2Property _normValues; - // properties::Vec2Property _backgroundValues; - // properties::BoolProperty _useLog; - // properties::BoolProperty _useHistogram;; + properties::TriggerProperty _delete; - // int groupId; - // IswaCygnet cygnet; - int _id; std::shared_ptr > _groupEvent; std::shared_ptr _dataProcessor; - //std::vector _cygnets; - IswaManager::CygnetType _type; - bool _registered; - std::string _fieldlineIndexFile; - std::string _kameleonPath; - std::map > _fieldlineState; + bool _registered; + std::string _type; }; } //namespace openspace diff --git a/modules/iswa/rendering/iswakameleongroup.cpp b/modules/iswa/rendering/iswakameleongroup.cpp new file mode 100644 index 0000000000..688bba237b --- /dev/null +++ b/modules/iswa/rendering/iswakameleongroup.cpp @@ -0,0 +1,163 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace { + const std::string _loggerCat = "IswaDataGroup"; + using json = nlohmann::json; +} + +namespace openspace{ +IswaKameleonGroup::IswaKameleonGroup(std::string name, std::string type) + :IswaDataGroup(name, type) + ,_resolution("resolution", "Resolution%", 100.0f, 10.0f, 200.0f) + ,_fieldlines("fieldlineSeedsIndexFile", "Fieldline Seedpoints") + ,_fieldlineIndexFile("") + ,_kameleonPath("") +{ + addProperty(_resolution); + addProperty(_fieldlines); + registerProperties(); +} + +IswaKameleonGroup::~IswaKameleonGroup(){} + +void IswaKameleonGroup::clearGroup(){ + IswaBaseGroup::clearGroup(); + clearFieldlines(); +} + +std::vector IswaKameleonGroup::fieldlineValue(){ + return _fieldlines.value(); +} + +void IswaKameleonGroup::setFieldlineInfo(std::string fieldlineIndexFile, std::string kameleonPath){ + if(fieldlineIndexFile != _fieldlineIndexFile){ + _fieldlineIndexFile = fieldlineIndexFile; + readFieldlinePaths(_fieldlineIndexFile); + } + + if(kameleonPath != _kameleonPath){ + _kameleonPath = kameleonPath; + clearFieldlines(); + updateFieldlineSeeds(); + } +} + + +void IswaKameleonGroup::registerProperties(){ + OsEng.gui()._iswa.registerProperty(&_resolution); + OsEng.gui()._iswa.registerProperty(&_fieldlines); + + _resolution.onChange([this]{ + LDEBUG("Group " + name() + " published resolutionChanged"); + _groupEvent->publish("resolutionChanged", ghoul::Dictionary({{"resolution", _resolution.value()}})); + }); + + _fieldlines.onChange([this]{ + updateFieldlineSeeds(); + }); +} + +void IswaKameleonGroup::readFieldlinePaths(std::string indexFile){ + LINFO("Reading seed points paths from file '" << indexFile << "'"); + + // Read the index file from disk + std::ifstream seedFile(indexFile); + if (!seedFile.good()) + LERROR("Could not open seed points file '" << indexFile << "'"); + else { + std::string line; + std::string fileContent; + while (std::getline(seedFile, line)) { + fileContent += line; + } + + try{ + //Parse and add each fieldline as an selection + json fieldlines = json::parse(fileContent); + int i = 0; + + for (json::iterator it = fieldlines.begin(); it != fieldlines.end(); ++it) { + _fieldlines.addOption({i, it.key()}); + _fieldlineState[i] = std::make_tuple(name()+"/"+it.key(), it.value(), false); + i++; + } + + } catch(const std::exception& e) { + LERROR("Error when reading json file with paths to seedpoints: " + std::string(e.what())); + } + } +} + +void IswaKameleonGroup::updateFieldlineSeeds(){ + std::vector selectedOptions = _fieldlines.value(); + + // SeedPath == map > + for (auto& seedPath: _fieldlineState) { + // if this option was turned off + if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)==selectedOptions.end() && std::get<2>(seedPath.second)){ + LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second)); + OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')"); + std::get<2>(seedPath.second) = false; + // if this option was turned on + } else if( std::find(selectedOptions.begin(), selectedOptions.end(), seedPath.first)!=selectedOptions.end() && !std::get<2>(seedPath.second)) { + LDEBUG("Created fieldlines: " + std::get<0>(seedPath.second)); + IswaManager::ref().createFieldline(std::get<0>(seedPath.second), _kameleonPath, std::get<1>(seedPath.second)); + std::get<2>(seedPath.second) = true; + } + } +} + +void IswaKameleonGroup::clearFieldlines(){ + // SeedPath == map > + for (auto& seedPath: _fieldlineState) { + if(std::get<2>(seedPath.second)){ + LDEBUG("Removed fieldlines: " + std::get<0>(seedPath.second)); + OsEng.scriptEngine().queueScript("openspace.removeSceneGraphNode('" + std::get<0>(seedPath.second) + "')"); + std::get<2>(seedPath.second) = false; + } + } +} + +void IswaKameleonGroup::changeCdf(std::string path){ + _kameleonPath = path; + clearFieldlines(); + updateFieldlineSeeds(); + + _groupEvent->publish("cdfChanged", ghoul::Dictionary({{"path", path}})); +} + +}//namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/iswakameleongroup.h b/modules/iswa/rendering/iswakameleongroup.h new file mode 100644 index 0000000000..c200ea0d46 --- /dev/null +++ b/modules/iswa/rendering/iswakameleongroup.h @@ -0,0 +1,56 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* 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 __ISWAKAMELEONGROUP_H__ +#define __ISWAKAMELEONGROUP_H__ +#include + +namespace openspace{ +class IswaKameleonGroup : public IswaDataGroup{ +public: + IswaKameleonGroup(std::string name, std::string type); + ~IswaKameleonGroup(); + + virtual void clearGroup(); + + std::vector fieldlineValue(); + void setFieldlineInfo(std::string fieldlineIndexFile, std::string kameleonPath); + void changeCdf(std::string path); + +protected: + void registerProperties(); + + void readFieldlinePaths(std::string indexFile); + void updateFieldlineSeeds(); + void clearFieldlines(); + + properties::FloatProperty _resolution; + properties::SelectionProperty _fieldlines; + + std::string _fieldlineIndexFile; + std::string _kameleonPath; + std::map > _fieldlineState; +}; + +}//namespace openspace +#endif \ No newline at end of file diff --git a/modules/iswa/rendering/kameleonplane.cpp b/modules/iswa/rendering/kameleonplane.cpp index 1e3b540407..79d046c9b9 100644 --- a/modules/iswa/rendering/kameleonplane.cpp +++ b/modules/iswa/rendering/kameleonplane.cpp @@ -1,72 +1,54 @@ -// /***************************************************************************************** -// * * -// * OpenSpace * -// * * -// * Copyright (c) 2014-2016 * -// * * -// * 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. * -// ****************************************************************************************/ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include #include -#include - +#include +#include namespace { using json = nlohmann::json; const std::string _loggerCat = "KameleonPlane"; - const int MAX_TEXTURES = 6; - } namespace openspace { KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) - :CygnetPlane(dictionary) + :DataCygnet(dictionary) ,_useLog("useLog","Use Logarithm", false) - ,_useHistogram("useHistogram", "Use Histogram", false) + ,_useHistogram("useHistogram", "Auto Contrast", false) ,_autoFilter("autoFilter", "Auto Filter", true) ,_normValues("normValues", "Normalize Values", glm::vec2(1.0,1.0), glm::vec2(0), glm::vec2(5.0)) ,_backgroundValues("backgroundValues", "Background Values", glm::vec2(0.0), glm::vec2(0), glm::vec2(1.0)) - ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/hot.tf") - ,_dataOptions("dataOptions", "Data Options") + ,_transferFunctionsFile("transferfunctions", "Transfer Functions", "${SCENE}/iswa/tfs/default.tf") ,_fieldlines("fieldlineSeedsIndexFile", "Fieldline Seedpoints") - ,_resolution("resolution", "Resolutionx100", 1, 1, 5) + ,_resolution("resolution", "Resolution%", 100.0f, 10.0f, 200.0f) ,_slice("slice", "Slice", 0.0, 0.0, 1.0) { - std::string name; - dictionary.getValue("Name", name); - setName(name); - - registerProperties(); addProperty(_useLog); addProperty(_useHistogram); @@ -76,12 +58,8 @@ KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) addProperty(_resolution); addProperty(_slice); addProperty(_transferFunctionsFile); - addProperty(_dataOptions); addProperty(_fieldlines); - - _type = IswaManager::CygnetType::Data; - dictionary.getValue("kwPath", _kwPath); std::string fieldlineIndexFile; @@ -92,25 +70,20 @@ KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) OsEng.gui()._iswa.registerProperty(&_slice); - if(axis == "x"){ - _scale = _data->scale.x; - _data->scale.x = 0; - _data->offset.x = 0; - _slice.setValue(0.8); - }else if(axis == "y"){ - _scale = _data->scale.y; - _data->scale.y = 0; - // _data->offset.y = 0; + if(axis == "x") _cut = 0; + else if (axis == "y") _cut = 1; + else _cut = 2; - _slice.setValue((_data->offset.y -_data->gridMin.y)/_scale); - }else{ - _scale = _data->scale.z; - _data->scale.z = 0; - // _data->offset.z = 0; + _origOffset = _data->offset; - _slice.setValue((_data->offset.z - _data->gridMin.z)/_scale); - } + _scale = _data->scale[_cut]; + _data->scale[_cut] = 0; + _data->offset[_cut] = 0; + + _slice.setValue((_data->offset[_cut] -_data->gridMin[_cut])/_scale); + + setDimensions(); _programName = "DataPlaneProgram"; _vsPath = "${MODULE_ISWA}/shaders/dataplane_vs.glsl"; @@ -122,13 +95,10 @@ KameleonPlane::~KameleonPlane(){} bool KameleonPlane::deinitialize(){ IswaCygnet::deinitialize(); _fieldlines.set(std::vector()); - _kw = nullptr; return true; } bool KameleonPlane::initialize(){ - _kw = std::make_shared(absPath(_kwPath)); - _textures.push_back(nullptr); if(!_data->groupName.empty()){ initializeGroup(); @@ -142,58 +112,7 @@ bool KameleonPlane::initialize(){ if(_group){ _dataProcessor = _group->dataProcessor(); - - _groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ - LDEBUG(name() + " Event useLogChanged"); - _useLog.setValue(dict.value("useLog")); - }); - - _groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event normValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("normValues", values); - if(success){ - _normValues.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event useHistogramChanged"); - _useHistogram.setValue(dict.value("useHistogram")); - }); - - _groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event dataOptionsChanged"); - std::shared_ptr > values; - bool success = dict.getValue("dataOptions", values); - if(success){ - _dataOptions.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event transferFunctionsChanged"); - _transferFunctionsFile.setValue(dict.value("transferFunctions")); - }); - - _groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event backgroundValuesChanged"); - std::shared_ptr values; - bool success = dict.getValue("backgroundValues", values); - if(success){ - _backgroundValues.setValue(*values); - } - }); - - _groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event autoFilterChanged"); - _autoFilter.setValue(dict.value("autoFilter")); - }); - - _groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ - LDEBUG(name() + " Event updateGroup"); - loadTexture(); - }); + subscribeToGroup(); }else{ OsEng.gui()._iswa.registerProperty(&_useLog); OsEng.gui()._iswa.registerProperty(&_useHistogram); @@ -204,262 +123,150 @@ bool KameleonPlane::initialize(){ OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_fieldlines); OsEng.gui()._iswa.registerProperty(&_dataOptions); - - _dataProcessor = std::make_shared( - _useLog.value(), - _useHistogram.value(), - _normValues - ); + _dataProcessor = std::make_shared(); + + //If autofiler is on, background values property should be hidden + _autoFilter.onChange([this](){ + // If autofiler is selected, use _dataProcessor to set backgroundValues + // and unregister backgroundvalues property. + if(_autoFilter.value()){ + _backgroundValues.setValue(_dataProcessor->filterValues()); + OsEng.gui()._iswa.unregisterProperty(&_backgroundValues); + // else if autofilter is turned off, register backgroundValues + } else { + OsEng.gui()._iswa.registerProperty(&_backgroundValues, &_autoFilter); + } + }); } - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); _normValues.onChange([this](){ _dataProcessor->normValues(_normValues.value()); - loadTexture(); + updateTexture(); }); _useLog.onChange([this](){ _dataProcessor->useLog(_useLog.value()); - loadTexture(); + updateTexture(); }); _useHistogram.onChange([this](){ _dataProcessor->useHistogram(_useHistogram.value()); - loadTexture(); + updateTexture(); }); _transferFunctionsFile.onChange([this](){ - setTransferFunctions(_transferFunctionsFile.value()); + readTransferFunctions(_transferFunctionsFile.value()); }); _resolution.onChange([this](){ for(int i=0; i<_textures.size(); i++){ _textures[i] = std::move(nullptr); } - _dataProcessor->clear(); - updateTexture(); + + updateTextureResource(); + setDimensions(); + }); _slice.onChange([this](){ - updateTexture(); + updateTextureResource(); }); _fieldlines.onChange([this](){ updateFieldlineSeeds(); }); - fillOptions(); - updateTexture(); + fillOptions(_kwPath); + // Has to be done after fillOptions + _dataOptions.onChange([this](){ + if(_dataOptions.value().size() > MAX_TEXTURES) + LWARNING("Too many options chosen, max is " + std::to_string(MAX_TEXTURES)); + updateTexture(); + }); + + std::dynamic_pointer_cast(_dataProcessor)->dimensions(_dimensions); + _dataProcessor->addDataValues(_kwPath, _dataOptions); + // if this datacygnet has added new values then reload texture + // for the whole group, including this datacygnet, and return after. + if(_group){ + _group->updateGroup(); + } + updateTextureResource(); return true; } -bool KameleonPlane::loadTexture() { - std::vector selectedOptions = _dataOptions.value(); - auto options = _dataOptions.options(); +bool KameleonPlane::createGeometry() { + glGenVertexArrays(1, &_quad); // generate array + glGenBuffers(1, &_vertexPositionBuffer); // generate buffer - for(int option : selectedOptions){ - if(!_dataSlices[option]){ + // ============================ + // GEOMETRY (quad) + // ============================ + // GLfloat x,y, z; + float s = _data->spatialScale.x; + const GLfloat x = s*_data->scale.x/2.0; + const GLfloat y = s*_data->scale.y/2.0; + const GLfloat z = s*_data->scale.z/2.0; + const GLfloat w = _data->spatialScale.w; - std::string optionName = options[option].description; - _dataSlices[option] = _kw->getUniformSliceValues(optionName, _dimensions, _slice.value()); - if(!_textures[option]){ - _dataProcessor->addValuesFromKameleonData(_dataSlices[option], _dimensions, options.size(), option); + const GLfloat vertex_data[] = { // square of two triangles (sigh) + // x y z w s t + -x, -y, -z, w, 0, 1, + x, y, z, w, 1, 0, + -x, ((x>0)?y:-y), z, w, 0, 0, + -x, -y, -z, w, 0, 1, + x, ((x>0)?-y:y), -z, w, 1, 1, + x, y, z, w, 1, 0, + }; - if(_group) - _group->updateGroup(); - } - } - } + glBindVertexArray(_quad); // bind array + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); - std::vector data = _dataProcessor->processKameleonData2(_dataSlices, _dimensions, _dataOptions); - - if(data.empty()) - return false; - - if(_autoFilter.value()) - _backgroundValues.setValue(_dataProcessor->filterValues()); - - bool texturesReady = false; - for(int option: selectedOptions){ - float* values = data[option]; - if(!values) continue; - - if(!_textures[option]){ - std::unique_ptr texture = std::make_unique( - values, - _textureDimensions, - ghoul::opengl::Texture::Format::Red, - GL_RED, - GL_FLOAT, - ghoul::opengl::Texture::FilterMode::Linear, - ghoul::opengl::Texture::WrappingMode::ClampToEdge - ); - - if(texture){ - texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - _textures[option] = std::move(texture); - } - }else{ - _textures[option]->setPixelData(values); - _textures[option]->uploadTexture(); - } - texturesReady = true; - } - - return texturesReady; + return true; } -bool KameleonPlane::updateTexture(){ - _dimensions = glm::size3_t(_resolution.value()*100); - if(_data->scale.x == 0){ - _dimensions.x = 1; - _dimensions.z = (int) _dimensions.y * (_data->scale.y/_data->scale.z); - _textureDimensions = glm::size3_t(_dimensions.y, _dimensions.z, 1); +bool KameleonPlane::destroyGeometry(){ + glDeleteVertexArrays(1, &_quad); + _quad = 0; - _data->offset.x = _data->gridMin.x+_slice.value()*_scale; + glDeleteBuffers(1, &_vertexPositionBuffer); + _vertexPositionBuffer = 0; - }else if(_data->scale.y == 0){ - _dimensions.y = 1; - _dimensions.z = (int) _dimensions.x * (_data->scale.x/_data->scale.z); - _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.z, 1); + return true; +} - _data->offset.y = _data->gridMin.y+_slice.value()*_scale; - }else{ - _dimensions.z = 1; - _dimensions.y = (int) _dimensions.x * (_data->scale.x/_data->scale.y); - _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.y, 1); +void KameleonPlane::renderGeometry() const { + glBindVertexArray(_quad); + glDrawArrays(GL_TRIANGLES, 0, 6); +} - _data->offset.z = _data->gridMin.z+_slice.value()*_scale; - } +std::vector KameleonPlane::textureData() { + return std::dynamic_pointer_cast(_dataProcessor)->processData(_kwPath, _dataOptions, _slice, _dimensions); +}; - for(int i=0; i<_dataSlices.size(); ++i){ - float* slice = _dataSlices[i]; - if(slice){ - _dataSlices[i] = nullptr; - delete slice; - } - } +bool KameleonPlane::updateTextureResource(){ + _data->offset[_cut] = _data->gridMin[_cut]+_slice.value()*_scale; _textureDirty = true; return true; } +void KameleonPlane::setUniforms(){ -bool KameleonPlane::readyToRender() const { - return (!_textures.empty() && !_transferFunctions.empty()); -} - -void KameleonPlane::setUniformAndTextures(){ - std::vector selectedOptions = _dataOptions.value(); - int activeTextures = std::min((int)selectedOptions.size(), MAX_TEXTURES); - int activeTransferfunctions = std::min((int)_transferFunctions.size(), MAX_TEXTURES); - - - ghoul::opengl::TextureUnit txUnits[6]; - int j = 0; - for(int option : selectedOptions){ - if(_textures[option]){ - txUnits[j].activate(); - _textures[option]->bind(); - _shader->setUniform( - "textures[" + std::to_string(j) + "]", - txUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - - if(activeTextures > 0){ - if(selectedOptions.back()>=activeTransferfunctions) - activeTransferfunctions = 1; - } - - ghoul::opengl::TextureUnit tfUnits[6]; - j = 0; - - if((activeTransferfunctions == 1)){ - tfUnits[0].activate(); - _transferFunctions[0]->bind(); - _shader->setUniform( - "transferFunctions[0]", - tfUnits[0] - ); - }else{ - for(int option : selectedOptions){ - if(_transferFunctions[option]){ - tfUnits[j].activate(); - _transferFunctions[option]->bind(); - _shader->setUniform( - "transferFunctions[" + std::to_string(j) + "]", - tfUnits[j] - ); - - j++; - if(j >= MAX_TEXTURES) break; - } - } - } - - _shader->setUniform("numTextures", activeTextures); - _shader->setUniform("numTransferFunctions", activeTransferfunctions); + setTextureUniforms(); _shader->setUniform("backgroundValues", _backgroundValues.value()); _shader->setUniform("transparency", _alpha.value()); } -void KameleonPlane::setTransferFunctions(std::string tfPath){ - std::string line; - std::ifstream tfFile(absPath(tfPath)); - - std::vector> tfs; - - if(tfFile.is_open()){ - while(getline(tfFile, line)){ - std::shared_ptr tf = std::make_shared(absPath(line)); - if(tf){ - tfs.push_back(tf); - } - } - tfFile.close(); - } - - if(!tfs.empty()){ - _transferFunctions.clear(); - _transferFunctions = tfs; - } -} - -void KameleonPlane::fillOptions(){ - std::vector options = _kw->getVariables(); - int numOptions = 0; - - for(std::string option : options){ - if(option.size() < 4 && option != "x" && option != "y" && option != "z"){ - _dataOptions.addOption({numOptions, option}); - _dataSlices.push_back(nullptr); - _textures.push_back(nullptr); - numOptions++; - } - } - if(_group){ - _group->registerOptions(_dataOptions.options()); - _dataOptions.setValue(_group->dataOptionsValue()); - }else{ - _dataOptions.setValue(std::vector(1,0)); - // IswaManager::ref().registerOptionsToGroup(_data->groupName, _dataOptions.options()); - } - _dataOptions.onChange([this](){ - if(_dataOptions.value().size() > MAX_TEXTURES) - LWARNING("Too many options chosen, max is " + std::to_string(MAX_TEXTURES)); - loadTexture(); - }); -} - void KameleonPlane::updateFieldlineSeeds(){ std::vector selectedOptions = _fieldlines.value(); @@ -485,7 +292,7 @@ void KameleonPlane::updateFieldlineSeeds(){ void KameleonPlane::readFieldlinePaths(std::string indexFile){ LINFO("Reading seed points paths from file '" << indexFile << "'"); if(_group){ - _group->setFieldlineInfo(indexFile, _kwPath); + std::dynamic_pointer_cast(_group)->setFieldlineInfo(indexFile, _kwPath); return; } @@ -494,34 +301,119 @@ void KameleonPlane::readFieldlinePaths(std::string indexFile){ if (!seedFile.good()) LERROR("Could not open seed points file '" << indexFile << "'"); else { - std::string line; - std::string fileContent; - while (std::getline(seedFile, line)) { - fileContent += line; - } - try{ //Parse and add each fieldline as an selection - json fieldlines = json::parse(fileContent); + json fieldlines = json::parse(seedFile); int i = 0; std::string fullName = name(); std::string partName = fullName.substr(0,fullName.find_last_of("-")); - std::cout << fullName << std::endl; - std::cout << partName << std::endl; for (json::iterator it = fieldlines.begin(); it != fieldlines.end(); ++it) { - - - _fieldlines.addOption({i, name()+"/"+it.key()}); + _fieldlines.addOption({i, it.key()}); _fieldlineState[i] = std::make_tuple(partName+"/"+it.key(), it.value(), false); i++; } - // if(_group) - // _group->registerFieldLineOptions(_fieldlines.options()); - } catch(const std::exception& e) { LERROR("Error when reading json file with paths to seedpoints: " + std::string(e.what())); } + } +} + +void KameleonPlane::subscribeToGroup(){ + auto groupEvent = _group->groupEvent(); + + groupEvent->subscribe(name(), "useLogChanged", [&](const ghoul::Dictionary& dict){ + LDEBUG(name() + " Event useLogChanged"); + _useLog.setValue(dict.value("useLog")); + }); + + groupEvent->subscribe(name(), "normValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event normValuesChanged"); + glm::vec2 values; + bool success = dict.getValue("normValues", values); + if(success){ + _normValues.setValue(values); + } + }); + + groupEvent->subscribe(name(), "useHistogramChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event useHistogramChanged"); + _useHistogram.setValue(dict.value("useHistogram")); + }); + + groupEvent->subscribe(name(), "dataOptionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event dataOptionsChanged"); + std::vector values; + bool success = dict.getValue >("dataOptions", values); + if(success){ + _dataOptions.setValue(values); + } + }); + + groupEvent->subscribe(name(), "transferFunctionsChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event transferFunctionsChanged"); + _transferFunctionsFile.setValue(dict.value("transferFunctions")); + }); + + groupEvent->subscribe(name(), "backgroundValuesChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event backgroundValuesChanged"); + glm::vec2 values; + bool success = dict.getValue("backgroundValues", values); + if(success){ + _backgroundValues.setValue(values); + } + }); + + groupEvent->subscribe(name(), "autoFilterChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event autoFilterChanged"); + _autoFilter.setValue(dict.value("autoFilter")); + }); + + groupEvent->subscribe(name(), "updateGroup", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event updateGroup"); + if(_autoFilter.value()) + _backgroundValues.setValue(_dataProcessor->filterValues()); + updateTexture(); + }); + + groupEvent->subscribe(name(), "resolutionChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event resolutionChanged"); + float resolution; + bool success = dict.getValue("resolution", resolution); + if(success){ + _resolution.setValue(resolution); + } + }); + + groupEvent->subscribe(name(), "cdfChanged", [&](ghoul::Dictionary dict){ + LDEBUG(name() + " Event cdfChanged"); + std::string path; + bool success = dict.getValue("path", path); + if(success){ + changeKwPath(path); + } + + updateTexture(); + }); +} + +void KameleonPlane::setDimensions(){ + // the cdf files has an offset of 0.5 in normali resolution. + // with lower resolution the offset increases. + _data->offset = _origOffset - 0.5f*(100.0f/_resolution.value()); + _dimensions = glm::size3_t(_data->scale*((float)_resolution.value()/100.f)); + _dimensions[_cut] = 1; + + if(_cut == 0){ + _textureDimensions = glm::size3_t(_dimensions.y, _dimensions.z, 1); + }else if(_cut == 1){ + _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.z, 1); + }else{ + _textureDimensions = glm::size3_t(_dimensions.x, _dimensions.y, 1); } } +void KameleonPlane::changeKwPath(std::string kwPath){ + _kwPath = kwPath; +} + }// namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/kameleonplane.h b/modules/iswa/rendering/kameleonplane.h index 3a1c7fc545..b4fe88ae24 100644 --- a/modules/iswa/rendering/kameleonplane.h +++ b/modules/iswa/rendering/kameleonplane.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * -* Copyright (c) 2014-2015 * +* Copyright (c) 2014-2016 * * * * 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 * @@ -25,30 +25,41 @@ #ifndef __KAMELEONPLANE_H__ #define __KAMELEONPLANE_H__ -#include -#include -#include +#include #include #include - namespace openspace{ - - class KameleonPlane : public CygnetPlane { - public: +namespace openspace{ + +/** + * KameleonPlane is a concrete IswaCygnet with volume data files from + * disk as input source. An object of this class will provide a cutplane + * through a volume of space weather data. It will also give the option + * to create fieldlines around and intersecting the planes. Interaction + * with the planes is possible through sliders that will move the planes + * through the data volume. + */ +class KameleonPlane : public DataCygnet { +public: KameleonPlane(const ghoul::Dictionary& dictionary); ~KameleonPlane(); bool initialize() override; bool deinitialize() override; - - - private: - virtual bool loadTexture() override; - virtual bool updateTexture() override; - virtual bool readyToRender() const override; - virtual void setUniformAndTextures() override; +private: + /** + * Creates a plane geometry + */ + bool createGeometry() override; + bool destroyGeometry() override; + bool updateTextureResource() override; + void renderGeometry() const override; + void setUniforms() override; + std::vector textureData() override; + + void setDimensions(); /** * Given a path to the json index of seedpoints file, this * method reads, parses and adds them as checkbox options @@ -63,37 +74,33 @@ * SelectionProperty and creates or removes fieldlines in the scene. */ void updateFieldlineSeeds(); + void subscribeToGroup(); - void setTransferFunctions(std::string tfPath); - void fillOptions(); - + void changeKwPath(std::string path); static int id(); - properties::IntProperty _resolution; + properties::FloatProperty _resolution; properties::FloatProperty _slice; - properties::SelectionProperty _dataOptions; - properties::SelectionProperty _fieldlines; properties::StringProperty _transferFunctionsFile; - properties::Vec2Property _backgroundValues; + properties::SelectionProperty _fieldlines; + + properties::Vec2Property _backgroundValues; properties::Vec2Property _normValues; properties::BoolProperty _useLog; properties::BoolProperty _useHistogram; properties::BoolProperty _autoFilter; - - std::shared_ptr _kw; - std::string _kwPath; + std::string _kwPath; glm::size3_t _dimensions; - glm::size3_t _textureDimensions; - float* _dataSlice; - std::string _var; - - std::vector _dataSlices; - std::shared_ptr _dataProcessor; + float* _dataSlice; + std::string _var; float _scale; + + glm::vec3 _origOffset; + /** * _fieldlineState maps the checkbox value of each fieldline seedpoint file to a tuple * containing information that is needed to either add or remove a fieldline from the scenegraph. @@ -101,8 +108,12 @@ */ std::map > _fieldlineState; std::string _fieldlineIndexFile; - }; + int _cut; + + GLuint _quad; + GLuint _vertexPositionBuffer; +}; - } // namespace openspace +} // namespace openspace #endif //__KAMELEONPLANE_H__ \ No newline at end of file diff --git a/modules/iswa/rendering/texturecygnet.cpp b/modules/iswa/rendering/texturecygnet.cpp index 2212f26f93..0616cc4f20 100644 --- a/modules/iswa/rendering/texturecygnet.cpp +++ b/modules/iswa/rendering/texturecygnet.cpp @@ -34,32 +34,21 @@ namespace openspace{ TextureCygnet::TextureCygnet(const ghoul::Dictionary& dictionary) :IswaCygnet(dictionary) -{} +{ + registerProperties(); +} TextureCygnet::~TextureCygnet(){} -bool TextureCygnet::loadTexture() { - - // if The future is done then get the new imageFile - DownloadManager::MemoryFile imageFile; - if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ - imageFile = _futureObject.get(); - - } else { - return false; - } - - if(imageFile.corrupted) - return false; +bool TextureCygnet::updateTexture() { std::unique_ptr texture = ghoul::io::TextureReader::ref().loadTexture( - (void*) imageFile.buffer, - imageFile.size, - imageFile.format); + (void*) _imageFile.buffer, + _imageFile.size, + _imageFile.format); if (texture) { LDEBUG("Loaded texture from image iswa cygnet with id: '" << _data->id << "'"); - texture->uploadTexture(); // Textures of planets looks much smoother with AnisotropicMipMap rather than linear texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); @@ -69,14 +58,14 @@ bool TextureCygnet::loadTexture() { return false; } -bool TextureCygnet::updateTexture(){ - - if(_textures.empty()) - _textures.push_back(nullptr); +bool TextureCygnet::downloadTextureResource(){ if(_futureObject.valid()) return false; + if(_textures.empty()) + _textures.push_back(nullptr); + std::future future = IswaManager::ref().fetchImageCygnet(_data->id); if(future.valid()){ @@ -87,6 +76,27 @@ bool TextureCygnet::updateTexture(){ return false; } +bool TextureCygnet::updateTextureResource(){ + + // if The future is done then get the new imageFile + DownloadManager::MemoryFile imageFile; + if(_futureObject.valid() && DownloadManager::futureReady(_futureObject)){ + imageFile = _futureObject.get(); + + if(imageFile.corrupted){ + if(imageFile.buffer) + delete[] imageFile.buffer; + return false; + } else { + _imageFile = imageFile; + } + } else { + return false; + } + + return true; +} + bool TextureCygnet::readyToRender() const { return (isReady() && ((!_textures.empty()) && (_textures[0] != nullptr))); } diff --git a/modules/iswa/rendering/texturecygnet.h b/modules/iswa/rendering/texturecygnet.h index d4837fe2a2..8d977d1f5b 100644 --- a/modules/iswa/rendering/texturecygnet.h +++ b/modules/iswa/rendering/texturecygnet.h @@ -30,7 +30,7 @@ namespace openspace{ /** - * This class exist tp abstract away the loading of images + * This class exist to abstract away the loading of images * from iSWA and updating of the textures for child geometries. * The class specifies the minimum interface that child classes * needs to implement. @@ -42,15 +42,19 @@ public: protected: - bool loadTexture() override; bool updateTexture() override; + bool downloadTextureResource() override; bool readyToRender() const override; + bool updateTextureResource() override; // Interface for concrete subclasses - virtual void setUniformAndTextures() = 0; + virtual void setUniforms() = 0; virtual bool createGeometry() = 0; virtual bool destroyGeometry() = 0; virtual void renderGeometry() const = 0; + +private: + DownloadManager::MemoryFile _imageFile; }; } //namespace openspace diff --git a/modules/iswa/rendering/textureplane.cpp b/modules/iswa/rendering/textureplane.cpp index f73aaac34d..777dac2c1a 100644 --- a/modules/iswa/rendering/textureplane.cpp +++ b/modules/iswa/rendering/textureplane.cpp @@ -36,13 +36,6 @@ TexturePlane::TexturePlane(const ghoul::Dictionary& dictionary) ,_quad(0) ,_vertexPositionBuffer(0) { - std::string name; - dictionary.getValue("Name", name); - setName(name); - registerProperties(); - - _type = IswaManager::CygnetType::Texture; - _programName = "PlaneProgram"; _vsPath = "${MODULE_ISWA}/shaders/cygnetplane_vs.glsl"; _fsPath = "${MODULE_ISWA}/shaders/cygnetplane_fs.glsl"; @@ -50,7 +43,7 @@ TexturePlane::TexturePlane(const ghoul::Dictionary& dictionary) TexturePlane::~TexturePlane(){} -void TexturePlane::setUniformAndTextures(){ +void TexturePlane::setUniforms(){ ghoul::opengl::TextureUnit unit; unit.activate(); diff --git a/modules/iswa/rendering/textureplane.h b/modules/iswa/rendering/textureplane.h index 62a2a571d1..4803ec0176 100644 --- a/modules/iswa/rendering/textureplane.h +++ b/modules/iswa/rendering/textureplane.h @@ -30,9 +30,9 @@ namespace openspace{ /** - * TexturePlane is a "concrete" IswaCygnet. It handles the creation, - * destruction and rendering of a plane geometry. It also specifies - * which shaders to use and the uniforms that it needs. + * TexturePlane is a "concrete" IswaCygnet with texture as its input source. + * It handles the creation, destruction and rendering of a plane geometry. + * It also specifies which shaders to use and the uniforms that it needs. */ class TexturePlane : public TextureCygnet{ public: @@ -41,7 +41,7 @@ public: private: bool createGeometry() override; - void setUniformAndTextures() override; + void setUniforms() override; bool destroyGeometry() override; void renderGeometry() const override; diff --git a/modules/iswa/shaders/dataplane_fs.glsl b/modules/iswa/shaders/dataplane_fs.glsl index c17b190d06..58f45b1052 100644 --- a/modules/iswa/shaders/dataplane_fs.glsl +++ b/modules/iswa/shaders/dataplane_fs.glsl @@ -35,7 +35,6 @@ uniform bool averageValues; uniform vec2 backgroundValues; uniform float transparency; - // uniform float background; in vec2 vs_st; @@ -62,14 +61,17 @@ Fragment getFragment() { vec4 color = texture(transferFunctions[0], vec2(v,0)); if((v<(x+y)) && v>(x-y)) - color = mix(transparent, color, clamp(1,0,abs(v-x))); + color = transparent; + // color = mix(transparent, color, clamp(1,0,abs(v-x))); + diffuse = color; }else{ for(int i=0; i(x-y)) - color = mix(transparent, color, clamp(1,0,abs(v-x))); + color = transparent; + // color = mix(transparent, color, clamp(1,0,abs(v-x))); diffuse += color; } } diff --git a/modules/iswa/util/dataprocessor.cpp b/modules/iswa/util/dataprocessor.cpp index 2381e762fb..d0897ec2f5 100644 --- a/modules/iswa/util/dataprocessor.cpp +++ b/modules/iswa/util/dataprocessor.cpp @@ -38,779 +38,64 @@ #include namespace { - const std::string _loggerCat = "DataPlane"; + const std::string _loggerCat = "DataProcessor"; using json = nlohmann::json; } namespace openspace { -DataProcessor::DataProcessor(bool useLog, bool useHistogram, glm::vec2 normValues) - :_useLog(useLog) - ,_useHistogram(useHistogram) - ,_normValues(normValues) - ,_filterValues(glm::vec2(0)) - ,_numValues(0) +DataProcessor::DataProcessor() + :_useLog(false) + ,_useHistogram(false) + ,_normValues(glm::vec2(1.0)) + ,_filterValues(glm::vec2(0.0)) { _coordinateVariables = {"x", "y", "z", "phi", "theta"}; -}; +} + DataProcessor::~DataProcessor(){}; -std::vector DataProcessor::readHeader(std::string& dataBuffer){ - std::vector options = std::vector(); - if(!dataBuffer.empty()){ - std::stringstream memorystream(dataBuffer); - std::string line; - - while(getline(memorystream,line)){ - if(line.find("#") == 0){ - if(line.find("# Output data:") == 0){ - - line = line.substr(26); - std::stringstream ss(line); - - std::string token; - getline(ss, token, 'x'); - int x = std::stoi(token); - - getline(ss, token, '='); - int y = std::stoi(token); - - _dimensions = glm::size3_t(x, y, 1); - - getline(memorystream, line); - line = line.substr(1); - - ss = std::stringstream(line); - std::string option; - while(ss >> option){ - if(_coordinateVariables.find(option) == _coordinateVariables.end()){ - options.push_back(option); - } - } - } - }else{ - break; - } - } - } - return options; +void DataProcessor::useLog(bool useLog){ + _useLog = useLog; } -std::vector DataProcessor::readJSONHeader(std::string& dataBuffer){ - std::vector options = std::vector(); - if(!dataBuffer.empty()){ - json j = json::parse(dataBuffer); - json var = j["variables"]; - for (json::iterator it = var.begin(); it != var.end(); ++it) { - std::string option = it.key(); - if(option == "x"){ - json lon = it.value(); - json lat = lon.at(0); - - _dimensions = glm::size3_t(lat.size(), lon.size(), 1); - } - if(_coordinateVariables.find(option) == _coordinateVariables.end()){ - options.push_back(option); - } - } - } - return options; +void DataProcessor::useHistogram(bool useHistogram){ + _useHistogram = useHistogram; } -void DataProcessor::addValues(std::string& dataBuffer, properties::SelectionProperty dataOptions){ - int numOptions = dataOptions.options().size(); - - if(_min.empty()) _min = std::vector(numOptions, std::numeric_limits::max()); - if(_max.empty()) _max = std::vector(numOptions, std::numeric_limits::min()); - if(_sum.empty()) _sum = std::vector(numOptions, 0.0f); - if(_sd.empty()) _sd = std::vector(numOptions, 0.0f); - if(_numValues.empty()) _numValues= std::vector(numOptions, 0.0f); - if(_histograms.empty())_histograms = std::vector>(numOptions, nullptr); - - if(!dataBuffer.empty()){ - - std::stringstream memorystream(dataBuffer); - std::string line; - std::vector sum(numOptions, 0.0f); - std::vector> values(numOptions, std::vector()); - - int numValues = 0; - while(getline(memorystream, line)){ - if(line.find("#") == 0) continue; - - std::stringstream ss(line); - std::vector value; - float v; - while(ss >> v){ - value.push_back(v); - } - - if(value.size()){ - for(int i=0; i(_min[i], _max[i], 512); - }else{ - _histograms[i]->changeRange(_min[i], _max[i]); - } - int numValues = values[i].size(); - float mean = (1.0/numValues)*sum[i]; - - float var = 0; - for(int j=0; jadd(values[i][j], 1); - } - float sd = sqrt(var / numValues); - - _sum[i] += sum[i]; - _sd[i] = sqrt(pow(_sd[i],2) + pow(sd, 2)); - _numValues[i] += numValues; - _histograms[i]->generateEqualizer(); - } - } +void DataProcessor::normValues(glm::vec2 normValues){ + _normValues = normValues; } - - -std::vector DataProcessor::readData(std::string& dataBuffer, properties::SelectionProperty dataOptions){ - if(!dataBuffer.empty()){ - std::stringstream memorystream(dataBuffer); - std::string line; - - std::vector selectedOptions = dataOptions.value(); - - int numSelected = selectedOptions.size(); - - std::vector min(numSelected, std::numeric_limits::max()); - std::vector max(numSelected, std::numeric_limits::min()); - - std::vector sum(numSelected, 0.0f); - std::vector> optionValues(numSelected, std::vector()); - - std::vector data(dataOptions.options().size(), nullptr); - for(int option : selectedOptions){ - data[option] = new float[_dimensions.x*_dimensions.y]{0.0f}; - } - - int numValues = 0; - while(getline(memorystream, line)){ - if(line.find("#") == 0){ //part of the header - continue; - } - - std::stringstream ss(line); - std::vector value; - float v; - while(ss >> v){ - value.push_back(v); - } - - if(value.size()){ - for(int i=0; i0)? 1:-1; - v = sign*log(fabs(v) + 1); - } - - optionValues[i].push_back(v); - - min[i] = std::min(min[i], v); - max[i] = std::max(max[i], v); - - sum[i] += v; - } - numValues++; - } - } - // std::cout << "Actual size: " << numValues << " Expected: " << _dimensions.x*_dimensions.y << std::endl; - if(numValues != _dimensions.x*_dimensions.y){ - LWARNING("Number of values read and expected are not the same"); - return std::vector(); - } - - // FOR TESTING - // =========== - // std::chrono::time_point start, end; - // start = std::chrono::system_clock::now(); - // =========== - - for(int i=0; i elapsed_seconds = end-start; - // _avgBenchmarkTime = ( (_avgBenchmarkTime * (_numOfBenchmarks-1)) + elapsed_seconds.count() ) / _numOfBenchmarks; - // std::cout << " readData():" << std::endl; - // std::cout << "avg elapsed time: " << _avgBenchmarkTime << "s\n"; - // std::cout << "num Benchmarks: " << _numOfBenchmarks << "\n"; - // =========== - - return data; - - } - else { - // LWARNING("Nothing in memory buffer, are you connected to the information super highway?"); - return std::vector(); - } +glm::size3_t DataProcessor::dimensions(){ + return _dimensions; } - -std::vector DataProcessor::readData2(std::string& dataBuffer, properties::SelectionProperty dataOptions){ - if(!dataBuffer.empty()){ - std::stringstream memorystream(dataBuffer); - std::string line; - - std::vector selectedOptions = dataOptions.value(); - int numSelected = selectedOptions.size(); - - std::vector> values(selectedOptions.size(), std::vector()); - std::vector data(dataOptions.options().size(), nullptr); - - for(int option : selectedOptions){ - data[option] = new float[_dimensions.x*_dimensions.y]{0.0f}; - } - - int numValues = 0; - while(getline(memorystream, line)){ - if(line.find("#") == 0){ //part of the header - continue; - } - - std::stringstream ss(line); - std::vector value; - float v; - while(ss >> v){ - value.push_back(v); - } - - if(value.size()){ - for(int option : selectedOptions){ - float v = value[option+3]; //+3 because "options" x, y and z. - data[option][numValues] = processDataPoint(v, option); - } - } - numValues++; - } - - if(numValues != _dimensions.x*_dimensions.y){ - LWARNING("Number of values read and expected are not the same"); - return std::vector(); - } - - - _filterValues = glm::vec2(0.0f); - if(!_histograms.empty()){ - for(int option : selectedOptions){ - std::shared_ptr histogram = _histograms[option]; - float mean = (1.0 / _numValues[option]) * _sum[option]; - float sd = _sd[option]; - - float filterMid = histogram->highestBinValue(_useHistogram); - float filterWidth = mean+histogram->binWidth(); - - if(_useHistogram) { - sd = histogram->equalize(sd); - mean = histogram->equalize(mean); - filterWidth = mean+1.0; - } - - filterMid = normalizeWithStandardScore(filterMid, mean, sd); - filterWidth = fabs(0.5-normalizeWithStandardScore(filterWidth, mean, sd)); - _filterValues += glm::vec2(filterMid, filterWidth); - } - } - - if(numSelected>0){ - _filterValues.x /= numSelected; - _filterValues.y /= numSelected; - }else{ - _filterValues = glm::vec2(0.0, 1.0); - } - - return data; - - }else{ - return std::vector(); - } +glm::vec2 DataProcessor::filterValues(){ + return _filterValues; } -std::vector DataProcessor::readJSONData(std::string& dataBuffer, properties::SelectionProperty dataOptions){ - if(!dataBuffer.empty()){ - json j = json::parse(dataBuffer); - json var = j["variables"]; - - std::vector selectedOptions = dataOptions.value(); - int numSelected = selectedOptions.size(); - - std::vector min(numSelected, std::numeric_limits::max()); - std::vector max(numSelected, std::numeric_limits::min()); - - std::vector sum(numSelected, 0.0f); - std::vector> optionValues(numSelected, std::vector()); - - auto options = dataOptions.options(); - - std::vector data(options.size(), nullptr); - int i = 0; - for(int option : selectedOptions){ - - data[option] = new float[_dimensions.x*_dimensions.y]{0.0f}; - - std::string optionName = options[option].description; - - json valueArray = var[optionName]; - int ySize = valueArray.size(); - - for(int y=0; y0)? 1:-1; - if(v != 0){ - v = sign*log(fabs(v)); - } - } - - optionValues[i].push_back(v); - - min[i] = std::min(min[i], v); - max[i] = std::max(max[i], v); - - sum[i] += v; - } - } - i++; - } - - for(int i=0; i(); - } +void DataProcessor::clear(){ + _min.clear(); + _max.clear(); + _sum.clear(); + _standardDeviation.clear(); + _histograms.clear(); + _numValues.clear(); } -void DataProcessor::addValuesFromJSON(std::string& dataBuffer, properties::SelectionProperty dataOptions){ - int numOptions = dataOptions.options().size(); - - if(_min.empty()) _min = std::vector(numOptions, std::numeric_limits::max()); - if(_max.empty()) _max = std::vector(numOptions, std::numeric_limits::min()); - if(_sum.empty()) _sum = std::vector(numOptions, 0.0f); - if(_sd.empty()) _sd = std::vector(numOptions, 0.0f); - if(_numValues.empty()) _numValues= std::vector(numOptions, 0.0f); - if(_histograms.empty())_histograms = std::vector>(numOptions, nullptr); - - - if(!dataBuffer.empty()){ - json j = json::parse(dataBuffer); - json var = j["variables"]; - - std::vector selectedOptions = dataOptions.value(); - int numSelected = selectedOptions.size(); - std::vector sum(numOptions, 0.0f); - - std::vector> values(numOptions, std::vector()); - auto options = dataOptions.options(); - std::vector data(options.size(), nullptr); - int i = 0; - - for(int i=0; i(_min[i], _max[i], 512); - // // // }else{ - // // // //_histogram[option]->changeRange(); - // // // } - // // // int numValues = values[i].size(); - // // // float mean = (1.0/numValues)*sum[i]; - - // // // float var = 0; - // // // for(int j=0; jadd(values[i][j], 1); - // // // } - // // // float sd = sqrt(var / numValues); - - // // // _sum[i] += sum[i]; - // // // _sd[i] = sqrt(pow(_sd[i],2) + pow(sd, 2)); - // // // _numValues[i] += numValues; - // // // _histograms[i]->generateEqualizer(); - // // // } - - - for(int i=0; i(_min[i], _max[i], 512); - }else{ - _histograms[i]->changeRange(_min[i], _max[i]); - } - int numValues = values[i].size(); - float mean = (1.0/numValues)*sum[i]; - - float var = 0; - for(int j=0; jadd(values[i][j], 1); - } - - float sd = sqrt(var / numValues); - - _sum[i] += sum[i]; - _sd[i] = sqrt(pow(_sd[i],2) + pow(sd, 2)); - _numValues[i] += numValues; - _histograms[i]->generateEqualizer(); - } - } -} - - -std::vector DataProcessor::readJSONData2(std::string& dataBuffer, properties::SelectionProperty dataOptions){ - if(!dataBuffer.empty()){ - json j = json::parse(dataBuffer); - json var = j["variables"]; - - std::vector selectedOptions = dataOptions.value(); - int numSelected = selectedOptions.size(); - - std::vector sum(numSelected, 0.0f); - std::vector> values(numSelected, std::vector()); - auto options = dataOptions.options(); - - std::vector data(options.size(), nullptr); - - _filterValues = glm::vec2(0.0f); - - for(int option : selectedOptions){ - - data[option] = new float[_dimensions.x*_dimensions.y]{0.0f}; - - // std::stringstream memorystream(); - std::string optionName = options[option].description; - // getline(memorystream, optionName, '/'); - // getline(memorystream, optionName, '/'); - - json yArray = var[optionName]; - for(int y=0; y histogram = _histograms[option]; - float filterMid = histogram->highestBinValue(_useHistogram); - float filterWidth = mean+histogram->binWidth(); - - if(_useHistogram) { - sd = histogram->equalize(sd); - mean = histogram->equalize(mean); - filterWidth = mean+1.0; - } - - filterMid = normalizeWithStandardScore(filterMid, mean, sd); - filterWidth = fabs(0.5-normalizeWithStandardScore(filterWidth, mean, sd)); - _filterValues += glm::vec2(filterMid, filterWidth); - } - } - - if(numSelected>0){ - _filterValues.x /= numSelected; - _filterValues.y /= numSelected; - }else{ - _filterValues = glm::vec2(0.0, 1.0); - } - - return data; - } - else { - // LWARNING("Nothing in memory buffer, are you connected to the information super highway?"); - return std::vector(); - } -} - - -void DataProcessor::addValuesFromKameleonData(float* kdata, glm::size3_t dimensions, int numOptions, int option){ - if(_min.empty()) _min = std::vector(numOptions, std::numeric_limits::max()); - if(_max.empty()) _max = std::vector(numOptions, std::numeric_limits::min()); - if(_sum.empty()) _sum= std::vector(numOptions, 0.0f); - if(_sd.empty()) _sd= std::vector(numOptions, 0.0f); - if(_numValues.empty()) _numValues= std::vector(numOptions, 0.0f); - if(_histograms.empty())_histograms = std::vector>(numOptions, nullptr); - - - int numValues = dimensions.x*dimensions.y*dimensions.z; - float sum = 0; - - for(int i=0; i(_min[i], _max[i], 512); - }else{ - _histograms[i]->changeRange(_min[i], _max[i]); - } - // int numValues = values[i].size(); - float mean = (1.0/numValues)*sum; - - float var = 0; - for(int j=0; jadd(kdata[j], 1); - } - float sd = sqrt(var / numValues); - - _sum[i] += sum; - _sd[i] = sqrt(pow(_sd[i],2) + pow(sd, 2)); - _numValues[i] += numValues; - _histograms[i]->generateEqualizer(); -} - -std::vector DataProcessor::processKameleonData2(std::vector kdata, glm::size3_t dimensions, properties::SelectionProperty dataOptions){ - std::vector selectedOptions = dataOptions.value(); - int numSelected = selectedOptions.size(); - - std::vector> values(selectedOptions.size(), std::vector()); - std::vector data(dataOptions.options().size(), nullptr); - int numValues = dimensions.x*dimensions.y*dimensions.z; - - _filterValues = glm::vec2(0.0f); - - for(int option : selectedOptions){ - data[option] = new float[numValues]{0.0f}; - - float mean = (1.0 / _numValues[option]) * _sum[option]; - float sd = _sd[option]; - - for(int i=0; i histogram = _histograms[option]; - float filterMid = histogram->highestBinValue(_useHistogram); - float filterWidth = mean+histogram->binWidth(); - - if(_useHistogram) { - sd = histogram->equalize(sd); - mean = histogram->equalize(mean); - filterWidth = mean+1.0; - } - - filterMid = normalizeWithStandardScore(filterMid, mean, sd); - filterWidth = fabs(0.5-normalizeWithStandardScore(filterWidth, mean, sd)); - _filterValues += glm::vec2(filterMid, filterWidth); - } - if(numSelected>0){ - _filterValues.x /= numSelected; - _filterValues.y /= numSelected; - }else{ - _filterValues = glm::vec2(0.0, 1.0); - } - - return data; -} - -std::vector DataProcessor::processKameleonData(std::vector kdata, glm::size3_t dimensions, properties::SelectionProperty dataOptions){ - std::vector selectedOptions = dataOptions.value(); - int numSelected = selectedOptions.size(); - auto options = dataOptions.options(); - int numOptions = options.size(); - - if(_min.empty()){ - _min = std::vector(numOptions, std::numeric_limits::max()); - } - - if(_max.empty()){ - _max = std::vector(numOptions, std::numeric_limits::min()); - } - - if(_sum.empty()){ - _sum= std::vector(numOptions, 0.0f); - } - - if(_sd.empty()){ - _sd= std::vector(numOptions, 0.0f); - } - - if(_histograms.empty()){ - _histograms = std::vector>(numOptions, nullptr); - } - - - std::vector min(numSelected, std::numeric_limits::max()); - std::vector max(numSelected, std::numeric_limits::min()); - - std::vector sum(numSelected, 0.0f); - std::vector> optionValues(numSelected, std::vector()); - - - std::vector data(options.size(), nullptr); - int numValues = dimensions.x*dimensions.y*dimensions.z; - int i = 0; - - for(int option : selectedOptions){ - bool calculateMin = (_min[option] == std::numeric_limits::max()); - bool calculateMax = (_max[option] == std::numeric_limits::min()); - bool claculateSum = (_sum[option] == 0.0f); - - data[option] = new float[numValues]{0.0f}; - - for(int j=0; j0)? 1:-1; - if(v != 0){ - v = sign*log(fabs(v)); - } - } - - optionValues[i].push_back(v); - - min[i] = std::min(min[i], v); - max[i] = std::max(max[i], v); - - sum[i] += v; - - if(calculateMin) - _min[option] = std::min(_min[option],v); - if(calculateMax) - _max[option] = std::max(_max[option],v); - if(claculateSum) - _sum[option] += v; - } - i++; - // if(calculateMin) - // std::cout << _min[option] << std::endl; - } - - for(int i=0; i& inputData, float min, float max,float sum, int selected){ - const int numValues = inputData.size(); - Histogram histogram(min, max, 512); - - //Calculate the mean - float mean = (1.0 / numValues) * sum; - - //Calculate the Standard Deviation - float var = 0; - for(auto dataValue : inputData){ - var += pow(dataValue - mean, 2); - } - float standardDeviation = sqrt ( var / numValues ); - - // Histogram functionality - if(_useHistogram){ - for(auto dataValue : inputData){ - histogram.add(dataValue, 1); - } - histogram.generateEqualizer(); - standardDeviation = histogram.equalize(standardDeviation); - mean = histogram.equalize(mean); - } - - // Normalize and equalize - for(int i=0; i < numValues; i++){ - float v = inputData[i]; - if(_useHistogram){ - v = histogram.equalize(v); - } - v = normalizeWithStandardScore(v, mean, standardDeviation); - outputData[i] += v; - } - - if(_useHistogram){ - float val = histogram.highestBinValue(_useHistogram); - val = normalizeWithStandardScore(val, mean, standardDeviation); - float width = normalizeWithStandardScore(1, mean, standardDeviation); - _filterValues = glm::vec2( val, width); - } - - // Histogram equalized = histogram.equalize(); - // histogram.print(); - // equalized.print(); -} float DataProcessor::processDataPoint(float value, int option){ if(_numValues.empty()) return 0.0f; std::shared_ptr histogram = _histograms[option]; float mean = (1.0 / _numValues[option]) * _sum[option]; - float sd = _sd[option]; + float sd = _standardDeviation[option]; if(_useHistogram){ - // std::cout << sd << " " << sd = histogram->equalize(sd); mean = histogram->equalize(mean); value = histogram->equalize(value); } - float v = normalizeWithStandardScore(value, mean, sd); return v; } @@ -826,18 +111,80 @@ float DataProcessor::normalizeWithStandardScore(float value, float mean, float s return ( standardScore + zScoreMin )/(zScoreMin + zScoreMax ); } - -glm::vec2 DataProcessor::filterValues(){ - return _filterValues; +void DataProcessor::initializeVectors(int numOptions){ + if(_min.empty()) _min = std::vector(numOptions, std::numeric_limits::max()); + if(_max.empty()) _max = std::vector(numOptions, std::numeric_limits::min()); + if(_sum.empty()) _sum = std::vector(numOptions, 0.0f); + if(_standardDeviation.empty()) _standardDeviation = std::vector(numOptions, 0.0f); + if(_numValues.empty()) _numValues = std::vector(numOptions, 0.0f); + if(_histograms.empty())_histograms = std::vector>(numOptions, nullptr); } -void DataProcessor::clear(){ - _min.clear(); - _max.clear(); - _sum.clear(); - _sd.clear(); - _histograms.clear(); - _numValues.clear(); +void DataProcessor::calculateFilterValues(std::vector selectedOptions){ + int numSelected = selectedOptions.size(); + std::shared_ptr histogram; + float mean, standardDeviation, filterMid, filterWidth; + + _filterValues = glm::vec2(0.0); + if(numSelected <= 0) return; + + if(!_histograms.empty()){ + for(int option : selectedOptions){ + histogram = _histograms[option]; + mean = (1.0/_numValues[option])*_sum[option]; + standardDeviation = _standardDeviation[option]; + + filterMid = histogram->highestBinValue(_useHistogram); + filterWidth = mean+histogram->binWidth(); + + if(_useHistogram){ + standardDeviation = histogram->equalize(standardDeviation); + mean = histogram->equalize(mean); + filterWidth = mean+1; + } + + filterMid = normalizeWithStandardScore(filterMid, mean, standardDeviation); + filterWidth = fabs(0.5-normalizeWithStandardScore(filterWidth, mean, standardDeviation)); + _filterValues += glm::vec2(filterMid, filterWidth); + + } + _filterValues /= numSelected; + } +} + +void DataProcessor::add(std::vector>& optionValues, std::vector& sum){ + int numOptions = optionValues.size(); + int numValues; + float mean, value, variance, standardDeviation; + + for(int i=0; i(_min[i], _max[i], 512); + } + else{ + _histograms[i]->changeRange(_min[i], _max[i]); + } + + std::vector values = optionValues[i]; + numValues = values.size(); + + variance = 0; + mean = (1.0f/numValues)*sum[i]; + + for(int j=0; jadd(value, 1); + } + + standardDeviation = sqrt(variance/ numValues); + + _sum[i] += sum[i]; + _standardDeviation[i] = sqrt(pow(standardDeviation, 2) + pow(_standardDeviation[i], 2)); + _numValues[i] += numValues; + + _histograms[i]->generateEqualizer(); + } } } \ No newline at end of file diff --git a/modules/iswa/util/dataprocessor.h b/modules/iswa/util/dataprocessor.h index b6517af0d0..c50b8cfe23 100644 --- a/modules/iswa/util/dataprocessor.h +++ b/modules/iswa/util/dataprocessor.h @@ -35,58 +35,30 @@ namespace openspace{ class DataProcessor{ - friend class IswaGroup; + friend class IswaBaseGroup; public: - DataProcessor(bool useLog, bool useHistogram, glm::vec2 normValues); + DataProcessor(); ~DataProcessor(); - void useLog(bool useLog){ - _useLog = useLog; - } + virtual std::vector readMetadata(std::string data) = 0; + virtual void addDataValues(std::string data, properties::SelectionProperty& dataOptions) = 0; + virtual std::vector processData(std::string data, properties::SelectionProperty& dataOptions) = 0; - void useHistogram(bool useHistogram){ - _useHistogram = useHistogram; - } - - void normValues(glm::vec2 normValues){ - _normValues = normValues; - } - - glm::size3_t dimensions(){ - return _dimensions; - } - - std::vector readHeader(std::string& dataBuffer); - std::vector readData(std::string& dataBuffer, properties::SelectionProperty dataOptions); - std::vector readData2(std::string& dataBuffer, properties::SelectionProperty dataOptions); - void addValues(std::string& dataBuffer, properties::SelectionProperty dataOptions); - - std::vector readJSONHeader(std::string& dataBuffer); - std::vector readJSONData(std::string& dataBuffer, properties::SelectionProperty dataOptions); - std::vector readJSONData2(std::string& dataBuffer, properties::SelectionProperty dataOptions); - void addValuesFromJSON(std::string& dataBuffer, properties::SelectionProperty dataOptions); - - std::vector processKameleonData(std::vector kdata, glm::size3_t dimensions, properties::SelectionProperty dataOptions); - std::vector processKameleonData2(std::vector kdata, glm::size3_t dimensions, properties::SelectionProperty dataOptions); - void addValuesFromKameleonData(float* kdata, glm::size3_t dimensions, int numOptions, int option); + void useLog(bool useLog); + void useHistogram(bool useHistogram); + void normValues(glm::vec2 normValues); + glm::size3_t dimensions(); + glm::vec2 filterValues(); void clear(); - - glm::vec2 filterValues(); -private: - void processData( - float* outputData, // Where you want your processed data to go - std::vector& inputData, //data that needs processing - float min, // min value of the input data - float max, // max valye of the input data - float sum, // sum of the input data - int selected = 0 - ); - +protected: float processDataPoint(float value, int option); - float normalizeWithStandardScore(float value, float mean, float sd); + void initializeVectors(int numOptions); + void calculateFilterValues(std::vector selectedOptions); + void add(std::vector>& optionValues, std::vector& sum); + glm::size3_t _dimensions; bool _useLog; bool _useHistogram; @@ -96,10 +68,9 @@ private: std::vector _min; std::vector _max; std::vector _sum; - std::vector _sd; + std::vector _standardDeviation; std::vector _numValues; std::vector> _histograms; - // int _numValues; std::set _coordinateVariables; }; diff --git a/modules/iswa/util/dataprocessorjson.cpp b/modules/iswa/util/dataprocessorjson.cpp new file mode 100644 index 0000000000..b3da5953a2 --- /dev/null +++ b/modules/iswa/util/dataprocessorjson.cpp @@ -0,0 +1,142 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include +#include +#include +#include + +namespace { + const std::string _loggerCat = "DataProcessorJson"; + using json = nlohmann::json; +} + +namespace openspace{ + +DataProcessorJson::DataProcessorJson() + :DataProcessor() +{} + +DataProcessorJson::~DataProcessorJson(){} + +std::vector DataProcessorJson::readMetadata(std::string data){ + std::vector options = std::vector(); + if(!data.empty()){ + json j = json::parse(data); + json variables = j["variables"]; + + for(json::iterator it = variables.begin(); it != variables.end(); ++it){ + std::string option = it.key(); + if(option == "x"){ + json row = it.value(); + json col = row.at(0); + + _dimensions = glm::size3_t(col.size(), row.size(), 1); + } + + if(_coordinateVariables.find(option) == _coordinateVariables.end()){ + options.push_back(option); + } + } + } + return options; +} + +void DataProcessorJson::addDataValues(std::string data, properties::SelectionProperty& dataOptions){ + int numOptions = dataOptions.options().size(); + initializeVectors(numOptions); + + if(!data.empty()){ + json j = json::parse(data); + json variables = j["variables"]; + + std::vector sum(numOptions, 0.0f); + std::vector> optionValues(numOptions, std::vector()); + auto options = dataOptions.options(); + + float value; + + for(int i=0; i DataProcessorJson::processData(std::string data, properties::SelectionProperty& dataOptions){ + if(!data.empty()){ + json j = json::parse(data); + json variables = j["variables"]; + + std::vector selectedOptions = dataOptions.value(); + int numSelected = selectedOptions.size(); + + auto options = dataOptions.options(); + int numOptions = options.size(); + + float value; + int rowsize, colsize, i; + + std::vector dataOptions(numOptions, nullptr); + for(int option : selectedOptions){ + dataOptions[option] = new float[_dimensions.x*_dimensions.y]{0.0f}; + + json row = variables[options[option].description]; + rowsize = row.size(); + + for(int y=0; y(); +} + +}//namespace openspace diff --git a/modules/iswa/rendering/cygnetplane.h b/modules/iswa/util/dataprocessorjson.h similarity index 78% rename from modules/iswa/rendering/cygnetplane.h rename to modules/iswa/util/dataprocessorjson.h index 337fd32a41..b6213cd7d4 100644 --- a/modules/iswa/rendering/cygnetplane.h +++ b/modules/iswa/util/dataprocessorjson.h @@ -21,28 +21,22 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include -#ifndef __CYGNETPLANE_H__ -#define __CYGNETPLANE_H__ +#ifndef __DATAPROCESSORJSON_H__ +#define __DATAPROCESSORJSON_H__ -#include -#include -#include +namespace openspace { -namespace openspace{ -class CygnetPlane : public IswaCygnet { +class DataProcessorJson : public DataProcessor { public: - CygnetPlane(const ghoul::Dictionary& dictionary); - ~CygnetPlane(); + DataProcessorJson(); + ~DataProcessorJson(); -protected: - virtual bool createGeometry() override; - virtual bool destroyGeometry() override; - virtual void renderGeometry() const override; - - GLuint _quad; - GLuint _vertexPositionBuffer; + virtual std::vector readMetadata(std::string data) override; + virtual void addDataValues(std::string data, properties::SelectionProperty& dataOptions) override; + virtual std::vector processData(std::string data, properties::SelectionProperty& dataOptions) override; }; -} //namespace openspace - -#endif //__CYGNETPLANE_H__ \ No newline at end of file + +}// namespace +#endif __DATAPROCESSORJSON_H__ \ No newline at end of file diff --git a/modules/iswa/util/dataprocessorkameleon.cpp b/modules/iswa/util/dataprocessorkameleon.cpp new file mode 100644 index 0000000000..085eb196c3 --- /dev/null +++ b/modules/iswa/util/dataprocessorkameleon.cpp @@ -0,0 +1,150 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include +#include +#include + +namespace { + const std::string _loggerCat = "DataProcessorKameleon"; +} + +namespace openspace{ + +DataProcessorKameleon::DataProcessorKameleon() + :DataProcessor() + ,_kwPath("") + ,_kw(nullptr) + ,_initialized(false) + ,_slice(0.5) +{} + +DataProcessorKameleon::~DataProcessorKameleon(){} + + +std::vector DataProcessorKameleon::readMetadata(std::string path){ + + if(!path.empty()){ + if(path != _kwPath || !_kw){ + + initializeKameleonWrapper(path); + } + + std::vector opts = _kw->getVariables(); + opts.erase( std::remove_if( + opts.begin(), + opts.end(), + [this](std::string opt){ return (opt.size() > 3 || _coordinateVariables.find(opt) != _coordinateVariables.end());} + ), + opts.end() + ); + return opts; + } + + return std::vector(); +} + +void DataProcessorKameleon::addDataValues(std::string path, properties::SelectionProperty& dataOptions){ + int numOptions = dataOptions.options().size(); + initializeVectors(numOptions); + + if(!path.empty()){ + if(path != _kwPath || !_kw) + initializeKameleonWrapper(path); + + std::vector sum(numOptions, 0.0f); + std::vector> optionValues(numOptions, std::vector()); + auto options = dataOptions.options(); + + int numValues = _dimensions.x*_dimensions.y*_dimensions.z; + + float* values; + float value; + + for(int i=0; igetUniformSliceValues(options[i].description, _dimensions, 0.5f); + + for(int j=0; j DataProcessorKameleon::processData(std::string path, properties::SelectionProperty& dataOptions, float slice, glm::size3_t& dimensions){ + _slice = slice; + _dimensions = dimensions; + return processData(path, dataOptions); +} + +std::vector DataProcessorKameleon::processData(std::string path, properties::SelectionProperty& dataOptions){ + int numOptions = dataOptions.options().size(); + + if(!path.empty()){ + if(path != _kwPath || !_kw) + initializeKameleonWrapper(path); + + std::vector selectedOptions = dataOptions.value(); + int numSelected = selectedOptions.size(); + + auto options = dataOptions.options(); + int numOptions = options.size(); + + int numValues = _dimensions.x*_dimensions.y*_dimensions.z; + + float value; + + std::vector dataOptions(numOptions, nullptr); + for(int option : selectedOptions){ + dataOptions[option] = _kw->getUniformSliceValues(options[option].description, _dimensions, _slice); + + for(int i=0; i(numOptions, nullptr); +} + +void DataProcessorKameleon::initializeKameleonWrapper(std::string path){ + const std::string& extension = ghoul::filesystem::File(absPath(path)).fileExtension(); + if(FileSys.fileExists(absPath(path)) && extension == "cdf"){ + if(_kw) _kw->close(); + + _kwPath = path; + _kw = std::make_shared(absPath(_kwPath)); + } +} + +}//namespace openspace \ No newline at end of file diff --git a/modules/iswa/util/dataprocessorkameleon.h b/modules/iswa/util/dataprocessorkameleon.h new file mode 100644 index 0000000000..f22a1f31d3 --- /dev/null +++ b/modules/iswa/util/dataprocessorkameleon.h @@ -0,0 +1,55 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include +#include + +#ifndef __DATAPROCESSORKAMELEON_H__ +#define __DATAPROCESSORKAMELEON_H__ + +namespace openspace { + +class DataProcessorKameleon : public DataProcessor { +public: + DataProcessorKameleon(); + ~DataProcessorKameleon(); + + virtual std::vector readMetadata(std::string path) override; + virtual void addDataValues(std::string data, properties::SelectionProperty& dataOptions) override; + virtual std::vector processData(std::string path, properties::SelectionProperty& dataOptions) override; + virtual std::vector processData(std::string path, properties::SelectionProperty& dataOptions, float slice, glm::size3_t& dimensions); + void dimensions(glm::size3_t dimensions){_dimensions = dimensions;} + +private: + void initializeKameleonWrapper(std::string kwPath); + + std::shared_ptr _kw; + std::string _kwPath; + std::vector _loadedVariables; + bool _initialized; + float _slice; + // std::vector _data; +}; + +}// namespace +#endif __DATAPROCESSORKAMELEON_H__ \ No newline at end of file diff --git a/modules/iswa/util/dataprocessortext.cpp b/modules/iswa/util/dataprocessortext.cpp new file mode 100644 index 0000000000..4f27d31229 --- /dev/null +++ b/modules/iswa/util/dataprocessortext.cpp @@ -0,0 +1,163 @@ +/***************************************************************************************** +* * +* OpenSpace * +* * +* Copyright (c) 2014-2015 * +* * +* Permission is hereby granted, free of charge, to any person obtaining a copy of this * +* software and associated documentation files (the "Software"), to deal in the Software * +* without restriction, including without limitation the rights to use, copy, modify, * +* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +* permit persons to whom the Software is furnished to do so, subject to the following * +* conditions: * +* * +* The above copyright notice and this permission notice shall be included in all copies * +* or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +****************************************************************************************/ +#include +#include +#include + +namespace { + const std::string _loggerCat = "DataProcessorText"; +} + +namespace openspace{ + +DataProcessorText::DataProcessorText() + :DataProcessor() +{} + +DataProcessorText::~DataProcessorText(){} + +std::vector DataProcessorText::readMetadata(std::string data){ + //The intresting part of the file looks like this: + //# Output data: field with 61x61=3721 elements + //# x y z N V_x B_x + + std::vector options = std::vector(); + std::string info = "# Output data: field with "; //The string where the interesting data begins + if(!data.empty()){ + std::string line; + std::stringstream memorystream(data); + + while(getline(memorystream, line)){ + if(line.find(info) == 0){ + line = line.substr(info.size()); + std::stringstream ss(line); + + std::string token; + getline(ss, token, 'x'); + int x = std::stoi(token); + + getline(ss, token, '='); + int y = std::stoi(token); + + _dimensions = glm::size3_t(x, y, 1); + + getline(memorystream, line); + line = line.substr(1); //because of the # char + + ss = std::stringstream(line); + std::string option; + while(ss >> option){ + if(_coordinateVariables.find(option) == _coordinateVariables.end()) + options.push_back(option); + } + } + } + } + return options; +} + +void DataProcessorText::addDataValues(std::string data, properties::SelectionProperty& dataOptions){ + int numOptions = dataOptions.options().size(); + initializeVectors(numOptions); + + if(!data.empty()){ + std::string line; + std::stringstream memorystream(data); + + std::vector sum(numOptions, 0.0f); //for standard diviation in the add() function + std::vector> optionValues(numOptions, std::vector()); + + std::vector values; + float value; + + while(getline(memorystream, line)){ + if(line.find("#") == 0) continue; + + values = std::vector(); + std::stringstream ss(line); + copy( + std::istream_iterator (ss), + std::istream_iterator (), + back_inserter(values) + ); + + if(values.size() <= 0) continue; + + for(int i=0; i DataProcessorText::processData(std::string data, properties::SelectionProperty& dataOptions){ + if(!data.empty()){ + std::string line; + std::stringstream memorystream(data); + + std::vector selectedOptions = dataOptions.value(); + int numSelected = selectedOptions.size(); + int numOptions = dataOptions.options().size(); + + std::vector values; + float value; + + std::vector dataOptions(numOptions, nullptr); + for(int option : selectedOptions){ + dataOptions[option] = new float[_dimensions.x*_dimensions.y]{0.0f}; + } + + int numValues = 0; + while(getline(memorystream, line)){ + if(line.find("#") == 0) continue; + + values = std::vector(); + std::stringstream ss(line); + copy( + std::istream_iterator (ss), + std::istream_iterator (), + back_inserter(values) + ); + + for(int option : selectedOptions){ + value = values[option+3]; //+3 because options x, y and z in the file + dataOptions[option][numValues] = processDataPoint(value, option); + } + numValues++; + } + + calculateFilterValues(selectedOptions); + return dataOptions; + } + return std::vector(); +} + +}//namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/cygnetsphere.h b/modules/iswa/util/dataprocessortext.h similarity index 71% rename from modules/iswa/rendering/cygnetsphere.h rename to modules/iswa/util/dataprocessortext.h index 055c25b3f5..17f87e0bb9 100644 --- a/modules/iswa/rendering/cygnetsphere.h +++ b/modules/iswa/util/dataprocessortext.h @@ -2,7 +2,7 @@ * * * OpenSpace * * * -* Copyright (c) 2014-2016 * +* Copyright (c) 2014-2015 * * * * 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 * @@ -21,34 +21,27 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include -#ifndef __CYGNETSPHERE_H__ -#define __CYGNETSPHERE_H__ +#ifndef __DATAPROCESSORTEXT_H__ +#define __DATAPROCESSORTEXT_H__ -#include +namespace openspace { -namespace openspace{ -class PowerScaledSphere; - -namespace planetgeometry { - class PlanetGeometry; -} - -class CygnetSphere : public IswaCygnet { +class DataProcessorText : public DataProcessor { public: - CygnetSphere(const ghoul::Dictionary& dictionary); - ~CygnetSphere(); + DataProcessorText(); + ~DataProcessorText(); + + virtual std::vector readMetadata(std::string data) override; + virtual void addDataValues(std::string data, properties::SelectionProperty& dataOptions) override; + virtual std::vector processData(std::string data, properties::SelectionProperty& dataOptions) override; -protected: - std::shared_ptr _sphere; private: - virtual bool createGeometry() override; - virtual bool destroyGeometry() override; - virtual void renderGeometry() const override; - - float _radius; + // void initialize(int numOptions); + // void add(std::vector>& optionValues, std::vector& sum); + // void calculateFilterValues(std::vector selectedOptions); }; -} //namespace openspace - -#endif // __CYGNETSPHERE_H__ \ No newline at end of file +}// namespace +#endif __DATAPROCESSORTEXT_H__ diff --git a/modules/iswa/util/iswamanager.cpp b/modules/iswa/util/iswamanager.cpp index e85ba5c88d..3dec502c8f 100644 --- a/modules/iswa/util/iswamanager.cpp +++ b/modules/iswa/util/iswamanager.cpp @@ -26,15 +26,20 @@ #include #include #include +#include + #include #include -#include +#include +#include +#include #include #include #include #include +#include #include #include #include @@ -69,12 +74,16 @@ IswaManager::IswaManager() _type[CygnetType::Texture] = "Texture"; _type[CygnetType::Data] = "Data"; _type[CygnetType::Kameleon] = "Kameleon"; + // _type[CygnetType::TexturePlane] = "TexturePlane"; + // _type[CygnetType::DataPlane] = "DataPlane"; + // _type[CygnetType::KameleonPlane] = "KameleonPlane"; + // _type[CygnetType::Kameleon] = "DataSphere"; _geom[CygnetGeometry::Plane] = "Plane"; _geom[CygnetGeometry::Sphere] = "Sphere"; DlManager.fetchFile( - "http://iswa2.ccmc.gsfc.nasa.gov/IswaSystemWebApp/CygnetHealthServlet", + "http://iswa3.ccmc.gsfc.nasa.gov/IswaSystemWebApp/CygnetHealthServlet", [this](const DownloadManager::MemoryFile& file){ fillCygnetInfo(std::string(file.buffer)); }, @@ -137,30 +146,27 @@ void IswaManager::addIswaCygnet(int id, std::string type, std::string group){ // Download metadata DlManager.fetchFile( "http://128.183.168.116:3000/" + std::to_string(-id), - // "http://10.0.0.76:3000/" + std::to_string(-id), + // "http://localhost:3000/" + std::to_string(-id), metadataCallback, [id](const std::string& err){ LDEBUG("Download to memory was aborted for data cygnet with id "+ std::to_string(id)+": " + err); } ); } - // else{ - // // Kameleonplane? - // // LERROR("No cygnet with id 0"); - // std::string kwPath = "${OPENSPACE_DATA}/BATSRUS.cdf"; - // if(type == "x" || type == "y" || type == "z") - // createKameleonPlane(kwPath, type, group); - // else - // createKameleonPlane(kwPath, "z", group); - // } } -void IswaManager::addKameleonCdf(std::string group, int pos){ +void IswaManager::addKameleonCdf(std::string groupName, int pos){ // auto info = _cdfInformation[group][pos]; // std::cout << group << " " << pos << std::endl; - createKameleonPlane(_cdfInformation[group][pos], "z"); - createKameleonPlane(_cdfInformation[group][pos], "y"); - createKameleonPlane(_cdfInformation[group][pos], "x"); + auto group = iswaGroup(groupName); + if(group){ + std::dynamic_pointer_cast(group)->changeCdf(_cdfInformation[groupName][pos].path); + return; + } + + createKameleonPlane(_cdfInformation[groupName][pos], "z"); + createKameleonPlane(_cdfInformation[groupName][pos], "y"); + createKameleonPlane(_cdfInformation[groupName][pos], "x"); } std::future IswaManager::fetchImageCygnet(int id){ @@ -191,9 +197,9 @@ std::string IswaManager::iswaUrl(int id, std::string type){ std::string url; if(id < 0){ url = "http://128.183.168.116:3000/"+type+"/" + std::to_string(-id) + "/"; - // url = "http://10.0.0.76:3000/"+type+"/" + std::to_string(-id) + "/"; + // url = "http://localhost:3000/"+type+"/" + std::to_string(-id) + "/"; } else{ - url = "http://iswa2.ccmc.gsfc.nasa.gov/IswaSystemWebApp/iSWACygnetStreamer?window=-1&cygnetId="+ std::to_string(id) +"×tamp="; + url = "http://iswa3.ccmc.gsfc.nasa.gov/IswaSystemWebApp/iSWACygnetStreamer?window=-1&cygnetId="+ std::to_string(id) +"×tamp="; } std::string t = Time::ref().currentTimeUTC(); @@ -212,43 +218,26 @@ std::string IswaManager::iswaUrl(int id, std::string type){ return url; } -std::shared_ptr > IswaManager::groupEvent(std::string groupName, CygnetType type){ - - // Do some type checking and get the groupEvent +void IswaManager::registerGroup(std::string groupName, std::string type){ if(_groups.find(groupName) == _groups.end()){ - _groups.insert(std::pair>(groupName, std::make_shared(groupName, type))); + bool dataGroup = (type == typeid(DataPlane).name()) || + (type == typeid(DataSphere).name()); + + bool kameleonGroup = (type == typeid(KameleonPlane).name()); + if(dataGroup){ + _groups.insert(std::pair>(groupName, std::make_shared(groupName, type))); + }else if(kameleonGroup){ + _groups.insert(std::pair>(groupName, std::make_shared(groupName, type))); + }else{ + _groups.insert(std::pair>(groupName, std::make_shared(groupName, type))); + } } else if(!_groups[groupName]->isType(type)){ - LWARNING("Can't subscribe to Events from groups with diffent type"); - return nullptr; + LWARNING("Can't add cygnet to groups with diffent type"); } - - return _groups[groupName]->groupEvent(); } -std::shared_ptr IswaManager::registerToGroup(std::string groupName, CygnetType type){ - if(_groups.find(groupName) == _groups.end()){ - _groups.insert(std::pair>(groupName, std::make_shared(groupName, type))); - } else if(!_groups[groupName]->isType(type)){ - LWARNING("Can't subscribe to Events from groups with diffent type"); - return nullptr; - } - return _groups[groupName]; -} - -// void IswaManager::unregisterFromGroup(std::string name, IswaCygnet* cygnet){ -// if(_groups.find(name) != _groups.end()){ -// _groups[name]->unregisterCygnet(cygnet); -// } -// } - -// void IswaManager::registerOptionsToGroup(std::string name, const std::vector& options){ -// if(_groups.find(name) != _groups.end()){ -// _groups[name]->registerOptions(options); -// } -// } - -std::shared_ptr IswaManager::iswaGroup(std::string name){ +std::shared_ptr IswaManager::iswaGroup(std::string name){ if(_groups.find(name) != _groups.end()){ return _groups[name]; } @@ -260,7 +249,7 @@ std::map>& IswaManager::cygnetInformation(){ return _cygnetInformation; } -std::map>& IswaManager::groups(){ +std::map>& IswaManager::groups(){ return _groups; } @@ -272,19 +261,17 @@ std::shared_ptr IswaManager::downloadMetadata(int id){ std::shared_ptr metaFuture = std::make_shared(); metaFuture->id = id; - DlManager.downloadToMemory( - "http://128.183.168.116:3000/" + std::to_string(-id), - // "http://10.0.0.76:3000/" + std::to_string(-id), - metaFuture->json, - [metaFuture](const DownloadManager::FileFuture& f){ - if(f.isFinished){ - metaFuture->isFinished; - LDEBUG("Download to memory finished"); - } else if (f.isAborted){ - LWARNING("Download to memory was aborted: " + f.errorMessage); - } - } - ); + DlManager.fetchFile( + "http://128.183.168.116:3000/" + std::to_string(-id), + // "http://localhost:3000/" + std::to_string(-id), + [&metaFuture](const DownloadManager::MemoryFile& file){ + metaFuture->json = std::string(file.buffer, file.size); + metaFuture->isFinished = true; + }, + [](const std::string& err){ + LWARNING("Download Metadata to memory was aborted: " + err); + } + ); return metaFuture; } @@ -369,7 +356,7 @@ std::string IswaManager::parseKWToLuaTable(CdfInfo info, std::string cut){ } std::string table = "{" - "Name = '" +info.group+"_"+info.name+"-"+cut+"'," + "Name = '" +info.name+ "'," "Parent = '" + parent + "', " "Renderable = {" "Type = 'KameleonPlane', " @@ -383,11 +370,11 @@ std::string IswaManager::parseKWToLuaTable(CdfInfo info, std::string cut){ "axisCut = '"+cut+"'," "CoordinateType = '" + coordinateType + "', " "Group = '"+ info.group + "'," + // "Group = ''," "fieldlineSeedsIndexFile = '"+info.fieldlineSeedsIndexFile+"'" "}" "}" - ; - // std::cout << table << std::endl; + ; return table; } } @@ -450,12 +437,25 @@ void IswaManager::createScreenSpace(int id){ void IswaManager::createPlane(std::shared_ptr data){ // check if this plane already exist + std::string name = _type[data->type] + _geom[data->geom] + std::to_string(data->id); if(!data->group.empty()){ + std::string type; + if(data->type == CygnetType::Data){ + type = typeid(DataPlane).name(); + }else{ + type = typeid(TexturePlane).name(); + } + + registerGroup(data->group, type); + auto it = _groups.find(data->group); - if(it == _groups.end() || (*it).second->isType((CygnetType) data->type)) + if(it == _groups.end() || (*it).second->isType(type)){ name = data->group +"_"+ name; + }else{ + data->group=""; + } } data->name = name; @@ -477,9 +477,15 @@ void IswaManager::createSphere(std::shared_ptr data){ std::string name = _type[data->type] + _geom[data->geom] + std::to_string(data->id); if(!data->group.empty()){ + std::string type = typeid(DataSphere).name(); + registerGroup(data->group, type); + auto it = _groups.find(data->group); - if(it == _groups.end() || (*it).second->isType((CygnetType) data->type)) + if(it == _groups.end() || (*it).second->isType(type)){ name = data->group +"_"+name; + }else{ + data->group=""; + } } data->name = name; @@ -496,14 +502,32 @@ void IswaManager::createSphere(std::shared_ptr data){ } void IswaManager::createKameleonPlane(CdfInfo info, std::string cut){ - std::cout << info.name << " " << cut << std::endl; const std::string& extension = ghoul::filesystem::File(absPath(info.path)).fileExtension(); - if(FileSys.fileExists(absPath(info.path)) && extension == "cdf"){ + + + if(!info.group.empty()){ + std::string type = typeid(KameleonPlane).name(); + registerGroup(info.group, type); + + auto it = _groups.find(info.group); + if(it == _groups.end() || (*it).second->isType(type)){ + info.name = info.group +"_"+info.name; + }else{ + info.group=""; + } + } + + info.name = info.name+"-"+cut; + + if( OsEng.renderEngine().scene()->sceneGraphNode(info.name) ){ + LERROR("A node with name \"" + info.name +"\" already exist"); + return; + } + std::string luaTable = parseKWToLuaTable(info, cut); if(!luaTable.empty()){ - // // std::cout << luaTable << std::endl; std::string script = "openspace.addSceneGraphNode(" + luaTable + ");"; OsEng.scriptEngine().queueScript(script); } diff --git a/modules/iswa/util/iswamanager.h b/modules/iswa/util/iswamanager.h index ce7e313298..7707fa4a14 100644 --- a/modules/iswa/util/iswamanager.h +++ b/modules/iswa/util/iswamanager.h @@ -48,7 +48,7 @@ namespace openspace { -class IswaGroup; +class IswaBaseGroup; class IswaCygnet; struct CdfInfo { @@ -95,15 +95,10 @@ public: std::future fetchDataCygnet(int id); std::string iswaUrl(int id, std::string type = "image"); - std::shared_ptr > groupEvent(std::string name, CygnetType type); - std::shared_ptr registerToGroup(std::string name, CygnetType type); - void unregisterFromGroup(std::string name, IswaCygnet* cygnet); - // void registerOptionsToGroup(std::string name, const std::vector& options); - std::shared_ptr iswaGroup(std::string name); + std::shared_ptr iswaGroup(std::string name); std::map>& cygnetInformation(); - std::map>& groups(); - // std::vector& cdfInformation(); + std::map>& groups(); std::map>& cdfInformation(); static scripting::ScriptEngine::LuaLibrary luaLibrary(); @@ -125,7 +120,8 @@ private: void createKameleonPlane(CdfInfo info, std::string cut); void fillCygnetInfo(std::string jsonString); - + void registerGroup(std::string groupName, std::string type); + std::map _month; std::map _type; std::map _geom; @@ -133,9 +129,8 @@ private: std::shared_ptr _kameleon; std::set _kameleonFrames; - std::map> _groups; + std::map> _groups; std::map> _cygnetInformation; - // std::vector _cdfInformation; std::map> _cdfInformation; ghoul::Event<> _iswaEvent; diff --git a/modules/kameleon/include/kameleonwrapper.h b/modules/kameleon/include/kameleonwrapper.h index a1da8bb3ab..fafa688bfb 100644 --- a/modules/kameleon/include/kameleonwrapper.h +++ b/modules/kameleon/include/kameleonwrapper.h @@ -139,6 +139,7 @@ public: std::string getParent(); std::string getFrame(); std::vector getVariables(); + std::vector getLoadedVariables(); private: typedef std::vector TraceLine; diff --git a/modules/kameleon/src/kameleonwrapper.cpp b/modules/kameleon/src/kameleonwrapper.cpp index caec7396d8..b9f0423075 100644 --- a/modules/kameleon/src/kameleonwrapper.cpp +++ b/modules/kameleon/src/kameleonwrapper.cpp @@ -477,12 +477,12 @@ float* KameleonWrapper::getUniformSliceValues( } } } - for(size_t i = 0; i < size; ++i) { + // for(size_t i = 0; i < size; ++i) { // double normalizedVal = (doubleData[i]-minValue)/(maxValue-minValue); // data[i] = glm::clamp(normalizedVal, 0.0, 1.0); // data[i] = 1; // std::cout << minValue << ", " << maxValue << ", " << doubleData[i] << ", " << normalizedVal << ", " << data[i] << std::endl; - } + // } delete[] doubleData; return data; @@ -1057,4 +1057,8 @@ std::vector KameleonWrapper::getVariables(){ return variableNames; } +std::vector KameleonWrapper::getLoadedVariables(){ + return _kameleon->getLoadedVariables(); +} + } // namespace openspace diff --git a/modules/onscreengui/src/guiiswacomponent.cpp b/modules/onscreengui/src/guiiswacomponent.cpp index 0dfbcee8d9..853dac4d87 100644 --- a/modules/onscreengui/src/guiiswacomponent.cpp +++ b/modules/onscreengui/src/guiiswacomponent.cpp @@ -70,21 +70,21 @@ void GuiIswaComponent::render() { bool iondatavalue = _iondata; ImGui::Begin("ISWA", &_isEnabled, size, 0.5f); - ImGui::Text("Global Magnetosphere"); - ImGui::Checkbox("Gm From Data", &_gmdata); ImGui::SameLine(); - ImGui::Checkbox("Gm From Images", &_gmimage); + // ImGui::Text("Global Magnetosphere"); + // ImGui::Checkbox("Gm From Data", &_gmdata); ImGui::SameLine(); + // ImGui::Checkbox("Gm From Images", &_gmimage); - ImGui::Text("Ionosphere"); - ImGui::Checkbox("Ion From Data", &_iondata); + // ImGui::Text("Ionosphere"); + // ImGui::Checkbox("Ion From Data", &_iondata); - ImGui::Spacing(); - static const int addCygnetBufferSize = 256; - static char addCygnetBuffer[addCygnetBufferSize]; - ImGui::InputText("addCynget", addCygnetBuffer, addCygnetBufferSize); + // ImGui::Spacing(); + // static const int addCygnetBufferSize = 256; + // static char addCygnetBuffer[addCygnetBufferSize]; + // ImGui::InputText("addCynget", addCygnetBuffer, addCygnetBufferSize); - if(ImGui::SmallButton("Add Cygnet")) - OsEng.scriptEngine().queueScript("openspace.iswa.addCygnet("+std::string(addCygnetBuffer)+");"); + // if(ImGui::SmallButton("Add Cygnet")) + // OsEng.scriptEngine().queueScript("openspace.iswa.addCygnet("+std::string(addCygnetBuffer)+");"); if(_gmdata != gmdatavalue){ if(_gmdata){ @@ -138,8 +138,8 @@ void GuiIswaComponent::render() { if(cdfOptionValue != cdfOption){ if(cdfOptionValue >= 0){ groupName = cdfs[cdfOptionValue].group; - std::cout << groupName << std::endl; - OsEng.scriptEngine().queueScript("openspace.iswa.removeGroup('"+groupName+"');"); + // std::cout << groupName << std::endl; + // OsEng.scriptEngine().queueScript("openspace.iswa.removeGroup('"+groupName+"');"); } std::string path = cdfs[cdfOption].path; diff --git a/src/engine/downloadmanager.cpp b/src/engine/downloadmanager.cpp index 27ca9f8ec3..c0716b34ea 100644 --- a/src/engine/downloadmanager.cpp +++ b/src/engine/downloadmanager.cpp @@ -63,13 +63,6 @@ namespace { return written; } - - size_t writeToMemory(void *contents, size_t size, size_t nmemb, void *userp) - { - ((std::string*)userp)->append((char*)contents, size * nmemb); - return size * nmemb; - } - size_t writeMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp){ size_t realsize = size * nmemb; openspace::DownloadManager::MemoryFile *mem = (openspace::DownloadManager::MemoryFile *)userp; @@ -222,66 +215,6 @@ std::shared_ptr DownloadManager::downloadFile( return future; } - -std::shared_ptr DownloadManager::downloadToMemory( - const std::string& url, std::string& memoryBuffer, - DownloadFinishedCallback finishedCallback) -{ - - std::shared_ptr future = std::make_shared(std::string("memory")); - LDEBUG("Start downloading file: '" << url << "' into memory"); - - auto downloadFunction = [url, finishedCallback, future, &memoryBuffer]() { - CURL* curl = curl_easy_init(); - if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &memoryBuffer); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeToMemory); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); - - CURLcode res = curl_easy_perform(curl); - if(res == CURLE_OK){ - // ask for the content-type - char *ct; - res = curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &ct); - if (res == CURLE_OK){ - future->format = std::string(ct); - future->isFinished = true; - } - } else { - future->errorMessage = curl_easy_strerror(res); - future->isAborted = true; - } - - if (finishedCallback) - finishedCallback(*future); - - curl_easy_cleanup(curl); - - } - }; - - if (_useMultithreadedDownload) { - std::thread t = std::thread(downloadFunction); - -#ifdef WIN32 - std::thread::native_handle_type h = t.native_handle(); - SetPriorityClass(h, IDLE_PRIORITY_CLASS); - SetThreadPriority(h, THREAD_PRIORITY_LOWEST); -#else - // TODO: Implement thread priority ---abock -#endif - - t.detach(); - } - else { - downloadFunction(); - } - - return future; -} - std::future DownloadManager::fetchFile( const std::string& url, SuccessCallback successCallback, ErrorCallback errorCallback) @@ -325,7 +258,7 @@ std::future DownloadManager::fetchFile( std::string err = curl_easy_strerror(res); errorCallback(err); curl_easy_cleanup(curl); - // Throw an error and use try-catch around future.get() call + // Throw an error and use try-catch around call to future.get() //throw std::runtime_error( err ); // or set a boolean variable in MemoryFile to determine if it is valid/corrupted or not. diff --git a/src/query/query.cpp b/src/query/query.cpp index fb73b94d1c..e80cfcc36b 100644 --- a/src/query/query.cpp +++ b/src/query/query.cpp @@ -85,7 +85,7 @@ properties::Property* property(const std::string& uri) { return property; } #ifdef OPENSPACE_MODULE_ISWA_ENABLED - std::shared_ptr group = IswaManager::ref().iswaGroup(nameUri); + std::shared_ptr group = IswaManager::ref().iswaGroup(nameUri); if(group){ properties::Property* property = group->property(remainingUri); return property;