diff --git a/data/scene/iswa/cdf/fieldlines.json b/data/scene/iswa/cdf/fieldlines.json new file mode 100644 index 0000000000..fee0f94ef8 --- /dev/null +++ b/data/scene/iswa/cdf/fieldlines.json @@ -0,0 +1,7 @@ +{ + "Separatrix Seeds": "${OPENSPACE_DATA}/scene/fieldlines/bats_seeds/BATS_R_US_separatrix_seeds_all.txt", + "Closed Seeds": "${OPENSPACE_DATA}/scene/fieldlines/bats_seeds/BATS_R_US_closed_seeds_all.txt", + "Open North Seeds": "${OPENSPACE_DATA}/scene/fieldlines/bats_seeds/BATS_R_US_open_north_all.txt", + "Open South Seeds": "${OPENSPACE_DATA}/scene/fieldlines/bats_seeds/BATS_R_US_open_south_all.txt", + "Solar Wind Seeds": "${OPENSPACE_DATA}/scene/fieldlines/bats_seeds/BATS_R_US_solar_wind_all.txt" +} \ No newline at end of file diff --git a/modules/fieldlines/rendering/renderablefieldlines.cpp b/modules/fieldlines/rendering/renderablefieldlines.cpp index 495fc7e33c..d5c96583bb 100644 --- a/modules/fieldlines/rendering/renderablefieldlines.cpp +++ b/modules/fieldlines/rendering/renderablefieldlines.cpp @@ -95,9 +95,10 @@ RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary) dictionary.hasKeyAndValue(SceneGraphNode::KeyName), "Renderable does not have a name" ); - + std::string name; dictionary.getValue(SceneGraphNode::KeyName, name); + setName(name); _loggerCat = "RenderableFieldlines [" + name + "]"; @@ -145,6 +146,13 @@ RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary) _seedPointSourceFile.onChange(dirtySeedpoints); addProperty(_seedPointSourceFile); + + // OsEng.gui()._property.registerProperty(&_enabled); + // OsEng.gui()._property.registerProperty(&_stepSize); + // OsEng.gui()._property.registerProperty(&_classification); + // OsEng.gui()._property.registerProperty(&_fieldlineColor); + // OsEng.gui()._property.registerProperty(&_seedPointSource); + // OsEng.gui()._property.registerProperty(&_seedPointSourceFile); } void RenderableFieldlines::initializeDefaultPropertyValues() { @@ -219,6 +227,13 @@ bool RenderableFieldlines::deinitialize() { _fieldlineVAO = 0; glDeleteBuffers(1, &_vertexPositionBuffer); _vertexPositionBuffer = 0; + + RenderEngine& renderEngine = OsEng.renderEngine(); + if (_program) { + renderEngine.removeRenderProgram(_program); + _program = nullptr; + } + return true; } diff --git a/modules/iswa/rendering/kameleonplane.cpp b/modules/iswa/rendering/kameleonplane.cpp index 117dcd12b8..5245a6186f 100644 --- a/modules/iswa/rendering/kameleonplane.cpp +++ b/modules/iswa/rendering/kameleonplane.cpp @@ -36,9 +36,11 @@ #include #include #include +#include namespace { + using json = nlohmann::json; const std::string _loggerCat = "KameleonPlane"; } @@ -52,6 +54,7 @@ KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) ,_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") + ,_fieldlines("fieldlineSeedsIndexFile", "Fieldline Seedpoints") { std::string name; dictionary.getValue("Name", name); @@ -65,6 +68,7 @@ KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) addProperty(_backgroundValues); addProperty(_transferFunctionsFile); addProperty(_dataOptions); + addProperty(_fieldlines); if(_data->groupName.empty()){ OsEng.gui()._iswa.registerProperty(&_useLog); @@ -73,6 +77,7 @@ KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) OsEng.gui()._iswa.registerProperty(&_backgroundValues); OsEng.gui()._iswa.registerProperty(&_transferFunctionsFile); OsEng.gui()._iswa.registerProperty(&_dataOptions); + OsEng.gui()._iswa.registerProperty(&_fieldlines); } setTransferFunctions(_transferFunctionsFile.value()); @@ -107,6 +112,13 @@ KameleonPlane::KameleonPlane(const ghoul::Dictionary& dictionary) _type = IswaManager::CygnetType::Data; dictionary.getValue("kwPath", _kwPath); + + std::string fieldlineIndexFile; + dictionary.getValue("fieldlineSeedsIndexFile", fieldlineIndexFile); + readFieldlinePaths(absPath(fieldlineIndexFile)); + + _dataOptions.onChange([this](){updateTexture();}); + _fieldlines.onChange([this](){ updateFieldlineSeeds();} ); std::string axis; dictionary.getValue("axisCut", axis); @@ -363,4 +375,49 @@ void KameleonPlane::fillOptions(){ IswaManager::ref().registerOptionsToGroup(_data->groupName, _dataOptions.options()); } +void KameleonPlane::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), _kwPath, std::get<1>(seedPath.second)); + std::get<2>(seedPath.second) = true; + } + } +} + +void KameleonPlane::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; + } + + //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(it.key(), it.value(), false); + i++; + } + // _fieldlines.setValue(std::vector(1,0)); + } +} + }// namespace openspace \ No newline at end of file diff --git a/modules/iswa/rendering/kameleonplane.h b/modules/iswa/rendering/kameleonplane.h index 00f48dd7ae..5a1f9f9bef 100644 --- a/modules/iswa/rendering/kameleonplane.h +++ b/modules/iswa/rendering/kameleonplane.h @@ -45,6 +45,8 @@ virtual bool readyToRender() override; virtual void setUniformAndTextures() override; virtual bool createShader() override; + void readFieldlinePaths(std::string indexFile); + void updateFieldlineSeeds(); void setTransferFunctions(std::string tfPath); void fillOptions(); @@ -52,6 +54,7 @@ static int id(); properties::SelectionProperty _dataOptions; + properties::SelectionProperty _fieldlines; properties::StringProperty _transferFunctionsFile; properties::Vec2Property _backgroundValues; @@ -68,8 +71,14 @@ std::string _var; std::vector _dataSlices; - std::shared_ptr _dataProcessor; - + std::shared_ptr _dataProcessor; + + /** + * _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. + * this is the name, path to seedpoints file and a boolean to determine if it is active or inactive. + */ + std::map > _fieldlineState; }; } // namespace openspace diff --git a/modules/iswa/util/iswamanager.cpp b/modules/iswa/util/iswamanager.cpp index 37f601836f..4cdfbe9b55 100644 --- a/modules/iswa/util/iswamanager.cpp +++ b/modules/iswa/util/iswamanager.cpp @@ -149,7 +149,6 @@ void IswaManager::addIswaCygnet(int id, std::string type, std::string group){ createKameleonPlane(kwPath, type, group); else createKameleonPlane(kwPath, "z", group); - } } @@ -358,6 +357,7 @@ std::string IswaManager::parseKWToLuaTable(std::string kwPath, std::string cut, "axisCut = '"+cut+"'," "CoordinateType = '" + coordinateType + "', " "Group = '"+ group + "'," + "fieldlineSeedsIndexFile = '${OPENSPACE_DATA}/scene/iswa/cdf/fieldlines.json'" "}" "}" ; @@ -485,6 +485,40 @@ void IswaManager::createKameleonPlane(std::string kwPath, std::string cut, std:: } } +void IswaManager::createFieldline(std::string name, std::string cdfPath, std::string seedPath){ + const std::string& extension = ghoul::filesystem::File(absPath(cdfPath)).fileExtension(); + + if(FileSys.fileExists(absPath(cdfPath)) && extension == "cdf"){ + std::string luaTable = "{" + "Name = '" + name + "'," + "Parent = 'Earth'," + "Renderable = {" + "Type = 'RenderableFieldlines'," + "VectorField = {" + "Type = 'VolumeKameleon'," + "File = '" + cdfPath + "'," + "Model = 'BATSRUS'," + "Variables = {'bx', 'by', 'bz'}" + "}," + "Fieldlines = {" + "Stepsize = 1," + "Classification = true" + "}," + "SeedPoints = {" + "Type = 'File'," + "File = '" + seedPath + "'" + "}" + "}" + "}"; + if(!luaTable.empty()){ + std::string script = "openspace.addSceneGraphNode(" + luaTable + ");"; + OsEng.scriptEngine().queueScript(script); + } + }else{ + LWARNING( cdfPath + " is not a cdf file or can't be found."); + } +} + void IswaManager::fillCygnetInfo(std::string jsonString){ if(jsonString != ""){ json j = json::parse(jsonString); diff --git a/modules/iswa/util/iswamanager.h b/modules/iswa/util/iswamanager.h index e2a10c9274..63144923a1 100644 --- a/modules/iswa/util/iswamanager.h +++ b/modules/iswa/util/iswamanager.h @@ -77,6 +77,7 @@ public: ~IswaManager(); void addIswaCygnet(int id, std::string type = "Texture", std::string group = ""); + void createFieldline(std::string name, std::string cdfPath, std::string seedPath); std::future fetchImageCygnet(int id); std::future fetchDataCygnet(int id);