From 6253a5cf2e0e66f268b6bd843c2aaa75c0928ecc Mon Sep 17 00:00:00 2001 From: GPayne Date: Sun, 22 Mar 2020 20:59:15 -0600 Subject: [PATCH 01/61] First pass on tracking changed properties/assets since initialization --- include/openspace/engine/openspaceengine.h | 1 + include/openspace/properties/property.h | 8 ++++++++ include/openspace/properties/templateproperty.inl | 2 ++ include/openspace/scene/assetloader.h | 3 +++ src/engine/openspaceengine.cpp | 14 ++++++++++++++ src/properties/property.cpp | 4 ++++ src/scene/assetloader.cpp | 2 ++ 7 files changed, 34 insertions(+) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 539530cad0..b150d594d1 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -76,6 +76,7 @@ public: const glm::mat4& projectionMatrix); void drawOverlays(); void postDraw(); + void resetPropertyChangeFlags(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); void charCallback(unsigned int codepoint, KeyModifier modifier); void mouseButtonCallback(MouseButton button, MouseAction action, KeyModifier mods); diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 1e5dd5c8b3..0cfbbc9be0 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -495,6 +495,11 @@ public: */ virtual std::string generateAdditionalJsonDescription() const; + /** + * Reset the valChanged flag to an unchanged state, as if value has not been changed. + */ + void resetToUnchanged(); + protected: static const char* IdentifierKey; static const char* NameKey; @@ -531,6 +536,9 @@ protected: /// The callback function sthat will be invoked whenever the value changes std::vector>> _onDeleteCallbacks; + /// Flag indicating that this property value has been changed after initialization + bool valChanged = false; + private: void notifyDeleteListeners(); diff --git a/include/openspace/properties/templateproperty.inl b/include/openspace/properties/templateproperty.inl index 56fdca6a1a..78af3f6039 100644 --- a/include/openspace/properties/templateproperty.inl +++ b/include/openspace/properties/templateproperty.inl @@ -176,6 +176,7 @@ void openspace::properties::TemplateProperty::setValue(T val) { if (val != _value) { _value = std::move(val); notifyChangeListeners(); + valChanged = true; } } @@ -196,6 +197,7 @@ void TemplateProperty::set(std::any value) { if (v != _value) { _value = std::move(v); notifyChangeListeners(); + valChanged = true; } } diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index ea32931835..6b3dac5369 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -226,6 +226,9 @@ private: std::unordered_map>> _onDependencyDeinitializationFunctionRefs; int _assetsTableRef; + + std::vector profileAssetsAdded; + std::vector profileAssetsRemoved; }; } // namespace openspace diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 2ed17ecb9a..0d0a8f4ad0 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1299,12 +1299,26 @@ void OpenSpaceEngine::postDraw() { if (_isFirstRenderingFirstFrame) { global::windowDelegate.setSynchronization(true); + resetPropertyChangeFlags(); _isFirstRenderingFirstFrame = false; } LTRACE("OpenSpaceEngine::postDraw(end)"); } +void OpenSpaceEngine::resetPropertyChangeFlags() { + ZoneScoped + + std::vector nodes = + global::renderEngine.scene()->allSceneGraphNodes(); + for (auto n : nodes) { + std::vector props = n->properties(); + for (auto p : props) { + p->resetToUnchanged(); + } + } +} + void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction action) { ZoneScoped diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 22812fda89..5a00032616 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -312,6 +312,10 @@ void Property::notifyDeleteListeners() { } } +void Property::resetToUnchanged() { + valChanged = false; +} + std::string Property::generateBaseJsonDescription() const { std::string cName = className(); std::string cNameSan = sanitizeString(cName); diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 6d4b7c95c0..888ee4fc3f 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -473,6 +473,7 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const { std::shared_ptr AssetLoader::add(const std::string& identifier) { setCurrentAsset(_rootAsset); + profileAssetsAdded.push_back(identifier); return request(identifier); } @@ -480,6 +481,7 @@ std::shared_ptr AssetLoader::add(const std::string& identifier) { void AssetLoader::remove(const std::string& identifier) { setCurrentAsset(_rootAsset); unrequest(identifier); + profileAssetsRemoved.push_back(identifier); } std::shared_ptr AssetLoader::has(const std::string& identifier) const { From 207c7d565744860a78e07cdca65afc1e247d0c1b Mon Sep 17 00:00:00 2001 From: GPayne Date: Fri, 27 Mar 2020 15:10:46 -0600 Subject: [PATCH 02/61] Profile file handler in progress --- include/openspace/engine/configuration.h | 1 + include/openspace/engine/globals.h | 3 + include/openspace/scene/assetloader.h | 5 +- include/openspace/scene/profile.h | 66 +++++ include/openspace/scene/profileFile.h | 128 ++++++++++ src/engine/globals.cpp | 7 +- src/engine/openspaceengine.cpp | 1 + src/scene/assetloader.cpp | 6 +- src/scene/profile.cpp | 99 ++++++++ src/scene/profileFile.cpp | 308 +++++++++++++++++++++++ src/scene/profile_lua.inl | 50 ++++ src/scene/scene.cpp | 10 +- 12 files changed, 674 insertions(+), 10 deletions(-) create mode 100644 include/openspace/scene/profile.h create mode 100644 include/openspace/scene/profileFile.h create mode 100644 src/scene/profile.cpp create mode 100644 src/scene/profileFile.cpp create mode 100644 src/scene/profile_lua.inl diff --git a/include/openspace/engine/configuration.h b/include/openspace/engine/configuration.h index 907ccd0e3f..41643b3041 100644 --- a/include/openspace/engine/configuration.h +++ b/include/openspace/engine/configuration.h @@ -91,6 +91,7 @@ struct Configuration { glm::dvec3 screenSpaceRotation = glm::dvec3(0.0); glm::dvec3 masterRotation = glm::dvec3(0.0); bool isConsoleDisabled = false; + bool usingProfile = false; std::map moduleConfigurations; diff --git a/include/openspace/engine/globals.h b/include/openspace/engine/globals.h index c7133339bf..60b0a8479a 100644 --- a/include/openspace/engine/globals.h +++ b/include/openspace/engine/globals.h @@ -65,6 +65,7 @@ namespace scripting { class ScriptEngine; class ScriptScheduler; } // namespace scripting +class Profile; namespace global { @@ -100,6 +101,7 @@ properties::PropertyOwner& gRootPropertyOwner(); properties::PropertyOwner& gScreenSpaceRootPropertyOwner(); scripting::ScriptEngine& gScriptEngine(); scripting::ScriptScheduler& gScriptScheduler(); +Profile& gProfile(); } // namespace detail @@ -138,6 +140,7 @@ static properties::PropertyOwner& screenSpaceRootPropertyOwner = detail::gScreenSpaceRootPropertyOwner(); static scripting::ScriptEngine& scriptEngine = detail::gScriptEngine(); static scripting::ScriptScheduler& scriptScheduler = detail::gScriptScheduler(); +static Profile& profile = detail::gProfile(); void initialize(); void initializeGL(); diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index 6b3dac5369..374448644f 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -227,8 +227,9 @@ private: _onDependencyDeinitializationFunctionRefs; int _assetsTableRef; - std::vector profileAssetsAdded; - std::vector profileAssetsRemoved; + std::vector _profileAssetsRequired; + std::vector _profileAssetsRequested; + std::vector _profileAssetsRemoved; }; } // namespace openspace diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h new file mode 100644 index 0000000000..c90b28556d --- /dev/null +++ b/include/openspace/scene/profile.h @@ -0,0 +1,66 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___PROFILE___H__ +#define __OPENSPACE_CORE___PROFILE___H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ghoul { class Dictionary; } +namespace ghoul::opengl { class ProgramObject; } + +namespace openspace { + +namespace documentation { struct Documentation; } +namespace scripting { struct LuaLibrary; } + + +class Profile { +public: + Profile(); + + void saveCurrentSettingsToProfile(std::string filename); + + /** + * Returns the Lua library that contains all Lua functions available to provide + * profile functionality. + * \return The Lua library that contains all Lua functions available for profiles + */ + static scripting::LuaLibrary luaLibrary(); + +private: +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___PROFILE___H__ diff --git a/include/openspace/scene/profileFile.h b/include/openspace/scene/profileFile.h new file mode 100644 index 0000000000..132dd0ee96 --- /dev/null +++ b/include/openspace/scene/profileFile.h @@ -0,0 +1,128 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___PROFILEFILE___H__ +#define __OPENSPACE_CORE___PROFILEFILE___H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ghoul { class Dictionary; } +namespace ghoul::opengl { class ProgramObject; } + +namespace openspace { + +namespace documentation { struct Documentation; } +namespace scripting { struct LuaLibrary; } + + +class ProfileFile { +public: + ProfileFile(std::string filename); + ~ProfileFile(); + + //Need a copy constructor here to do a deep copy + + void read(); + void write(); + + void setFilename(std::string filename); + + //Methods for updating contents + void updateTime(); + void updateCamera(); + void addModuleLine(std::string line); + void addAssetLine(std::string line); + void addPropertyLine(std::string line); + void addKeybindingLine(std::string line); + void addMarkNodesLine(std::string line); + + //Methods for getting contents of each section + std::string time(); + std::string camera(); + std::vector modules(); + std::vector assets(); + std::vector properties(); + std::vector keybindings(); + std::vector markNodes(); + +private: + void logError(std::string message); + void clearAllFields(); + bool isBlank(std::string line); + int splitByTab(std::string line, std::vector& result); + bool determineSection(std::string line); + void parseCurrentSection(std::string line); + void parseVersion(std::string line); + void parseModule(std::string line); + void parseAsset(std::string line); + void parseProperty(std::string line); + void parseKeybinding(std::string line); + void parseTime(std::string line); + void parseCamera(std::string line); + void parseMarkNodes(std::string line); + void verifyRequiredFields(std::string sectionName, std::vector fields, + std::vector standard, unsigned int nFields); + + const int versionLinesExpected = 1; + const int timeLinesExpected = 1; + const int cameraLinesExpected = 1; + + const int versionFieldsExpected = 1; + const int moduleFieldsExpected = 3; + const int assetFieldsExpected = 2; + const int propertyFieldsExpected = 3; + const int keybindingFieldsExpected = 6; + const int timeFieldsExpected = 2; + const int cameraNavigationFieldsExpected = 8; + const int cameraGeoFieldsExpected = 5; + const int markNodesFieldsExpected = 1; + + std::string _filename; + unsigned int _lineNum = 1; + unsigned int _numLinesVersion = 0; + unsigned int _numLinesTime = 0; + unsigned int _numLinesCamera = 0; + + std::string _version; + std::string _time; + std::string _camera; + std::vector _modules; + std::vector _assets; + std::vector _properties; + std::vector _keybindings; + std::vector _markNodes; +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___PROFILEFILE___H__ diff --git a/src/engine/globals.cpp b/src/engine/globals.cpp index a2e3c6b5a2..34effc2cc5 100644 --- a/src/engine/globals.cpp +++ b/src/engine/globals.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -182,7 +183,6 @@ interaction::SessionRecording& gSessionRecording() { return g; } - interaction::ShortcutManager& gShortcutManager() { static interaction::ShortcutManager g; return g; @@ -213,6 +213,11 @@ scripting::ScriptScheduler& gScriptScheduler() { return g; } +Profile& gProfile() { + static Profile g; + return g; +} + } // namespace detail void initialize() { diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 0d0a8f4ad0..033ab87322 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -338,6 +338,7 @@ void OpenSpaceEngine::initialize() { // an asset name if both are provided. global::configuration.asset = absPath("${TEMPORARY}/") + global::configuration.profile; + global::configuration.usingProfile = true; } // Set up asset loader diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 888ee4fc3f..9439ea805a 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -444,6 +444,7 @@ std::shared_ptr AssetLoader::require(const std::string& identifier) { std::shared_ptr asset = getAsset(identifier); std::shared_ptr dependant = _currentAsset; dependant->require(asset); + _profileAssetsRequired.push_back(asset->assetFilePath()); return asset; } @@ -452,6 +453,7 @@ std::shared_ptr AssetLoader::request(const std::string& identifier) { std::shared_ptr parent = _currentAsset; parent->request(asset); assetRequested(parent, asset); + _profileAssetsRequested.push_back(asset->assetFilePath()); return asset; } @@ -473,7 +475,7 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const { std::shared_ptr AssetLoader::add(const std::string& identifier) { setCurrentAsset(_rootAsset); - profileAssetsAdded.push_back(identifier); + return request(identifier); } @@ -481,7 +483,7 @@ std::shared_ptr AssetLoader::add(const std::string& identifier) { void AssetLoader::remove(const std::string& identifier) { setCurrentAsset(_rootAsset); unrequest(identifier); - profileAssetsRemoved.push_back(identifier); + _profileAssetsRemoved.push_back(identifier); } std::shared_ptr AssetLoader::has(const std::string& identifier) const { diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp new file mode 100644 index 0000000000..b4b0560d5b --- /dev/null +++ b/src/scene/profile.cpp @@ -0,0 +1,99 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 "profile_lua.inl" + +namespace { + constexpr const char* _loggerCat = "Profile"; + constexpr const char* KeyIdentifier = "Identifier"; + constexpr const char* KeyParent = "Parent"; + +} // namespace + +namespace openspace { + +Profile::Profile() + : properties::PropertyOwner({"Scene", "Scene"}) + , _initializer(std::move(initializer)) +{ + _rootDummy.setIdentifier(SceneGraphNode::RootNodeIdentifier); + _rootDummy.setScene(this); +} + +Profile::~Profile() { + clear(); + _rootDummy.setScene(nullptr); +} + +void Profile::saveCurrentSettingsToProfile(std::string filename) { + if (! global::configuration.usingProfile) { + std::string errorMessage = "Program was not started using a profile, " + "so cannot use this save-current-settings feature."; + LERROR(errorMessage); + } + std::string initProfile = global::configuration.profile; +} + +scripting::LuaLibrary Profile::luaLibrary() { + return { + "", + { + { + "saveCurrentSettingsToProfile", + &luascriptfunctions::saveCurrentSettingsToProfile, + {}, + "string", + "Collects all changes that have been made since startup, including all " + "property changes and assets required, requested, or removed. All " + "changes will be added to the profile that OpenSpace was started with, " + "and the new saved file will contain all of this information. The " + "file will be named according to the argument provided. If this argument " + "is blank, then the new file will have the base name of the profile that " + " was started, with a _YYYYMMDD suffix." + } + } + }; +} + +} // namespace openspace diff --git a/src/scene/profileFile.cpp b/src/scene/profileFile.cpp new file mode 100644 index 0000000000..d029f5ac1b --- /dev/null +++ b/src/scene/profileFile.cpp @@ -0,0 +1,308 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 +#include + +namespace { + constexpr const char* _loggerCat = "ProfileFile"; + constexpr const char* KeyIdentifier = "Identifier"; + constexpr const char* KeyParent = "Parent"; + +} // namespace + +namespace openspace { + +ProfileFile::ProfileFile(std::string filename) + : _filename(filename) +{ +} + +ProfileFile::~ProfileFile() { +} + +void ProfileFile::read() { + clearAllFields(); + std::ifstream inFile; + inFile.open(_filename, std::ifstream::in); + std::string line; + _lineNum = 1; + bool insideSection = false; + + while (getline(inFile, line)) { + if (insideSection) { + if (isBlank(line)) { + insideSection = false; + } + else { + parseCurrentSection(line); + } + } + else if (line.substr(0, 1) == "#") { + if (determineSection(line)) { + insideSection = true; + } + } + _lineNum++; + } + inFile.close(); +} + +void ProfileFile::clearAllFields() { + _numLinesVersion = 0; + _numLinesTime = 0; + _numLinesCamera = 0; + + _version.clear(); + _time.clear(); + _camera.clear(); + _modules.clear(); + _assets.clear(); + _properties.clear(); + _keybindings.clear(); + _markNodes.clear(); +} + +bool ProfileFile::isBlank(std::string line) { + char* c = line.c_str(); + int nonBlanks = 0; + while (*c) { + if (!isspace(*c)) { + nonBlanks++; + } + c++; + } + return (nonBlanks == 0); +} + +bool ProfileFile::determineSection(std::string line) { + +} + +void ProfileFile::parseCurrentSection(std::string line) { + +} + +void ProfileFile::logError(std::string message) { + std::string e = "Error @ line " + std::to_string(_lineNum) + ": "; + LERROR(e + message); +} + +void ProfileFile::parseVersion(std::string line) { + std::vector fields; + + if (++_numLinesVersion > versionLinesExpected) { + logError("Too many lines in Version section"); + } + if (splitByTab(line, fields) > versionFieldsExpected) { + logError("No tabs allowed in Version entry"); + } + else { + _version = line; + } +} + +void ProfileFile::parseModule(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != moduleFieldsExpected) { + logError(std::to_string(moduleFieldsExpected) + + " fields required in a Module entry"); + } + std::vector standard = { + "module name", + "", + "" + }; + verifyRequiredFields(fields, standard, moduleFieldsExpected); + _modules.push_back(line); +} + +void ProfileFile::parseAsset(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != assetFieldsExpected) { + logError(std::to_string(assetFieldsExpected) + + " fields required in an Asset entry"); + } + std::vector standard = { + "asset name", + "" + }; + verifyRequiredFields(fields, standard, assetFieldsExpected); + _assets.push_back(line); +} + +void ProfileFile::parseProperty(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != propertyFieldsExpected) { + logError(std::to_string(propertyFieldsExpected) + + " fields required in Property entry"); + } + std::vector standard = { + "set command", + "name", + "value" + }; + verifyRequiredFields("Property", fields, standard, propertyFieldsExpected); + _properties.push_back(line); +} + +void ProfileFile::parseKeybinding(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != keybindingFieldsExpected) { + logError(std::to_string(keybindingFieldsExpected) + + " fields required in Keybinding entry"); + } + std::vector standard = { + "key", + "documentation", + "name", + "GuiPath", + "local(T/F)", + "script to execute" + }; + verifyRequiredFields("Keybinding", fields, standard, propertyFieldsExpected); + _properties.push_back(line); +} + +void ProfileFile::parseTime(std::string line) { + std::vector fields; + + if (++_numLinesTime > timeLinesExpected) { + logError("Too many lines in time section"); + } + if (splitByTab(line, fields) != timeFieldsExpected) { + logError(std::to_string(timeFieldsExpected) + + " fields required in Time entry"); + } + std::vector standard = { + "time set type", + "time value to set" + }; + verifyRequiredFields("Time", fields, standard, propertyFieldsExpected); + _time = line; +} + +void ProfileFile::parseCamera(std::string line) { + std::vector fields; + + if (++_numLinesCamera > cameraLinesExpected) { + logError("Too many lines in camera section"); + } + int nFields = splitByTab(line, fields); + if (nFields == cameraNavigationFieldsExpected) { + std::vector standard = { + "Type of camera set (setNavigationState)", + "setNavigationState Anchor", + "", + "", + "setNavigationState position vector", + "", + "", + "" + }; + verifyRequiredFields("Camera", fields, standard, cameraNavigationFieldsExpected); + } + else if (nFields == cameraGeoFieldsExpected) { + std::vector standard = { + "Type of camera set (goToGeo)", + "", + "Camera goToGeo Latitude", + "Camera goToGeo Longitude", + "" + }; + verifyRequiredFields("Camera goToGeo", fields, standard, + cameraNavigationFieldsExpected); + } + else { + logError(std::to_string(cameraNavigationFieldsExpected) + " or " + + std::to_string(cameraGeoFieldsExpected) + " fields required in Camera entry"); + } + _camera = line; +} + +void ProfileFile::parseMarkNodes(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != markNodesFieldsExpected) { + logError(std::to_string(markNodesFieldsExpected) + + " field required in an Mark Nodes entry"); + } + std::vector standard = { + "Mark Interesting Node name" + }; + verifyRequiredFields("Mark Interesting Nodes", fields, standard, + markNodesFieldsExpected); + _assets.push_back(line); +} + +void ProfileFile::verifyRequiredFields(std::string sectionName, + std::vector fields, + std::vector standard, + unsigned int nFields) +{ + for (unsigned int i = 0; i < fields.size(); i++) { + if (!standard[i].empty() && fields[i].empty()) { + std::string errMsg = sectionName + " " + standard[i]; + errMsg += "(arg " + std::to_string(i) + "/" + nFields + ") is required"; + logError(errMsg); + } + } +} + +int ProfileFile::splitByTab(std::string line, std::vector& result) { + std::istringstream iss(line); + std::string tmp; + result.clear(); + while(std::getline(iss, tmp, '\t')) { + result.push_back(tmp); + } + return result.size(); +} + +} // namespace openspace diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl new file mode 100644 index 0000000000..e647961a32 --- /dev/null +++ b/src/scene/profile_lua.inl @@ -0,0 +1,50 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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. * + ****************************************************************************************/ + +namespace openspace::luascriptfunctions { + + +int saveCurrentSettingsToProfile(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::saveCurrentSettingsToProfile"); + + using ghoul::lua::luaTypeToString; + + const std::string saveFilePath = ghoul::lua::value( + L, + 1, + ghoul::lua::PopValue::Yes + ); + + if (saveFilePath.empty()) { + return luaL_error(L, "save filepath string is empty"); + } + global::profile.saveCurrentSettingsToProfile( + saveFilePath + ); + + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + return 0; +} + +} // namespace openspace::luascriptfunctions diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 1f5574816f..82a0672084 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -616,19 +616,19 @@ scripting::LuaLibrary Scene::luaLibrary() { "to match the type that the property (or properties) expect. If the " "third is not present or is '0', the value changes instantly, otherwise " "the change will take that many seconds and the value is interpolated at " - "each steap in between. The fourth parameter is an optional easing " + "each step in between. The fourth parameter is an optional easing " "function if a 'duration' has been specified. If 'duration' is 0, this " "parameter value is ignored. Otherwise, it can be one of many supported " "easing functions. See easing.h for available functions. The fifth " - "argument must be either empty, 'regex', or 'single'. If the last " + "argument must be either empty, 'regex', or 'single'. If the fifth" "argument is empty (the default), the URI is interpreted using a " "wildcard in which '*' is expanded to '(.*)' and bracketed components " "'{ }' are interpreted as group tag names. Then, the passed value will " "be set on all properties that fit the regex + group name combination. " - "If the third argument is 'regex' neither the '*' expansion, nor the " + "If the fifth argument is 'regex' neither the '*' expansion, nor the " "group tag expansion is performed and the first argument is used as an " "ECMAScript style regular expression that matches against the fully " - "qualified IDs of properties. If the third arugment is 'single' no " + "qualified IDs of properties. If the fifth argument is 'single' no " "substitutions are performed and exactly 0 or 1 properties are changed." }, { @@ -640,7 +640,7 @@ scripting::LuaLibrary Scene::luaLibrary() { "second argument can be any type, but it has to match the type that the " "property expects. If the third is not present or is '0', the value " "changes instantly, otherwise the change will take that many seconds and " - "the value is interpolated at each steap in between. The fourth " + "the value is interpolated at each step in between. The fourth " "parameter is an optional easing function if a 'duration' has been " "specified. If 'duration' is 0, this parameter value is ignored. " "Otherwise, it has to be 'linear', 'easein', 'easeout', or 'easeinout'. " From 5a6ff377598f2a8fd86da188bbbc409086786c8a Mon Sep 17 00:00:00 2001 From: GPayne Date: Fri, 3 Apr 2020 21:43:24 -0600 Subject: [PATCH 03/61] Created unit tests for profileFile --- include/openspace/scene/profile.h | 2 - .../scene/{profileFile.h => profilefile.h} | 95 ++-- src/CMakeLists.txt | 5 + src/scene/profile.cpp | 13 - src/scene/profileFile.cpp | 308 ------------ src/scene/profilefile.cpp | 450 ++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/profile/test_profilefile.cpp | 268 +++++++++++ 8 files changed, 772 insertions(+), 370 deletions(-) rename include/openspace/scene/{profileFile.h => profilefile.h} (64%) delete mode 100644 src/scene/profileFile.cpp create mode 100644 src/scene/profilefile.cpp create mode 100644 tests/profile/test_profilefile.cpp diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index c90b28556d..d839a6ca97 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -47,8 +47,6 @@ namespace scripting { struct LuaLibrary; } class Profile { public: - Profile(); - void saveCurrentSettingsToProfile(std::string filename); /** diff --git a/include/openspace/scene/profileFile.h b/include/openspace/scene/profilefile.h similarity index 64% rename from include/openspace/scene/profileFile.h rename to include/openspace/scene/profilefile.h index 132dd0ee96..065b36f4fe 100644 --- a/include/openspace/scene/profileFile.h +++ b/include/openspace/scene/profilefile.h @@ -25,15 +25,10 @@ #ifndef __OPENSPACE_CORE___PROFILEFILE___H__ #define __OPENSPACE_CORE___PROFILEFILE___H__ -#include - -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include namespace ghoul { class Dictionary; } @@ -44,18 +39,15 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } - class ProfileFile { public: - ProfileFile(std::string filename); - ~ProfileFile(); + void readLines(std::function reader); + void readFromFile(std::string filename); + void processIndividualLine(bool& insideSection, std::string line); + void write(std::ostream& output); + void writeToFile(std::string filename); - //Need a copy constructor here to do a deep copy - - void read(); - void write(); - - void setFilename(std::string filename); + const std::string getVersion() const; //Methods for updating contents void updateTime(); @@ -67,21 +59,24 @@ public: void addMarkNodesLine(std::string line); //Methods for getting contents of each section - std::string time(); - std::string camera(); - std::vector modules(); - std::vector assets(); - std::vector properties(); - std::vector keybindings(); - std::vector markNodes(); + std::string time() const; + std::string camera() const; + std::vector modules() const; + std::vector assets() const; + std::vector properties() const; + std::vector keybindings() const; + std::vector markNodes() const; private: - void logError(std::string message); + std::string errorString(std::string message); void clearAllFields(); bool isBlank(std::string line); - int splitByTab(std::string line, std::vector& result); + size_t splitByTab(std::string line, std::vector& result); + void verifyRequiredFields(std::string sectionName, std::vector fields, + std::vector standard, unsigned int nFields); + bool determineSection(std::string line); - void parseCurrentSection(std::string line); + void (ProfileFile::* parseCurrentSection)(std::string); void parseVersion(std::string line); void parseModule(std::string line); void parseAsset(std::string line); @@ -90,28 +85,34 @@ private: void parseTime(std::string line); void parseCamera(std::string line); void parseMarkNodes(std::string line); - void verifyRequiredFields(std::string sectionName, std::vector fields, - std::vector standard, unsigned int nFields); + void addAllElements(std::ostream& file, std::vector& list); - const int versionLinesExpected = 1; - const int timeLinesExpected = 1; - const int cameraLinesExpected = 1; + const size_t _versionLinesExpected = 1; + const size_t _timeLinesExpected = 1; + const size_t _cameraLinesExpected = 1; + const size_t _versionFieldsExpected = 1; + const size_t _moduleFieldsExpected = 3; + const size_t _assetFieldsExpected = 2; + const size_t _propertyFieldsExpected = 3; + const size_t _keybindingFieldsExpected = 6; + const size_t _timeFieldsExpected = 2; + const size_t _cameraNavigationFieldsExpected = 8; + const size_t _cameraGeoFieldsExpected = 5; + const size_t _markNodesFieldsExpected = 1; - const int versionFieldsExpected = 1; - const int moduleFieldsExpected = 3; - const int assetFieldsExpected = 2; - const int propertyFieldsExpected = 3; - const int keybindingFieldsExpected = 6; - const int timeFieldsExpected = 2; - const int cameraNavigationFieldsExpected = 8; - const int cameraGeoFieldsExpected = 5; - const int markNodesFieldsExpected = 1; + const std::string header_Version = "#Version"; + const std::string header_Module = "#Module"; + const std::string header_Asset = "#Asset"; + const std::string header_Property = "#Property"; + const std::string header_Keybinding = "#Keybinding"; + const std::string header_Time = "#Time"; + const std::string header_Camera = "#Camera"; + const std::string header_MarkNodes = "#MarkNodes"; - std::string _filename; - unsigned int _lineNum = 1; - unsigned int _numLinesVersion = 0; - unsigned int _numLinesTime = 0; - unsigned int _numLinesCamera = 0; + size_t _lineNum = 1; + size_t _numLinesVersion = 0; + size_t _numLinesTime = 0; + size_t _numLinesCamera = 0; std::string _version; std::string _time; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dde2ceb7e2..edaa11a0e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -152,6 +152,9 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/assetmanager.cpp ${OPENSPACE_BASE_DIR}/src/scene/assetmanager_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/lightsource.cpp + ${OPENSPACE_BASE_DIR}/src/scene/profile.cpp + ${OPENSPACE_BASE_DIR}/src/scene/profilefile.cpp + ${OPENSPACE_BASE_DIR}/src/scene/profile_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/rotation.cpp ${OPENSPACE_BASE_DIR}/src/scene/scale.cpp ${OPENSPACE_BASE_DIR}/src/scene/scene.cpp @@ -342,6 +345,8 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetloader.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/lightsource.h + ${OPENSPACE_BASE_DIR}/include/openspace/scene/profile.h + ${OPENSPACE_BASE_DIR}/include/openspace/scene/profilefile.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index b4b0560d5b..bf9f8217ae 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -53,19 +53,6 @@ namespace { namespace openspace { -Profile::Profile() - : properties::PropertyOwner({"Scene", "Scene"}) - , _initializer(std::move(initializer)) -{ - _rootDummy.setIdentifier(SceneGraphNode::RootNodeIdentifier); - _rootDummy.setScene(this); -} - -Profile::~Profile() { - clear(); - _rootDummy.setScene(nullptr); -} - void Profile::saveCurrentSettingsToProfile(std::string filename) { if (! global::configuration.usingProfile) { std::string errorMessage = "Program was not started using a profile, " diff --git a/src/scene/profileFile.cpp b/src/scene/profileFile.cpp deleted file mode 100644 index d029f5ac1b..0000000000 --- a/src/scene/profileFile.cpp +++ /dev/null @@ -1,308 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 -#include - -namespace { - constexpr const char* _loggerCat = "ProfileFile"; - constexpr const char* KeyIdentifier = "Identifier"; - constexpr const char* KeyParent = "Parent"; - -} // namespace - -namespace openspace { - -ProfileFile::ProfileFile(std::string filename) - : _filename(filename) -{ -} - -ProfileFile::~ProfileFile() { -} - -void ProfileFile::read() { - clearAllFields(); - std::ifstream inFile; - inFile.open(_filename, std::ifstream::in); - std::string line; - _lineNum = 1; - bool insideSection = false; - - while (getline(inFile, line)) { - if (insideSection) { - if (isBlank(line)) { - insideSection = false; - } - else { - parseCurrentSection(line); - } - } - else if (line.substr(0, 1) == "#") { - if (determineSection(line)) { - insideSection = true; - } - } - _lineNum++; - } - inFile.close(); -} - -void ProfileFile::clearAllFields() { - _numLinesVersion = 0; - _numLinesTime = 0; - _numLinesCamera = 0; - - _version.clear(); - _time.clear(); - _camera.clear(); - _modules.clear(); - _assets.clear(); - _properties.clear(); - _keybindings.clear(); - _markNodes.clear(); -} - -bool ProfileFile::isBlank(std::string line) { - char* c = line.c_str(); - int nonBlanks = 0; - while (*c) { - if (!isspace(*c)) { - nonBlanks++; - } - c++; - } - return (nonBlanks == 0); -} - -bool ProfileFile::determineSection(std::string line) { - -} - -void ProfileFile::parseCurrentSection(std::string line) { - -} - -void ProfileFile::logError(std::string message) { - std::string e = "Error @ line " + std::to_string(_lineNum) + ": "; - LERROR(e + message); -} - -void ProfileFile::parseVersion(std::string line) { - std::vector fields; - - if (++_numLinesVersion > versionLinesExpected) { - logError("Too many lines in Version section"); - } - if (splitByTab(line, fields) > versionFieldsExpected) { - logError("No tabs allowed in Version entry"); - } - else { - _version = line; - } -} - -void ProfileFile::parseModule(std::string line) { - std::vector fields; - - if (splitByTab(line, fields) != moduleFieldsExpected) { - logError(std::to_string(moduleFieldsExpected) + - " fields required in a Module entry"); - } - std::vector standard = { - "module name", - "", - "" - }; - verifyRequiredFields(fields, standard, moduleFieldsExpected); - _modules.push_back(line); -} - -void ProfileFile::parseAsset(std::string line) { - std::vector fields; - - if (splitByTab(line, fields) != assetFieldsExpected) { - logError(std::to_string(assetFieldsExpected) + - " fields required in an Asset entry"); - } - std::vector standard = { - "asset name", - "" - }; - verifyRequiredFields(fields, standard, assetFieldsExpected); - _assets.push_back(line); -} - -void ProfileFile::parseProperty(std::string line) { - std::vector fields; - - if (splitByTab(line, fields) != propertyFieldsExpected) { - logError(std::to_string(propertyFieldsExpected) + - " fields required in Property entry"); - } - std::vector standard = { - "set command", - "name", - "value" - }; - verifyRequiredFields("Property", fields, standard, propertyFieldsExpected); - _properties.push_back(line); -} - -void ProfileFile::parseKeybinding(std::string line) { - std::vector fields; - - if (splitByTab(line, fields) != keybindingFieldsExpected) { - logError(std::to_string(keybindingFieldsExpected) + - " fields required in Keybinding entry"); - } - std::vector standard = { - "key", - "documentation", - "name", - "GuiPath", - "local(T/F)", - "script to execute" - }; - verifyRequiredFields("Keybinding", fields, standard, propertyFieldsExpected); - _properties.push_back(line); -} - -void ProfileFile::parseTime(std::string line) { - std::vector fields; - - if (++_numLinesTime > timeLinesExpected) { - logError("Too many lines in time section"); - } - if (splitByTab(line, fields) != timeFieldsExpected) { - logError(std::to_string(timeFieldsExpected) + - " fields required in Time entry"); - } - std::vector standard = { - "time set type", - "time value to set" - }; - verifyRequiredFields("Time", fields, standard, propertyFieldsExpected); - _time = line; -} - -void ProfileFile::parseCamera(std::string line) { - std::vector fields; - - if (++_numLinesCamera > cameraLinesExpected) { - logError("Too many lines in camera section"); - } - int nFields = splitByTab(line, fields); - if (nFields == cameraNavigationFieldsExpected) { - std::vector standard = { - "Type of camera set (setNavigationState)", - "setNavigationState Anchor", - "", - "", - "setNavigationState position vector", - "", - "", - "" - }; - verifyRequiredFields("Camera", fields, standard, cameraNavigationFieldsExpected); - } - else if (nFields == cameraGeoFieldsExpected) { - std::vector standard = { - "Type of camera set (goToGeo)", - "", - "Camera goToGeo Latitude", - "Camera goToGeo Longitude", - "" - }; - verifyRequiredFields("Camera goToGeo", fields, standard, - cameraNavigationFieldsExpected); - } - else { - logError(std::to_string(cameraNavigationFieldsExpected) + " or " + - std::to_string(cameraGeoFieldsExpected) + " fields required in Camera entry"); - } - _camera = line; -} - -void ProfileFile::parseMarkNodes(std::string line) { - std::vector fields; - - if (splitByTab(line, fields) != markNodesFieldsExpected) { - logError(std::to_string(markNodesFieldsExpected) + - " field required in an Mark Nodes entry"); - } - std::vector standard = { - "Mark Interesting Node name" - }; - verifyRequiredFields("Mark Interesting Nodes", fields, standard, - markNodesFieldsExpected); - _assets.push_back(line); -} - -void ProfileFile::verifyRequiredFields(std::string sectionName, - std::vector fields, - std::vector standard, - unsigned int nFields) -{ - for (unsigned int i = 0; i < fields.size(); i++) { - if (!standard[i].empty() && fields[i].empty()) { - std::string errMsg = sectionName + " " + standard[i]; - errMsg += "(arg " + std::to_string(i) + "/" + nFields + ") is required"; - logError(errMsg); - } - } -} - -int ProfileFile::splitByTab(std::string line, std::vector& result) { - std::istringstream iss(line); - std::string tmp; - result.clear(); - while(std::getline(iss, tmp, '\t')) { - result.push_back(tmp); - } - return result.size(); -} - -} // namespace openspace diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp new file mode 100644 index 0000000000..c9d3c16964 --- /dev/null +++ b/src/scene/profilefile.cpp @@ -0,0 +1,450 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 + +namespace { + constexpr const char* _loggerCat = "ProfileFile"; + constexpr const char* KeyIdentifier = "Identifier"; + constexpr const char* KeyParent = "Parent"; + +} // namespace + +namespace openspace { + +void ProfileFile::readFromFile(std::string filename) { + clearAllFields(); + std::ifstream inFile; + + try { + inFile.open(filename, std::_Ios_Openmode::_S_in); + } + catch (std::ifstream::failure& e) { + throw ghoul::RuntimeError("Exception opening profile file for read: " + + filename, "profileFile"); + } + + try { + readLines([&inFile] (std::string& line) { + if (getline(inFile, line)) + return true; + else + return false; + }); + } + catch (std::ifstream::failure& e) { + throw ghoul::RuntimeError(errorString("Read error using getline"), + "profileFile"); + } + + try { + inFile.close(); + } + catch (std::ifstream::failure& e) { + throw ghoul::RuntimeError("Exception closing profile file after read: " + + filename, "profileFile"); + } +} + +void ProfileFile::readLines(std::function reader) { + std::string line; + bool insideSection = false; + _lineNum = 1; + + while (reader(line)) { + processIndividualLine(insideSection, line); + _lineNum++; + } +} + +void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { + if (insideSection) { + if (isBlank(line)) { + insideSection = false; + } + else { + if (parseCurrentSection != nullptr) { + (this->*parseCurrentSection)(line); + } + } + } + else if (line.substr(0, 1) == "#") { + if (determineSection(line)) { + insideSection = true; + } + } +} + +void ProfileFile::writeToFile(std::string filename) { + std::ofstream outFile; + try { + outFile.open(filename, std::ofstream::out | std::ofstream::app); + } + catch (std::ofstream::failure& e) { + LERROR("Exception opening profile file for write: " + filename); + } + + try { + write(outFile); + } + catch (std::ofstream::failure& e) { + LERROR("Data write error to file: " + filename); + } + + try { + outFile.close(); + } + catch (std::ofstream::failure& e) { + LERROR("Exception closing profile file after write: " + filename); + } +} + +void ProfileFile::write(std::ostream& output) { + output << header_Version << std::endl; + output << _version << std::endl << std::endl; + output << header_Module << std::endl; + addAllElements(output, _modules); + output << std::endl; + output << header_Asset << std::endl; + addAllElements(output, _assets); + output << std::endl; + output << header_Property << std::endl; + addAllElements(output, _properties); + output << std::endl; + output << header_Keybinding << std::endl; + addAllElements(output, _keybindings); + output << std::endl; + output << header_Time << std::endl; + output << _time << std::endl << std::endl; + output << header_Camera << std::endl; + output << _camera << std::endl; + output << header_MarkNodes << std::endl; + addAllElements(output, _markNodes); +} + +const std::string ProfileFile::getVersion() const { + return _version; +} + +void ProfileFile::addAllElements(std::ostream& file, std::vector& list) { + for (auto s : list) { + file << s << std::endl; + } +} + +void ProfileFile::clearAllFields() { + _numLinesVersion = 0; + _numLinesTime = 0; + _numLinesCamera = 0; + + _version.clear(); + _time.clear(); + _camera.clear(); + _modules.clear(); + _assets.clear(); + _properties.clear(); + _keybindings.clear(); + _markNodes.clear(); +} + +bool ProfileFile::isBlank(std::string line) { + char* c = const_cast(line.c_str()); + int nonBlanks = 0; + while (*c) { + if (!isspace(*c)) { + nonBlanks++; + } + c++; + } + return (nonBlanks == 0); +} + +bool ProfileFile::determineSection(std::string line) { + bool foundSection = true; + + if (line.compare(header_Version) == 0) { + parseCurrentSection = &ProfileFile::parseVersion; + } + else if (line.compare(header_Module) == 0) { + parseCurrentSection = &ProfileFile::parseModule; + } + else if (line.compare(header_Asset) == 0) { + parseCurrentSection = &ProfileFile::parseAsset; + } + else if (line.compare(header_Property) == 0) { + parseCurrentSection = &ProfileFile::parseProperty; + } + else if (line.compare(header_Keybinding) == 0) { + parseCurrentSection = &ProfileFile::parseKeybinding; + } + else if (line.compare(header_Time) == 0) { + parseCurrentSection = &ProfileFile::parseTime; + } + else if (line.compare(header_Camera) == 0) { + parseCurrentSection = &ProfileFile::parseCamera; + } + else if (line.compare(header_MarkNodes) == 0) { + parseCurrentSection = &ProfileFile::parseMarkNodes; + } + else { + throw ghoul::RuntimeError(errorString("Invalid section header '" + line + "'"), + "profileFile"); + foundSection = false; + } + return foundSection; +} + +std::string ProfileFile::errorString(std::string message) { + std::string e = "Error @ line " + std::to_string(_lineNum) + ": "; + return e + message; +} + +std::string ProfileFile::time() const { + return _time; +} + +std::string ProfileFile::camera() const { + return _camera; +} + +std::vector ProfileFile::modules() const { + return _modules; +} + +std::vector ProfileFile::assets() const { + return _assets; +} + +std::vector ProfileFile::properties() const { + return _properties; +} + +std::vector ProfileFile::keybindings() const { + return _keybindings; +} + +std::vector ProfileFile::markNodes() const { + return _markNodes; +} + +void ProfileFile::parseVersion(std::string line) { + std::vector fields; + + if (++_numLinesVersion > _versionLinesExpected) { + throw ghoul::RuntimeError(errorString("Too many lines in Version section"), + "profileFile"); + } + if (splitByTab(line, fields) > _versionFieldsExpected) { + throw ghoul::RuntimeError(errorString("No tabs allowed in Version entry"), + "profileFile"); + } + else { + _version = line; + } +} + +void ProfileFile::parseModule(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != _moduleFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(_moduleFieldsExpected) + + " fields required in a Module entry"), "profileFile"); + } + std::vector standard = { + "module name", + "", + "" + }; + verifyRequiredFields("Module", fields, standard, _moduleFieldsExpected); + _modules.push_back(line); +} + +void ProfileFile::parseAsset(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != _assetFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(_assetFieldsExpected) + + " fields required in an Asset entry"), "profileFile"); + } + std::vector standard = { + "asset name", + "" + }; + verifyRequiredFields("Asset", fields, standard, _assetFieldsExpected); + _assets.push_back(line); +} + +void ProfileFile::parseProperty(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != _propertyFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(_propertyFieldsExpected) + + " fields required in Property entry"), "profileFile"); + } + std::vector standard = { + "set command", + "name", + "value" + }; + verifyRequiredFields("Property", fields, standard, _propertyFieldsExpected); + _properties.push_back(line); +} + +void ProfileFile::parseKeybinding(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != _keybindingFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(_keybindingFieldsExpected) + + " fields required in Keybinding entry"), "profileFile"); + } + std::vector standard = { + "key", + "documentation", + "name", + "GuiPath", + "local(T/F)", + "script to execute" + }; + verifyRequiredFields("Keybinding", fields, standard, _keybindingFieldsExpected); + _keybindings.push_back(line); +} + +void ProfileFile::parseTime(std::string line) { + std::vector fields; + + if (++_numLinesTime > _timeLinesExpected) { + throw ghoul::RuntimeError(errorString("Too many lines in time section"), + "profileFile"); + } + if (splitByTab(line, fields) != _timeFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(_timeFieldsExpected) + + " fields required in Time entry"), "profileFile"); + } + std::vector standard = { + "time set type", + "time value to set" + }; + verifyRequiredFields("Time", fields, standard, _timeFieldsExpected); + _time = line; +} + +void ProfileFile::parseCamera(std::string line) { + std::vector fields; + + if (++_numLinesCamera > _cameraLinesExpected) { + throw ghoul::RuntimeError(errorString("Too many lines in camera section"), + "profileFile"); + } + size_t nFields = splitByTab(line, fields); + if (nFields == _cameraNavigationFieldsExpected) { + std::vector standard = { + "Type of camera set (setNavigationState)", + "setNavigationState Anchor", + "", + "", + "setNavigationState position vector", + "", + "", + "" + }; + verifyRequiredFields("Camera navigation", fields, standard, + _cameraNavigationFieldsExpected); + } + else if (nFields == _cameraGeoFieldsExpected) { + std::vector standard = { + "Type of camera set (goToGeo)", + "", + "Camera goToGeo Latitude", + "Camera goToGeo Longitude", + "" + }; + verifyRequiredFields("Camera goToGeo", fields, standard, + _cameraGeoFieldsExpected); + } + else { + throw ghoul::RuntimeError(errorString(std::to_string( + _cameraNavigationFieldsExpected) + " or " + std::to_string( + _cameraGeoFieldsExpected) + " fields required in Camera entry"), + "profileFile"); + } + _camera = line; +} + +void ProfileFile::parseMarkNodes(std::string line) { + std::vector fields; + + if (splitByTab(line, fields) != _markNodesFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(_markNodesFieldsExpected) + + " field required in an Mark Nodes entry"), "profileFile"); + } + std::vector standard = { + "Mark Interesting Node name" + }; + verifyRequiredFields("Mark Interesting Nodes", fields, standard, + _markNodesFieldsExpected); + _markNodes.push_back(line); +} + +void ProfileFile::verifyRequiredFields(std::string sectionName, + std::vector fields, + std::vector standard, + unsigned int nFields) +{ + for (unsigned int i = 0; i < fields.size(); i++) { + if (!standard[i].empty() && fields[i].empty()) { + std::string errMsg = sectionName + " " + standard[i]; + errMsg += "(arg " + std::to_string(i) + "/"; + errMsg += std::to_string(nFields) + ") is required"; + throw ghoul::RuntimeError(errorString(errMsg), "profileFile"); + } + } +} + +size_t ProfileFile::splitByTab(std::string line, std::vector& result) { + std::istringstream iss(line); + std::string tmp; + result.clear(); + while (getline(iss, tmp, '\t')) { + result.push_back(tmp); + } + //Insert additional empty fields only for the case of tab delimiters at end of + // string without populated field(s) + size_t nTabs = std::count(line.begin(), line.end(), '\t'); + for (size_t i = 0; i < (nTabs - result.size() + 1); ++i) { + result.push_back(""); + } + return result.size(); +} + +} // namespace openspace diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 74b2691cf4..018bc93ba6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,6 +34,7 @@ add_executable( test_lrucache.cpp test_luaconversions.cpp test_optionproperty.cpp + profile/test_profilefile.cpp test_rawvolumeio.cpp test_scriptscheduler.cpp test_spicemanager.cpp diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp new file mode 100644 index 0000000000..91af2108ed --- /dev/null +++ b/tests/profile/test_profilefile.cpp @@ -0,0 +1,268 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 "catch2/catch.hpp" + +#include "openspace/scene/profilefile.h" +#include +#include +#include +#include + +using namespace openspace; + +namespace { +} + +struct testProfileFormat { + std::vector tsv; + std::vector tsm; + std::vector tsa; + std::vector tsp; + std::vector tsk; + std::vector tst; + std::vector tsc; + std::vector tsn; +}; + +testProfileFormat buildTestProfile1() { + testProfileFormat tp1; + tp1.tsv.push_back("#Version"); + tp1.tsv.push_back("123.4"); + tp1.tsm.push_back("#Module"); + tp1.tsm.push_back("globebrowsing\t\t"); + tp1.tsm.push_back("gaia\tprint(\"success.\")\t"); + tp1.tsm.push_back("volume\t\tquit"); + tp1.tsa.push_back("#Asset"); + tp1.tsa.push_back("scene/solarsystem/planets/earth/moon/moon\trequired"); + tp1.tsa.push_back("scene/solarsystem/missions/apollo/apollo8\trequested"); + tp1.tsa.push_back("scene/solarsystem/planets/earth/earth\t"); + tp1.tsp.push_back("#Property"); + tp1.tsp.push_back("setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000"); + tp1.tsp.push_back("setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse"); + tp1.tsp.push_back("setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse"); + tp1.tsp.push_back("setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse"); + tp1.tsk.push_back("#Keybinding"); + tp1.tsk.push_back("F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\""); + tp1.tsk.push_back("F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\""); + tp1.tsk.push_back("F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""); + tp1.tsk.push_back("F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\""); + tp1.tst.push_back("#Time"); + tp1.tst.push_back("absolute\t1977-12-21T12:51:51.0"); + tp1.tsc.push_back("#Camera"); + tp1.tsc.push_back("setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"); + tp1.tsn.push_back("#MarkNodes"); + tp1.tsn.push_back("Pluto"); + tp1.tsn.push_back("NewHorizons"); + tp1.tsn.push_back("Charon"); + + return tp1; +} + +std::string stringFromSingleProfileSection(std::vector& section) { + std::string result; + for (std::string s : section) { + result += s + "\n"; + } + result += "\n"; + return result; +} + +std::string stringFromTestProfileFormat(testProfileFormat& tpf) { + std::string fullProfile; + + fullProfile += stringFromSingleProfileSection(tpf.tsv); + fullProfile += stringFromSingleProfileSection(tpf.tsm); + fullProfile += stringFromSingleProfileSection(tpf.tsa); + fullProfile += stringFromSingleProfileSection(tpf.tsp); + fullProfile += stringFromSingleProfileSection(tpf.tsk); + fullProfile += stringFromSingleProfileSection(tpf.tst); + fullProfile += stringFromSingleProfileSection(tpf.tsc); + fullProfile += stringFromSingleProfileSection(tpf.tsn); + + return fullProfile; +} + +TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { + testProfileFormat test = buildTestProfile1(); + std::string testFull_string = stringFromTestProfileFormat(test); + std::istringstream iss(testFull_string); + + ProfileFile pf; + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + }); + + std::vector tVect; + + REQUIRE(pf.getVersion() == test.tsv[1]); + REQUIRE(pf.time() == test.tst[1]); + REQUIRE(pf.camera() == test.tsc[1]); + tVect = pf.modules(); + REQUIRE(tVect[0] == test.tsm[1]); + REQUIRE(tVect[1] == test.tsm[2]); + REQUIRE(tVect[2] == test.tsm[3]); + tVect = pf.assets(); + REQUIRE(tVect[0] == test.tsa[1]); + REQUIRE(tVect[1] == test.tsa[2]); + REQUIRE(tVect[2] == test.tsa[3]); + tVect = pf.properties(); + REQUIRE(tVect[0] == test.tsp[1]); + REQUIRE(tVect[1] == test.tsp[2]); + REQUIRE(tVect[2] == test.tsp[3]); + REQUIRE(tVect[3] == test.tsp[4]); + tVect = pf.keybindings(); + REQUIRE(tVect[0] == test.tsk[1]); + REQUIRE(tVect[1] == test.tsk[2]); + REQUIRE(tVect[2] == test.tsk[3]); + REQUIRE(tVect[3] == test.tsk[4]); + tVect = pf.markNodes(); + REQUIRE(tVect[0] == test.tsn[1]); + REQUIRE(tVect[1] == test.tsn[2]); + REQUIRE(tVect[2] == test.tsn[3]); +} + +TEST_CASE("profileFile: Unrecognized header", "[profileFile]") { + testProfileFormat test = buildTestProfile1(); + + test.tsa[0] = "#Azzet"; + std::string testFull_string = stringFromTestProfileFormat(test); + std::istringstream iss(testFull_string); + + ProfileFile pf; + REQUIRE_THROWS_WITH( + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ), + Catch::Matchers::Contains ( "Invalid section header" ) + && Catch::Matchers::Contains( "#Azzet" ) + ); +} + +TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { + testProfileFormat test = buildTestProfile1(); + std::string testFull_string; + test.tsm[1] = "globebrowsing\t\t\t"; + testFull_string = stringFromTestProfileFormat(test); + { + std::istringstream iss(testFull_string); + ProfileFile pf; + REQUIRE_THROWS_WITH( + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ), + Catch::Matchers::Contains ("fields required in a Module entry") + ); + } + + test.tsm[1] = "globebrowsing\t\t"; + test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"; + testFull_string = stringFromTestProfileFormat(test); + { + std::istringstream iss(testFull_string); + ProfileFile pf; + REQUIRE_THROWS_WITH( + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ), + Catch::Matchers::Contains ("fields required in Camera entry") + ); + } +} + +TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") { + testProfileFormat test = buildTestProfile1(); + std::string testFull_string; + test.tst.push_back("relative\t\"-1 day\""); + testFull_string = stringFromTestProfileFormat(test); + { + std::istringstream iss(testFull_string); + ProfileFile pf; + REQUIRE_THROWS_WITH( + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ), + Catch::Matchers::Contains ("Too many lines in time section") + ); + } +} + +TEST_CASE("profileFile: Required field missing", "[profileFile]") { + testProfileFormat test = buildTestProfile1(); + std::string testFull_string; + test.tsc[1] = "setNavigationState\t\"NewHorizons\"\ttest\t\"Root\"\t\t0.102164, -0.362945, 0.926193\t\t"; + + testFull_string = stringFromTestProfileFormat(test); + { + std::istringstream iss(testFull_string); + ProfileFile pf; + REQUIRE_THROWS_WITH( + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ), + Catch::Matchers::Contains ("Camera navigation setNavigationState position vector(arg 4/8) is required") + ); + } + + test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t1, 2, 3\t0.102164, -0.362945, 0.926193\t\t"; + test.tsk[3] = "F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\t\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""; + testFull_string = stringFromTestProfileFormat(test); + { + std::istringstream iss(testFull_string); + ProfileFile pf; + REQUIRE_THROWS_WITH( + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ), + Catch::Matchers::Contains ("Keybinding local(T/F)(arg 4/6) is required") + ); + } +} From 924a0085a78457372a5f917785f2c3325b0585c2 Mon Sep 17 00:00:00 2001 From: GPayne Date: Sun, 5 Apr 2020 21:47:51 -0600 Subject: [PATCH 04/61] Additional work on converting from profile to scene/asset format --- include/openspace/scene/profile.h | 18 ++- include/openspace/scene/profilefile.h | 118 +++++++++++---- src/scene/profile.cpp | 201 ++++++++++++++++++++++++++ src/scene/profilefile.cpp | 97 +++++++------ tests/profile/test_profilefile.cpp | 41 ++++-- 5 files changed, 387 insertions(+), 88 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index d839a6ca97..e34e5ef111 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_CORE___PROFILE___H__ #define __OPENSPACE_CORE___PROFILE___H__ -#include +#include #include #include @@ -49,6 +49,14 @@ class Profile { public: void saveCurrentSettingsToProfile(std::string filename); + /** + * Returns the string contents of a profileFile object converted to scene/asset + * equivalent syntax. + * \param pf The profileFile object to be converted + * \return The full string contents of scene/asset equivalent of the profile file. + */ + std::string convertToAsset(ProfileFile& pf); + /** * Returns the Lua library that contains all Lua functions available to provide * profile functionality. @@ -57,6 +65,14 @@ public: static scripting::LuaLibrary luaLibrary(); private: + std::string convertToAsset_assets(ProfileFile& pf); + std::string convertToAsset_modules(ProfileFile& pf); + std::string convertToAsset_properties(ProfileFile& pf); + std::string convertToAsset_markNodes(ProfileFile& pf); + std::string convertToAsset_keybindings(ProfileFile& pf); + std::string convertToAsset_time(ProfileFile& pf); + std::string convertToAsset_camera(ProfileFile& pf); + }; } // namespace openspace diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 065b36f4fe..f7f8c12593 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -39,15 +39,94 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } +const size_t versionLinesExpected = 1; +const size_t timeLinesExpected = 1; +const size_t cameraLinesExpected = 1; +const size_t versionFieldsExpected = 1; +const size_t moduleFieldsExpected = 3; +const size_t assetFieldsExpected = 2; +const size_t propertyFieldsExpected = 3; +const size_t keybindingFieldsExpected = 6; +const size_t timeFieldsExpected = 2; +const size_t cameraNavigationFieldsExpected = 8; +const size_t cameraGeoFieldsExpected = 5; +const size_t markNodesFieldsExpected = 1; + +const size_t moduleFieldName = 0; +const size_t moduleFieldLoaded = 1; +const size_t moduleFieldNotLoaded = 2; +const size_t assetFieldName = 0; +const size_t assetFieldReqd = 1; +const size_t propertyFieldType = 0; +const size_t propertyFieldName = 1; +const size_t propertyFieldValue = 2; +const size_t keybindingFieldKey = 0; +const size_t keybindingFieldDoc = 1; +const size_t keybindingFieldName = 2; +const size_t keybindingFieldGuiPath = 3; +const size_t keybindingFieldLocal = 4; +const size_t keybindingFieldCommand = 5; +const size_t timeFieldType = 0; +const size_t timeFieldSet = 1; +const size_t cameraFieldType = 0; +const size_t cameraNavigationFieldAnchor = 1; +const size_t cameraNavigationFieldAim = 2; +const size_t cameraNavigationFieldRef = 3; +const size_t cameraNavigationFieldPosition = 4; +const size_t cameraNavigationFieldUp = 5; +const size_t cameraNavigationFieldYaw = 6; +const size_t cameraNavigationFieldPitch = 7; +const size_t cameraGeoFieldAnchor = 1; +const size_t cameraGeoFieldLatitude = 2; +const size_t cameraGeoFieldLongitude = 3; +const size_t cameraGeoFieldAltitude = 4; + +const std::string header_Version = "#Version"; +const std::string header_Module = "#Module"; +const std::string header_Asset = "#Asset"; +const std::string header_Property = "#Property"; +const std::string header_Keybinding = "#Keybinding"; +const std::string header_Time = "#Time"; +const std::string header_Camera = "#Camera"; +const std::string header_MarkNodes = "#MarkNodes"; + class ProfileFile { public: - void readLines(std::function reader); + /** + * Reads the contents of a profile file and populates vector containers for all + * sections. This only pulls individual line entries into their proper sections; + * it does not parse the tab-delimited fields of each line. + * \param filename The profile file to read + */ void readFromFile(std::string filename); - void processIndividualLine(bool& insideSection, std::string line); - void write(std::ostream& output); - void writeToFile(std::string filename); - const std::string getVersion() const; + /** + * Alternative function for reading the lines from a profile file. This is mainly + * intended for testing purposes, but it can be used to provide the profile file + * contents from another source (the function readFromFile() provides its own + * ifstream source). + * \param reader A std::function object that accepts a string reference which will + * be populated with a single line of content. This function returns + * true if a single line was read successfully, or false if not to + * indicate that the end of the content has been reached. + */ + void readLines(std::function reader); + + /** + * Returns the string contents of this object converted to scene/asset + * equivalent syntax, with all section headers and contents of each listed on an + * individual line. + * \return The full contents of the profile file in string format. + */ + std::string writeToString(); + + /** + * Writes the formatted contents of this object to a file. + * This function calls writeToString() in order to get everything in formatted + * form. + * \param filename The filename to write to. + */ + void writeToFile(std::string filename); //Methods for updating contents void updateTime(); @@ -59,6 +138,7 @@ public: void addMarkNodesLine(std::string line); //Methods for getting contents of each section + const std::string getVersion() const; std::string time() const; std::string camera() const; std::vector modules() const; @@ -66,15 +146,15 @@ public: std::vector properties() const; std::vector keybindings() const; std::vector markNodes() const; + size_t splitByTab(std::string line, std::vector& result); private: std::string errorString(std::string message); void clearAllFields(); bool isBlank(std::string line); - size_t splitByTab(std::string line, std::vector& result); void verifyRequiredFields(std::string sectionName, std::vector fields, std::vector standard, unsigned int nFields); - + void processIndividualLine(bool& insideSection, std::string line); bool determineSection(std::string line); void (ProfileFile::* parseCurrentSection)(std::string); void parseVersion(std::string line); @@ -85,29 +165,7 @@ private: void parseTime(std::string line); void parseCamera(std::string line); void parseMarkNodes(std::string line); - void addAllElements(std::ostream& file, std::vector& list); - - const size_t _versionLinesExpected = 1; - const size_t _timeLinesExpected = 1; - const size_t _cameraLinesExpected = 1; - const size_t _versionFieldsExpected = 1; - const size_t _moduleFieldsExpected = 3; - const size_t _assetFieldsExpected = 2; - const size_t _propertyFieldsExpected = 3; - const size_t _keybindingFieldsExpected = 6; - const size_t _timeFieldsExpected = 2; - const size_t _cameraNavigationFieldsExpected = 8; - const size_t _cameraGeoFieldsExpected = 5; - const size_t _markNodesFieldsExpected = 1; - - const std::string header_Version = "#Version"; - const std::string header_Module = "#Module"; - const std::string header_Asset = "#Asset"; - const std::string header_Property = "#Property"; - const std::string header_Keybinding = "#Keybinding"; - const std::string header_Time = "#Time"; - const std::string header_Camera = "#Camera"; - const std::string header_MarkNodes = "#MarkNodes"; + void addAllElements(std::string& str, std::vector& list); size_t _lineNum = 1; size_t _numLinesVersion = 0; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index bf9f8217ae..a5df683edc 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -62,6 +62,207 @@ void Profile::saveCurrentSettingsToProfile(std::string filename) { std::string initProfile = global::configuration.profile; } +std::string Profile::convertToAsset(ProfileFile& pf) { + std::string result; + + result += convertToAsset_modules(pf) + "\n"; + result += convertToAsset_assets(pf) + "\n"; + result += "asset.onInitialize(function ()\n"; + result += convertToAsset_time(pf) + "\n"; + result += convertToAsset_keybindings(pf) + "\n"; + result += convertToAsset_markNodes(pf); + result += convertToAsset_properties(pf); + result += convertToAsset_camera(pf); + result += "end)\n"; + + return result; +} + +std::string Profile::convertToAsset_modules(ProfileFile& pf) { + std::string result; + std::vector fields; + + for (std::string m : pf.modules()) { + pf.splitByTab(m, fields); + if (fields[moduleFieldLoaded] != "" && fields[moduleFieldNotLoaded] != "") { + result += "if openspace.modules.isLoaded(\"" + fields[moduleFieldName]; + result += "\") then\n " + fields[moduleFieldLoaded] + "\nelse\n"; + result += " " + fields[moduleFieldNotLoaded] + "\nend\n"; + } + else if (fields[moduleFieldNotLoaded] == "") { + result += "if not openspace.modules.isLoaded(\"" + fields[moduleFieldName]; + result += "\") then\n " + fields[moduleFieldNotLoaded] + "\nend\n"; + } + else if (fields[moduleFieldLoaded] == "") { + result += "if openspace.modules.isLoaded(\"" + fields[moduleFieldName]; + result += "\") then\n " + fields[moduleFieldLoaded] + "\nend\n"; + } + } + return result; +} + +std::string Profile::convertToAsset_assets(ProfileFile& pf) { + std::string result; + std::vector fields; + std::string assetR; + + result += "asset.require(\"base\");\n"; + result += "'local assetHelper = asset.require(\"util/asset_helper\")\n"; + result += "'local propertyHelper = asset.require(\"util/property_helper\")\n"; + result += "'local sceneHelper = asset.require(\"util/scene_helper\")\n"; + result += "'local renderableHelper = asset.require(\"util/renderable_helper\")\n"; + + for (size_t i = 0; i < pf.assets().size(); ++i) { + std::string a = pf.assets()[i]; + pf.splitByTab(a, fields); + + if (fields[assetFieldReqd] == "required") { + assetR = "require"; + } + else if (fields[assetFieldReqd] == "requested") { + assetR = "request"; + } + else { + std::string err = "Asset " + std::to_string(i + 1) + " of "; + err += std::to_string(pf.assets().size()) + " has bad arg 2/2 which must "; + err += "be either 'required' or 'requested'"; + throw ghoul::RuntimeError(err); + } + result += "asset." + assetR + "(\"" + fields[assetFieldName] + "\")\n"; + } + return result; +} + +std::string Profile::convertToAsset_properties(ProfileFile& pf) { + std::string result; + std::vector fields; + + for (size_t i = 0; i < pf.properties().size(); ++i) { + std::string p = pf.properties()[i]; + pf.splitByTab(p, fields); + + if (fields[propertyFieldType] != "setPropertyValue" + && fields[propertyFieldType] != "setPropertyValueSingle") + { + std::string err = "Property" + std::to_string(i + 1) + " of "; + err += std::to_string(pf.properties().size()) + " has bad arg 1/1 which "; + err += "must be either 'setPropertyValue' or 'setPropertyValueSingle'"; + throw ghoul::RuntimeError(err); + } + else { + result = " openspace." + fields[propertyFieldType] + "(\"" + + fields[propertyFieldName] + "\", " + fields[propertyFieldValue] + ")\n"; + } + } + return result; +} + +std::string Profile::convertToAsset_keybindings(ProfileFile& pf) { + std::string result; + std::vector fields; + std::string assetR; + + result += "local Keybindings = {\n"; + for (size_t i = 0; i < pf.keybindings().size(); ++i) { + std::string k = pf.keybindings()[i]; + pf.splitByTab(k, fields); + + result += " {\n"; + result += " Key = \"" + fields[0] + "\",\n"; + result += " Documentation = \"" + fields[1] + "\",\n"; + result += " Name = \"" + fields[2] + "\",\n"; + result += " GuiPath = \"" + fields[3] + "\",\n"; + result += " Local = " + fields[4] + ",\n"; + result += " Command = " + fields[5] + "\n"; + result += " }\n"; + } + result += "}\n"; + return result; +} + +std::string Profile::convertToAsset_markNodes(ProfileFile& pf) { + std::string result; + + if (pf.markNodes().size() > 0) { + result += " openspace.markInterestingNodes({'"; + } + for (std::string m : pf.markNodes()) { + result += "\"" + m + "\", "; + } + result += "})\n"; + return result; +} + +std::string Profile::convertToAsset_time(ProfileFile& pf) { + std::string result; + std::vector fields; + std::string assetR; + + pf.splitByTab(pf.time(), fields); + + if (fields[timeFieldType] == "absolute") { + result += " openspace.time.setTime(\"" + fields[timeFieldSet] + "\")\n"; + } + else if (fields[timeFieldType] == "relative") { + result += " local now = openspace.time.currentWallTime(); "; + result += "openspace.time.setTime("; + result += "openspace.time.advancedTime(now, \"" + fields[timeFieldSet] + "\"))\n"; + } + else { + std::string err = "Time entry's arg 1/1 must be either 'absolute' or 'relative'"; + throw ghoul::RuntimeError(err); + } + return result; +} + +std::string Profile::convertToAsset_camera(ProfileFile& pf) { + std::string result; + std::vector fields; + std::string assetR; + + pf.splitByTab(pf.camera(), fields); + + if (fields[cameraFieldType] == "setNavigationState") { + result += " openspace.navigation.setNavigationState({ "; + result += "Anchor = " + fields[cameraNavigationFieldAnchor] + ", "; + if (fields[cameraNavigationFieldAim] != "") { + result += "Aim = " + fields[cameraNavigationFieldAim] + ", "; + } + if (fields[cameraNavigationFieldRef] != "") { + result += "ReferenceFrame = " + fields[cameraNavigationFieldRef] + ", "; + } + result += "Position = " + fields[cameraNavigationFieldPosition] + ", "; + if (fields[cameraNavigationFieldUp] != "") { + result += "Up = {" + fields[cameraNavigationFieldPosition] + "}, "; + } + if (fields[cameraNavigationFieldYaw] != "") { + result += "Yaw = " + fields[cameraNavigationFieldYaw] + ", "; + } + if (fields[cameraNavigationFieldPitch] != "") { + result += "Pitch = " + fields[cameraNavigationFieldPitch] + " "; + } + result += "})\n"; + } + else if (fields[cameraFieldType] == "goToGeo") { + result += " openspace.globebrowsing.goToGeo({ "; + if (fields[cameraGeoFieldAnchor] != "") { + result += fields[cameraGeoFieldAnchor] + ", "; + } + result += fields[cameraGeoFieldLatitude] + ", "; + result += fields[cameraGeoFieldLongitude] + ", "; + if (fields[cameraGeoFieldAltitude] != "") { + result += fields[cameraGeoFieldAltitude] + ", "; + } + result += ")\n"; + } + else { + std::string err = "Camera entry's arg 1/1 must be either "; + err += "'setNavigationState' or 'goToGeo'"; + throw ghoul::RuntimeError(err); + } + return result; +} + scripting::LuaLibrary Profile::luaLibrary() { return { "", diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index c9d3c16964..3ea55f17a5 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -116,7 +116,7 @@ void ProfileFile::writeToFile(std::string filename) { } try { - write(outFile); + outFile << writeToString(); } catch (std::ofstream::failure& e) { LERROR("Data write error to file: " + filename); @@ -130,36 +130,39 @@ void ProfileFile::writeToFile(std::string filename) { } } -void ProfileFile::write(std::ostream& output) { - output << header_Version << std::endl; - output << _version << std::endl << std::endl; - output << header_Module << std::endl; +std::string ProfileFile::writeToString() { + std::string output; + output = header_Version + '\n'; + output += _version + '\n' + '\n'; + output += header_Module + '\n'; addAllElements(output, _modules); - output << std::endl; - output << header_Asset << std::endl; + output += '\n'; + output += header_Asset + '\n'; addAllElements(output, _assets); - output << std::endl; - output << header_Property << std::endl; + output += '\n'; + output += header_Property + '\n'; addAllElements(output, _properties); - output << std::endl; - output << header_Keybinding << std::endl; + output += '\n'; + output += header_Keybinding + '\n'; addAllElements(output, _keybindings); - output << std::endl; - output << header_Time << std::endl; - output << _time << std::endl << std::endl; - output << header_Camera << std::endl; - output << _camera << std::endl; - output << header_MarkNodes << std::endl; + output += '\n'; + output += header_Time + '\n'; + output += _time + '\n' + '\n'; + output += header_Camera + '\n'; + output += _camera + '\n' + '\n'; + output += header_MarkNodes + '\n'; addAllElements(output, _markNodes); + + return output; } const std::string ProfileFile::getVersion() const { return _version; } -void ProfileFile::addAllElements(std::ostream& file, std::vector& list) { +void ProfileFile::addAllElements(std::string& str, std::vector& list) { for (auto s : list) { - file << s << std::endl; + str += s + '\n'; } } @@ -261,11 +264,11 @@ std::vector ProfileFile::markNodes() const { void ProfileFile::parseVersion(std::string line) { std::vector fields; - if (++_numLinesVersion > _versionLinesExpected) { + if (++_numLinesVersion > versionLinesExpected) { throw ghoul::RuntimeError(errorString("Too many lines in Version section"), "profileFile"); } - if (splitByTab(line, fields) > _versionFieldsExpected) { + if (splitByTab(line, fields) > versionFieldsExpected) { throw ghoul::RuntimeError(errorString("No tabs allowed in Version entry"), "profileFile"); } @@ -277,8 +280,8 @@ void ProfileFile::parseVersion(std::string line) { void ProfileFile::parseModule(std::string line) { std::vector fields; - if (splitByTab(line, fields) != _moduleFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(_moduleFieldsExpected) + + if (splitByTab(line, fields) != moduleFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(moduleFieldsExpected) + " fields required in a Module entry"), "profileFile"); } std::vector standard = { @@ -286,30 +289,30 @@ void ProfileFile::parseModule(std::string line) { "", "" }; - verifyRequiredFields("Module", fields, standard, _moduleFieldsExpected); + verifyRequiredFields("Module", fields, standard, moduleFieldsExpected); _modules.push_back(line); } void ProfileFile::parseAsset(std::string line) { std::vector fields; - if (splitByTab(line, fields) != _assetFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(_assetFieldsExpected) + + if (splitByTab(line, fields) != assetFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(assetFieldsExpected) + " fields required in an Asset entry"), "profileFile"); } std::vector standard = { "asset name", "" }; - verifyRequiredFields("Asset", fields, standard, _assetFieldsExpected); + verifyRequiredFields("Asset", fields, standard, assetFieldsExpected); _assets.push_back(line); } void ProfileFile::parseProperty(std::string line) { std::vector fields; - if (splitByTab(line, fields) != _propertyFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(_propertyFieldsExpected) + + if (splitByTab(line, fields) != propertyFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(propertyFieldsExpected) + " fields required in Property entry"), "profileFile"); } std::vector standard = { @@ -317,15 +320,15 @@ void ProfileFile::parseProperty(std::string line) { "name", "value" }; - verifyRequiredFields("Property", fields, standard, _propertyFieldsExpected); + verifyRequiredFields("Property", fields, standard, propertyFieldsExpected); _properties.push_back(line); } void ProfileFile::parseKeybinding(std::string line) { std::vector fields; - if (splitByTab(line, fields) != _keybindingFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(_keybindingFieldsExpected) + if (splitByTab(line, fields) != keybindingFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(keybindingFieldsExpected) + " fields required in Keybinding entry"), "profileFile"); } std::vector standard = { @@ -336,38 +339,38 @@ void ProfileFile::parseKeybinding(std::string line) { "local(T/F)", "script to execute" }; - verifyRequiredFields("Keybinding", fields, standard, _keybindingFieldsExpected); + verifyRequiredFields("Keybinding", fields, standard, keybindingFieldsExpected); _keybindings.push_back(line); } void ProfileFile::parseTime(std::string line) { std::vector fields; - if (++_numLinesTime > _timeLinesExpected) { + if (++_numLinesTime > timeLinesExpected) { throw ghoul::RuntimeError(errorString("Too many lines in time section"), "profileFile"); } - if (splitByTab(line, fields) != _timeFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(_timeFieldsExpected) + + if (splitByTab(line, fields) != timeFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(timeFieldsExpected) + " fields required in Time entry"), "profileFile"); } std::vector standard = { "time set type", "time value to set" }; - verifyRequiredFields("Time", fields, standard, _timeFieldsExpected); + verifyRequiredFields("Time", fields, standard, timeFieldsExpected); _time = line; } void ProfileFile::parseCamera(std::string line) { std::vector fields; - if (++_numLinesCamera > _cameraLinesExpected) { + if (++_numLinesCamera > cameraLinesExpected) { throw ghoul::RuntimeError(errorString("Too many lines in camera section"), "profileFile"); } size_t nFields = splitByTab(line, fields); - if (nFields == _cameraNavigationFieldsExpected) { + if (nFields == cameraNavigationFieldsExpected) { std::vector standard = { "Type of camera set (setNavigationState)", "setNavigationState Anchor", @@ -379,9 +382,9 @@ void ProfileFile::parseCamera(std::string line) { "" }; verifyRequiredFields("Camera navigation", fields, standard, - _cameraNavigationFieldsExpected); + cameraNavigationFieldsExpected); } - else if (nFields == _cameraGeoFieldsExpected) { + else if (nFields == cameraGeoFieldsExpected) { std::vector standard = { "Type of camera set (goToGeo)", "", @@ -390,12 +393,12 @@ void ProfileFile::parseCamera(std::string line) { "" }; verifyRequiredFields("Camera goToGeo", fields, standard, - _cameraGeoFieldsExpected); + cameraGeoFieldsExpected); } else { throw ghoul::RuntimeError(errorString(std::to_string( - _cameraNavigationFieldsExpected) + " or " + std::to_string( - _cameraGeoFieldsExpected) + " fields required in Camera entry"), + cameraNavigationFieldsExpected) + " or " + std::to_string( + cameraGeoFieldsExpected) + " fields required in Camera entry"), "profileFile"); } _camera = line; @@ -404,15 +407,15 @@ void ProfileFile::parseCamera(std::string line) { void ProfileFile::parseMarkNodes(std::string line) { std::vector fields; - if (splitByTab(line, fields) != _markNodesFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(_markNodesFieldsExpected) + + if (splitByTab(line, fields) != markNodesFieldsExpected) { + throw ghoul::RuntimeError(errorString(std::to_string(markNodesFieldsExpected) + " field required in an Mark Nodes entry"), "profileFile"); } std::vector standard = { "Mark Interesting Node name" }; verifyRequiredFields("Mark Interesting Nodes", fields, standard, - _markNodesFieldsExpected); + markNodesFieldsExpected); _markNodes.push_back(line); } diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index 91af2108ed..fce123113e 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -80,26 +80,30 @@ testProfileFormat buildTestProfile1() { return tp1; } -std::string stringFromSingleProfileSection(std::vector& section) { +std::string stringFromSingleProfileSection(std::vector& section, + bool blankLineSeparator) +{ std::string result; for (std::string s : section) { result += s + "\n"; } - result += "\n"; + if (blankLineSeparator) { + result += "\n"; + } return result; } std::string stringFromTestProfileFormat(testProfileFormat& tpf) { std::string fullProfile; - fullProfile += stringFromSingleProfileSection(tpf.tsv); - fullProfile += stringFromSingleProfileSection(tpf.tsm); - fullProfile += stringFromSingleProfileSection(tpf.tsa); - fullProfile += stringFromSingleProfileSection(tpf.tsp); - fullProfile += stringFromSingleProfileSection(tpf.tsk); - fullProfile += stringFromSingleProfileSection(tpf.tst); - fullProfile += stringFromSingleProfileSection(tpf.tsc); - fullProfile += stringFromSingleProfileSection(tpf.tsn); + fullProfile += stringFromSingleProfileSection(tpf.tsv, true); + fullProfile += stringFromSingleProfileSection(tpf.tsm, true); + fullProfile += stringFromSingleProfileSection(tpf.tsa, true); + fullProfile += stringFromSingleProfileSection(tpf.tsp, true); + fullProfile += stringFromSingleProfileSection(tpf.tsk, true); + fullProfile += stringFromSingleProfileSection(tpf.tst, true); + fullProfile += stringFromSingleProfileSection(tpf.tsc, true); + fullProfile += stringFromSingleProfileSection(tpf.tsn, false); return fullProfile; } @@ -266,3 +270,20 @@ TEST_CASE("profileFile: Required field missing", "[profileFile]") { ); } } + +TEST_CASE("profileFile: Write test", "[profileFile]") { + testProfileFormat test = buildTestProfile1(); + std::string testFull_string = stringFromTestProfileFormat(test); + std::istringstream iss(testFull_string); + ProfileFile pf; + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ); + + std::string result = pf.writeToString(); + REQUIRE(testFull_string == result); +} From 3d96836ee1eb310790a3f1b9285eb6a67aa2fb01 Mon Sep 17 00:00:00 2001 From: GPayne Date: Tue, 7 Apr 2020 20:39:31 -0600 Subject: [PATCH 05/61] Added unit tests for conversion from profile to scene --- include/openspace/scene/profile.h | 5 + include/openspace/scene/profilefile.h | 117 ++++++- src/scene/profile.cpp | 30 +- src/scene/profilefile.cpp | 24 +- tests/CMakeLists.txt | 2 + tests/profile/test_common.cpp | 124 ++++++++ tests/profile/test_common.h | 437 ++++++++++++++++++++++++++ tests/profile/test_profile.cpp | 79 +++++ tests/profile/test_profilefile.cpp | 74 +---- 9 files changed, 795 insertions(+), 97 deletions(-) create mode 100644 tests/profile/test_common.cpp create mode 100644 tests/profile/test_common.h create mode 100644 tests/profile/test_profile.cpp diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index e34e5ef111..42e1e2b3fd 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -47,6 +47,11 @@ namespace scripting { struct LuaLibrary; } class Profile { public: + /** + * Saves all current settings, starting from the profile that was loaded at startup, + * and all of the property & asset changes that were made since startup. + * \param filename The filename of the new profile to be saved + */ void saveCurrentSettingsToProfile(std::string filename); /** diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index f7f8c12593..730c3cda18 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -126,26 +126,123 @@ public: * form. * \param filename The filename to write to. */ - void writeToFile(std::string filename); + void writeToFile(const std::string filename); - //Methods for updating contents - void updateTime(); - void updateCamera(); - void addModuleLine(std::string line); - void addAssetLine(std::string line); - void addPropertyLine(std::string line); - void addKeybindingLine(std::string line); - void addMarkNodesLine(std::string line); + /** + * Updates the full string that defines the starting time. The format for this line + * is defined by ProfileFile::parseTime and Profile::convertToAsset_time + * \param line The time entry line to replace current time entry + */ + void updateTime(const std::string line); - //Methods for getting contents of each section + /** + * Updates the full string that defines the starting camera position. The format for + * this line is defined by ProfileFile::parseCamera and Profile::convertToAsset_camera + * \param line The camera entry line to replace current camera entry + */ + void updateCamera(const std::string line); + + /** + * Adds a new module line to the list of module lines to be analyzed by the profile + * at startup. The format for a module line is defined by ProfileFile::parseModule and + * Profile::convertToAsset_modules + * \param line The module name to be added + */ + void addModuleLine(const std::string line); + + /** + * Adds a new asset to the list of assets to be loaded at startup. The format for an + * asset line is defined by ProfileFile::parseAsset and Profile::convertToAsset_assets + * \param line The asset name to be added + */ + void addAssetLine(const std::string line); + + /** + * Adds a new property set command to the list of property settings to be + * performed at startup. The format for a property set command line is defined by + * ProfileFile::parseProperty and Profile::convertToAsset_properties + * \param line The property set command to be added + */ + void addPropertyLine(const std::string line); + + /** + * Adds a new keybinding shortcut to the list of keybindings. The format for a + * keybinding line is defined by ProfileFile::parseKeybinding and + * Profile::convertToAsset_keybindings + * \param line The keyboard shortcut line to be added + */ + void addKeybindingLine(const std::string line); + + /** + * Adds a new scenegraph node name to be added to the list of those marked as + * 'interesting'. The format for a mark nodes line is defined by + * ProfileFile::parseMarkNodes and Profile::convertToAsset_markNodes + * \param line The scenegraph node to be added + */ + void addMarkNodesLine(const std::string line); + + /** + * Returns the version number (profiles syntax version) string + * \return The version string + */ const std::string getVersion() const; + + /** + * Returns the profile's time string. See updateTime comment header for notes on + * syntax of this time string + * \return The time string + */ std::string time() const; + + /** + * Returns the profile's camera string. See updateCamera comment header for notes on + * syntax of this camera string + * \return The camera string + */ std::string camera() const; + + /** + * Returns the vector of OpenSpace modules listed in this profile. See addModuleLine + * comment header for notes on the syntax of each entry. + * \return The vector of module lines + */ std::vector modules() const; + + /** + * Returns the vector of OpenSpace assets listed in this profile. See addAssetLine + * comment header for notes on the syntax of each entry. + * \return The vector of asset lines + */ std::vector assets() const; + + /** + * Returns the vector of OpenSpace property set commands included in this profile. + * See addPropertyLine comment header for notes on the syntax of each entry. + * \return The vector of property set commands + */ std::vector properties() const; + + /** + * Returns the vector of OpenSpace keybinding shortcut definitions included in this + * profile. See addKeybindingLine comment header for syntax notes of each entry. + * \return The vector of keybinding shortcut definitions + */ std::vector keybindings() const; + + /** + * Returns the vector of OpenSpace scenegraph nodes marked as 'interesting'. + * See addMarkNodesLine comment header for syntax notes of each entry. + * \return The vector of nodes to be marked as interesting. + */ std::vector markNodes() const; + + /** + * Splits a tab-delimited line (of any type) into a vector with individual string + * entries. + * \param line The tab-delimited line from which to extract the fields + * \param result A vector of n strings that is populated by the split operation + * \return The number of fields that were extracted + */ size_t splitByTab(std::string line, std::vector& result); private: diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index a5df683edc..b8af9a5bd6 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -67,11 +67,12 @@ std::string Profile::convertToAsset(ProfileFile& pf) { result += convertToAsset_modules(pf) + "\n"; result += convertToAsset_assets(pf) + "\n"; + result += convertToAsset_keybindings(pf) + "\n"; result += "asset.onInitialize(function ()\n"; result += convertToAsset_time(pf) + "\n"; - result += convertToAsset_keybindings(pf) + "\n"; - result += convertToAsset_markNodes(pf); - result += convertToAsset_properties(pf); + result += " sceneHelper.bindKeys(Keybindings)\n\n"; + result += convertToAsset_markNodes(pf) + "\n"; + result += convertToAsset_properties(pf) + "\n"; result += convertToAsset_camera(pf); result += "end)\n"; @@ -107,10 +108,10 @@ std::string Profile::convertToAsset_assets(ProfileFile& pf) { std::string assetR; result += "asset.require(\"base\");\n"; - result += "'local assetHelper = asset.require(\"util/asset_helper\")\n"; - result += "'local propertyHelper = asset.require(\"util/property_helper\")\n"; - result += "'local sceneHelper = asset.require(\"util/scene_helper\")\n"; - result += "'local renderableHelper = asset.require(\"util/renderable_helper\")\n"; + result += "local assetHelper = asset.require(\"util/asset_helper\")\n"; + result += "local propertyHelper = asset.require(\"util/property_helper\")\n"; + result += "local sceneHelper = asset.require(\"util/scene_helper\")\n"; + result += "local renderableHelper = asset.require(\"util/renderable_helper\")\n"; for (size_t i = 0; i < pf.assets().size(); ++i) { std::string a = pf.assets()[i]; @@ -122,6 +123,9 @@ std::string Profile::convertToAsset_assets(ProfileFile& pf) { else if (fields[assetFieldReqd] == "requested") { assetR = "request"; } + else if (fields[assetFieldReqd] == "") { + assetR = "require"; + } else { std::string err = "Asset " + std::to_string(i + 1) + " of "; err += std::to_string(pf.assets().size()) + " has bad arg 2/2 which must "; @@ -150,7 +154,7 @@ std::string Profile::convertToAsset_properties(ProfileFile& pf) { throw ghoul::RuntimeError(err); } else { - result = " openspace." + fields[propertyFieldType] + "(\"" + result += " openspace." + fields[propertyFieldType] + "(\"" + fields[propertyFieldName] + "\", " + fields[propertyFieldValue] + ")\n"; } } @@ -174,7 +178,7 @@ std::string Profile::convertToAsset_keybindings(ProfileFile& pf) { result += " GuiPath = \"" + fields[3] + "\",\n"; result += " Local = " + fields[4] + ",\n"; result += " Command = " + fields[5] + "\n"; - result += " }\n"; + result += " },\n"; } result += "}\n"; return result; @@ -184,7 +188,7 @@ std::string Profile::convertToAsset_markNodes(ProfileFile& pf) { std::string result; if (pf.markNodes().size() > 0) { - result += " openspace.markInterestingNodes({'"; + result += " openspace.markInterestingNodes({"; } for (std::string m : pf.markNodes()) { result += "\"" + m + "\", "; @@ -223,7 +227,7 @@ std::string Profile::convertToAsset_camera(ProfileFile& pf) { pf.splitByTab(pf.camera(), fields); if (fields[cameraFieldType] == "setNavigationState") { - result += " openspace.navigation.setNavigationState({ "; + result += " openspace.navigation.setNavigationState({"; result += "Anchor = " + fields[cameraNavigationFieldAnchor] + ", "; if (fields[cameraNavigationFieldAim] != "") { result += "Aim = " + fields[cameraNavigationFieldAim] + ", "; @@ -231,9 +235,9 @@ std::string Profile::convertToAsset_camera(ProfileFile& pf) { if (fields[cameraNavigationFieldRef] != "") { result += "ReferenceFrame = " + fields[cameraNavigationFieldRef] + ", "; } - result += "Position = " + fields[cameraNavigationFieldPosition] + ", "; + result += "Position = {" + fields[cameraNavigationFieldPosition] + "}, "; if (fields[cameraNavigationFieldUp] != "") { - result += "Up = {" + fields[cameraNavigationFieldPosition] + "}, "; + result += "Up = {" + fields[cameraNavigationFieldUp] + "}, "; } if (fields[cameraNavigationFieldYaw] != "") { result += "Yaw = " + fields[cameraNavigationFieldYaw] + ", "; diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 3ea55f17a5..b2c4251cb4 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -106,7 +106,7 @@ void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { } } -void ProfileFile::writeToFile(std::string filename) { +void ProfileFile::writeToFile(const std::string filename) { std::ofstream outFile; try { outFile.open(filename, std::ofstream::out | std::ofstream::app); @@ -450,4 +450,26 @@ size_t ProfileFile::splitByTab(std::string line, std::vector& resul return result.size(); } +void ProfileFile::updateTime(const std::string line) { + _time = line; +} +void ProfileFile::updateCamera(const std::string line) { + _camera = line; +} +void ProfileFile::addModuleLine(const std::string line) { + _modules.push_back(line); +} +void ProfileFile::addAssetLine(const std::string line) { + _assets.push_back(line); +} +void ProfileFile::addPropertyLine(const std::string line) { + _properties.push_back(line); +} +void ProfileFile::addKeybindingLine(const std::string line) { + _keybindings.push_back(line); +} +void ProfileFile::addMarkNodesLine(const std::string line) { + _markNodes.push_back(line); +} + } // namespace openspace diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 018bc93ba6..75e310568c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,7 +34,9 @@ add_executable( test_lrucache.cpp test_luaconversions.cpp test_optionproperty.cpp + profile/test_common.cpp profile/test_profilefile.cpp + profile/test_profile.cpp test_rawvolumeio.cpp test_scriptscheduler.cpp test_spicemanager.cpp diff --git a/tests/profile/test_common.cpp b/tests/profile/test_common.cpp new file mode 100644 index 0000000000..dd8009c6a4 --- /dev/null +++ b/tests/profile/test_common.cpp @@ -0,0 +1,124 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 "catch2/catch.hpp" +#include "test_common.h" + +#include "openspace/scene/profile.h" +#include "openspace/scene/profilefile.h" +#include +#include +#include +#include + +using namespace openspace; + +namespace { +} + +testProfileFormat buildTestProfile1() { + testProfileFormat tp1; + tp1.tsv.push_back("#Version"); + tp1.tsv.push_back("123.4"); + tp1.tsm.push_back("#Module"); + tp1.tsm.push_back("globebrowsing\t\t"); + tp1.tsm.push_back("gaia\tprint(\"success.\")\t"); + tp1.tsm.push_back("volume\t\tquit"); + tp1.tsa.push_back("#Asset"); + tp1.tsa.push_back("scene/solarsystem/planets/earth/moon/moon\trequired"); + tp1.tsa.push_back("scene/solarsystem/missions/apollo/apollo8\trequested"); + tp1.tsa.push_back("scene/solarsystem/planets/earth/earth\t"); + tp1.tsp.push_back("#Property"); + tp1.tsp.push_back("setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000"); + tp1.tsp.push_back("setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse"); + tp1.tsp.push_back("setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse"); + tp1.tsp.push_back("setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse"); + tp1.tsk.push_back("#Keybinding"); + tp1.tsk.push_back("F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\""); + tp1.tsk.push_back("F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\""); + tp1.tsk.push_back("F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""); + tp1.tsk.push_back("F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\""); + tp1.tst.push_back("#Time"); + tp1.tst.push_back("absolute\t1977-12-21T12:51:51.0"); + tp1.tsc.push_back("#Camera"); + tp1.tsc.push_back("setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"); + tp1.tsn.push_back("#MarkNodes"); + tp1.tsn.push_back("Pluto"); + tp1.tsn.push_back("NewHorizons"); + tp1.tsn.push_back("Charon"); + + return tp1; +} + +std::string stringFromSingleProfileSection(std::vector& section, + bool blankLineSeparator) +{ + std::string result; + for (std::string s : section) { + result += s + "\n"; + } + if (blankLineSeparator) { + result += "\n"; + } + return result; +} + +std::string stringFromTestProfileFormat(testProfileFormat& tpf) { + std::string fullProfile; + + fullProfile += stringFromSingleProfileSection(tpf.tsv, true); + fullProfile += stringFromSingleProfileSection(tpf.tsm, true); + fullProfile += stringFromSingleProfileSection(tpf.tsa, true); + fullProfile += stringFromSingleProfileSection(tpf.tsp, true); + fullProfile += stringFromSingleProfileSection(tpf.tsk, true); + fullProfile += stringFromSingleProfileSection(tpf.tst, true); + fullProfile += stringFromSingleProfileSection(tpf.tsc, true); + fullProfile += stringFromSingleProfileSection(tpf.tsn, false); + + return fullProfile; +} + +ProfileFile makeProfileFromString(std::string s) { + std::istringstream iss(s); + + ProfileFile pf; + pf.readLines([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + }); + + return pf; +} + +StringPerLineReader::StringPerLineReader(std::string s) : _iss(s) { +} + +bool StringPerLineReader::getNextLine(std::string& line) { + if (getline(_iss, line)) + return true; + else + return false; +} diff --git a/tests/profile/test_common.h b/tests/profile/test_common.h new file mode 100644 index 0000000000..cdff281d0c --- /dev/null +++ b/tests/profile/test_common.h @@ -0,0 +1,437 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_TEST___PROFILE_COMMON___H__ +#define __OPENSPACE_TEST___PROFILE_COMMON___H__ + +#include "catch2/catch.hpp" +#include "openspace/scene/profile.h" +#include "openspace/scene/profilefile.h" +#include +#include +#include +#include + +using namespace openspace; + +namespace { +} + +struct testProfileFormat { + std::vector tsv; + std::vector tsm; + std::vector tsa; + std::vector tsp; + std::vector tsk; + std::vector tst; + std::vector tsc; + std::vector tsn; +}; + +const std::string newHorizonsProfileInput ="\ +#Version\n\ +1.0\n\ +\n\ +#Asset\n\ +scene/solarsystem/missions/newhorizons/newhorizons\trequired\n\ +scene/solarsystem/missions/newhorizons/model\trequired\n\ +\n\ +#Property\n\ +setPropertyValueSingle\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +a\tSets the focus of the camera on 'NewHorizons'.\tFocus on New Horizons\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +SHIFT+a\tSets the focus of the camera on 'NewHorizons'.\tAnchor at New Horizons, Aim at Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +s\tSets the focus of the camera on 'Pluto'\tFocus on Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +d\tSets the focus of the camera on 'Charon'.\tFocus on New Charon\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +F7\tToggles New Horizons image projection.\tToggle NH Image Projection\t/New Horizons\tfalse\t[[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ +F8\tRemoves all image projections from Pluto and Charon.\tClear image projections\t/New Horizons\tfalse\t\"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ +F9\tJumps to the 14th of July 2015 at 0900 UTC and clears all projections.\tReset time and projections\t/New Horizons\tfalse\t\"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ +KP_8\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +CTRL+I\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +KP_2\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +CTRL+K\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +KP_9\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +CTRL+O\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +KP_3\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +CTRL+L\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +o\tToggles the visibility of the trail behind Pluto.\tToggle Pluto Trail\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ +j\tToggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\tToggle Pluto Labels\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ +l\tToggles the visibility of the labels for the New Horizons instruments.\tToggle New Horizons Labels\t/New Horizons\tfalse\tpropertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ +m\tDraws the instrument field of views in a solid color or as lines.\tToggle instrument FOVs\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ +Shift+t\tToggles the visibility of the shadow visualization of Pluto and Charon.\tToggle Shadows\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ +t\tToggles the trail of New Horizons.\tToggle NH Trail\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ +h\tDisables visibility of the trails\tHide Trails\t/Rendering\tfalse\t\"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ +1\tSetting the simulation speed to 1 seconds per realtime second\tSet sim speed 1\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1)\"\n\ +2\tSetting the simulation speed to 5 seconds per realtime second\tSet sim speed 5\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(5)\"\n\ +3\tSetting the simulation speed to 10 seconds per realtime second\tSet sim speed 10\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(10)\"\n\ +4\tSetting the simulation speed to 20 seconds per realtime second\tSet sim speed 20\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(20)\"\n\ +5\tSetting the simulation speed to 40 seconds per realtime second\tSet sim speed 40\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(40)\"\n\ +6\tSetting the simulation speed to 60 seconds per realtime second\tSet sim speed 60\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(60)\"\n\ +7\tSetting the simulation speed to 120 seconds per realtime second\tSet sim speed 120\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(120)\"\n\ +8\tSetting the simulation speed to 360 seconds per realtime second\tSet sim speed 360\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(360)\"\n\ +9\tSetting the simulation speed to 540 seconds per realtime second\tSet sim speed 540\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(540)\"\n\ +0\tSetting the simulation speed to 1080 seconds per realtime second\tSet sim speed 1080\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1080)\"\n\ +Shift+1\tSetting the simulation speed to 2160 seconds per realtime second\tSet sim speed 2160\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(2160)\"\n\ +Shift+2\tSetting the simulation speed to 4320 seconds per realtime second\tSet sim speed 4320\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(4320)\"\n\ +Shift+3\tSetting the simulation speed to 8640 seconds per realtime second\tSet sim speed 8640\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(8640)\"\n\ +\n\ +#Time\n\ +absolute\t2015-07-14T08:00:00.00\n\ +\n\ +#Camera\n\ +setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t\n\ +\n\ +#MarkNodes\n\ +Pluto\n\ +NewHorizons\n\ +Charon"; + +const std::string newHorizonsExpectedSceneOutput = "\ +\n\ +asset.require(\"base\");\n\ +local assetHelper = asset.require(\"util/asset_helper\")\n\ +local propertyHelper = asset.require(\"util/property_helper\")\n\ +local sceneHelper = asset.require(\"util/scene_helper\")\n\ +local renderableHelper = asset.require(\"util/renderable_helper\")\n\ +asset.require(\"scene/solarsystem/missions/newhorizons/newhorizons\")\n\ +asset.require(\"scene/solarsystem/missions/newhorizons/model\")\n\ +\n\ +local Keybindings = {\n\ + {\n\ + Key = \"a\",\n\ + Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ + Name = \"Focus on New Horizons\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ + },\n\ + {\n\ + Key = \"SHIFT+a\",\n\ + Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ + Name = \"Anchor at New Horizons, Aim at Pluto\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ + },\n\ + {\n\ + Key = \"s\",\n\ + Documentation = \"Sets the focus of the camera on 'Pluto'\",\n\ + Name = \"Focus on Pluto\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ + },\n\ + {\n\ + Key = \"d\",\n\ + Documentation = \"Sets the focus of the camera on 'Charon'.\",\n\ + Name = \"Focus on New Charon\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ + },\n\ + {\n\ + Key = \"F7\",\n\ + Documentation = \"Toggles New Horizons image projection.\",\n\ + Name = \"Toggle NH Image Projection\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = [[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ + },\n\ + {\n\ + Key = \"F8\",\n\ + Documentation = \"Removes all image projections from Pluto and Charon.\",\n\ + Name = \"Clear image projections\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = \"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ + },\n\ + {\n\ + Key = \"F9\",\n\ + Documentation = \"Jumps to the 14th of July 2015 at 0900 UTC and clears all projections.\",\n\ + Name = \"Reset time and projections\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = \"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ + },\n\ + {\n\ + Key = \"KP_8\",\n\ + Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ + Name = \"Pluto HeightExaggeration +\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"CTRL+I\",\n\ + Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ + Name = \"Pluto HeightExaggeration +\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"KP_2\",\n\ + Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ + Name = \"Pluto HeightExaggeration -\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"CTRL+K\",\n\ + Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ + Name = \"Pluto HeightExaggeration -\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"KP_9\",\n\ + Documentation = \"Increases the height map exaggeration on Charon.\",\n\ + Name = \"Charon HeightExaggeration +\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"CTRL+O\",\n\ + Documentation = \"Increases the height map exaggeration on Charon.\",\n\ + Name = \"Charon HeightExaggeration +\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"KP_3\",\n\ + Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ + Name = \"Charon HeightExaggeration -\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"CTRL+L\",\n\ + Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ + Name = \"Charon HeightExaggeration -\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ + },\n\ + {\n\ + Key = \"o\",\n\ + Documentation = \"Toggles the visibility of the trail behind Pluto.\",\n\ + Name = \"Toggle Pluto Trail\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ + },\n\ + {\n\ + Key = \"j\",\n\ + Documentation = \"Toggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\",\n\ + Name = \"Toggle Pluto Labels\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = renderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ + },\n\ + {\n\ + Key = \"l\",\n\ + Documentation = \"Toggles the visibility of the labels for the New Horizons instruments.\",\n\ + Name = \"Toggle New Horizons Labels\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ + },\n\ + {\n\ + Key = \"m\",\n\ + Documentation = \"Draws the instrument field of views in a solid color or as lines.\",\n\ + Name = \"Toggle instrument FOVs\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = propertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ + },\n\ + {\n\ + Key = \"Shift+t\",\n\ + Documentation = \"Toggles the visibility of the shadow visualization of Pluto and Charon.\",\n\ + Name = \"Toggle Shadows\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = renderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ + },\n\ + {\n\ + Key = \"t\",\n\ + Documentation = \"Toggles the trail of New Horizons.\",\n\ + Name = \"Toggle NH Trail\",\n\ + GuiPath = \"/New Horizons\",\n\ + Local = false,\n\ + Command = renderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ + },\n\ + {\n\ + Key = \"h\",\n\ + Documentation = \"Disables visibility of the trails\",\n\ + Name = \"Hide Trails\",\n\ + GuiPath = \"/Rendering\",\n\ + Local = false,\n\ + Command = \"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ + },\n\ + {\n\ + Key = \"1\",\n\ + Documentation = \"Setting the simulation speed to 1 seconds per realtime second\",\n\ + Name = \"Set sim speed 1\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(1)\"\n\ + },\n\ + {\n\ + Key = \"2\",\n\ + Documentation = \"Setting the simulation speed to 5 seconds per realtime second\",\n\ + Name = \"Set sim speed 5\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(5)\"\n\ + },\n\ + {\n\ + Key = \"3\",\n\ + Documentation = \"Setting the simulation speed to 10 seconds per realtime second\",\n\ + Name = \"Set sim speed 10\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(10)\"\n\ + },\n\ + {\n\ + Key = \"4\",\n\ + Documentation = \"Setting the simulation speed to 20 seconds per realtime second\",\n\ + Name = \"Set sim speed 20\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(20)\"\n\ + },\n\ + {\n\ + Key = \"5\",\n\ + Documentation = \"Setting the simulation speed to 40 seconds per realtime second\",\n\ + Name = \"Set sim speed 40\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(40)\"\n\ + },\n\ + {\n\ + Key = \"6\",\n\ + Documentation = \"Setting the simulation speed to 60 seconds per realtime second\",\n\ + Name = \"Set sim speed 60\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(60)\"\n\ + },\n\ + {\n\ + Key = \"7\",\n\ + Documentation = \"Setting the simulation speed to 120 seconds per realtime second\",\n\ + Name = \"Set sim speed 120\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(120)\"\n\ + },\n\ + {\n\ + Key = \"8\",\n\ + Documentation = \"Setting the simulation speed to 360 seconds per realtime second\",\n\ + Name = \"Set sim speed 360\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(360)\"\n\ + },\n\ + {\n\ + Key = \"9\",\n\ + Documentation = \"Setting the simulation speed to 540 seconds per realtime second\",\n\ + Name = \"Set sim speed 540\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(540)\"\n\ + },\n\ + {\n\ + Key = \"0\",\n\ + Documentation = \"Setting the simulation speed to 1080 seconds per realtime second\",\n\ + Name = \"Set sim speed 1080\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(1080)\"\n\ + },\n\ + {\n\ + Key = \"Shift+1\",\n\ + Documentation = \"Setting the simulation speed to 2160 seconds per realtime second\",\n\ + Name = \"Set sim speed 2160\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(2160)\"\n\ + },\n\ + {\n\ + Key = \"Shift+2\",\n\ + Documentation = \"Setting the simulation speed to 4320 seconds per realtime second\",\n\ + Name = \"Set sim speed 4320\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(4320)\"\n\ + },\n\ + {\n\ + Key = \"Shift+3\",\n\ + Documentation = \"Setting the simulation speed to 8640 seconds per realtime second\",\n\ + Name = \"Set sim speed 8640\",\n\ + GuiPath = \"/Simulation Speed\",\n\ + Local = false,\n\ + Command = \"openspace.time.interpolateDeltaTime(8640)\"\n\ + },\n\ +}\n\ +\n\ +asset.onInitialize(function ()\n\ + openspace.time.setTime(\"2015-07-14T08:00:00.00\")\n\ +\n\ + sceneHelper.bindKeys(Keybindings)\n\ +\n\ + openspace.markInterestingNodes({\"Pluto\", \"NewHorizons\", \"Charon\", })\n\ +\n\ + openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\", 20.000000)\n\ + openspace.setPropertyValueSingle(\"Scene.Pluto.Renderable.Enabled\", false)\n\ + openspace.setPropertyValueSingle(\"Scene.Charon.Renderable.Enabled\", false)\n\ + openspace.setPropertyValueSingle(\"Scene.PlutoBarycenterTrail.Renderable.Enabled\", false)\n\ +\n\ + openspace.navigation.setNavigationState({Anchor = \"NewHorizons\", ReferenceFrame = \"Root\", Position = {-6.572656E1, -7.239404E1, -2.111890E1}, Up = {0.102164, -0.362945, 0.926193}, })\n\ +end)"; + +testProfileFormat buildTestProfile1(); +std::string stringFromSingleProfileSection(std::vector& section, + bool blankLineSeparator); +std::string stringFromTestProfileFormat(testProfileFormat& tpf); +ProfileFile makeProfileFromString(std::string s); + +class StringPerLineReader { +public: + StringPerLineReader(std::string s); + bool getNextLine(std::string& line); + +private: + std::istringstream _iss; +}; + +#endif //__OPENSPACE_TEST___PROFILE_COMMON___H__ diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp new file mode 100644 index 0000000000..62389a275b --- /dev/null +++ b/tests/profile/test_profile.cpp @@ -0,0 +1,79 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2020 * + * * + * 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 "catch2/catch.hpp" +#include "test_common.h" + +#include "openspace/scene/profile.h" +#include +#include +#include +#include + +using namespace openspace; + +namespace { +} + +static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { + s = "@line " + std::to_string(lineNumber) + ": '" + s + "'"; +} + +TEST_CASE("profile: Convert profileFile to asset", "[profile]") { + testProfileFormat test = buildTestProfile1(); + std::string testFull_string = stringFromTestProfileFormat(test); + + ProfileFile pf = makeProfileFromString(testFull_string); + + Profile p; + REQUIRE_NOTHROW( + p.convertToAsset(pf) + ); +} + +TEST_CASE("profile: Verify conversion to scene", "[profile]") { + ProfileFile pf = makeProfileFromString(newHorizonsProfileInput); + + Profile p; + std::string result; + REQUIRE_NOTHROW( + result = p.convertToAsset(pf) + ); + + std::string testing, comparing; + StringPerLineReader sr_result(result); + StringPerLineReader sr_standard(newHorizonsExpectedSceneOutput); + + size_t lineN = 1; + while (sr_result.getNextLine(testing)) { + sr_standard.getNextLine(comparing); + addLineHeaderForFailureMessage(testing, lineN); + addLineHeaderForFailureMessage(comparing, lineN); + REQUIRE(testing == comparing); + lineN++; + } + //If this fails there are extra lines in the comparison string that weren't in result + REQUIRE(sr_standard.getNextLine(comparing) == false); +} + diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index fce123113e..ad1db7997d 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -25,6 +25,7 @@ #include "catch2/catch.hpp" #include "openspace/scene/profilefile.h" +#include "test_common.h" #include #include #include @@ -35,79 +36,6 @@ using namespace openspace; namespace { } -struct testProfileFormat { - std::vector tsv; - std::vector tsm; - std::vector tsa; - std::vector tsp; - std::vector tsk; - std::vector tst; - std::vector tsc; - std::vector tsn; -}; - -testProfileFormat buildTestProfile1() { - testProfileFormat tp1; - tp1.tsv.push_back("#Version"); - tp1.tsv.push_back("123.4"); - tp1.tsm.push_back("#Module"); - tp1.tsm.push_back("globebrowsing\t\t"); - tp1.tsm.push_back("gaia\tprint(\"success.\")\t"); - tp1.tsm.push_back("volume\t\tquit"); - tp1.tsa.push_back("#Asset"); - tp1.tsa.push_back("scene/solarsystem/planets/earth/moon/moon\trequired"); - tp1.tsa.push_back("scene/solarsystem/missions/apollo/apollo8\trequested"); - tp1.tsa.push_back("scene/solarsystem/planets/earth/earth\t"); - tp1.tsp.push_back("#Property"); - tp1.tsp.push_back("setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000"); - tp1.tsp.push_back("setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse"); - tp1.tsp.push_back("setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse"); - tp1.tsp.push_back("setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse"); - tp1.tsk.push_back("#Keybinding"); - tp1.tsk.push_back("F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\""); - tp1.tsk.push_back("F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\""); - tp1.tsk.push_back("F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""); - tp1.tsk.push_back("F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\""); - tp1.tst.push_back("#Time"); - tp1.tst.push_back("absolute\t1977-12-21T12:51:51.0"); - tp1.tsc.push_back("#Camera"); - tp1.tsc.push_back("setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"); - tp1.tsn.push_back("#MarkNodes"); - tp1.tsn.push_back("Pluto"); - tp1.tsn.push_back("NewHorizons"); - tp1.tsn.push_back("Charon"); - - return tp1; -} - -std::string stringFromSingleProfileSection(std::vector& section, - bool blankLineSeparator) -{ - std::string result; - for (std::string s : section) { - result += s + "\n"; - } - if (blankLineSeparator) { - result += "\n"; - } - return result; -} - -std::string stringFromTestProfileFormat(testProfileFormat& tpf) { - std::string fullProfile; - - fullProfile += stringFromSingleProfileSection(tpf.tsv, true); - fullProfile += stringFromSingleProfileSection(tpf.tsm, true); - fullProfile += stringFromSingleProfileSection(tpf.tsa, true); - fullProfile += stringFromSingleProfileSection(tpf.tsp, true); - fullProfile += stringFromSingleProfileSection(tpf.tsk, true); - fullProfile += stringFromSingleProfileSection(tpf.tst, true); - fullProfile += stringFromSingleProfileSection(tpf.tsc, true); - fullProfile += stringFromSingleProfileSection(tpf.tsn, false); - - return fullProfile; -} - TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { testProfileFormat test = buildTestProfile1(); std::string testFull_string = stringFromTestProfileFormat(test); From 83ef5ed245d828574fb71ad1a649f222bc0072d4 Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 15 Apr 2020 16:31:05 -0600 Subject: [PATCH 06/61] Switched profile-to-scene conversion from lua script to Profile class --- include/openspace/scene/profile.h | 10 + include/openspace/scene/profilefile.h | 8 +- scripts/convert_profile_to_scene.lua | 473 -------------------------- src/engine/openspaceengine.cpp | 41 +-- src/scene/profile.cpp | 31 +- 5 files changed, 52 insertions(+), 511 deletions(-) delete mode 100644 scripts/convert_profile_to_scene.lua diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 42e1e2b3fd..9bfabfde04 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -54,6 +54,16 @@ public: */ void saveCurrentSettingsToProfile(std::string filename); + /** + * Reads in a .profile file, converts it to scene/asset equivalent syntax, and + * writes the result to the specified output path. + * \param inProfilePath The .profile file to be converted + * \param outFilePath The output file path that will be written with the converted + * contents (in an .asset file) + */ + void convertToAssetFile(const std::string inProfilePath, + const std::string outFilePath); + /** * Returns the string contents of a profileFile object converted to scene/asset * equivalent syntax. diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 730c3cda18..82cfa0facd 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -137,22 +137,22 @@ public: /** * Updates the full string that defines the starting camera position. The format for - * this line is defined by ProfileFile::parseCamera and Profile::convertToAsset_camera + * this line is defined by ProfileFile::parseCamera & Profile::convertToAsset_camera * \param line The camera entry line to replace current camera entry */ void updateCamera(const std::string line); /** * Adds a new module line to the list of module lines to be analyzed by the profile - * at startup. The format for a module line is defined by ProfileFile::parseModule and - * Profile::convertToAsset_modules + * at startup. The format for a module line is defined by ProfileFile::parseModule + * and Profile::convertToAsset_modules * \param line The module name to be added */ void addModuleLine(const std::string line); /** * Adds a new asset to the list of assets to be loaded at startup. The format for an - * asset line is defined by ProfileFile::parseAsset and Profile::convertToAsset_assets + * asset line is defined by ProfileFile::parseAsset & Profile::convertToAsset_assets * \param line The asset name to be added */ void addAssetLine(const std::string line); diff --git a/scripts/convert_profile_to_scene.lua b/scripts/convert_profile_to_scene.lua deleted file mode 100644 index 0b852fe290..0000000000 --- a/scripts/convert_profile_to_scene.lua +++ /dev/null @@ -1,473 +0,0 @@ -version = '' -modulesTable = {} -assetsTable = {} -propertiesTable = {} -timeTable = {} -cameraTable = {} -markNodesTable = {} -keybindingsTable = {} -resultTable = {} -insideSection = false -currFunction = 'None' -currSection = 'None' -numLinesVersion = 0 -lineIndex = 1 - - -function printError(message) - print('Error @ line ' .. lineIndex .. ': ' .. message) -end - -function splitByTab(inputstr) - sep = "\t" - t = {} - for match in (inputstr .. sep):gmatch('(.-)' .. sep) do - table.insert(t, match) - end - return t; -end - -function parseVersion(line) - numLinesVersion = numLinesVersion + 1 - if numLinesVersion > 1 then - printError('Too many lines in Version section') - os.exit() - else - lineS = splitByTab(line) - if tableLen(lineS) > 1 then - printError('No tabs allowed in version entry') - os.exit() - else - version = line - end - end -end - -function parseMarkNodes(line) - lineS = splitByTab(line) - if tableLen(lineS) > 1 then - printError('No tabs allowed in MarkNodes entry') - os.exit() - else - table.insert(markNodesTable, line) - end -end - -function parseModule(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 3 then - printError('3 fields requried in a Module entry') - os.exit() - else - table.insert(modulesTable, t) - end -end - -function parseAsset(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 2 then - printError('2 fields required in a Asset entry') - os.exit() - else - local req = 'required' - if t[2] == 'requested' then - req = 'requested' - end - table.insert(assetsTable, {t[1], req}) - end -end - -function parseProperty(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 3 then - printError('3 fields required in a Property entry') - os.exit() - elseif isBlank(t[1]) then - printError('Property set command (arg 1/3) is required') - os.exit() - elseif isBlank(t[2]) then - printError('Property name (arg 2/3) is required') - os.exit() - elseif isBlank(t[3]) then - printError('Property value to set (arg 3/3) is required') - os.exit() - end - - if t[1] ~= 'setPropertyValue' and t[1] ~= 'setPropertyValueSingle' then - printError('Property set command "' .. t[1] .. '" is not supported') - os.exit() - end - - table.insert(propertiesTable, t) -end - -function parseKeybinding(line) - local numReqFields = 6 - t = {} - t = splitByTab(line) - if tableLen(t) < numReqFields then - printError(numReqFields .. ' fields required in a Keybinding entry') - os.exit() - elseif isBlank(t[1]) then - printError('Keybinding key (arg 1/6) is required') - os.exit() - elseif isBlank(t[2]) then - printError('Keybinding documentation (arg 2/6) is required') - os.exit() - elseif isBlank(t[3]) then - printError('Keybinding name (arg 3/6) is required') - os.exit() - elseif isBlank(t[4]) then - printError('Keybinding GuiPath (arg 4/6) is required') - os.exit() - elseif isBlank(t[5]) then - printError('Keybinding local(T/F) (arg 5/6) is required') - os.exit() - elseif isBlank(t[6]) then - printError('Keybinding script to execute (arg 6/6) is required') - os.exit() - end - - --If there are more than 6 fields then combine the final fields together - --assuming that this is a lua script that contains tabs - if tableLen(t) > numReqFields then - for i=(numReqFields + 1),tableLen(t) do - t[numReqFields] = t[numReqFields]..t[i] - end - end - - if t[5] ~= 'true' and t[5] ~= 'false' then - printError('Keybinding local arg must be true or false') - os.exit() - end - - table.insert(keybindingsTable, { t[1], t[2], t[3], t[4], t[5], t[6] }) -end - -function parseTime(line) - t = {} - t = splitByTab(line) - if tableLen(t) ~= 2 then - printError('2 fields required in a Time entry') - os.exit() - elseif isBlank(t[1]) then - printError('Time set type (arg 1/2) is required') - os.exit() - elseif isBlank(t[2]) then - printError('Time value to set (arg 2/2) is required') - os.exit() - end - - if t[1] ~= 'absolute' and t[1] ~= 'relative' then - printError('Time set type "' .. t[1] .. '" is not supported') - os.exit() - end - - table.insert(timeTable, t) -end - -function parseCamera(line) - t = {} - t = splitByTab(line) - - local cmd = t[1] - if cmd == 'setNavigationState' then - if tableLen(t) ~= 8 then - printError('8 fields required in camera "setNavigationState" line') - os.exit() - elseif isBlank(t[2]) then - printError('Camera setNavigationState Anchor (arg 1/7) is required') - os.exit() - elseif isBlank(t[5]) then - printError('Camera setNavigationState position vector (arg 4/7) is required') - os.exit() - end - elseif cmd == 'goToGeo' then - if tableLen(t) ~= 5 then - printError('5 fields required in camera "goToGeo" line') - os.exit() - elseif isBlank(t[3]) then - printError('Camera goToGeo Latitude (arg 2/4) is required') - os.exit() - elseif isBlank(t[4]) then - printError('Camera goToGeo Longitude (arg 3/4) is required') - os.exit() - end - else - printError('Camera position command "' .. cmd .. '" is not supported') - os.exit() - end - - table.insert(cameraTable, t) -end - -function file_exists(file) - local f = io.open(file, 'rb') - if f then - f:close() - end - return f ~= nil -end - -function lines_from(file) - if not file_exists(file) then - return {} - end - lines = {} - for line in io.lines(file) do - lines[#lines + 1] = line - end - return lines -end - -function determineSection(header) - header = header:sub(2) - for _,i in pairs(parsingSections) do - if i.section == header then - currSection = i.section - currFunction = i.func - return true - end - end - return false -end - -function isBlank(line) - return line:match('%S') == nil -end - -function parseCurrentSection(line) - currFunction(line) -end - -function tableLen(T) - local size = 0 - for _ in pairs(T) do - size = size + 1 - end - return size -end - -function parseProfile(fileIn) - local lines = lines_from(fileIn) - - for k,v in pairs(lines) do - if insideSection then - if isBlank(v) then - insideSection = false - else - parseCurrentSection(v) - end - elseif v:sub(1, 1) == '#' then - if determineSection(v) then - insideSection = true - end - end - lineIndex = lineIndex + 1 - end - - resultTable['Version'] = version - resultTable['Module'] = modulesTable - resultTable['Asset'] = assetsTable - resultTable['Property'] = propertiesTable - resultTable['Time'] = timeTable - resultTable['Camera'] = cameraTable - resultTable['MarkNodes'] = markNodesTable - resultTable['Keybinding'] = keybindingsTable - - return resultTable -end - -function tableSize(T) - local size = 0 - for _ in pairs(T) do - size = size + 1 - end - return size -end - -function generateAsset(T, fileOut) - file = io.open(fileOut, 'w') - io.output(file) - - --Module section - for i,j in pairs(T['Module']) do - if not isBlank(j[2]) and not isBlank(j[3]) then - ModuleStr = ModuleStr .. 'if openspace.modules.isLoaded("' .. j[1] .. '") then\n' - ModuleStr = ModuleStr .. ' ' .. j[2] .. '\nelse\n' .. ' ' .. j[3] .. '\nend\n' - elseif not isBlank(j[3]) then - ModuleStr = ModuleStr .. 'if not openspace.modules.isLoaded("' .. j[1] .. '") then\n' - ModuleStr = ModuleStr .. ' ' .. j[3] .. '\nend\n' - elseif not isBlank(j[2]) then - ModuleStr = ModuleStr .. 'if openspace.modules.isLoaded("' .. j[1] .. '") then\n' - ModuleStr = ModuleStr .. ' ' .. j[2] .. '\nend\n' - end - end - - --Asset section - AssetStr = AssetStr .. 'asset.require("base");\n' - AssetStr = AssetStr .. 'local assetHelper = asset.require("util/asset_helper")\n' - AssetStr = AssetStr .. 'local propertyHelper = asset.require("util/property_helper")\n' - AssetStr = AssetStr .. 'local sceneHelper = asset.require("util/scene_helper")\n' - AssetStr = AssetStr .. 'local renderableHelper = asset.require("util/renderable_helper")\n' - local assetType = '' - for i,j in pairs(T['Asset']) do - if isBlank(j[2]) then - assetType = 'require' - else - if (j[2] == 'required') then - assetType = 'require' - elseif (j[2] == 'requested') then - assetType = 'request' - else - printError('Asset arg 2/2 must be either "required" or "requested"') - os.exit() - end - end - AssetStr = AssetStr .. 'asset.' .. assetType .. '("' .. j[1] .. '")\n' - end - - --Keybindings section - if not (tableSize(T['Keybinding']) == 0) then - KeyStr = KeyStr .. 'local Keybindings = {\n' - for i,j in pairs(T['Keybinding']) do - KeyStr = KeyStr..' {\n' - KeyStr = KeyStr..' Key = "' .. j[1] .. '",\n' - KeyStr = KeyStr..' Documentation = "' .. j[2] .. '",\n' - KeyStr = KeyStr..' Name = "' .. j[3] .. '",\n' - KeyStr = KeyStr..' GuiPath = "' .. j[4] .. '",\n' - KeyStr = KeyStr..' Local = ' .. j[5] .. ',\n' - KeyStr = KeyStr..' Command = ' .. j[6] .. '\n' - KeyStr = KeyStr..' },\n' - end - KeyStr = KeyStr.."}\n" - end - - --Time section - for i,j in pairs(T['Time']) do - if not (j[1] == 'absolute') and not (j[1] == 'relative') then - printError('Time arg 1/1 must be either "absolute" or "relative"') - os.exit() - elseif (j[1] == 'absolute') then - TimeStr = TimeStr .. ' openspace.time.setTime("' .. j[2] .. '")\n' - elseif (j[1] == 'relative') then - TimeStr = TimeStr .. ' local now = openspace.time.currentWallTime();' - TimeStr = TimeStr .. ' openspace.time.setTime(' - TimeStr = TimeStr .. 'openspace.time.advancedTime(now, "' .. j[2] .. '"))\n' - end - end - - --MarkNodes section - mkNodLen = tableSize(T['MarkNodes']) - if not (mkNodLen == 0) then - MarkNodesStr = MarkNodesStr .. ' openspace.markInterestingNodes({' - for i, j in pairs(T['MarkNodes']) do - MarkNodesStr = MarkNodesStr .. '"' .. j .. '"' - if (i < mkNodLen) then - MarkNodesStr = MarkNodesStr .. ', ' - end - end - MarkNodesStr = MarkNodesStr .. '})\n' - end - - --Property section - for i, j in pairs(T['Property']) do - if not (j[1] == 'setPropertyValue') and not (j[1] == 'setPropertyValueSingle') then - printError('Property arg 1/1 must be "setPropertyValue[Single]"') - os.exit() - else - PropertyStr = PropertyStr .. ' openspace.' .. j[1] .. '("' .. j[2] .. '", ' .. j[3] .. ')\n' - end - end - - --Camera section - for i,j in pairs(T['Camera']) do - if (j[1] == 'setNavigationState') then - CameraStr = CameraStr .. ' openspace.navigation.setNavigationState({' - CameraStr = CameraStr .. 'Anchor = ' .. j[2] .. ', ' - if not isBlank(j[3]) then - CameraStr = CameraStr .. 'Aim = ' .. j[3] .. ', ' - end - if not isBlank(j[4]) then - CameraStr = CameraStr .. 'ReferenceFrame = ' .. j[4] .. ', ' - end - CameraStr = CameraStr .. 'Position = {' .. j[5] .. '}, ' - if not isBlank(j[6]) then - CameraStr = CameraStr .. 'Up = {' .. j[6] .. '}, ' - end - if not isBlank(j[7]) then - CameraStr = CameraStr .. 'Yaw = ' .. j[7] .. ', ' - end - if not isBlank(j[8]) then - CameraStr = CameraStr .. 'Pitch = ' .. j[8] - end - CameraStr = CameraStr .. '})\n' - elseif (j[1] == 'goToGeo') then - CameraStr = CameraStr .. ' openspace.globebrowsing.goToGeo(' - if not isBlank(j[2]) then - CameraStr = CameraStr .. j[2] .. ', ' - end - CameraStr = CameraStr .. j[3] .. ', ' .. j[4] - if not isBlank(j[5]) then - CameraStr = CameraStr .. ', ' .. j[5] - end - CameraStr = CameraStr .. ')\n' - else - printError('Camera arg 1/1 must be "setNavigationState" or "goToGeo"') - os.exit() - end - end - - --Write the file - io.write(ModuleStr .. '\n') - io.write(AssetStr .. '\n') - io.write(KeyStr .. '\n') - io.write('asset.onInitialize(function ()\n') - io.write(TimeStr .. '\n') - if not (tableSize(T['Keybinding']) == 0) then - io.write(' sceneHelper.bindKeys(Keybindings)\n') - end - io.write(MarkNodesStr .. '\n') - io.write(PropertyStr .. '\n') - io.write(CameraStr .. '\n') - io.write('end)\n') - - io.close(file) -end - ---[[ -########################################################################################## - M a i n -########################################################################################## -]]-- - -ModuleStr = '' -AssetStr = '' -KeyStr = '' -TimeStr = '' -MarkNodesStr = '' -PropertyStr = '' -CameraStr = '' - -parsingSections = { - { section = 'Version', func = parseVersion }, - { section = 'Module', func = parseModule }, - { section = 'Asset', func = parseAsset }, - { section = 'Property', func = parseProperty }, - { section = 'Keybinding', func = parseKeybinding }, - { section = 'Time', func = parseTime }, - { section = 'Camera', func = parseCamera }, - { section = 'MarkNodes', func = parseMarkNodes } -} - -profilePathIn = openspace.profile.getProfileInputPath() -scenePathOut = openspace.profile.getSceneOutputPath() - -profileIn = profilePathIn .. '.profile' -assetOut = scenePathOut .. '.scene' - -local resultTable = parseProfile(profileIn) -generateAsset(resultTable, assetOut) diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 033ab87322..5f04e66c2a 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -99,8 +100,6 @@ namespace { constexpr const char* _loggerCat = "OpenSpaceEngine"; constexpr const int CacheVersion = 1; - constexpr const char* ProfileToSceneConverter - = "${BASE}/scripts/convert_profile_to_scene.lua"; } // namespace @@ -300,38 +299,14 @@ void OpenSpaceEngine::initialize() { // Convert profile to scene file (if was provided in configuration file) if (!global::configuration.profile.empty()) { - LINFO( - fmt::format("Run Lua script to convert {}.profile to scene", - global::configuration.profile) - ); - ghoul::lua::LuaState lState; - - // We can't use the absPath function here because we pass the path into the Lua - // function, which requires additional escaping - std::string inputProfilePath = generateFilePath("${ASSETS}"); - std::string outputScenePath = generateFilePath("${TEMPORARY}"); - - std::string setProfileFilenameInLuaState = fmt::format(R"( - openspace = {{}} - openspace.profile = {{}} - function openspace.profile.getFilename() - return "{}.profile" - end - function openspace.profile.getProfileInputPath() - return "{}" - end - function openspace.profile.getSceneOutputPath() - return "{}" - end - )", - global::configuration.profile, - inputProfilePath, - outputScenePath - ); - - ghoul::lua::runScript(lState, setProfileFilenameInLuaState); - ghoul::lua::runScriptFile(lState, absPath(ProfileToSceneConverter)); + std::string inputProfilePath = absPath("${ASSETS}"); + std::string outputScenePath = absPath("${TEMPORARY}"); + std::string inputProfile = inputProfilePath + "/" + global::configuration.profile + + ".profile"; + std::string outputAsset = outputScenePath + "/" + global::configuration.profile + + ".asset"; + global::profile.convertToAssetFile(inputProfile, outputAsset); // Set asset name to that of the profile because a new scene file will be // created with that name, and also because the profile name will override diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index b8af9a5bd6..57bb85fd89 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -48,7 +48,6 @@ namespace { constexpr const char* _loggerCat = "Profile"; constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeyParent = "Parent"; - } // namespace namespace openspace { @@ -62,6 +61,36 @@ void Profile::saveCurrentSettingsToProfile(std::string filename) { std::string initProfile = global::configuration.profile; } +void Profile::convertToAssetFile(const std::string inProfilePath, + const std::string outFilePath) +{ + ProfileFile pf; + + pf.readFromFile(inProfilePath); + + std::ofstream outFile; + try { + outFile.open(outFilePath, std::ofstream::out); + } + catch (std::ofstream::failure& e) { + LERROR("Exception opening profile file for write: " + outFilePath); + } + + try { + outFile << convertToAsset(pf); + } + catch (std::ofstream::failure& e) { + LERROR("Data write error to file: " + outFilePath); + } + + try { + outFile.close(); + } + catch (std::ofstream::failure& e) { + LERROR("Exception closing profile file after write: " + outFilePath); + } +} + std::string Profile::convertToAsset(ProfileFile& pf) { std::string result; From 1fbb9e8acf878894c3c75f3dc8782e9c7782ae55 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 23 Apr 2020 12:06:34 -0600 Subject: [PATCH 07/61] Completed code for detecting and storing changes made since startup --- include/openspace/engine/openspaceengine.h | 3 + include/openspace/properties/property.h | 7 + include/openspace/scene/assetloader.h | 14 ++ include/openspace/scene/assetmanager.h | 3 + include/openspace/scene/profile.h | 50 ++++- include/openspace/scene/profilefile.h | 27 ++- src/engine/openspaceengine.cpp | 11 +- src/properties/property.cpp | 4 + src/scene/assetloader.cpp | 18 +- src/scene/assetmanager.cpp | 8 + src/scene/profile.cpp | 203 +++++++++++++++++++-- src/scene/profilefile.cpp | 14 +- tests/profile/test_profile.cpp | 4 +- 13 files changed, 320 insertions(+), 46 deletions(-) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index b150d594d1..3e9a86eb80 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___OPENSPACEENGINE___H__ #include +#include #include #include #include @@ -76,6 +77,8 @@ public: const glm::mat4& projectionMatrix); void drawOverlays(); void postDraw(); + std::vector listOfAllAssetEvents(); + void resetAssetChangeTracking(); void resetPropertyChangeFlags(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); void charCallback(unsigned int codepoint, KeyModifier modifier); diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 0cfbbc9be0..779ef9fe42 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -495,6 +495,13 @@ public: */ virtual std::string generateAdditionalJsonDescription() const; + /** + * Returns whether or not the property value has changed. + * + * \return true if the property has changed + */ + bool hasChanged(); + /** * Reset the valChanged flag to an unchanged state, as if value has not been changed. */ diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index 374448644f..25ec440b4f 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___ASSETLOADER___H__ #include +#include #include #include #include @@ -169,10 +170,22 @@ public: */ void assetUnrequested(std::shared_ptr parent, std::shared_ptr child); + /** + * Retrieve a reference to vector list of all assets events, including require, + * request, and remove + */ + const std::vector& listOfAllAssetEvents() const; + + /** + * Clear lists of all assets that have been either requested, required, or removed + */ + void listOfAllAssetEvents_reset(); + private: std::shared_ptr require(const std::string& identifier); std::shared_ptr request(const std::string& identifier); void unrequest(const std::string& identifier); + void addToProfileTracking(std::string asset, Profile::AssetEventType type); void setUpAssetLuaTable(Asset* asset); void tearDownAssetLuaTable(Asset* asset); @@ -227,6 +240,7 @@ private: _onDependencyDeinitializationFunctionRefs; int _assetsTableRef; + std::vector _profileAssets; std::vector _profileAssetsRequired; std::vector _profileAssetsRequested; std::vector _profileAssetsRemoved; diff --git a/include/openspace/scene/assetmanager.h b/include/openspace/scene/assetmanager.h index d279219463..db010c7d02 100644 --- a/include/openspace/scene/assetmanager.h +++ b/include/openspace/scene/assetmanager.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___ASSETMANAGER___H__ #include +#include #include #include @@ -70,6 +71,8 @@ public: std::shared_ptr child) override; bool update(); + const std::vector& listOfAllAssetEvents() const; + void listOfAllAssetEvents_reset(); scripting::LuaLibrary luaLibrary(); private: diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 9bfabfde04..6ef18bf6c5 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -44,9 +44,23 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } - class Profile { public: + enum class AssetEventType { + require, + request, + remove + }; + const std::map AssetEventTypeString { + {AssetEventType::require, "required"}, + {AssetEventType::request, "requested"}, + {AssetEventType::remove, "removed"}, + }; + struct AssetEvent { + std::string name; + AssetEventType eventType; + }; + /** * Saves all current settings, starting from the profile that was loaded at startup, * and all of the property & asset changes that were made since startup. @@ -61,7 +75,7 @@ public: * \param outFilePath The output file path that will be written with the converted * contents (in an .asset file) */ - void convertToAssetFile(const std::string inProfilePath, + void convertToSceneFile(const std::string inProfilePath, const std::string outFilePath); /** @@ -70,7 +84,7 @@ public: * \param pf The profileFile object to be converted * \return The full string contents of scene/asset equivalent of the profile file. */ - std::string convertToAsset(ProfileFile& pf); + std::string convertToScene(ProfileFile& pf); /** * Returns the Lua library that contains all Lua functions available to provide @@ -80,14 +94,30 @@ public: static scripting::LuaLibrary luaLibrary(); private: - std::string convertToAsset_assets(ProfileFile& pf); - std::string convertToAsset_modules(ProfileFile& pf); - std::string convertToAsset_properties(ProfileFile& pf); - std::string convertToAsset_markNodes(ProfileFile& pf); - std::string convertToAsset_keybindings(ProfileFile& pf); - std::string convertToAsset_time(ProfileFile& pf); - std::string convertToAsset_camera(ProfileFile& pf); + struct AllAssetDetails { + std::vector base; + std::vector changed; + }; + std::string convertToScene_assets(ProfileFile& pf); + std::string convertToScene_modules(ProfileFile& pf); + std::string convertToScene_properties(ProfileFile& pf); + std::string convertToScene_markNodes(ProfileFile& pf); + std::string convertToScene_keybindings(ProfileFile& pf); + std::string convertToScene_time(ProfileFile& pf); + std::string convertToScene_camera(ProfileFile& pf); + + std::vector modifyAssetsToReflectChanges(ProfileFile& pf); + void parseAssetFileLines(std::vector& results, ProfileFile& pf); + void handleChangedRequire(std::vector& base, std::string asset); + void handleChangedRequest(std::vector& base, std::string asset); + void handleChangedRemove(std::vector& base, std::string asset); + void addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf); + void modifyPropertiesToReflectChanges(ProfileFile& pf); + std::vector getNodesThatHaveChangedProperties( + ProfileFile& pf); + void addCurrentTimeToProfileFile(ProfileFile& pf); + void addCurrentCameraToProfileFile(ProfileFile& pf); }; } // namespace openspace diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 82cfa0facd..3b01d97e54 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -92,6 +92,8 @@ const std::string header_MarkNodes = "#MarkNodes"; class ProfileFile { public: + using Lines = std::vector; + /** * Reads the contents of a profile file and populates vector containers for all * sections. This only pulls individual line entries into their proper sections; @@ -157,6 +159,11 @@ public: */ void addAssetLine(const std::string line); + /** + * Clears all asset entries + */ + void clearAssets(); + /** * Adds a new property set command to the list of property settings to be * performed at startup. The format for a property set command line is defined by @@ -213,28 +220,28 @@ public: * comment header for notes on the syntax of each entry. * \return The vector of asset lines */ - std::vector assets() const; + Lines assets() const; /** * Returns the vector of OpenSpace property set commands included in this profile. * See addPropertyLine comment header for notes on the syntax of each entry. * \return The vector of property set commands */ - std::vector properties() const; + Lines properties() const; /** * Returns the vector of OpenSpace keybinding shortcut definitions included in this * profile. See addKeybindingLine comment header for syntax notes of each entry. * \return The vector of keybinding shortcut definitions */ - std::vector keybindings() const; + Lines keybindings() const; /** * Returns the vector of OpenSpace scenegraph nodes marked as 'interesting'. * See addMarkNodesLine comment header for syntax notes of each entry. * \return The vector of nodes to be marked as interesting. */ - std::vector markNodes() const; + Lines markNodes() const; /** * Splits a tab-delimited line (of any type) into a vector with individual string @@ -245,6 +252,8 @@ public: */ size_t splitByTab(std::string line, std::vector& result); + + private: std::string errorString(std::string message); void clearAllFields(); @@ -272,11 +281,11 @@ private: std::string _version; std::string _time; std::string _camera; - std::vector _modules; - std::vector _assets; - std::vector _properties; - std::vector _keybindings; - std::vector _markNodes; + Lines _modules; + Lines _assets; + Lines _properties; + Lines _keybindings; + Lines _markNodes; }; } // namespace openspace diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 5f04e66c2a..f825c45370 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -306,7 +306,7 @@ void OpenSpaceEngine::initialize() { std::string outputAsset = outputScenePath + "/" + global::configuration.profile + ".asset"; - global::profile.convertToAssetFile(inputProfile, outputAsset); + global::profile.convertToSceneFile(inputProfile, outputAsset); // Set asset name to that of the profile because a new scene file will be // created with that name, and also because the profile name will override @@ -1276,12 +1276,21 @@ void OpenSpaceEngine::postDraw() { if (_isFirstRenderingFirstFrame) { global::windowDelegate.setSynchronization(true); resetPropertyChangeFlags(); + resetAssetChangeTracking(); _isFirstRenderingFirstFrame = false; } LTRACE("OpenSpaceEngine::postDraw(end)"); } +void OpenSpaceEngine::resetAssetChangeTracking() { + global::openSpaceEngine._assetManager->listOfAllAssetEvents_reset(); +} + +std::vector OpenSpaceEngine::listOfAllAssetEvents() { + return global::openSpaceEngine._assetManager->listOfAllAssetEvents(); +} + void OpenSpaceEngine::resetPropertyChangeFlags() { ZoneScoped diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 5a00032616..1bedc86ac7 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -312,6 +312,10 @@ void Property::notifyDeleteListeners() { } } +bool Property::hasChanged() { + return valChanged; +} + void Property::resetToUnchanged() { valChanged = false; } diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 9439ea805a..9981ee4f05 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -444,7 +444,7 @@ std::shared_ptr AssetLoader::require(const std::string& identifier) { std::shared_ptr asset = getAsset(identifier); std::shared_ptr dependant = _currentAsset; dependant->require(asset); - _profileAssetsRequired.push_back(asset->assetFilePath()); + addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::require); return asset; } @@ -453,10 +453,15 @@ std::shared_ptr AssetLoader::request(const std::string& identifier) { std::shared_ptr parent = _currentAsset; parent->request(asset); assetRequested(parent, asset); - _profileAssetsRequested.push_back(asset->assetFilePath()); + addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::request); return asset; } +void AssetLoader::addToProfileTracking(std::string asset, Profile::AssetEventType type) { + Profile::AssetEvent pa = {asset, type}; + _profileAssets.push_back(pa); +} + void AssetLoader::unrequest(const std::string& identifier) { std::shared_ptr asset = has(identifier); std::shared_ptr parent = _currentAsset; @@ -484,6 +489,7 @@ void AssetLoader::remove(const std::string& identifier) { setCurrentAsset(_rootAsset); unrequest(identifier); _profileAssetsRemoved.push_back(identifier); + addToProfileTracking(identifier, Profile::AssetEventType::remove); } std::shared_ptr AssetLoader::has(const std::string& identifier) const { @@ -810,4 +816,12 @@ void AssetLoader::assetUnrequested(std::shared_ptr parent, } } +const std::vector& AssetLoader::listOfAllAssetEvents() const { + return _profileAssets; +} + +void AssetLoader::listOfAllAssetEvents_reset() { + _profileAssets.clear(); +} + } // namespace openspace diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index e64409fadd..d9d8e5e12e 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -121,6 +121,14 @@ std::shared_ptr AssetManager::rootAsset() { return _assetLoader->rootAsset(); } +const std::vector& AssetManager::listOfAllAssetEvents() const { + return _assetLoader->listOfAllAssetEvents(); +} + +void AssetManager::listOfAllAssetEvents_reset() { + _assetLoader->listOfAllAssetEvents_reset(); +} + scripting::LuaLibrary AssetManager::luaLibrary() { return { "asset", diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 57bb85fd89..e42934b4e5 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -27,20 +27,26 @@ #include #include #include +#include #include +#include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include #include #include #include +#include #include "profile_lua.inl" @@ -59,9 +65,172 @@ void Profile::saveCurrentSettingsToProfile(std::string filename) { LERROR(errorMessage); } std::string initProfile = global::configuration.profile; + ProfileFile pf; + pf.readFromFile(initProfile); + std::vector ass = modifyAssetsToReflectChanges(pf); + addAssetsToProfileFile(ass, pf); + modifyPropertiesToReflectChanges(pf); + addCurrentTimeToProfileFile(pf); + addCurrentCameraToProfileFile(pf); } -void Profile::convertToAssetFile(const std::string inProfilePath, +std::vector Profile::modifyAssetsToReflectChanges(ProfileFile& pf) { + std::vector a; + parseAssetFileLines(a, pf); + AllAssetDetails assetDetails; + + assetDetails.base = a; + assetDetails.changed = global::openSpaceEngine.listOfAllAssetEvents(); + + for (AssetEvent event : assetDetails.changed) { + if (event.eventType == AssetEventType::require) { + handleChangedRequire(assetDetails.base, event.name); + } + else if (event.eventType == AssetEventType::request) { + handleChangedRequest(assetDetails.base, event.name); + } + else if (event.eventType == AssetEventType::remove) { + handleChangedRemove(assetDetails.base, event.name); + } + } + return assetDetails.base; +} + +void Profile::handleChangedRequire(std::vector& base, std::string asset) { + for (auto b : base) { + if (b.name == asset && b.eventType == AssetEventType::request) { + base.push_back({asset, AssetEventType::require}); + } + } +} + +void Profile::handleChangedRequest(std::vector& base, std::string asset) { + bool addThisAsset = true; + std::vector::iterator f; + f = find_if(base.begin(), base.end(), [asset](AssetEvent ae) + { return (ae.name == asset); } ); + if (f != base.end()) { + addThisAsset = false; + } + + if (addThisAsset) { + AssetEvent ae = {asset, AssetEventType::request}; + base.push_back(ae); + } +} + +void Profile::handleChangedRemove(std::vector& base, std::string asset) { + std::vector::iterator f; + f = remove_if(base.begin(), base.end(), [asset](AssetEvent ae) + { return (ae.name == asset); } ); +} + +void Profile::addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf) +{ + pf.clearAssets(); + for (AssetEvent a : allAssets) { + std::string entry = a.name + "\t" + AssetEventTypeString.at(a.eventType); + pf.addAssetLine(entry); + } +} + +void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf) { + std::vector elements; + AssetEvent a; + + for (std::string line : pf.assets()) { + pf.splitByTab(line, elements); + + if (a.name.empty()) { + LERROR("Error in parsing asset file line '" + line + + "'. Asset name is needed (field 1/2)."); + } + else { + a.name = elements[0]; + } + + if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { + a.eventType = AssetEventType::require; + } + else if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { + a.eventType = AssetEventType::request; + } + else if (elements[1] == "") { + a.eventType = AssetEventType::request; + } + else { + LERROR("Error in parsing asset file line '" + line + + "'. Invalid required param (field 2/2)."); + } + + results.push_back(a); + } +} + +void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { + std::vector changedProps + = getNodesThatHaveChangedProperties(pf); + std::string newLine; + + for (auto prop : changedProps) { + newLine = "setPropertyValueSingle\t"; + newLine += prop->identifier() + "\t"; + newLine += prop->getStringValue() + "\n"; + pf.addPropertyLine(newLine); + } +} + +std::vector Profile::getNodesThatHaveChangedProperties( + ProfileFile& pf) +{ + ZoneScoped + + std::vector nodes = + global::renderEngine.scene()->allSceneGraphNodes(); + std::vector changedProps; + + for (auto n : nodes) { + std::vector props = n->properties(); + for (auto p : props) { + if (p->hasChanged()) { + changedProps.push_back(p); + } + } + } + return changedProps; +} + +void Profile::addCurrentTimeToProfileFile(ProfileFile& pf) { + std::string t = global::timeManager.time().UTC(); + std::string update = "absolute\t" + t + "\n"; + pf.updateTime(update); +} + +void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { + std::string update = "setNavigationState\t"; + interaction::NavigationHandler::NavigationState nav; + nav = global::navigationHandler.navigationState(); + update += nav.anchor + "\t"; + update += nav.aim + "\t"; + update += nav.referenceFrame + "\t"; + update += std::to_string(nav.position.x) + ","; + update += std::to_string(nav.position.y) + ","; + update += std::to_string(nav.position.z) + "\t"; + if (nav.up.has_value()) { + glm::dvec3 u = nav.up.value(); + //glm::dvec3 u = static_cast(nav.up.value()); + update += std::to_string(u.x) + ","; + update += std::to_string(u.y) + ","; + update += std::to_string(u.z); + } + update += "\t"; + update += std::to_string(nav.yaw) + "\t"; + update += std::to_string(nav.pitch) + "\n"; + + pf.updateCamera(update); +} + +void Profile::convertToSceneFile(const std::string inProfilePath, const std::string outFilePath) { ProfileFile pf; @@ -77,7 +246,7 @@ void Profile::convertToAssetFile(const std::string inProfilePath, } try { - outFile << convertToAsset(pf); + outFile << convertToScene(pf); } catch (std::ofstream::failure& e) { LERROR("Data write error to file: " + outFilePath); @@ -91,24 +260,24 @@ void Profile::convertToAssetFile(const std::string inProfilePath, } } -std::string Profile::convertToAsset(ProfileFile& pf) { +std::string Profile::convertToScene(ProfileFile& pf) { std::string result; - result += convertToAsset_modules(pf) + "\n"; - result += convertToAsset_assets(pf) + "\n"; - result += convertToAsset_keybindings(pf) + "\n"; + result += convertToScene_modules(pf) + "\n"; + result += convertToScene_assets(pf) + "\n"; + result += convertToScene_keybindings(pf) + "\n"; result += "asset.onInitialize(function ()\n"; - result += convertToAsset_time(pf) + "\n"; + result += convertToScene_time(pf) + "\n"; result += " sceneHelper.bindKeys(Keybindings)\n\n"; - result += convertToAsset_markNodes(pf) + "\n"; - result += convertToAsset_properties(pf) + "\n"; - result += convertToAsset_camera(pf); + result += convertToScene_markNodes(pf) + "\n"; + result += convertToScene_properties(pf) + "\n"; + result += convertToScene_camera(pf); result += "end)\n"; return result; } -std::string Profile::convertToAsset_modules(ProfileFile& pf) { +std::string Profile::convertToScene_modules(ProfileFile& pf) { std::string result; std::vector fields; @@ -131,7 +300,7 @@ std::string Profile::convertToAsset_modules(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_assets(ProfileFile& pf) { +std::string Profile::convertToScene_assets(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; @@ -166,7 +335,7 @@ std::string Profile::convertToAsset_assets(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_properties(ProfileFile& pf) { +std::string Profile::convertToScene_properties(ProfileFile& pf) { std::string result; std::vector fields; @@ -190,7 +359,7 @@ std::string Profile::convertToAsset_properties(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_keybindings(ProfileFile& pf) { +std::string Profile::convertToScene_keybindings(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; @@ -213,7 +382,7 @@ std::string Profile::convertToAsset_keybindings(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_markNodes(ProfileFile& pf) { +std::string Profile::convertToScene_markNodes(ProfileFile& pf) { std::string result; if (pf.markNodes().size() > 0) { @@ -226,7 +395,7 @@ std::string Profile::convertToAsset_markNodes(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_time(ProfileFile& pf) { +std::string Profile::convertToScene_time(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; @@ -248,7 +417,7 @@ std::string Profile::convertToAsset_time(ProfileFile& pf) { return result; } -std::string Profile::convertToAsset_camera(ProfileFile& pf) { +std::string Profile::convertToScene_camera(ProfileFile& pf) { std::string result; std::vector fields; std::string assetR; diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index b2c4251cb4..345a258f9c 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -241,23 +241,23 @@ std::string ProfileFile::camera() const { return _camera; } -std::vector ProfileFile::modules() const { +ProfileFile::Lines ProfileFile::modules() const { return _modules; } -std::vector ProfileFile::assets() const { +ProfileFile::Lines ProfileFile::assets() const { return _assets; } -std::vector ProfileFile::properties() const { +ProfileFile::Lines ProfileFile::properties() const { return _properties; } -std::vector ProfileFile::keybindings() const { +ProfileFile::Lines ProfileFile::keybindings() const { return _keybindings; } -std::vector ProfileFile::markNodes() const { +ProfileFile::Lines ProfileFile::markNodes() const { return _markNodes; } @@ -472,4 +472,8 @@ void ProfileFile::addMarkNodesLine(const std::string line) { _markNodes.push_back(line); } +void ProfileFile::clearAssets() { + _assets.clear(); +} + } // namespace openspace diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 62389a275b..12fdc5a94c 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -48,7 +48,7 @@ TEST_CASE("profile: Convert profileFile to asset", "[profile]") { Profile p; REQUIRE_NOTHROW( - p.convertToAsset(pf) + p.convertToScene(pf) ); } @@ -58,7 +58,7 @@ TEST_CASE("profile: Verify conversion to scene", "[profile]") { Profile p; std::string result; REQUIRE_NOTHROW( - result = p.convertToAsset(pf) + result = p.convertToScene(pf) ); std::string testing, comparing; From 02fb61d95df3926494d45468297d44e4afb96533 Mon Sep 17 00:00:00 2001 From: GPayne Date: Tue, 5 May 2020 20:57:54 -0600 Subject: [PATCH 08/61] Continued unit testing work --- include/openspace/scene/profile.h | 31 ++++- include/openspace/scene/profilefile.h | 26 ++++- src/scene/assetloader.cpp | 4 +- src/scene/profile.cpp | 156 ++++++++++++++++++-------- src/scene/profilefile.cpp | 16 ++- tests/profile/default.profile | 21 ++++ tests/profile/initialization.asset | 3 + tests/profile/test1.asset | 1 + tests/profile/test2.profile | 21 ++++ tests/profile/test_common.cpp | 3 +- tests/profile/test_profile.cpp | 107 +++++++++++++++++- tests/profile/test_profilefile.cpp | 30 +++-- 12 files changed, 334 insertions(+), 85 deletions(-) create mode 100644 tests/profile/default.profile create mode 100644 tests/profile/initialization.asset create mode 100644 tests/profile/test1.asset create mode 100644 tests/profile/test2.profile diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 6ef18bf6c5..4ecb5194d6 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -27,6 +27,7 @@ #include +#include #include #include #include @@ -47,20 +48,26 @@ namespace scripting { struct LuaLibrary; } class Profile { public: enum class AssetEventType { + add, require, request, - remove + remove, + ignore }; const std::map AssetEventTypeString { + {AssetEventType::add, "add"}, {AssetEventType::require, "required"}, {AssetEventType::request, "requested"}, {AssetEventType::remove, "removed"}, + {AssetEventType::ignore, "ignored"}, }; struct AssetEvent { std::string name; AssetEventType eventType; }; + virtual ~Profile() {}; + /** * Saves all current settings, starting from the profile that was loaded at startup, * and all of the property & asset changes that were made since startup. @@ -68,6 +75,12 @@ public: */ void saveCurrentSettingsToProfile(std::string filename); + /** + * Saves all current settings, similar to saveCurrentSettingsToProfile() except the + * output is a string without writing to a file. + */ + std::string saveCurrentSettingsToProfile_string(); + /** * Reads in a .profile file, converts it to scene/asset equivalent syntax, and * writes the result to the specified output path. @@ -99,6 +112,9 @@ private: std::vector changed; }; + virtual bool usingProfile(); + virtual std::string initialProfile(); + ProfileFile collateBaseWithChanges(); std::string convertToScene_assets(ProfileFile& pf); std::string convertToScene_modules(ProfileFile& pf); std::string convertToScene_properties(ProfileFile& pf); @@ -109,13 +125,16 @@ private: std::vector modifyAssetsToReflectChanges(ProfileFile& pf); void parseAssetFileLines(std::vector& results, ProfileFile& pf); - void handleChangedRequire(std::vector& base, std::string asset); - void handleChangedRequest(std::vector& base, std::string asset); - void handleChangedRemove(std::vector& base, std::string asset); + void handleChangedAdd(std::vector& base, unsigned int changedIdx, + std::vector& changed, std::string asset); + void handleChangedRemove(std::vector& base, unsigned int changedIdx, + std::vector& changed, std::string asset); void addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf); void modifyPropertiesToReflectChanges(ProfileFile& pf); - std::vector getNodesThatHaveChangedProperties( - ProfileFile& pf); + virtual std::vector getChangedProperties(); + virtual std::vector getChangedPropertiesFormatted(); + virtual std::string getCurrentTimeUTC(); + virtual interaction::NavigationHandler::NavigationState getCurrentCameraState(); void addCurrentTimeToProfileFile(ProfileFile& pf); void addCurrentCameraToProfileFile(ProfileFile& pf); }; diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 3b01d97e54..d1665f8cc9 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -94,25 +94,47 @@ class ProfileFile { public: using Lines = std::vector; + /** + * Constructs object by reading the contents of a profile file and populates vector + * containers for all sections. This only pulls individual line entries into their + * proper sections; it does not parse the tab-delimited fields of each line. + * \param filename The profile file to read + */ + ProfileFile(std::string filename); + + /** + * Constructor with alternative method of populating the object by reading the lines + * from a profile file. This is mainly intended for testing purposes, but it can be + * used to provide the profile file contents from another source (the function + * readFromFile() provides its own ifstream source). + * \param reader A std::function object that accepts a string reference which will + * be populated with a single line of content. This function returns + * true if a single line was read successfully, or false if not to + * indicate that the end of the content has been reached. + */ + ProfileFile(std::function reader); + /** * Reads the contents of a profile file and populates vector containers for all * sections. This only pulls individual line entries into their proper sections; * it does not parse the tab-delimited fields of each line. + * This will reset contents of the object. * \param filename The profile file to read */ - void readFromFile(std::string filename); + void readIn(std::string filename); /** * Alternative function for reading the lines from a profile file. This is mainly * intended for testing purposes, but it can be used to provide the profile file * contents from another source (the function readFromFile() provides its own * ifstream source). + * This will reset contents of the object. * \param reader A std::function object that accepts a string reference which will * be populated with a single line of content. This function returns * true if a single line was read successfully, or false if not to * indicate that the end of the content has been reached. */ - void readLines(std::function reader); + void readIn(std::function reader); /** * Returns the string contents of this object converted to scene/asset diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 9981ee4f05..d1d5f10c40 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -444,7 +444,6 @@ std::shared_ptr AssetLoader::require(const std::string& identifier) { std::shared_ptr asset = getAsset(identifier); std::shared_ptr dependant = _currentAsset; dependant->require(asset); - addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::require); return asset; } @@ -453,7 +452,6 @@ std::shared_ptr AssetLoader::request(const std::string& identifier) { std::shared_ptr parent = _currentAsset; parent->request(asset); assetRequested(parent, asset); - addToProfileTracking(asset->assetFilePath(), Profile::AssetEventType::request); return asset; } @@ -480,7 +478,7 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const { std::shared_ptr AssetLoader::add(const std::string& identifier) { setCurrentAsset(_rootAsset); - + addToProfileTracking(identifier, Profile::AssetEventType::add); return request(identifier); } diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index e42934b4e5..5da2069ec9 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -59,19 +59,37 @@ namespace { namespace openspace { void Profile::saveCurrentSettingsToProfile(std::string filename) { - if (! global::configuration.usingProfile) { + ProfileFile pf = collateBaseWithChanges(); + pf.writeToFile(filename); +} + +std::string Profile::saveCurrentSettingsToProfile_string() { + ProfileFile pf = collateBaseWithChanges(); + return pf.writeToString(); +} + +bool Profile::usingProfile() { + return global::configuration.usingProfile; +} + +std::string Profile::initialProfile() { + return global::configuration.profile; +} + +ProfileFile Profile::collateBaseWithChanges() { + if (! usingProfile()) { std::string errorMessage = "Program was not started using a profile, " "so cannot use this save-current-settings feature."; LERROR(errorMessage); } - std::string initProfile = global::configuration.profile; - ProfileFile pf; - pf.readFromFile(initProfile); + std::string initProfile = initialProfile(); + ProfileFile pf(initProfile); std::vector ass = modifyAssetsToReflectChanges(pf); addAssetsToProfileFile(ass, pf); modifyPropertiesToReflectChanges(pf); addCurrentTimeToProfileFile(pf); addCurrentCameraToProfileFile(pf); + return pf; } std::vector Profile::modifyAssetsToReflectChanges(ProfileFile& pf) { @@ -82,35 +100,41 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi assetDetails.base = a; assetDetails.changed = global::openSpaceEngine.listOfAllAssetEvents(); - for (AssetEvent event : assetDetails.changed) { - if (event.eventType == AssetEventType::require) { - handleChangedRequire(assetDetails.base, event.name); - } - else if (event.eventType == AssetEventType::request) { - handleChangedRequest(assetDetails.base, event.name); + for (unsigned int i = 0; i < assetDetails.changed.size(); i++) { + AssetEvent event = assetDetails.changed[i]; + + if (event.eventType == AssetEventType::add) { + handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); } else if (event.eventType == AssetEventType::remove) { - handleChangedRemove(assetDetails.base, event.name); + handleChangedRemove(assetDetails.base, i, assetDetails.changed, event.name); } } return assetDetails.base; } -void Profile::handleChangedRequire(std::vector& base, std::string asset) { +void Profile::handleChangedAdd(std::vector& base, unsigned int changedIdx, + std::vector& changed, std::string asset) +{ + bool addThisAsset = true; + //Check base profile to see if has already been added there for (auto b : base) { - if (b.name == asset && b.eventType == AssetEventType::request) { - base.push_back({asset, AssetEventType::require}); + if (b.name == asset ) { + if ( b.eventType == AssetEventType::require + || b.eventType == AssetEventType::request) + { + addThisAsset = false; + break; + } } } -} -void Profile::handleChangedRequest(std::vector& base, std::string asset) { - bool addThisAsset = true; - std::vector::iterator f; - f = find_if(base.begin(), base.end(), [asset](AssetEvent ae) - { return (ae.name == asset); } ); - if (f != base.end()) { - addThisAsset = false; + //Check changed asset commands only prior to this one to see if already added + for (unsigned int i = 0; i < changedIdx; i++) { + if (changed[i].name == asset) { + addThisAsset = false; + break; + } } if (addThisAsset) { @@ -119,10 +143,24 @@ void Profile::handleChangedRequest(std::vector& base, std::string as } } -void Profile::handleChangedRemove(std::vector& base, std::string asset) { - std::vector::iterator f; - f = remove_if(base.begin(), base.end(), [asset](AssetEvent ae) - { return (ae.name == asset); } ); +void Profile::handleChangedRemove(std::vector& base, unsigned int changedIdx, + std::vector& changed, std::string asset) +{ + //Blank-out any base profile entries where this asset was required/requested + for (unsigned int i = 0; i < base.size(); i++) { + if (base[i].name == asset) { + base[i].name = ""; + base[i].eventType = AssetEventType::ignore; + } + } + + //Blank-out any changes profile entries where this asset was required/requested + for (unsigned int i = 0; i < changedIdx; i++) { + if (changed[i].name == asset) { + changed[i].name = ""; + changed[i].eventType = AssetEventType::ignore; + } + } } void Profile::addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf) @@ -152,7 +190,7 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileFile& if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { a.eventType = AssetEventType::require; } - else if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { + else if (elements[1] == AssetEventTypeString.at(AssetEventType::request)) { a.eventType = AssetEventType::request; } else if (elements[1] == "") { @@ -168,48 +206,66 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileFile& } void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { - std::vector changedProps - = getNodesThatHaveChangedProperties(pf); - std::string newLine; + std::vector formatted = getChangedPropertiesFormatted(); - for (auto prop : changedProps) { - newLine = "setPropertyValueSingle\t"; - newLine += prop->identifier() + "\t"; - newLine += prop->getStringValue() + "\n"; - pf.addPropertyLine(newLine); + for (std::string line: formatted) { + pf.addPropertyLine(line); } } -std::vector Profile::getNodesThatHaveChangedProperties( - ProfileFile& pf) +std::vector Profile::getChangedPropertiesFormatted() { + std::vector changedProps + = getChangedProperties(); + std::vector formattedLines; + + for (auto prop : changedProps) { + std::string newLine = "setPropertyValueSingle\t"; + newLine += prop->identifier() + "\t"; + newLine += prop->getStringValue() + "\n"; + formattedLines.push_back(newLine); + } + return formattedLines; +} + +std::vector Profile::getChangedProperties() { ZoneScoped - std::vector nodes = - global::renderEngine.scene()->allSceneGraphNodes(); + std::vector nodes + = global::renderEngine.scene()->allSceneGraphNodes(); std::vector changedProps; for (auto n : nodes) { - std::vector props = n->properties(); - for (auto p : props) { - if (p->hasChanged()) { - changedProps.push_back(p); - } - } + if (n != nullptr) { + std::vector props = n->properties(); + for (auto p : props) { + if (p->hasChanged()) { + changedProps.push_back(p); + } + } + } } return changedProps; } +std::string Profile::getCurrentTimeUTC() { + return global::timeManager.time().UTC(); +} + void Profile::addCurrentTimeToProfileFile(ProfileFile& pf) { - std::string t = global::timeManager.time().UTC(); + std::string t = getCurrentTimeUTC(); std::string update = "absolute\t" + t + "\n"; pf.updateTime(update); } +interaction::NavigationHandler::NavigationState Profile::getCurrentCameraState() { + return global::navigationHandler.navigationState(); +} + void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { std::string update = "setNavigationState\t"; interaction::NavigationHandler::NavigationState nav; - nav = global::navigationHandler.navigationState(); + nav = getCurrentCameraState(); update += nav.anchor + "\t"; update += nav.aim + "\t"; update += nav.referenceFrame + "\t"; @@ -233,9 +289,9 @@ void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { void Profile::convertToSceneFile(const std::string inProfilePath, const std::string outFilePath) { - ProfileFile pf; + ZoneScoped - pf.readFromFile(inProfilePath); + ProfileFile pf(inProfilePath); std::ofstream outFile; try { @@ -261,6 +317,8 @@ void Profile::convertToSceneFile(const std::string inProfilePath, } std::string Profile::convertToScene(ProfileFile& pf) { + ZoneScoped + std::string result; result += convertToScene_modules(pf) + "\n"; diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 345a258f9c..5a4dbd9b28 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -43,7 +43,15 @@ namespace { namespace openspace { -void ProfileFile::readFromFile(std::string filename) { +ProfileFile::ProfileFile(std::string filename) { + readIn(filename); +} + +ProfileFile::ProfileFile(std::function reader) { + readIn(reader); +} + +void ProfileFile::readIn(std::string filename) { clearAllFields(); std::ifstream inFile; @@ -56,7 +64,7 @@ void ProfileFile::readFromFile(std::string filename) { } try { - readLines([&inFile] (std::string& line) { + readIn([&inFile] (std::string& line) { if (getline(inFile, line)) return true; else @@ -77,7 +85,8 @@ void ProfileFile::readFromFile(std::string filename) { } } -void ProfileFile::readLines(std::function reader) { +void ProfileFile::readIn(std::function reader) { + clearAllFields(); std::string line; bool insideSection = false; _lineNum = 1; @@ -295,7 +304,6 @@ void ProfileFile::parseModule(std::string line) { void ProfileFile::parseAsset(std::string line) { std::vector fields; - if (splitByTab(line, fields) != assetFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(assetFieldsExpected) + " fields required in an Asset entry"), "profileFile"); diff --git a/tests/profile/default.profile b/tests/profile/default.profile new file mode 100644 index 0000000000..b5614baf84 --- /dev/null +++ b/tests/profile/default.profile @@ -0,0 +1,21 @@ +#Version +1.0 + +#Asset +scene/solarsystem/planets/earth/earth required +scene/solarsystem/planets/earth/satellites/satellites required + +#Property +setPropertyValue {earth_satellites}.Renderable.Enabled false + +#Time +relative -1d + +#Camera +goToGeo "Earth" 58.5877 16.1924 20000000 + +#MarkNodes +Earth +Mars +Moon +Sun diff --git a/tests/profile/initialization.asset b/tests/profile/initialization.asset new file mode 100644 index 0000000000..186dee561b --- /dev/null +++ b/tests/profile/initialization.asset @@ -0,0 +1,3 @@ +asset.onInitialize(function () + passTest() +end) \ No newline at end of file diff --git a/tests/profile/test1.asset b/tests/profile/test1.asset new file mode 100644 index 0000000000..3acea7c194 --- /dev/null +++ b/tests/profile/test1.asset @@ -0,0 +1 @@ +assert (true) \ No newline at end of file diff --git a/tests/profile/test2.profile b/tests/profile/test2.profile new file mode 100644 index 0000000000..9365bfc57b --- /dev/null +++ b/tests/profile/test2.profile @@ -0,0 +1,21 @@ +#Version +1.0 + +#Asset +scene/solarsystem/planets/earth/earth required +scene/solarsystem/planets/earth/satellites/satellites required + +#Property +setPropertyValue {earth_satellites}.Renderable.Enabled false + +#Time +relative -1d + +#Camera +goToGeo "Earth" 58.5877 16.1924 20000000 + +#MarkNodes +Earth +Mars +Moon +Sun diff --git a/tests/profile/test_common.cpp b/tests/profile/test_common.cpp index dd8009c6a4..23225903cb 100644 --- a/tests/profile/test_common.cpp +++ b/tests/profile/test_common.cpp @@ -102,8 +102,7 @@ std::string stringFromTestProfileFormat(testProfileFormat& tpf) { ProfileFile makeProfileFromString(std::string s) { std::istringstream iss(s); - ProfileFile pf; - pf.readLines([&iss](std::string& line) { + ProfileFile pf([&iss](std::string& line) { if (getline(iss, line)) return true; else diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 12fdc5a94c..1f8e0567db 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -24,27 +24,93 @@ #include "catch2/catch.hpp" #include "test_common.h" +#include +#include +#include +#include #include "openspace/scene/profile.h" +#include +#include +#include +#include #include #include +#include + #include #include +#include using namespace openspace; namespace { -} + int passTest(lua_State* state) { + bool* test = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); + *test = true; + return 0; + } +} // namespace + +class Profile2 : public Profile { +public: + std::string getCurrentTimeUTC() { + return "2020-02-29T01:23:45.00"; + } + interaction::NavigationHandler::NavigationState getCurrentCameraState() { + interaction::NavigationHandler::NavigationState n; + n.anchor = "Earth"; + n.aim = "Sun"; + n.referenceFrame = "root"; + n.position = {-1.0, -2.0, -3.0}; + n.up = {0.0, 0.0, 1.0}; + n.pitch = 0.0; + n.yaw = 0.0; + return n; + } + void addPropertiesMarkedAsChanged(std::string formattedLine) { + _scenegraphProps.push_back(formattedLine); + } + std::vector getChangedPropertiesFormatted() { + std::vector formattedLines; + for (std::string s : _scenegraphProps) { + formattedLines.push_back(s); + } + return formattedLines; + } + bool usingProfile() { + return true; + } + std::string initialProfile() { + return _initProfile; + } + void setInitialProfile(std::string file) { + _initProfile = file; + } +private: + std::vector _scenegraphProps; + std::string _initProfile; +}; static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { s = "@line " + std::to_string(lineNumber) + ": '" + s + "'"; } + + TEST_CASE("profile: Convert profileFile to asset", "[profile]") { testProfileFormat test = buildTestProfile1(); std::string testFull_string = stringFromTestProfileFormat(test); - ProfileFile pf = makeProfileFromString(testFull_string); + std::istringstream iss(testFull_string); + ProfileFile pf("default.profile"); + pf.readIn([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ); Profile p; REQUIRE_NOTHROW( @@ -53,7 +119,15 @@ TEST_CASE("profile: Convert profileFile to asset", "[profile]") { } TEST_CASE("profile: Verify conversion to scene", "[profile]") { - ProfileFile pf = makeProfileFromString(newHorizonsProfileInput); + std::istringstream iss(newHorizonsProfileInput); + ProfileFile pf("default.profile"); + pf.readIn([&iss](std::string& line) { + if (getline(iss, line)) + return true; + else + return false; + } + ); Profile p; std::string result; @@ -77,3 +151,30 @@ TEST_CASE("profile: Verify conversion to scene", "[profile]") { REQUIRE(sr_standard.getNextLine(comparing) == false); } +TEST_CASE("profile: Detect new required asset", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + std::shared_ptr asset = assetLoader.add("initialization"); + asset->initialize(); + assetLoader.add("test1"); + + Profile2 p; + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.addPropertiesMarkedAsChanged("initialized 1st\t123"); + p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); + p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); + std::string output = p.saveCurrentSettingsToProfile_string(); + std::cout << output << std::endl; +} diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index ad1db7997d..0d237b2ecc 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -41,8 +41,7 @@ TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { std::string testFull_string = stringFromTestProfileFormat(test); std::istringstream iss(testFull_string); - ProfileFile pf; - pf.readLines([&iss](std::string& line) { + ProfileFile pf([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -85,9 +84,9 @@ TEST_CASE("profileFile: Unrecognized header", "[profileFile]") { std::string testFull_string = stringFromTestProfileFormat(test); std::istringstream iss(testFull_string); - ProfileFile pf; + ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readLines([&iss](std::string& line) { + pf.readIn([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -106,9 +105,9 @@ TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { testFull_string = stringFromTestProfileFormat(test); { std::istringstream iss(testFull_string); - ProfileFile pf; + ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readLines([&iss](std::string& line) { + pf.readIn([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -124,9 +123,9 @@ TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { testFull_string = stringFromTestProfileFormat(test); { std::istringstream iss(testFull_string); - ProfileFile pf; + ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readLines([&iss](std::string& line) { + pf.readIn([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -145,9 +144,9 @@ TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") { testFull_string = stringFromTestProfileFormat(test); { std::istringstream iss(testFull_string); - ProfileFile pf; + ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readLines([&iss](std::string& line) { + pf.readIn([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -167,9 +166,9 @@ TEST_CASE("profileFile: Required field missing", "[profileFile]") { testFull_string = stringFromTestProfileFormat(test); { std::istringstream iss(testFull_string); - ProfileFile pf; + ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readLines([&iss](std::string& line) { + pf.readIn([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -185,9 +184,9 @@ TEST_CASE("profileFile: Required field missing", "[profileFile]") { testFull_string = stringFromTestProfileFormat(test); { std::istringstream iss(testFull_string); - ProfileFile pf; + ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readLines([&iss](std::string& line) { + pf.readIn([&iss](std::string& line) { if (getline(iss, line)) return true; else @@ -203,8 +202,7 @@ TEST_CASE("profileFile: Write test", "[profileFile]") { testProfileFormat test = buildTestProfile1(); std::string testFull_string = stringFromTestProfileFormat(test); std::istringstream iss(testFull_string); - ProfileFile pf; - pf.readLines([&iss](std::string& line) { + ProfileFile pf([&iss](std::string& line) { if (getline(iss, line)) return true; else From fe24b0c4463fb13f84d21891fc19f8422e7254ac Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 7 May 2020 15:39:50 -0600 Subject: [PATCH 09/61] Finished unit tests for profile save current feature --- include/openspace/scene/assetloader.h | 2 +- include/openspace/scene/profile.h | 1 + src/scene/assetloader.cpp | 2 +- src/scene/profile.cpp | 14 +- tests/profile/default.profile | 4 +- .../solarsystem/planets/earth/earth.asset | 1 + tests/profile/test2.asset | 1 + tests/profile/test2.profile | 4 +- tests/profile/test3.asset | 1 + tests/profile/test4.asset | 1 + tests/profile/test_common.h | 205 ++++++++++++++++++ tests/profile/test_profile.cpp | 197 ++++++++++++++++- 12 files changed, 412 insertions(+), 21 deletions(-) create mode 100644 tests/profile/scene/solarsystem/planets/earth/earth.asset create mode 100644 tests/profile/test2.asset create mode 100644 tests/profile/test3.asset create mode 100644 tests/profile/test4.asset diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index 25ec440b4f..fbb7db24e2 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -174,7 +174,7 @@ public: * Retrieve a reference to vector list of all assets events, including require, * request, and remove */ - const std::vector& listOfAllAssetEvents() const; + std::vector& listOfAllAssetEvents(); /** * Clear lists of all assets that have been either requested, required, or removed diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 4ecb5194d6..b25945d489 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -114,6 +114,7 @@ private: virtual bool usingProfile(); virtual std::string initialProfile(); + virtual std::vector listOfAllAssetEvents(); ProfileFile collateBaseWithChanges(); std::string convertToScene_assets(ProfileFile& pf); std::string convertToScene_modules(ProfileFile& pf); diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index d1d5f10c40..31bfa3e180 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -814,7 +814,7 @@ void AssetLoader::assetUnrequested(std::shared_ptr parent, } } -const std::vector& AssetLoader::listOfAllAssetEvents() const { +std::vector& AssetLoader::listOfAllAssetEvents() { return _profileAssets; } diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 5da2069ec9..4cb3412b7e 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -76,6 +76,10 @@ std::string Profile::initialProfile() { return global::configuration.profile; } +std::vector Profile::listOfAllAssetEvents() { + return global::openSpaceEngine.listOfAllAssetEvents(); +} + ProfileFile Profile::collateBaseWithChanges() { if (! usingProfile()) { std::string errorMessage = "Program was not started using a profile, " @@ -98,7 +102,7 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi AllAssetDetails assetDetails; assetDetails.base = a; - assetDetails.changed = global::openSpaceEngine.listOfAllAssetEvents(); + assetDetails.changed = listOfAllAssetEvents(); for (unsigned int i = 0; i < assetDetails.changed.size(); i++) { AssetEvent event = assetDetails.changed[i]; @@ -167,8 +171,10 @@ void Profile::addAssetsToProfileFile(std::vector& allAssets, Profile { pf.clearAssets(); for (AssetEvent a : allAssets) { - std::string entry = a.name + "\t" + AssetEventTypeString.at(a.eventType); - pf.addAssetLine(entry); + if (a.eventType != AssetEventType::ignore) { + std::string entry = a.name + "\t" + AssetEventTypeString.at(a.eventType); + pf.addAssetLine(entry); + } } } @@ -179,7 +185,7 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileFile& for (std::string line : pf.assets()) { pf.splitByTab(line, elements); - if (a.name.empty()) { + if (elements[0].empty()) { LERROR("Error in parsing asset file line '" + line + "'. Asset name is needed (field 1/2)."); } diff --git a/tests/profile/default.profile b/tests/profile/default.profile index b5614baf84..7d10fb2b71 100644 --- a/tests/profile/default.profile +++ b/tests/profile/default.profile @@ -3,10 +3,10 @@ #Asset scene/solarsystem/planets/earth/earth required -scene/solarsystem/planets/earth/satellites/satellites required +scene/solarsystem/planets/earth/satellites/satellites required #Property -setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValue {earth_satellites}.Renderable.Enabled false #Time relative -1d diff --git a/tests/profile/scene/solarsystem/planets/earth/earth.asset b/tests/profile/scene/solarsystem/planets/earth/earth.asset new file mode 100644 index 0000000000..3acea7c194 --- /dev/null +++ b/tests/profile/scene/solarsystem/planets/earth/earth.asset @@ -0,0 +1 @@ +assert (true) \ No newline at end of file diff --git a/tests/profile/test2.asset b/tests/profile/test2.asset new file mode 100644 index 0000000000..3acea7c194 --- /dev/null +++ b/tests/profile/test2.asset @@ -0,0 +1 @@ +assert (true) \ No newline at end of file diff --git a/tests/profile/test2.profile b/tests/profile/test2.profile index 9365bfc57b..c5e8fab1c3 100644 --- a/tests/profile/test2.profile +++ b/tests/profile/test2.profile @@ -6,7 +6,9 @@ scene/solarsystem/planets/earth/earth required scene/solarsystem/planets/earth/satellites/satellites required #Property -setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValueSingle Scene.Pluto.Renderable.Enabled false +setPropertyValueSingle Scene.Charon.Renderable.Enabled false #Time relative -1d diff --git a/tests/profile/test3.asset b/tests/profile/test3.asset new file mode 100644 index 0000000000..3acea7c194 --- /dev/null +++ b/tests/profile/test3.asset @@ -0,0 +1 @@ +assert (true) \ No newline at end of file diff --git a/tests/profile/test4.asset b/tests/profile/test4.asset new file mode 100644 index 0000000000..3acea7c194 --- /dev/null +++ b/tests/profile/test4.asset @@ -0,0 +1 @@ +assert (true) \ No newline at end of file diff --git a/tests/profile/test_common.h b/tests/profile/test_common.h index cdff281d0c..db010d17c0 100644 --- a/tests/profile/test_common.h +++ b/tests/profile/test_common.h @@ -419,6 +419,211 @@ asset.onInitialize(function ()\n\ openspace.navigation.setNavigationState({Anchor = \"NewHorizons\", ReferenceFrame = \"Root\", Position = {-6.572656E1, -7.239404E1, -2.111890E1}, Up = {0.102164, -0.362945, 0.926193}, })\n\ end)"; +const std::string detectChangedPropsResult_1 = "\ +#Version\n\ +1.0\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +initialized 1st\t123\n\ +initialized 2nd\t3.14159\n\ +initialized 3rd\ttested.\n\ +initialized fourth\tfalse.\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ +\n\ +\n\ +#Camera\n\ +setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + +const std::string detectChangedAssetsResult_1 = "\ +#Version\n\ +1.0\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +initialization\trequested\n\ +test2\trequested\n\ +test3\trequested\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ +\n\ +\n\ +#Camera\n\ +setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + +const std::string detectChangedAssetsResult_2 = "\ +#Version\n\ +1.0\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +test3\trequested\n\ +test4\trequested\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ +\n\ +\n\ +#Camera\n\ +setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + +const std::string detectChangedAssetsResult_3 = "\ +#Version\n\ +1.0\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +test2\trequested\n\ +test4\trequested\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ +\n\ +\n\ +#Camera\n\ +setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + +const std::string detectChangedAssetsResult_4 = "\ +#Version\n\ +1.0\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +test2\trequested\n\ +test4\trequested\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ +\n\ +\n\ +#Camera\n\ +setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + +const std::string detectChangedAssetsResult_5 = "\ +#Version\n\ +1.0\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +test2\trequested\n\ +test4\trequested\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ +\n\ +\n\ +#Camera\n\ +setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + testProfileFormat buildTestProfile1(); std::string stringFromSingleProfileSection(std::vector& section, bool blankLineSeparator); diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 1f8e0567db..cee22b172b 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -26,6 +26,7 @@ #include "test_common.h" #include #include +#include #include #include @@ -54,10 +55,11 @@ namespace { class Profile2 : public Profile { public: - std::string getCurrentTimeUTC() { + Profile2(AssetLoader& refAssetLoader) : _assLoader(refAssetLoader) {} + std::string getCurrentTimeUTC() override { return "2020-02-29T01:23:45.00"; } - interaction::NavigationHandler::NavigationState getCurrentCameraState() { + interaction::NavigationHandler::NavigationState getCurrentCameraState() override { interaction::NavigationHandler::NavigationState n; n.anchor = "Earth"; n.aim = "Sun"; @@ -71,25 +73,29 @@ public: void addPropertiesMarkedAsChanged(std::string formattedLine) { _scenegraphProps.push_back(formattedLine); } - std::vector getChangedPropertiesFormatted() { + std::vector getChangedPropertiesFormatted() override { std::vector formattedLines; for (std::string s : _scenegraphProps) { formattedLines.push_back(s); } return formattedLines; } - bool usingProfile() { + bool usingProfile() override { return true; } - std::string initialProfile() { + std::string initialProfile() override { return _initProfile; } void setInitialProfile(std::string file) { _initProfile = file; } + std::vector listOfAllAssetEvents() override { + return _assLoader.listOfAllAssetEvents(); + } private: std::vector _scenegraphProps; std::string _initProfile; + AssetLoader& _assLoader; }; static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { @@ -151,7 +157,32 @@ TEST_CASE("profile: Verify conversion to scene", "[profile]") { REQUIRE(sr_standard.getNextLine(comparing) == false); } -TEST_CASE("profile: Detect new required asset", "[profile]") { +TEST_CASE("profile: Detect new properties", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + Profile2 p(assetLoader); + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.addPropertiesMarkedAsChanged("initialized 1st\t123"); + p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); + p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); + p.addPropertiesMarkedAsChanged("initialized fourth\tfalse."); + std::string output = p.saveCurrentSettingsToProfile_string(); + REQUIRE(output == detectChangedPropsResult_1); +} + +TEST_CASE("profile: Detect new added assets", "[profile]") { openspace::Scene scene(std::make_unique()); ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); openspace::SynchronizationWatcher syncWatcher; @@ -168,13 +199,155 @@ TEST_CASE("profile: Detect new required asset", "[profile]") { std::shared_ptr asset = assetLoader.add("initialization"); asset->initialize(); - assetLoader.add("test1"); + std::shared_ptr asset2 = assetLoader.add("test2"); + asset2->initialize(); + std::shared_ptr asset3 = assetLoader.add("test3"); + asset3->initialize(); - Profile2 p; + Profile2 p(assetLoader); p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); - p.addPropertiesMarkedAsChanged("initialized 1st\t123"); - p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); - p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); std::string output = p.saveCurrentSettingsToProfile_string(); - std::cout << output << std::endl; + REQUIRE(output == detectChangedAssetsResult_1); +} + +TEST_CASE("profile: Detect new added assets after reset", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + std::shared_ptr asset = assetLoader.add("initialization"); + asset->initialize(); + std::shared_ptr asset2 = assetLoader.add("test2"); + asset2->initialize(); + assetLoader.listOfAllAssetEvents_reset(); + std::shared_ptr asset3 = assetLoader.add("test3"); + asset3->initialize(); + std::shared_ptr asset4 = assetLoader.add("test4"); + asset4->initialize(); + + Profile2 p(assetLoader); + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + std::string output = p.saveCurrentSettingsToProfile_string(); + REQUIRE(output == detectChangedAssetsResult_2); +} + +TEST_CASE("profile: Detect repeat added assets from new", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + std::shared_ptr asset = assetLoader.add("test2"); + asset->initialize(); + std::shared_ptr asset2 = assetLoader.add("test4"); + asset2->initialize(); + std::shared_ptr asset3 = assetLoader.add("test2"); + asset3->initialize(); + + Profile2 p(assetLoader); + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + std::string output = p.saveCurrentSettingsToProfile_string(); + REQUIRE(output == detectChangedAssetsResult_3); +} + +TEST_CASE("profile: Detect repeat added assets from base", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + std::shared_ptr asset = assetLoader.add("test2"); + asset->initialize(); + std::shared_ptr asset2 = assetLoader.add("test4"); + asset2->initialize(); + std::shared_ptr asset3 = assetLoader.add("scene/solarsystem/planets/earth/earth"); + asset3->initialize(); + + Profile2 p(assetLoader); + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + std::string output = p.saveCurrentSettingsToProfile_string(); + REQUIRE(output == detectChangedAssetsResult_4); +} + +TEST_CASE("profile: Detect removed assets not already loaded", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + std::shared_ptr asset = assetLoader.add("test2"); + asset->initialize(); + std::shared_ptr asset2 = assetLoader.add("test4"); + asset2->initialize(); + assetLoader.remove("test5"); + + Profile2 p(assetLoader); + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + std::string output = p.saveCurrentSettingsToProfile_string(); + REQUIRE(output == detectChangedAssetsResult_4); +} + +TEST_CASE("profile: Detect removed assets from already loaded", "[profile]") { + openspace::Scene scene(std::make_unique()); + ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); + openspace::SynchronizationWatcher syncWatcher; + AssetLoader assetLoader( + state, + &syncWatcher, + FileSys.absolutePath("${TESTDIR}/profile/") + ); + + bool passed; + lua_pushlightuserdata(*state, &passed); + lua_pushcclosure(*state, &passTest, 1); + lua_setglobal(*state, "passTest"); + + std::shared_ptr asset = assetLoader.add("test2"); + asset->initialize(); + std::shared_ptr asset2 = assetLoader.add("test4"); + asset2->initialize(); + assetLoader.remove("scene/solarsystem/planets/earth/earth"); + assetLoader.remove("scene/solarsystem/planets/earth/satellites/satellites"); + + Profile2 p(assetLoader); + p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + std::string output = p.saveCurrentSettingsToProfile_string(); + REQUIRE(output == detectChangedAssetsResult_5); } From dfb61097b2fe9ad238e560a16f9ccabb7e2ab5a3 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 14 May 2020 13:20:05 -0600 Subject: [PATCH 10/61] Finished testing new save-settings-to-profile feature --- include/openspace/engine/openspaceengine.h | 1 + include/openspace/scene/profile.h | 18 +++- include/openspace/scene/profilefile.h | 8 +- src/documentation/core_registration.cpp | 1 + src/engine/openspaceengine.cpp | 37 +++++--- src/scene/profile.cpp | 100 +++++++++++++-------- src/scene/profilefile.cpp | 49 +++++++--- tests/profile/test_common.cpp | 1 + tests/profile/test_common.h | 72 ++++++++++----- tests/profile/test_profile.cpp | 59 +++++++----- 10 files changed, 236 insertions(+), 110 deletions(-) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 3e9a86eb80..efceb720b4 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -114,6 +114,7 @@ private: void runGlobalCustomizationScripts(); void configureLogging(); std::string generateFilePath(std::string openspaceRelativePath); + void resetPropertyChangeFlagsOfSubowners(openspace::properties::PropertyOwner* po); std::unique_ptr _scene; std::unique_ptr _assetManager; diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index b25945d489..c758f97af2 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -45,6 +45,8 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } +const std::string profileFormatVersion = "1.0"; + class Profile { public: enum class AssetEventType { @@ -68,6 +70,10 @@ public: virtual ~Profile() {}; + const std::string formatVersion() { + return profileFormatVersion; + } + /** * Saves all current settings, starting from the profile that was loaded at startup, * and all of the property & asset changes that were made since startup. @@ -106,14 +112,17 @@ public: */ static scripting::LuaLibrary luaLibrary(); +protected: + std::string _profileBaseDirectory = "${ASSETS}"; + private: struct AllAssetDetails { std::vector base; std::vector changed; }; - virtual bool usingProfile(); virtual std::string initialProfile(); + virtual std::string profileBaseDirectory(); virtual std::vector listOfAllAssetEvents(); ProfileFile collateBaseWithChanges(); std::string convertToScene_assets(ProfileFile& pf); @@ -124,15 +133,18 @@ private: std::string convertToScene_time(ProfileFile& pf); std::string convertToScene_camera(ProfileFile& pf); + void updateToCurrentFormatVersion(ProfileFile& pf); std::vector modifyAssetsToReflectChanges(ProfileFile& pf); void parseAssetFileLines(std::vector& results, ProfileFile& pf); void handleChangedAdd(std::vector& base, unsigned int changedIdx, std::vector& changed, std::string asset); - void handleChangedRemove(std::vector& base, unsigned int changedIdx, - std::vector& changed, std::string asset); + void handleChangedRemove(std::vector& base, std::string asset); void addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf); void modifyPropertiesToReflectChanges(ProfileFile& pf); virtual std::vector getChangedProperties(); + void checkForChangedProps(std::vector& changedList, + openspace::properties::PropertyOwner* po); + std::string getFullPropertyPath(openspace::properties::Property* prop); virtual std::vector getChangedPropertiesFormatted(); virtual std::string getCurrentTimeUTC(); virtual interaction::NavigationHandler::NavigationState getCurrentCameraState(); diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index d1665f8cc9..807daf8cfd 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -211,11 +211,17 @@ public: void addMarkNodesLine(const std::string line); /** - * Returns the version number (profiles syntax version) string + * Returns the format version number (profiles syntax version) string * \return The version string */ const std::string getVersion() const; + /** + * Sets the format version number (profiles syntax version) string + * \param The version string to set + */ + void setVersion(std::string); + /** * Returns the profile's time string. See updateTime comment header for notes on * syntax of this time string diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 974c386296..3b44fae6fb 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -83,6 +83,7 @@ void registerCoreClasses(scripting::ScriptEngine& engine) { engine.addLibrary(ParallelPeer::luaLibrary()); engine.addLibrary(RenderEngine::luaLibrary()); engine.addLibrary(SpiceManager::luaLibrary()); + engine.addLibrary(Profile::luaLibrary()); engine.addLibrary(Scene::luaLibrary()); engine.addLibrary(Time::luaLibrary()); engine.addLibrary(interaction::KeybindingManager::luaLibrary()); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index f825c45370..a7baa68726 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -306,14 +306,21 @@ void OpenSpaceEngine::initialize() { std::string outputAsset = outputScenePath + "/" + global::configuration.profile + ".asset"; - global::profile.convertToSceneFile(inputProfile, outputAsset); + if (!FileSys.fileExists(inputProfile)) { + LERROR(fmt::format( + "Could not load profile '{}': File does not exist", inputProfile) + ); + } + else { + global::profile.convertToSceneFile(inputProfile, outputAsset); - // Set asset name to that of the profile because a new scene file will be - // created with that name, and also because the profile name will override - // an asset name if both are provided. - global::configuration.asset = - absPath("${TEMPORARY}/") + global::configuration.profile; - global::configuration.usingProfile = true; + // Set asset name to that of the profile because a new scene file will be + // created with that name, and also because the profile name will override + // an asset name if both are provided. + global::configuration.asset = + absPath("${TEMPORARY}/") + global::configuration.profile; + global::configuration.usingProfile = true; + } } // Set up asset loader @@ -1297,10 +1304,18 @@ void OpenSpaceEngine::resetPropertyChangeFlags() { std::vector nodes = global::renderEngine.scene()->allSceneGraphNodes(); for (auto n : nodes) { - std::vector props = n->properties(); - for (auto p : props) { - p->resetToUnchanged(); - } + resetPropertyChangeFlagsOfSubowners(n); + } +} + +void OpenSpaceEngine::resetPropertyChangeFlagsOfSubowners( + openspace::properties::PropertyOwner* po) +{ + for (auto subOwner : po->propertySubOwners()) { + resetPropertyChangeFlagsOfSubowners(subOwner); + } + for (auto p : po->properties()) { + p->resetToUnchanged(); } } diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 4cb3412b7e..ff48d93a5e 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,10 @@ std::vector Profile::listOfAllAssetEvents() { return global::openSpaceEngine.listOfAllAssetEvents(); } +std::string Profile::profileBaseDirectory() { + return _profileBaseDirectory; +} + ProfileFile Profile::collateBaseWithChanges() { if (! usingProfile()) { std::string errorMessage = "Program was not started using a profile, " @@ -87,7 +92,10 @@ ProfileFile Profile::collateBaseWithChanges() { LERROR(errorMessage); } std::string initProfile = initialProfile(); - ProfileFile pf(initProfile); + std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + + ".profile"; + ProfileFile pf(inputProfilePath); + updateToCurrentFormatVersion(pf); std::vector ass = modifyAssetsToReflectChanges(pf); addAssetsToProfileFile(ass, pf); modifyPropertiesToReflectChanges(pf); @@ -96,6 +104,10 @@ ProfileFile Profile::collateBaseWithChanges() { return pf; } +void Profile::updateToCurrentFormatVersion(ProfileFile& pf) { + pf.setVersion(profileFormatVersion); +} + std::vector Profile::modifyAssetsToReflectChanges(ProfileFile& pf) { std::vector a; parseAssetFileLines(a, pf); @@ -111,7 +123,7 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); } else if (event.eventType == AssetEventType::remove) { - handleChangedRemove(assetDetails.base, i, assetDetails.changed, event.name); + handleChangedRemove(assetDetails.base, event.name); } } return assetDetails.base; @@ -147,24 +159,9 @@ void Profile::handleChangedAdd(std::vector& base, unsigned int chang } } -void Profile::handleChangedRemove(std::vector& base, unsigned int changedIdx, - std::vector& changed, std::string asset) +void Profile::handleChangedRemove(std::vector& base, std::string asset) { - //Blank-out any base profile entries where this asset was required/requested - for (unsigned int i = 0; i < base.size(); i++) { - if (base[i].name == asset) { - base[i].name = ""; - base[i].eventType = AssetEventType::ignore; - } - } - - //Blank-out any changes profile entries where this asset was required/requested - for (unsigned int i = 0; i < changedIdx; i++) { - if (changed[i].name == asset) { - changed[i].name = ""; - changed[i].eventType = AssetEventType::ignore; - } - } + base.push_back({asset, AssetEventType::remove}); } void Profile::addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf) @@ -226,13 +223,44 @@ std::vector Profile::getChangedPropertiesFormatted() { for (auto prop : changedProps) { std::string newLine = "setPropertyValueSingle\t"; - newLine += prop->identifier() + "\t"; - newLine += prop->getStringValue() + "\n"; + newLine += getFullPropertyPath(prop) + "\t"; + newLine += prop->getStringValue(); formattedLines.push_back(newLine); } return formattedLines; } +std::string recurseForFullName(openspace::properties::PropertyOwner* po) { + std::string path; + if (po != nullptr) { + std::string name = recurseForFullName(po->owner()) + po->identifier(); + if (!name.empty()) { + path = name + "."; + } + } + return path; +} + +std::string Profile::getFullPropertyPath(openspace::properties::Property* prop) { + return recurseForFullName(prop->owner()) + prop->identifier(); +} + +void Profile::checkForChangedProps( + std::vector& changedList, + openspace::properties::PropertyOwner* po) +{ + if (po != nullptr) { + for (auto subOwner : po->propertySubOwners()) { + checkForChangedProps(changedList, subOwner); + } + for (auto p : po->properties()) { + if (p->hasChanged()) { + changedList.push_back(p); + } + } + } +} + std::vector Profile::getChangedProperties() { ZoneScoped @@ -242,25 +270,18 @@ std::vector Profile::getChangedProperties() std::vector changedProps; for (auto n : nodes) { - if (n != nullptr) { - std::vector props = n->properties(); - for (auto p : props) { - if (p->hasChanged()) { - changedProps.push_back(p); - } - } - } + checkForChangedProps(changedProps, n); } return changedProps; } std::string Profile::getCurrentTimeUTC() { - return global::timeManager.time().UTC(); + return global::timeManager.time().ISO8601(); } void Profile::addCurrentTimeToProfileFile(ProfileFile& pf) { std::string t = getCurrentTimeUTC(); - std::string update = "absolute\t" + t + "\n"; + std::string update = "absolute\t" + t; pf.updateTime(update); } @@ -272,9 +293,9 @@ void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { std::string update = "setNavigationState\t"; interaction::NavigationHandler::NavigationState nav; nav = getCurrentCameraState(); - update += nav.anchor + "\t"; - update += nav.aim + "\t"; - update += nav.referenceFrame + "\t"; + update += "\"" + nav.anchor + "\"\t"; + update += "\"" + nav.aim + "\"\t"; + update += "\"" + nav.referenceFrame + "\"\t"; update += std::to_string(nav.position.x) + ","; update += std::to_string(nav.position.y) + ","; update += std::to_string(nav.position.z) + "\t"; @@ -287,7 +308,7 @@ void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { } update += "\t"; update += std::to_string(nav.yaw) + "\t"; - update += std::to_string(nav.pitch) + "\n"; + update += std::to_string(nav.pitch); pf.updateCamera(update); } @@ -304,21 +325,24 @@ void Profile::convertToSceneFile(const std::string inProfilePath, outFile.open(outFilePath, std::ofstream::out); } catch (std::ofstream::failure& e) { - LERROR("Exception opening profile file for write: " + outFilePath); + LERROR("Exception opening scene file for write: " + outFilePath + + " (" + e.what() + ")"); } try { outFile << convertToScene(pf); } catch (std::ofstream::failure& e) { - LERROR("Data write error to file: " + outFilePath); + LERROR("Data write error to scene file: " + outFilePath + + " (" + e.what() + ")"); } try { outFile.close(); } catch (std::ofstream::failure& e) { - LERROR("Exception closing profile file after write: " + outFilePath); + LERROR("Exception closing scene file after write: " + outFilePath + + " (" + e.what() + ")"); } } diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 5a4dbd9b28..90029ac412 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -56,11 +56,11 @@ void ProfileFile::readIn(std::string filename) { std::ifstream inFile; try { - inFile.open(filename, std::_Ios_Openmode::_S_in); + inFile.open(filename, std::ifstream::in); } catch (std::ifstream::failure& e) { throw ghoul::RuntimeError("Exception opening profile file for read: " - + filename, "profileFile"); + + filename + " (" + e.what() + ")", "profileFile"); } try { @@ -72,16 +72,16 @@ void ProfileFile::readIn(std::string filename) { }); } catch (std::ifstream::failure& e) { - throw ghoul::RuntimeError(errorString("Read error using getline"), - "profileFile"); + throw ghoul::RuntimeError(errorString("Read error using getline in: " + + filename + " (" + e.what() + ")"), "profileFile"); } try { inFile.close(); } catch (std::ifstream::failure& e) { - throw ghoul::RuntimeError("Exception closing profile file after read: " - + filename, "profileFile"); + throw ghoul::RuntimeError("Exception closing profile file after read in: " + + filename + " (" + e.what() + ")", "profileFile"); } } @@ -116,26 +116,51 @@ void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { } void ProfileFile::writeToFile(const std::string filename) { + if (filename.find("/") != std::string::npos) { + LERROR("Profile filename must not contain path (/) elements"); + return; + } + else if (filename.find(":") != std::string::npos) { + LERROR("Profile filename must not contain path (:) elements"); + return; + } + else if (filename.find(".") != std::string::npos) { + LERROR("Only provide the filename to save without file extension"); + return; + } + const std::string absFilename = absPath("${ASSETS}/" + filename + ".profile"); + + if (FileSys.fileExists(absFilename)) { + LERROR(fmt::format( + "Unable to save profile '{}'. File of same name already exists.", + absFilename.c_str() + )); + return; + } + std::ofstream outFile; try { - outFile.open(filename, std::ofstream::out | std::ofstream::app); + outFile.open(absFilename, std::ofstream::out); } catch (std::ofstream::failure& e) { - LERROR("Exception opening profile file for write: " + filename); + LERROR("Exception opening profile file for write: " + + absFilename + " (" + e.what() + ")"); } try { outFile << writeToString(); } catch (std::ofstream::failure& e) { - LERROR("Data write error to file: " + filename); + LERROR("Data write error to file: " + + absFilename + " (" + e.what() + ")"); } try { outFile.close(); } catch (std::ofstream::failure& e) { - LERROR("Exception closing profile file after write: " + filename); + LERROR("Exception closing profile file after write: " + + absFilename + " (" + e.what() + ")"); } } @@ -169,6 +194,10 @@ const std::string ProfileFile::getVersion() const { return _version; } +void ProfileFile::setVersion(std::string v) { + _version = v; +} + void ProfileFile::addAllElements(std::string& str, std::vector& list) { for (auto s : list) { str += s + '\n'; diff --git a/tests/profile/test_common.cpp b/tests/profile/test_common.cpp index 23225903cb..f1bf784a97 100644 --- a/tests/profile/test_common.cpp +++ b/tests/profile/test_common.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include using namespace openspace; diff --git a/tests/profile/test_common.h b/tests/profile/test_common.h index db010d17c0..fabd2cedeb 100644 --- a/tests/profile/test_common.h +++ b/tests/profile/test_common.h @@ -31,6 +31,7 @@ #include #include #include +#include #include using namespace openspace; @@ -421,7 +422,7 @@ end)"; const std::string detectChangedPropsResult_1 = "\ #Version\n\ -1.0\n\ +" + profileFormatVersion + "\n\ \n\ #Module\n\ \n\ @@ -443,10 +444,8 @@ initialized fourth\tfalse.\n\ #Time\n\ absolute\t2020-02-29T01:23:45.00\n\ \n\ -\n\ #Camera\n\ -setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ \n\ #MarkNodes\n\ Earth\n\ @@ -457,7 +456,7 @@ Sun\n\ const std::string detectChangedAssetsResult_1 = "\ #Version\n\ -1.0\n\ +" + profileFormatVersion + "\n\ \n\ #Module\n\ \n\ @@ -478,10 +477,8 @@ setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ #Time\n\ absolute\t2020-02-29T01:23:45.00\n\ \n\ -\n\ #Camera\n\ -setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ \n\ #MarkNodes\n\ Earth\n\ @@ -492,7 +489,7 @@ Sun\n\ const std::string detectChangedAssetsResult_2 = "\ #Version\n\ -1.0\n\ +" + profileFormatVersion + "\n\ \n\ #Module\n\ \n\ @@ -512,10 +509,8 @@ setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ #Time\n\ absolute\t2020-02-29T01:23:45.00\n\ \n\ -\n\ #Camera\n\ -setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ \n\ #MarkNodes\n\ Earth\n\ @@ -526,7 +521,7 @@ Sun\n\ const std::string detectChangedAssetsResult_3 = "\ #Version\n\ -1.0\n\ +" + profileFormatVersion + "\n\ \n\ #Module\n\ \n\ @@ -546,10 +541,8 @@ setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ #Time\n\ absolute\t2020-02-29T01:23:45.00\n\ \n\ -\n\ #Camera\n\ -setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ \n\ #MarkNodes\n\ Earth\n\ @@ -560,7 +553,7 @@ Sun\n\ const std::string detectChangedAssetsResult_4 = "\ #Version\n\ -1.0\n\ +" + profileFormatVersion + "\n\ \n\ #Module\n\ \n\ @@ -580,10 +573,8 @@ setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ #Time\n\ absolute\t2020-02-29T01:23:45.00\n\ \n\ -\n\ #Camera\n\ -setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ \n\ #MarkNodes\n\ Earth\n\ @@ -594,13 +585,16 @@ Sun\n\ const std::string detectChangedAssetsResult_5 = "\ #Version\n\ -1.0\n\ +" + profileFormatVersion + "\n\ \n\ #Module\n\ \n\ #Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ test2\trequested\n\ test4\trequested\n\ +test5\tremoved\n\ \n\ #Property\n\ setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ @@ -612,10 +606,42 @@ setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ #Time\n\ absolute\t2020-02-29T01:23:45.00\n\ \n\ +#Camera\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +\n\ +#MarkNodes\n\ +Earth\n\ +Mars\n\ +Moon\n\ +Sun\n\ +"; + +const std::string detectChangedAssetsResult_6 = "\ +#Version\n\ +" + profileFormatVersion + "\n\ +\n\ +#Module\n\ +\n\ +#Asset\n\ +scene/solarsystem/planets/earth/earth\trequired\n\ +scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +test2\trequested\n\ +test4\trequested\n\ +scene/solarsystem/planets/earth/earth\tremoved\n\ +scene/solarsystem/planets/earth/satellites/satellites\tremoved\n\ +\n\ +#Property\n\ +setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +\n\ +#Keybinding\n\ +\n\ +#Time\n\ +absolute\t2020-02-29T01:23:45.00\n\ \n\ #Camera\n\ -setNavigationState\tEarth\tSun\troot\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ +setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ \n\ #MarkNodes\n\ Earth\n\ diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index cee22b172b..7ca31841f1 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -92,6 +92,9 @@ public: std::vector listOfAllAssetEvents() override { return _assLoader.listOfAllAssetEvents(); } + void setProfileBaseDirectory(std::string dir) { + _profileBaseDirectory = dir; + } private: std::vector _scenegraphProps; std::string _initProfile; @@ -102,8 +105,6 @@ static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { s = "@line " + std::to_string(lineNumber) + ": '" + s + "'"; } - - TEST_CASE("profile: Convert profileFile to asset", "[profile]") { testProfileFormat test = buildTestProfile1(); std::string testFull_string = stringFromTestProfileFormat(test); @@ -140,21 +141,24 @@ TEST_CASE("profile: Verify conversion to scene", "[profile]") { REQUIRE_NOTHROW( result = p.convertToScene(pf) ); + + if (result != newHorizonsExpectedSceneOutput) { + std::string testing, comparing; + StringPerLineReader sr_result(result); + StringPerLineReader sr_standard(newHorizonsExpectedSceneOutput); - std::string testing, comparing; - StringPerLineReader sr_result(result); - StringPerLineReader sr_standard(newHorizonsExpectedSceneOutput); - - size_t lineN = 1; - while (sr_result.getNextLine(testing)) { - sr_standard.getNextLine(comparing); - addLineHeaderForFailureMessage(testing, lineN); - addLineHeaderForFailureMessage(comparing, lineN); - REQUIRE(testing == comparing); - lineN++; + size_t lineN = 1; + while (sr_result.getNextLine(testing)) { + sr_standard.getNextLine(comparing); + addLineHeaderForFailureMessage(testing, lineN); + addLineHeaderForFailureMessage(comparing, lineN); + REQUIRE(testing == comparing); + lineN++; + } + //If this fails there are extra lines in the comparison string that weren't in result + REQUIRE(sr_standard.getNextLine(comparing) == false); } - //If this fails there are extra lines in the comparison string that weren't in result - REQUIRE(sr_standard.getNextLine(comparing) == false); + //REQUIRE(result == newHorizonsExpectedSceneOutput); } TEST_CASE("profile: Detect new properties", "[profile]") { @@ -173,7 +177,8 @@ TEST_CASE("profile: Detect new properties", "[profile]") { lua_setglobal(*state, "passTest"); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); p.addPropertiesMarkedAsChanged("initialized 1st\t123"); p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); @@ -205,7 +210,8 @@ TEST_CASE("profile: Detect new added assets", "[profile]") { asset3->initialize(); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); std::string output = p.saveCurrentSettingsToProfile_string(); REQUIRE(output == detectChangedAssetsResult_1); } @@ -236,7 +242,8 @@ TEST_CASE("profile: Detect new added assets after reset", "[profile]") { asset4->initialize(); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); std::string output = p.saveCurrentSettingsToProfile_string(); REQUIRE(output == detectChangedAssetsResult_2); } @@ -264,7 +271,8 @@ TEST_CASE("profile: Detect repeat added assets from new", "[profile]") { asset3->initialize(); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); std::string output = p.saveCurrentSettingsToProfile_string(); REQUIRE(output == detectChangedAssetsResult_3); } @@ -292,7 +300,8 @@ TEST_CASE("profile: Detect repeat added assets from base", "[profile]") { asset3->initialize(); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); std::string output = p.saveCurrentSettingsToProfile_string(); REQUIRE(output == detectChangedAssetsResult_4); } @@ -319,9 +328,10 @@ TEST_CASE("profile: Detect removed assets not already loaded", "[profile]") { assetLoader.remove("test5"); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_4); + REQUIRE(output == detectChangedAssetsResult_5); } TEST_CASE("profile: Detect removed assets from already loaded", "[profile]") { @@ -347,7 +357,8 @@ TEST_CASE("profile: Detect removed assets from already loaded", "[profile]") { assetLoader.remove("scene/solarsystem/planets/earth/satellites/satellites"); Profile2 p(assetLoader); - p.setInitialProfile(FileSys.absolutePath("${TESTDIR}/profile/test2.profile")); + p.setProfileBaseDirectory("${TESTDIR}/profile"); + p.setInitialProfile("test2"); std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_5); + REQUIRE(output == detectChangedAssetsResult_6); } From 748fc64d605dc58a2d522c5d7cd61e106d1c5e1b Mon Sep 17 00:00:00 2001 From: GPayne Date: Mon, 18 May 2020 14:47:35 -0600 Subject: [PATCH 11/61] Fixed format error if markNodes is empty --- src/scene/profile.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index ff48d93a5e..1da60105df 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -475,11 +475,11 @@ std::string Profile::convertToScene_markNodes(ProfileFile& pf) { if (pf.markNodes().size() > 0) { result += " openspace.markInterestingNodes({"; + for (std::string m : pf.markNodes()) { + result += "\"" + m + "\", "; + } + result += "})\n"; } - for (std::string m : pf.markNodes()) { - result += "\"" + m + "\", "; - } - result += "})\n"; return result; } From 433d96bbb4e1bfb50153fcc217390754a901669b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 11 Jun 2020 00:24:58 +0200 Subject: [PATCH 12/61] SGCT compile fix First pass for pull request --- apps/OpenSpace/main.cpp | 6 +- data/assets/default.profile | 4 +- include/openspace/engine/openspaceengine.h | 2 +- include/openspace/properties/property.h | 4 +- .../openspace/properties/templateproperty.inl | 4 +- include/openspace/scene/assetloader.h | 7 +- include/openspace/scene/assetmanager.h | 4 +- include/openspace/scene/profile.h | 62 +-- include/openspace/scene/profilefile.h | 16 +- modules/imgui/src/gui.cpp | 9 +- openspace.cfg | 4 +- src/engine/openspaceengine.cpp | 6 +- src/properties/property.cpp | 6 +- src/scene/assetloader.cpp | 11 +- src/scene/assetmanager.cpp | 8 +- src/scene/profile.cpp | 380 ++++++++++-------- src/scene/profilefile.cpp | 41 +- tests/profile/test_common.h | 14 +- tests/profile/test_profile.cpp | 16 +- 19 files changed, 306 insertions(+), 298 deletions(-) diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index e7f534c60c..56337cc78d 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -517,7 +517,7 @@ void mainPostSyncPreDrawFunc() { -void mainRenderFunc(const RenderData& data) { +void mainRenderFunc(const sgct::RenderData& data) { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -592,7 +592,7 @@ void mainRenderFunc(const RenderData& data) { -void mainDraw2DFunc(const RenderData& data) { +void mainDraw2DFunc(const sgct::RenderData& data) { ZoneScoped #ifdef OPENSPACE_HAS_VTUNE @@ -1295,9 +1295,9 @@ int main(int argc, char** argv) { Engine::create(cluster, callbacks, config); } catch (...) { - Engine::destroy(); global::openSpaceEngine.deinitialize(); ghoul::deinitialize(); + Engine::destroy(); throw; } diff --git a/data/assets/default.profile b/data/assets/default.profile index b5614baf84..7d10fb2b71 100644 --- a/data/assets/default.profile +++ b/data/assets/default.profile @@ -3,10 +3,10 @@ #Asset scene/solarsystem/planets/earth/earth required -scene/solarsystem/planets/earth/satellites/satellites required +scene/solarsystem/planets/earth/satellites/satellites required #Property -setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValue {earth_satellites}.Renderable.Enabled false #Time relative -1d diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 76c06f8fd7..07838dc8c0 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -77,7 +77,7 @@ public: const glm::mat4& projectionMatrix); void drawOverlays(); void postDraw(); - std::vector listOfAllAssetEvents(); + std::vector assetEvents(); void resetAssetChangeTracking(); void resetPropertyChangeFlags(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 779ef9fe42..ce92102ece 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -500,7 +500,7 @@ public: * * \return true if the property has changed */ - bool hasChanged(); + bool hasChanged() const; /** * Reset the valChanged flag to an unchanged state, as if value has not been changed. @@ -544,7 +544,7 @@ protected: std::vector>> _onDeleteCallbacks; /// Flag indicating that this property value has been changed after initialization - bool valChanged = false; + bool _isValueDirty = false; private: void notifyDeleteListeners(); diff --git a/include/openspace/properties/templateproperty.inl b/include/openspace/properties/templateproperty.inl index 78af3f6039..f8bdb0ecd3 100644 --- a/include/openspace/properties/templateproperty.inl +++ b/include/openspace/properties/templateproperty.inl @@ -176,7 +176,7 @@ void openspace::properties::TemplateProperty::setValue(T val) { if (val != _value) { _value = std::move(val); notifyChangeListeners(); - valChanged = true; + _isValueDirty = true; } } @@ -197,7 +197,7 @@ void TemplateProperty::set(std::any value) { if (v != _value) { _value = std::move(v); notifyChangeListeners(); - valChanged = true; + _isValueDirty = true; } } diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index fbb7db24e2..dd7a1fb0af 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -174,12 +174,12 @@ public: * Retrieve a reference to vector list of all assets events, including require, * request, and remove */ - std::vector& listOfAllAssetEvents(); + const std::vector& assetEvents() const; /** * Clear lists of all assets that have been either requested, required, or removed */ - void listOfAllAssetEvents_reset(); + void resetAssetEvents(); private: std::shared_ptr require(const std::string& identifier); @@ -241,9 +241,6 @@ private: int _assetsTableRef; std::vector _profileAssets; - std::vector _profileAssetsRequired; - std::vector _profileAssetsRequested; - std::vector _profileAssetsRemoved; }; } // namespace openspace diff --git a/include/openspace/scene/assetmanager.h b/include/openspace/scene/assetmanager.h index db010c7d02..6caa9a66b4 100644 --- a/include/openspace/scene/assetmanager.h +++ b/include/openspace/scene/assetmanager.h @@ -71,8 +71,8 @@ public: std::shared_ptr child) override; bool update(); - const std::vector& listOfAllAssetEvents() const; - void listOfAllAssetEvents_reset(); + const std::vector& assetEvents() const; + void resetAssetEvents(); scripting::LuaLibrary luaLibrary(); private: diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index c758f97af2..89ad550fe2 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -25,9 +25,8 @@ #ifndef __OPENSPACE_CORE___PROFILE___H__ #define __OPENSPACE_CORE___PROFILE___H__ -#include - #include +#include #include #include #include @@ -45,24 +44,18 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } -const std::string profileFormatVersion = "1.0"; - class Profile { public: + static constexpr const char* FormatVersion = "1.0"; + enum class AssetEventType { - add, - require, - request, - remove, - ignore - }; - const std::map AssetEventTypeString { - {AssetEventType::add, "add"}, - {AssetEventType::require, "required"}, - {AssetEventType::request, "requested"}, - {AssetEventType::remove, "removed"}, - {AssetEventType::ignore, "ignored"}, + Add, + Require, + Request, + Remove, + Ignore }; + struct AssetEvent { std::string name; AssetEventType eventType; @@ -70,16 +63,12 @@ public: virtual ~Profile() {}; - const std::string formatVersion() { - return profileFormatVersion; - } - /** * Saves all current settings, starting from the profile that was loaded at startup, * and all of the property & asset changes that were made since startup. * \param filename The filename of the new profile to be saved */ - void saveCurrentSettingsToProfile(std::string filename); + void saveCurrentSettingsToProfile(const std::string& filename); /** * Saves all current settings, similar to saveCurrentSettingsToProfile() except the @@ -94,8 +83,8 @@ public: * \param outFilePath The output file path that will be written with the converted * contents (in an .asset file) */ - void convertToSceneFile(const std::string inProfilePath, - const std::string outFilePath); + void convertToSceneFile(const std::string& inProfilePath, + const std::string& outFilePath); /** * Returns the string contents of a profileFile object converted to scene/asset @@ -120,10 +109,10 @@ private: std::vector base; std::vector changed; }; - virtual bool usingProfile(); - virtual std::string initialProfile(); - virtual std::string profileBaseDirectory(); - virtual std::vector listOfAllAssetEvents(); + virtual bool usingProfile() const; + virtual std::string initialProfile() const; + virtual std::string profileBaseDirectory() const; + virtual std::vector assetEvents() const; ProfileFile collateBaseWithChanges(); std::string convertToScene_assets(ProfileFile& pf); std::string convertToScene_modules(ProfileFile& pf); @@ -133,23 +122,16 @@ private: std::string convertToScene_time(ProfileFile& pf); std::string convertToScene_camera(ProfileFile& pf); - void updateToCurrentFormatVersion(ProfileFile& pf); std::vector modifyAssetsToReflectChanges(ProfileFile& pf); void parseAssetFileLines(std::vector& results, ProfileFile& pf); - void handleChangedAdd(std::vector& base, unsigned int changedIdx, - std::vector& changed, std::string asset); - void handleChangedRemove(std::vector& base, std::string asset); - void addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf); + void modifyPropertiesToReflectChanges(ProfileFile& pf); - virtual std::vector getChangedProperties(); - void checkForChangedProps(std::vector& changedList, - openspace::properties::PropertyOwner* po); + virtual std::vector changedProperties(); std::string getFullPropertyPath(openspace::properties::Property* prop); - virtual std::vector getChangedPropertiesFormatted(); - virtual std::string getCurrentTimeUTC(); - virtual interaction::NavigationHandler::NavigationState getCurrentCameraState(); - void addCurrentTimeToProfileFile(ProfileFile& pf); - void addCurrentCameraToProfileFile(ProfileFile& pf); + virtual std::vector changedPropertiesFormatted(); + virtual std::string currentTimeUTC() const; + virtual interaction::NavigationHandler::NavigationState currentCameraState() const; + void addCurrentCameraToProfileFile(ProfileFile& pf) const; }; } // namespace openspace diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 807daf8cfd..840245fc86 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -150,21 +150,21 @@ public: * form. * \param filename The filename to write to. */ - void writeToFile(const std::string filename); + void writeToFile(const std::string& filename); /** * Updates the full string that defines the starting time. The format for this line * is defined by ProfileFile::parseTime and Profile::convertToAsset_time * \param line The time entry line to replace current time entry */ - void updateTime(const std::string line); + void updateTime(std::string line); /** * Updates the full string that defines the starting camera position. The format for * this line is defined by ProfileFile::parseCamera & Profile::convertToAsset_camera * \param line The camera entry line to replace current camera entry */ - void updateCamera(const std::string line); + void updateCamera(std::string line); /** * Adds a new module line to the list of module lines to be analyzed by the profile @@ -172,14 +172,14 @@ public: * and Profile::convertToAsset_modules * \param line The module name to be added */ - void addModuleLine(const std::string line); + void addModuleLine(std::string line); /** * Adds a new asset to the list of assets to be loaded at startup. The format for an * asset line is defined by ProfileFile::parseAsset & Profile::convertToAsset_assets * \param line The asset name to be added */ - void addAssetLine(const std::string line); + void addAssetLine(std::string line); /** * Clears all asset entries @@ -192,7 +192,7 @@ public: * ProfileFile::parseProperty and Profile::convertToAsset_properties * \param line The property set command to be added */ - void addPropertyLine(const std::string line); + void addPropertyLine(std::string line); /** * Adds a new keybinding shortcut to the list of keybindings. The format for a @@ -200,7 +200,7 @@ public: * Profile::convertToAsset_keybindings * \param line The keyboard shortcut line to be added */ - void addKeybindingLine(const std::string line); + void addKeybindingLine(std::string line); /** * Adds a new scenegraph node name to be added to the list of those marked as @@ -208,7 +208,7 @@ public: * ProfileFile::parseMarkNodes and Profile::convertToAsset_markNodes * \param line The scenegraph node to be added */ - void addMarkNodesLine(const std::string line); + void addMarkNodesLine(std::string line); /** * Returns the format version number (profiles syntax version) string diff --git a/modules/imgui/src/gui.cpp b/modules/imgui/src/gui.cpp index f1d2d3ffcd..04a6dd092b 100644 --- a/modules/imgui/src/gui.cpp +++ b/modules/imgui/src/gui.cpp @@ -190,16 +190,13 @@ GUI::GUI() GUI::~GUI() {} // NOLINT -void GUI::initialize() { - -} +void GUI::initialize() {} void GUI::deinitialize() { ImGui::Shutdown(); - int nWindows = global::windowDelegate.nWindows(); - for (int i = 0; i < nWindows; ++i) { - ImGui::DestroyContext(_contexts[i]); + for (ImGuiContext* ctx : _contexts) { + ImGui::DestroyContext(ctx); } for (GuiComponent* comp : _components) { diff --git a/openspace.cfg b/openspace.cfg index a557e5468d..0bf64655ba 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -45,7 +45,7 @@ SGCTConfig = sgct.config.single{} -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace -Asset = "default" +-- Asset = "default" -- Asset = "asteroids" -- Asset = "default_full" -- Asset = "newhorizons" @@ -64,7 +64,7 @@ Asset = "default" -- Sets the profile that should be loaded by OpenSpace. Profiles are going to replace -- assets in a future versions and shouldn't be used at the same time as the 'Asset' -- setting above --- Profile = "default" +Profile = "default" -- These scripts are executed after the initialization of each scene, thus making -- it possible to have global overrides to default values or execute other scripts diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 10c4b9d9c8..576ae5372b 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1286,11 +1286,11 @@ void OpenSpaceEngine::postDraw() { } void OpenSpaceEngine::resetAssetChangeTracking() { - global::openSpaceEngine._assetManager->listOfAllAssetEvents_reset(); + global::openSpaceEngine._assetManager->resetAssetEvents(); } -std::vector OpenSpaceEngine::listOfAllAssetEvents() { - return global::openSpaceEngine._assetManager->listOfAllAssetEvents(); +std::vector OpenSpaceEngine::assetEvents() { + return global::openSpaceEngine._assetManager->assetEvents(); } void OpenSpaceEngine::resetPropertyChangeFlags() { diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 1bedc86ac7..85f2f6fdd9 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -312,12 +312,12 @@ void Property::notifyDeleteListeners() { } } -bool Property::hasChanged() { - return valChanged; +bool Property::hasChanged() const { + return _isValueDirty; } void Property::resetToUnchanged() { - valChanged = false; + _isValueDirty = false; } std::string Property::generateBaseJsonDescription() const { diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 31bfa3e180..d4ec30c2f4 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -456,7 +456,7 @@ std::shared_ptr AssetLoader::request(const std::string& identifier) { } void AssetLoader::addToProfileTracking(std::string asset, Profile::AssetEventType type) { - Profile::AssetEvent pa = {asset, type}; + Profile::AssetEvent pa = { std::move(asset), type }; _profileAssets.push_back(pa); } @@ -478,7 +478,7 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const { std::shared_ptr AssetLoader::add(const std::string& identifier) { setCurrentAsset(_rootAsset); - addToProfileTracking(identifier, Profile::AssetEventType::add); + addToProfileTracking(identifier, Profile::AssetEventType::Add); return request(identifier); } @@ -486,8 +486,7 @@ std::shared_ptr AssetLoader::add(const std::string& identifier) { void AssetLoader::remove(const std::string& identifier) { setCurrentAsset(_rootAsset); unrequest(identifier); - _profileAssetsRemoved.push_back(identifier); - addToProfileTracking(identifier, Profile::AssetEventType::remove); + addToProfileTracking(identifier, Profile::AssetEventType::Remove); } std::shared_ptr AssetLoader::has(const std::string& identifier) const { @@ -814,11 +813,11 @@ void AssetLoader::assetUnrequested(std::shared_ptr parent, } } -std::vector& AssetLoader::listOfAllAssetEvents() { +const std::vector& AssetLoader::assetEvents() const { return _profileAssets; } -void AssetLoader::listOfAllAssetEvents_reset() { +void AssetLoader::resetAssetEvents() { _profileAssets.clear(); } diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index d9d8e5e12e..bb98f0d0cf 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -121,12 +121,12 @@ std::shared_ptr AssetManager::rootAsset() { return _assetLoader->rootAsset(); } -const std::vector& AssetManager::listOfAllAssetEvents() const { - return _assetLoader->listOfAllAssetEvents(); +const std::vector& AssetManager::assetEvents() const { + return _assetLoader->assetEvents(); } -void AssetManager::listOfAllAssetEvents_reset() { - _assetLoader->listOfAllAssetEvents_reset(); +void AssetManager::resetAssetEvents() { + _assetLoader->resetAssetEvents(); } scripting::LuaLibrary AssetManager::luaLibrary() { diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 1da60105df..3728d9e7ee 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -51,15 +51,104 @@ #include "profile_lua.inl" +namespace openspace { + namespace { constexpr const char* _loggerCat = "Profile"; constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeyParent = "Parent"; + + const std::map AssetEventTypeString{ + { Profile::AssetEventType::Add, "add" }, + { Profile::AssetEventType::Require, "required" }, + { Profile::AssetEventType::Request, "requested" }, + { Profile::AssetEventType::Remove, "removed" }, + { Profile::AssetEventType::Ignore, "ignored" }, + }; + + void handleChangedAdd(std::vector& base, unsigned int changedIdx, + std::vector& changed, std::string asset) + { + // @TODO: Replace the next for loop with std::any_of or std::all_of + + bool addThisAsset = true; + // Check base profile to see if has already been added there + for (const Profile::AssetEvent& b : base) { + if (b.name == asset) { + if (b.eventType == Profile::AssetEventType::Require + || b.eventType == Profile::AssetEventType::Request) + { + addThisAsset = false; + break; + } + } + } + + // Check changed asset commands only prior to this one to see if already added + for (unsigned int i = 0; i < changedIdx; i++) { + if (changed[i].name == asset) { + addThisAsset = false; + break; + } + } + + if (addThisAsset) { + Profile::AssetEvent ae = { + std::move(asset), + Profile::AssetEventType::Request + }; + base.push_back(ae); + } + } + + void handleChangedRemove(std::vector& base, std::string asset) { + base.push_back({ std::move(asset), Profile::AssetEventType::Remove }); + } + + void addAssetsToProfileFile(ProfileFile& pf, + const std::vector& allAssets) + { + pf.clearAssets(); + for (Profile::AssetEvent a : allAssets) { + if (a.eventType != Profile::AssetEventType::Ignore) { + std::string entry = + a.name + "\t" + AssetEventTypeString.at(a.eventType); + pf.addAssetLine(entry); + } + } + } + + std::string recurseForFullName(properties::PropertyOwner* po) { + if (po == nullptr) { + return ""; + } + std::string name = recurseForFullName(po->owner()) + po->identifier(); + if (!name.empty()) { + return name + "."; + } + else { + return ""; + } + } + + void checkForChangedProps(std::vector& changedList, + properties::PropertyOwner* po) + { + if (po) { + for (properties::PropertyOwner* subOwner : po->propertySubOwners()) { + checkForChangedProps(changedList, subOwner); + } + for (properties::Property* p : po->properties()) { + if (p->hasChanged()) { + changedList.push_back(p); + } + } + } + } + } // namespace -namespace openspace { - -void Profile::saveCurrentSettingsToProfile(std::string filename) { +void Profile::saveCurrentSettingsToProfile(const std::string& filename) { ProfileFile pf = collateBaseWithChanges(); pf.writeToFile(filename); } @@ -69,112 +158,67 @@ std::string Profile::saveCurrentSettingsToProfile_string() { return pf.writeToString(); } -bool Profile::usingProfile() { +bool Profile::usingProfile() const { return global::configuration.usingProfile; } -std::string Profile::initialProfile() { +std::string Profile::initialProfile() const { return global::configuration.profile; } -std::vector Profile::listOfAllAssetEvents() { - return global::openSpaceEngine.listOfAllAssetEvents(); +std::vector Profile::assetEvents() const { + return global::openSpaceEngine.assetEvents(); } -std::string Profile::profileBaseDirectory() { +std::string Profile::profileBaseDirectory() const { return _profileBaseDirectory; } ProfileFile Profile::collateBaseWithChanges() { - if (! usingProfile()) { + if (!usingProfile()) { std::string errorMessage = "Program was not started using a profile, " - "so cannot use this save-current-settings feature."; + "so cannot use this save-current-settings feature"; LERROR(errorMessage); } std::string initProfile = initialProfile(); std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + ".profile"; ProfileFile pf(inputProfilePath); - updateToCurrentFormatVersion(pf); + pf.setVersion(FormatVersion); std::vector ass = modifyAssetsToReflectChanges(pf); - addAssetsToProfileFile(ass, pf); + addAssetsToProfileFile(pf, ass); modifyPropertiesToReflectChanges(pf); - addCurrentTimeToProfileFile(pf); + + // add current time to profile file + std::string t = currentTimeUTC(); + std::string update = "absolute\t" + t; + pf.updateTime(update); + addCurrentCameraToProfileFile(pf); return pf; } -void Profile::updateToCurrentFormatVersion(ProfileFile& pf) { - pf.setVersion(profileFormatVersion); -} - std::vector Profile::modifyAssetsToReflectChanges(ProfileFile& pf) { std::vector a; parseAssetFileLines(a, pf); AllAssetDetails assetDetails; assetDetails.base = a; - assetDetails.changed = listOfAllAssetEvents(); + assetDetails.changed = assetEvents(); for (unsigned int i = 0; i < assetDetails.changed.size(); i++) { AssetEvent event = assetDetails.changed[i]; - if (event.eventType == AssetEventType::add) { + if (event.eventType == AssetEventType::Add) { handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); } - else if (event.eventType == AssetEventType::remove) { + else if (event.eventType == AssetEventType::Remove) { handleChangedRemove(assetDetails.base, event.name); } } return assetDetails.base; } -void Profile::handleChangedAdd(std::vector& base, unsigned int changedIdx, - std::vector& changed, std::string asset) -{ - bool addThisAsset = true; - //Check base profile to see if has already been added there - for (auto b : base) { - if (b.name == asset ) { - if ( b.eventType == AssetEventType::require - || b.eventType == AssetEventType::request) - { - addThisAsset = false; - break; - } - } - } - - //Check changed asset commands only prior to this one to see if already added - for (unsigned int i = 0; i < changedIdx; i++) { - if (changed[i].name == asset) { - addThisAsset = false; - break; - } - } - - if (addThisAsset) { - AssetEvent ae = {asset, AssetEventType::request}; - base.push_back(ae); - } -} - -void Profile::handleChangedRemove(std::vector& base, std::string asset) -{ - base.push_back({asset, AssetEventType::remove}); -} - -void Profile::addAssetsToProfileFile(std::vector& allAssets, ProfileFile& pf) -{ - pf.clearAssets(); - for (AssetEvent a : allAssets) { - if (a.eventType != AssetEventType::ignore) { - std::string entry = a.name + "\t" + AssetEventTypeString.at(a.eventType); - pf.addAssetLine(entry); - } - } -} - void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf) { std::vector elements; AssetEvent a; @@ -183,25 +227,29 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf.splitByTab(line, elements); if (elements[0].empty()) { - LERROR("Error in parsing asset file line '" + line - + "'. Asset name is needed (field 1/2)."); + LERROR(fmt::format( + "Error parsing profile line '{}'. Asset name is needed (field 1/2)", + line + )); } else { a.name = elements[0]; } - if (elements[1] == AssetEventTypeString.at(AssetEventType::require)) { - a.eventType = AssetEventType::require; + if (elements[1] == AssetEventTypeString.at(AssetEventType::Require)) { + a.eventType = AssetEventType::Require; } - else if (elements[1] == AssetEventTypeString.at(AssetEventType::request)) { - a.eventType = AssetEventType::request; + else if (elements[1] == AssetEventTypeString.at(AssetEventType::Request)) { + a.eventType = AssetEventType::Request; } else if (elements[1] == "") { - a.eventType = AssetEventType::request; + a.eventType = AssetEventType::Request; } else { - LERROR("Error in parsing asset file line '" + line - + "'. Invalid required param (field 2/2)."); + LERROR(fmt::format( + "Error parsing profile line '{}'. Invalid required param (field 2/2)", + line + )); } results.push_back(a); @@ -209,19 +257,18 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileFile& } void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { - std::vector formatted = getChangedPropertiesFormatted(); + std::vector formatted = changedPropertiesFormatted(); - for (std::string line: formatted) { - pf.addPropertyLine(line); + for (std::string line : formatted) { + pf.addPropertyLine(std::move(line)); } } -std::vector Profile::getChangedPropertiesFormatted() { - std::vector changedProps - = getChangedProperties(); +std::vector Profile::changedPropertiesFormatted() { + std::vector changedProps = changedProperties(); std::vector formattedLines; - for (auto prop : changedProps) { + for (properties::Property* prop : changedProps) { std::string newLine = "setPropertyValueSingle\t"; newLine += getFullPropertyPath(prop) + "\t"; newLine += prop->getStringValue(); @@ -230,69 +277,35 @@ std::vector Profile::getChangedPropertiesFormatted() { return formattedLines; } -std::string recurseForFullName(openspace::properties::PropertyOwner* po) { - std::string path; - if (po != nullptr) { - std::string name = recurseForFullName(po->owner()) + po->identifier(); - if (!name.empty()) { - path = name + "."; - } - } - return path; -} - -std::string Profile::getFullPropertyPath(openspace::properties::Property* prop) { +std::string Profile::getFullPropertyPath(properties::Property* prop) { return recurseForFullName(prop->owner()) + prop->identifier(); } -void Profile::checkForChangedProps( - std::vector& changedList, - openspace::properties::PropertyOwner* po) -{ - if (po != nullptr) { - for (auto subOwner : po->propertySubOwners()) { - checkForChangedProps(changedList, subOwner); - } - for (auto p : po->properties()) { - if (p->hasChanged()) { - changedList.push_back(p); - } - } - } -} - -std::vector Profile::getChangedProperties() -{ +std::vector Profile::changedProperties() { ZoneScoped - std::vector nodes + std::vector nodes = global::renderEngine.scene()->allSceneGraphNodes(); - std::vector changedProps; + std::vector changedProps; - for (auto n : nodes) { + for (SceneGraphNode* n : nodes) { checkForChangedProps(changedProps, n); } return changedProps; } -std::string Profile::getCurrentTimeUTC() { +std::string Profile::currentTimeUTC() const { return global::timeManager.time().ISO8601(); } -void Profile::addCurrentTimeToProfileFile(ProfileFile& pf) { - std::string t = getCurrentTimeUTC(); - std::string update = "absolute\t" + t; - pf.updateTime(update); -} - -interaction::NavigationHandler::NavigationState Profile::getCurrentCameraState() { +interaction::NavigationHandler::NavigationState Profile::currentCameraState() const { return global::navigationHandler.navigationState(); } -void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { +void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) const { std::string update = "setNavigationState\t"; interaction::NavigationHandler::NavigationState nav; - nav = getCurrentCameraState(); + nav = currentCameraState(); update += "\"" + nav.anchor + "\"\t"; update += "\"" + nav.aim + "\"\t"; update += "\"" + nav.referenceFrame + "\"\t"; @@ -313,8 +326,8 @@ void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) { pf.updateCamera(update); } -void Profile::convertToSceneFile(const std::string inProfilePath, - const std::string outFilePath) +void Profile::convertToSceneFile(const std::string& inProfilePath, + const std::string& outFilePath) { ZoneScoped @@ -324,7 +337,7 @@ void Profile::convertToSceneFile(const std::string inProfilePath, try { outFile.open(outFilePath, std::ofstream::out); } - catch (std::ofstream::failure& e) { + catch (const std::ofstream::failure& e) { LERROR("Exception opening scene file for write: " + outFilePath + " (" + e.what() + ")"); } @@ -332,7 +345,7 @@ void Profile::convertToSceneFile(const std::string inProfilePath, try { outFile << convertToScene(pf); } - catch (std::ofstream::failure& e) { + catch (const std::ofstream::failure& e) { LERROR("Data write error to scene file: " + outFilePath + " (" + e.what() + ")"); } @@ -340,7 +353,7 @@ void Profile::convertToSceneFile(const std::string inProfilePath, try { outFile.close(); } - catch (std::ofstream::failure& e) { + catch (const std::ofstream::failure& e) { LERROR("Exception closing scene file after write: " + outFilePath + " (" + e.what() + ")"); } @@ -371,18 +384,23 @@ std::string Profile::convertToScene_modules(ProfileFile& pf) { for (std::string m : pf.modules()) { pf.splitByTab(m, fields); - if (fields[moduleFieldLoaded] != "" && fields[moduleFieldNotLoaded] != "") { - result += "if openspace.modules.isLoaded(\"" + fields[moduleFieldName]; - result += "\") then\n " + fields[moduleFieldLoaded] + "\nelse\n"; - result += " " + fields[moduleFieldNotLoaded] + "\nend\n"; + if (!fields[moduleFieldLoaded].empty() && !fields[moduleFieldNotLoaded].empty()) { + result += fmt::format( + "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", + fields[moduleFieldName], fields[moduleFieldLoaded], fields[moduleFieldNotLoaded] + ); } - else if (fields[moduleFieldNotLoaded] == "") { - result += "if not openspace.modules.isLoaded(\"" + fields[moduleFieldName]; - result += "\") then\n " + fields[moduleFieldNotLoaded] + "\nend\n"; + else if (fields[moduleFieldNotLoaded].empty()) { + result += fmt::format( + "if not openspace.modules.isLoaded(\"{}\") then {} end\n", + fields[moduleFieldName], fields[moduleFieldNotLoaded] + ); } - else if (fields[moduleFieldLoaded] == "") { - result += "if openspace.modules.isLoaded(\"" + fields[moduleFieldName]; - result += "\") then\n " + fields[moduleFieldLoaded] + "\nend\n"; + else if (fields[moduleFieldLoaded].empty()) { + result += fmt::format( + "if openspace.modules.isLoaded(\"{}\") then {} end\n", + fields[moduleFieldName], fields[moduleFieldLoaded] + ); } } return result; @@ -413,12 +431,13 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { assetR = "require"; } else { - std::string err = "Asset " + std::to_string(i + 1) + " of "; - err += std::to_string(pf.assets().size()) + " has bad arg 2/2 which must "; - err += "be either 'required' or 'requested'"; + std::string err = fmt::format( + "Asset {} of {} has bad arg 2/2 which must be 'required' or 'requested'", + i + 1, pf.assets().size() + ); throw ghoul::RuntimeError(err); } - result += "asset." + assetR + "(\"" + fields[assetFieldName] + "\")\n"; + result += fmt::format("asset.{}(\"{}\")\n", assetR, fields[assetFieldName]); } return result; } @@ -434,14 +453,18 @@ std::string Profile::convertToScene_properties(ProfileFile& pf) { if (fields[propertyFieldType] != "setPropertyValue" && fields[propertyFieldType] != "setPropertyValueSingle") { - std::string err = "Property" + std::to_string(i + 1) + " of "; - err += std::to_string(pf.properties().size()) + " has bad arg 1/1 which "; - err += "must be either 'setPropertyValue' or 'setPropertyValueSingle'"; + std::string err = fmt::format( + "Property {} of {} has bad arg 1/1 which must be " + "'setPropertyValue' or 'setPropertyValueSingle'", + i + 1, pf.properties().size() + ); throw ghoul::RuntimeError(err); } else { - result += " openspace." + fields[propertyFieldType] + "(\"" - + fields[propertyFieldName] + "\", " + fields[propertyFieldValue] + ")\n"; + result += fmt::format( + " openspace.{}(\"{}\", {})\n", + fields[propertyFieldType], fields[propertyFieldName], fields[propertyFieldValue] + ); } } return result; @@ -458,12 +481,12 @@ std::string Profile::convertToScene_keybindings(ProfileFile& pf) { pf.splitByTab(k, fields); result += " {\n"; - result += " Key = \"" + fields[0] + "\",\n"; - result += " Documentation = \"" + fields[1] + "\",\n"; - result += " Name = \"" + fields[2] + "\",\n"; - result += " GuiPath = \"" + fields[3] + "\",\n"; - result += " Local = " + fields[4] + ",\n"; - result += " Command = " + fields[5] + "\n"; + result += fmt::format(" {} = \"{}\",\n", "Key", fields[0]); + result += fmt::format(" {} = \"{}\",\n", "Documentation", fields[1]); + result += fmt::format(" {} = \"{}\",\n", "Name", fields[2]); + result += fmt::format(" {} = \"{}\",\n", "GuiPath", fields[3]); + result += fmt::format(" {} = \"{}\",\n", "Local", fields[4]); + result += fmt::format(" {} = \"{}\"\n", "Command", fields[5]); result += " },\n"; } result += "}\n"; @@ -473,10 +496,10 @@ std::string Profile::convertToScene_keybindings(ProfileFile& pf) { std::string Profile::convertToScene_markNodes(ProfileFile& pf) { std::string result; - if (pf.markNodes().size() > 0) { + if (!pf.markNodes().empty()) { result += " openspace.markInterestingNodes({"; - for (std::string m : pf.markNodes()) { - result += "\"" + m + "\", "; + for (const std::string& m : pf.markNodes()) { + result += fmt::format("\"{}\",", m); } result += "})\n"; } @@ -491,9 +514,14 @@ std::string Profile::convertToScene_time(ProfileFile& pf) { pf.splitByTab(pf.time(), fields); if (fields[timeFieldType] == "absolute") { - result += " openspace.time.setTime(\"" + fields[timeFieldSet] + "\")\n"; + result += fmt::format(" openspace.time.setTime(\"{}\")\n", fields[timeFieldSet]); } else if (fields[timeFieldType] == "relative") { + result += fmt::format( + " openspace.time.setTime(openspace.time.advancedTime(" + "openspace.time.currentWallTime(), \"{}\"))\n", + fields[timeFieldSet] + ); result += " local now = openspace.time.currentWallTime(); "; result += "openspace.time.setTime("; result += "openspace.time.advancedTime(now, \"" + fields[timeFieldSet] + "\"))\n"; @@ -514,41 +542,41 @@ std::string Profile::convertToScene_camera(ProfileFile& pf) { if (fields[cameraFieldType] == "setNavigationState") { result += " openspace.navigation.setNavigationState({"; - result += "Anchor = " + fields[cameraNavigationFieldAnchor] + ", "; - if (fields[cameraNavigationFieldAim] != "") { - result += "Aim = " + fields[cameraNavigationFieldAim] + ", "; + result += fmt::format("Anchor = {}, ", fields[cameraNavigationFieldAnchor]); + if (!fields[cameraNavigationFieldAim].empty()) { + result += fmt::format("Aim = {}, ", fields[cameraNavigationFieldAim]); } - if (fields[cameraNavigationFieldRef] != "") { - result += "ReferenceFrame = " + fields[cameraNavigationFieldRef] + ", "; + if (!fields[cameraNavigationFieldRef].empty()) { + result += fmt::format("ReferenceFrame = {}, ", fields[cameraNavigationFieldRef]); } - result += "Position = {" + fields[cameraNavigationFieldPosition] + "}, "; - if (fields[cameraNavigationFieldUp] != "") { - result += "Up = {" + fields[cameraNavigationFieldUp] + "}, "; + result += fmt::format("Position = {{ {} }}, ", fields[cameraNavigationFieldPosition]); + if (!fields[cameraNavigationFieldUp].empty()) { + result += fmt::format("Up = {{ {} }}, ", fields[cameraNavigationFieldUp]); } - if (fields[cameraNavigationFieldYaw] != "") { - result += "Yaw = " + fields[cameraNavigationFieldYaw] + ", "; + if (!fields[cameraNavigationFieldYaw].empty()) { + result += fmt::format("Yaw = {}, ", fields[cameraNavigationFieldYaw]); } - if (fields[cameraNavigationFieldPitch] != "") { - result += "Pitch = " + fields[cameraNavigationFieldPitch] + " "; + if (!fields[cameraNavigationFieldPitch].empty()) { + result += fmt::format("Pitch = {} ", fields[cameraNavigationFieldPitch]); } result += "})\n"; } else if (fields[cameraFieldType] == "goToGeo") { result += " openspace.globebrowsing.goToGeo({ "; - if (fields[cameraGeoFieldAnchor] != "") { + if (!fields[cameraGeoFieldAnchor].empty()) { result += fields[cameraGeoFieldAnchor] + ", "; } result += fields[cameraGeoFieldLatitude] + ", "; result += fields[cameraGeoFieldLongitude] + ", "; - if (fields[cameraGeoFieldAltitude] != "") { + if (!fields[cameraGeoFieldAltitude].empty()) { result += fields[cameraGeoFieldAltitude] + ", "; } result += ")\n"; } else { - std::string err = "Camera entry's arg 1/1 must be either "; - err += "'setNavigationState' or 'goToGeo'"; - throw ghoul::RuntimeError(err); + throw ghoul::RuntimeError( + "Camera entry's arg 1/1 must be either 'setNavigationState' or 'goToGeo'" + ); } return result; } diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 90029ac412..e68d6c7ec0 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -38,7 +38,6 @@ namespace { constexpr const char* _loggerCat = "ProfileFile"; constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeyParent = "Parent"; - } // namespace namespace openspace { @@ -115,7 +114,7 @@ void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { } } -void ProfileFile::writeToFile(const std::string filename) { +void ProfileFile::writeToFile(const std::string& filename) { if (filename.find("/") != std::string::npos) { LERROR("Profile filename must not contain path (/) elements"); return; @@ -195,11 +194,11 @@ const std::string ProfileFile::getVersion() const { } void ProfileFile::setVersion(std::string v) { - _version = v; + _version = std::move(v); } void ProfileFile::addAllElements(std::string& str, std::vector& list) { - for (auto s : list) { + for (const std::string& s : list) { str += s + '\n'; } } @@ -487,26 +486,32 @@ size_t ProfileFile::splitByTab(std::string line, std::vector& resul return result.size(); } -void ProfileFile::updateTime(const std::string line) { - _time = line; +void ProfileFile::updateTime(std::string line) { + _time = std::move(line); } -void ProfileFile::updateCamera(const std::string line) { - _camera = line; + +void ProfileFile::updateCamera(std::string line) { + _camera = std::move(line); } -void ProfileFile::addModuleLine(const std::string line) { - _modules.push_back(line); + +void ProfileFile::addModuleLine(std::string line) { + _modules.push_back(std::move(line)); } -void ProfileFile::addAssetLine(const std::string line) { - _assets.push_back(line); + +void ProfileFile::addAssetLine(std::string line) { + _assets.push_back(std::move(line)); } -void ProfileFile::addPropertyLine(const std::string line) { - _properties.push_back(line); + +void ProfileFile::addPropertyLine(std::string line) { + _properties.push_back(std::move(line)); } -void ProfileFile::addKeybindingLine(const std::string line) { - _keybindings.push_back(line); + +void ProfileFile::addKeybindingLine(std::string line) { + _keybindings.push_back(std::move(line)); } -void ProfileFile::addMarkNodesLine(const std::string line) { - _markNodes.push_back(line); + +void ProfileFile::addMarkNodesLine(std::string line) { + _markNodes.push_back(std::move(line)); } void ProfileFile::clearAssets() { diff --git a/tests/profile/test_common.h b/tests/profile/test_common.h index fabd2cedeb..44313bfdef 100644 --- a/tests/profile/test_common.h +++ b/tests/profile/test_common.h @@ -422,7 +422,7 @@ end)"; const std::string detectChangedPropsResult_1 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ @@ -456,7 +456,7 @@ Sun\n\ const std::string detectChangedAssetsResult_1 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ @@ -489,7 +489,7 @@ Sun\n\ const std::string detectChangedAssetsResult_2 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ @@ -521,7 +521,7 @@ Sun\n\ const std::string detectChangedAssetsResult_3 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ @@ -553,7 +553,7 @@ Sun\n\ const std::string detectChangedAssetsResult_4 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ @@ -585,7 +585,7 @@ Sun\n\ const std::string detectChangedAssetsResult_5 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ @@ -618,7 +618,7 @@ Sun\n\ const std::string detectChangedAssetsResult_6 = "\ #Version\n\ -" + profileFormatVersion + "\n\ +" + std::string(Profile::FormatVersion) + "\n\ \n\ #Module\n\ \n\ diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 7ca31841f1..99477c1a02 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -56,10 +56,10 @@ namespace { class Profile2 : public Profile { public: Profile2(AssetLoader& refAssetLoader) : _assLoader(refAssetLoader) {} - std::string getCurrentTimeUTC() override { + std::string currentTimeUTC() const override { return "2020-02-29T01:23:45.00"; } - interaction::NavigationHandler::NavigationState getCurrentCameraState() override { + interaction::NavigationHandler::NavigationState currentCameraState() const override { interaction::NavigationHandler::NavigationState n; n.anchor = "Earth"; n.aim = "Sun"; @@ -73,24 +73,24 @@ public: void addPropertiesMarkedAsChanged(std::string formattedLine) { _scenegraphProps.push_back(formattedLine); } - std::vector getChangedPropertiesFormatted() override { + std::vector changedPropertiesFormatted() override { std::vector formattedLines; for (std::string s : _scenegraphProps) { formattedLines.push_back(s); } return formattedLines; } - bool usingProfile() override { + bool usingProfile() const override { return true; } - std::string initialProfile() override { + std::string initialProfile() const override { return _initProfile; } void setInitialProfile(std::string file) { _initProfile = file; } - std::vector listOfAllAssetEvents() override { - return _assLoader.listOfAllAssetEvents(); + std::vector assetEvents() const override { + return _assLoader.assetEvents(); } void setProfileBaseDirectory(std::string dir) { _profileBaseDirectory = dir; @@ -235,7 +235,7 @@ TEST_CASE("profile: Detect new added assets after reset", "[profile]") { asset->initialize(); std::shared_ptr asset2 = assetLoader.add("test2"); asset2->initialize(); - assetLoader.listOfAllAssetEvents_reset(); + assetLoader.resetAssetEvents(); std::shared_ptr asset3 = assetLoader.add("test3"); asset3->initialize(); std::shared_ptr asset4 = assetLoader.add("test4"); From f9d1b030efcf3338c01afea7402e6381a0b085ef Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sun, 14 Jun 2020 18:34:52 +0200 Subject: [PATCH 13/61] Small cleanup --- include/openspace/scene/profilefile.h | 9 ------ src/scene/profile.cpp | 2 +- src/scene/profilefile.cpp | 41 ++++++++++++++++----------- tests/profile/test_common.cpp | 13 --------- 4 files changed, 26 insertions(+), 39 deletions(-) diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 840245fc86..2c4b50fb20 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -81,15 +81,6 @@ const size_t cameraGeoFieldLatitude = 2; const size_t cameraGeoFieldLongitude = 3; const size_t cameraGeoFieldAltitude = 4; -const std::string header_Version = "#Version"; -const std::string header_Module = "#Module"; -const std::string header_Asset = "#Asset"; -const std::string header_Property = "#Property"; -const std::string header_Keybinding = "#Keybinding"; -const std::string header_Time = "#Time"; -const std::string header_Camera = "#Camera"; -const std::string header_MarkNodes = "#MarkNodes"; - class ProfileFile { public: using Lines = std::vector; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 3728d9e7ee..a2934bc530 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -63,7 +63,7 @@ namespace { { Profile::AssetEventType::Require, "required" }, { Profile::AssetEventType::Request, "requested" }, { Profile::AssetEventType::Remove, "removed" }, - { Profile::AssetEventType::Ignore, "ignored" }, + { Profile::AssetEventType::Ignore, "ignored" } }; void handleChangedAdd(std::vector& base, unsigned int changedIdx, diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index e68d6c7ec0..6d57a5728f 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -38,6 +38,15 @@ namespace { constexpr const char* _loggerCat = "ProfileFile"; constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeyParent = "Parent"; + + constexpr const char* headerVersion = "#Version"; + constexpr const char* headerModule = "#Module"; + constexpr const char* headerAsset = "#Asset"; + constexpr const char* headerProperty = "#Property"; + constexpr const char* headerKeybinding = "#Keybinding"; + constexpr const char* headerTime = "#Time"; + constexpr const char* headerCamera = "#Camera"; + constexpr const char* headerMarkNodes = "#MarkNodes"; } // namespace namespace openspace { @@ -165,25 +174,25 @@ void ProfileFile::writeToFile(const std::string& filename) { std::string ProfileFile::writeToString() { std::string output; - output = header_Version + '\n'; + output = headerVersion + '\n'; output += _version + '\n' + '\n'; - output += header_Module + '\n'; + output += headerModule + '\n'; addAllElements(output, _modules); output += '\n'; - output += header_Asset + '\n'; + output += headerAsset + '\n'; addAllElements(output, _assets); output += '\n'; - output += header_Property + '\n'; + output += headerProperty + '\n'; addAllElements(output, _properties); output += '\n'; - output += header_Keybinding + '\n'; + output += headerKeybinding + '\n'; addAllElements(output, _keybindings); output += '\n'; - output += header_Time + '\n'; + output += headerTime + '\n'; output += _time + '\n' + '\n'; - output += header_Camera + '\n'; + output += headerCamera + '\n'; output += _camera + '\n' + '\n'; - output += header_MarkNodes + '\n'; + output += headerMarkNodes + '\n'; addAllElements(output, _markNodes); return output; @@ -233,28 +242,28 @@ bool ProfileFile::isBlank(std::string line) { bool ProfileFile::determineSection(std::string line) { bool foundSection = true; - if (line.compare(header_Version) == 0) { + if (line.compare(headerVersion) == 0) { parseCurrentSection = &ProfileFile::parseVersion; } - else if (line.compare(header_Module) == 0) { + else if (line.compare(headerModule) == 0) { parseCurrentSection = &ProfileFile::parseModule; } - else if (line.compare(header_Asset) == 0) { + else if (line.compare(headerAsset) == 0) { parseCurrentSection = &ProfileFile::parseAsset; } - else if (line.compare(header_Property) == 0) { + else if (line.compare(headerProperty) == 0) { parseCurrentSection = &ProfileFile::parseProperty; } - else if (line.compare(header_Keybinding) == 0) { + else if (line.compare(headerKeybinding) == 0) { parseCurrentSection = &ProfileFile::parseKeybinding; } - else if (line.compare(header_Time) == 0) { + else if (line.compare(headerTime) == 0) { parseCurrentSection = &ProfileFile::parseTime; } - else if (line.compare(header_Camera) == 0) { + else if (line.compare(headerCamera) == 0) { parseCurrentSection = &ProfileFile::parseCamera; } - else if (line.compare(header_MarkNodes) == 0) { + else if (line.compare(headerMarkNodes) == 0) { parseCurrentSection = &ProfileFile::parseMarkNodes; } else { diff --git a/tests/profile/test_common.cpp b/tests/profile/test_common.cpp index f1bf784a97..90d69f626b 100644 --- a/tests/profile/test_common.cpp +++ b/tests/profile/test_common.cpp @@ -100,19 +100,6 @@ std::string stringFromTestProfileFormat(testProfileFormat& tpf) { return fullProfile; } -ProfileFile makeProfileFromString(std::string s) { - std::istringstream iss(s); - - ProfileFile pf([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - }); - - return pf; -} - StringPerLineReader::StringPerLineReader(std::string s) : _iss(s) { } From b64784b1226937139be598dfe1c3bb0a555b3f4b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 15 Jun 2020 10:23:53 +0200 Subject: [PATCH 14/61] First small cleanup --- include/openspace/scene/profilefile.h | 11 ------ src/scene/profile.cpp | 34 +++++----------- src/scene/profilefile.cpp | 56 ++++++++++----------------- 3 files changed, 30 insertions(+), 71 deletions(-) diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 2c4b50fb20..111b7211c7 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -262,17 +262,6 @@ public: */ Lines markNodes() const; - /** - * Splits a tab-delimited line (of any type) into a vector with individual string - * entries. - * \param line The tab-delimited line from which to extract the fields - * \param result A vector of n strings that is populated by the split operation - * \return The number of fields that were extracted - */ - size_t splitByTab(std::string line, std::vector& result); - - - private: std::string errorString(std::string message); void clearAllFields(); diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index a2934bc530..650d1bf62e 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -40,11 +40,12 @@ #include #include #include -#include #include -#include +#include #include +#include #include +#include #include #include #include @@ -220,11 +221,10 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi } void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf) { - std::vector elements; AssetEvent a; for (std::string line : pf.assets()) { - pf.splitByTab(line, elements); + std::vector elements = ghoul::tokenizeString(line, '\t'); if (elements[0].empty()) { LERROR(fmt::format( @@ -380,10 +380,9 @@ std::string Profile::convertToScene(ProfileFile& pf) { std::string Profile::convertToScene_modules(ProfileFile& pf) { std::string result; - std::vector fields; for (std::string m : pf.modules()) { - pf.splitByTab(m, fields); + std::vector fields = ghoul::tokenizeString(m, '\t'); if (!fields[moduleFieldLoaded].empty() && !fields[moduleFieldNotLoaded].empty()) { result += fmt::format( "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", @@ -408,7 +407,6 @@ std::string Profile::convertToScene_modules(ProfileFile& pf) { std::string Profile::convertToScene_assets(ProfileFile& pf) { std::string result; - std::vector fields; std::string assetR; result += "asset.require(\"base\");\n"; @@ -418,8 +416,7 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { result += "local renderableHelper = asset.require(\"util/renderable_helper\")\n"; for (size_t i = 0; i < pf.assets().size(); ++i) { - std::string a = pf.assets()[i]; - pf.splitByTab(a, fields); + std::vector fields = ghoul::tokenizeString(pf.assets()[i], '\t'); if (fields[assetFieldReqd] == "required") { assetR = "require"; @@ -444,11 +441,9 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { std::string Profile::convertToScene_properties(ProfileFile& pf) { std::string result; - std::vector fields; for (size_t i = 0; i < pf.properties().size(); ++i) { - std::string p = pf.properties()[i]; - pf.splitByTab(p, fields); + std::vector fields = ghoul::tokenizeString(pf.properties()[i], '\t'); if (fields[propertyFieldType] != "setPropertyValue" && fields[propertyFieldType] != "setPropertyValueSingle") @@ -472,13 +467,10 @@ std::string Profile::convertToScene_properties(ProfileFile& pf) { std::string Profile::convertToScene_keybindings(ProfileFile& pf) { std::string result; - std::vector fields; - std::string assetR; result += "local Keybindings = {\n"; for (size_t i = 0; i < pf.keybindings().size(); ++i) { - std::string k = pf.keybindings()[i]; - pf.splitByTab(k, fields); + std::vector fields = ghoul::tokenizeString(pf.keybindings()[i], '\t'); result += " {\n"; result += fmt::format(" {} = \"{}\",\n", "Key", fields[0]); @@ -508,11 +500,8 @@ std::string Profile::convertToScene_markNodes(ProfileFile& pf) { std::string Profile::convertToScene_time(ProfileFile& pf) { std::string result; - std::vector fields; - std::string assetR; - - pf.splitByTab(pf.time(), fields); + std::vector fields = ghoul::tokenizeString(pf.time(), '\t'); if (fields[timeFieldType] == "absolute") { result += fmt::format(" openspace.time.setTime(\"{}\")\n", fields[timeFieldSet]); } @@ -535,11 +524,8 @@ std::string Profile::convertToScene_time(ProfileFile& pf) { std::string Profile::convertToScene_camera(ProfileFile& pf) { std::string result; - std::vector fields; - std::string assetR; - - pf.splitByTab(pf.camera(), fields); + std::vector fields = ghoul::tokenizeString(pf.camera(), '\t'); if (fields[cameraFieldType] == "setNavigationState") { result += " openspace.navigation.setNavigationState({"; result += fmt::format("Anchor = {}, ", fields[cameraNavigationFieldAnchor]); diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 6d57a5728f..7930865b2e 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -308,13 +309,12 @@ ProfileFile::Lines ProfileFile::markNodes() const { } void ProfileFile::parseVersion(std::string line) { - std::vector fields; - if (++_numLinesVersion > versionLinesExpected) { throw ghoul::RuntimeError(errorString("Too many lines in Version section"), "profileFile"); } - if (splitByTab(line, fields) > versionFieldsExpected) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() > versionFieldsExpected) { throw ghoul::RuntimeError(errorString("No tabs allowed in Version entry"), "profileFile"); } @@ -324,9 +324,9 @@ void ProfileFile::parseVersion(std::string line) { } void ProfileFile::parseModule(std::string line) { - std::vector fields; + std::vector fields = ghoul::tokenizeString(line, '\t'); - if (splitByTab(line, fields) != moduleFieldsExpected) { + if (fields.size() != moduleFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(moduleFieldsExpected) + " fields required in a Module entry"), "profileFile"); } @@ -340,8 +340,8 @@ void ProfileFile::parseModule(std::string line) { } void ProfileFile::parseAsset(std::string line) { - std::vector fields; - if (splitByTab(line, fields) != assetFieldsExpected) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != assetFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(assetFieldsExpected) + " fields required in an Asset entry"), "profileFile"); } @@ -354,9 +354,9 @@ void ProfileFile::parseAsset(std::string line) { } void ProfileFile::parseProperty(std::string line) { - std::vector fields; + std::vector fields = ghoul::tokenizeString(line, '\t'); - if (splitByTab(line, fields) != propertyFieldsExpected) { + if (fields.size() != propertyFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(propertyFieldsExpected) + " fields required in Property entry"), "profileFile"); } @@ -370,9 +370,9 @@ void ProfileFile::parseProperty(std::string line) { } void ProfileFile::parseKeybinding(std::string line) { - std::vector fields; + std::vector fields = ghoul::tokenizeString(line, '\t'); - if (splitByTab(line, fields) != keybindingFieldsExpected) { + if (fields.size() != keybindingFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(keybindingFieldsExpected) + " fields required in Keybinding entry"), "profileFile"); } @@ -389,13 +389,13 @@ void ProfileFile::parseKeybinding(std::string line) { } void ProfileFile::parseTime(std::string line) { - std::vector fields; - if (++_numLinesTime > timeLinesExpected) { throw ghoul::RuntimeError(errorString("Too many lines in time section"), "profileFile"); } - if (splitByTab(line, fields) != timeFieldsExpected) { + + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != timeFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(timeFieldsExpected) + " fields required in Time entry"), "profileFile"); } @@ -408,14 +408,14 @@ void ProfileFile::parseTime(std::string line) { } void ProfileFile::parseCamera(std::string line) { - std::vector fields; + std::vector fields = ghoul::tokenizeString(line, '\t'); if (++_numLinesCamera > cameraLinesExpected) { throw ghoul::RuntimeError(errorString("Too many lines in camera section"), "profileFile"); } - size_t nFields = splitByTab(line, fields); - if (nFields == cameraNavigationFieldsExpected) { + + if (fields.size() == cameraNavigationFieldsExpected) { std::vector standard = { "Type of camera set (setNavigationState)", "setNavigationState Anchor", @@ -429,7 +429,7 @@ void ProfileFile::parseCamera(std::string line) { verifyRequiredFields("Camera navigation", fields, standard, cameraNavigationFieldsExpected); } - else if (nFields == cameraGeoFieldsExpected) { + else if (fields.size() == cameraGeoFieldsExpected) { std::vector standard = { "Type of camera set (goToGeo)", "", @@ -450,9 +450,9 @@ void ProfileFile::parseCamera(std::string line) { } void ProfileFile::parseMarkNodes(std::string line) { - std::vector fields; + std::vector fields = ghoul::tokenizeString(line, '\t'); - if (splitByTab(line, fields) != markNodesFieldsExpected) { + if (fields.size() != markNodesFieldsExpected) { throw ghoul::RuntimeError(errorString(std::to_string(markNodesFieldsExpected) + " field required in an Mark Nodes entry"), "profileFile"); } @@ -479,22 +479,6 @@ void ProfileFile::verifyRequiredFields(std::string sectionName, } } -size_t ProfileFile::splitByTab(std::string line, std::vector& result) { - std::istringstream iss(line); - std::string tmp; - result.clear(); - while (getline(iss, tmp, '\t')) { - result.push_back(tmp); - } - //Insert additional empty fields only for the case of tab delimiters at end of - // string without populated field(s) - size_t nTabs = std::count(line.begin(), line.end(), '\t'); - for (size_t i = 0; i < (nTabs - result.size() + 1); ++i) { - result.push_back(""); - } - return result.size(); -} - void ProfileFile::updateTime(std::string line) { _time = std::move(line); } From 7f0c92430fca9cc05f2205932edf5be9653660c8 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 15 Jun 2020 16:07:16 +0200 Subject: [PATCH 15/61] Add the ability to load images lazily for RenderablePlanes Add ability to purge textures from RAM if they are read-only Make use of both for constellation images to reduce the memory footprint --- apps/OpenSpace/ext/sgct | 2 +- .../constellations/constellation_art.asset | 97 ++++++++++++++++++- .../generate_constellations.asset | 79 --------------- ext/ghoul | 2 +- .../rendering/renderableplaneimagelocal.cpp | 35 ++++++- .../rendering/renderableplaneimagelocal.h | 1 + .../rendering/renderableplaneimageonline.cpp | 4 +- 7 files changed, 130 insertions(+), 90 deletions(-) delete mode 100644 data/assets/scene/milkyway/constellations/generate_constellations.asset diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 95d4237eaf..0d902bbe4f 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 95d4237eaf2dc683c1782753f921f6b6ef373db0 +Subproject commit 0d902bbe4f13be7e1e532aa4428b9cc90422611b diff --git a/data/assets/scene/milkyway/constellations/constellation_art.asset b/data/assets/scene/milkyway/constellations/constellation_art.asset index 578592a220..c38d8d0576 100644 --- a/data/assets/scene/milkyway/constellations/constellation_art.asset +++ b/data/assets/scene/milkyway/constellations/constellation_art.asset @@ -1,11 +1,102 @@ -local constellation_helper = asset.require('./generate_constellations') - local constellationsCSV = asset.localResource('constellation_data.csv') +local transforms = asset.require("scene/solarsystem/sun/transforms") + +local images = asset.syncedResource({ + Name = "Constellation Images", + Type = "HttpSynchronization", + Identifier = "constellation_images", + Version = 1 +}) + +-- local image_resolution = "low" +-- local image_resolution = "medium" +local image_resolution = "high" + +--function that reads the file +local createConstellations = function (guiPath, constellationfile) + local genConstellations = {}; + --skip the first line + local notFirstLine = false; + -- define parsec to meters + local PARSEC_CONSTANT = 3.0856776E16; + -- how many parsecs away do you want the images to be? + -- this setting puts the billboards at the location of the constellation bounds grid from DU. + -- but they can really be anywhere since the billboard size will scale with distance. + local distanceMultiplier = 3.2; + local baseScale = 1e17; + for line in io.lines(openspace.absPath(constellationfile)) do + if (notFirstLine) then + -- describes the data + local matchstring = '(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-)$' + local group, abbreviation, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar = line:match(matchstring) + local magVec = math.sqrt(x*x + y*y + z*z) + local normx = x/magVec + local normy = y/magVec + local normz = z/magVec + + group = (group == '' and globe or group) + + local texture + if image_resolution == "low" then + texture = images .. "/" .. imageName:sub(1, -5) .. "-512.png" + elseif image_resolution == "medium" then + texture = images .. "/" .. imageName:sub(1, -5) .. "-1024.png" + elseif image_resolution == "high" then + texture = images .. "/" .. imageName + else + openspace.printError("Unknown image resolution: " .. image_resolution) + end + + local aconstellation = { + Identifier = guiPath .. '-' .. name, + Parent = transforms.SolarSystemBarycenter.Identifier, + Transform = { + Translation = { + Type = "StaticTranslation", + -- position is in parsecs from the SolarSystemBarycenter, so convert to meters + Position = { + normx * PARSEC_CONSTANT * distanceMultiplier, + normy * PARSEC_CONSTANT * distanceMultiplier, + normz * PARSEC_CONSTANT * distanceMultiplier + } + }, + Rotation = { + Type = "StaticRotation", + Rotation = { tonumber(rotX), tonumber(rotY), tonumber(rotZ) } + } + + }, + Renderable = { + Type = "RenderablePlaneImageLocal", + Size = tonumber(baseScale * scale * distanceMultiplier / 10), + Enabled = false, + Origin = "Center", + Billboard = false, + LazyLoading = true, + Texture = texture, + BlendMode = "Additive", + Opacity = 0.1 + }, + Tag = { "ConstellationArtImage", group }, + GUI = { + Name = name .. ' Image', + Path = '/Milky Way/' .. guiPath + } + } + table.insert(genConstellations, aconstellation); + + else + notFirstLine = true + end + end + return genConstellations +end + local nodes = {} asset.onInitialize(function () - nodes = constellation_helper.createConstellations('Constellation Art', constellationsCSV) + nodes = createConstellations('Constellation Art', constellationsCSV) for _, n in ipairs(nodes) do openspace.addSceneGraphNode(n); end diff --git a/data/assets/scene/milkyway/constellations/generate_constellations.asset b/data/assets/scene/milkyway/constellations/generate_constellations.asset deleted file mode 100644 index 696215b1dd..0000000000 --- a/data/assets/scene/milkyway/constellations/generate_constellations.asset +++ /dev/null @@ -1,79 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') -local transforms = asset.require("scene/solarsystem/sun/transforms") - -local images = asset.syncedResource({ - Name = "Constellation Images", - Type = "HttpSynchronization", - Identifier = "constellation_images", - Version = 1 -}) - ---function that reads the file -local createConstellations = function (guiPath, constellationfile) - local genConstellations = {}; - --skip the first line - local notFirstLine = false; - -- define parsec to meters - local PARSEC_CONSTANT = 3.0856776E16; - -- how many parsecs away do you want the images to be? - -- this setting puts the billboards at the location of the constellation bounds grid from DU. - -- but they can really be anywhere since the billboard size will scale with distance. - local distanceMultiplier = 3.2; - local baseScale = 1e17; - for line in io.lines(openspace.absPath(constellationfile)) do - if (notFirstLine) then - -- describes the data - local matchstring = '(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-),(.-)$' - local group, abbreviation, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar = line:match(matchstring) - local magVec = math.sqrt(x*x + y*y + z*z) - local normx = x/magVec - local normy = y/magVec - local normz = z/magVec - - group = (group == '' and globe or group) - - local aconstellation = { - Identifier = guiPath .. '-' .. name, - Parent = transforms.SolarSystemBarycenter.Identifier, - Transform = { - Translation = { - Type = "StaticTranslation", - -- position is in parsecs from the SolarSystemBarycenter, so convert to meters - Position = { - normx * PARSEC_CONSTANT * distanceMultiplier, - normy * PARSEC_CONSTANT * distanceMultiplier, - normz * PARSEC_CONSTANT * distanceMultiplier - } - }, - Rotation = { - Type = "StaticRotation", - Rotation = { tonumber(rotX), tonumber(rotY), tonumber(rotZ) } - } - - }, - Renderable = { - Type = "RenderablePlaneImageLocal", - Size = tonumber(baseScale*scale*distanceMultiplier/10), - Enabled = false, - Origin = "Center", - Billboard = false, - Texture = images .. "/" .. imageName, - BlendMode = "Additive", - Opacity = 0.1 - }, - Tag = { "ConstellationArtImage", group }, - GUI = { - Name = name .. ' Image', - Path = '/Milky Way/' .. guiPath - } - } - table.insert(genConstellations, aconstellation); - - else - notFirstLine = true - end - end - return genConstellations -end - -asset.export('createConstellations', createConstellations) diff --git a/ext/ghoul b/ext/ghoul index a634fc1515..19f324db68 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit a634fc15154ee51462e379917299fbe546c9fd1d +Subproject commit 19f324db68837b867779059f538b46051aec1bd9 diff --git a/modules/base/rendering/renderableplaneimagelocal.cpp b/modules/base/rendering/renderableplaneimagelocal.cpp index 5c106c21ed..31f61f140e 100644 --- a/modules/base/rendering/renderableplaneimagelocal.cpp +++ b/modules/base/rendering/renderableplaneimagelocal.cpp @@ -36,6 +36,8 @@ #include namespace { + constexpr const char* KeyLazyLoading = "LazyLoading"; + constexpr openspace::properties::Property::PropertyInfo TextureInfo = { "Texture", "Texture", @@ -70,6 +72,15 @@ documentation::Documentation RenderablePlaneImageLocal::Documentation() { new StringVerifier, Optional::Yes, RenderableTypeInfo.description + }, + { + KeyLazyLoading, + new BoolVerifier, + Optional::Yes, + "If this value is set to 'true', the image for this plane will not be " + "loaded at startup but rather when image is shown for the first time. " + "Additionally, if the plane is hidden, the image will automatically be " + "unloaded" } } }; @@ -116,16 +127,34 @@ RenderablePlaneImageLocal::RenderablePlaneImageLocal(const ghoul::Dictionary& di else { setRenderBin(Renderable::RenderBin::Opaque); } + + if (dictionary.hasKey(KeyLazyLoading)) { + _isLoadingLazily = dictionary.value(KeyLazyLoading); + + if (_isLoadingLazily) { + _enabled.onChange([this]() { + if (!_enabled) { + BaseModule::TextureManager.release(_texture); + _texture = nullptr; + } + if (_enabled) { + _textureIsDirty = true; + } + }); + } + } } bool RenderablePlaneImageLocal::isReady() const { - return RenderablePlane::isReady() && (_texture != nullptr); + return RenderablePlane::isReady(); } void RenderablePlaneImageLocal::initializeGL() { RenderablePlane::initializeGL(); - loadTexture(); + if (!_isLoadingLazily) { + loadTexture(); + } } void RenderablePlaneImageLocal::deinitializeGL() { @@ -165,8 +194,8 @@ void RenderablePlaneImageLocal::loadTexture() { fmt::format("Loaded texture from '{}'", absPath(path)) ); texture->uploadTexture(); - texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + texture->purgeFromRAM(); return texture; } diff --git a/modules/base/rendering/renderableplaneimagelocal.h b/modules/base/rendering/renderableplaneimagelocal.h index 4b2f795e6d..0e428296de 100644 --- a/modules/base/rendering/renderableplaneimagelocal.h +++ b/modules/base/rendering/renderableplaneimagelocal.h @@ -60,6 +60,7 @@ private: ghoul::opengl::Texture* _texture = nullptr; std::unique_ptr _textureFile; + bool _isLoadingLazily = false; bool _textureIsDirty = false; }; diff --git a/modules/base/rendering/renderableplaneimageonline.cpp b/modules/base/rendering/renderableplaneimageonline.cpp index 9e89e49525..148da49c50 100644 --- a/modules/base/rendering/renderableplaneimageonline.cpp +++ b/modules/base/rendering/renderableplaneimageonline.cpp @@ -133,10 +133,8 @@ void RenderablePlaneImageOnline::update(const UpdateData&) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); texture->uploadTexture(); - - // Textures of planets looks much smoother with AnisotropicMipMap rather - // than linear texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap); + texture->purgeFromRAM(); _texture = std::move(texture); _textureIsDirty = false; From d7e976f67f6df871cecc7580c92be135281756b7 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 15 Jun 2020 16:07:50 +0200 Subject: [PATCH 16/61] Add some more fixes --- include/openspace/scene/profilefile.h | 12 ----------- src/scene/profile.cpp | 6 +++--- src/scene/profilefile.cpp | 4 ---- tests/profile/test_profilefile.cpp | 30 +++++++++++++-------------- 4 files changed, 17 insertions(+), 35 deletions(-) diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 111b7211c7..9ddd41342e 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -93,18 +93,6 @@ public: */ ProfileFile(std::string filename); - /** - * Constructor with alternative method of populating the object by reading the lines - * from a profile file. This is mainly intended for testing purposes, but it can be - * used to provide the profile file contents from another source (the function - * readFromFile() provides its own ifstream source). - * \param reader A std::function object that accepts a string reference which will - * be populated with a single line of content. This function returns - * true if a single line was read successfully, or false if not to - * indicate that the end of the content has been reached. - */ - ProfileFile(std::function reader); - /** * Reads the contents of a profile file and populates vector containers for all * sections. This only pulls individual line entries into their proper sections; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 650d1bf62e..6cf3602f5a 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -548,14 +548,14 @@ std::string Profile::convertToScene_camera(ProfileFile& pf) { result += "})\n"; } else if (fields[cameraFieldType] == "goToGeo") { - result += " openspace.globebrowsing.goToGeo({ "; + result += " openspace.globebrowsing.goToGeo("; if (!fields[cameraGeoFieldAnchor].empty()) { result += fields[cameraGeoFieldAnchor] + ", "; } result += fields[cameraGeoFieldLatitude] + ", "; - result += fields[cameraGeoFieldLongitude] + ", "; + result += fields[cameraGeoFieldLongitude]; if (!fields[cameraGeoFieldAltitude].empty()) { - result += fields[cameraGeoFieldAltitude] + ", "; + result += + ", " + fields[cameraGeoFieldAltitude]; } result += ")\n"; } diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 7930865b2e..101064b5f4 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -56,10 +56,6 @@ ProfileFile::ProfileFile(std::string filename) { readIn(filename); } -ProfileFile::ProfileFile(std::function reader) { - readIn(reader); -} - void ProfileFile::readIn(std::string filename) { clearAllFields(); std::ifstream inFile; diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index 0d237b2ecc..423ebc872b 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -38,15 +38,14 @@ namespace { TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { testProfileFormat test = buildTestProfile1(); - std::string testFull_string = stringFromTestProfileFormat(test); - std::istringstream iss(testFull_string); + std::string testFile = absPath("${TEMPORARY}/profile-test-simple"); + { + std::string testFull_string = stringFromTestProfileFormat(test); + std::ofstream f(testFile); + f << testFull_string; + } - ProfileFile pf([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - }); + ProfileFile pf(testFile); std::vector tVect; @@ -200,15 +199,14 @@ TEST_CASE("profileFile: Required field missing", "[profileFile]") { TEST_CASE("profileFile: Write test", "[profileFile]") { testProfileFormat test = buildTestProfile1(); + std::string testFile = absPath("${TEMPORARY}/profile-test-write-test"); std::string testFull_string = stringFromTestProfileFormat(test); - std::istringstream iss(testFull_string); - ProfileFile pf([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ); + { + std::ofstream f(testFile); + f << testFull_string; + } + + ProfileFile pf(testFile); std::string result = pf.writeToString(); REQUIRE(testFull_string == result); From 393e0648741f50c07d0bba89264ce6ae7ec314ce Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 16 Jun 2020 11:05:56 +0200 Subject: [PATCH 17/61] Yet more cleanup Add ProfileError class --- ext/ghoul | 2 +- include/openspace/scene/profilefile.h | 37 ++---- src/scene/profile.cpp | 2 +- src/scene/profilefile.cpp | 183 ++++++++++++-------------- tests/profile/test_profilefile.cpp | 2 +- 5 files changed, 95 insertions(+), 131 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 19f324db68..d35be27b61 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 19f324db68837b867779059f538b46051aec1bd9 +Subproject commit d35be27b61140e76d8283999d9faee16977b1bfc diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 9ddd41342e..f3738b8b0d 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -93,28 +93,6 @@ public: */ ProfileFile(std::string filename); - /** - * Reads the contents of a profile file and populates vector containers for all - * sections. This only pulls individual line entries into their proper sections; - * it does not parse the tab-delimited fields of each line. - * This will reset contents of the object. - * \param filename The profile file to read - */ - void readIn(std::string filename); - - /** - * Alternative function for reading the lines from a profile file. This is mainly - * intended for testing purposes, but it can be used to provide the profile file - * contents from another source (the function readFromFile() provides its own - * ifstream source). - * This will reset contents of the object. - * \param reader A std::function object that accepts a string reference which will - * be populated with a single line of content. This function returns - * true if a single line was read successfully, or false if not to - * indicate that the end of the content has been reached. - */ - void readIn(std::function reader); - /** * Returns the string contents of this object converted to scene/asset * equivalent syntax, with all section headers and contents of each listed on an @@ -193,7 +171,7 @@ public: * Returns the format version number (profiles syntax version) string * \return The version string */ - const std::string getVersion() const; + const std::string& version() const; /** * Sets the format version number (profiles syntax version) string @@ -251,9 +229,17 @@ public: Lines markNodes() const; private: - std::string errorString(std::string message); + + /** + * Reads the contents of a profile file and populates vector containers for all + * sections. This only pulls individual line entries into their proper sections; + * it does not parse the tab-delimited fields of each line. + * This will reset contents of the object. + * \param filename The profile file to read + */ + void readIn(std::string filename); + void clearAllFields(); - bool isBlank(std::string line); void verifyRequiredFields(std::string sectionName, std::vector fields, std::vector standard, unsigned int nFields); void processIndividualLine(bool& insideSection, std::string line); @@ -267,7 +253,6 @@ private: void parseTime(std::string line); void parseCamera(std::string line); void parseMarkNodes(std::string line); - void addAllElements(std::string& str, std::vector& list); size_t _lineNum = 1; size_t _numLinesVersion = 0; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 6cf3602f5a..77563f99c9 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -478,7 +478,7 @@ std::string Profile::convertToScene_keybindings(ProfileFile& pf) { result += fmt::format(" {} = \"{}\",\n", "Name", fields[2]); result += fmt::format(" {} = \"{}\",\n", "GuiPath", fields[3]); result += fmt::format(" {} = \"{}\",\n", "Local", fields[4]); - result += fmt::format(" {} = \"{}\"\n", "Command", fields[5]); + result += fmt::format(" {} = {}\n", "Command", fields[5]); result += " },\n"; } result += "}\n"; diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 101064b5f4..a32b3b9a7e 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -25,12 +25,13 @@ #include #include -#include -#include -#include #include #include +#include #include +#include +#include +#include #include #include #include @@ -48,6 +49,15 @@ namespace { constexpr const char* headerTime = "#Time"; constexpr const char* headerCamera = "#Camera"; constexpr const char* headerMarkNodes = "#MarkNodes"; + + struct ProfileError : public ghoul::RuntimeError { + explicit ProfileError(unsigned int lineNum, std::string msg) + : ghoul::RuntimeError( + fmt::format("Error @ line {}: {}", lineNum, std::move(msg)), + "profileFile" + ) + {} + }; } // namespace namespace openspace { @@ -58,53 +68,38 @@ ProfileFile::ProfileFile(std::string filename) { void ProfileFile::readIn(std::string filename) { clearAllFields(); + _lineNum = 1; std::ifstream inFile; try { inFile.open(filename, std::ifstream::in); } catch (std::ifstream::failure& e) { - throw ghoul::RuntimeError("Exception opening profile file for read: " - + filename + " (" + e.what() + ")", "profileFile"); + throw ghoul::RuntimeError(fmt::format( + "Exception opening profile file for read: {} ({})", filename, e.what()), + "profileFile" + ); } try { - readIn([&inFile] (std::string& line) { - if (getline(inFile, line)) - return true; - else - return false; - }); + std::string line; + bool insideSection = false; + while (std::getline(inFile, line)) { + processIndividualLine(insideSection, line); + _lineNum++; + } } catch (std::ifstream::failure& e) { - throw ghoul::RuntimeError(errorString("Read error using getline in: " - + filename + " (" + e.what() + ")"), "profileFile"); - } - - try { - inFile.close(); - } - catch (std::ifstream::failure& e) { - throw ghoul::RuntimeError("Exception closing profile file after read in: " - + filename + " (" + e.what() + ")", "profileFile"); - } -} - -void ProfileFile::readIn(std::function reader) { - clearAllFields(); - std::string line; - bool insideSection = false; - _lineNum = 1; - - while (reader(line)) { - processIndividualLine(insideSection, line); - _lineNum++; + throw ProfileError( + _lineNum, + fmt::format("Read error using getline in: {} ({})", filename, e.what() + )); } } void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { if (insideSection) { - if (isBlank(line)) { + if (std::all_of(line.begin(), line.end(), ::isspace)) { insideSection = false; } else { @@ -144,12 +139,14 @@ void ProfileFile::writeToFile(const std::string& filename) { } std::ofstream outFile; + // @TODO (abock, 2020-06-15) Replace with non-throwing stream try { outFile.open(absFilename, std::ofstream::out); } catch (std::ofstream::failure& e) { - LERROR("Exception opening profile file for write: " - + absFilename + " (" + e.what() + ")"); + LERROR(fmt::format( + "Exception opening profile file for write: {} ({})", absFilename, e.what() + )); } try { @@ -160,13 +157,7 @@ void ProfileFile::writeToFile(const std::string& filename) { + absFilename + " (" + e.what() + ")"); } - try { - outFile.close(); - } - catch (std::ofstream::failure& e) { - LERROR("Exception closing profile file after write: " - + absFilename + " (" + e.what() + ")"); - } + outFile.close(); } std::string ProfileFile::writeToString() { @@ -174,28 +165,28 @@ std::string ProfileFile::writeToString() { output = headerVersion + '\n'; output += _version + '\n' + '\n'; output += headerModule + '\n'; - addAllElements(output, _modules); + output += ghoul::join(_modules, "\n"); output += '\n'; output += headerAsset + '\n'; - addAllElements(output, _assets); + output += ghoul::join(_assets, "\n"); output += '\n'; output += headerProperty + '\n'; - addAllElements(output, _properties); + output += ghoul::join(_properties, "\n"); output += '\n'; output += headerKeybinding + '\n'; - addAllElements(output, _keybindings); + output += ghoul::join(_keybindings, "\n"); output += '\n'; output += headerTime + '\n'; output += _time + '\n' + '\n'; output += headerCamera + '\n'; output += _camera + '\n' + '\n'; output += headerMarkNodes + '\n'; - addAllElements(output, _markNodes); + output += ghoul::join(_markNodes, "\n"); return output; } -const std::string ProfileFile::getVersion() const { +const std::string& ProfileFile::version() const { return _version; } @@ -203,12 +194,6 @@ void ProfileFile::setVersion(std::string v) { _version = std::move(v); } -void ProfileFile::addAllElements(std::string& str, std::vector& list) { - for (const std::string& s : list) { - str += s + '\n'; - } -} - void ProfileFile::clearAllFields() { _numLinesVersion = 0; _numLinesTime = 0; @@ -224,18 +209,6 @@ void ProfileFile::clearAllFields() { _markNodes.clear(); } -bool ProfileFile::isBlank(std::string line) { - char* c = const_cast(line.c_str()); - int nonBlanks = 0; - while (*c) { - if (!isspace(*c)) { - nonBlanks++; - } - c++; - } - return (nonBlanks == 0); -} - bool ProfileFile::determineSection(std::string line) { bool foundSection = true; @@ -264,18 +237,15 @@ bool ProfileFile::determineSection(std::string line) { parseCurrentSection = &ProfileFile::parseMarkNodes; } else { - throw ghoul::RuntimeError(errorString("Invalid section header '" + line + "'"), - "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("Invalid section header '{}'", line) + ); foundSection = false; } return foundSection; } -std::string ProfileFile::errorString(std::string message) { - std::string e = "Error @ line " + std::to_string(_lineNum) + ": "; - return e + message; -} - std::string ProfileFile::time() const { return _time; } @@ -306,13 +276,11 @@ ProfileFile::Lines ProfileFile::markNodes() const { void ProfileFile::parseVersion(std::string line) { if (++_numLinesVersion > versionLinesExpected) { - throw ghoul::RuntimeError(errorString("Too many lines in Version section"), - "profileFile"); + throw ProfileError(_lineNum, "Too many lines in Version section"); } std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() > versionFieldsExpected) { - throw ghoul::RuntimeError(errorString("No tabs allowed in Version entry"), - "profileFile"); + throw ProfileError(_lineNum, "No tabs allowed in Version entry"); } else { _version = line; @@ -323,8 +291,10 @@ void ProfileFile::parseModule(std::string line) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != moduleFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(moduleFieldsExpected) + - " fields required in a Module entry"), "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("{} fields required in a Module entry", moduleFieldsExpected) + ); } std::vector standard = { "module name", @@ -338,8 +308,10 @@ void ProfileFile::parseModule(std::string line) { void ProfileFile::parseAsset(std::string line) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != assetFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(assetFieldsExpected) + - " fields required in an Asset entry"), "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("{} fields required in an Asset entry", assetFieldsExpected) + ); } std::vector standard = { "asset name", @@ -353,8 +325,10 @@ void ProfileFile::parseProperty(std::string line) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != propertyFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(propertyFieldsExpected) + - " fields required in Property entry"), "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("{} fields required in Property entry", propertyFieldsExpected) + ); } std::vector standard = { "set command", @@ -369,8 +343,10 @@ void ProfileFile::parseKeybinding(std::string line) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != keybindingFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(keybindingFieldsExpected) - + " fields required in Keybinding entry"), "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("{} fields required in Keybinding entry", keybindingFieldsExpected) + ); } std::vector standard = { "key", @@ -386,14 +362,15 @@ void ProfileFile::parseKeybinding(std::string line) { void ProfileFile::parseTime(std::string line) { if (++_numLinesTime > timeLinesExpected) { - throw ghoul::RuntimeError(errorString("Too many lines in time section"), - "profileFile"); + throw ProfileError(_lineNum, "Too many lines in Time section"); } std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != timeFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(timeFieldsExpected) + - " fields required in Time entry"), "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("{} fields required in Time entry", timeFieldsExpected) + ); } std::vector standard = { "time set type", @@ -407,8 +384,7 @@ void ProfileFile::parseCamera(std::string line) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (++_numLinesCamera > cameraLinesExpected) { - throw ghoul::RuntimeError(errorString("Too many lines in camera section"), - "profileFile"); + throw ProfileError(_lineNum, "Too many lines in Camera section"); } if (fields.size() == cameraNavigationFieldsExpected) { @@ -437,10 +413,13 @@ void ProfileFile::parseCamera(std::string line) { cameraGeoFieldsExpected); } else { - throw ghoul::RuntimeError(errorString(std::to_string( - cameraNavigationFieldsExpected) + " or " + std::to_string( - cameraGeoFieldsExpected) + " fields required in Camera entry"), - "profileFile"); + throw ProfileError( + _lineNum, + fmt::format( + "{} or {} fields required in Camera entry", + cameraNavigationFieldsExpected, cameraGeoFieldsExpected + ) + ); } _camera = line; } @@ -449,12 +428,12 @@ void ProfileFile::parseMarkNodes(std::string line) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != markNodesFieldsExpected) { - throw ghoul::RuntimeError(errorString(std::to_string(markNodesFieldsExpected) + - " field required in an Mark Nodes entry"), "profileFile"); + throw ProfileError( + _lineNum, + fmt::format("{} field required in a Mark Nodes entry", markNodesFieldsExpected) + ); } - std::vector standard = { - "Mark Interesting Node name" - }; + std::vector standard = { "Mark Interesting Node name" }; verifyRequiredFields("Mark Interesting Nodes", fields, standard, markNodesFieldsExpected); _markNodes.push_back(line); @@ -470,7 +449,7 @@ void ProfileFile::verifyRequiredFields(std::string sectionName, std::string errMsg = sectionName + " " + standard[i]; errMsg += "(arg " + std::to_string(i) + "/"; errMsg += std::to_string(nFields) + ") is required"; - throw ghoul::RuntimeError(errorString(errMsg), "profileFile"); + throw ProfileError(_lineNum, std::move(errMsg)); } } } diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index 423ebc872b..4937147279 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -49,7 +49,7 @@ TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { std::vector tVect; - REQUIRE(pf.getVersion() == test.tsv[1]); + REQUIRE(pf.version() == test.tsv[1]); REQUIRE(pf.time() == test.tst[1]); REQUIRE(pf.camera() == test.tsc[1]); tVect = pf.modules(); From 9d922f26344e018a2283e3f60e3c8d5ad26b80c4 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 16 Jun 2020 13:22:19 +0200 Subject: [PATCH 18/61] Remove explicit read-in function --- include/openspace/scene/profilefile.h | 10 -- src/scene/profilefile.cpp | 6 +- tests/profile/test_profile.cpp | 26 ++--- tests/profile/test_profilefile.cpp | 162 +++++++++++++------------- 4 files changed, 88 insertions(+), 116 deletions(-) diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index f3738b8b0d..f1b03f37c1 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -229,16 +229,6 @@ public: Lines markNodes() const; private: - - /** - * Reads the contents of a profile file and populates vector containers for all - * sections. This only pulls individual line entries into their proper sections; - * it does not parse the tab-delimited fields of each line. - * This will reset contents of the object. - * \param filename The profile file to read - */ - void readIn(std::string filename); - void clearAllFields(); void verifyRequiredFields(std::string sectionName, std::vector fields, std::vector standard, unsigned int nFields); diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index a32b3b9a7e..979da0951e 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -63,10 +63,6 @@ namespace { namespace openspace { ProfileFile::ProfileFile(std::string filename) { - readIn(filename); -} - -void ProfileFile::readIn(std::string filename) { clearAllFields(); _lineNum = 1; std::ifstream inFile; @@ -93,7 +89,7 @@ void ProfileFile::readIn(std::string filename) { throw ProfileError( _lineNum, fmt::format("Read error using getline in: {} ({})", filename, e.what() - )); + )); } } diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 99477c1a02..2cbb587a4f 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -108,17 +108,13 @@ static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { TEST_CASE("profile: Convert profileFile to asset", "[profile]") { testProfileFormat test = buildTestProfile1(); std::string testFull_string = stringFromTestProfileFormat(test); + std::string testFilePath = absPath("${TEMPORARY}/test-profile-convert.profile"); + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } - std::istringstream iss(testFull_string); - ProfileFile pf("default.profile"); - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ); - + ProfileFile pf(testFilePath); Profile p; REQUIRE_NOTHROW( p.convertToScene(pf) @@ -127,15 +123,7 @@ TEST_CASE("profile: Convert profileFile to asset", "[profile]") { TEST_CASE("profile: Verify conversion to scene", "[profile]") { std::istringstream iss(newHorizonsProfileInput); - ProfileFile pf("default.profile"); - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ); - + ProfileFile pf(newHorizonsProfileInput); Profile p; std::string result; REQUIRE_NOTHROW( diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index 4937147279..bc94bd6314 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -77,123 +77,121 @@ TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { } TEST_CASE("profileFile: Unrecognized header", "[profileFile]") { + std::string testFilePath = absPath("${TEMPORARY}/test-profile-unrec-header.profile"); testProfileFormat test = buildTestProfile1(); - test.tsa[0] = "#Azzet"; std::string testFull_string = stringFromTestProfileFormat(test); - std::istringstream iss(testFull_string); + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } - ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ), - Catch::Matchers::Contains ( "Invalid section header" ) - && Catch::Matchers::Contains( "#Azzet" ) + ProfileFile(testFilePath), + Catch::Matchers::Contains("Invalid section header") && + Catch::Matchers::Contains("#Azzet") ); } TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { - testProfileFormat test = buildTestProfile1(); - std::string testFull_string; - test.tsm[1] = "globebrowsing\t\t\t"; - testFull_string = stringFromTestProfileFormat(test); { - std::istringstream iss(testFull_string); - ProfileFile pf("default.profile"); + std::string testFilePath = absPath( + "${TEMPORARY}/test-profile-bad-n-fields-1.profile" + ); + testProfileFormat test = buildTestProfile1(); + test.tsm[1] = "globebrowsing\t\t\t"; + std::string testFull_string = stringFromTestProfileFormat(test); + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } REQUIRE_THROWS_WITH( - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ), - Catch::Matchers::Contains ("fields required in a Module entry") + ProfileFile(testFilePath), + Catch::Matchers::Contains("fields required in a Module entry") ); } - - test.tsm[1] = "globebrowsing\t\t"; - test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"; - testFull_string = stringFromTestProfileFormat(test); + { - std::istringstream iss(testFull_string); - ProfileFile pf("default.profile"); + std::string testFilePath = absPath( + "${TEMPORARY}/test-profile-bad-n-fields-2.profile" + ); + + testProfileFormat test = buildTestProfile1(); + test.tsm[1] = "globebrowsing\t\t"; + test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"; + std::string testFull_string = stringFromTestProfileFormat(test); + + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } REQUIRE_THROWS_WITH( - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ), - Catch::Matchers::Contains ("fields required in Camera entry") + ProfileFile(testFilePath), + Catch::Matchers::Contains("fields required in Camera entry") ); } } TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") { testProfileFormat test = buildTestProfile1(); - std::string testFull_string; test.tst.push_back("relative\t\"-1 day\""); - testFull_string = stringFromTestProfileFormat(test); + std::string testFull_string = stringFromTestProfileFormat(test); + std::string testFilePath = absPath( + "${TEMPORARY}/test-profile-too-many-lines-time.profile" + ); + + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } { - std::istringstream iss(testFull_string); - ProfileFile pf("default.profile"); REQUIRE_THROWS_WITH( - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ), - Catch::Matchers::Contains ("Too many lines in time section") + ProfileFile(testFilePath), + Catch::Matchers::Contains("Too many lines in time section") ); } } TEST_CASE("profileFile: Required field missing", "[profileFile]") { - testProfileFormat test = buildTestProfile1(); - std::string testFull_string; - test.tsc[1] = "setNavigationState\t\"NewHorizons\"\ttest\t\"Root\"\t\t0.102164, -0.362945, 0.926193\t\t"; - - testFull_string = stringFromTestProfileFormat(test); { - std::istringstream iss(testFull_string); - ProfileFile pf("default.profile"); - REQUIRE_THROWS_WITH( - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ), - Catch::Matchers::Contains ("Camera navigation setNavigationState position vector(arg 4/8) is required") + testProfileFormat test = buildTestProfile1(); + test.tsc[1] = "setNavigationState\t\"NewHorizons\"\ttest\t\"Root\"\t\t0.102164, -0.362945, 0.926193\t\t"; + std::string testFull_string = stringFromTestProfileFormat(test); + std::string testFilePath = absPath( + "${TEMPORARY}/test-profile-required-field-missing-1.profile" ); + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } + + { + REQUIRE_THROWS_WITH( + ProfileFile(testFilePath), + Catch::Matchers::Contains("Camera navigation setNavigationState position vector(arg 4/8) is required") + ); + } } - test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t1, 2, 3\t0.102164, -0.362945, 0.926193\t\t"; - test.tsk[3] = "F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\t\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""; - testFull_string = stringFromTestProfileFormat(test); { - std::istringstream iss(testFull_string); - ProfileFile pf("default.profile"); - REQUIRE_THROWS_WITH( - pf.readIn([&iss](std::string& line) { - if (getline(iss, line)) - return true; - else - return false; - } - ), - Catch::Matchers::Contains ("Keybinding local(T/F)(arg 4/6) is required") + testProfileFormat test = buildTestProfile1(); + test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t1, 2, 3\t0.102164, -0.362945, 0.926193\t\t"; + test.tsk[3] = "F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\t\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""; + std::string testFull_string = stringFromTestProfileFormat(test); + std::string testFilePath = absPath( + "${TEMPORARY}/test-profile-required-field-missing-2.profile" ); + { + std::ofstream testFile(testFilePath); + testFile << testFull_string; + } + { + ProfileFile pf("default.profile"); + REQUIRE_THROWS_WITH( + ProfileFile(testFilePath), + Catch::Matchers::Contains("Keybinding local(T/F)(arg 4/6) is required") + ); + } } } From 809ee9c7532727ab3b79c35b9d6a983655e170cf Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 16 Jun 2020 16:39:51 +0200 Subject: [PATCH 19/61] Adding struct to hold parsed Profile --- include/openspace/scene/profilefile.h | 94 +++++++++- src/scene/profilefile.cpp | 246 ++++++++++++++++++++++++-- 2 files changed, 318 insertions(+), 22 deletions(-) diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index f1b03f37c1..aab90afab7 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -29,8 +29,12 @@ #include #include #include +#include +#include #include +#include + namespace ghoul { class Dictionary; } namespace ghoul::opengl { class ProgramObject; } @@ -83,6 +87,90 @@ const size_t cameraGeoFieldAltitude = 4; class ProfileFile { public: + struct ProfileStruct { + // Version + struct Version { + int major = 0; + int minor = 0; + int patch = 0; + }; + Version version; + + struct Module { + std::string name; + std::string loadedInstruction; + std::string notLoadedInstruction; + }; + std::vector modules; + + struct Asset { + enum class Type { + Require, + Request + }; + + std::string path; + Type type; + }; + std::vector assets; + + struct Property { + enum class SetType { + SetPropertyValue, + SetPropertyValueSingle + }; + + SetType setType; + std::string name; + std::string value; + }; + std::vector properties; + + struct Keybinding { + std::string key; // @TODO (abock, 2020-06-16) change to key+action + std::string documentation; + std::string name; + std::string guiPath; + bool isLocal; + std::string script; + }; + std::vector keybindings; + + struct Time { + enum class Type { + Absolute, + Relative + }; + + Type type; + std::string time; + }; + Time time; + + struct CameraNavState { + std::string anchor; + std::string aim; + std::string referenceFrame; + std::string position; + std::string up; + std::string yaw; + std::string pitch; + }; + struct CameraGoToGeo { + std::string anchor; + double latitude; + double longitude; + std::optional altitude; + }; + std::variant camera; + + std::vector markNodes; + }; + + ProfileStruct profile; + + + using Lines = std::vector; /** @@ -233,7 +321,7 @@ private: void verifyRequiredFields(std::string sectionName, std::vector fields, std::vector standard, unsigned int nFields); void processIndividualLine(bool& insideSection, std::string line); - bool determineSection(std::string line); + void determineSection(std::string line); void (ProfileFile::* parseCurrentSection)(std::string); void parseVersion(std::string line); void parseModule(std::string line); @@ -246,8 +334,8 @@ private: size_t _lineNum = 1; size_t _numLinesVersion = 0; - size_t _numLinesTime = 0; - size_t _numLinesCamera = 0; + size_t _numLinesTime = 0; + size_t _numLinesCamera = 0; std::string _version; std::string _time; diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 979da0951e..6c62fdd3f9 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -89,7 +89,7 @@ ProfileFile::ProfileFile(std::string filename) { throw ProfileError( _lineNum, fmt::format("Read error using getline in: {} ({})", filename, e.what() - )); + )); } } @@ -105,9 +105,8 @@ void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { } } else if (line.substr(0, 1) == "#") { - if (determineSection(line)) { - insideSection = true; - } + determineSection(line); + insideSection = true; } } @@ -203,33 +202,33 @@ void ProfileFile::clearAllFields() { _properties.clear(); _keybindings.clear(); _markNodes.clear(); + + profile = ProfileStruct(); } -bool ProfileFile::determineSection(std::string line) { - bool foundSection = true; - - if (line.compare(headerVersion) == 0) { +void ProfileFile::determineSection(std::string line) { + if (line == headerVersion) { parseCurrentSection = &ProfileFile::parseVersion; } - else if (line.compare(headerModule) == 0) { + else if (line == headerModule) { parseCurrentSection = &ProfileFile::parseModule; } - else if (line.compare(headerAsset) == 0) { + else if (line == headerAsset) { parseCurrentSection = &ProfileFile::parseAsset; } - else if (line.compare(headerProperty) == 0) { + else if (line == headerProperty) { parseCurrentSection = &ProfileFile::parseProperty; } - else if (line.compare(headerKeybinding) == 0) { + else if (line == headerKeybinding) { parseCurrentSection = &ProfileFile::parseKeybinding; } - else if (line.compare(headerTime) == 0) { + else if (line == headerTime) { parseCurrentSection = &ProfileFile::parseTime; } - else if (line.compare(headerCamera) == 0) { + else if (line == headerCamera) { parseCurrentSection = &ProfileFile::parseCamera; } - else if (line.compare(headerMarkNodes) == 0) { + else if (line == headerMarkNodes) { parseCurrentSection = &ProfileFile::parseMarkNodes; } else { @@ -237,9 +236,7 @@ bool ProfileFile::determineSection(std::string line) { _lineNum, fmt::format("Invalid section header '{}'", line) ); - foundSection = false; } - return foundSection; } std::string ProfileFile::time() const { @@ -278,9 +275,29 @@ void ProfileFile::parseVersion(std::string line) { if (fields.size() > versionFieldsExpected) { throw ProfileError(_lineNum, "No tabs allowed in Version entry"); } - else { - _version = line; + _version = line; + + // + // New + // + std::vector parts = ghoul::tokenizeString(line, '.'); + if (parts.empty() || parts.size() > 3) { + throw ProfileError( + _lineNum, + fmt::format("Expected 1-3 version components, got {}", parts.size()) + ); } + + ProfileStruct::Version version; + + version.major = std::stoi(parts[0]); + if (parts.size() > 1) { + version.minor = std::stoi(parts[1]); + } + if (parts.size() > 2) { + version.patch = std::stoi(parts[2]); + } + profile.version = std::move(version); } void ProfileFile::parseModule(std::string line) { @@ -299,6 +316,22 @@ void ProfileFile::parseModule(std::string line) { }; verifyRequiredFields("Module", fields, standard, moduleFieldsExpected); _modules.push_back(line); + + + // + // New + // + if (fields.size() != 3) { + throw ProfileError( + _lineNum, + fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) + ); + } + ProfileStruct::Module m; + m.name = fields[0]; + m.loadedInstruction = fields[1]; + m.notLoadedInstruction = fields[2]; + profile.modules.push_back(std::move(m)); } void ProfileFile::parseAsset(std::string line) { @@ -315,6 +348,33 @@ void ProfileFile::parseAsset(std::string line) { }; verifyRequiredFields("Asset", fields, standard, assetFieldsExpected); _assets.push_back(line); + + + // + // New + // + if (fields.size() != 2) { + throw ProfileError( + _lineNum, + fmt::format("Expected 2 fields in an Asset entry, got {}", fields.size()) + ); + } + + ProfileStruct::Asset a; + a.path = fields[0]; + a.type = [&](const std::string& type) -> ProfileStruct::Asset::Type { + if (type == "required") { + return ProfileStruct::Asset::Type::Require; + } + if (type == "request") { + return ProfileStruct::Asset::Type::Request; + } + throw ProfileError( + _lineNum, + fmt::format("Expected asset type 'required' or 'request', got {}", type) + ); + }(fields[1]); + profile.assets.push_back(std::move(a)); } void ProfileFile::parseProperty(std::string line) { @@ -333,6 +393,37 @@ void ProfileFile::parseProperty(std::string line) { }; verifyRequiredFields("Property", fields, standard, propertyFieldsExpected); _properties.push_back(line); + + + // + // New + // + if (fields.size() != 3) { + throw ProfileError( + _lineNum, + fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) + ); + } + ProfileStruct::Property p; + p.setType = [&](const std::string& type) -> ProfileStruct::Property::SetType { + if (type == "setPropertyValue") { + return ProfileStruct::Property::SetType::SetPropertyValue; + } + if (type == "setPropertyValueSingle") { + return ProfileStruct::Property::SetType::SetPropertyValueSingle; + } + throw ProfileError( + _lineNum, + fmt::format( + "Expected property set type 'setPropertyValue' or " + "'setPropertyValueSingle', got {}", + type + ) + ); + }(fields[0]); + p.name = fields[1]; + p.value = fields[2]; + profile.properties.push_back(std::move(p)); } void ProfileFile::parseKeybinding(std::string line) { @@ -354,6 +445,36 @@ void ProfileFile::parseKeybinding(std::string line) { }; verifyRequiredFields("Keybinding", fields, standard, keybindingFieldsExpected); _keybindings.push_back(line); + + + // + // New + // + if (fields.size() != 6) { + throw ProfileError( + _lineNum, + fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) + ); + } + ProfileStruct::Keybinding kb; + kb.key = fields[0]; + kb.documentation = fields[1]; + kb.name = fields[2]; + kb.guiPath = fields[3]; + kb.isLocal = [&](const std::string& local) -> bool { + if (local == "false") { + return false; + } + if (local == "true") { + return true; + } + throw ProfileError( + _lineNum, + fmt::format("Expected 'false' or 'true' for the local path, got {}", local) + ); + }(fields[4]); + kb.script = fields[5]; + profile.keybindings.push_back(std::move(kb)); } void ProfileFile::parseTime(std::string line) { @@ -374,6 +495,32 @@ void ProfileFile::parseTime(std::string line) { }; verifyRequiredFields("Time", fields, standard, timeFieldsExpected); _time = line; + + + // + // New + // + if (fields.size() != 2) { + throw ProfileError( + _lineNum, + fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) + ); + } + ProfileStruct::Time time; + time.type = [&](const std::string& type) -> ProfileStruct::Time::Type { + if (type == "absolute") { + return ProfileStruct::Time::Type::Absolute; + } + if (type == "relative") { + return ProfileStruct::Time::Type::Relative; + } + throw ProfileError( + _lineNum, + fmt::format("Expected 'absolute' or 'relative' for the type, got {}", type) + ); + }(fields[0]); + time.time = fields[1]; + profile.time = std::move(time); } void ProfileFile::parseCamera(std::string line) { @@ -418,6 +565,61 @@ void ProfileFile::parseCamera(std::string line) { ); } _camera = line; + + + // + // New + // + if (fields.empty()) { + throw ProfileError(_lineNum, "No values specified for Camera location"); + } + if (fields[0] == "setNavigationState") { + if (fields.size() != 8) { + throw ProfileError( + _lineNum, + fmt::format( + "Expected 8 fields in the Camera entry, got {}", fields.size() + ) + ); + } + + ProfileStruct::CameraNavState camera; + camera.anchor = fields[1]; + camera.aim = fields[2]; + camera.referenceFrame = fields[3]; + camera.position = fields[4]; + camera.up = fields[5]; + camera.yaw = fields[6]; + camera.pitch = fields[7]; + profile.camera = std::move(camera); + return; + } + if (fields[0] == "goToGeo") { + if (fields.size() != 5) { + throw ProfileError( + _lineNum, + fmt::format( + "Expected 5 fields in the Camera entry, got {}", fields.size() + ) + ); + } + + ProfileStruct::CameraGoToGeo camera; + camera.anchor = fields[1]; + camera.latitude = std::stod(fields[2]); + camera.longitude = std::stod(fields[3]); + if (!fields[4].empty()) { + camera.altitude = std::stod(fields[4]); + } + profile.camera = std::move(camera); + return; + } + throw ProfileError( + _lineNum, + fmt::format( + "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", fields[0] + ) + ); } void ProfileFile::parseMarkNodes(std::string line) { @@ -433,6 +635,12 @@ void ProfileFile::parseMarkNodes(std::string line) { verifyRequiredFields("Mark Interesting Nodes", fields, standard, markNodesFieldsExpected); _markNodes.push_back(line); + + + // + // New + // + profile.markNodes.push_back(line); } void ProfileFile::verifyRequiredFields(std::string sectionName, From 52ca39fc228c892afdab33cf57f62fb5c3e9b231 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 17 Jun 2020 09:33:41 +0200 Subject: [PATCH 20/61] Replace 'required' with 'require' and 'requested' with 'request' Continue the work of factoring out the serialization and deserialization of the profile files --- data/assets/apollo8.profile | 6 +- data/assets/apollo_sites.profile | 14 +- data/assets/dawn.profile | 6 +- data/assets/default.profile | 4 +- data/assets/default_full.profile | 14 +- data/assets/gaia.profile | 12 +- data/assets/insight.profile | 2 +- data/assets/juno.profile | 2 +- data/assets/messenger.profile | 2 +- data/assets/newhorizons.profile | 4 +- data/assets/osirisrex.profile | 4 +- data/assets/rosetta.profile | 4 +- data/assets/touch.profile | 4 +- data/assets/voyager.profile | 16 +-- include/openspace/scene/profilefile.h | 180 +++++++++++++------------- src/scene/profile.cpp | 8 +- src/scene/profilefile.cpp | 150 +++++++++++++++------ tests/profile/test_profilefile.cpp | 2 +- 18 files changed, 249 insertions(+), 185 deletions(-) diff --git a/data/assets/apollo8.profile b/data/assets/apollo8.profile index 7c7b3f73bb..13638ccb1d 100644 --- a/data/assets/apollo8.profile +++ b/data/assets/apollo8.profile @@ -2,9 +2,9 @@ 1.0 #Asset -scene/solarsystem/planets/earth/moon/moon required -scene/solarsystem/missions/apollo/8/apollo8 required -scene/solarsystem/planets/earth/earth required +scene/solarsystem/planets/earth/moon/moon require +scene/solarsystem/missions/apollo/8/apollo8 require +scene/solarsystem/planets/earth/earth require #Property setPropertyValueSingle NavigationHandler.OrbitalNavigator.MinimumAllowedDistance 0.000000 diff --git a/data/assets/apollo_sites.profile b/data/assets/apollo_sites.profile index 9c42c9fa97..9cd537a7d0 100644 --- a/data/assets/apollo_sites.profile +++ b/data/assets/apollo_sites.profile @@ -2,13 +2,13 @@ 1.0 #Asset -scene/solarsystem/planets/earth/moon/moon required -scene/solarsystem/missions/apollo/8/apollo8 required -scene/solarsystem/missions/apollo/11/apollo11 required -scene/solarsystem/missions/apollo/17/lem required -scene/solarsystem/missions/apollo/apollo_globebrowsing required -scene/solarsystem/missions/apollo/11/lem_flipbook required -scene/solarsystem/missions/apollo/insignias_map required +scene/solarsystem/planets/earth/moon/moon require +scene/solarsystem/missions/apollo/8/apollo8 require +scene/solarsystem/missions/apollo/11/apollo11 require +scene/solarsystem/missions/apollo/17/lem require +scene/solarsystem/missions/apollo/apollo_globebrowsing require +scene/solarsystem/missions/apollo/11/lem_flipbook require +scene/solarsystem/missions/apollo/insignias_map require #Property setPropertyValueSingle Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode 0 diff --git a/data/assets/dawn.profile b/data/assets/dawn.profile index 533e43d6dc..f94d2a325a 100644 --- a/data/assets/dawn.profile +++ b/data/assets/dawn.profile @@ -2,9 +2,9 @@ 1.0 #Asset -scene/solarsystem/missions/dawn/ceres required -scene/solarsystem/missions/dawn/dawn required -scene/solarsystem/missions/dawn/vesta required +scene/solarsystem/missions/dawn/ceres require +scene/solarsystem/missions/dawn/dawn require +scene/solarsystem/missions/dawn/vesta require #Time absolute 2011 AUG 06 00:00:00 diff --git a/data/assets/default.profile b/data/assets/default.profile index 7d10fb2b71..6f4a41d1b0 100644 --- a/data/assets/default.profile +++ b/data/assets/default.profile @@ -2,8 +2,8 @@ 1.0 #Asset -scene/solarsystem/planets/earth/earth required -scene/solarsystem/planets/earth/satellites/satellites required +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/earth/satellites/satellites require #Property setPropertyValue {earth_satellites}.Renderable.Enabled false diff --git a/data/assets/default_full.profile b/data/assets/default_full.profile index e6c2522523..9e98477827 100644 --- a/data/assets/default_full.profile +++ b/data/assets/default_full.profile @@ -2,13 +2,13 @@ 1.0 #Asset -scene/solarsystem/planets/earth/earth required -scene/solarsystem/planets/jupiter/minor_moons required -scene/solarsystem/planets/saturn/minor_moons required -scene/solarsystem/planets/uranus/minor_moons required -scene/solarsystem/planets/neptune/inner_moons required -scene/solarsystem/planets/neptune/irregular_prograde_moons required -scene/solarsystem/planets/neptune/irregular_retrograde_moons required +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/jupiter/minor_moons require +scene/solarsystem/planets/saturn/minor_moons require +scene/solarsystem/planets/uranus/minor_moons require +scene/solarsystem/planets/neptune/inner_moons require +scene/solarsystem/planets/neptune/irregular_prograde_moons require +scene/solarsystem/planets/neptune/irregular_retrograde_moons require #Time relative -1d diff --git a/data/assets/gaia.profile b/data/assets/gaia.profile index 82d54557b1..922ccc15b4 100644 --- a/data/assets/gaia.profile +++ b/data/assets/gaia.profile @@ -5,12 +5,12 @@ Gaia openspace.printFatal('Could not load scene due to missing module "gaia"') #Asset -scene/solarsystem/planets/earth/earth required -scene/milkyway/gaia/gaiastars required -scene/milkyway/gaia/apogee required -scene/milkyway/gaia/galah required -scene/solarsystem/missions/gaia/gaia required -scene/solarsystem/missions/gaia/trail required +scene/solarsystem/planets/earth/earth require +scene/milkyway/gaia/gaiastars require +scene/milkyway/gaia/apogee require +scene/milkyway/gaia/galah require +scene/solarsystem/missions/gaia/gaia require +scene/solarsystem/missions/gaia/trail require #Property setPropertyValueSingle Scene.Stars.Renderable.Enabled false diff --git a/data/assets/insight.profile b/data/assets/insight.profile index 0491c3e059..cc5be21b46 100644 --- a/data/assets/insight.profile +++ b/data/assets/insight.profile @@ -2,7 +2,7 @@ 1.0 #Asset -scene/solarsystem/missions/insight/edl required +scene/solarsystem/missions/insight/edl require #Property setPropertyValueSingle Scene.PlutoBarycenterTrail.Renderable.Enabled false diff --git a/data/assets/juno.profile b/data/assets/juno.profile index d2bb28a316..c17b10c283 100644 --- a/data/assets/juno.profile +++ b/data/assets/juno.profile @@ -2,7 +2,7 @@ 1.0 #Asset -scene/solarsystem/missions/juno/juno required +scene/solarsystem/missions/juno/juno require #Keybinding 1 Setting the simulation speed to 1 seconds per realtime second Set sim speed 1 /Simulation Speed false "openspace.time.interpolateDeltaTime(1)" diff --git a/data/assets/messenger.profile b/data/assets/messenger.profile index 8a508388d9..740cc62cc3 100644 --- a/data/assets/messenger.profile +++ b/data/assets/messenger.profile @@ -5,7 +5,7 @@ Volume asset.require('scene/solarsystem/missions/messenger/mercurymagnetosphere') openspace.printWarning("Volume module is not loaded, skipping asset: mercurymagnetosphere") #Asset -scene/solarsystem/missions/messenger/messengerSC required +scene/solarsystem/missions/messenger/messengerSC require #Keybinding 1 Setting the simulation speed to 1 seconds per realtime second Set sim speed 1 /Simulation Speed false "openspace.time.interpolateDeltaTime(1)" diff --git a/data/assets/newhorizons.profile b/data/assets/newhorizons.profile index ff3a46a096..400a2fde81 100644 --- a/data/assets/newhorizons.profile +++ b/data/assets/newhorizons.profile @@ -2,8 +2,8 @@ 1.0 #Asset -scene/solarsystem/missions/newhorizons/newhorizons required -scene/solarsystem/missions/newhorizons/model required +scene/solarsystem/missions/newhorizons/newhorizons require +scene/solarsystem/missions/newhorizons/model require #Property setPropertyValueSingle NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance 20.000000 diff --git a/data/assets/osirisrex.profile b/data/assets/osirisrex.profile index eec35f2466..099678c382 100644 --- a/data/assets/osirisrex.profile +++ b/data/assets/osirisrex.profile @@ -2,8 +2,8 @@ 1.0 #Asset -scene/solarsystem/missions/osirisrex/model required -scene/solarsystem/missions/osirisrex/osirisrex required +scene/solarsystem/missions/osirisrex/model require +scene/solarsystem/missions/osirisrex/osirisrex require #Property setPropertyValueSingle NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance 20.000000 diff --git a/data/assets/rosetta.profile b/data/assets/rosetta.profile index 0b0bd37881..a7f2b3bdd4 100644 --- a/data/assets/rosetta.profile +++ b/data/assets/rosetta.profile @@ -5,8 +5,8 @@ Volume asset.require('scene/solarsystem/missions/messenger/mercurymagnetosphere') openspace.printWarning("Volume module is not loaded, skipping asset: mercurymagnetosphere") #Asset -scene/solarsystem/missions/rosetta/67p required -scene/solarsystem/missions/rosetta/rosetta required +scene/solarsystem/missions/rosetta/67p require +scene/solarsystem/missions/rosetta/rosetta require #Property setPropertyValue Scene.67P.Renderable.PerformShading false diff --git a/data/assets/touch.profile b/data/assets/touch.profile index 237a1c79b5..a770c1ceb6 100644 --- a/data/assets/touch.profile +++ b/data/assets/touch.profile @@ -5,8 +5,8 @@ Touch local webGui = asset.require('util/webgui'); webGui.setCefRoute("ontouch") openspace.printFatal('Could not load scene due to missing module "touch"') #Asset -scene/solarsystem/planets/earth/earth required -util/webgui required +scene/solarsystem/planets/earth/earth require +util/webgui require #Property setPropertyValueSingle Scene.Pluto.Renderable.Enabled false diff --git a/data/assets/voyager.profile b/data/assets/voyager.profile index 150344f1e1..a3e6401223 100644 --- a/data/assets/voyager.profile +++ b/data/assets/voyager.profile @@ -2,14 +2,14 @@ 1.0 #Asset -scene/solarsystem/planets/jupiter/minor_moons required -scene/solarsystem/planets/saturn/minor_moons required -scene/solarsystem/planets/uranus/minor_moons required -scene/solarsystem/planets/neptune/inner_moons required -scene/solarsystem/planets/neptune/irregular_prograde_moons required -scene/solarsystem/planets/neptune/irregular_retrograde_moons required -scene/solarsystem/missions/voyager/voyager1 required -scene/solarsystem/missions/voyager/voyager2 required +scene/solarsystem/planets/jupiter/minor_moons require +scene/solarsystem/planets/saturn/minor_moons require +scene/solarsystem/planets/uranus/minor_moons require +scene/solarsystem/planets/neptune/inner_moons require +scene/solarsystem/planets/neptune/irregular_prograde_moons require +scene/solarsystem/planets/neptune/irregular_retrograde_moons require +scene/solarsystem/missions/voyager/voyager1 require +scene/solarsystem/missions/voyager/voyager2 require #Keybinding 1 Setting the simulation speed to 1 seconds per realtime second Set sim speed 1 /Simulation Speed false "openspace.time.interpolateDeltaTime(1)" diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index aab90afab7..026c45e8fa 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -43,10 +43,8 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } -const size_t versionLinesExpected = 1; const size_t timeLinesExpected = 1; const size_t cameraLinesExpected = 1; -const size_t versionFieldsExpected = 1; const size_t moduleFieldsExpected = 3; const size_t assetFieldsExpected = 2; const size_t propertyFieldsExpected = 3; @@ -85,92 +83,96 @@ const size_t cameraGeoFieldLatitude = 2; const size_t cameraGeoFieldLongitude = 3; const size_t cameraGeoFieldAltitude = 4; +struct ProfileStruct { + // Version + struct Version { + int major = 0; + int minor = 0; + int patch = 0; + }; + Version version; + + struct Module { + std::string name; + std::string loadedInstruction; + std::string notLoadedInstruction; + }; + std::vector modules; + + struct Asset { + enum class Type { + Require, + Request + }; + + std::string path; + Type type; + }; + std::vector assets; + + struct Property { + enum class SetType { + SetPropertyValue, + SetPropertyValueSingle + }; + + SetType setType; + std::string name; + std::string value; + }; + std::vector properties; + + struct Keybinding { + std::string key; // @TODO (abock, 2020-06-16) change to key+action + std::string documentation; + std::string name; + std::string guiPath; + bool isLocal; + std::string script; + }; + std::vector keybindings; + + struct Time { + enum class Type { + Absolute, + Relative + }; + + Type type; + std::string time; + }; + Time time; + + struct CameraNavState { + static constexpr const char* Type = "setNavigationState"; + + std::string anchor; + std::string aim; + std::string referenceFrame; + std::string position; + std::string up; + std::string yaw; + std::string pitch; + }; + struct CameraGoToGeo { + static constexpr const char* Type = "goToGeo"; + + std::string anchor; + double latitude; + double longitude; + std::optional altitude; + }; + std::variant camera; + + std::vector markNodes; +}; + +std::string serialize(const ProfileStruct& ps); + class ProfileFile { public: - struct ProfileStruct { - // Version - struct Version { - int major = 0; - int minor = 0; - int patch = 0; - }; - Version version; - - struct Module { - std::string name; - std::string loadedInstruction; - std::string notLoadedInstruction; - }; - std::vector modules; - - struct Asset { - enum class Type { - Require, - Request - }; - - std::string path; - Type type; - }; - std::vector assets; - - struct Property { - enum class SetType { - SetPropertyValue, - SetPropertyValueSingle - }; - - SetType setType; - std::string name; - std::string value; - }; - std::vector properties; - - struct Keybinding { - std::string key; // @TODO (abock, 2020-06-16) change to key+action - std::string documentation; - std::string name; - std::string guiPath; - bool isLocal; - std::string script; - }; - std::vector keybindings; - - struct Time { - enum class Type { - Absolute, - Relative - }; - - Type type; - std::string time; - }; - Time time; - - struct CameraNavState { - std::string anchor; - std::string aim; - std::string referenceFrame; - std::string position; - std::string up; - std::string yaw; - std::string pitch; - }; - struct CameraGoToGeo { - std::string anchor; - double latitude; - double longitude; - std::optional altitude; - }; - std::variant camera; - - std::vector markNodes; - }; - ProfileStruct profile; - - using Lines = std::vector; /** @@ -181,21 +183,13 @@ public: */ ProfileFile(std::string filename); - /** - * Returns the string contents of this object converted to scene/asset - * equivalent syntax, with all section headers and contents of each listed on an - * individual line. - * \return The full contents of the profile file in string format. - */ - std::string writeToString(); - /** * Writes the formatted contents of this object to a file. * This function calls writeToString() in order to get everything in formatted * form. * \param filename The filename to write to. */ - void writeToFile(const std::string& filename); + void writeToFile(const std::string& filename) const; /** * Updates the full string that defines the starting time. The format for this line diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 77563f99c9..bde1d7291b 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -156,7 +156,7 @@ void Profile::saveCurrentSettingsToProfile(const std::string& filename) { std::string Profile::saveCurrentSettingsToProfile_string() { ProfileFile pf = collateBaseWithChanges(); - return pf.writeToString(); + return serialize(pf.profile); } bool Profile::usingProfile() const { @@ -418,10 +418,10 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { for (size_t i = 0; i < pf.assets().size(); ++i) { std::vector fields = ghoul::tokenizeString(pf.assets()[i], '\t'); - if (fields[assetFieldReqd] == "required") { + if (fields[assetFieldReqd] == "require") { assetR = "require"; } - else if (fields[assetFieldReqd] == "requested") { + else if (fields[assetFieldReqd] == "request") { assetR = "request"; } else if (fields[assetFieldReqd] == "") { @@ -429,7 +429,7 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { } else { std::string err = fmt::format( - "Asset {} of {} has bad arg 2/2 which must be 'required' or 'requested'", + "Asset {} of {} has bad arg 2/2 which must be 'require' or 'request'", i + 1, pf.assets().size() ); throw ghoul::RuntimeError(err); diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 6c62fdd3f9..e36fc8b65d 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -50,6 +50,10 @@ namespace { constexpr const char* headerCamera = "#Camera"; constexpr const char* headerMarkNodes = "#MarkNodes"; + // Helper structs for the visitor pattern of the std::variant + template struct overloaded : Ts... { using Ts::operator()...; }; + template overloaded(Ts...) -> overloaded; + struct ProfileError : public ghoul::RuntimeError { explicit ProfileError(unsigned int lineNum, std::string msg) : ghoul::RuntimeError( @@ -62,6 +66,95 @@ namespace { namespace openspace { +std::string serialize(const ProfileStruct& ps) { + std::string output; + output += fmt::format("{}\n", headerVersion); + output += fmt::format("{}.{}.{}\n", ps.version.major, ps.version.minor, ps.version.patch); + + output += fmt::format("\n{}\n", headerModule); + for (const ProfileStruct::Module& m : ps.modules) { + output += fmt::format("{}\t{}\t{}\n", m.name, m.loadedInstruction, m.notLoadedInstruction); + } + + output += fmt::format("\n{}\n", headerAsset); + for (const ProfileStruct::Asset& a : ps.assets) { + const std::string type = [](ProfileStruct::Asset::Type t) { + switch (t) { + case ProfileStruct::Asset::Type::Require: return "require"; + case ProfileStruct::Asset::Type::Request: return "request"; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + output += fmt::format("{}\t{}\n", a.path, type); + } + + output += fmt::format("\n{}\n", headerProperty); + for (const ProfileStruct::Property& p : ps.properties) { + const std::string type = [](ProfileStruct::Property::SetType t) { + switch (t) { + case ProfileStruct::Property::SetType::SetPropertyValue: + return "setPropertyValue"; + case ProfileStruct::Property::SetType::SetPropertyValueSingle: + return "setPropertyValueSingle"; + } + }(p.setType); + output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); + } + + output += fmt::format("\n{}\n", headerKeybinding); + for (const ProfileStruct::Keybinding& k : ps.keybindings) { + const std::string local = k.isLocal ? "true" : "false"; + output += fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\n", + k.key, k.documentation, k.name, k.guiPath, local, k.script + ); + } + + output += fmt::format("\n{}\n", headerTime); + { + const std::string type = [](ProfileStruct::Time::Type t) { + switch (t) { + case ProfileStruct::Time::Type::Absolute: return "absolute"; + case ProfileStruct::Time::Type::Relative: return "relative"; + default: throw ghoul::MissingCaseException(); + } + }(ps.time.type); + output += fmt::format("{}\t{}\n", type, ps.time.time); + } + + output += fmt::format("\n{}\n", headerCamera); + output += std::visit(overloaded{ + [](const ProfileStruct::CameraNavState& camera) { + return fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", + ProfileStruct::CameraNavState::Type, + camera.anchor, camera.aim, camera.referenceFrame, camera.position, + camera.up, camera.yaw, camera.pitch + ); + }, + [](const ProfileStruct::CameraGoToGeo& camera) { + std::string altitude; + if (camera.altitude.has_value()) { + altitude = std::to_string(*camera.altitude); + } + + return fmt::format( + "{}\t{}\t{}\t{}\t{}\n", + ProfileStruct::CameraGoToGeo::Type, + camera.anchor, camera.latitude, camera.longitude, altitude + ); + } + }, ps.camera); + + output += fmt::format("\n{}\n", headerMarkNodes); + for (const std::string& n : ps.markNodes) { + output += fmt::format("{}\n", n); + } + + return output; +} + + ProfileFile::ProfileFile(std::string filename) { clearAllFields(); _lineNum = 1; @@ -70,7 +163,7 @@ ProfileFile::ProfileFile(std::string filename) { try { inFile.open(filename, std::ifstream::in); } - catch (std::ifstream::failure& e) { + catch (const std::ifstream::failure& e) { throw ghoul::RuntimeError(fmt::format( "Exception opening profile file for read: {} ({})", filename, e.what()), "profileFile" @@ -85,7 +178,7 @@ ProfileFile::ProfileFile(std::string filename) { _lineNum++; } } - catch (std::ifstream::failure& e) { + catch (const std::ifstream::failure& e) { throw ProfileError( _lineNum, fmt::format("Read error using getline in: {} ({})", filename, e.what() @@ -110,16 +203,16 @@ void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { } } -void ProfileFile::writeToFile(const std::string& filename) { - if (filename.find("/") != std::string::npos) { +void ProfileFile::writeToFile(const std::string& filename) const { + if (filename.find('/') != std::string::npos) { LERROR("Profile filename must not contain path (/) elements"); return; } - else if (filename.find(":") != std::string::npos) { + else if (filename.find(':') != std::string::npos) { LERROR("Profile filename must not contain path (:) elements"); return; } - else if (filename.find(".") != std::string::npos) { + else if (filename.find('.') != std::string::npos) { LERROR("Only provide the filename to save without file extension"); return; } @@ -138,16 +231,16 @@ void ProfileFile::writeToFile(const std::string& filename) { try { outFile.open(absFilename, std::ofstream::out); } - catch (std::ofstream::failure& e) { + catch (const std::ofstream::failure& e) { LERROR(fmt::format( "Exception opening profile file for write: {} ({})", absFilename, e.what() )); } try { - outFile << writeToString(); + outFile << serialize(profile); } - catch (std::ofstream::failure& e) { + catch (const std::ofstream::failure& e) { LERROR("Data write error to file: " + absFilename + " (" + e.what() + ")"); } @@ -155,31 +248,6 @@ void ProfileFile::writeToFile(const std::string& filename) { outFile.close(); } -std::string ProfileFile::writeToString() { - std::string output; - output = headerVersion + '\n'; - output += _version + '\n' + '\n'; - output += headerModule + '\n'; - output += ghoul::join(_modules, "\n"); - output += '\n'; - output += headerAsset + '\n'; - output += ghoul::join(_assets, "\n"); - output += '\n'; - output += headerProperty + '\n'; - output += ghoul::join(_properties, "\n"); - output += '\n'; - output += headerKeybinding + '\n'; - output += ghoul::join(_keybindings, "\n"); - output += '\n'; - output += headerTime + '\n'; - output += _time + '\n' + '\n'; - output += headerCamera + '\n'; - output += _camera + '\n' + '\n'; - output += headerMarkNodes + '\n'; - output += ghoul::join(_markNodes, "\n"); - - return output; -} const std::string& ProfileFile::version() const { return _version; @@ -268,11 +336,13 @@ ProfileFile::Lines ProfileFile::markNodes() const { } void ProfileFile::parseVersion(std::string line) { - if (++_numLinesVersion > versionLinesExpected) { + constexpr const size_t VersionLinesExpected = 1; + + if (++_numLinesVersion > VersionLinesExpected) { throw ProfileError(_lineNum, "Too many lines in Version section"); } std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() > versionFieldsExpected) { + if (fields.size() > 1) { throw ProfileError(_lineNum, "No tabs allowed in Version entry"); } _version = line; @@ -363,7 +433,7 @@ void ProfileFile::parseAsset(std::string line) { ProfileStruct::Asset a; a.path = fields[0]; a.type = [&](const std::string& type) -> ProfileStruct::Asset::Type { - if (type == "required") { + if (type == "require") { return ProfileStruct::Asset::Type::Require; } if (type == "request") { @@ -371,7 +441,7 @@ void ProfileFile::parseAsset(std::string line) { } throw ProfileError( _lineNum, - fmt::format("Expected asset type 'required' or 'request', got {}", type) + fmt::format("Expected asset type 'require' or 'request', got {}", type) ); }(fields[1]); profile.assets.push_back(std::move(a)); @@ -573,7 +643,7 @@ void ProfileFile::parseCamera(std::string line) { if (fields.empty()) { throw ProfileError(_lineNum, "No values specified for Camera location"); } - if (fields[0] == "setNavigationState") { + if (fields[0] == ProfileStruct::CameraNavState::Type) { if (fields.size() != 8) { throw ProfileError( _lineNum, @@ -594,7 +664,7 @@ void ProfileFile::parseCamera(std::string line) { profile.camera = std::move(camera); return; } - if (fields[0] == "goToGeo") { + if (fields[0] == ProfileStruct::CameraGoToGeo::Type) { if (fields.size() != 5) { throw ProfileError( _lineNum, diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index bc94bd6314..1d5833e471 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -206,6 +206,6 @@ TEST_CASE("profileFile: Write test", "[profileFile]") { ProfileFile pf(testFile); - std::string result = pf.writeToString(); + std::string result = serialize(pf.profile); REQUIRE(testFull_string == result); } From d2fd3b8f1f1cdee50a6bcaa6060c3b4864f7fb7e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 17 Jun 2020 11:12:01 +0200 Subject: [PATCH 21/61] Include helper assets and base assets explicitly Add a new function to export profile struct to module text --- data/assets/apollo8.profile | 11 +- data/assets/apollo_sites.profile | 19 ++- data/assets/dawn.profile | 11 +- data/assets/default.profile | 9 +- data/assets/default_full.profile | 19 ++- data/assets/gaia.profile | 17 ++- data/assets/insight.profile | 7 +- data/assets/juno.profile | 7 +- data/assets/messenger.profile | 7 +- data/assets/newhorizons.profile | 9 +- data/assets/osirisrex.profile | 9 +- data/assets/rosetta.profile | 9 +- data/assets/touch.profile | 9 +- data/assets/util/scene_helper.asset | 1 - data/assets/voyager.profile | 21 +-- include/openspace/scene/profilefile.h | 6 +- src/scene/profile.cpp | 28 +--- src/scene/profilefile.cpp | 190 ++++++++++++++++++++++---- 18 files changed, 295 insertions(+), 94 deletions(-) diff --git a/data/assets/apollo8.profile b/data/assets/apollo8.profile index 13638ccb1d..2c50610c09 100644 --- a/data/assets/apollo8.profile +++ b/data/assets/apollo8.profile @@ -2,9 +2,14 @@ 1.0 #Asset -scene/solarsystem/planets/earth/moon/moon require -scene/solarsystem/missions/apollo/8/apollo8 require -scene/solarsystem/planets/earth/earth require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/earth/moon/moon require +scene/solarsystem/missions/apollo/8/apollo8 require +scene/solarsystem/planets/earth/earth require #Property setPropertyValueSingle NavigationHandler.OrbitalNavigator.MinimumAllowedDistance 0.000000 diff --git a/data/assets/apollo_sites.profile b/data/assets/apollo_sites.profile index 9cd537a7d0..5b1bcc786d 100644 --- a/data/assets/apollo_sites.profile +++ b/data/assets/apollo_sites.profile @@ -2,13 +2,18 @@ 1.0 #Asset -scene/solarsystem/planets/earth/moon/moon require -scene/solarsystem/missions/apollo/8/apollo8 require -scene/solarsystem/missions/apollo/11/apollo11 require -scene/solarsystem/missions/apollo/17/lem require -scene/solarsystem/missions/apollo/apollo_globebrowsing require -scene/solarsystem/missions/apollo/11/lem_flipbook require -scene/solarsystem/missions/apollo/insignias_map require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/earth/moon/moon require +scene/solarsystem/missions/apollo/8/apollo8 require +scene/solarsystem/missions/apollo/11/apollo11 require +scene/solarsystem/missions/apollo/17/lem require +scene/solarsystem/missions/apollo/apollo_globebrowsing require +scene/solarsystem/missions/apollo/11/lem_flipbook require +scene/solarsystem/missions/apollo/insignias_map require #Property setPropertyValueSingle Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode 0 diff --git a/data/assets/dawn.profile b/data/assets/dawn.profile index f94d2a325a..603ad0d504 100644 --- a/data/assets/dawn.profile +++ b/data/assets/dawn.profile @@ -2,9 +2,14 @@ 1.0 #Asset -scene/solarsystem/missions/dawn/ceres require -scene/solarsystem/missions/dawn/dawn require -scene/solarsystem/missions/dawn/vesta require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/dawn/ceres require +scene/solarsystem/missions/dawn/dawn require +scene/solarsystem/missions/dawn/vesta require #Time absolute 2011 AUG 06 00:00:00 diff --git a/data/assets/default.profile b/data/assets/default.profile index 6f4a41d1b0..33831bef7c 100644 --- a/data/assets/default.profile +++ b/data/assets/default.profile @@ -2,8 +2,13 @@ 1.0 #Asset -scene/solarsystem/planets/earth/earth require -scene/solarsystem/planets/earth/satellites/satellites require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/earth/satellites/satellites require #Property setPropertyValue {earth_satellites}.Renderable.Enabled false diff --git a/data/assets/default_full.profile b/data/assets/default_full.profile index 9e98477827..76721f3a73 100644 --- a/data/assets/default_full.profile +++ b/data/assets/default_full.profile @@ -2,13 +2,18 @@ 1.0 #Asset -scene/solarsystem/planets/earth/earth require -scene/solarsystem/planets/jupiter/minor_moons require -scene/solarsystem/planets/saturn/minor_moons require -scene/solarsystem/planets/uranus/minor_moons require -scene/solarsystem/planets/neptune/inner_moons require -scene/solarsystem/planets/neptune/irregular_prograde_moons require -scene/solarsystem/planets/neptune/irregular_retrograde_moons require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/jupiter/minor_moons require +scene/solarsystem/planets/saturn/minor_moons require +scene/solarsystem/planets/uranus/minor_moons require +scene/solarsystem/planets/neptune/inner_moons require +scene/solarsystem/planets/neptune/irregular_prograde_moons require +scene/solarsystem/planets/neptune/irregular_retrograde_moons require #Time relative -1d diff --git a/data/assets/gaia.profile b/data/assets/gaia.profile index 922ccc15b4..54e49d9593 100644 --- a/data/assets/gaia.profile +++ b/data/assets/gaia.profile @@ -5,12 +5,17 @@ Gaia openspace.printFatal('Could not load scene due to missing module "gaia"') #Asset -scene/solarsystem/planets/earth/earth require -scene/milkyway/gaia/gaiastars require -scene/milkyway/gaia/apogee require -scene/milkyway/gaia/galah require -scene/solarsystem/missions/gaia/gaia require -scene/solarsystem/missions/gaia/trail require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/earth/earth require +scene/milkyway/gaia/gaiastars require +scene/milkyway/gaia/apogee require +scene/milkyway/gaia/galah require +scene/solarsystem/missions/gaia/gaia require +scene/solarsystem/missions/gaia/trail require #Property setPropertyValueSingle Scene.Stars.Renderable.Enabled false diff --git a/data/assets/insight.profile b/data/assets/insight.profile index cc5be21b46..7b30dba282 100644 --- a/data/assets/insight.profile +++ b/data/assets/insight.profile @@ -2,7 +2,12 @@ 1.0 #Asset -scene/solarsystem/missions/insight/edl require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/insight/edl require #Property setPropertyValueSingle Scene.PlutoBarycenterTrail.Renderable.Enabled false diff --git a/data/assets/juno.profile b/data/assets/juno.profile index c17b10c283..3b38739df0 100644 --- a/data/assets/juno.profile +++ b/data/assets/juno.profile @@ -2,7 +2,12 @@ 1.0 #Asset -scene/solarsystem/missions/juno/juno require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/juno/juno require #Keybinding 1 Setting the simulation speed to 1 seconds per realtime second Set sim speed 1 /Simulation Speed false "openspace.time.interpolateDeltaTime(1)" diff --git a/data/assets/messenger.profile b/data/assets/messenger.profile index 740cc62cc3..3d268995e7 100644 --- a/data/assets/messenger.profile +++ b/data/assets/messenger.profile @@ -5,7 +5,12 @@ Volume asset.require('scene/solarsystem/missions/messenger/mercurymagnetosphere') openspace.printWarning("Volume module is not loaded, skipping asset: mercurymagnetosphere") #Asset -scene/solarsystem/missions/messenger/messengerSC require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/messenger/messengerSC require #Keybinding 1 Setting the simulation speed to 1 seconds per realtime second Set sim speed 1 /Simulation Speed false "openspace.time.interpolateDeltaTime(1)" diff --git a/data/assets/newhorizons.profile b/data/assets/newhorizons.profile index 400a2fde81..1b96e05c7b 100644 --- a/data/assets/newhorizons.profile +++ b/data/assets/newhorizons.profile @@ -2,8 +2,13 @@ 1.0 #Asset -scene/solarsystem/missions/newhorizons/newhorizons require -scene/solarsystem/missions/newhorizons/model require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/newhorizons/newhorizons require +scene/solarsystem/missions/newhorizons/model require #Property setPropertyValueSingle NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance 20.000000 diff --git a/data/assets/osirisrex.profile b/data/assets/osirisrex.profile index 099678c382..8077989134 100644 --- a/data/assets/osirisrex.profile +++ b/data/assets/osirisrex.profile @@ -2,8 +2,13 @@ 1.0 #Asset -scene/solarsystem/missions/osirisrex/model require -scene/solarsystem/missions/osirisrex/osirisrex require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/osirisrex/model require +scene/solarsystem/missions/osirisrex/osirisrex require #Property setPropertyValueSingle NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance 20.000000 diff --git a/data/assets/rosetta.profile b/data/assets/rosetta.profile index a7f2b3bdd4..206e3b0a1e 100644 --- a/data/assets/rosetta.profile +++ b/data/assets/rosetta.profile @@ -5,8 +5,13 @@ Volume asset.require('scene/solarsystem/missions/messenger/mercurymagnetosphere') openspace.printWarning("Volume module is not loaded, skipping asset: mercurymagnetosphere") #Asset -scene/solarsystem/missions/rosetta/67p require -scene/solarsystem/missions/rosetta/rosetta require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/missions/rosetta/67p require +scene/solarsystem/missions/rosetta/rosetta require #Property setPropertyValue Scene.67P.Renderable.PerformShading false diff --git a/data/assets/touch.profile b/data/assets/touch.profile index a770c1ceb6..f296c95fc3 100644 --- a/data/assets/touch.profile +++ b/data/assets/touch.profile @@ -5,8 +5,13 @@ Touch local webGui = asset.require('util/webgui'); webGui.setCefRoute("ontouch") openspace.printFatal('Could not load scene due to missing module "touch"') #Asset -scene/solarsystem/planets/earth/earth require -util/webgui require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/earth/earth require +util/webgui require #Property setPropertyValueSingle Scene.Pluto.Renderable.Enabled false diff --git a/data/assets/util/scene_helper.asset b/data/assets/util/scene_helper.asset index 579af633d8..9e7a87cc3c 100644 --- a/data/assets/util/scene_helper.asset +++ b/data/assets/util/scene_helper.asset @@ -9,7 +9,6 @@ local bindKeys = function(t, ignoreWarning) local currentKey = openspace.getKeyBinding(k.Key) if (next(currentKey) ~= nil) and (not ignoreWarning) then - openspace.printWarning('New keybind for "' .. k.Key .. '" is added, but a previous keybind already existed. If you want to silence this warning, pass "true", to this call to bindKeys') end diff --git a/data/assets/voyager.profile b/data/assets/voyager.profile index a3e6401223..c2f50a2acb 100644 --- a/data/assets/voyager.profile +++ b/data/assets/voyager.profile @@ -2,14 +2,19 @@ 1.0 #Asset -scene/solarsystem/planets/jupiter/minor_moons require -scene/solarsystem/planets/saturn/minor_moons require -scene/solarsystem/planets/uranus/minor_moons require -scene/solarsystem/planets/neptune/inner_moons require -scene/solarsystem/planets/neptune/irregular_prograde_moons require -scene/solarsystem/planets/neptune/irregular_retrograde_moons require -scene/solarsystem/missions/voyager/voyager1 require -scene/solarsystem/missions/voyager/voyager2 require +util/asset_helper require assetHelper +util/property_helper require propertyHelper +util/scene_helper require sceneHelper +util/renderable_helper require renderableHelper +base require +scene/solarsystem/planets/jupiter/minor_moons require +scene/solarsystem/planets/saturn/minor_moons require +scene/solarsystem/planets/uranus/minor_moons require +scene/solarsystem/planets/neptune/inner_moons require +scene/solarsystem/planets/neptune/irregular_prograde_moons require +scene/solarsystem/planets/neptune/irregular_retrograde_moons require +scene/solarsystem/missions/voyager/voyager1 require +scene/solarsystem/missions/voyager/voyager2 require #Keybinding 1 Setting the simulation speed to 1 seconds per realtime second Set sim speed 1 /Simulation Speed false "openspace.time.interpolateDeltaTime(1)" diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 026c45e8fa..753433ec1c 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -46,7 +46,7 @@ namespace scripting { struct LuaLibrary; } const size_t timeLinesExpected = 1; const size_t cameraLinesExpected = 1; const size_t moduleFieldsExpected = 3; -const size_t assetFieldsExpected = 2; +const size_t assetFieldsExpected = 3; const size_t propertyFieldsExpected = 3; const size_t keybindingFieldsExpected = 6; const size_t timeFieldsExpected = 2; @@ -107,6 +107,7 @@ struct ProfileStruct { std::string path; Type type; + std::string name; }; std::vector assets; @@ -168,6 +169,9 @@ struct ProfileStruct { }; std::string serialize(const ProfileStruct& ps); +ProfileStruct deserialize(const std::string& filename); + +std::string convertToSceneFile(const ProfileStruct& ps); class ProfileFile { public: diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index bde1d7291b..16d8c703d2 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -360,22 +360,7 @@ void Profile::convertToSceneFile(const std::string& inProfilePath, } std::string Profile::convertToScene(ProfileFile& pf) { - ZoneScoped - - std::string result; - - result += convertToScene_modules(pf) + "\n"; - result += convertToScene_assets(pf) + "\n"; - result += convertToScene_keybindings(pf) + "\n"; - result += "asset.onInitialize(function ()\n"; - result += convertToScene_time(pf) + "\n"; - result += " sceneHelper.bindKeys(Keybindings)\n\n"; - result += convertToScene_markNodes(pf) + "\n"; - result += convertToScene_properties(pf) + "\n"; - result += convertToScene_camera(pf); - result += "end)\n"; - - return result; + return openspace::convertToSceneFile(pf.profile); } std::string Profile::convertToScene_modules(ProfileFile& pf) { @@ -409,12 +394,6 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { std::string result; std::string assetR; - result += "asset.require(\"base\");\n"; - result += "local assetHelper = asset.require(\"util/asset_helper\")\n"; - result += "local propertyHelper = asset.require(\"util/property_helper\")\n"; - result += "local sceneHelper = asset.require(\"util/scene_helper\")\n"; - result += "local renderableHelper = asset.require(\"util/renderable_helper\")\n"; - for (size_t i = 0; i < pf.assets().size(); ++i) { std::vector fields = ghoul::tokenizeString(pf.assets()[i], '\t'); @@ -434,7 +413,12 @@ std::string Profile::convertToScene_assets(ProfileFile& pf) { ); throw ghoul::RuntimeError(err); } + + if (!fields[2].empty()) { + result += fmt::format("local {} = ", fields[2]); + } result += fmt::format("asset.{}(\"{}\")\n", assetR, fields[assetFieldName]); + } return result; } diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index e36fc8b65d..95896ed6b5 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -123,28 +123,31 @@ std::string serialize(const ProfileStruct& ps) { } output += fmt::format("\n{}\n", headerCamera); - output += std::visit(overloaded{ - [](const ProfileStruct::CameraNavState& camera) { - return fmt::format( - "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", - ProfileStruct::CameraNavState::Type, - camera.anchor, camera.aim, camera.referenceFrame, camera.position, - camera.up, camera.yaw, camera.pitch - ); - }, - [](const ProfileStruct::CameraGoToGeo& camera) { - std::string altitude; - if (camera.altitude.has_value()) { - altitude = std::to_string(*camera.altitude); - } + output += std::visit( + overloaded { + [](const ProfileStruct::CameraNavState& camera) { + return fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", + ProfileStruct::CameraNavState::Type, + camera.anchor, camera.aim, camera.referenceFrame, camera.position, + camera.up, camera.yaw, camera.pitch + ); + }, + [](const ProfileStruct::CameraGoToGeo& camera) { + std::string altitude; + if (camera.altitude.has_value()) { + altitude = std::to_string(*camera.altitude); + } - return fmt::format( - "{}\t{}\t{}\t{}\t{}\n", - ProfileStruct::CameraGoToGeo::Type, - camera.anchor, camera.latitude, camera.longitude, altitude - ); - } - }, ps.camera); + return fmt::format( + "{}\t{}\t{}\t{}\t{}\n", + ProfileStruct::CameraGoToGeo::Type, + camera.anchor, camera.latitude, camera.longitude, altitude + ); + } + }, + ps.camera + ); output += fmt::format("\n{}\n", headerMarkNodes); for (const std::string& n : ps.markNodes) { @@ -154,6 +157,145 @@ std::string serialize(const ProfileStruct& ps) { return output; } +ProfileStruct deserialize(const std::string& filename) { + return ProfileStruct(); +} + +std::string convertToSceneFile(const ProfileStruct& ps) { + ZoneScoped + + std::string output; + + // Modules + for (const ProfileStruct::Module& m : ps.modules) { + output += fmt::format( + "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", + m.name, m.loadedInstruction, m.notLoadedInstruction + ); + } + + // Assets + for (const ProfileStruct::Asset& a : ps.assets) { + if (!a.name.empty()) { + output += fmt::format("local {} = ", a.name); + } + std::string type = [](ProfileStruct::Asset::Type t) { + switch (t) { + case ProfileStruct::Asset::Type::Request: return "request"; + case ProfileStruct::Asset::Type::Require: return "require"; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + + output += fmt::format("asset.{}(\"{}\");\n", type, a.path); + } + + output += "asset.onInitialize(function()\n"; + // Keybindings + for (const ProfileStruct::Keybinding& k : ps.keybindings) { + const std::string name = k.name.empty() ? k.key : k.name; + output += fmt::format( + k.isLocal ? + "openspace.bindKeyLocal(\"{}\", {}, [[{}]], [[{}]], [[{}]]);\n" : + "openspace.bindKey(\"{}\", {}, [[{}]], [[{}]], [[{}]]);\n", + k.key, k.script, k.documentation, k.name.empty() ? k.key : k.name, k.guiPath + ); + } + + // Time + switch (ps.time.type) { + case ProfileStruct::Time::Type::Absolute: + output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); + break; + case ProfileStruct::Time::Type::Relative: + output += "local now = openspace.time.currentWallTime();\n"; + output += fmt::format( + "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time + ); + output += "openspace.time.setTime(prev);\n"; + default: + throw ghoul::MissingCaseException(); + } + + // Mark Nodes + { + std::string nodes; + for (const std::string& n : ps.markNodes) { + nodes += fmt::format("[[ {} ]],", n); + } + output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes); + } + + // Properties + for (const ProfileStruct::Property& p : ps.properties) { + constexpr const char* regular = "openspace.setPropertyValue(\"{}\", {});\n"; + constexpr const char* single = "openspace.setPropertyValueSingle(\"{}\", {});\n"; + + switch (p.setType) { + case ProfileStruct::Property::SetType::SetPropertyValue: + output += fmt::format( + "openspace.setPropertyValue(\"{}\", {});\n", + p.name, p.value + ); + break; + case ProfileStruct::Property::SetType::SetPropertyValueSingle: + output += fmt::format( + "openspace.setPropertyValueSingle(\"{}\", {});\n", + p.name, p.value + ); + break; + default: + throw ghoul::MissingCaseException(); + } + } + + // Camera + output += std::visit( + overloaded { + [](const ProfileStruct::CameraNavState& camera) { + std::string result; + result += " openspace.navigation.setNavigationState({"; + result += fmt::format("Anchor = {}, ", camera.anchor); + if (!camera.aim.empty()) { + result += fmt::format("Aim = {}, ", camera.aim); + } + if (!camera.referenceFrame.empty()) { + result += fmt::format("ReferenceFrame = {}, ", camera.referenceFrame); + } + result += fmt::format("Position = {{ {} }}, ", camera.position); + if (!camera.up.empty()) { + result += fmt::format("Up = {{ {} }}, ", camera.up); + } + if (!camera.yaw.empty()) { + result += fmt::format("Yaw = {}, ", camera.yaw); + } + if (!camera.pitch.empty()) { + result += fmt::format("Pitch = {} ", camera.pitch); + } + result += "})\n"; + return result; + }, + [](const ProfileStruct::CameraGoToGeo& camera) { + if (camera.altitude.has_value()) { + return fmt::format( + "openspace.globebrowsing.goToGeo({}, {}, {}, {});\n", + camera.anchor, camera.latitude, camera.longitude, *camera.altitude + ); + } + else { + return fmt::format( + "openspace.globebrowsing.goToGeo({}, {}, {});\n", + camera.anchor, camera.latitude, camera.longitude + ); + } + } + }, + ps.camera + ); + output += "end)\n"; + + return output; +} ProfileFile::ProfileFile(std::string filename) { clearAllFields(); @@ -414,6 +556,7 @@ void ProfileFile::parseAsset(std::string line) { } std::vector standard = { "asset name", + "", "" }; verifyRequiredFields("Asset", fields, standard, assetFieldsExpected); @@ -423,10 +566,10 @@ void ProfileFile::parseAsset(std::string line) { // // New // - if (fields.size() != 2) { + if (fields.size() != 3) { throw ProfileError( _lineNum, - fmt::format("Expected 2 fields in an Asset entry, got {}", fields.size()) + fmt::format("Expected 3 fields in an Asset entry, got {}", fields.size()) ); } @@ -444,6 +587,7 @@ void ProfileFile::parseAsset(std::string line) { fmt::format("Expected asset type 'require' or 'request', got {}", type) ); }(fields[1]); + a.name = fields[2]; profile.assets.push_back(std::move(a)); } From fe989d1ea174b7bda7a95fb471009b0edf550270 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Wed, 17 Jun 2020 19:02:11 +0200 Subject: [PATCH 22/61] Continuing on the work to use the struct variant of profiles --- include/openspace/scene/profile.h | 7 - include/openspace/scene/profilefile.h | 70 +- src/scene/profile.cpp | 299 ++------- src/scene/profilefile.cpp | 891 ++++++++++---------------- 4 files changed, 389 insertions(+), 878 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 4b6c1bbc46..f0f5dde450 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -113,13 +113,6 @@ private: virtual std::string profileBaseDirectory() const; virtual std::vector assetEvents() const; ProfileFile collateBaseWithChanges(); - std::string convertToScene_assets(ProfileFile& pf); - std::string convertToScene_modules(ProfileFile& pf); - std::string convertToScene_properties(ProfileFile& pf); - std::string convertToScene_markNodes(ProfileFile& pf); - std::string convertToScene_keybindings(ProfileFile& pf); - std::string convertToScene_time(ProfileFile& pf); - std::string convertToScene_camera(ProfileFile& pf); std::vector modifyAssetsToReflectChanges(ProfileFile& pf); void parseAssetFileLines(std::vector& results, ProfileFile& pf); diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 753433ec1c..ec3e837476 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -90,7 +90,7 @@ struct ProfileStruct { int minor = 0; int patch = 0; }; - Version version; + Version version = { 1, 0, 0 }; struct Module { std::string name; @@ -150,8 +150,8 @@ struct ProfileStruct { std::string anchor; std::string aim; std::string referenceFrame; - std::string position; - std::string up; + std::string position; // @TODO (abock, 2020-06-17) change to vec3 + std::string up;// @TODO (abock, 2020-06-17) change to vec3 std::string yaw; std::string pitch; }; @@ -200,14 +200,14 @@ public: * is defined by ProfileFile::parseTime and Profile::convertToAsset_time * \param line The time entry line to replace current time entry */ - void updateTime(std::string line); + //void updateTime(std::string line); /** * Updates the full string that defines the starting camera position. The format for * this line is defined by ProfileFile::parseCamera & Profile::convertToAsset_camera * \param line The camera entry line to replace current camera entry */ - void updateCamera(std::string line); + //void updateCamera(std::string line); /** * Adds a new module line to the list of module lines to be analyzed by the profile @@ -215,19 +215,19 @@ public: * and Profile::convertToAsset_modules * \param line The module name to be added */ - void addModuleLine(std::string line); + //void addModuleLine(std::string line); /** * Adds a new asset to the list of assets to be loaded at startup. The format for an * asset line is defined by ProfileFile::parseAsset & Profile::convertToAsset_assets * \param line The asset name to be added */ - void addAssetLine(std::string line); + //void addAssetLine(std::string line); /** * Clears all asset entries */ - void clearAssets(); + //void clearAssets(); /** * Adds a new property set command to the list of property settings to be @@ -235,7 +235,7 @@ public: * ProfileFile::parseProperty and Profile::convertToAsset_properties * \param line The property set command to be added */ - void addPropertyLine(std::string line); + //void addPropertyLine(std::string line); /** * Adds a new keybinding shortcut to the list of keybindings. The format for a @@ -243,7 +243,7 @@ public: * Profile::convertToAsset_keybindings * \param line The keyboard shortcut line to be added */ - void addKeybindingLine(std::string line); + //void addKeybindingLine(std::string line); /** * Adds a new scenegraph node name to be added to the list of those marked as @@ -251,98 +251,68 @@ public: * ProfileFile::parseMarkNodes and Profile::convertToAsset_markNodes * \param line The scenegraph node to be added */ - void addMarkNodesLine(std::string line); + //void addMarkNodesLine(std::string line); /** * Returns the format version number (profiles syntax version) string * \return The version string */ - const std::string& version() const; + //const std::string& version() const; /** * Sets the format version number (profiles syntax version) string * \param The version string to set */ - void setVersion(std::string); + //void setVersion(std::string); /** * Returns the profile's time string. See updateTime comment header for notes on * syntax of this time string * \return The time string */ - std::string time() const; + //std::string time() const; /** * Returns the profile's camera string. See updateCamera comment header for notes on * syntax of this camera string * \return The camera string */ - std::string camera() const; + //std::string camera() const; /** * Returns the vector of OpenSpace modules listed in this profile. See addModuleLine * comment header for notes on the syntax of each entry. * \return The vector of module lines */ - std::vector modules() const; + //std::vector modules() const; /** * Returns the vector of OpenSpace assets listed in this profile. See addAssetLine * comment header for notes on the syntax of each entry. * \return The vector of asset lines */ - Lines assets() const; + //Lines assets() const; /** * Returns the vector of OpenSpace property set commands included in this profile. * See addPropertyLine comment header for notes on the syntax of each entry. * \return The vector of property set commands */ - Lines properties() const; + //Lines properties() const; /** * Returns the vector of OpenSpace keybinding shortcut definitions included in this * profile. See addKeybindingLine comment header for syntax notes of each entry. * \return The vector of keybinding shortcut definitions */ - Lines keybindings() const; + //Lines keybindings() const; /** * Returns the vector of OpenSpace scenegraph nodes marked as 'interesting'. * See addMarkNodesLine comment header for syntax notes of each entry. * \return The vector of nodes to be marked as interesting. */ - Lines markNodes() const; - -private: - void clearAllFields(); - void verifyRequiredFields(std::string sectionName, std::vector fields, - std::vector standard, unsigned int nFields); - void processIndividualLine(bool& insideSection, std::string line); - void determineSection(std::string line); - void (ProfileFile::* parseCurrentSection)(std::string); - void parseVersion(std::string line); - void parseModule(std::string line); - void parseAsset(std::string line); - void parseProperty(std::string line); - void parseKeybinding(std::string line); - void parseTime(std::string line); - void parseCamera(std::string line); - void parseMarkNodes(std::string line); - - size_t _lineNum = 1; - size_t _numLinesVersion = 0; - size_t _numLinesTime = 0; - size_t _numLinesCamera = 0; - - std::string _version; - std::string _time; - std::string _camera; - Lines _modules; - Lines _assets; - Lines _properties; - Lines _keybindings; - Lines _markNodes; + //Lines markNodes() const; }; } // namespace openspace diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 16d8c703d2..559754a3dc 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -109,12 +109,13 @@ namespace { void addAssetsToProfileFile(ProfileFile& pf, const std::vector& allAssets) { - pf.clearAssets(); + pf.profile.assets.clear(); for (Profile::AssetEvent a : allAssets) { if (a.eventType != Profile::AssetEventType::Ignore) { - std::string entry = - a.name + "\t" + AssetEventTypeString.at(a.eventType); - pf.addAssetLine(entry); + ProfileStruct::Asset asset; + asset.path = a.name; + asset.type = ProfileStruct::Asset::Type::Require; + pf.profile.assets.push_back(std::move(asset)); } } } @@ -185,15 +186,17 @@ ProfileFile Profile::collateBaseWithChanges() { std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + ".profile"; ProfileFile pf(inputProfilePath); - pf.setVersion(FormatVersion); + pf.profile.version = ProfileStruct::Version{}; + std::vector ass = modifyAssetsToReflectChanges(pf); addAssetsToProfileFile(pf, ass); modifyPropertiesToReflectChanges(pf); // add current time to profile file - std::string t = currentTimeUTC(); - std::string update = "absolute\t" + t; - pf.updateTime(update); + ProfileStruct::Time time; + time.time = currentTimeUTC(); + time.type = ProfileStruct::Time::Type::Absolute; + pf.profile.time = std::move(time); addCurrentCameraToProfileFile(pf); return pf; @@ -221,46 +224,30 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi } void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf) { - AssetEvent a; - - for (std::string line : pf.assets()) { - std::vector elements = ghoul::tokenizeString(line, '\t'); - - if (elements[0].empty()) { - LERROR(fmt::format( - "Error parsing profile line '{}'. Asset name is needed (field 1/2)", - line - )); - } - else { - a.name = elements[0]; - } - - if (elements[1] == AssetEventTypeString.at(AssetEventType::Require)) { - a.eventType = AssetEventType::Require; - } - else if (elements[1] == AssetEventTypeString.at(AssetEventType::Request)) { - a.eventType = AssetEventType::Request; - } - else if (elements[1] == "") { - a.eventType = AssetEventType::Request; - } - else { - LERROR(fmt::format( - "Error parsing profile line '{}'. Invalid required param (field 2/2)", - line - )); - } - - results.push_back(a); + for (ProfileStruct::Asset& a : pf.profile.assets) { + AssetEvent assetEvent; + assetEvent.name = a.path; + assetEvent.eventType = [](ProfileStruct::Asset::Type type) { + switch (type) { + case ProfileStruct::Asset::Type::Request: return AssetEventType::Request; + case ProfileStruct::Asset::Type::Require: return AssetEventType::Require; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + results.push_back(assetEvent); } } void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { - std::vector formatted = changedPropertiesFormatted(); + std::vector changedProps = changedProperties(); + std::vector formattedLines; - for (std::string line : formatted) { - pf.addPropertyLine(std::move(line)); + for (properties::Property* prop : changedProps) { + ProfileStruct::Property p; + p.setType = ProfileStruct::Property::SetType::SetPropertyValueSingle; + p.name = getFullPropertyPath(prop); + p.value = prop->getStringValue(); + pf.profile.properties.push_back(std::move(p)); } } @@ -303,27 +290,25 @@ interaction::NavigationHandler::NavigationState Profile::currentCameraState() co } void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) const { - std::string update = "setNavigationState\t"; - interaction::NavigationHandler::NavigationState nav; - nav = currentCameraState(); - update += "\"" + nav.anchor + "\"\t"; - update += "\"" + nav.aim + "\"\t"; - update += "\"" + nav.referenceFrame + "\"\t"; - update += std::to_string(nav.position.x) + ","; - update += std::to_string(nav.position.y) + ","; - update += std::to_string(nav.position.z) + "\t"; - if (nav.up.has_value()) { - glm::dvec3 u = nav.up.value(); - //glm::dvec3 u = static_cast(nav.up.value()); - update += std::to_string(u.x) + ","; - update += std::to_string(u.y) + ","; - update += std::to_string(u.z); - } - update += "\t"; - update += std::to_string(nav.yaw) + "\t"; - update += std::to_string(nav.pitch); + interaction::NavigationHandler::NavigationState nav = currentCameraState(); - pf.updateCamera(update); + ProfileStruct::CameraNavState camera; + camera.anchor = nav.anchor; + camera.aim = nav.aim; + camera.referenceFrame = nav.referenceFrame; + camera.position = fmt::format( + "{},{},{}", + nav.position.x, nav.position.y, nav.position.z + ); + if (nav.up.has_value()) { + camera.up = fmt::format( + "{},{},{}", + nav.up->x, nav.up->y, nav.up->z + ); + } + camera.yaw = nav.yaw; + camera.pitch = nav.pitch; + pf.profile.camera = std::move(camera); } void Profile::convertToSceneFile(const std::string& inProfilePath, @@ -363,194 +348,6 @@ std::string Profile::convertToScene(ProfileFile& pf) { return openspace::convertToSceneFile(pf.profile); } -std::string Profile::convertToScene_modules(ProfileFile& pf) { - std::string result; - - for (std::string m : pf.modules()) { - std::vector fields = ghoul::tokenizeString(m, '\t'); - if (!fields[moduleFieldLoaded].empty() && !fields[moduleFieldNotLoaded].empty()) { - result += fmt::format( - "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", - fields[moduleFieldName], fields[moduleFieldLoaded], fields[moduleFieldNotLoaded] - ); - } - else if (fields[moduleFieldNotLoaded].empty()) { - result += fmt::format( - "if not openspace.modules.isLoaded(\"{}\") then {} end\n", - fields[moduleFieldName], fields[moduleFieldNotLoaded] - ); - } - else if (fields[moduleFieldLoaded].empty()) { - result += fmt::format( - "if openspace.modules.isLoaded(\"{}\") then {} end\n", - fields[moduleFieldName], fields[moduleFieldLoaded] - ); - } - } - return result; -} - -std::string Profile::convertToScene_assets(ProfileFile& pf) { - std::string result; - std::string assetR; - - for (size_t i = 0; i < pf.assets().size(); ++i) { - std::vector fields = ghoul::tokenizeString(pf.assets()[i], '\t'); - - if (fields[assetFieldReqd] == "require") { - assetR = "require"; - } - else if (fields[assetFieldReqd] == "request") { - assetR = "request"; - } - else if (fields[assetFieldReqd] == "") { - assetR = "require"; - } - else { - std::string err = fmt::format( - "Asset {} of {} has bad arg 2/2 which must be 'require' or 'request'", - i + 1, pf.assets().size() - ); - throw ghoul::RuntimeError(err); - } - - if (!fields[2].empty()) { - result += fmt::format("local {} = ", fields[2]); - } - result += fmt::format("asset.{}(\"{}\")\n", assetR, fields[assetFieldName]); - - } - return result; -} - -std::string Profile::convertToScene_properties(ProfileFile& pf) { - std::string result; - - for (size_t i = 0; i < pf.properties().size(); ++i) { - std::vector fields = ghoul::tokenizeString(pf.properties()[i], '\t'); - - if (fields[propertyFieldType] != "setPropertyValue" - && fields[propertyFieldType] != "setPropertyValueSingle") - { - std::string err = fmt::format( - "Property {} of {} has bad arg 1/1 which must be " - "'setPropertyValue' or 'setPropertyValueSingle'", - i + 1, pf.properties().size() - ); - throw ghoul::RuntimeError(err); - } - else { - result += fmt::format( - " openspace.{}(\"{}\", {})\n", - fields[propertyFieldType], fields[propertyFieldName], fields[propertyFieldValue] - ); - } - } - return result; -} - -std::string Profile::convertToScene_keybindings(ProfileFile& pf) { - std::string result; - - result += "local Keybindings = {\n"; - for (size_t i = 0; i < pf.keybindings().size(); ++i) { - std::vector fields = ghoul::tokenizeString(pf.keybindings()[i], '\t'); - - result += " {\n"; - result += fmt::format(" {} = \"{}\",\n", "Key", fields[0]); - result += fmt::format(" {} = \"{}\",\n", "Documentation", fields[1]); - result += fmt::format(" {} = \"{}\",\n", "Name", fields[2]); - result += fmt::format(" {} = \"{}\",\n", "GuiPath", fields[3]); - result += fmt::format(" {} = \"{}\",\n", "Local", fields[4]); - result += fmt::format(" {} = {}\n", "Command", fields[5]); - result += " },\n"; - } - result += "}\n"; - return result; -} - -std::string Profile::convertToScene_markNodes(ProfileFile& pf) { - std::string result; - - if (!pf.markNodes().empty()) { - result += " openspace.markInterestingNodes({"; - for (const std::string& m : pf.markNodes()) { - result += fmt::format("\"{}\",", m); - } - result += "})\n"; - } - return result; -} - -std::string Profile::convertToScene_time(ProfileFile& pf) { - std::string result; - - std::vector fields = ghoul::tokenizeString(pf.time(), '\t'); - if (fields[timeFieldType] == "absolute") { - result += fmt::format(" openspace.time.setTime(\"{}\")\n", fields[timeFieldSet]); - } - else if (fields[timeFieldType] == "relative") { - result += fmt::format( - " openspace.time.setTime(openspace.time.advancedTime(" - "openspace.time.currentWallTime(), \"{}\"))\n", - fields[timeFieldSet] - ); - result += " local now = openspace.time.currentWallTime(); "; - result += "openspace.time.setTime("; - result += "openspace.time.advancedTime(now, \"" + fields[timeFieldSet] + "\"))\n"; - } - else { - std::string err = "Time entry's arg 1/1 must be either 'absolute' or 'relative'"; - throw ghoul::RuntimeError(err); - } - return result; -} - -std::string Profile::convertToScene_camera(ProfileFile& pf) { - std::string result; - - std::vector fields = ghoul::tokenizeString(pf.camera(), '\t'); - if (fields[cameraFieldType] == "setNavigationState") { - result += " openspace.navigation.setNavigationState({"; - result += fmt::format("Anchor = {}, ", fields[cameraNavigationFieldAnchor]); - if (!fields[cameraNavigationFieldAim].empty()) { - result += fmt::format("Aim = {}, ", fields[cameraNavigationFieldAim]); - } - if (!fields[cameraNavigationFieldRef].empty()) { - result += fmt::format("ReferenceFrame = {}, ", fields[cameraNavigationFieldRef]); - } - result += fmt::format("Position = {{ {} }}, ", fields[cameraNavigationFieldPosition]); - if (!fields[cameraNavigationFieldUp].empty()) { - result += fmt::format("Up = {{ {} }}, ", fields[cameraNavigationFieldUp]); - } - if (!fields[cameraNavigationFieldYaw].empty()) { - result += fmt::format("Yaw = {}, ", fields[cameraNavigationFieldYaw]); - } - if (!fields[cameraNavigationFieldPitch].empty()) { - result += fmt::format("Pitch = {} ", fields[cameraNavigationFieldPitch]); - } - result += "})\n"; - } - else if (fields[cameraFieldType] == "goToGeo") { - result += " openspace.globebrowsing.goToGeo("; - if (!fields[cameraGeoFieldAnchor].empty()) { - result += fields[cameraGeoFieldAnchor] + ", "; - } - result += fields[cameraGeoFieldLatitude] + ", "; - result += fields[cameraGeoFieldLongitude]; - if (!fields[cameraGeoFieldAltitude].empty()) { - result += + ", " + fields[cameraGeoFieldAltitude]; - } - result += ")\n"; - } - else { - throw ghoul::RuntimeError( - "Camera entry's arg 1/1 must be either 'setNavigationState' or 'goToGeo'" - ); - } - return result; -} - scripting::LuaLibrary Profile::luaLibrary() { return { "", diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 95896ed6b5..18adb59629 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -36,6 +36,8 @@ #include #include +namespace openspace { + namespace { constexpr const char* _loggerCat = "ProfileFile"; constexpr const char* KeyIdentifier = "Identifier"; @@ -52,19 +54,253 @@ namespace { // Helper structs for the visitor pattern of the std::variant template struct overloaded : Ts... { using Ts::operator()...; }; - template overloaded(Ts...) -> overloaded; + template overloaded(Ts...)->overloaded; struct ProfileError : public ghoul::RuntimeError { - explicit ProfileError(unsigned int lineNum, std::string msg) + explicit ProfileError(std::string msg) + : ghoul::RuntimeError(std::move(msg), "profileFile") + {} + + ProfileError(unsigned int lineNum, std::string msg) : ghoul::RuntimeError( fmt::format("Error @ line {}: {}", lineNum, std::move(msg)), "profileFile" ) {} }; -} // namespace -namespace openspace { + enum class Section { + None, + Version, + Module, + Asset, + Property, + Keybinding, + Time, + Camera, + MarkNodes + }; + + Section parseSection(const std::string& line, int lineNumber) { + if (line == headerVersion) { return Section::Version; } + if (line == headerModule) { return Section::Module; } + if (line == headerAsset) { return Section::Asset; } + if (line == headerProperty) { return Section::Property; } + if (line == headerKeybinding) { return Section::Keybinding; } + if (line == headerTime) { return Section::Time; } + if (line == headerCamera) { return Section::Camera; } + if (line == headerMarkNodes) { return Section::MarkNodes; } + + throw ProfileError(lineNumber, fmt::format("Invalid section header: {}", line)); + } + + void parseVersion(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector parts = ghoul::tokenizeString(line, '.'); + if (parts.empty() || parts.size() > 3) { + throw ProfileError( + lineNumber, + fmt::format("Expected 1-3 version components, got {}", parts.size()) + ); + } + + ProfileStruct::Version version; + + version.major = std::stoi(parts[0]); + if (parts.size() > 1) { + version.minor = std::stoi(parts[1]); + } + if (parts.size() > 2) { + version.patch = std::stoi(parts[2]); + } + ps.version = std::move(version); + } + + void parseModule(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 3) { + throw ProfileError( + lineNumber, + fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) + ); + } + ProfileStruct::Module m; + m.name = fields[0]; + m.loadedInstruction = fields[1]; + m.notLoadedInstruction = fields[2]; + ps.modules.push_back(std::move(m)); + } + + void parseAsset(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 3) { + throw ProfileError( + lineNumber, + fmt::format("Expected 3 fields in an Asset entry, got {}", fields.size()) + ); + } + + ProfileStruct::Asset a; + a.path = fields[0]; + a.type = [&](const std::string& type) -> ProfileStruct::Asset::Type { + if (type == "require") { + return ProfileStruct::Asset::Type::Require; + } + if (type == "request") { + return ProfileStruct::Asset::Type::Request; + } + throw ProfileError( + lineNumber, + fmt::format("Expected asset type 'require' or 'request', got {}", type) + ); + }(fields[1]); + a.name = fields[2]; + ps.assets.push_back(std::move(a)); + } + + void parseProperty(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 3) { + throw ProfileError( + lineNumber, + fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) + ); + } + ProfileStruct::Property p; + p.setType = [&](const std::string& type) -> ProfileStruct::Property::SetType { + if (type == "setPropertyValue") { + return ProfileStruct::Property::SetType::SetPropertyValue; + } + if (type == "setPropertyValueSingle") { + return ProfileStruct::Property::SetType::SetPropertyValueSingle; + } + throw ProfileError( + lineNumber, + fmt::format( + "Expected property set type 'setPropertyValue' or " + "'setPropertyValueSingle', got {}", + type + ) + ); + }(fields[0]); + p.name = fields[1]; + p.value = fields[2]; + ps.properties.push_back(std::move(p)); + } + + void parseKeybinding(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 6) { + throw ProfileError( + lineNumber, + fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) + ); + } + ProfileStruct::Keybinding kb; + kb.key = fields[0]; + kb.documentation = fields[1]; + kb.name = fields[2]; + kb.guiPath = fields[3]; + kb.isLocal = [&](const std::string& local) -> bool { + if (local == "false") { + return false; + } + if (local == "true") { + return true; + } + throw ProfileError( + lineNumber, + fmt::format("Expected 'false' or 'true' for the local path, got {}", local) + ); + }(fields[4]); + kb.script = fields[5]; + ps.keybindings.push_back(std::move(kb)); + } + + void parseTime(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 2) { + throw ProfileError( + lineNumber, + fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) + ); + } + ProfileStruct::Time time; + time.type = [&](const std::string& type) -> ProfileStruct::Time::Type { + if (type == "absolute") { + return ProfileStruct::Time::Type::Absolute; + } + if (type == "relative") { + return ProfileStruct::Time::Type::Relative; + } + throw ProfileError( + lineNumber, + fmt::format("Expected 'absolute' or 'relative' for the type, got {}", type) + ); + }(fields[0]); + time.time = fields[1]; + ps.time = std::move(time); + } + + void parseCamera(ProfileStruct& ps, const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.empty()) { + throw ProfileError(lineNumber, "No values specified for Camera location"); + } + ps.camera = [&](const std::string& type) -> + std::variant + { + if (type == ProfileStruct::CameraNavState::Type) { + if (fields.size() != 8) { + throw ProfileError( + lineNumber, + fmt::format( + "Expected 8 fields in the Camera entry, got {}", fields.size() + ) + ); + } + + ProfileStruct::CameraNavState camera; + camera.anchor = fields[1]; + camera.aim = fields[2]; + camera.referenceFrame = fields[3]; + camera.position = fields[4]; + camera.up = fields[5]; + camera.yaw = fields[6]; + camera.pitch = fields[7]; + return camera; + } + if (type == ProfileStruct::CameraGoToGeo::Type) { + if (fields.size() != 5) { + throw ProfileError( + lineNumber, + fmt::format( + "Expected 5 fields in the Camera entry, got {}", fields.size() + ) + ); + } + + ProfileStruct::CameraGoToGeo camera; + camera.anchor = fields[1]; + camera.latitude = std::stod(fields[2]); + camera.longitude = std::stod(fields[3]); + if (!fields[4].empty()) { + camera.altitude = std::stod(fields[4]); + } + return camera; + } + throw ProfileError( + lineNumber, + fmt::format( + "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", fields[0] + ) + ); + }(fields[0]); + } + + void parseMarkNodes(ProfileStruct& ps, const std::string& line, int) { + ps.markNodes.push_back(line); + } +} // namespace std::string serialize(const ProfileStruct& ps) { std::string output; @@ -92,10 +328,12 @@ std::string serialize(const ProfileStruct& ps) { for (const ProfileStruct::Property& p : ps.properties) { const std::string type = [](ProfileStruct::Property::SetType t) { switch (t) { - case ProfileStruct::Property::SetType::SetPropertyValue: - return "setPropertyValue"; - case ProfileStruct::Property::SetType::SetPropertyValueSingle: - return "setPropertyValueSingle"; + case ProfileStruct::Property::SetType::SetPropertyValue: + return "setPropertyValue"; + case ProfileStruct::Property::SetType::SetPropertyValueSingle: + return "setPropertyValueSingle"; + default: + throw ghoul::MissingCaseException(); } }(p.setType); output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); @@ -158,7 +396,64 @@ std::string serialize(const ProfileStruct& ps) { } ProfileStruct deserialize(const std::string& filename) { - return ProfileStruct(); + ProfileStruct result; + + int lineNum = 1; + std::ifstream inFile; + try { + inFile.open(filename, std::ifstream::in); + } + catch (const std::ifstream::failure& e) { + throw ProfileError(fmt::format( + "Exception opening profile file for read: {} ({})", filename, e.what()) + ); + } + + Section currentSection = Section::None; + std::string line; + while (std::getline(inFile, line)) { + if (std::all_of(line.begin(), line.end(), ::isspace)) { + currentSection = Section::None; + lineNum++; + continue; + } + + switch (currentSection) { + case Section::None: + currentSection = parseSection(line, lineNum); + break; + case Section::Version: + parseVersion(result, line, lineNum); + break; + case Section::Module: + parseModule(result, line, lineNum); + break; + case Section::Asset: + parseAsset(result, line, lineNum); + break; + case Section::Property: + parseProperty(result, line, lineNum); + break; + case Section::Keybinding: + parseKeybinding(result, line, lineNum); + break; + case Section::Time: + parseTime(result, line, lineNum); + break; + case Section::Camera: + parseCamera(result, line, lineNum); + break; + case Section::MarkNodes: + parseMarkNodes(result, line, lineNum); + break; + default: + throw ghoul::MissingCaseException(); + } + + lineNum++; + } + + return result; } std::string convertToSceneFile(const ProfileStruct& ps) { @@ -228,9 +523,6 @@ std::string convertToSceneFile(const ProfileStruct& ps) { // Properties for (const ProfileStruct::Property& p : ps.properties) { - constexpr const char* regular = "openspace.setPropertyValue(\"{}\", {});\n"; - constexpr const char* single = "openspace.setPropertyValueSingle(\"{}\", {});\n"; - switch (p.setType) { case ProfileStruct::Property::SetType::SetPropertyValue: output += fmt::format( @@ -298,52 +590,25 @@ std::string convertToSceneFile(const ProfileStruct& ps) { } ProfileFile::ProfileFile(std::string filename) { - clearAllFields(); - _lineNum = 1; - std::ifstream inFile; - - try { - inFile.open(filename, std::ifstream::in); - } - catch (const std::ifstream::failure& e) { - throw ghoul::RuntimeError(fmt::format( - "Exception opening profile file for read: {} ({})", filename, e.what()), - "profileFile" - ); - } - - try { - std::string line; - bool insideSection = false; - while (std::getline(inFile, line)) { - processIndividualLine(insideSection, line); - _lineNum++; - } - } - catch (const std::ifstream::failure& e) { - throw ProfileError( - _lineNum, - fmt::format("Read error using getline in: {} ({})", filename, e.what() - )); - } + profile = deserialize(filename); } -void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { - if (insideSection) { - if (std::all_of(line.begin(), line.end(), ::isspace)) { - insideSection = false; - } - else { - if (parseCurrentSection != nullptr) { - (this->*parseCurrentSection)(line); - } - } - } - else if (line.substr(0, 1) == "#") { - determineSection(line); - insideSection = true; - } -} +//void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { +// if (insideSection) { +// if (std::all_of(line.begin(), line.end(), ::isspace)) { +// insideSection = false; +// } +// else { +// if (parseCurrentSection != nullptr) { +// (this->*parseCurrentSection)(line); +// } +// } +// } +// else if (line.substr(0, 1) == "#") { +// determineSection(line); +// insideSection = true; +// } +//} void ProfileFile::writeToFile(const std::string& filename) const { if (filename.find('/') != std::string::npos) { @@ -390,518 +655,4 @@ void ProfileFile::writeToFile(const std::string& filename) const { outFile.close(); } - -const std::string& ProfileFile::version() const { - return _version; -} - -void ProfileFile::setVersion(std::string v) { - _version = std::move(v); -} - -void ProfileFile::clearAllFields() { - _numLinesVersion = 0; - _numLinesTime = 0; - _numLinesCamera = 0; - - _version.clear(); - _time.clear(); - _camera.clear(); - _modules.clear(); - _assets.clear(); - _properties.clear(); - _keybindings.clear(); - _markNodes.clear(); - - profile = ProfileStruct(); -} - -void ProfileFile::determineSection(std::string line) { - if (line == headerVersion) { - parseCurrentSection = &ProfileFile::parseVersion; - } - else if (line == headerModule) { - parseCurrentSection = &ProfileFile::parseModule; - } - else if (line == headerAsset) { - parseCurrentSection = &ProfileFile::parseAsset; - } - else if (line == headerProperty) { - parseCurrentSection = &ProfileFile::parseProperty; - } - else if (line == headerKeybinding) { - parseCurrentSection = &ProfileFile::parseKeybinding; - } - else if (line == headerTime) { - parseCurrentSection = &ProfileFile::parseTime; - } - else if (line == headerCamera) { - parseCurrentSection = &ProfileFile::parseCamera; - } - else if (line == headerMarkNodes) { - parseCurrentSection = &ProfileFile::parseMarkNodes; - } - else { - throw ProfileError( - _lineNum, - fmt::format("Invalid section header '{}'", line) - ); - } -} - -std::string ProfileFile::time() const { - return _time; -} - -std::string ProfileFile::camera() const { - return _camera; -} - -ProfileFile::Lines ProfileFile::modules() const { - return _modules; -} - -ProfileFile::Lines ProfileFile::assets() const { - return _assets; -} - -ProfileFile::Lines ProfileFile::properties() const { - return _properties; -} - -ProfileFile::Lines ProfileFile::keybindings() const { - return _keybindings; -} - -ProfileFile::Lines ProfileFile::markNodes() const { - return _markNodes; -} - -void ProfileFile::parseVersion(std::string line) { - constexpr const size_t VersionLinesExpected = 1; - - if (++_numLinesVersion > VersionLinesExpected) { - throw ProfileError(_lineNum, "Too many lines in Version section"); - } - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() > 1) { - throw ProfileError(_lineNum, "No tabs allowed in Version entry"); - } - _version = line; - - // - // New - // - std::vector parts = ghoul::tokenizeString(line, '.'); - if (parts.empty() || parts.size() > 3) { - throw ProfileError( - _lineNum, - fmt::format("Expected 1-3 version components, got {}", parts.size()) - ); - } - - ProfileStruct::Version version; - - version.major = std::stoi(parts[0]); - if (parts.size() > 1) { - version.minor = std::stoi(parts[1]); - } - if (parts.size() > 2) { - version.patch = std::stoi(parts[2]); - } - profile.version = std::move(version); -} - -void ProfileFile::parseModule(std::string line) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - - if (fields.size() != moduleFieldsExpected) { - throw ProfileError( - _lineNum, - fmt::format("{} fields required in a Module entry", moduleFieldsExpected) - ); - } - std::vector standard = { - "module name", - "", - "" - }; - verifyRequiredFields("Module", fields, standard, moduleFieldsExpected); - _modules.push_back(line); - - - // - // New - // - if (fields.size() != 3) { - throw ProfileError( - _lineNum, - fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) - ); - } - ProfileStruct::Module m; - m.name = fields[0]; - m.loadedInstruction = fields[1]; - m.notLoadedInstruction = fields[2]; - profile.modules.push_back(std::move(m)); -} - -void ProfileFile::parseAsset(std::string line) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != assetFieldsExpected) { - throw ProfileError( - _lineNum, - fmt::format("{} fields required in an Asset entry", assetFieldsExpected) - ); - } - std::vector standard = { - "asset name", - "", - "" - }; - verifyRequiredFields("Asset", fields, standard, assetFieldsExpected); - _assets.push_back(line); - - - // - // New - // - if (fields.size() != 3) { - throw ProfileError( - _lineNum, - fmt::format("Expected 3 fields in an Asset entry, got {}", fields.size()) - ); - } - - ProfileStruct::Asset a; - a.path = fields[0]; - a.type = [&](const std::string& type) -> ProfileStruct::Asset::Type { - if (type == "require") { - return ProfileStruct::Asset::Type::Require; - } - if (type == "request") { - return ProfileStruct::Asset::Type::Request; - } - throw ProfileError( - _lineNum, - fmt::format("Expected asset type 'require' or 'request', got {}", type) - ); - }(fields[1]); - a.name = fields[2]; - profile.assets.push_back(std::move(a)); -} - -void ProfileFile::parseProperty(std::string line) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - - if (fields.size() != propertyFieldsExpected) { - throw ProfileError( - _lineNum, - fmt::format("{} fields required in Property entry", propertyFieldsExpected) - ); - } - std::vector standard = { - "set command", - "name", - "value" - }; - verifyRequiredFields("Property", fields, standard, propertyFieldsExpected); - _properties.push_back(line); - - - // - // New - // - if (fields.size() != 3) { - throw ProfileError( - _lineNum, - fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) - ); - } - ProfileStruct::Property p; - p.setType = [&](const std::string& type) -> ProfileStruct::Property::SetType { - if (type == "setPropertyValue") { - return ProfileStruct::Property::SetType::SetPropertyValue; - } - if (type == "setPropertyValueSingle") { - return ProfileStruct::Property::SetType::SetPropertyValueSingle; - } - throw ProfileError( - _lineNum, - fmt::format( - "Expected property set type 'setPropertyValue' or " - "'setPropertyValueSingle', got {}", - type - ) - ); - }(fields[0]); - p.name = fields[1]; - p.value = fields[2]; - profile.properties.push_back(std::move(p)); -} - -void ProfileFile::parseKeybinding(std::string line) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - - if (fields.size() != keybindingFieldsExpected) { - throw ProfileError( - _lineNum, - fmt::format("{} fields required in Keybinding entry", keybindingFieldsExpected) - ); - } - std::vector standard = { - "key", - "documentation", - "name", - "GuiPath", - "local(T/F)", - "script to execute" - }; - verifyRequiredFields("Keybinding", fields, standard, keybindingFieldsExpected); - _keybindings.push_back(line); - - - // - // New - // - if (fields.size() != 6) { - throw ProfileError( - _lineNum, - fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) - ); - } - ProfileStruct::Keybinding kb; - kb.key = fields[0]; - kb.documentation = fields[1]; - kb.name = fields[2]; - kb.guiPath = fields[3]; - kb.isLocal = [&](const std::string& local) -> bool { - if (local == "false") { - return false; - } - if (local == "true") { - return true; - } - throw ProfileError( - _lineNum, - fmt::format("Expected 'false' or 'true' for the local path, got {}", local) - ); - }(fields[4]); - kb.script = fields[5]; - profile.keybindings.push_back(std::move(kb)); -} - -void ProfileFile::parseTime(std::string line) { - if (++_numLinesTime > timeLinesExpected) { - throw ProfileError(_lineNum, "Too many lines in Time section"); - } - - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != timeFieldsExpected) { - throw ProfileError( - _lineNum, - fmt::format("{} fields required in Time entry", timeFieldsExpected) - ); - } - std::vector standard = { - "time set type", - "time value to set" - }; - verifyRequiredFields("Time", fields, standard, timeFieldsExpected); - _time = line; - - - // - // New - // - if (fields.size() != 2) { - throw ProfileError( - _lineNum, - fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) - ); - } - ProfileStruct::Time time; - time.type = [&](const std::string& type) -> ProfileStruct::Time::Type { - if (type == "absolute") { - return ProfileStruct::Time::Type::Absolute; - } - if (type == "relative") { - return ProfileStruct::Time::Type::Relative; - } - throw ProfileError( - _lineNum, - fmt::format("Expected 'absolute' or 'relative' for the type, got {}", type) - ); - }(fields[0]); - time.time = fields[1]; - profile.time = std::move(time); -} - -void ProfileFile::parseCamera(std::string line) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - - if (++_numLinesCamera > cameraLinesExpected) { - throw ProfileError(_lineNum, "Too many lines in Camera section"); - } - - if (fields.size() == cameraNavigationFieldsExpected) { - std::vector standard = { - "Type of camera set (setNavigationState)", - "setNavigationState Anchor", - "", - "", - "setNavigationState position vector", - "", - "", - "" - }; - verifyRequiredFields("Camera navigation", fields, standard, - cameraNavigationFieldsExpected); - } - else if (fields.size() == cameraGeoFieldsExpected) { - std::vector standard = { - "Type of camera set (goToGeo)", - "", - "Camera goToGeo Latitude", - "Camera goToGeo Longitude", - "" - }; - verifyRequiredFields("Camera goToGeo", fields, standard, - cameraGeoFieldsExpected); - } - else { - throw ProfileError( - _lineNum, - fmt::format( - "{} or {} fields required in Camera entry", - cameraNavigationFieldsExpected, cameraGeoFieldsExpected - ) - ); - } - _camera = line; - - - // - // New - // - if (fields.empty()) { - throw ProfileError(_lineNum, "No values specified for Camera location"); - } - if (fields[0] == ProfileStruct::CameraNavState::Type) { - if (fields.size() != 8) { - throw ProfileError( - _lineNum, - fmt::format( - "Expected 8 fields in the Camera entry, got {}", fields.size() - ) - ); - } - - ProfileStruct::CameraNavState camera; - camera.anchor = fields[1]; - camera.aim = fields[2]; - camera.referenceFrame = fields[3]; - camera.position = fields[4]; - camera.up = fields[5]; - camera.yaw = fields[6]; - camera.pitch = fields[7]; - profile.camera = std::move(camera); - return; - } - if (fields[0] == ProfileStruct::CameraGoToGeo::Type) { - if (fields.size() != 5) { - throw ProfileError( - _lineNum, - fmt::format( - "Expected 5 fields in the Camera entry, got {}", fields.size() - ) - ); - } - - ProfileStruct::CameraGoToGeo camera; - camera.anchor = fields[1]; - camera.latitude = std::stod(fields[2]); - camera.longitude = std::stod(fields[3]); - if (!fields[4].empty()) { - camera.altitude = std::stod(fields[4]); - } - profile.camera = std::move(camera); - return; - } - throw ProfileError( - _lineNum, - fmt::format( - "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", fields[0] - ) - ); -} - -void ProfileFile::parseMarkNodes(std::string line) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - - if (fields.size() != markNodesFieldsExpected) { - throw ProfileError( - _lineNum, - fmt::format("{} field required in a Mark Nodes entry", markNodesFieldsExpected) - ); - } - std::vector standard = { "Mark Interesting Node name" }; - verifyRequiredFields("Mark Interesting Nodes", fields, standard, - markNodesFieldsExpected); - _markNodes.push_back(line); - - - // - // New - // - profile.markNodes.push_back(line); -} - -void ProfileFile::verifyRequiredFields(std::string sectionName, - std::vector fields, - std::vector standard, - unsigned int nFields) -{ - for (unsigned int i = 0; i < fields.size(); i++) { - if (!standard[i].empty() && fields[i].empty()) { - std::string errMsg = sectionName + " " + standard[i]; - errMsg += "(arg " + std::to_string(i) + "/"; - errMsg += std::to_string(nFields) + ") is required"; - throw ProfileError(_lineNum, std::move(errMsg)); - } - } -} - -void ProfileFile::updateTime(std::string line) { - _time = std::move(line); -} - -void ProfileFile::updateCamera(std::string line) { - _camera = std::move(line); -} - -void ProfileFile::addModuleLine(std::string line) { - _modules.push_back(std::move(line)); -} - -void ProfileFile::addAssetLine(std::string line) { - _assets.push_back(std::move(line)); -} - -void ProfileFile::addPropertyLine(std::string line) { - _properties.push_back(std::move(line)); -} - -void ProfileFile::addKeybindingLine(std::string line) { - _keybindings.push_back(std::move(line)); -} - -void ProfileFile::addMarkNodesLine(std::string line) { - _markNodes.push_back(std::move(line)); -} - -void ProfileFile::clearAssets() { - _assets.clear(); -} - } // namespace openspace From 1e0f427dcf868ae131f51d060fc2b6c31df07063 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 09:37:38 +0200 Subject: [PATCH 23/61] More profile file cleanup --- include/openspace/scene/profilefile.h | 124 +------------------------- src/scene/profilefile.cpp | 66 +++++++------- 2 files changed, 34 insertions(+), 156 deletions(-) diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index ec3e837476..cf2aaa3038 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -169,10 +169,11 @@ struct ProfileStruct { }; std::string serialize(const ProfileStruct& ps); -ProfileStruct deserialize(const std::string& filename); +ProfileStruct deserialize(const std::vector& content); std::string convertToSceneFile(const ProfileStruct& ps); + class ProfileFile { public: ProfileStruct profile; @@ -185,7 +186,7 @@ public: * proper sections; it does not parse the tab-delimited fields of each line. * \param filename The profile file to read */ - ProfileFile(std::string filename); + ProfileFile(const std::string& filename); /** * Writes the formatted contents of this object to a file. @@ -194,125 +195,6 @@ public: * \param filename The filename to write to. */ void writeToFile(const std::string& filename) const; - - /** - * Updates the full string that defines the starting time. The format for this line - * is defined by ProfileFile::parseTime and Profile::convertToAsset_time - * \param line The time entry line to replace current time entry - */ - //void updateTime(std::string line); - - /** - * Updates the full string that defines the starting camera position. The format for - * this line is defined by ProfileFile::parseCamera & Profile::convertToAsset_camera - * \param line The camera entry line to replace current camera entry - */ - //void updateCamera(std::string line); - - /** - * Adds a new module line to the list of module lines to be analyzed by the profile - * at startup. The format for a module line is defined by ProfileFile::parseModule - * and Profile::convertToAsset_modules - * \param line The module name to be added - */ - //void addModuleLine(std::string line); - - /** - * Adds a new asset to the list of assets to be loaded at startup. The format for an - * asset line is defined by ProfileFile::parseAsset & Profile::convertToAsset_assets - * \param line The asset name to be added - */ - //void addAssetLine(std::string line); - - /** - * Clears all asset entries - */ - //void clearAssets(); - - /** - * Adds a new property set command to the list of property settings to be - * performed at startup. The format for a property set command line is defined by - * ProfileFile::parseProperty and Profile::convertToAsset_properties - * \param line The property set command to be added - */ - //void addPropertyLine(std::string line); - - /** - * Adds a new keybinding shortcut to the list of keybindings. The format for a - * keybinding line is defined by ProfileFile::parseKeybinding and - * Profile::convertToAsset_keybindings - * \param line The keyboard shortcut line to be added - */ - //void addKeybindingLine(std::string line); - - /** - * Adds a new scenegraph node name to be added to the list of those marked as - * 'interesting'. The format for a mark nodes line is defined by - * ProfileFile::parseMarkNodes and Profile::convertToAsset_markNodes - * \param line The scenegraph node to be added - */ - //void addMarkNodesLine(std::string line); - - /** - * Returns the format version number (profiles syntax version) string - * \return The version string - */ - //const std::string& version() const; - - /** - * Sets the format version number (profiles syntax version) string - * \param The version string to set - */ - //void setVersion(std::string); - - /** - * Returns the profile's time string. See updateTime comment header for notes on - * syntax of this time string - * \return The time string - */ - //std::string time() const; - - /** - * Returns the profile's camera string. See updateCamera comment header for notes on - * syntax of this camera string - * \return The camera string - */ - //std::string camera() const; - - /** - * Returns the vector of OpenSpace modules listed in this profile. See addModuleLine - * comment header for notes on the syntax of each entry. - * \return The vector of module lines - */ - //std::vector modules() const; - - /** - * Returns the vector of OpenSpace assets listed in this profile. See addAssetLine - * comment header for notes on the syntax of each entry. - * \return The vector of asset lines - */ - //Lines assets() const; - - /** - * Returns the vector of OpenSpace property set commands included in this profile. - * See addPropertyLine comment header for notes on the syntax of each entry. - * \return The vector of property set commands - */ - //Lines properties() const; - - /** - * Returns the vector of OpenSpace keybinding shortcut definitions included in this - * profile. See addKeybindingLine comment header for syntax notes of each entry. - * \return The vector of keybinding shortcut definitions - */ - //Lines keybindings() const; - - /** - * Returns the vector of OpenSpace scenegraph nodes marked as 'interesting'. - * See addMarkNodesLine comment header for syntax notes of each entry. - * \return The vector of nodes to be marked as interesting. - */ - //Lines markNodes() const; }; } // namespace openspace diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 18adb59629..feac37d487 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -395,26 +395,25 @@ std::string serialize(const ProfileStruct& ps) { return output; } -ProfileStruct deserialize(const std::string& filename) { +ProfileStruct deserialize(const std::vector& content) { ProfileStruct result; - int lineNum = 1; - std::ifstream inFile; - try { - inFile.open(filename, std::ifstream::in); - } - catch (const std::ifstream::failure& e) { - throw ProfileError(fmt::format( - "Exception opening profile file for read: {} ({})", filename, e.what()) - ); - } + //int lineNum = 1; + //std::ifstream inFile; + //try { + // inFile.open(filename, std::ifstream::in); + //} + //catch (const std::ifstream::failure& e) { + // throw ProfileError(fmt::format( + // "Exception opening profile file for read: {} ({})", filename, e.what()) + // ); + //} Section currentSection = Section::None; - std::string line; - while (std::getline(inFile, line)) { + for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { + std::string line = content[lineNum - 1]; if (std::all_of(line.begin(), line.end(), ::isspace)) { currentSection = Section::None; - lineNum++; continue; } @@ -449,8 +448,6 @@ ProfileStruct deserialize(const std::string& filename) { default: throw ghoul::MissingCaseException(); } - - lineNum++; } return result; @@ -589,26 +586,25 @@ std::string convertToSceneFile(const ProfileStruct& ps) { return output; } -ProfileFile::ProfileFile(std::string filename) { - profile = deserialize(filename); -} +ProfileFile::ProfileFile(const std::string& filename) { + std::ifstream inFile; + try { + inFile.open(filename, std::ifstream::in); + } + catch (const std::ifstream::failure& e) { + throw ProfileError(fmt::format( + "Exception opening profile file for read: {} ({})", filename, e.what()) + ); + } -//void ProfileFile::processIndividualLine(bool& insideSection, std::string line) { -// if (insideSection) { -// if (std::all_of(line.begin(), line.end(), ::isspace)) { -// insideSection = false; -// } -// else { -// if (parseCurrentSection != nullptr) { -// (this->*parseCurrentSection)(line); -// } -// } -// } -// else if (line.substr(0, 1) == "#") { -// determineSection(line); -// insideSection = true; -// } -//} + std::vector content; + std::string line; + while (std::getline(inFile, line)) { + content.push_back(std::move(line)); + } + + profile = deserialize(content); +} void ProfileFile::writeToFile(const std::string& filename) const { if (filename.find('/') != std::string::npos) { From 02b109f4dba9ff82a2bbf1b914e3cf6a7cf710db Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 09:58:31 +0200 Subject: [PATCH 24/61] More simplification --- include/openspace/scene/profile.h | 7 --- include/openspace/scene/profilefile.h | 11 ---- src/scene/profile.cpp | 75 ++++++++++++++++++--------- src/scene/profilefile.cpp | 45 ---------------- 4 files changed, 51 insertions(+), 87 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index f0f5dde450..a738a9763e 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -85,13 +85,6 @@ public: void convertToSceneFile(const std::string& inProfilePath, const std::string& outFilePath); - /** - * Returns the string contents of a profileFile object converted to scene/asset - * equivalent syntax. - * \param pf The profileFile object to be converted - * \return The full string contents of scene/asset equivalent of the profile file. - */ - std::string convertToScene(ProfileFile& pf); /** * Returns the Lua library that contains all Lua functions available to provide diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index cf2aaa3038..7314fa2477 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -177,9 +177,6 @@ std::string convertToSceneFile(const ProfileStruct& ps); class ProfileFile { public: ProfileStruct profile; - - using Lines = std::vector; - /** * Constructs object by reading the contents of a profile file and populates vector * containers for all sections. This only pulls individual line entries into their @@ -187,14 +184,6 @@ public: * \param filename The profile file to read */ ProfileFile(const std::string& filename); - - /** - * Writes the formatted contents of this object to a file. - * This function calls writeToString() in order to get everything in formatted - * form. - * \param filename The filename to write to. - */ - void writeToFile(const std::string& filename) const; }; } // namespace openspace diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 559754a3dc..11438d996d 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -102,10 +102,6 @@ namespace { } } - void handleChangedRemove(std::vector& base, std::string asset) { - base.push_back({ std::move(asset), Profile::AssetEventType::Remove }); - } - void addAssetsToProfileFile(ProfileFile& pf, const std::vector& allAssets) { @@ -147,12 +143,53 @@ namespace { } } } - } // namespace void Profile::saveCurrentSettingsToProfile(const std::string& filename) { ProfileFile pf = collateBaseWithChanges(); - pf.writeToFile(filename); + + if (filename.find('/') != std::string::npos) { + LERROR("Profile filename must not contain path (/) elements"); + return; + } + else if (filename.find(':') != std::string::npos) { + LERROR("Profile filename must not contain path (:) elements"); + return; + } + else if (filename.find('.') != std::string::npos) { + LERROR("Only provide the filename to save without file extension"); + return; + } + const std::string absFilename = absPath("${ASSETS}/" + filename + ".profile"); + + if (FileSys.fileExists(absFilename)) { + LERROR(fmt::format( + "Unable to save profile '{}'. File of same name already exists.", + absFilename.c_str() + )); + return; + } + + std::ofstream outFile; + // @TODO (abock, 2020-06-15) Replace with non-throwing stream + try { + outFile.open(absFilename, std::ofstream::out); + } + catch (const std::ofstream::failure& e) { + LERROR(fmt::format( + "Exception opening profile file for write: {} ({})", absFilename, e.what() + )); + } + + try { + outFile << serialize(pf.profile); + } + catch (const std::ofstream::failure& e) { + LERROR("Data write error to file: " + + absFilename + " (" + e.what() + ")"); + } + + outFile.close(); } std::string Profile::saveCurrentSettingsToProfile_string() { @@ -217,7 +254,7 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); } else if (event.eventType == AssetEventType::Remove) { - handleChangedRemove(assetDetails.base, event.name); + assetDetails.base.push_back({ event.name, Profile::AssetEventType::Remove }); } } return assetDetails.base; @@ -323,29 +360,19 @@ void Profile::convertToSceneFile(const std::string& inProfilePath, outFile.open(outFilePath, std::ofstream::out); } catch (const std::ofstream::failure& e) { - LERROR("Exception opening scene file for write: " + outFilePath - + " (" + e.what() + ")"); + LERROR(fmt::format( + "Exception opening scene file for write: {} ({})", outFilePath, e.what() + )); } try { - outFile << convertToScene(pf); + outFile << openspace::convertToSceneFile(pf.profile); } catch (const std::ofstream::failure& e) { - LERROR("Data write error to scene file: " + outFilePath - + " (" + e.what() + ")"); + LERROR(fmt::format( + "Data write error to scene file: {} ({})", outFilePath, e.what() + )); } - - try { - outFile.close(); - } - catch (const std::ofstream::failure& e) { - LERROR("Exception closing scene file after write: " + outFilePath - + " (" + e.what() + ")"); - } -} - -std::string Profile::convertToScene(ProfileFile& pf) { - return openspace::convertToSceneFile(pf.profile); } scripting::LuaLibrary Profile::luaLibrary() { diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index feac37d487..efc29ca886 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -606,49 +606,4 @@ ProfileFile::ProfileFile(const std::string& filename) { profile = deserialize(content); } -void ProfileFile::writeToFile(const std::string& filename) const { - if (filename.find('/') != std::string::npos) { - LERROR("Profile filename must not contain path (/) elements"); - return; - } - else if (filename.find(':') != std::string::npos) { - LERROR("Profile filename must not contain path (:) elements"); - return; - } - else if (filename.find('.') != std::string::npos) { - LERROR("Only provide the filename to save without file extension"); - return; - } - const std::string absFilename = absPath("${ASSETS}/" + filename + ".profile"); - - if (FileSys.fileExists(absFilename)) { - LERROR(fmt::format( - "Unable to save profile '{}'. File of same name already exists.", - absFilename.c_str() - )); - return; - } - - std::ofstream outFile; - // @TODO (abock, 2020-06-15) Replace with non-throwing stream - try { - outFile.open(absFilename, std::ofstream::out); - } - catch (const std::ofstream::failure& e) { - LERROR(fmt::format( - "Exception opening profile file for write: {} ({})", absFilename, e.what() - )); - } - - try { - outFile << serialize(profile); - } - catch (const std::ofstream::failure& e) { - LERROR("Data write error to file: " - + absFilename + " (" + e.what() + ")"); - } - - outFile.close(); -} - } // namespace openspace From a433ed1a726a1a3c376c1588c4f327381edd0e9b Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 10:14:21 +0200 Subject: [PATCH 25/61] Removing more of ProfileFile --- include/openspace/scene/profile.h | 10 ++--- include/openspace/scene/profilefile.h | 53 +-------------------------- src/scene/profile.cpp | 52 +++++++++++++------------- src/scene/profilefile.cpp | 4 +- 4 files changed, 34 insertions(+), 85 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index a738a9763e..e48060378b 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -105,18 +105,18 @@ private: virtual std::string initialProfile() const; virtual std::string profileBaseDirectory() const; virtual std::vector assetEvents() const; - ProfileFile collateBaseWithChanges(); + ProfileStruct collateBaseWithChanges(); - std::vector modifyAssetsToReflectChanges(ProfileFile& pf); - void parseAssetFileLines(std::vector& results, ProfileFile& pf); + std::vector modifyAssetsToReflectChanges(ProfileStruct& ps); + void parseAssetFileLines(std::vector& results, ProfileStruct& ps); - void modifyPropertiesToReflectChanges(ProfileFile& pf); + void modifyPropertiesToReflectChanges(ProfileStruct& ps); virtual std::vector changedProperties(); std::string getFullPropertyPath(openspace::properties::Property* prop); virtual std::vector changedPropertiesFormatted(); virtual std::string currentTimeUTC() const; virtual interaction::NavigationHandler::NavigationState currentCameraState() const; - void addCurrentCameraToProfileFile(ProfileFile& pf) const; + void addCurrentCameraToProfileFile(ProfileStruct& ps) const; }; } // namespace openspace diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 7314fa2477..1b8aeeabef 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -43,46 +43,6 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } -const size_t timeLinesExpected = 1; -const size_t cameraLinesExpected = 1; -const size_t moduleFieldsExpected = 3; -const size_t assetFieldsExpected = 3; -const size_t propertyFieldsExpected = 3; -const size_t keybindingFieldsExpected = 6; -const size_t timeFieldsExpected = 2; -const size_t cameraNavigationFieldsExpected = 8; -const size_t cameraGeoFieldsExpected = 5; -const size_t markNodesFieldsExpected = 1; - -const size_t moduleFieldName = 0; -const size_t moduleFieldLoaded = 1; -const size_t moduleFieldNotLoaded = 2; -const size_t assetFieldName = 0; -const size_t assetFieldReqd = 1; -const size_t propertyFieldType = 0; -const size_t propertyFieldName = 1; -const size_t propertyFieldValue = 2; -const size_t keybindingFieldKey = 0; -const size_t keybindingFieldDoc = 1; -const size_t keybindingFieldName = 2; -const size_t keybindingFieldGuiPath = 3; -const size_t keybindingFieldLocal = 4; -const size_t keybindingFieldCommand = 5; -const size_t timeFieldType = 0; -const size_t timeFieldSet = 1; -const size_t cameraFieldType = 0; -const size_t cameraNavigationFieldAnchor = 1; -const size_t cameraNavigationFieldAim = 2; -const size_t cameraNavigationFieldRef = 3; -const size_t cameraNavigationFieldPosition = 4; -const size_t cameraNavigationFieldUp = 5; -const size_t cameraNavigationFieldYaw = 6; -const size_t cameraNavigationFieldPitch = 7; -const size_t cameraGeoFieldAnchor = 1; -const size_t cameraGeoFieldLatitude = 2; -const size_t cameraGeoFieldLongitude = 3; -const size_t cameraGeoFieldAltitude = 4; - struct ProfileStruct { // Version struct Version { @@ -173,18 +133,7 @@ ProfileStruct deserialize(const std::vector& content); std::string convertToSceneFile(const ProfileStruct& ps); - -class ProfileFile { -public: - ProfileStruct profile; - /** - * Constructs object by reading the contents of a profile file and populates vector - * containers for all sections. This only pulls individual line entries into their - * proper sections; it does not parse the tab-delimited fields of each line. - * \param filename The profile file to read - */ - ProfileFile(const std::string& filename); -}; +ProfileStruct readFromFile(const std::string& filename); } // namespace openspace diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 11438d996d..ca66404073 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -102,16 +102,16 @@ namespace { } } - void addAssetsToProfileFile(ProfileFile& pf, + void addAssetsToProfileFile(ProfileStruct& ps, const std::vector& allAssets) { - pf.profile.assets.clear(); + ps.assets.clear(); for (Profile::AssetEvent a : allAssets) { if (a.eventType != Profile::AssetEventType::Ignore) { ProfileStruct::Asset asset; asset.path = a.name; asset.type = ProfileStruct::Asset::Type::Require; - pf.profile.assets.push_back(std::move(asset)); + ps.assets.push_back(std::move(asset)); } } } @@ -146,7 +146,7 @@ namespace { } // namespace void Profile::saveCurrentSettingsToProfile(const std::string& filename) { - ProfileFile pf = collateBaseWithChanges(); + ProfileStruct ps = collateBaseWithChanges(); if (filename.find('/') != std::string::npos) { LERROR("Profile filename must not contain path (/) elements"); @@ -182,7 +182,7 @@ void Profile::saveCurrentSettingsToProfile(const std::string& filename) { } try { - outFile << serialize(pf.profile); + outFile << serialize(ps); } catch (const std::ofstream::failure& e) { LERROR("Data write error to file: " @@ -193,8 +193,8 @@ void Profile::saveCurrentSettingsToProfile(const std::string& filename) { } std::string Profile::saveCurrentSettingsToProfile_string() { - ProfileFile pf = collateBaseWithChanges(); - return serialize(pf.profile); + ProfileStruct ps = collateBaseWithChanges(); + return serialize(ps); } bool Profile::usingProfile() const { @@ -213,7 +213,7 @@ std::string Profile::profileBaseDirectory() const { return _profileBaseDirectory; } -ProfileFile Profile::collateBaseWithChanges() { +ProfileStruct Profile::collateBaseWithChanges() { if (!usingProfile()) { std::string errorMessage = "Program was not started using a profile, " "so cannot use this save-current-settings feature"; @@ -222,26 +222,26 @@ ProfileFile Profile::collateBaseWithChanges() { std::string initProfile = initialProfile(); std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + ".profile"; - ProfileFile pf(inputProfilePath); - pf.profile.version = ProfileStruct::Version{}; + ProfileStruct ps = readFromFile(inputProfilePath); + ps.version = ProfileStruct::Version{}; - std::vector ass = modifyAssetsToReflectChanges(pf); - addAssetsToProfileFile(pf, ass); - modifyPropertiesToReflectChanges(pf); + std::vector ass = modifyAssetsToReflectChanges(ps); + addAssetsToProfileFile(ps, ass); + modifyPropertiesToReflectChanges(ps); // add current time to profile file ProfileStruct::Time time; time.time = currentTimeUTC(); time.type = ProfileStruct::Time::Type::Absolute; - pf.profile.time = std::move(time); + ps.time = std::move(time); - addCurrentCameraToProfileFile(pf); - return pf; + addCurrentCameraToProfileFile(ps); + return ps; } -std::vector Profile::modifyAssetsToReflectChanges(ProfileFile& pf) { +std::vector Profile::modifyAssetsToReflectChanges(ProfileStruct& ps) { std::vector a; - parseAssetFileLines(a, pf); + parseAssetFileLines(a, ps); AllAssetDetails assetDetails; assetDetails.base = a; @@ -260,8 +260,8 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileFi return assetDetails.base; } -void Profile::parseAssetFileLines(std::vector& results, ProfileFile& pf) { - for (ProfileStruct::Asset& a : pf.profile.assets) { +void Profile::parseAssetFileLines(std::vector& results, ProfileStruct& ps) { + for (ProfileStruct::Asset& a : ps.assets) { AssetEvent assetEvent; assetEvent.name = a.path; assetEvent.eventType = [](ProfileStruct::Asset::Type type) { @@ -275,7 +275,7 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileFile& } } -void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { +void Profile::modifyPropertiesToReflectChanges(ProfileStruct& ps) { std::vector changedProps = changedProperties(); std::vector formattedLines; @@ -284,7 +284,7 @@ void Profile::modifyPropertiesToReflectChanges(ProfileFile& pf) { p.setType = ProfileStruct::Property::SetType::SetPropertyValueSingle; p.name = getFullPropertyPath(prop); p.value = prop->getStringValue(); - pf.profile.properties.push_back(std::move(p)); + ps.properties.push_back(std::move(p)); } } @@ -326,7 +326,7 @@ interaction::NavigationHandler::NavigationState Profile::currentCameraState() co return global::navigationHandler.navigationState(); } -void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) const { +void Profile::addCurrentCameraToProfileFile(ProfileStruct& ps) const { interaction::NavigationHandler::NavigationState nav = currentCameraState(); ProfileStruct::CameraNavState camera; @@ -345,7 +345,7 @@ void Profile::addCurrentCameraToProfileFile(ProfileFile& pf) const { } camera.yaw = nav.yaw; camera.pitch = nav.pitch; - pf.profile.camera = std::move(camera); + ps.camera = std::move(camera); } void Profile::convertToSceneFile(const std::string& inProfilePath, @@ -353,7 +353,7 @@ void Profile::convertToSceneFile(const std::string& inProfilePath, { ZoneScoped - ProfileFile pf(inProfilePath); + ProfileStruct ps = readFromFile(inProfilePath); std::ofstream outFile; try { @@ -366,7 +366,7 @@ void Profile::convertToSceneFile(const std::string& inProfilePath, } try { - outFile << openspace::convertToSceneFile(pf.profile); + outFile << openspace::convertToSceneFile(ps); } catch (const std::ofstream::failure& e) { LERROR(fmt::format( diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index efc29ca886..63dd5c2021 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -586,7 +586,7 @@ std::string convertToSceneFile(const ProfileStruct& ps) { return output; } -ProfileFile::ProfileFile(const std::string& filename) { +ProfileStruct readFromFile(const std::string& filename) { std::ifstream inFile; try { inFile.open(filename, std::ifstream::in); @@ -603,7 +603,7 @@ ProfileFile::ProfileFile(const std::string& filename) { content.push_back(std::move(line)); } - profile = deserialize(content); + return deserialize(content); } } // namespace openspace From e00a51d82278d1a6286c6b941cbbbf9276f98a5f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 10:59:22 +0200 Subject: [PATCH 26/61] Removing some more global state --- include/openspace/scene/profile.h | 15 +-- include/openspace/scene/profilefile.h | 23 +--- src/engine/openspaceengine.cpp | 2 + src/scene/profile.cpp | 133 +++++++++---------- src/scene/profile_lua.inl | 7 + src/scene/profilefile.cpp | 184 +++++++++++--------------- 6 files changed, 160 insertions(+), 204 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index e48060378b..1349d5710c 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -73,7 +73,7 @@ public: * Saves all current settings, similar to saveCurrentSettingsToProfile() except the * output is a string without writing to a file. */ - std::string saveCurrentSettingsToProfile_string(); + //std::string saveCurrentSettingsToProfile_string(); /** * Reads in a .profile file, converts it to scene/asset equivalent syntax, and @@ -97,26 +97,25 @@ protected: std::string _profileBaseDirectory = "${ASSETS}"; private: + ProfileData profile; + struct AllAssetDetails { std::vector base; std::vector changed; }; - virtual bool usingProfile() const; virtual std::string initialProfile() const; virtual std::string profileBaseDirectory() const; virtual std::vector assetEvents() const; - ProfileStruct collateBaseWithChanges(); + ProfileData collateBaseWithChanges(); - std::vector modifyAssetsToReflectChanges(ProfileStruct& ps); - void parseAssetFileLines(std::vector& results, ProfileStruct& ps); + std::vector modifyAssetsToReflectChanges(ProfileData& ps); + void parseAssetFileLines(std::vector& results, ProfileData& ps); - void modifyPropertiesToReflectChanges(ProfileStruct& ps); + void modifyPropertiesToReflectChanges(ProfileData& ps); virtual std::vector changedProperties(); std::string getFullPropertyPath(openspace::properties::Property* prop); - virtual std::vector changedPropertiesFormatted(); virtual std::string currentTimeUTC() const; virtual interaction::NavigationHandler::NavigationState currentCameraState() const; - void addCurrentCameraToProfileFile(ProfileStruct& ps) const; }; } // namespace openspace diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h index 1b8aeeabef..f9a7db22f3 100644 --- a/include/openspace/scene/profilefile.h +++ b/include/openspace/scene/profilefile.h @@ -25,25 +25,14 @@ #ifndef __OPENSPACE_CORE___PROFILEFILE___H__ #define __OPENSPACE_CORE___PROFILEFILE___H__ -#include -#include -#include -#include #include +#include #include #include -#include - -namespace ghoul { class Dictionary; } -namespace ghoul::opengl { class ProgramObject; } - namespace openspace { -namespace documentation { struct Documentation; } -namespace scripting { struct LuaLibrary; } - -struct ProfileStruct { +struct ProfileData { // Version struct Version { int major = 0; @@ -128,12 +117,10 @@ struct ProfileStruct { std::vector markNodes; }; -std::string serialize(const ProfileStruct& ps); -ProfileStruct deserialize(const std::vector& content); +std::string serialize(const ProfileData& ps); +ProfileData deserialize(const std::vector& content); -std::string convertToSceneFile(const ProfileStruct& ps); - -ProfileStruct readFromFile(const std::string& filename); +std::string convertToSceneFile(const ProfileData& ps); } // namespace openspace diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index f497d785cf..c8aa7612b7 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -312,6 +312,8 @@ void OpenSpaceEngine::initialize() { ); } else { + + global::profile.convertToSceneFile(inputProfile, outputAsset); // Set asset name to that of the profile because a new scene file will be diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index ca66404073..49a3cfac91 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -102,15 +102,15 @@ namespace { } } - void addAssetsToProfileFile(ProfileStruct& ps, + void addAssetsToProfileFile(ProfileData& ps, const std::vector& allAssets) { ps.assets.clear(); for (Profile::AssetEvent a : allAssets) { if (a.eventType != Profile::AssetEventType::Ignore) { - ProfileStruct::Asset asset; + ProfileData::Asset asset; asset.path = a.name; - asset.type = ProfileStruct::Asset::Type::Require; + asset.type = ProfileData::Asset::Type::Require; ps.assets.push_back(std::move(asset)); } } @@ -143,10 +143,31 @@ namespace { } } } + + ProfileData readFromFile(const std::string& filename) { + std::ifstream inFile; + try { + inFile.open(filename, std::ifstream::in); + } + catch (const std::ifstream::failure& e) { + throw ghoul::RuntimeError(fmt::format( + "Exception opening profile file for read: {} ({})", filename, e.what()) + ); + } + + std::vector content; + std::string line; + while (std::getline(inFile, line)) { + content.push_back(std::move(line)); + } + + return deserialize(content); + } + } // namespace void Profile::saveCurrentSettingsToProfile(const std::string& filename) { - ProfileStruct ps = collateBaseWithChanges(); + ProfileData ps = collateBaseWithChanges(); if (filename.find('/') != std::string::npos) { LERROR("Profile filename must not contain path (/) elements"); @@ -192,15 +213,6 @@ void Profile::saveCurrentSettingsToProfile(const std::string& filename) { outFile.close(); } -std::string Profile::saveCurrentSettingsToProfile_string() { - ProfileStruct ps = collateBaseWithChanges(); - return serialize(ps); -} - -bool Profile::usingProfile() const { - return global::configuration.usingProfile; -} - std::string Profile::initialProfile() const { return global::configuration.profile; } @@ -213,33 +225,47 @@ std::string Profile::profileBaseDirectory() const { return _profileBaseDirectory; } -ProfileStruct Profile::collateBaseWithChanges() { - if (!usingProfile()) { - std::string errorMessage = "Program was not started using a profile, " - "so cannot use this save-current-settings feature"; - LERROR(errorMessage); - } +ProfileData Profile::collateBaseWithChanges() { std::string initProfile = initialProfile(); std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + ".profile"; - ProfileStruct ps = readFromFile(inputProfilePath); - ps.version = ProfileStruct::Version{}; + ProfileData ps = readFromFile(inputProfilePath); + ps.version = ProfileData::Version{}; std::vector ass = modifyAssetsToReflectChanges(ps); addAssetsToProfileFile(ps, ass); modifyPropertiesToReflectChanges(ps); // add current time to profile file - ProfileStruct::Time time; + ProfileData::Time time; time.time = currentTimeUTC(); - time.type = ProfileStruct::Time::Type::Absolute; + time.type = ProfileData::Time::Type::Absolute; ps.time = std::move(time); - addCurrentCameraToProfileFile(ps); + // Camera + interaction::NavigationHandler::NavigationState nav = currentCameraState(); + + ProfileData::CameraNavState camera; + camera.anchor = nav.anchor; + camera.aim = nav.aim; + camera.referenceFrame = nav.referenceFrame; + camera.position = fmt::format( + "{},{},{}", + nav.position.x, nav.position.y, nav.position.z + ); + if (nav.up.has_value()) { + camera.up = fmt::format( + "{},{},{}", + nav.up->x, nav.up->y, nav.up->z + ); + } + camera.yaw = std::to_string(nav.yaw); + camera.pitch = std::to_string(nav.pitch); + ps.camera = std::move(camera); return ps; } -std::vector Profile::modifyAssetsToReflectChanges(ProfileStruct& ps) { +std::vector Profile::modifyAssetsToReflectChanges(ProfileData& ps) { std::vector a; parseAssetFileLines(a, ps); AllAssetDetails assetDetails; @@ -260,14 +286,14 @@ std::vector Profile::modifyAssetsToReflectChanges(ProfileSt return assetDetails.base; } -void Profile::parseAssetFileLines(std::vector& results, ProfileStruct& ps) { - for (ProfileStruct::Asset& a : ps.assets) { +void Profile::parseAssetFileLines(std::vector& results, ProfileData& ps) { + for (ProfileData::Asset& a : ps.assets) { AssetEvent assetEvent; assetEvent.name = a.path; - assetEvent.eventType = [](ProfileStruct::Asset::Type type) { + assetEvent.eventType = [](ProfileData::Asset::Type type) { switch (type) { - case ProfileStruct::Asset::Type::Request: return AssetEventType::Request; - case ProfileStruct::Asset::Type::Require: return AssetEventType::Require; + case ProfileData::Asset::Type::Request: return AssetEventType::Request; + case ProfileData::Asset::Type::Require: return AssetEventType::Require; default: throw ghoul::MissingCaseException(); } }(a.type); @@ -275,32 +301,19 @@ void Profile::parseAssetFileLines(std::vector& results, ProfileStruc } } -void Profile::modifyPropertiesToReflectChanges(ProfileStruct& ps) { +void Profile::modifyPropertiesToReflectChanges(ProfileData& ps) { std::vector changedProps = changedProperties(); std::vector formattedLines; for (properties::Property* prop : changedProps) { - ProfileStruct::Property p; - p.setType = ProfileStruct::Property::SetType::SetPropertyValueSingle; + ProfileData::Property p; + p.setType = ProfileData::Property::SetType::SetPropertyValueSingle; p.name = getFullPropertyPath(prop); p.value = prop->getStringValue(); ps.properties.push_back(std::move(p)); } } -std::vector Profile::changedPropertiesFormatted() { - std::vector changedProps = changedProperties(); - std::vector formattedLines; - - for (properties::Property* prop : changedProps) { - std::string newLine = "setPropertyValueSingle\t"; - newLine += getFullPropertyPath(prop) + "\t"; - newLine += prop->getStringValue(); - formattedLines.push_back(newLine); - } - return formattedLines; -} - std::string Profile::getFullPropertyPath(properties::Property* prop) { return recurseForFullName(prop->owner()) + prop->identifier(); } @@ -308,8 +321,8 @@ std::string Profile::getFullPropertyPath(properties::Property* prop) { std::vector Profile::changedProperties() { ZoneScoped - std::vector nodes - = global::renderEngine.scene()->allSceneGraphNodes(); + std::vector nodes = + global::renderEngine.scene()->allSceneGraphNodes(); std::vector changedProps; for (SceneGraphNode* n : nodes) { @@ -326,34 +339,12 @@ interaction::NavigationHandler::NavigationState Profile::currentCameraState() co return global::navigationHandler.navigationState(); } -void Profile::addCurrentCameraToProfileFile(ProfileStruct& ps) const { - interaction::NavigationHandler::NavigationState nav = currentCameraState(); - - ProfileStruct::CameraNavState camera; - camera.anchor = nav.anchor; - camera.aim = nav.aim; - camera.referenceFrame = nav.referenceFrame; - camera.position = fmt::format( - "{},{},{}", - nav.position.x, nav.position.y, nav.position.z - ); - if (nav.up.has_value()) { - camera.up = fmt::format( - "{},{},{}", - nav.up->x, nav.up->y, nav.up->z - ); - } - camera.yaw = nav.yaw; - camera.pitch = nav.pitch; - ps.camera = std::move(camera); -} - void Profile::convertToSceneFile(const std::string& inProfilePath, const std::string& outFilePath) { ZoneScoped - ProfileStruct ps = readFromFile(inProfilePath); + ProfileData ps = readFromFile(inProfilePath); std::ofstream outFile; try { diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index e647961a32..782076f401 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -39,6 +39,13 @@ int saveCurrentSettingsToProfile(lua_State* L) { if (saveFilePath.empty()) { return luaL_error(L, "save filepath string is empty"); } + if (!global::configuration.usingProfile) { + return luaL_error( + L, + "Program was not started with a profile, so cannot use this " + "save-current-settings feature" + ); + } global::profile.saveCurrentSettingsToProfile( saveFilePath ); diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp index 63dd5c2021..bf0a6e4170 100644 --- a/src/scene/profilefile.cpp +++ b/src/scene/profilefile.cpp @@ -24,17 +24,11 @@ #include -#include -#include -#include -#include +#include +#include #include #include -#include #include -#include -#include -#include namespace openspace { @@ -94,7 +88,7 @@ namespace { throw ProfileError(lineNumber, fmt::format("Invalid section header: {}", line)); } - void parseVersion(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseVersion(ProfileData& ps, const std::string& line, int lineNumber) { std::vector parts = ghoul::tokenizeString(line, '.'); if (parts.empty() || parts.size() > 3) { throw ProfileError( @@ -103,7 +97,7 @@ namespace { ); } - ProfileStruct::Version version; + ProfileData::Version version; version.major = std::stoi(parts[0]); if (parts.size() > 1) { @@ -115,7 +109,7 @@ namespace { ps.version = std::move(version); } - void parseModule(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseModule(ProfileData& ps, const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { throw ProfileError( @@ -123,14 +117,14 @@ namespace { fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) ); } - ProfileStruct::Module m; + ProfileData::Module m; m.name = fields[0]; m.loadedInstruction = fields[1]; m.notLoadedInstruction = fields[2]; ps.modules.push_back(std::move(m)); } - void parseAsset(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseAsset(ProfileData& ps, const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { throw ProfileError( @@ -139,14 +133,14 @@ namespace { ); } - ProfileStruct::Asset a; + ProfileData::Asset a; a.path = fields[0]; - a.type = [&](const std::string& type) -> ProfileStruct::Asset::Type { + a.type = [&](const std::string& type) -> ProfileData::Asset::Type { if (type == "require") { - return ProfileStruct::Asset::Type::Require; + return ProfileData::Asset::Type::Require; } if (type == "request") { - return ProfileStruct::Asset::Type::Request; + return ProfileData::Asset::Type::Request; } throw ProfileError( lineNumber, @@ -157,7 +151,7 @@ namespace { ps.assets.push_back(std::move(a)); } - void parseProperty(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseProperty(ProfileData& ps, const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { throw ProfileError( @@ -165,13 +159,13 @@ namespace { fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) ); } - ProfileStruct::Property p; - p.setType = [&](const std::string& type) -> ProfileStruct::Property::SetType { + ProfileData::Property p; + p.setType = [&](const std::string& type) -> ProfileData::Property::SetType { if (type == "setPropertyValue") { - return ProfileStruct::Property::SetType::SetPropertyValue; + return ProfileData::Property::SetType::SetPropertyValue; } if (type == "setPropertyValueSingle") { - return ProfileStruct::Property::SetType::SetPropertyValueSingle; + return ProfileData::Property::SetType::SetPropertyValueSingle; } throw ProfileError( lineNumber, @@ -187,7 +181,7 @@ namespace { ps.properties.push_back(std::move(p)); } - void parseKeybinding(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseKeybinding(ProfileData& ps, const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 6) { throw ProfileError( @@ -195,7 +189,7 @@ namespace { fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) ); } - ProfileStruct::Keybinding kb; + ProfileData::Keybinding kb; kb.key = fields[0]; kb.documentation = fields[1]; kb.name = fields[2]; @@ -216,7 +210,7 @@ namespace { ps.keybindings.push_back(std::move(kb)); } - void parseTime(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseTime(ProfileData& ps, const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 2) { throw ProfileError( @@ -224,13 +218,13 @@ namespace { fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) ); } - ProfileStruct::Time time; - time.type = [&](const std::string& type) -> ProfileStruct::Time::Type { + ProfileData::Time time; + time.type = [&](const std::string& type) -> ProfileData::Time::Type { if (type == "absolute") { - return ProfileStruct::Time::Type::Absolute; + return ProfileData::Time::Type::Absolute; } if (type == "relative") { - return ProfileStruct::Time::Type::Relative; + return ProfileData::Time::Type::Relative; } throw ProfileError( lineNumber, @@ -241,15 +235,15 @@ namespace { ps.time = std::move(time); } - void parseCamera(ProfileStruct& ps, const std::string& line, int lineNumber) { + void parseCamera(ProfileData& ps, const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.empty()) { throw ProfileError(lineNumber, "No values specified for Camera location"); } ps.camera = [&](const std::string& type) -> - std::variant + std::variant { - if (type == ProfileStruct::CameraNavState::Type) { + if (type == ProfileData::CameraNavState::Type) { if (fields.size() != 8) { throw ProfileError( lineNumber, @@ -259,7 +253,7 @@ namespace { ); } - ProfileStruct::CameraNavState camera; + ProfileData::CameraNavState camera; camera.anchor = fields[1]; camera.aim = fields[2]; camera.referenceFrame = fields[3]; @@ -269,7 +263,7 @@ namespace { camera.pitch = fields[7]; return camera; } - if (type == ProfileStruct::CameraGoToGeo::Type) { + if (type == ProfileData::CameraGoToGeo::Type) { if (fields.size() != 5) { throw ProfileError( lineNumber, @@ -279,7 +273,7 @@ namespace { ); } - ProfileStruct::CameraGoToGeo camera; + ProfileData::CameraGoToGeo camera; camera.anchor = fields[1]; camera.latitude = std::stod(fields[2]); camera.longitude = std::stod(fields[3]); @@ -291,46 +285,53 @@ namespace { throw ProfileError( lineNumber, fmt::format( - "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", fields[0] + "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", + fields[0] ) ); }(fields[0]); } - void parseMarkNodes(ProfileStruct& ps, const std::string& line, int) { + void parseMarkNodes(ProfileData& ps, const std::string& line, int) { ps.markNodes.push_back(line); } } // namespace -std::string serialize(const ProfileStruct& ps) { +std::string serialize(const ProfileData& ps) { std::string output; output += fmt::format("{}\n", headerVersion); - output += fmt::format("{}.{}.{}\n", ps.version.major, ps.version.minor, ps.version.patch); + output += fmt::format( + "{}.{}.{}\n", + ps.version.major, ps.version.minor, ps.version.patch + ); output += fmt::format("\n{}\n", headerModule); - for (const ProfileStruct::Module& m : ps.modules) { - output += fmt::format("{}\t{}\t{}\n", m.name, m.loadedInstruction, m.notLoadedInstruction); + for (const ProfileData::Module& m : ps.modules) { + output += fmt::format( + "{}\t{}\t{}\n", + m.name, m.loadedInstruction, m.notLoadedInstruction + ); } output += fmt::format("\n{}\n", headerAsset); - for (const ProfileStruct::Asset& a : ps.assets) { - const std::string type = [](ProfileStruct::Asset::Type t) { + for (const ProfileData::Asset& a : ps.assets) { + const std::string type = [](ProfileData::Asset::Type t) { switch (t) { - case ProfileStruct::Asset::Type::Require: return "require"; - case ProfileStruct::Asset::Type::Request: return "request"; - default: throw ghoul::MissingCaseException(); + case ProfileData::Asset::Type::Require: return "require"; + case ProfileData::Asset::Type::Request: return "request"; + default: throw ghoul::MissingCaseException(); } }(a.type); output += fmt::format("{}\t{}\n", a.path, type); } output += fmt::format("\n{}\n", headerProperty); - for (const ProfileStruct::Property& p : ps.properties) { - const std::string type = [](ProfileStruct::Property::SetType t) { + for (const ProfileData::Property& p : ps.properties) { + const std::string type = [](ProfileData::Property::SetType t) { switch (t) { - case ProfileStruct::Property::SetType::SetPropertyValue: + case ProfileData::Property::SetType::SetPropertyValue: return "setPropertyValue"; - case ProfileStruct::Property::SetType::SetPropertyValueSingle: + case ProfileData::Property::SetType::SetPropertyValueSingle: return "setPropertyValueSingle"; default: throw ghoul::MissingCaseException(); @@ -340,7 +341,7 @@ std::string serialize(const ProfileStruct& ps) { } output += fmt::format("\n{}\n", headerKeybinding); - for (const ProfileStruct::Keybinding& k : ps.keybindings) { + for (const ProfileData::Keybinding& k : ps.keybindings) { const std::string local = k.isLocal ? "true" : "false"; output += fmt::format( "{}\t{}\t{}\t{}\t{}\t{}\n", @@ -350,11 +351,11 @@ std::string serialize(const ProfileStruct& ps) { output += fmt::format("\n{}\n", headerTime); { - const std::string type = [](ProfileStruct::Time::Type t) { + const std::string type = [](ProfileData::Time::Type t) { switch (t) { - case ProfileStruct::Time::Type::Absolute: return "absolute"; - case ProfileStruct::Time::Type::Relative: return "relative"; - default: throw ghoul::MissingCaseException(); + case ProfileData::Time::Type::Absolute: return "absolute"; + case ProfileData::Time::Type::Relative: return "relative"; + default: throw ghoul::MissingCaseException(); } }(ps.time.type); output += fmt::format("{}\t{}\n", type, ps.time.time); @@ -363,15 +364,15 @@ std::string serialize(const ProfileStruct& ps) { output += fmt::format("\n{}\n", headerCamera); output += std::visit( overloaded { - [](const ProfileStruct::CameraNavState& camera) { + [](const ProfileData::CameraNavState& camera) { return fmt::format( "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", - ProfileStruct::CameraNavState::Type, + ProfileData::CameraNavState::Type, camera.anchor, camera.aim, camera.referenceFrame, camera.position, camera.up, camera.yaw, camera.pitch ); }, - [](const ProfileStruct::CameraGoToGeo& camera) { + [](const ProfileData::CameraGoToGeo& camera) { std::string altitude; if (camera.altitude.has_value()) { altitude = std::to_string(*camera.altitude); @@ -379,7 +380,7 @@ std::string serialize(const ProfileStruct& ps) { return fmt::format( "{}\t{}\t{}\t{}\t{}\n", - ProfileStruct::CameraGoToGeo::Type, + ProfileData::CameraGoToGeo::Type, camera.anchor, camera.latitude, camera.longitude, altitude ); } @@ -395,19 +396,8 @@ std::string serialize(const ProfileStruct& ps) { return output; } -ProfileStruct deserialize(const std::vector& content) { - ProfileStruct result; - - //int lineNum = 1; - //std::ifstream inFile; - //try { - // inFile.open(filename, std::ifstream::in); - //} - //catch (const std::ifstream::failure& e) { - // throw ProfileError(fmt::format( - // "Exception opening profile file for read: {} ({})", filename, e.what()) - // ); - //} +ProfileData deserialize(const std::vector& content) { + ProfileData result; Section currentSection = Section::None; for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { @@ -453,13 +443,13 @@ ProfileStruct deserialize(const std::vector& content) { return result; } -std::string convertToSceneFile(const ProfileStruct& ps) { +std::string convertToSceneFile(const ProfileData& ps) { ZoneScoped std::string output; // Modules - for (const ProfileStruct::Module& m : ps.modules) { + for (const ProfileData::Module& m : ps.modules) { output += fmt::format( "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", m.name, m.loadedInstruction, m.notLoadedInstruction @@ -467,14 +457,14 @@ std::string convertToSceneFile(const ProfileStruct& ps) { } // Assets - for (const ProfileStruct::Asset& a : ps.assets) { + for (const ProfileData::Asset& a : ps.assets) { if (!a.name.empty()) { output += fmt::format("local {} = ", a.name); } - std::string type = [](ProfileStruct::Asset::Type t) { + std::string type = [](ProfileData::Asset::Type t) { switch (t) { - case ProfileStruct::Asset::Type::Request: return "request"; - case ProfileStruct::Asset::Type::Require: return "require"; + case ProfileData::Asset::Type::Request: return "request"; + case ProfileData::Asset::Type::Require: return "require"; default: throw ghoul::MissingCaseException(); } }(a.type); @@ -484,7 +474,7 @@ std::string convertToSceneFile(const ProfileStruct& ps) { output += "asset.onInitialize(function()\n"; // Keybindings - for (const ProfileStruct::Keybinding& k : ps.keybindings) { + for (const ProfileData::Keybinding& k : ps.keybindings) { const std::string name = k.name.empty() ? k.key : k.name; output += fmt::format( k.isLocal ? @@ -496,10 +486,10 @@ std::string convertToSceneFile(const ProfileStruct& ps) { // Time switch (ps.time.type) { - case ProfileStruct::Time::Type::Absolute: + case ProfileData::Time::Type::Absolute: output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); break; - case ProfileStruct::Time::Type::Relative: + case ProfileData::Time::Type::Relative: output += "local now = openspace.time.currentWallTime();\n"; output += fmt::format( "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time @@ -519,15 +509,15 @@ std::string convertToSceneFile(const ProfileStruct& ps) { } // Properties - for (const ProfileStruct::Property& p : ps.properties) { + for (const ProfileData::Property& p : ps.properties) { switch (p.setType) { - case ProfileStruct::Property::SetType::SetPropertyValue: + case ProfileData::Property::SetType::SetPropertyValue: output += fmt::format( "openspace.setPropertyValue(\"{}\", {});\n", p.name, p.value ); break; - case ProfileStruct::Property::SetType::SetPropertyValueSingle: + case ProfileData::Property::SetType::SetPropertyValueSingle: output += fmt::format( "openspace.setPropertyValueSingle(\"{}\", {});\n", p.name, p.value @@ -541,9 +531,9 @@ std::string convertToSceneFile(const ProfileStruct& ps) { // Camera output += std::visit( overloaded { - [](const ProfileStruct::CameraNavState& camera) { + [](const ProfileData::CameraNavState& camera) { std::string result; - result += " openspace.navigation.setNavigationState({"; + result += "openspace.navigation.setNavigationState({"; result += fmt::format("Anchor = {}, ", camera.anchor); if (!camera.aim.empty()) { result += fmt::format("Aim = {}, ", camera.aim); @@ -564,7 +554,7 @@ std::string convertToSceneFile(const ProfileStruct& ps) { result += "})\n"; return result; }, - [](const ProfileStruct::CameraGoToGeo& camera) { + [](const ProfileData::CameraGoToGeo& camera) { if (camera.altitude.has_value()) { return fmt::format( "openspace.globebrowsing.goToGeo({}, {}, {}, {});\n", @@ -586,24 +576,4 @@ std::string convertToSceneFile(const ProfileStruct& ps) { return output; } -ProfileStruct readFromFile(const std::string& filename) { - std::ifstream inFile; - try { - inFile.open(filename, std::ifstream::in); - } - catch (const std::ifstream::failure& e) { - throw ProfileError(fmt::format( - "Exception opening profile file for read: {} ({})", filename, e.what()) - ); - } - - std::vector content; - std::string line; - while (std::getline(inFile, line)) { - content.push_back(std::move(line)); - } - - return deserialize(content); -} - } // namespace openspace From 5bad314b0c5ee4f039207bf51607637d9c839df8 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 14:29:36 +0200 Subject: [PATCH 27/61] Removing the last remnants of ProfileFile --- include/openspace/scene/profile.h | 127 ++++- include/openspace/scene/profilefile.h | 127 ----- src/CMakeLists.txt | 2 - src/engine/openspaceengine.cpp | 12 +- src/scene/profile.cpp | 648 ++++++++++++++++++++++++-- src/scene/profilefile.cpp | 579 ----------------------- 6 files changed, 723 insertions(+), 772 deletions(-) delete mode 100644 include/openspace/scene/profilefile.h delete mode 100644 src/scene/profilefile.cpp diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 1349d5710c..e727fe4df6 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -26,13 +26,14 @@ #define __OPENSPACE_CORE___PROFILE___H__ #include -#include #include #include #include #include +#include #include #include +#include #include namespace ghoul { class Dictionary; } @@ -43,10 +44,94 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } +struct ProfileData { + // Version + struct Version { + int major = 0; + int minor = 0; + int patch = 0; + }; + Version version = { 1, 0, 0 }; + + struct Module { + std::string name; + std::string loadedInstruction; + std::string notLoadedInstruction; + }; + std::vector modules; + + struct Asset { + enum class Type { + Require, + Request + }; + + std::string path; + Type type; + std::string name; + }; + std::vector assets; + + struct Property { + enum class SetType { + SetPropertyValue, + SetPropertyValueSingle + }; + + SetType setType; + std::string name; + std::string value; + }; + std::vector properties; + + struct Keybinding { + std::string key; // @TODO (abock, 2020-06-16) change to key+action + std::string documentation; + std::string name; + std::string guiPath; + bool isLocal; + std::string script; + }; + std::vector keybindings; + + struct Time { + enum class Type { + Absolute, + Relative + }; + + Type type; + std::string time; + }; + Time time; + + struct CameraNavState { + static constexpr const char* Type = "setNavigationState"; + + std::string anchor; + std::string aim; + std::string referenceFrame; + std::string position; // @TODO (abock, 2020-06-17) change to vec3 + std::string up;// @TODO (abock, 2020-06-17) change to vec3 + std::string yaw; + std::string pitch; + }; + struct CameraGoToGeo { + static constexpr const char* Type = "goToGeo"; + + std::string anchor; + double latitude; + double longitude; + std::optional altitude; + }; + using CameraType = std::variant; + CameraType camera; + + std::vector markNodes; +}; + class Profile { public: - static constexpr const char* FormatVersion = "1.0"; - enum class AssetEventType { Add, Require, @@ -60,6 +145,9 @@ public: AssetEventType eventType; }; + Profile() = default; + explicit Profile(const std::string& filename); + virtual ~Profile() {}; /** @@ -75,17 +163,6 @@ public: */ //std::string saveCurrentSettingsToProfile_string(); - /** - * Reads in a .profile file, converts it to scene/asset equivalent syntax, and - * writes the result to the specified output path. - * \param inProfilePath The .profile file to be converted - * \param outFilePath The output file path that will be written with the converted - * contents (in an .asset file) - */ - void convertToSceneFile(const std::string& inProfilePath, - const std::string& outFilePath); - - /** * Returns the Lua library that contains all Lua functions available to provide * profile functionality. @@ -93,12 +170,12 @@ public: */ static scripting::LuaLibrary luaLibrary(); + ProfileData profile; + protected: std::string _profileBaseDirectory = "${ASSETS}"; private: - ProfileData profile; - struct AllAssetDetails { std::vector base; std::vector changed; @@ -106,7 +183,6 @@ private: virtual std::string initialProfile() const; virtual std::string profileBaseDirectory() const; virtual std::vector assetEvents() const; - ProfileData collateBaseWithChanges(); std::vector modifyAssetsToReflectChanges(ProfileData& ps); void parseAssetFileLines(std::vector& results, ProfileData& ps); @@ -118,6 +194,23 @@ private: virtual interaction::NavigationHandler::NavigationState currentCameraState() const; }; + +std::string serialize(const ProfileData& ps); +ProfileData deserialize(const std::vector& content); + +std::string convertToSceneFile(const ProfileData& ps); + +/** + * Reads in a .profile file, converts it to scene/asset equivalent syntax, and + * writes the result to the specified output path. + * \param inProfilePath The .profile file to be converted + * \param outFilePath The output file path that will be written with the converted + * contents (in an .asset file) + */ +void convertProfileToScene(const std::string& inProfilePath, + const std::string& outFilePath); + + } // namespace openspace #endif // __OPENSPACE_CORE___PROFILE___H__ diff --git a/include/openspace/scene/profilefile.h b/include/openspace/scene/profilefile.h deleted file mode 100644 index f9a7db22f3..0000000000 --- a/include/openspace/scene/profilefile.h +++ /dev/null @@ -1,127 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_CORE___PROFILEFILE___H__ -#define __OPENSPACE_CORE___PROFILEFILE___H__ - -#include -#include -#include -#include - -namespace openspace { - -struct ProfileData { - // Version - struct Version { - int major = 0; - int minor = 0; - int patch = 0; - }; - Version version = { 1, 0, 0 }; - - struct Module { - std::string name; - std::string loadedInstruction; - std::string notLoadedInstruction; - }; - std::vector modules; - - struct Asset { - enum class Type { - Require, - Request - }; - - std::string path; - Type type; - std::string name; - }; - std::vector assets; - - struct Property { - enum class SetType { - SetPropertyValue, - SetPropertyValueSingle - }; - - SetType setType; - std::string name; - std::string value; - }; - std::vector properties; - - struct Keybinding { - std::string key; // @TODO (abock, 2020-06-16) change to key+action - std::string documentation; - std::string name; - std::string guiPath; - bool isLocal; - std::string script; - }; - std::vector keybindings; - - struct Time { - enum class Type { - Absolute, - Relative - }; - - Type type; - std::string time; - }; - Time time; - - struct CameraNavState { - static constexpr const char* Type = "setNavigationState"; - - std::string anchor; - std::string aim; - std::string referenceFrame; - std::string position; // @TODO (abock, 2020-06-17) change to vec3 - std::string up;// @TODO (abock, 2020-06-17) change to vec3 - std::string yaw; - std::string pitch; - }; - struct CameraGoToGeo { - static constexpr const char* Type = "goToGeo"; - - std::string anchor; - double latitude; - double longitude; - std::optional altitude; - }; - std::variant camera; - - std::vector markNodes; -}; - -std::string serialize(const ProfileData& ps); -ProfileData deserialize(const std::vector& content); - -std::string convertToSceneFile(const ProfileData& ps); - -} // namespace openspace - -#endif // __OPENSPACE_CORE___PROFILEFILE___H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 68e9b97c6f..3ea989bb7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -153,7 +153,6 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/assetmanager_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/lightsource.cpp ${OPENSPACE_BASE_DIR}/src/scene/profile.cpp - ${OPENSPACE_BASE_DIR}/src/scene/profilefile.cpp ${OPENSPACE_BASE_DIR}/src/scene/profile_lua.inl ${OPENSPACE_BASE_DIR}/src/scene/rotation.cpp ${OPENSPACE_BASE_DIR}/src/scene/scale.cpp @@ -345,7 +344,6 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/lightsource.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/profile.h - ${OPENSPACE_BASE_DIR}/include/openspace/scene/profilefile.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/rotation.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scale.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/scene.h diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index c8aa7612b7..49635dcade 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -312,15 +312,19 @@ void OpenSpaceEngine::initialize() { ); } else { + // Load the profile + global::profile = Profile(inputProfile); - - global::profile.convertToSceneFile(inputProfile, outputAsset); + // Then save the profile to a scene so that we can load it with the + // existing infrastructure + std::ofstream scene(outputAsset); + std::string sceneContent = convertToSceneFile(global::profile.profile); + scene << sceneContent; // Set asset name to that of the profile because a new scene file will be // created with that name, and also because the profile name will override // an asset name if both are provided. - global::configuration.asset = - absPath("${TEMPORARY}/") + global::configuration.profile; + global::configuration.asset = outputAsset; global::configuration.usingProfile = true; } } diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 49a3cfac91..28f7deb34e 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -59,6 +59,32 @@ namespace { constexpr const char* KeyIdentifier = "Identifier"; constexpr const char* KeyParent = "Parent"; + constexpr const char* headerVersion = "#Version"; + constexpr const char* headerModule = "#Module"; + constexpr const char* headerAsset = "#Asset"; + constexpr const char* headerProperty = "#Property"; + constexpr const char* headerKeybinding = "#Keybinding"; + constexpr const char* headerTime = "#Time"; + constexpr const char* headerCamera = "#Camera"; + constexpr const char* headerMarkNodes = "#MarkNodes"; + + // Helper structs for the visitor pattern of the std::variant + template struct overloaded : Ts... { using Ts::operator()...; }; + template overloaded(Ts...)->overloaded; + + struct ProfileParsingError : public ghoul::RuntimeError { + explicit ProfileParsingError(std::string msg) + : ghoul::RuntimeError(std::move(msg), "profileFile") + {} + + ProfileParsingError(unsigned int lineNum, std::string msg) + : ghoul::RuntimeError( + fmt::format("Error @ line {}: {}", lineNum, std::move(msg)), + "profileFile" + ) + {} + }; + const std::map AssetEventTypeString{ { Profile::AssetEventType::Add, "add" }, { Profile::AssetEventType::Require, "required" }, @@ -164,10 +190,291 @@ namespace { return deserialize(content); } + enum class Section { + None, + Version, + Module, + Asset, + Property, + Keybinding, + Time, + Camera, + MarkNodes + }; + + //struct ParsingContext { + // std::string filename; + // int lineNumber; + //}; + + Section parseSection(const std::string& line, int lineNumber) { + if (line == headerVersion) { return Section::Version; } + if (line == headerModule) { return Section::Module; } + if (line == headerAsset) { return Section::Asset; } + if (line == headerProperty) { return Section::Property; } + if (line == headerKeybinding) { return Section::Keybinding; } + if (line == headerTime) { return Section::Time; } + if (line == headerCamera) { return Section::Camera; } + if (line == headerMarkNodes) { return Section::MarkNodes; } + + throw ProfileParsingError( + lineNumber, + fmt::format("Invalid section header: {}", line) + ); + } + + [[ nodiscard ]] ProfileData::Version parseVersion(const std::string& line, int lineNumber) { + std::vector parts = ghoul::tokenizeString(line, '.'); + if (parts.empty() || parts.size() > 3) { + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 1-3 version components, got {}", parts.size()) + ); + } + + ProfileData::Version version; + version.major = std::stoi(parts[0]); + if (parts.size() > 1) { + version.minor = std::stoi(parts[1]); + } + if (parts.size() > 2) { + version.patch = std::stoi(parts[2]); + } + return version; + } + + [[ nodiscard ]] ProfileData::Module parseModule(const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 3) { + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) + ); + } + ProfileData::Module m; + m.name = fields[0]; + m.loadedInstruction = fields[1]; + m.notLoadedInstruction = fields[2]; + return m; + } + + [[ nodiscard ]] ProfileData::Asset parseAsset(const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 3) { + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 3 fields in an Asset entry, got {}", fields.size()) + ); + } + + ProfileData::Asset a; + a.path = fields[0]; + a.type = [&](const std::string& type) -> ProfileData::Asset::Type { + if (type == "require") { + return ProfileData::Asset::Type::Require; + } + if (type == "request") { + return ProfileData::Asset::Type::Request; + } + throw ProfileParsingError( + lineNumber, + fmt::format("Expected asset type 'require' or 'request', got {}", type) + ); + }(fields[1]); + a.name = fields[2]; + return a; + } + + [[ nodiscard ]] ProfileData::Property parseProperty(const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 3) { + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) + ); + } + ProfileData::Property p; + p.setType = [&](const std::string& type) -> ProfileData::Property::SetType { + if (type == "setPropertyValue") { + return ProfileData::Property::SetType::SetPropertyValue; + } + if (type == "setPropertyValueSingle") { + return ProfileData::Property::SetType::SetPropertyValueSingle; + } + throw ProfileParsingError( + lineNumber, + fmt::format( + "Expected property set type 'setPropertyValue' or " + "'setPropertyValueSingle', got {}", + type + ) + ); + }(fields[0]); + p.name = fields[1]; + p.value = fields[2]; + return p; + } + + [[ nodiscard ]] ProfileData::Keybinding parseKeybinding(const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 6) { + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) + ); + } + ProfileData::Keybinding kb; + kb.key = fields[0]; + kb.documentation = fields[1]; + kb.name = fields[2]; + kb.guiPath = fields[3]; + kb.isLocal = [&](const std::string& local) -> bool { + if (local == "false") { + return false; + } + if (local == "true") { + return true; + } + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 'false' or 'true' for the local path, got {}", local) + ); + }(fields[4]); + kb.script = fields[5]; + return kb; + } + + [[ nodiscard ]] ProfileData::Time parseTime(const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.size() != 2) { + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) + ); + } + ProfileData::Time time; + time.type = [&](const std::string& type) -> ProfileData::Time::Type { + if (type == "absolute") { + return ProfileData::Time::Type::Absolute; + } + if (type == "relative") { + return ProfileData::Time::Type::Relative; + } + throw ProfileParsingError( + lineNumber, + fmt::format("Expected 'absolute' or 'relative' for the type, got {}", type) + ); + }(fields[0]); + time.time = fields[1]; + return time; + } + + [[ nodiscard ]] ProfileData::CameraType parseCamera(const std::string& line, int lineNumber) { + std::vector fields = ghoul::tokenizeString(line, '\t'); + if (fields.empty()) { + throw ProfileParsingError(lineNumber, "No values specified for Camera location"); + } + ProfileData::CameraType camera = [&](const std::string& type) -> + std::variant + { + if (type == ProfileData::CameraNavState::Type) { + if (fields.size() != 8) { + throw ProfileParsingError( + lineNumber, + fmt::format( + "Expected 8 fields in the Camera entry, got {}", fields.size() + ) + ); + } + + ProfileData::CameraNavState camera; + camera.anchor = fields[1]; + camera.aim = fields[2]; + camera.referenceFrame = fields[3]; + camera.position = fields[4]; + camera.up = fields[5]; + camera.yaw = fields[6]; + camera.pitch = fields[7]; + return camera; + } + if (type == ProfileData::CameraGoToGeo::Type) { + if (fields.size() != 5) { + throw ProfileParsingError( + lineNumber, + fmt::format( + "Expected 5 fields in the Camera entry, got {}", fields.size() + ) + ); + } + + ProfileData::CameraGoToGeo camera; + camera.anchor = fields[1]; + camera.latitude = std::stod(fields[2]); + camera.longitude = std::stod(fields[3]); + if (!fields[4].empty()) { + camera.altitude = std::stod(fields[4]); + } + return camera; + } + throw ProfileParsingError( + lineNumber, + fmt::format( + "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", + fields[0] + ) + ); + }(fields[0]); + + return camera; + } + + [[ nodiscard ]] std::string parseMarkNodes(const std::string& line, int) { + return line; + } } // namespace +Profile::Profile(const std::string& filename) { + profile = readFromFile(filename); +} + void Profile::saveCurrentSettingsToProfile(const std::string& filename) { - ProfileData ps = collateBaseWithChanges(); + std::string initProfile = initialProfile(); + std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + + ".profile"; + ProfileData ps = readFromFile(inputProfilePath); + ps.version = ProfileData::Version{}; + + std::vector ass = modifyAssetsToReflectChanges(ps); + addAssetsToProfileFile(ps, ass); + modifyPropertiesToReflectChanges(ps); + + // add current time to profile file + ProfileData::Time time; + time.time = currentTimeUTC(); + time.type = ProfileData::Time::Type::Absolute; + ps.time = std::move(time); + + // Camera + interaction::NavigationHandler::NavigationState nav = currentCameraState(); + + ProfileData::CameraNavState camera; + camera.anchor = nav.anchor; + camera.aim = nav.aim; + camera.referenceFrame = nav.referenceFrame; + camera.position = fmt::format( + "{},{},{}", + nav.position.x, nav.position.y, nav.position.z + ); + if (nav.up.has_value()) { + camera.up = fmt::format( + "{},{},{}", + nav.up->x, nav.up->y, nav.up->z + ); + } + camera.yaw = std::to_string(nav.yaw); + camera.pitch = std::to_string(nav.pitch); + ps.camera = std::move(camera); + if (filename.find('/') != std::string::npos) { LERROR("Profile filename must not contain path (/) elements"); @@ -225,46 +532,6 @@ std::string Profile::profileBaseDirectory() const { return _profileBaseDirectory; } -ProfileData Profile::collateBaseWithChanges() { - std::string initProfile = initialProfile(); - std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile - + ".profile"; - ProfileData ps = readFromFile(inputProfilePath); - ps.version = ProfileData::Version{}; - - std::vector ass = modifyAssetsToReflectChanges(ps); - addAssetsToProfileFile(ps, ass); - modifyPropertiesToReflectChanges(ps); - - // add current time to profile file - ProfileData::Time time; - time.time = currentTimeUTC(); - time.type = ProfileData::Time::Type::Absolute; - ps.time = std::move(time); - - // Camera - interaction::NavigationHandler::NavigationState nav = currentCameraState(); - - ProfileData::CameraNavState camera; - camera.anchor = nav.anchor; - camera.aim = nav.aim; - camera.referenceFrame = nav.referenceFrame; - camera.position = fmt::format( - "{},{},{}", - nav.position.x, nav.position.y, nav.position.z - ); - if (nav.up.has_value()) { - camera.up = fmt::format( - "{},{},{}", - nav.up->x, nav.up->y, nav.up->z - ); - } - camera.yaw = std::to_string(nav.yaw); - camera.pitch = std::to_string(nav.pitch); - ps.camera = std::move(camera); - return ps; -} - std::vector Profile::modifyAssetsToReflectChanges(ProfileData& ps) { std::vector a; parseAssetFileLines(a, ps); @@ -339,8 +606,8 @@ interaction::NavigationHandler::NavigationState Profile::currentCameraState() co return global::navigationHandler.navigationState(); } -void Profile::convertToSceneFile(const std::string& inProfilePath, - const std::string& outFilePath) +void convertProfileToScene(const std::string& inProfilePath, + const std::string& outFilePath) { ZoneScoped @@ -387,4 +654,299 @@ scripting::LuaLibrary Profile::luaLibrary() { }; } +std::string serialize(const ProfileData& ps) { + std::string output; + output += fmt::format("{}\n", headerVersion); + output += fmt::format( + "{}.{}.{}\n", + ps.version.major, ps.version.minor, ps.version.patch + ); + + output += fmt::format("\n{}\n", headerModule); + for (const ProfileData::Module& m : ps.modules) { + output += fmt::format( + "{}\t{}\t{}\n", + m.name, m.loadedInstruction, m.notLoadedInstruction + ); + } + + output += fmt::format("\n{}\n", headerAsset); + for (const ProfileData::Asset& a : ps.assets) { + const std::string type = [](ProfileData::Asset::Type t) { + switch (t) { + case ProfileData::Asset::Type::Require: return "require"; + case ProfileData::Asset::Type::Request: return "request"; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + output += fmt::format("{}\t{}\n", a.path, type); + } + + output += fmt::format("\n{}\n", headerProperty); + for (const ProfileData::Property& p : ps.properties) { + const std::string type = [](ProfileData::Property::SetType t) { + switch (t) { + case ProfileData::Property::SetType::SetPropertyValue: + return "setPropertyValue"; + case ProfileData::Property::SetType::SetPropertyValueSingle: + return "setPropertyValueSingle"; + default: + throw ghoul::MissingCaseException(); + } + }(p.setType); + output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); + } + + output += fmt::format("\n{}\n", headerKeybinding); + for (const ProfileData::Keybinding& k : ps.keybindings) { + const std::string local = k.isLocal ? "true" : "false"; + output += fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\n", + k.key, k.documentation, k.name, k.guiPath, local, k.script + ); + } + + output += fmt::format("\n{}\n", headerTime); + { + const std::string type = [](ProfileData::Time::Type t) { + switch (t) { + case ProfileData::Time::Type::Absolute: return "absolute"; + case ProfileData::Time::Type::Relative: return "relative"; + default: throw ghoul::MissingCaseException(); + } + }(ps.time.type); + output += fmt::format("{}\t{}\n", type, ps.time.time); + } + + output += fmt::format("\n{}\n", headerCamera); + output += std::visit( + overloaded{ + [](const ProfileData::CameraNavState& camera) { + return fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", + ProfileData::CameraNavState::Type, + camera.anchor, camera.aim, camera.referenceFrame, camera.position, + camera.up, camera.yaw, camera.pitch + ); + }, + [](const ProfileData::CameraGoToGeo& camera) { + std::string altitude; + if (camera.altitude.has_value()) { + altitude = std::to_string(*camera.altitude); + } + + return fmt::format( + "{}\t{}\t{}\t{}\t{}\n", + ProfileData::CameraGoToGeo::Type, + camera.anchor, camera.latitude, camera.longitude, altitude + ); + } + }, + ps.camera + ); + + output += fmt::format("\n{}\n", headerMarkNodes); + for (const std::string& n : ps.markNodes) { + output += fmt::format("{}\n", n); + } + + return output; +} + +ProfileData deserialize(const std::vector& content) { + ProfileData result; + + Section currentSection = Section::None; + for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { + std::string line = content[lineNum - 1]; + if (std::all_of(line.begin(), line.end(), ::isspace)) { + currentSection = Section::None; + continue; + } + + switch (currentSection) { + case Section::None: + currentSection = parseSection(line, lineNum); + break; + case Section::Version: + result.version = parseVersion(line, lineNum); + break; + case Section::Module: + { + ProfileData::Module m = parseModule(line, lineNum); + result.modules.push_back(std::move(m)); + break; + } + case Section::Asset: + { + ProfileData::Asset a = parseAsset(line, lineNum); + result.assets.push_back(std::move(a)); + break; + } + case Section::Property: + { + ProfileData::Property p = parseProperty(line, lineNum); + result.properties.push_back(std::move(p)); + break; + } + case Section::Keybinding: + { + ProfileData::Keybinding kb = parseKeybinding(line, lineNum); + result.keybindings.push_back(std::move(kb)); + break; + } + case Section::Time: + result.time = parseTime(line, lineNum); + break; + case Section::Camera: + result.camera = parseCamera(line, lineNum); + break; + case Section::MarkNodes: + { + std::string m = parseMarkNodes(line, lineNum); + result.markNodes.push_back(std::move(m)); + break; + } + default: + throw ghoul::MissingCaseException(); + } + } + + return result; +} + +std::string convertToSceneFile(const ProfileData& ps) { + ZoneScoped + + std::string output; + + // Modules + for (const ProfileData::Module& m : ps.modules) { + output += fmt::format( + "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", + m.name, m.loadedInstruction, m.notLoadedInstruction + ); + } + + // Assets + for (const ProfileData::Asset& a : ps.assets) { + if (!a.name.empty()) { + output += fmt::format("local {} = ", a.name); + } + std::string type = [](ProfileData::Asset::Type t) { + switch (t) { + case ProfileData::Asset::Type::Request: return "request"; + case ProfileData::Asset::Type::Require: return "require"; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + + output += fmt::format("asset.{}(\"{}\");\n", type, a.path); + } + + output += "asset.onInitialize(function()\n"; + // Keybindings + for (const ProfileData::Keybinding& k : ps.keybindings) { + const std::string name = k.name.empty() ? k.key : k.name; + output += fmt::format( + k.isLocal ? + "openspace.bindKeyLocal(\"{}\", {}, [[{}]], [[{}]], [[{}]]);\n" : + "openspace.bindKey(\"{}\", {}, [[{}]], [[{}]], [[{}]]);\n", + k.key, k.script, k.documentation, k.name.empty() ? k.key : k.name, k.guiPath + ); + } + + // Time + switch (ps.time.type) { + case ProfileData::Time::Type::Absolute: + output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); + break; + case ProfileData::Time::Type::Relative: + output += "local now = openspace.time.currentWallTime();\n"; + output += fmt::format( + "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time + ); + output += "openspace.time.setTime(prev);\n"; + default: + throw ghoul::MissingCaseException(); + } + + // Mark Nodes + { + std::string nodes; + for (const std::string& n : ps.markNodes) { + nodes += fmt::format("[[ {} ]],", n); + } + output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes); + } + + // Properties + for (const ProfileData::Property& p : ps.properties) { + switch (p.setType) { + case ProfileData::Property::SetType::SetPropertyValue: + output += fmt::format( + "openspace.setPropertyValue(\"{}\", {});\n", + p.name, p.value + ); + break; + case ProfileData::Property::SetType::SetPropertyValueSingle: + output += fmt::format( + "openspace.setPropertyValueSingle(\"{}\", {});\n", + p.name, p.value + ); + break; + default: + throw ghoul::MissingCaseException(); + } + } + + // Camera + output += std::visit( + overloaded{ + [](const ProfileData::CameraNavState& camera) { + std::string result; + result += "openspace.navigation.setNavigationState({"; + result += fmt::format("Anchor = {}, ", camera.anchor); + if (!camera.aim.empty()) { + result += fmt::format("Aim = {}, ", camera.aim); + } + if (!camera.referenceFrame.empty()) { + result += fmt::format("ReferenceFrame = {}, ", camera.referenceFrame); + } + result += fmt::format("Position = {{ {} }}, ", camera.position); + if (!camera.up.empty()) { + result += fmt::format("Up = {{ {} }}, ", camera.up); + } + if (!camera.yaw.empty()) { + result += fmt::format("Yaw = {}, ", camera.yaw); + } + if (!camera.pitch.empty()) { + result += fmt::format("Pitch = {} ", camera.pitch); + } + result += "})\n"; + return result; + }, + [](const ProfileData::CameraGoToGeo& camera) { + if (camera.altitude.has_value()) { + return fmt::format( + "openspace.globebrowsing.goToGeo({}, {}, {}, {});\n", + camera.anchor, camera.latitude, camera.longitude, *camera.altitude + ); + } + else { + return fmt::format( + "openspace.globebrowsing.goToGeo({}, {}, {});\n", + camera.anchor, camera.latitude, camera.longitude + ); + } + } + }, + ps.camera + ); + output += "end)\n"; + + return output; +} + + } // namespace openspace diff --git a/src/scene/profilefile.cpp b/src/scene/profilefile.cpp deleted file mode 100644 index bf0a6e4170..0000000000 --- a/src/scene/profilefile.cpp +++ /dev/null @@ -1,579 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 - -namespace openspace { - -namespace { - constexpr const char* _loggerCat = "ProfileFile"; - constexpr const char* KeyIdentifier = "Identifier"; - constexpr const char* KeyParent = "Parent"; - - constexpr const char* headerVersion = "#Version"; - constexpr const char* headerModule = "#Module"; - constexpr const char* headerAsset = "#Asset"; - constexpr const char* headerProperty = "#Property"; - constexpr const char* headerKeybinding = "#Keybinding"; - constexpr const char* headerTime = "#Time"; - constexpr const char* headerCamera = "#Camera"; - constexpr const char* headerMarkNodes = "#MarkNodes"; - - // Helper structs for the visitor pattern of the std::variant - template struct overloaded : Ts... { using Ts::operator()...; }; - template overloaded(Ts...)->overloaded; - - struct ProfileError : public ghoul::RuntimeError { - explicit ProfileError(std::string msg) - : ghoul::RuntimeError(std::move(msg), "profileFile") - {} - - ProfileError(unsigned int lineNum, std::string msg) - : ghoul::RuntimeError( - fmt::format("Error @ line {}: {}", lineNum, std::move(msg)), - "profileFile" - ) - {} - }; - - enum class Section { - None, - Version, - Module, - Asset, - Property, - Keybinding, - Time, - Camera, - MarkNodes - }; - - Section parseSection(const std::string& line, int lineNumber) { - if (line == headerVersion) { return Section::Version; } - if (line == headerModule) { return Section::Module; } - if (line == headerAsset) { return Section::Asset; } - if (line == headerProperty) { return Section::Property; } - if (line == headerKeybinding) { return Section::Keybinding; } - if (line == headerTime) { return Section::Time; } - if (line == headerCamera) { return Section::Camera; } - if (line == headerMarkNodes) { return Section::MarkNodes; } - - throw ProfileError(lineNumber, fmt::format("Invalid section header: {}", line)); - } - - void parseVersion(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector parts = ghoul::tokenizeString(line, '.'); - if (parts.empty() || parts.size() > 3) { - throw ProfileError( - lineNumber, - fmt::format("Expected 1-3 version components, got {}", parts.size()) - ); - } - - ProfileData::Version version; - - version.major = std::stoi(parts[0]); - if (parts.size() > 1) { - version.minor = std::stoi(parts[1]); - } - if (parts.size() > 2) { - version.patch = std::stoi(parts[2]); - } - ps.version = std::move(version); - } - - void parseModule(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != 3) { - throw ProfileError( - lineNumber, - fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) - ); - } - ProfileData::Module m; - m.name = fields[0]; - m.loadedInstruction = fields[1]; - m.notLoadedInstruction = fields[2]; - ps.modules.push_back(std::move(m)); - } - - void parseAsset(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != 3) { - throw ProfileError( - lineNumber, - fmt::format("Expected 3 fields in an Asset entry, got {}", fields.size()) - ); - } - - ProfileData::Asset a; - a.path = fields[0]; - a.type = [&](const std::string& type) -> ProfileData::Asset::Type { - if (type == "require") { - return ProfileData::Asset::Type::Require; - } - if (type == "request") { - return ProfileData::Asset::Type::Request; - } - throw ProfileError( - lineNumber, - fmt::format("Expected asset type 'require' or 'request', got {}", type) - ); - }(fields[1]); - a.name = fields[2]; - ps.assets.push_back(std::move(a)); - } - - void parseProperty(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != 3) { - throw ProfileError( - lineNumber, - fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) - ); - } - ProfileData::Property p; - p.setType = [&](const std::string& type) -> ProfileData::Property::SetType { - if (type == "setPropertyValue") { - return ProfileData::Property::SetType::SetPropertyValue; - } - if (type == "setPropertyValueSingle") { - return ProfileData::Property::SetType::SetPropertyValueSingle; - } - throw ProfileError( - lineNumber, - fmt::format( - "Expected property set type 'setPropertyValue' or " - "'setPropertyValueSingle', got {}", - type - ) - ); - }(fields[0]); - p.name = fields[1]; - p.value = fields[2]; - ps.properties.push_back(std::move(p)); - } - - void parseKeybinding(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != 6) { - throw ProfileError( - lineNumber, - fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) - ); - } - ProfileData::Keybinding kb; - kb.key = fields[0]; - kb.documentation = fields[1]; - kb.name = fields[2]; - kb.guiPath = fields[3]; - kb.isLocal = [&](const std::string& local) -> bool { - if (local == "false") { - return false; - } - if (local == "true") { - return true; - } - throw ProfileError( - lineNumber, - fmt::format("Expected 'false' or 'true' for the local path, got {}", local) - ); - }(fields[4]); - kb.script = fields[5]; - ps.keybindings.push_back(std::move(kb)); - } - - void parseTime(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.size() != 2) { - throw ProfileError( - lineNumber, - fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) - ); - } - ProfileData::Time time; - time.type = [&](const std::string& type) -> ProfileData::Time::Type { - if (type == "absolute") { - return ProfileData::Time::Type::Absolute; - } - if (type == "relative") { - return ProfileData::Time::Type::Relative; - } - throw ProfileError( - lineNumber, - fmt::format("Expected 'absolute' or 'relative' for the type, got {}", type) - ); - }(fields[0]); - time.time = fields[1]; - ps.time = std::move(time); - } - - void parseCamera(ProfileData& ps, const std::string& line, int lineNumber) { - std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.empty()) { - throw ProfileError(lineNumber, "No values specified for Camera location"); - } - ps.camera = [&](const std::string& type) -> - std::variant - { - if (type == ProfileData::CameraNavState::Type) { - if (fields.size() != 8) { - throw ProfileError( - lineNumber, - fmt::format( - "Expected 8 fields in the Camera entry, got {}", fields.size() - ) - ); - } - - ProfileData::CameraNavState camera; - camera.anchor = fields[1]; - camera.aim = fields[2]; - camera.referenceFrame = fields[3]; - camera.position = fields[4]; - camera.up = fields[5]; - camera.yaw = fields[6]; - camera.pitch = fields[7]; - return camera; - } - if (type == ProfileData::CameraGoToGeo::Type) { - if (fields.size() != 5) { - throw ProfileError( - lineNumber, - fmt::format( - "Expected 5 fields in the Camera entry, got {}", fields.size() - ) - ); - } - - ProfileData::CameraGoToGeo camera; - camera.anchor = fields[1]; - camera.latitude = std::stod(fields[2]); - camera.longitude = std::stod(fields[3]); - if (!fields[4].empty()) { - camera.altitude = std::stod(fields[4]); - } - return camera; - } - throw ProfileError( - lineNumber, - fmt::format( - "Expected 'setNavigationState' or 'goToGeo' for the type, got {}", - fields[0] - ) - ); - }(fields[0]); - } - - void parseMarkNodes(ProfileData& ps, const std::string& line, int) { - ps.markNodes.push_back(line); - } -} // namespace - -std::string serialize(const ProfileData& ps) { - std::string output; - output += fmt::format("{}\n", headerVersion); - output += fmt::format( - "{}.{}.{}\n", - ps.version.major, ps.version.minor, ps.version.patch - ); - - output += fmt::format("\n{}\n", headerModule); - for (const ProfileData::Module& m : ps.modules) { - output += fmt::format( - "{}\t{}\t{}\n", - m.name, m.loadedInstruction, m.notLoadedInstruction - ); - } - - output += fmt::format("\n{}\n", headerAsset); - for (const ProfileData::Asset& a : ps.assets) { - const std::string type = [](ProfileData::Asset::Type t) { - switch (t) { - case ProfileData::Asset::Type::Require: return "require"; - case ProfileData::Asset::Type::Request: return "request"; - default: throw ghoul::MissingCaseException(); - } - }(a.type); - output += fmt::format("{}\t{}\n", a.path, type); - } - - output += fmt::format("\n{}\n", headerProperty); - for (const ProfileData::Property& p : ps.properties) { - const std::string type = [](ProfileData::Property::SetType t) { - switch (t) { - case ProfileData::Property::SetType::SetPropertyValue: - return "setPropertyValue"; - case ProfileData::Property::SetType::SetPropertyValueSingle: - return "setPropertyValueSingle"; - default: - throw ghoul::MissingCaseException(); - } - }(p.setType); - output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); - } - - output += fmt::format("\n{}\n", headerKeybinding); - for (const ProfileData::Keybinding& k : ps.keybindings) { - const std::string local = k.isLocal ? "true" : "false"; - output += fmt::format( - "{}\t{}\t{}\t{}\t{}\t{}\n", - k.key, k.documentation, k.name, k.guiPath, local, k.script - ); - } - - output += fmt::format("\n{}\n", headerTime); - { - const std::string type = [](ProfileData::Time::Type t) { - switch (t) { - case ProfileData::Time::Type::Absolute: return "absolute"; - case ProfileData::Time::Type::Relative: return "relative"; - default: throw ghoul::MissingCaseException(); - } - }(ps.time.type); - output += fmt::format("{}\t{}\n", type, ps.time.time); - } - - output += fmt::format("\n{}\n", headerCamera); - output += std::visit( - overloaded { - [](const ProfileData::CameraNavState& camera) { - return fmt::format( - "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", - ProfileData::CameraNavState::Type, - camera.anchor, camera.aim, camera.referenceFrame, camera.position, - camera.up, camera.yaw, camera.pitch - ); - }, - [](const ProfileData::CameraGoToGeo& camera) { - std::string altitude; - if (camera.altitude.has_value()) { - altitude = std::to_string(*camera.altitude); - } - - return fmt::format( - "{}\t{}\t{}\t{}\t{}\n", - ProfileData::CameraGoToGeo::Type, - camera.anchor, camera.latitude, camera.longitude, altitude - ); - } - }, - ps.camera - ); - - output += fmt::format("\n{}\n", headerMarkNodes); - for (const std::string& n : ps.markNodes) { - output += fmt::format("{}\n", n); - } - - return output; -} - -ProfileData deserialize(const std::vector& content) { - ProfileData result; - - Section currentSection = Section::None; - for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { - std::string line = content[lineNum - 1]; - if (std::all_of(line.begin(), line.end(), ::isspace)) { - currentSection = Section::None; - continue; - } - - switch (currentSection) { - case Section::None: - currentSection = parseSection(line, lineNum); - break; - case Section::Version: - parseVersion(result, line, lineNum); - break; - case Section::Module: - parseModule(result, line, lineNum); - break; - case Section::Asset: - parseAsset(result, line, lineNum); - break; - case Section::Property: - parseProperty(result, line, lineNum); - break; - case Section::Keybinding: - parseKeybinding(result, line, lineNum); - break; - case Section::Time: - parseTime(result, line, lineNum); - break; - case Section::Camera: - parseCamera(result, line, lineNum); - break; - case Section::MarkNodes: - parseMarkNodes(result, line, lineNum); - break; - default: - throw ghoul::MissingCaseException(); - } - } - - return result; -} - -std::string convertToSceneFile(const ProfileData& ps) { - ZoneScoped - - std::string output; - - // Modules - for (const ProfileData::Module& m : ps.modules) { - output += fmt::format( - "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", - m.name, m.loadedInstruction, m.notLoadedInstruction - ); - } - - // Assets - for (const ProfileData::Asset& a : ps.assets) { - if (!a.name.empty()) { - output += fmt::format("local {} = ", a.name); - } - std::string type = [](ProfileData::Asset::Type t) { - switch (t) { - case ProfileData::Asset::Type::Request: return "request"; - case ProfileData::Asset::Type::Require: return "require"; - default: throw ghoul::MissingCaseException(); - } - }(a.type); - - output += fmt::format("asset.{}(\"{}\");\n", type, a.path); - } - - output += "asset.onInitialize(function()\n"; - // Keybindings - for (const ProfileData::Keybinding& k : ps.keybindings) { - const std::string name = k.name.empty() ? k.key : k.name; - output += fmt::format( - k.isLocal ? - "openspace.bindKeyLocal(\"{}\", {}, [[{}]], [[{}]], [[{}]]);\n" : - "openspace.bindKey(\"{}\", {}, [[{}]], [[{}]], [[{}]]);\n", - k.key, k.script, k.documentation, k.name.empty() ? k.key : k.name, k.guiPath - ); - } - - // Time - switch (ps.time.type) { - case ProfileData::Time::Type::Absolute: - output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); - break; - case ProfileData::Time::Type::Relative: - output += "local now = openspace.time.currentWallTime();\n"; - output += fmt::format( - "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time - ); - output += "openspace.time.setTime(prev);\n"; - default: - throw ghoul::MissingCaseException(); - } - - // Mark Nodes - { - std::string nodes; - for (const std::string& n : ps.markNodes) { - nodes += fmt::format("[[ {} ]],", n); - } - output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes); - } - - // Properties - for (const ProfileData::Property& p : ps.properties) { - switch (p.setType) { - case ProfileData::Property::SetType::SetPropertyValue: - output += fmt::format( - "openspace.setPropertyValue(\"{}\", {});\n", - p.name, p.value - ); - break; - case ProfileData::Property::SetType::SetPropertyValueSingle: - output += fmt::format( - "openspace.setPropertyValueSingle(\"{}\", {});\n", - p.name, p.value - ); - break; - default: - throw ghoul::MissingCaseException(); - } - } - - // Camera - output += std::visit( - overloaded { - [](const ProfileData::CameraNavState& camera) { - std::string result; - result += "openspace.navigation.setNavigationState({"; - result += fmt::format("Anchor = {}, ", camera.anchor); - if (!camera.aim.empty()) { - result += fmt::format("Aim = {}, ", camera.aim); - } - if (!camera.referenceFrame.empty()) { - result += fmt::format("ReferenceFrame = {}, ", camera.referenceFrame); - } - result += fmt::format("Position = {{ {} }}, ", camera.position); - if (!camera.up.empty()) { - result += fmt::format("Up = {{ {} }}, ", camera.up); - } - if (!camera.yaw.empty()) { - result += fmt::format("Yaw = {}, ", camera.yaw); - } - if (!camera.pitch.empty()) { - result += fmt::format("Pitch = {} ", camera.pitch); - } - result += "})\n"; - return result; - }, - [](const ProfileData::CameraGoToGeo& camera) { - if (camera.altitude.has_value()) { - return fmt::format( - "openspace.globebrowsing.goToGeo({}, {}, {}, {});\n", - camera.anchor, camera.latitude, camera.longitude, *camera.altitude - ); - } - else { - return fmt::format( - "openspace.globebrowsing.goToGeo({}, {}, {});\n", - camera.anchor, camera.latitude, camera.longitude - ); - } - } - }, - ps.camera - ); - output += "end)\n"; - - return output; -} - -} // namespace openspace From 83e933fa00fe239dc229c1f94b75a314309bfe38 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 15:47:17 +0200 Subject: [PATCH 28/61] Automatically create new profile name if no name is specified --- include/openspace/scene/profile.h | 9 +- src/scene/profile.cpp | 181 ++++++++++++++++-------------- src/scene/profile_lua.inl | 58 +++++++--- 3 files changed, 148 insertions(+), 100 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index e727fe4df6..e53612d004 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -51,7 +51,8 @@ struct ProfileData { int minor = 0; int patch = 0; }; - Version version = { 1, 0, 0 }; + static constexpr const Version CurrentVersion = Version{ 1, 0, 0 }; + Version version = CurrentVersion; struct Module { std::string name; @@ -150,6 +151,12 @@ public: virtual ~Profile() {}; + /** + * Saves all current settings, starting from the profile that was loaded at startup, + * and all of the property & asset changes that were made since startup. + */ + void saveCurrentSettingsToProfile(); + /** * Saves all current settings, starting from the profile that was loaded at startup, * and all of the property & asset changes that were made since startup. diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 28f7deb34e..9e35028223 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -437,22 +437,18 @@ Profile::Profile(const std::string& filename) { profile = readFromFile(filename); } -void Profile::saveCurrentSettingsToProfile(const std::string& filename) { - std::string initProfile = initialProfile(); - std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile - + ".profile"; - ProfileData ps = readFromFile(inputProfilePath); - ps.version = ProfileData::Version{}; +void Profile::saveCurrentSettingsToProfile() { + profile.version = ProfileData::CurrentVersion; - std::vector ass = modifyAssetsToReflectChanges(ps); - addAssetsToProfileFile(ps, ass); - modifyPropertiesToReflectChanges(ps); + std::vector ass = modifyAssetsToReflectChanges(profile); + addAssetsToProfileFile(profile, ass); + modifyPropertiesToReflectChanges(profile); // add current time to profile file ProfileData::Time time; time.time = currentTimeUTC(); time.type = ProfileData::Time::Type::Absolute; - ps.time = std::move(time); + profile.time = std::move(time); // Camera interaction::NavigationHandler::NavigationState nav = currentCameraState(); @@ -473,7 +469,16 @@ void Profile::saveCurrentSettingsToProfile(const std::string& filename) { } camera.yaw = std::to_string(nav.yaw); camera.pitch = std::to_string(nav.pitch); - ps.camera = std::move(camera); + profile.camera = std::move(camera); +} + +void Profile::saveCurrentSettingsToProfile(const std::string& filename) { + //std::string initProfile = initialProfile(); + //std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile + // + ".profile"; + //ProfileData ps = readFromFile(inputProfilePath); + + saveCurrentSettingsToProfile(); if (filename.find('/') != std::string::npos) { @@ -510,11 +515,10 @@ void Profile::saveCurrentSettingsToProfile(const std::string& filename) { } try { - outFile << serialize(ps); + outFile << serialize(profile); } catch (const std::ofstream::failure& e) { - LERROR("Data write error to file: " - + absFilename + " (" + e.what() + ")"); + LERROR(fmt::format("Data write error to file: {} ({})", absFilename, e.what())); } outFile.close(); @@ -662,48 +666,56 @@ std::string serialize(const ProfileData& ps) { ps.version.major, ps.version.minor, ps.version.patch ); - output += fmt::format("\n{}\n", headerModule); - for (const ProfileData::Module& m : ps.modules) { - output += fmt::format( - "{}\t{}\t{}\n", - m.name, m.loadedInstruction, m.notLoadedInstruction - ); + if (!ps.modules.empty()) { + output += fmt::format("\n{}\n", headerModule); + for (const ProfileData::Module& m : ps.modules) { + output += fmt::format( + "{}\t{}\t{}\n", + m.name, m.loadedInstruction, m.notLoadedInstruction + ); + } } - output += fmt::format("\n{}\n", headerAsset); - for (const ProfileData::Asset& a : ps.assets) { - const std::string type = [](ProfileData::Asset::Type t) { - switch (t) { - case ProfileData::Asset::Type::Require: return "require"; - case ProfileData::Asset::Type::Request: return "request"; - default: throw ghoul::MissingCaseException(); - } - }(a.type); - output += fmt::format("{}\t{}\n", a.path, type); + if (!ps.assets.empty()) { + output += fmt::format("\n{}\n", headerAsset); + for (const ProfileData::Asset& a : ps.assets) { + const std::string type = [](ProfileData::Asset::Type t) { + switch (t) { + case ProfileData::Asset::Type::Require: return "require"; + case ProfileData::Asset::Type::Request: return "request"; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + output += fmt::format("{}\t{}\n", a.path, type); + } } - output += fmt::format("\n{}\n", headerProperty); - for (const ProfileData::Property& p : ps.properties) { - const std::string type = [](ProfileData::Property::SetType t) { - switch (t) { - case ProfileData::Property::SetType::SetPropertyValue: - return "setPropertyValue"; - case ProfileData::Property::SetType::SetPropertyValueSingle: - return "setPropertyValueSingle"; - default: - throw ghoul::MissingCaseException(); - } - }(p.setType); - output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); + if (!ps.properties.empty()) { + output += fmt::format("\n{}\n", headerProperty); + for (const ProfileData::Property& p : ps.properties) { + const std::string type = [](ProfileData::Property::SetType t) { + switch (t) { + case ProfileData::Property::SetType::SetPropertyValue: + return "setPropertyValue"; + case ProfileData::Property::SetType::SetPropertyValueSingle: + return "setPropertyValueSingle"; + default: + throw ghoul::MissingCaseException(); + } + }(p.setType); + output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); + } } - output += fmt::format("\n{}\n", headerKeybinding); - for (const ProfileData::Keybinding& k : ps.keybindings) { - const std::string local = k.isLocal ? "true" : "false"; - output += fmt::format( - "{}\t{}\t{}\t{}\t{}\t{}\n", - k.key, k.documentation, k.name, k.guiPath, local, k.script - ); + if (!ps.keybindings.empty()) { + output += fmt::format("\n{}\n", headerKeybinding); + for (const ProfileData::Keybinding& k : ps.keybindings) { + const std::string local = k.isLocal ? "true" : "false"; + output += fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\n", + k.key, k.documentation, k.name, k.guiPath, local, k.script + ); + } } output += fmt::format("\n{}\n", headerTime); @@ -743,11 +755,13 @@ std::string serialize(const ProfileData& ps) { } }, ps.camera - ); + ); - output += fmt::format("\n{}\n", headerMarkNodes); - for (const std::string& n : ps.markNodes) { - output += fmt::format("{}\n", n); + if (!ps.markNodes.empty()) { + output += fmt::format("\n{}\n", headerMarkNodes); + for (const std::string& n : ps.markNodes) { + output += fmt::format("{}\n", n); + } } return output; @@ -818,7 +832,7 @@ ProfileData deserialize(const std::vector& content) { std::string convertToSceneFile(const ProfileData& ps) { ZoneScoped - std::string output; + std::string output; // Modules for (const ProfileData::Module& m : ps.modules) { @@ -835,9 +849,9 @@ std::string convertToSceneFile(const ProfileData& ps) { } std::string type = [](ProfileData::Asset::Type t) { switch (t) { - case ProfileData::Asset::Type::Request: return "request"; - case ProfileData::Asset::Type::Require: return "require"; - default: throw ghoul::MissingCaseException(); + case ProfileData::Asset::Type::Request: return "request"; + case ProfileData::Asset::Type::Require: return "require"; + default: throw ghoul::MissingCaseException(); } }(a.type); @@ -858,17 +872,18 @@ std::string convertToSceneFile(const ProfileData& ps) { // Time switch (ps.time.type) { - case ProfileData::Time::Type::Absolute: - output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); - break; - case ProfileData::Time::Type::Relative: - output += "local now = openspace.time.currentWallTime();\n"; - output += fmt::format( - "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time - ); - output += "openspace.time.setTime(prev);\n"; - default: - throw ghoul::MissingCaseException(); + case ProfileData::Time::Type::Absolute: + output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); + break; + case ProfileData::Time::Type::Relative: + output += "local now = openspace.time.currentWallTime();\n"; + output += fmt::format( + "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time + ); + output += "openspace.time.setTime(prev);\n"; + break; + default: + throw ghoul::MissingCaseException(); } // Mark Nodes @@ -883,20 +898,20 @@ std::string convertToSceneFile(const ProfileData& ps) { // Properties for (const ProfileData::Property& p : ps.properties) { switch (p.setType) { - case ProfileData::Property::SetType::SetPropertyValue: - output += fmt::format( - "openspace.setPropertyValue(\"{}\", {});\n", - p.name, p.value - ); - break; - case ProfileData::Property::SetType::SetPropertyValueSingle: - output += fmt::format( - "openspace.setPropertyValueSingle(\"{}\", {});\n", - p.name, p.value - ); - break; - default: - throw ghoul::MissingCaseException(); + case ProfileData::Property::SetType::SetPropertyValue: + output += fmt::format( + "openspace.setPropertyValue(\"{}\", {});\n", + p.name, p.value + ); + break; + case ProfileData::Property::SetType::SetPropertyValueSingle: + output += fmt::format( + "openspace.setPropertyValueSingle(\"{}\", {});\n", + p.name, p.value + ); + break; + default: + throw ghoul::MissingCaseException(); } } diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index 782076f401..8fc8759695 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -22,23 +22,12 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include +#include + namespace openspace::luascriptfunctions { - int saveCurrentSettingsToProfile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::saveCurrentSettingsToProfile"); - - using ghoul::lua::luaTypeToString; - - const std::string saveFilePath = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); - - if (saveFilePath.empty()) { - return luaL_error(L, "save filepath string is empty"); - } if (!global::configuration.usingProfile) { return luaL_error( L, @@ -46,10 +35,47 @@ int saveCurrentSettingsToProfile(lua_State* L) { "save-current-settings feature" ); } - global::profile.saveCurrentSettingsToProfile( - saveFilePath + + const int n = ghoul::lua::checkArgumentsAndThrow( + L, + { 0, 1 }, + "lua::saveCurrentSettingsToProfile" ); + using ghoul::lua::luaTypeToString; + + std::string saveFilePath; + if (n == 0) { + const ghoul::filesystem::File f = global::configuration.profile; + + std::time_t t = std::time(nullptr); + std::tm* utcTime = std::gmtime(&t); + ghoul_assert(utcTime, "Conversion to UTC failed"); + + std::string time = fmt::format( + "{:04d}-{:02d}-{:02d}T{:02d}_{:02d}_{:02d}", + utcTime->tm_year + 1900, + utcTime->tm_mon + 1, + utcTime->tm_mday, + utcTime->tm_hour, + utcTime->tm_min, + utcTime->tm_sec + ); + saveFilePath = fmt::format("{}_{}.{}", f.fullBaseName(), time, f.fileExtension()); + } + else { + saveFilePath = ghoul::lua::value( + L, + 1, + ghoul::lua::PopValue::Yes + ); + if (saveFilePath.empty()) { + return luaL_error(L, "save filepath string is empty"); + } + } + + global::profile.saveCurrentSettingsToProfile(saveFilePath); + ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } From 944bd38ae7af025acffa40eab67e8f1657c16879 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 17:07:20 +0200 Subject: [PATCH 29/61] Rename saveCurrentSettings to saveSettings --- include/openspace/scene/profile.h | 15 ------ src/scene/profile.cpp | 80 +++++------------------------- src/scene/profile_lua.inl | 81 ++++++++++++++++++++++++++----- 3 files changed, 80 insertions(+), 96 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index e53612d004..e42705d56f 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -157,19 +157,6 @@ public: */ void saveCurrentSettingsToProfile(); - /** - * Saves all current settings, starting from the profile that was loaded at startup, - * and all of the property & asset changes that were made since startup. - * \param filename The filename of the new profile to be saved - */ - void saveCurrentSettingsToProfile(const std::string& filename); - - /** - * Saves all current settings, similar to saveCurrentSettingsToProfile() except the - * output is a string without writing to a file. - */ - //std::string saveCurrentSettingsToProfile_string(); - /** * Returns the Lua library that contains all Lua functions available to provide * profile functionality. @@ -196,8 +183,6 @@ private: void modifyPropertiesToReflectChanges(ProfileData& ps); virtual std::vector changedProperties(); - std::string getFullPropertyPath(openspace::properties::Property* prop); - virtual std::string currentTimeUTC() const; virtual interaction::NavigationHandler::NavigationState currentCameraState() const; }; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 9e35028223..4faa969b58 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -446,7 +446,7 @@ void Profile::saveCurrentSettingsToProfile() { // add current time to profile file ProfileData::Time time; - time.time = currentTimeUTC(); + time.time = global::timeManager.time().ISO8601(); time.type = ProfileData::Time::Type::Absolute; profile.time = std::move(time); @@ -472,58 +472,6 @@ void Profile::saveCurrentSettingsToProfile() { profile.camera = std::move(camera); } -void Profile::saveCurrentSettingsToProfile(const std::string& filename) { - //std::string initProfile = initialProfile(); - //std::string inputProfilePath = absPath(_profileBaseDirectory) + "/" + initProfile - // + ".profile"; - //ProfileData ps = readFromFile(inputProfilePath); - - saveCurrentSettingsToProfile(); - - - if (filename.find('/') != std::string::npos) { - LERROR("Profile filename must not contain path (/) elements"); - return; - } - else if (filename.find(':') != std::string::npos) { - LERROR("Profile filename must not contain path (:) elements"); - return; - } - else if (filename.find('.') != std::string::npos) { - LERROR("Only provide the filename to save without file extension"); - return; - } - const std::string absFilename = absPath("${ASSETS}/" + filename + ".profile"); - - if (FileSys.fileExists(absFilename)) { - LERROR(fmt::format( - "Unable to save profile '{}'. File of same name already exists.", - absFilename.c_str() - )); - return; - } - - std::ofstream outFile; - // @TODO (abock, 2020-06-15) Replace with non-throwing stream - try { - outFile.open(absFilename, std::ofstream::out); - } - catch (const std::ofstream::failure& e) { - LERROR(fmt::format( - "Exception opening profile file for write: {} ({})", absFilename, e.what() - )); - } - - try { - outFile << serialize(profile); - } - catch (const std::ofstream::failure& e) { - LERROR(fmt::format("Data write error to file: {} ({})", absFilename, e.what())); - } - - outFile.close(); -} - std::string Profile::initialProfile() const { return global::configuration.profile; } @@ -579,16 +527,12 @@ void Profile::modifyPropertiesToReflectChanges(ProfileData& ps) { for (properties::Property* prop : changedProps) { ProfileData::Property p; p.setType = ProfileData::Property::SetType::SetPropertyValueSingle; - p.name = getFullPropertyPath(prop); + p.name = recurseForFullName(prop->owner()) + prop->identifier(); p.value = prop->getStringValue(); ps.properties.push_back(std::move(p)); } } -std::string Profile::getFullPropertyPath(properties::Property* prop) { - return recurseForFullName(prop->owner()) + prop->identifier(); -} - std::vector Profile::changedProperties() { ZoneScoped @@ -602,10 +546,6 @@ std::vector Profile::changedProperties() { return changedProps; } -std::string Profile::currentTimeUTC() const { - return global::timeManager.time().ISO8601(); -} - interaction::NavigationHandler::NavigationState Profile::currentCameraState() const { return global::navigationHandler.navigationState(); } @@ -642,17 +582,19 @@ scripting::LuaLibrary Profile::luaLibrary() { "", { { - "saveCurrentSettingsToProfile", - &luascriptfunctions::saveCurrentSettingsToProfile, + "saveSettingsToProfile", + &luascriptfunctions::saveSettingsToProfile, {}, - "string", + "[string, bool]", "Collects all changes that have been made since startup, including all " "property changes and assets required, requested, or removed. All " "changes will be added to the profile that OpenSpace was started with, " - "and the new saved file will contain all of this information. The " - "file will be named according to the argument provided. If this argument " - "is blank, then the new file will have the base name of the profile that " - " was started, with a _YYYYMMDD suffix." + "and the new saved file will contain all of this information. If the " + "arugment is provided, the settings will be saved into new profile with " + "that name. If the argument is blank, the current profile will be saved " + "to a backup file and the original profile will be overwritten. The " + "second argument determines if a file that already exists should be " + "overwritten, which is 'false' by default" } } }; diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index 8fc8759695..e66986380d 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -24,10 +24,11 @@ #include #include +#include namespace openspace::luascriptfunctions { -int saveCurrentSettingsToProfile(lua_State* L) { +int saveSettingsToProfile(lua_State* L) { if (!global::configuration.usingProfile) { return luaL_error( L, @@ -38,11 +39,11 @@ int saveCurrentSettingsToProfile(lua_State* L) { const int n = ghoul::lua::checkArgumentsAndThrow( L, - { 0, 1 }, - "lua::saveCurrentSettingsToProfile" + { 0, 2 }, + "lua::saveSettingsToProfile" ); - using ghoul::lua::luaTypeToString; + LINFOC("1", ghoul::lua::stackInformation(L)); std::string saveFilePath; if (n == 0) { @@ -61,22 +62,78 @@ int saveCurrentSettingsToProfile(lua_State* L) { utcTime->tm_min, utcTime->tm_sec ); - saveFilePath = fmt::format("{}_{}.{}", f.fullBaseName(), time, f.fileExtension()); + std::string newFile = fmt::format( + "{}_{}.{}", + f.fullBaseName(), time, f.fileExtension() + ); + std::filesystem::copy(global::configuration.profile, newFile); + saveFilePath = global::configuration.profile; } else { - saveFilePath = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + saveFilePath = ghoul::lua::value(L, 1); + LINFOC("2", ghoul::lua::stackInformation(L)); if (saveFilePath.empty()) { return luaL_error(L, "save filepath string is empty"); } } - global::profile.saveCurrentSettingsToProfile(saveFilePath); + global::profile.saveCurrentSettingsToProfile(); + global::configuration.profile = saveFilePath; - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + if (saveFilePath.find('/') != std::string::npos) { + return luaL_error(L, "Profile filename must not contain path (/) elements"); + } + else if (saveFilePath.find(':') != std::string::npos) { + return luaL_error(L, "Profile filename must not contain path (:) elements"); + } + else if (saveFilePath.find('.') != std::string::npos) { + return luaL_error(L, "Only provide the filename to save without file extension"); + } + const std::string absFilename = absPath("${ASSETS}/" + saveFilePath + ".profile"); + + const bool overwrite = (n == 2) ? ghoul::lua::value< bool>(L, 2) : false; + LINFOC("3", ghoul::lua::stackInformation(L)); + + if (FileSys.fileExists(absFilename) && !overwrite) { + return luaL_error( + L, + fmt::format( + "Unable to save profile '{}'. File of same name already exists.", + absFilename.c_str() + ).c_str() + ); + } + + std::ofstream outFile; + // @TODO (abock, 2020-06-15) Replace with non-throwing stream + try { + outFile.open(absFilename, std::ofstream::out); + } + catch (const std::ofstream::failure& e) { + return luaL_error( + L, + fmt::format( + "Exception opening profile file for write: {} ({})", absFilename, e.what() + ).c_str() + ); + } + + try { + outFile << serialize(global::profile.profile); + } + catch (const std::ofstream::failure& e) { + return luaL_error( + L, + fmt::format( + "Data write error to file: {} ({})", + absFilename, e.what() + ).c_str() + ); + } + + outFile.close(); + + lua_settop(L, 0); return 0; } From a8c5d3bb914bb89cc2209ee758cffc889eae8eb1 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 18:07:04 +0200 Subject: [PATCH 30/61] More cleanup --- include/openspace/scene/profile.h | 31 ------ src/scene/profile.cpp | 171 +++++++++++------------------- src/scene/profile_lua.inl | 2 +- 3 files changed, 65 insertions(+), 139 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index e42705d56f..2bf8ede6fd 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -165,44 +165,13 @@ public: static scripting::LuaLibrary luaLibrary(); ProfileData profile; - -protected: - std::string _profileBaseDirectory = "${ASSETS}"; - -private: - struct AllAssetDetails { - std::vector base; - std::vector changed; - }; - virtual std::string initialProfile() const; - virtual std::string profileBaseDirectory() const; - virtual std::vector assetEvents() const; - - std::vector modifyAssetsToReflectChanges(ProfileData& ps); - void parseAssetFileLines(std::vector& results, ProfileData& ps); - - void modifyPropertiesToReflectChanges(ProfileData& ps); - virtual std::vector changedProperties(); - virtual interaction::NavigationHandler::NavigationState currentCameraState() const; }; - std::string serialize(const ProfileData& ps); ProfileData deserialize(const std::vector& content); std::string convertToSceneFile(const ProfileData& ps); -/** - * Reads in a .profile file, converts it to scene/asset equivalent syntax, and - * writes the result to the specified output path. - * \param inProfilePath The .profile file to be converted - * \param outFilePath The output file path that will be written with the converted - * contents (in an .asset file) - */ -void convertProfileToScene(const std::string& inProfilePath, - const std::string& outFilePath); - - } // namespace openspace #endif // __OPENSPACE_CORE___PROFILE___H__ diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 4faa969b58..58d3713629 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -431,6 +431,43 @@ namespace { [[ nodiscard ]] std::string parseMarkNodes(const std::string& line, int) { return line; } + + std::vector modifyAssetsToReflectChanges(ProfileData& ps) { + std::vector results; + for (ProfileData::Asset& a : ps.assets) { + Profile::AssetEvent assetEvent; + assetEvent.name = a.path; + assetEvent.eventType = [](ProfileData::Asset::Type type) { + switch (type) { + case ProfileData::Asset::Type::Request: + return Profile::AssetEventType::Request; + case ProfileData::Asset::Type::Require: + return Profile::AssetEventType::Require; + default: throw ghoul::MissingCaseException(); + } + }(a.type); + results.push_back(assetEvent); + } + struct { + std::vector base; + std::vector changed; + } assetDetails; + + assetDetails.base = results; + assetDetails.changed = global::openSpaceEngine.assetEvents(); + + for (unsigned int i = 0; i < assetDetails.changed.size(); i++) { + Profile::AssetEvent event = assetDetails.changed[i]; + + if (event.eventType == Profile::AssetEventType::Add) { + handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); + } + else if (event.eventType == Profile::AssetEventType::Remove) { + assetDetails.base.push_back({ event.name, Profile::AssetEventType::Remove }); + } + } + return assetDetails.base; + } } // namespace Profile::Profile(const std::string& filename) { @@ -440,18 +477,43 @@ Profile::Profile(const std::string& filename) { void Profile::saveCurrentSettingsToProfile() { profile.version = ProfileData::CurrentVersion; + // + // Update assets + // std::vector ass = modifyAssetsToReflectChanges(profile); addAssetsToProfileFile(profile, ass); - modifyPropertiesToReflectChanges(profile); + // + // Update properties + // + std::vector nodes = + global::renderEngine.scene()->allSceneGraphNodes(); + std::vector changedProps; + + for (SceneGraphNode* n : nodes) { + checkForChangedProps(changedProps, n); + } + std::vector formattedLines; + + for (properties::Property* prop : changedProps) { + ProfileData::Property p; + p.setType = ProfileData::Property::SetType::SetPropertyValueSingle; + p.name = recurseForFullName(prop->owner()) + prop->identifier(); + p.value = prop->getStringValue(); + profile.properties.push_back(std::move(p)); + } + + // // add current time to profile file + // ProfileData::Time time; time.time = global::timeManager.time().ISO8601(); time.type = ProfileData::Time::Type::Absolute; profile.time = std::move(time); // Camera - interaction::NavigationHandler::NavigationState nav = currentCameraState(); + interaction::NavigationHandler::NavigationState nav = + global::navigationHandler.navigationState(); ProfileData::CameraNavState camera; camera.anchor = nav.anchor; @@ -472,111 +534,6 @@ void Profile::saveCurrentSettingsToProfile() { profile.camera = std::move(camera); } -std::string Profile::initialProfile() const { - return global::configuration.profile; -} - -std::vector Profile::assetEvents() const { - return global::openSpaceEngine.assetEvents(); -} - -std::string Profile::profileBaseDirectory() const { - return _profileBaseDirectory; -} - -std::vector Profile::modifyAssetsToReflectChanges(ProfileData& ps) { - std::vector a; - parseAssetFileLines(a, ps); - AllAssetDetails assetDetails; - - assetDetails.base = a; - assetDetails.changed = assetEvents(); - - for (unsigned int i = 0; i < assetDetails.changed.size(); i++) { - AssetEvent event = assetDetails.changed[i]; - - if (event.eventType == AssetEventType::Add) { - handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); - } - else if (event.eventType == AssetEventType::Remove) { - assetDetails.base.push_back({ event.name, Profile::AssetEventType::Remove }); - } - } - return assetDetails.base; -} - -void Profile::parseAssetFileLines(std::vector& results, ProfileData& ps) { - for (ProfileData::Asset& a : ps.assets) { - AssetEvent assetEvent; - assetEvent.name = a.path; - assetEvent.eventType = [](ProfileData::Asset::Type type) { - switch (type) { - case ProfileData::Asset::Type::Request: return AssetEventType::Request; - case ProfileData::Asset::Type::Require: return AssetEventType::Require; - default: throw ghoul::MissingCaseException(); - } - }(a.type); - results.push_back(assetEvent); - } -} - -void Profile::modifyPropertiesToReflectChanges(ProfileData& ps) { - std::vector changedProps = changedProperties(); - std::vector formattedLines; - - for (properties::Property* prop : changedProps) { - ProfileData::Property p; - p.setType = ProfileData::Property::SetType::SetPropertyValueSingle; - p.name = recurseForFullName(prop->owner()) + prop->identifier(); - p.value = prop->getStringValue(); - ps.properties.push_back(std::move(p)); - } -} - -std::vector Profile::changedProperties() { - ZoneScoped - - std::vector nodes = - global::renderEngine.scene()->allSceneGraphNodes(); - std::vector changedProps; - - for (SceneGraphNode* n : nodes) { - checkForChangedProps(changedProps, n); - } - return changedProps; -} - -interaction::NavigationHandler::NavigationState Profile::currentCameraState() const { - return global::navigationHandler.navigationState(); -} - -void convertProfileToScene(const std::string& inProfilePath, - const std::string& outFilePath) -{ - ZoneScoped - - ProfileData ps = readFromFile(inProfilePath); - - std::ofstream outFile; - try { - outFile.open(outFilePath, std::ofstream::out); - } - catch (const std::ofstream::failure& e) { - LERROR(fmt::format( - "Exception opening scene file for write: {} ({})", outFilePath, e.what() - )); - } - - try { - outFile << openspace::convertToSceneFile(ps); - } - catch (const std::ofstream::failure& e) { - LERROR(fmt::format( - "Data write error to scene file: {} ({})", outFilePath, e.what() - )); - } -} - scripting::LuaLibrary Profile::luaLibrary() { return { "", diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index e66986380d..99dae7b938 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -91,7 +91,7 @@ int saveSettingsToProfile(lua_State* L) { } const std::string absFilename = absPath("${ASSETS}/" + saveFilePath + ".profile"); - const bool overwrite = (n == 2) ? ghoul::lua::value< bool>(L, 2) : false; + const bool overwrite = (n == 2) ? ghoul::lua::value(L, 2) : false; LINFOC("3", ghoul::lua::stackInformation(L)); if (FileSys.fileExists(absFilename) && !overwrite) { From b59b6cc2d2651ccc8294e0e40f782cb461f4f761 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 19:40:16 +0200 Subject: [PATCH 31/61] Yet more cleanup --- include/openspace/scene/profile.h | 10 +--- src/engine/openspaceengine.cpp | 21 ++++++- src/scene/profile.cpp | 99 +++++++++++-------------------- src/scene/profile_lua.inl | 2 +- 4 files changed, 59 insertions(+), 73 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 2bf8ede6fd..84503c571f 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -147,9 +147,10 @@ public: }; Profile() = default; - explicit Profile(const std::string& filename); + Profile(const std::vector& content); + std::string serialize() const; - virtual ~Profile() {}; + std::string convertToScene() const; /** * Saves all current settings, starting from the profile that was loaded at startup, @@ -167,11 +168,6 @@ public: ProfileData profile; }; -std::string serialize(const ProfileData& ps); -ProfileData deserialize(const std::vector& content); - -std::string convertToSceneFile(const ProfileData& ps); - } // namespace openspace #endif // __OPENSPACE_CORE___PROFILE___H__ diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 49635dcade..60571871f6 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -313,12 +313,29 @@ void OpenSpaceEngine::initialize() { } else { // Load the profile - global::profile = Profile(inputProfile); + std::ifstream inFile; + try { + inFile.open(inputProfile, std::ifstream::in); + } + catch (const std::ifstream::failure& e) { + throw ghoul::RuntimeError(fmt::format( + "Exception opening profile file for read: {} ({})", + inputProfile, e.what()) + ); + } + + std::vector content; + std::string line; + while (std::getline(inFile, line)) { + content.push_back(std::move(line)); + } + + global::profile = Profile(content); // Then save the profile to a scene so that we can load it with the // existing infrastructure std::ofstream scene(outputAsset); - std::string sceneContent = convertToSceneFile(global::profile.profile); + std::string sceneContent = global::profile.convertToScene(); scene << sceneContent; // Set asset name to that of the profile because a new scene file will be diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 58d3713629..56d74e5dfc 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -170,26 +170,6 @@ namespace { } } - ProfileData readFromFile(const std::string& filename) { - std::ifstream inFile; - try { - inFile.open(filename, std::ifstream::in); - } - catch (const std::ifstream::failure& e) { - throw ghoul::RuntimeError(fmt::format( - "Exception opening profile file for read: {} ({})", filename, e.what()) - ); - } - - std::vector content; - std::string line; - while (std::getline(inFile, line)) { - content.push_back(std::move(line)); - } - - return deserialize(content); - } - enum class Section { None, Version, @@ -470,10 +450,6 @@ namespace { } } // namespace -Profile::Profile(const std::string& filename) { - profile = readFromFile(filename); -} - void Profile::saveCurrentSettingsToProfile() { profile.version = ProfileData::CurrentVersion; @@ -557,17 +533,17 @@ scripting::LuaLibrary Profile::luaLibrary() { }; } -std::string serialize(const ProfileData& ps) { +std::string Profile::serialize() const { std::string output; output += fmt::format("{}\n", headerVersion); output += fmt::format( "{}.{}.{}\n", - ps.version.major, ps.version.minor, ps.version.patch + profile.version.major, profile.version.minor, profile.version.patch ); - if (!ps.modules.empty()) { + if (!profile.modules.empty()) { output += fmt::format("\n{}\n", headerModule); - for (const ProfileData::Module& m : ps.modules) { + for (const ProfileData::Module& m : profile.modules) { output += fmt::format( "{}\t{}\t{}\n", m.name, m.loadedInstruction, m.notLoadedInstruction @@ -575,9 +551,9 @@ std::string serialize(const ProfileData& ps) { } } - if (!ps.assets.empty()) { + if (!profile.assets.empty()) { output += fmt::format("\n{}\n", headerAsset); - for (const ProfileData::Asset& a : ps.assets) { + for (const ProfileData::Asset& a : profile.assets) { const std::string type = [](ProfileData::Asset::Type t) { switch (t) { case ProfileData::Asset::Type::Require: return "require"; @@ -589,9 +565,9 @@ std::string serialize(const ProfileData& ps) { } } - if (!ps.properties.empty()) { + if (!profile.properties.empty()) { output += fmt::format("\n{}\n", headerProperty); - for (const ProfileData::Property& p : ps.properties) { + for (const ProfileData::Property& p : profile.properties) { const std::string type = [](ProfileData::Property::SetType t) { switch (t) { case ProfileData::Property::SetType::SetPropertyValue: @@ -606,9 +582,9 @@ std::string serialize(const ProfileData& ps) { } } - if (!ps.keybindings.empty()) { + if (!profile.keybindings.empty()) { output += fmt::format("\n{}\n", headerKeybinding); - for (const ProfileData::Keybinding& k : ps.keybindings) { + for (const ProfileData::Keybinding& k : profile.keybindings) { const std::string local = k.isLocal ? "true" : "false"; output += fmt::format( "{}\t{}\t{}\t{}\t{}\t{}\n", @@ -625,8 +601,8 @@ std::string serialize(const ProfileData& ps) { case ProfileData::Time::Type::Relative: return "relative"; default: throw ghoul::MissingCaseException(); } - }(ps.time.type); - output += fmt::format("{}\t{}\n", type, ps.time.time); + }(profile.time.type); + output += fmt::format("{}\t{}\n", type, profile.time.time); } output += fmt::format("\n{}\n", headerCamera); @@ -653,12 +629,12 @@ std::string serialize(const ProfileData& ps) { ); } }, - ps.camera + profile.camera ); - if (!ps.markNodes.empty()) { + if (!profile.markNodes.empty()) { output += fmt::format("\n{}\n", headerMarkNodes); - for (const std::string& n : ps.markNodes) { + for (const std::string& n : profile.markNodes) { output += fmt::format("{}\n", n); } } @@ -666,9 +642,7 @@ std::string serialize(const ProfileData& ps) { return output; } -ProfileData deserialize(const std::vector& content) { - ProfileData result; - +Profile::Profile(const std::vector& content) { Section currentSection = Section::None; for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { std::string line = content[lineNum - 1]; @@ -682,59 +656,57 @@ ProfileData deserialize(const std::vector& content) { currentSection = parseSection(line, lineNum); break; case Section::Version: - result.version = parseVersion(line, lineNum); + profile.version = parseVersion(line, lineNum); break; case Section::Module: { ProfileData::Module m = parseModule(line, lineNum); - result.modules.push_back(std::move(m)); + profile.modules.push_back(std::move(m)); break; } case Section::Asset: { ProfileData::Asset a = parseAsset(line, lineNum); - result.assets.push_back(std::move(a)); + profile.assets.push_back(std::move(a)); break; } case Section::Property: { ProfileData::Property p = parseProperty(line, lineNum); - result.properties.push_back(std::move(p)); + profile.properties.push_back(std::move(p)); break; } case Section::Keybinding: { ProfileData::Keybinding kb = parseKeybinding(line, lineNum); - result.keybindings.push_back(std::move(kb)); + profile.keybindings.push_back(std::move(kb)); break; } case Section::Time: - result.time = parseTime(line, lineNum); + profile.time = parseTime(line, lineNum); break; case Section::Camera: - result.camera = parseCamera(line, lineNum); + profile.camera = parseCamera(line, lineNum); break; case Section::MarkNodes: { std::string m = parseMarkNodes(line, lineNum); - result.markNodes.push_back(std::move(m)); + profile.markNodes.push_back(std::move(m)); break; } default: throw ghoul::MissingCaseException(); } } - - return result; } -std::string convertToSceneFile(const ProfileData& ps) { +std::string Profile::convertToScene() const { ZoneScoped std::string output; // Modules - for (const ProfileData::Module& m : ps.modules) { + for (const ProfileData::Module& m : profile.modules) { output += fmt::format( "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", m.name, m.loadedInstruction, m.notLoadedInstruction @@ -742,7 +714,7 @@ std::string convertToSceneFile(const ProfileData& ps) { } // Assets - for (const ProfileData::Asset& a : ps.assets) { + for (const ProfileData::Asset& a : profile.assets) { if (!a.name.empty()) { output += fmt::format("local {} = ", a.name); } @@ -759,7 +731,7 @@ std::string convertToSceneFile(const ProfileData& ps) { output += "asset.onInitialize(function()\n"; // Keybindings - for (const ProfileData::Keybinding& k : ps.keybindings) { + for (const ProfileData::Keybinding& k : profile.keybindings) { const std::string name = k.name.empty() ? k.key : k.name; output += fmt::format( k.isLocal ? @@ -770,14 +742,15 @@ std::string convertToSceneFile(const ProfileData& ps) { } // Time - switch (ps.time.type) { + switch (profile.time.type) { case ProfileData::Time::Type::Absolute: - output += fmt::format("openspace.time.setTime(\"{}\")\n", ps.time.time); + output += fmt::format("openspace.time.setTime(\"{}\")\n", profile.time.time); break; case ProfileData::Time::Type::Relative: output += "local now = openspace.time.currentWallTime();\n"; output += fmt::format( - "local prev = openspace.time.advancedTime(now, \"{}\");\n", ps.time.time + "local prev = openspace.time.advancedTime(now, \"{}\");\n", + profile.time.time ); output += "openspace.time.setTime(prev);\n"; break; @@ -788,14 +761,14 @@ std::string convertToSceneFile(const ProfileData& ps) { // Mark Nodes { std::string nodes; - for (const std::string& n : ps.markNodes) { + for (const std::string& n : profile.markNodes) { nodes += fmt::format("[[ {} ]],", n); } output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes); } // Properties - for (const ProfileData::Property& p : ps.properties) { + for (const ProfileData::Property& p : profile.properties) { switch (p.setType) { case ProfileData::Property::SetType::SetPropertyValue: output += fmt::format( @@ -855,8 +828,8 @@ std::string convertToSceneFile(const ProfileData& ps) { } } }, - ps.camera - ); + profile.camera + ); output += "end)\n"; return output; diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index 99dae7b938..03e13a0b0b 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -119,7 +119,7 @@ int saveSettingsToProfile(lua_State* L) { } try { - outFile << serialize(global::profile.profile); + outFile << global::profile.serialize(); } catch (const std::ofstream::failure& e) { return luaL_error( From 12daf94cb5b4f970b1bcc9c35ed39003b4ee383e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 22:17:12 +0200 Subject: [PATCH 32/61] Make time specification in profiles optional Provide a nicer error message when forgetting version and camera parameters --- include/openspace/scene/profile.h | 5 +++-- src/scene/profile.cpp | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 84503c571f..d82552a545 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -98,10 +98,11 @@ struct ProfileData { struct Time { enum class Type { Absolute, - Relative + Relative, + None }; - Type type; + Type type = Type::None; std::string time; }; Time time; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 56d74e5dfc..97e9830dd3 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -644,6 +644,9 @@ std::string Profile::serialize() const { Profile::Profile(const std::vector& content) { Section currentSection = Section::None; + bool foundVersion = false; + bool foundCamera = false; + for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { std::string line = content[lineNum - 1]; if (std::all_of(line.begin(), line.end(), ::isspace)) { @@ -657,6 +660,7 @@ Profile::Profile(const std::vector& content) { break; case Section::Version: profile.version = parseVersion(line, lineNum); + foundVersion = true; break; case Section::Module: { @@ -687,6 +691,7 @@ Profile::Profile(const std::vector& content) { break; case Section::Camera: profile.camera = parseCamera(line, lineNum); + foundCamera = true; break; case Section::MarkNodes: { @@ -698,6 +703,18 @@ Profile::Profile(const std::vector& content) { throw ghoul::MissingCaseException(); } } + + if (!foundVersion) { + throw ghoul::RuntimeError( + "Did not find Version information when loading profile" + ); + } + + if (!foundCamera) { + throw ghoul::RuntimeError( + "Did not find Camera information when loading profile" + ); + } } std::string Profile::convertToScene() const { @@ -754,6 +771,9 @@ std::string Profile::convertToScene() const { ); output += "openspace.time.setTime(prev);\n"; break; + case ProfileData::Time::Type::None: + output += "openspace.time.setTime(openspace.time.currentWallTime());\n"; + break; default: throw ghoul::MissingCaseException(); } From 4c9555425b8bc8902f8e8e51fc8b60adf5eafd85 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 18 Jun 2020 23:09:26 +0200 Subject: [PATCH 33/61] Cleanup of asset handling and move more functionality to the Profile --- include/openspace/engine/openspaceengine.h | 3 - include/openspace/scene/assetloader.h | 15 --- include/openspace/scene/assetmanager.h | 3 - include/openspace/scene/profile.h | 13 +++ src/documentation/core_registration.cpp | 1 + src/engine/openspaceengine.cpp | 22 ++-- src/scene/assetloader.cpp | 15 --- src/scene/assetmanager.cpp | 12 +-- src/scene/profile.cpp | 115 ++++++++++----------- src/scene/profile_lua.inl | 4 - 10 files changed, 77 insertions(+), 126 deletions(-) diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 07838dc8c0..967629e94b 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -26,7 +26,6 @@ #define __OPENSPACE_CORE___OPENSPACEENGINE___H__ #include -#include #include #include #include @@ -77,8 +76,6 @@ public: const glm::mat4& projectionMatrix); void drawOverlays(); void postDraw(); - std::vector assetEvents(); - void resetAssetChangeTracking(); void resetPropertyChangeFlags(); void keyboardCallback(Key key, KeyModifier mod, KeyAction action); void charCallback(unsigned int codepoint, KeyModifier modifier); diff --git a/include/openspace/scene/assetloader.h b/include/openspace/scene/assetloader.h index affc5e09b7..4d99b176f8 100644 --- a/include/openspace/scene/assetloader.h +++ b/include/openspace/scene/assetloader.h @@ -26,7 +26,6 @@ #define __OPENSPACE_CORE___ASSETLOADER___H__ #include -#include #include #include #include @@ -164,21 +163,9 @@ public: */ void assetUnrequested(Asset* parent, std::shared_ptr child); - /** - * Retrieve a reference to vector list of all assets events, including require, - * request, and remove - */ - const std::vector& assetEvents() const; - - /** - * Clear lists of all assets that have been either requested, required, or removed - */ - void resetAssetEvents(); - private: std::shared_ptr request(const std::string& identifier); void unrequest(const std::string& identifier); - void addToProfileTracking(std::string asset, Profile::AssetEventType type); void setUpAssetLuaTable(Asset* asset); void tearDownAssetLuaTable(Asset* asset); @@ -233,8 +220,6 @@ private: _onDependencyDeinitializationFunctionRefs; int _assetsTableRef = 0; - - std::vector _profileAssets; }; } // namespace openspace diff --git a/include/openspace/scene/assetmanager.h b/include/openspace/scene/assetmanager.h index 455758d285..8ed157d56d 100644 --- a/include/openspace/scene/assetmanager.h +++ b/include/openspace/scene/assetmanager.h @@ -26,7 +26,6 @@ #define __OPENSPACE_CORE___ASSETMANAGER___H__ #include -#include #include #include @@ -69,8 +68,6 @@ public: void assetUnrequested(Asset* parent, std::shared_ptr child) override; bool update(); - const std::vector& assetEvents() const; - void resetAssetEvents(); scripting::LuaLibrary luaLibrary(); private: diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index d82552a545..c552e1819f 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -159,6 +159,16 @@ public: */ void saveCurrentSettingsToProfile(); + /// If the value passed to this function is 'true', the addAsset and removeAsset + /// functions will be no-ops instead + void setIgnoreUpdates(bool ignoreUpdates); + + /// Adds a new asset and checks for duplicates + void addAsset(const std::string& path); + + /// Removes an asset + void removeAsset(const std::string& path); + /** * Returns the Lua library that contains all Lua functions available to provide * profile functionality. @@ -167,6 +177,9 @@ public: static scripting::LuaLibrary luaLibrary(); ProfileData profile; + +private: + bool _ignoreUpdates = false; }; } // namespace openspace diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 3b44fae6fb..fe894136f8 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 60571871f6..71891051bf 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1073,7 +1073,10 @@ void OpenSpaceEngine::preSynchronization() { if (_hasScheduledAssetLoading) { LINFO(fmt::format("Loading asset: {}", _scheduledAssetPathToLoad)); + global::profile.setIgnoreUpdates(true); loadSingleAsset(_scheduledAssetPathToLoad); + global::profile.setIgnoreUpdates(false); + resetPropertyChangeFlagsOfSubowners(&global::rootPropertyOwner); _hasScheduledAssetLoading = false; _scheduledAssetPathToLoad.clear(); } @@ -1290,38 +1293,27 @@ void OpenSpaceEngine::postDraw() { if (_isFirstRenderingFirstFrame) { global::windowDelegate.setSynchronization(true); resetPropertyChangeFlags(); - resetAssetChangeTracking(); _isFirstRenderingFirstFrame = false; } LTRACE("OpenSpaceEngine::postDraw(end)"); } -void OpenSpaceEngine::resetAssetChangeTracking() { - global::openSpaceEngine._assetManager->resetAssetEvents(); -} - -std::vector OpenSpaceEngine::assetEvents() { - return global::openSpaceEngine._assetManager->assetEvents(); -} - void OpenSpaceEngine::resetPropertyChangeFlags() { ZoneScoped std::vector nodes = global::renderEngine.scene()->allSceneGraphNodes(); - for (auto n : nodes) { + for (SceneGraphNode* n : nodes) { resetPropertyChangeFlagsOfSubowners(n); } } -void OpenSpaceEngine::resetPropertyChangeFlagsOfSubowners( - openspace::properties::PropertyOwner* po) -{ - for (auto subOwner : po->propertySubOwners()) { +void OpenSpaceEngine::resetPropertyChangeFlagsOfSubowners(properties::PropertyOwner* po) { + for (properties::PropertyOwner* subOwner : po->propertySubOwners()) { resetPropertyChangeFlagsOfSubowners(subOwner); } - for (auto p : po->properties()) { + for (properties::Property* p : po->properties()) { p->resetToUnchanged(); } } diff --git a/src/scene/assetloader.cpp b/src/scene/assetloader.cpp index 059cef1550..9642504ccf 100644 --- a/src/scene/assetloader.cpp +++ b/src/scene/assetloader.cpp @@ -480,11 +480,6 @@ std::shared_ptr AssetLoader::request(const std::string& identifier) { return asset; } -void AssetLoader::addToProfileTracking(std::string asset, Profile::AssetEventType type) { - Profile::AssetEvent pa = { std::move(asset), type }; - _profileAssets.push_back(pa); -} - void AssetLoader::unrequest(const std::string& identifier) { std::shared_ptr asset = has(identifier); Asset* parent = _currentAsset; @@ -503,14 +498,12 @@ ghoul::filesystem::Directory AssetLoader::currentDirectory() const { std::shared_ptr AssetLoader::add(const std::string& identifier) { setCurrentAsset(_rootAsset.get()); - addToProfileTracking(identifier, Profile::AssetEventType::Add); return request(identifier); } void AssetLoader::remove(const std::string& identifier) { setCurrentAsset(_rootAsset.get()); unrequest(identifier); - addToProfileTracking(identifier, Profile::AssetEventType::Remove); } std::shared_ptr AssetLoader::has(const std::string& identifier) const { @@ -834,12 +827,4 @@ void AssetLoader::assetUnrequested(Asset* parent, std::shared_ptr child) } } -const std::vector& AssetLoader::assetEvents() const { - return _profileAssets; -} - -void AssetLoader::resetAssetEvents() { - _profileAssets.clear(); -} - } // namespace openspace diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index 3dbbfa35b1..06282fa109 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -24,7 +24,9 @@ #include +#include #include +#include #include #include #include @@ -60,6 +62,7 @@ bool AssetManager::update() { const bool add = c.second; if (add) { _assetLoader.add(path); + global::profile.addAsset(path); } } // Remove assets @@ -68,6 +71,7 @@ bool AssetManager::update() { const bool remove = !c.second; if (remove && _assetLoader.has(path)) { _assetLoader.remove(path); + global::profile.removeAsset(path); } } _pendingStateChangeCommands.clear(); @@ -118,14 +122,6 @@ Asset& AssetManager::rootAsset() { return _assetLoader.rootAsset(); } -const std::vector& AssetManager::assetEvents() const { - return _assetLoader.assetEvents(); -} - -void AssetManager::resetAssetEvents() { - _assetLoader.resetAssetEvents(); -} - scripting::LuaLibrary AssetManager::luaLibrary() { return { "asset", diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 97e9830dd3..089ad30795 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -128,20 +128,6 @@ namespace { } } - void addAssetsToProfileFile(ProfileData& ps, - const std::vector& allAssets) - { - ps.assets.clear(); - for (Profile::AssetEvent a : allAssets) { - if (a.eventType != Profile::AssetEventType::Ignore) { - ProfileData::Asset asset; - asset.path = a.name; - asset.type = ProfileData::Asset::Type::Require; - ps.assets.push_back(std::move(asset)); - } - } - } - std::string recurseForFullName(properties::PropertyOwner* po) { if (po == nullptr) { return ""; @@ -411,64 +397,21 @@ namespace { [[ nodiscard ]] std::string parseMarkNodes(const std::string& line, int) { return line; } - - std::vector modifyAssetsToReflectChanges(ProfileData& ps) { - std::vector results; - for (ProfileData::Asset& a : ps.assets) { - Profile::AssetEvent assetEvent; - assetEvent.name = a.path; - assetEvent.eventType = [](ProfileData::Asset::Type type) { - switch (type) { - case ProfileData::Asset::Type::Request: - return Profile::AssetEventType::Request; - case ProfileData::Asset::Type::Require: - return Profile::AssetEventType::Require; - default: throw ghoul::MissingCaseException(); - } - }(a.type); - results.push_back(assetEvent); - } - struct { - std::vector base; - std::vector changed; - } assetDetails; - - assetDetails.base = results; - assetDetails.changed = global::openSpaceEngine.assetEvents(); - - for (unsigned int i = 0; i < assetDetails.changed.size(); i++) { - Profile::AssetEvent event = assetDetails.changed[i]; - - if (event.eventType == Profile::AssetEventType::Add) { - handleChangedAdd(assetDetails.base, i, assetDetails.changed, event.name); - } - else if (event.eventType == Profile::AssetEventType::Remove) { - assetDetails.base.push_back({ event.name, Profile::AssetEventType::Remove }); - } - } - return assetDetails.base; - } } // namespace void Profile::saveCurrentSettingsToProfile() { profile.version = ProfileData::CurrentVersion; - // - // Update assets - // - std::vector ass = modifyAssetsToReflectChanges(profile); - addAssetsToProfileFile(profile, ass); - // // Update properties // - std::vector nodes = - global::renderEngine.scene()->allSceneGraphNodes(); + //std::vector nodes = + // global::renderEngine.scene()->allSceneGraphNodes(); std::vector changedProps; - for (SceneGraphNode* n : nodes) { - checkForChangedProps(changedProps, n); - } + //for (SceneGraphNode* n : nodes) { + checkForChangedProps(changedProps, &global::rootPropertyOwner); + //} std::vector formattedLines; for (properties::Property* prop : changedProps) { @@ -510,6 +453,52 @@ void Profile::saveCurrentSettingsToProfile() { profile.camera = std::move(camera); } +void Profile::setIgnoreUpdates(bool ignoreUpdates) { + _ignoreUpdates = ignoreUpdates; +} + +void Profile::addAsset(const std::string& path) { + if (_ignoreUpdates) { + return; + } + + const auto it = std::find_if( + profile.assets.begin(), + profile.assets.end(), + [path](const ProfileData::Asset& a) { return a.path == path; } + ); + + if (it != profile.assets.end()) { + // Asset already existed, so nothing to do here + return; + } + + ProfileData::Asset a; + a.path = path; + a.type = ProfileData::Asset::Type::Require; + profile.assets.push_back(std::move(a)); +} + +void Profile::removeAsset(const std::string& path) { + if (_ignoreUpdates) { + return; + } + + const auto it = std::find_if( + profile.assets.begin(), + profile.assets.end(), + [path](const ProfileData::Asset& a) { return a.path == path; } + ); + + if (it == profile.assets.end()) { + throw ghoul::RuntimeError(fmt::format( + "Tried to remove non-existing asset '{}'", path + )); + } + + profile.assets.erase(it); +} + scripting::LuaLibrary Profile::luaLibrary() { return { "", @@ -561,7 +550,7 @@ std::string Profile::serialize() const { default: throw ghoul::MissingCaseException(); } }(a.type); - output += fmt::format("{}\t{}\n", a.path, type); + output += fmt::format("{}\t{}\t{}\n", a.path, type, a.name); } } diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index 03e13a0b0b..3f2f6c6ff2 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -43,8 +43,6 @@ int saveSettingsToProfile(lua_State* L) { "lua::saveSettingsToProfile" ); - LINFOC("1", ghoul::lua::stackInformation(L)); - std::string saveFilePath; if (n == 0) { const ghoul::filesystem::File f = global::configuration.profile; @@ -71,7 +69,6 @@ int saveSettingsToProfile(lua_State* L) { } else { saveFilePath = ghoul::lua::value(L, 1); - LINFOC("2", ghoul::lua::stackInformation(L)); if (saveFilePath.empty()) { return luaL_error(L, "save filepath string is empty"); } @@ -92,7 +89,6 @@ int saveSettingsToProfile(lua_State* L) { const std::string absFilename = absPath("${ASSETS}/" + saveFilePath + ".profile"); const bool overwrite = (n == 2) ? ghoul::lua::value(L, 2) : false; - LINFOC("3", ghoul::lua::stackInformation(L)); if (FileSys.fileExists(absFilename) && !overwrite) { return luaL_error( From 604935b64095b0dfca89207a30582ccccd97398d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 19 Jun 2020 00:09:43 +0200 Subject: [PATCH 34/61] Move profile information from ProfileData into Profile class Temporarily comment out unit tests --- include/openspace/scene/profile.h | 35 +- src/scene/profile.cpp | 243 +++--- tests/profile/test_common.cpp | 182 ++-- tests/profile/test_common.h | 1279 ++++++++++++++-------------- tests/profile/test_profile.cpp | 610 ++++++------- tests/profile/test_profilefile.cpp | 352 ++++---- 6 files changed, 1360 insertions(+), 1341 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index c552e1819f..4cf257e609 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -44,23 +44,19 @@ namespace openspace { namespace documentation { struct Documentation; } namespace scripting { struct LuaLibrary; } -struct ProfileData { +class Profile { +public: // Version struct Version { int major = 0; int minor = 0; int patch = 0; }; - static constexpr const Version CurrentVersion = Version{ 1, 0, 0 }; - Version version = CurrentVersion; - struct Module { std::string name; std::string loadedInstruction; std::string notLoadedInstruction; }; - std::vector modules; - struct Asset { enum class Type { Require, @@ -71,8 +67,6 @@ struct ProfileData { Type type; std::string name; }; - std::vector assets; - struct Property { enum class SetType { SetPropertyValue, @@ -83,8 +77,6 @@ struct ProfileData { std::string name; std::string value; }; - std::vector properties; - struct Keybinding { std::string key; // @TODO (abock, 2020-06-16) change to key+action std::string documentation; @@ -93,8 +85,6 @@ struct ProfileData { bool isLocal; std::string script; }; - std::vector keybindings; - struct Time { enum class Type { Absolute, @@ -105,8 +95,6 @@ struct ProfileData { Type type = Type::None; std::string time; }; - Time time; - struct CameraNavState { static constexpr const char* Type = "setNavigationState"; @@ -127,13 +115,7 @@ struct ProfileData { std::optional altitude; }; using CameraType = std::variant; - CameraType camera; - std::vector markNodes; -}; - -class Profile { -public: enum class AssetEventType { Add, Require, @@ -176,9 +158,18 @@ public: */ static scripting::LuaLibrary luaLibrary(); - ProfileData profile; - private: + static constexpr const Version CurrentVersion = Version{ 1, 0, 0 }; + Version version = CurrentVersion; + std::vector modules; + std::vector assets; + std::vector properties; + std::vector keybindings; + Time time; + CameraType camera; + std::vector markNodes; + + bool _ignoreUpdates = false; }; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 089ad30795..88b6616fce 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -189,7 +189,7 @@ namespace { ); } - [[ nodiscard ]] ProfileData::Version parseVersion(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Version parseVersion(const std::string& line, int lineNumber) { std::vector parts = ghoul::tokenizeString(line, '.'); if (parts.empty() || parts.size() > 3) { throw ProfileParsingError( @@ -198,7 +198,7 @@ namespace { ); } - ProfileData::Version version; + Profile::Version version; version.major = std::stoi(parts[0]); if (parts.size() > 1) { version.minor = std::stoi(parts[1]); @@ -209,7 +209,7 @@ namespace { return version; } - [[ nodiscard ]] ProfileData::Module parseModule(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Module parseModule(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { throw ProfileParsingError( @@ -217,14 +217,14 @@ namespace { fmt::format("Expected 3 fields in a Module entry, got {}", fields.size()) ); } - ProfileData::Module m; + Profile::Module m; m.name = fields[0]; m.loadedInstruction = fields[1]; m.notLoadedInstruction = fields[2]; return m; } - [[ nodiscard ]] ProfileData::Asset parseAsset(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Asset parseAsset(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { throw ProfileParsingError( @@ -233,14 +233,14 @@ namespace { ); } - ProfileData::Asset a; + Profile::Asset a; a.path = fields[0]; - a.type = [&](const std::string& type) -> ProfileData::Asset::Type { + a.type = [&](const std::string& type) -> Profile::Asset::Type { if (type == "require") { - return ProfileData::Asset::Type::Require; + return Profile::Asset::Type::Require; } if (type == "request") { - return ProfileData::Asset::Type::Request; + return Profile::Asset::Type::Request; } throw ProfileParsingError( lineNumber, @@ -251,7 +251,7 @@ namespace { return a; } - [[ nodiscard ]] ProfileData::Property parseProperty(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Property parseProperty(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 3) { throw ProfileParsingError( @@ -259,13 +259,13 @@ namespace { fmt::format("Expected 3 fields in Property entry, got {}", fields.size()) ); } - ProfileData::Property p; - p.setType = [&](const std::string& type) -> ProfileData::Property::SetType { + Profile::Property p; + p.setType = [&](const std::string& type) -> Profile::Property::SetType { if (type == "setPropertyValue") { - return ProfileData::Property::SetType::SetPropertyValue; + return Profile::Property::SetType::SetPropertyValue; } if (type == "setPropertyValueSingle") { - return ProfileData::Property::SetType::SetPropertyValueSingle; + return Profile::Property::SetType::SetPropertyValueSingle; } throw ProfileParsingError( lineNumber, @@ -281,7 +281,7 @@ namespace { return p; } - [[ nodiscard ]] ProfileData::Keybinding parseKeybinding(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Keybinding parseKeybinding(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 6) { throw ProfileParsingError( @@ -289,7 +289,7 @@ namespace { fmt::format("Expected 6 fields in Keybinding entry, got {}", fields.size()) ); } - ProfileData::Keybinding kb; + Profile::Keybinding kb; kb.key = fields[0]; kb.documentation = fields[1]; kb.name = fields[2]; @@ -310,7 +310,7 @@ namespace { return kb; } - [[ nodiscard ]] ProfileData::Time parseTime(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Time parseTime(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.size() != 2) { throw ProfileParsingError( @@ -318,13 +318,13 @@ namespace { fmt::format("Expected 2 fields in Time entry, got {}", fields.size()) ); } - ProfileData::Time time; - time.type = [&](const std::string& type) -> ProfileData::Time::Type { + Profile::Time time; + time.type = [&](const std::string& type) -> Profile::Time::Type { if (type == "absolute") { - return ProfileData::Time::Type::Absolute; + return Profile::Time::Type::Absolute; } if (type == "relative") { - return ProfileData::Time::Type::Relative; + return Profile::Time::Type::Relative; } throw ProfileParsingError( lineNumber, @@ -335,15 +335,15 @@ namespace { return time; } - [[ nodiscard ]] ProfileData::CameraType parseCamera(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::CameraType parseCamera(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); if (fields.empty()) { throw ProfileParsingError(lineNumber, "No values specified for Camera location"); } - ProfileData::CameraType camera = [&](const std::string& type) -> - std::variant + Profile::CameraType camera = [&](const std::string& type) -> + std::variant { - if (type == ProfileData::CameraNavState::Type) { + if (type == Profile::CameraNavState::Type) { if (fields.size() != 8) { throw ProfileParsingError( lineNumber, @@ -353,7 +353,7 @@ namespace { ); } - ProfileData::CameraNavState camera; + Profile::CameraNavState camera; camera.anchor = fields[1]; camera.aim = fields[2]; camera.referenceFrame = fields[3]; @@ -363,7 +363,7 @@ namespace { camera.pitch = fields[7]; return camera; } - if (type == ProfileData::CameraGoToGeo::Type) { + if (type == Profile::CameraGoToGeo::Type) { if (fields.size() != 5) { throw ProfileParsingError( lineNumber, @@ -373,7 +373,7 @@ namespace { ); } - ProfileData::CameraGoToGeo camera; + Profile::CameraGoToGeo camera; camera.anchor = fields[1]; camera.latitude = std::stod(fields[2]); camera.longitude = std::stod(fields[3]); @@ -400,7 +400,7 @@ namespace { } // namespace void Profile::saveCurrentSettingsToProfile() { - profile.version = ProfileData::CurrentVersion; + version = Profile::CurrentVersion; // // Update properties @@ -415,42 +415,42 @@ void Profile::saveCurrentSettingsToProfile() { std::vector formattedLines; for (properties::Property* prop : changedProps) { - ProfileData::Property p; - p.setType = ProfileData::Property::SetType::SetPropertyValueSingle; + Property p; + p.setType = Property::SetType::SetPropertyValueSingle; p.name = recurseForFullName(prop->owner()) + prop->identifier(); p.value = prop->getStringValue(); - profile.properties.push_back(std::move(p)); + properties.push_back(std::move(p)); } // // add current time to profile file // - ProfileData::Time time; - time.time = global::timeManager.time().ISO8601(); - time.type = ProfileData::Time::Type::Absolute; - profile.time = std::move(time); + Time t; + t.time = global::timeManager.time().ISO8601(); + t.type = Time::Type::Absolute; + time = std::move(t); // Camera interaction::NavigationHandler::NavigationState nav = global::navigationHandler.navigationState(); - ProfileData::CameraNavState camera; - camera.anchor = nav.anchor; - camera.aim = nav.aim; - camera.referenceFrame = nav.referenceFrame; - camera.position = fmt::format( + CameraNavState c; + c.anchor = nav.anchor; + c.aim = nav.aim; + c.referenceFrame = nav.referenceFrame; + c.position = fmt::format( "{},{},{}", nav.position.x, nav.position.y, nav.position.z ); if (nav.up.has_value()) { - camera.up = fmt::format( + c.up = fmt::format( "{},{},{}", nav.up->x, nav.up->y, nav.up->z ); } - camera.yaw = std::to_string(nav.yaw); - camera.pitch = std::to_string(nav.pitch); - profile.camera = std::move(camera); + c.yaw = std::to_string(nav.yaw); + c.pitch = std::to_string(nav.pitch); + camera = std::move(c); } void Profile::setIgnoreUpdates(bool ignoreUpdates) { @@ -463,20 +463,20 @@ void Profile::addAsset(const std::string& path) { } const auto it = std::find_if( - profile.assets.begin(), - profile.assets.end(), - [path](const ProfileData::Asset& a) { return a.path == path; } + assets.begin(), + assets.end(), + [path](const Asset& a) { return a.path == path; } ); - if (it != profile.assets.end()) { + if (it != assets.end()) { // Asset already existed, so nothing to do here return; } - ProfileData::Asset a; + Asset a; a.path = path; - a.type = ProfileData::Asset::Type::Require; - profile.assets.push_back(std::move(a)); + a.type = Asset::Type::Require; + assets.push_back(std::move(a)); } void Profile::removeAsset(const std::string& path) { @@ -485,18 +485,18 @@ void Profile::removeAsset(const std::string& path) { } const auto it = std::find_if( - profile.assets.begin(), - profile.assets.end(), - [path](const ProfileData::Asset& a) { return a.path == path; } + assets.begin(), + assets.end(), + [path](const Asset& a) { return a.path == path; } ); - if (it == profile.assets.end()) { + if (it == assets.end()) { throw ghoul::RuntimeError(fmt::format( "Tried to remove non-existing asset '{}'", path )); } - profile.assets.erase(it); + assets.erase(it); } scripting::LuaLibrary Profile::luaLibrary() { @@ -526,13 +526,12 @@ std::string Profile::serialize() const { std::string output; output += fmt::format("{}\n", headerVersion); output += fmt::format( - "{}.{}.{}\n", - profile.version.major, profile.version.minor, profile.version.patch + "{}.{}.{}\n", version.major, version.minor, version.patch ); - if (!profile.modules.empty()) { + if (!modules.empty()) { output += fmt::format("\n{}\n", headerModule); - for (const ProfileData::Module& m : profile.modules) { + for (const Module& m : modules) { output += fmt::format( "{}\t{}\t{}\n", m.name, m.loadedInstruction, m.notLoadedInstruction @@ -540,40 +539,40 @@ std::string Profile::serialize() const { } } - if (!profile.assets.empty()) { + if (!assets.empty()) { output += fmt::format("\n{}\n", headerAsset); - for (const ProfileData::Asset& a : profile.assets) { - const std::string type = [](ProfileData::Asset::Type t) { + for (const Asset& a : assets) { + const std::string type = [](Asset::Type t) { switch (t) { - case ProfileData::Asset::Type::Require: return "require"; - case ProfileData::Asset::Type::Request: return "request"; - default: throw ghoul::MissingCaseException(); + case Asset::Type::Require: return "require"; + case Asset::Type::Request: return "request"; + default: throw ghoul::MissingCaseException(); } }(a.type); output += fmt::format("{}\t{}\t{}\n", a.path, type, a.name); } } - if (!profile.properties.empty()) { + if (!properties.empty()) { output += fmt::format("\n{}\n", headerProperty); - for (const ProfileData::Property& p : profile.properties) { - const std::string type = [](ProfileData::Property::SetType t) { + for (const Property& p : properties) { + const std::string type = [](Property::SetType t) { switch (t) { - case ProfileData::Property::SetType::SetPropertyValue: - return "setPropertyValue"; - case ProfileData::Property::SetType::SetPropertyValueSingle: - return "setPropertyValueSingle"; - default: - throw ghoul::MissingCaseException(); + case Property::SetType::SetPropertyValue: + return "setPropertyValue"; + case Property::SetType::SetPropertyValueSingle: + return "setPropertyValueSingle"; + default: + throw ghoul::MissingCaseException(); } }(p.setType); output += fmt::format("{}\t{}\t{}\n", type, p.name, p.value); } } - if (!profile.keybindings.empty()) { + if (!keybindings.empty()) { output += fmt::format("\n{}\n", headerKeybinding); - for (const ProfileData::Keybinding& k : profile.keybindings) { + for (const Keybinding& k : keybindings) { const std::string local = k.isLocal ? "true" : "false"; output += fmt::format( "{}\t{}\t{}\t{}\t{}\t{}\n", @@ -584,28 +583,28 @@ std::string Profile::serialize() const { output += fmt::format("\n{}\n", headerTime); { - const std::string type = [](ProfileData::Time::Type t) { + const std::string type = [](Time::Type t) { switch (t) { - case ProfileData::Time::Type::Absolute: return "absolute"; - case ProfileData::Time::Type::Relative: return "relative"; - default: throw ghoul::MissingCaseException(); + case Time::Type::Absolute: return "absolute"; + case Time::Type::Relative: return "relative"; + default: throw ghoul::MissingCaseException(); } - }(profile.time.type); - output += fmt::format("{}\t{}\n", type, profile.time.time); + }(time.type); + output += fmt::format("{}\t{}\n", type, time.time); } output += fmt::format("\n{}\n", headerCamera); output += std::visit( overloaded{ - [](const ProfileData::CameraNavState& camera) { + [](const CameraNavState& camera) { return fmt::format( "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", - ProfileData::CameraNavState::Type, + CameraNavState::Type, camera.anchor, camera.aim, camera.referenceFrame, camera.position, camera.up, camera.yaw, camera.pitch ); }, - [](const ProfileData::CameraGoToGeo& camera) { + [](const Profile::CameraGoToGeo& camera) { std::string altitude; if (camera.altitude.has_value()) { altitude = std::to_string(*camera.altitude); @@ -613,17 +612,17 @@ std::string Profile::serialize() const { return fmt::format( "{}\t{}\t{}\t{}\t{}\n", - ProfileData::CameraGoToGeo::Type, + CameraGoToGeo::Type, camera.anchor, camera.latitude, camera.longitude, altitude ); } }, - profile.camera + camera ); - if (!profile.markNodes.empty()) { + if (!markNodes.empty()) { output += fmt::format("\n{}\n", headerMarkNodes); - for (const std::string& n : profile.markNodes) { + for (const std::string& n : markNodes) { output += fmt::format("{}\n", n); } } @@ -648,44 +647,44 @@ Profile::Profile(const std::vector& content) { currentSection = parseSection(line, lineNum); break; case Section::Version: - profile.version = parseVersion(line, lineNum); + version = parseVersion(line, lineNum); foundVersion = true; break; case Section::Module: { - ProfileData::Module m = parseModule(line, lineNum); - profile.modules.push_back(std::move(m)); + Module m = parseModule(line, lineNum); + modules.push_back(std::move(m)); break; } case Section::Asset: { - ProfileData::Asset a = parseAsset(line, lineNum); - profile.assets.push_back(std::move(a)); + Asset a = parseAsset(line, lineNum); + assets.push_back(std::move(a)); break; } case Section::Property: { - ProfileData::Property p = parseProperty(line, lineNum); - profile.properties.push_back(std::move(p)); + Property p = parseProperty(line, lineNum); + properties.push_back(std::move(p)); break; } case Section::Keybinding: { - ProfileData::Keybinding kb = parseKeybinding(line, lineNum); - profile.keybindings.push_back(std::move(kb)); + Keybinding kb = parseKeybinding(line, lineNum); + keybindings.push_back(std::move(kb)); break; } case Section::Time: - profile.time = parseTime(line, lineNum); + time = parseTime(line, lineNum); break; case Section::Camera: - profile.camera = parseCamera(line, lineNum); + camera = parseCamera(line, lineNum); foundCamera = true; break; case Section::MarkNodes: { std::string m = parseMarkNodes(line, lineNum); - profile.markNodes.push_back(std::move(m)); + markNodes.push_back(std::move(m)); break; } default: @@ -712,7 +711,7 @@ std::string Profile::convertToScene() const { std::string output; // Modules - for (const ProfileData::Module& m : profile.modules) { + for (const Module& m : modules) { output += fmt::format( "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", m.name, m.loadedInstruction, m.notLoadedInstruction @@ -720,14 +719,14 @@ std::string Profile::convertToScene() const { } // Assets - for (const ProfileData::Asset& a : profile.assets) { + for (const Asset& a : assets) { if (!a.name.empty()) { output += fmt::format("local {} = ", a.name); } - std::string type = [](ProfileData::Asset::Type t) { + std::string type = [](Asset::Type t) { switch (t) { - case ProfileData::Asset::Type::Request: return "request"; - case ProfileData::Asset::Type::Require: return "require"; + case Asset::Type::Request: return "request"; + case Asset::Type::Require: return "require"; default: throw ghoul::MissingCaseException(); } }(a.type); @@ -737,7 +736,7 @@ std::string Profile::convertToScene() const { output += "asset.onInitialize(function()\n"; // Keybindings - for (const ProfileData::Keybinding& k : profile.keybindings) { + for (const Keybinding& k : keybindings) { const std::string name = k.name.empty() ? k.key : k.name; output += fmt::format( k.isLocal ? @@ -748,19 +747,19 @@ std::string Profile::convertToScene() const { } // Time - switch (profile.time.type) { - case ProfileData::Time::Type::Absolute: - output += fmt::format("openspace.time.setTime(\"{}\")\n", profile.time.time); + switch (time.type) { + case Time::Type::Absolute: + output += fmt::format("openspace.time.setTime(\"{}\")\n", time.time); break; - case ProfileData::Time::Type::Relative: + case Time::Type::Relative: output += "local now = openspace.time.currentWallTime();\n"; output += fmt::format( "local prev = openspace.time.advancedTime(now, \"{}\");\n", - profile.time.time + time.time ); output += "openspace.time.setTime(prev);\n"; break; - case ProfileData::Time::Type::None: + case Time::Type::None: output += "openspace.time.setTime(openspace.time.currentWallTime());\n"; break; default: @@ -770,22 +769,22 @@ std::string Profile::convertToScene() const { // Mark Nodes { std::string nodes; - for (const std::string& n : profile.markNodes) { + for (const std::string& n : markNodes) { nodes += fmt::format("[[ {} ]],", n); } output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes); } // Properties - for (const ProfileData::Property& p : profile.properties) { + for (const Property& p : properties) { switch (p.setType) { - case ProfileData::Property::SetType::SetPropertyValue: + case Property::SetType::SetPropertyValue: output += fmt::format( "openspace.setPropertyValue(\"{}\", {});\n", p.name, p.value ); break; - case ProfileData::Property::SetType::SetPropertyValueSingle: + case Property::SetType::SetPropertyValueSingle: output += fmt::format( "openspace.setPropertyValueSingle(\"{}\", {});\n", p.name, p.value @@ -799,7 +798,7 @@ std::string Profile::convertToScene() const { // Camera output += std::visit( overloaded{ - [](const ProfileData::CameraNavState& camera) { + [](const CameraNavState& camera) { std::string result; result += "openspace.navigation.setNavigationState({"; result += fmt::format("Anchor = {}, ", camera.anchor); @@ -822,7 +821,7 @@ std::string Profile::convertToScene() const { result += "})\n"; return result; }, - [](const ProfileData::CameraGoToGeo& camera) { + [](const CameraGoToGeo& camera) { if (camera.altitude.has_value()) { return fmt::format( "openspace.globebrowsing.goToGeo({}, {}, {}, {});\n", @@ -837,7 +836,7 @@ std::string Profile::convertToScene() const { } } }, - profile.camera + camera ); output += "end)\n"; diff --git a/tests/profile/test_common.cpp b/tests/profile/test_common.cpp index 90d69f626b..e334d3f33e 100644 --- a/tests/profile/test_common.cpp +++ b/tests/profile/test_common.cpp @@ -26,7 +26,6 @@ #include "test_common.h" #include "openspace/scene/profile.h" -#include "openspace/scene/profilefile.h" #include #include #include @@ -35,77 +34,112 @@ using namespace openspace; -namespace { -} +constexpr const char* TestProfile1Text = "" +"#Version\n" +"123.4\n" +"\n" +"#Module\n" +"globebrowsing\t\t\n" +"gaia\tprint(\"success.\")\t\n" +"volume\t\tquit\n" +"\n" +"#Asset" +"scene/solarsystem/planets/earth/moon/moon\trequire\t\n" +"scene/solarsystem/missions/apollo/apollo8\trequest\t\n" +"scene/solarsystem/planets/earth/earth\trequire\t\n" +"\n" +"#Property\n" +"setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000\n" +"setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n" +"setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse\n" +"setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse\n" +"\n" +"#Keybinding\n" +"F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\"\n" +"F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\"\n" +"F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\"\n" +"F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\"\n" +"\n" +"#Time\n" +"absolute\t1977-12-21T12:51:51.0\n" +"\n" +"#Camera\n" +"setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t\n" +"\n" +"#MarkNodes\n" +"Pluto\n" +"NewHorizons\n" +"Charon\n"; -testProfileFormat buildTestProfile1() { - testProfileFormat tp1; - tp1.tsv.push_back("#Version"); - tp1.tsv.push_back("123.4"); - tp1.tsm.push_back("#Module"); - tp1.tsm.push_back("globebrowsing\t\t"); - tp1.tsm.push_back("gaia\tprint(\"success.\")\t"); - tp1.tsm.push_back("volume\t\tquit"); - tp1.tsa.push_back("#Asset"); - tp1.tsa.push_back("scene/solarsystem/planets/earth/moon/moon\trequired"); - tp1.tsa.push_back("scene/solarsystem/missions/apollo/apollo8\trequested"); - tp1.tsa.push_back("scene/solarsystem/planets/earth/earth\t"); - tp1.tsp.push_back("#Property"); - tp1.tsp.push_back("setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000"); - tp1.tsp.push_back("setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse"); - tp1.tsp.push_back("setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse"); - tp1.tsp.push_back("setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse"); - tp1.tsk.push_back("#Keybinding"); - tp1.tsk.push_back("F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\""); - tp1.tsk.push_back("F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\""); - tp1.tsk.push_back("F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""); - tp1.tsk.push_back("F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\""); - tp1.tst.push_back("#Time"); - tp1.tst.push_back("absolute\t1977-12-21T12:51:51.0"); - tp1.tsc.push_back("#Camera"); - tp1.tsc.push_back("setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"); - tp1.tsn.push_back("#MarkNodes"); - tp1.tsn.push_back("Pluto"); - tp1.tsn.push_back("NewHorizons"); - tp1.tsn.push_back("Charon"); - - return tp1; -} - -std::string stringFromSingleProfileSection(std::vector& section, - bool blankLineSeparator) -{ - std::string result; - for (std::string s : section) { - result += s + "\n"; - } - if (blankLineSeparator) { - result += "\n"; - } - return result; -} - -std::string stringFromTestProfileFormat(testProfileFormat& tpf) { - std::string fullProfile; - - fullProfile += stringFromSingleProfileSection(tpf.tsv, true); - fullProfile += stringFromSingleProfileSection(tpf.tsm, true); - fullProfile += stringFromSingleProfileSection(tpf.tsa, true); - fullProfile += stringFromSingleProfileSection(tpf.tsp, true); - fullProfile += stringFromSingleProfileSection(tpf.tsk, true); - fullProfile += stringFromSingleProfileSection(tpf.tst, true); - fullProfile += stringFromSingleProfileSection(tpf.tsc, true); - fullProfile += stringFromSingleProfileSection(tpf.tsn, false); - - return fullProfile; -} - -StringPerLineReader::StringPerLineReader(std::string s) : _iss(s) { -} - -bool StringPerLineReader::getNextLine(std::string& line) { - if (getline(_iss, line)) - return true; - else - return false; -} +// +//testProfileFormat buildTestProfile1() { +// testProfileFormat tp1; +// tp1.tsv.push_back("#Version"); +// tp1.tsv.push_back("123.4"); +// tp1.tsm.push_back("#Module"); +// tp1.tsm.push_back("globebrowsing\t\t"); +// tp1.tsm.push_back("gaia\tprint(\"success.\")\t"); +// tp1.tsm.push_back("volume\t\tquit"); +// tp1.tsa.push_back("#Asset"); +// tp1.tsa.push_back("scene/solarsystem/planets/earth/moon/moon\trequired"); +// tp1.tsa.push_back("scene/solarsystem/missions/apollo/apollo8\trequested"); +// tp1.tsa.push_back("scene/solarsystem/planets/earth/earth\t"); +// tp1.tsp.push_back("#Property"); +// tp1.tsp.push_back("setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000"); +// tp1.tsp.push_back("setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse"); +// tp1.tsp.push_back("setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse"); +// tp1.tsp.push_back("setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse"); +// tp1.tsk.push_back("#Keybinding"); +// tp1.tsk.push_back("F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\""); +// tp1.tsk.push_back("F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\""); +// tp1.tsk.push_back("F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""); +// tp1.tsk.push_back("F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\""); +// tp1.tst.push_back("#Time"); +// tp1.tst.push_back("absolute\t1977-12-21T12:51:51.0"); +// tp1.tsc.push_back("#Camera"); +// tp1.tsc.push_back("setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"); +// tp1.tsn.push_back("#MarkNodes"); +// tp1.tsn.push_back("Pluto"); +// tp1.tsn.push_back("NewHorizons"); +// tp1.tsn.push_back("Charon"); +// +// return tp1; +//} +// +//std::string stringFromSingleProfileSection(std::vector& section, +// bool blankLineSeparator) +//{ +// std::string result; +// for (std::string s : section) { +// result += s + "\n"; +// } +// if (blankLineSeparator) { +// result += "\n"; +// } +// return result; +//} +// +//std::string stringFromTestProfileFormat(testProfileFormat& tpf) { +// std::string fullProfile; +// +// fullProfile += stringFromSingleProfileSection(tpf.tsv, true); +// fullProfile += stringFromSingleProfileSection(tpf.tsm, true); +// fullProfile += stringFromSingleProfileSection(tpf.tsa, true); +// fullProfile += stringFromSingleProfileSection(tpf.tsp, true); +// fullProfile += stringFromSingleProfileSection(tpf.tsk, true); +// fullProfile += stringFromSingleProfileSection(tpf.tst, true); +// fullProfile += stringFromSingleProfileSection(tpf.tsc, true); +// fullProfile += stringFromSingleProfileSection(tpf.tsn, false); +// +// return fullProfile; +//} +// +//StringPerLineReader::StringPerLineReader(std::string s) : _iss(s) { +//} +// +//bool StringPerLineReader::getNextLine(std::string& line) { +// if (getline(_iss, line)) +// return true; +// else +// return false; +//} diff --git a/tests/profile/test_common.h b/tests/profile/test_common.h index 44313bfdef..9ecba1f68b 100644 --- a/tests/profile/test_common.h +++ b/tests/profile/test_common.h @@ -25,644 +25,643 @@ #ifndef __OPENSPACE_TEST___PROFILE_COMMON___H__ #define __OPENSPACE_TEST___PROFILE_COMMON___H__ -#include "catch2/catch.hpp" -#include "openspace/scene/profile.h" -#include "openspace/scene/profilefile.h" -#include -#include -#include -#include -#include - -using namespace openspace; - -namespace { -} - -struct testProfileFormat { - std::vector tsv; - std::vector tsm; - std::vector tsa; - std::vector tsp; - std::vector tsk; - std::vector tst; - std::vector tsc; - std::vector tsn; -}; - -const std::string newHorizonsProfileInput ="\ -#Version\n\ -1.0\n\ -\n\ -#Asset\n\ -scene/solarsystem/missions/newhorizons/newhorizons\trequired\n\ -scene/solarsystem/missions/newhorizons/model\trequired\n\ -\n\ -#Property\n\ -setPropertyValueSingle\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -a\tSets the focus of the camera on 'NewHorizons'.\tFocus on New Horizons\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -SHIFT+a\tSets the focus of the camera on 'NewHorizons'.\tAnchor at New Horizons, Aim at Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -s\tSets the focus of the camera on 'Pluto'\tFocus on Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -d\tSets the focus of the camera on 'Charon'.\tFocus on New Charon\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -F7\tToggles New Horizons image projection.\tToggle NH Image Projection\t/New Horizons\tfalse\t[[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ -F8\tRemoves all image projections from Pluto and Charon.\tClear image projections\t/New Horizons\tfalse\t\"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ -F9\tJumps to the 14th of July 2015 at 0900 UTC and clears all projections.\tReset time and projections\t/New Horizons\tfalse\t\"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ -KP_8\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -CTRL+I\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -KP_2\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -CTRL+K\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -KP_9\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -CTRL+O\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -KP_3\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -CTRL+L\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -o\tToggles the visibility of the trail behind Pluto.\tToggle Pluto Trail\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ -j\tToggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\tToggle Pluto Labels\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ -l\tToggles the visibility of the labels for the New Horizons instruments.\tToggle New Horizons Labels\t/New Horizons\tfalse\tpropertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ -m\tDraws the instrument field of views in a solid color or as lines.\tToggle instrument FOVs\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ -Shift+t\tToggles the visibility of the shadow visualization of Pluto and Charon.\tToggle Shadows\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ -t\tToggles the trail of New Horizons.\tToggle NH Trail\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ -h\tDisables visibility of the trails\tHide Trails\t/Rendering\tfalse\t\"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ -1\tSetting the simulation speed to 1 seconds per realtime second\tSet sim speed 1\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1)\"\n\ -2\tSetting the simulation speed to 5 seconds per realtime second\tSet sim speed 5\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(5)\"\n\ -3\tSetting the simulation speed to 10 seconds per realtime second\tSet sim speed 10\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(10)\"\n\ -4\tSetting the simulation speed to 20 seconds per realtime second\tSet sim speed 20\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(20)\"\n\ -5\tSetting the simulation speed to 40 seconds per realtime second\tSet sim speed 40\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(40)\"\n\ -6\tSetting the simulation speed to 60 seconds per realtime second\tSet sim speed 60\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(60)\"\n\ -7\tSetting the simulation speed to 120 seconds per realtime second\tSet sim speed 120\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(120)\"\n\ -8\tSetting the simulation speed to 360 seconds per realtime second\tSet sim speed 360\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(360)\"\n\ -9\tSetting the simulation speed to 540 seconds per realtime second\tSet sim speed 540\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(540)\"\n\ -0\tSetting the simulation speed to 1080 seconds per realtime second\tSet sim speed 1080\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1080)\"\n\ -Shift+1\tSetting the simulation speed to 2160 seconds per realtime second\tSet sim speed 2160\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(2160)\"\n\ -Shift+2\tSetting the simulation speed to 4320 seconds per realtime second\tSet sim speed 4320\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(4320)\"\n\ -Shift+3\tSetting the simulation speed to 8640 seconds per realtime second\tSet sim speed 8640\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(8640)\"\n\ -\n\ -#Time\n\ -absolute\t2015-07-14T08:00:00.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t\n\ -\n\ -#MarkNodes\n\ -Pluto\n\ -NewHorizons\n\ -Charon"; - -const std::string newHorizonsExpectedSceneOutput = "\ -\n\ -asset.require(\"base\");\n\ -local assetHelper = asset.require(\"util/asset_helper\")\n\ -local propertyHelper = asset.require(\"util/property_helper\")\n\ -local sceneHelper = asset.require(\"util/scene_helper\")\n\ -local renderableHelper = asset.require(\"util/renderable_helper\")\n\ -asset.require(\"scene/solarsystem/missions/newhorizons/newhorizons\")\n\ -asset.require(\"scene/solarsystem/missions/newhorizons/model\")\n\ -\n\ -local Keybindings = {\n\ - {\n\ - Key = \"a\",\n\ - Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ - Name = \"Focus on New Horizons\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ - },\n\ - {\n\ - Key = \"SHIFT+a\",\n\ - Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ - Name = \"Anchor at New Horizons, Aim at Pluto\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ - },\n\ - {\n\ - Key = \"s\",\n\ - Documentation = \"Sets the focus of the camera on 'Pluto'\",\n\ - Name = \"Focus on Pluto\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ - },\n\ - {\n\ - Key = \"d\",\n\ - Documentation = \"Sets the focus of the camera on 'Charon'.\",\n\ - Name = \"Focus on New Charon\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ - },\n\ - {\n\ - Key = \"F7\",\n\ - Documentation = \"Toggles New Horizons image projection.\",\n\ - Name = \"Toggle NH Image Projection\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = [[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ - },\n\ - {\n\ - Key = \"F8\",\n\ - Documentation = \"Removes all image projections from Pluto and Charon.\",\n\ - Name = \"Clear image projections\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = \"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ - },\n\ - {\n\ - Key = \"F9\",\n\ - Documentation = \"Jumps to the 14th of July 2015 at 0900 UTC and clears all projections.\",\n\ - Name = \"Reset time and projections\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = \"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ - },\n\ - {\n\ - Key = \"KP_8\",\n\ - Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ - Name = \"Pluto HeightExaggeration +\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"CTRL+I\",\n\ - Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ - Name = \"Pluto HeightExaggeration +\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"KP_2\",\n\ - Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ - Name = \"Pluto HeightExaggeration -\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"CTRL+K\",\n\ - Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ - Name = \"Pluto HeightExaggeration -\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"KP_9\",\n\ - Documentation = \"Increases the height map exaggeration on Charon.\",\n\ - Name = \"Charon HeightExaggeration +\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"CTRL+O\",\n\ - Documentation = \"Increases the height map exaggeration on Charon.\",\n\ - Name = \"Charon HeightExaggeration +\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"KP_3\",\n\ - Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ - Name = \"Charon HeightExaggeration -\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"CTRL+L\",\n\ - Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ - Name = \"Charon HeightExaggeration -\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ - },\n\ - {\n\ - Key = \"o\",\n\ - Documentation = \"Toggles the visibility of the trail behind Pluto.\",\n\ - Name = \"Toggle Pluto Trail\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ - },\n\ - {\n\ - Key = \"j\",\n\ - Documentation = \"Toggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\",\n\ - Name = \"Toggle Pluto Labels\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = renderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ - },\n\ - {\n\ - Key = \"l\",\n\ - Documentation = \"Toggles the visibility of the labels for the New Horizons instruments.\",\n\ - Name = \"Toggle New Horizons Labels\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ - },\n\ - {\n\ - Key = \"m\",\n\ - Documentation = \"Draws the instrument field of views in a solid color or as lines.\",\n\ - Name = \"Toggle instrument FOVs\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = propertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ - },\n\ - {\n\ - Key = \"Shift+t\",\n\ - Documentation = \"Toggles the visibility of the shadow visualization of Pluto and Charon.\",\n\ - Name = \"Toggle Shadows\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = renderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ - },\n\ - {\n\ - Key = \"t\",\n\ - Documentation = \"Toggles the trail of New Horizons.\",\n\ - Name = \"Toggle NH Trail\",\n\ - GuiPath = \"/New Horizons\",\n\ - Local = false,\n\ - Command = renderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ - },\n\ - {\n\ - Key = \"h\",\n\ - Documentation = \"Disables visibility of the trails\",\n\ - Name = \"Hide Trails\",\n\ - GuiPath = \"/Rendering\",\n\ - Local = false,\n\ - Command = \"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ - },\n\ - {\n\ - Key = \"1\",\n\ - Documentation = \"Setting the simulation speed to 1 seconds per realtime second\",\n\ - Name = \"Set sim speed 1\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(1)\"\n\ - },\n\ - {\n\ - Key = \"2\",\n\ - Documentation = \"Setting the simulation speed to 5 seconds per realtime second\",\n\ - Name = \"Set sim speed 5\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(5)\"\n\ - },\n\ - {\n\ - Key = \"3\",\n\ - Documentation = \"Setting the simulation speed to 10 seconds per realtime second\",\n\ - Name = \"Set sim speed 10\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(10)\"\n\ - },\n\ - {\n\ - Key = \"4\",\n\ - Documentation = \"Setting the simulation speed to 20 seconds per realtime second\",\n\ - Name = \"Set sim speed 20\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(20)\"\n\ - },\n\ - {\n\ - Key = \"5\",\n\ - Documentation = \"Setting the simulation speed to 40 seconds per realtime second\",\n\ - Name = \"Set sim speed 40\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(40)\"\n\ - },\n\ - {\n\ - Key = \"6\",\n\ - Documentation = \"Setting the simulation speed to 60 seconds per realtime second\",\n\ - Name = \"Set sim speed 60\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(60)\"\n\ - },\n\ - {\n\ - Key = \"7\",\n\ - Documentation = \"Setting the simulation speed to 120 seconds per realtime second\",\n\ - Name = \"Set sim speed 120\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(120)\"\n\ - },\n\ - {\n\ - Key = \"8\",\n\ - Documentation = \"Setting the simulation speed to 360 seconds per realtime second\",\n\ - Name = \"Set sim speed 360\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(360)\"\n\ - },\n\ - {\n\ - Key = \"9\",\n\ - Documentation = \"Setting the simulation speed to 540 seconds per realtime second\",\n\ - Name = \"Set sim speed 540\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(540)\"\n\ - },\n\ - {\n\ - Key = \"0\",\n\ - Documentation = \"Setting the simulation speed to 1080 seconds per realtime second\",\n\ - Name = \"Set sim speed 1080\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(1080)\"\n\ - },\n\ - {\n\ - Key = \"Shift+1\",\n\ - Documentation = \"Setting the simulation speed to 2160 seconds per realtime second\",\n\ - Name = \"Set sim speed 2160\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(2160)\"\n\ - },\n\ - {\n\ - Key = \"Shift+2\",\n\ - Documentation = \"Setting the simulation speed to 4320 seconds per realtime second\",\n\ - Name = \"Set sim speed 4320\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(4320)\"\n\ - },\n\ - {\n\ - Key = \"Shift+3\",\n\ - Documentation = \"Setting the simulation speed to 8640 seconds per realtime second\",\n\ - Name = \"Set sim speed 8640\",\n\ - GuiPath = \"/Simulation Speed\",\n\ - Local = false,\n\ - Command = \"openspace.time.interpolateDeltaTime(8640)\"\n\ - },\n\ -}\n\ -\n\ -asset.onInitialize(function ()\n\ - openspace.time.setTime(\"2015-07-14T08:00:00.00\")\n\ -\n\ - sceneHelper.bindKeys(Keybindings)\n\ -\n\ - openspace.markInterestingNodes({\"Pluto\", \"NewHorizons\", \"Charon\", })\n\ -\n\ - openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\", 20.000000)\n\ - openspace.setPropertyValueSingle(\"Scene.Pluto.Renderable.Enabled\", false)\n\ - openspace.setPropertyValueSingle(\"Scene.Charon.Renderable.Enabled\", false)\n\ - openspace.setPropertyValueSingle(\"Scene.PlutoBarycenterTrail.Renderable.Enabled\", false)\n\ -\n\ - openspace.navigation.setNavigationState({Anchor = \"NewHorizons\", ReferenceFrame = \"Root\", Position = {-6.572656E1, -7.239404E1, -2.111890E1}, Up = {0.102164, -0.362945, 0.926193}, })\n\ -end)"; - -const std::string detectChangedPropsResult_1 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -initialized 1st\t123\n\ -initialized 2nd\t3.14159\n\ -initialized 3rd\ttested.\n\ -initialized fourth\tfalse.\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -const std::string detectChangedAssetsResult_1 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -initialization\trequested\n\ -test2\trequested\n\ -test3\trequested\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -const std::string detectChangedAssetsResult_2 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -test3\trequested\n\ -test4\trequested\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -const std::string detectChangedAssetsResult_3 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -test2\trequested\n\ -test4\trequested\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -const std::string detectChangedAssetsResult_4 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -test2\trequested\n\ -test4\trequested\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -const std::string detectChangedAssetsResult_5 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -test2\trequested\n\ -test4\trequested\n\ -test5\tremoved\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -const std::string detectChangedAssetsResult_6 = "\ -#Version\n\ -" + std::string(Profile::FormatVersion) + "\n\ -\n\ -#Module\n\ -\n\ -#Asset\n\ -scene/solarsystem/planets/earth/earth\trequired\n\ -scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -test2\trequested\n\ -test4\trequested\n\ -scene/solarsystem/planets/earth/earth\tremoved\n\ -scene/solarsystem/planets/earth/satellites/satellites\tremoved\n\ -\n\ -#Property\n\ -setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -\n\ -#Keybinding\n\ -\n\ -#Time\n\ -absolute\t2020-02-29T01:23:45.00\n\ -\n\ -#Camera\n\ -setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -\n\ -#MarkNodes\n\ -Earth\n\ -Mars\n\ -Moon\n\ -Sun\n\ -"; - -testProfileFormat buildTestProfile1(); -std::string stringFromSingleProfileSection(std::vector& section, - bool blankLineSeparator); -std::string stringFromTestProfileFormat(testProfileFormat& tpf); -ProfileFile makeProfileFromString(std::string s); - -class StringPerLineReader { -public: - StringPerLineReader(std::string s); - bool getNextLine(std::string& line); - -private: - std::istringstream _iss; -}; - +//#include "catch2/catch.hpp" +//#include "openspace/scene/profile.h" +//#include +//#include +//#include +//#include +//#include +// +//using namespace openspace; +// +//namespace { +//} +// +//struct testProfileFormat { +// std::vector tsv; +// std::vector tsm; +// std::vector tsa; +// std::vector tsp; +// std::vector tsk; +// std::vector tst; +// std::vector tsc; +// std::vector tsn; +//}; +// +//const std::string newHorizonsProfileInput ="\ +//#Version\n\ +//1.0\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/missions/newhorizons/newhorizons\trequired\n\ +//scene/solarsystem/missions/newhorizons/model\trequired\n\ +//\n\ +//#Property\n\ +//setPropertyValueSingle\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//a\tSets the focus of the camera on 'NewHorizons'.\tFocus on New Horizons\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +//SHIFT+a\tSets the focus of the camera on 'NewHorizons'.\tAnchor at New Horizons, Aim at Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +//s\tSets the focus of the camera on 'Pluto'\tFocus on Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +//d\tSets the focus of the camera on 'Charon'.\tFocus on New Charon\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +//F7\tToggles New Horizons image projection.\tToggle NH Image Projection\t/New Horizons\tfalse\t[[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ +//F8\tRemoves all image projections from Pluto and Charon.\tClear image projections\t/New Horizons\tfalse\t\"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ +//F9\tJumps to the 14th of July 2015 at 0900 UTC and clears all projections.\tReset time and projections\t/New Horizons\tfalse\t\"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ +//KP_8\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +//CTRL+I\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +//KP_2\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +//CTRL+K\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +//KP_9\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +//CTRL+O\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +//KP_3\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +//CTRL+L\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +//o\tToggles the visibility of the trail behind Pluto.\tToggle Pluto Trail\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ +//j\tToggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\tToggle Pluto Labels\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ +//l\tToggles the visibility of the labels for the New Horizons instruments.\tToggle New Horizons Labels\t/New Horizons\tfalse\tpropertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ +//m\tDraws the instrument field of views in a solid color or as lines.\tToggle instrument FOVs\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ +//Shift+t\tToggles the visibility of the shadow visualization of Pluto and Charon.\tToggle Shadows\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ +//t\tToggles the trail of New Horizons.\tToggle NH Trail\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ +//h\tDisables visibility of the trails\tHide Trails\t/Rendering\tfalse\t\"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ +//1\tSetting the simulation speed to 1 seconds per realtime second\tSet sim speed 1\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1)\"\n\ +//2\tSetting the simulation speed to 5 seconds per realtime second\tSet sim speed 5\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(5)\"\n\ +//3\tSetting the simulation speed to 10 seconds per realtime second\tSet sim speed 10\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(10)\"\n\ +//4\tSetting the simulation speed to 20 seconds per realtime second\tSet sim speed 20\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(20)\"\n\ +//5\tSetting the simulation speed to 40 seconds per realtime second\tSet sim speed 40\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(40)\"\n\ +//6\tSetting the simulation speed to 60 seconds per realtime second\tSet sim speed 60\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(60)\"\n\ +//7\tSetting the simulation speed to 120 seconds per realtime second\tSet sim speed 120\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(120)\"\n\ +//8\tSetting the simulation speed to 360 seconds per realtime second\tSet sim speed 360\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(360)\"\n\ +//9\tSetting the simulation speed to 540 seconds per realtime second\tSet sim speed 540\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(540)\"\n\ +//0\tSetting the simulation speed to 1080 seconds per realtime second\tSet sim speed 1080\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1080)\"\n\ +//Shift+1\tSetting the simulation speed to 2160 seconds per realtime second\tSet sim speed 2160\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(2160)\"\n\ +//Shift+2\tSetting the simulation speed to 4320 seconds per realtime second\tSet sim speed 4320\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(4320)\"\n\ +//Shift+3\tSetting the simulation speed to 8640 seconds per realtime second\tSet sim speed 8640\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(8640)\"\n\ +//\n\ +//#Time\n\ +//absolute\t2015-07-14T08:00:00.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t\n\ +//\n\ +//#MarkNodes\n\ +//Pluto\n\ +//NewHorizons\n\ +//Charon"; +// +//const std::string newHorizonsExpectedSceneOutput = "\ +//\n\ +//asset.require(\"base\");\n\ +//local assetHelper = asset.require(\"util/asset_helper\")\n\ +//local propertyHelper = asset.require(\"util/property_helper\")\n\ +//local sceneHelper = asset.require(\"util/scene_helper\")\n\ +//local renderableHelper = asset.require(\"util/renderable_helper\")\n\ +//asset.require(\"scene/solarsystem/missions/newhorizons/newhorizons\")\n\ +//asset.require(\"scene/solarsystem/missions/newhorizons/model\")\n\ +//\n\ +//local Keybindings = {\n\ +// {\n\ +// Key = \"a\",\n\ +// Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ +// Name = \"Focus on New Horizons\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +// },\n\ +// {\n\ +// Key = \"SHIFT+a\",\n\ +// Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ +// Name = \"Anchor at New Horizons, Aim at Pluto\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +// },\n\ +// {\n\ +// Key = \"s\",\n\ +// Documentation = \"Sets the focus of the camera on 'Pluto'\",\n\ +// Name = \"Focus on Pluto\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +// },\n\ +// {\n\ +// Key = \"d\",\n\ +// Documentation = \"Sets the focus of the camera on 'Charon'.\",\n\ +// Name = \"Focus on New Charon\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ +// },\n\ +// {\n\ +// Key = \"F7\",\n\ +// Documentation = \"Toggles New Horizons image projection.\",\n\ +// Name = \"Toggle NH Image Projection\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = [[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ +// },\n\ +// {\n\ +// Key = \"F8\",\n\ +// Documentation = \"Removes all image projections from Pluto and Charon.\",\n\ +// Name = \"Clear image projections\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = \"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ +// },\n\ +// {\n\ +// Key = \"F9\",\n\ +// Documentation = \"Jumps to the 14th of July 2015 at 0900 UTC and clears all projections.\",\n\ +// Name = \"Reset time and projections\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ +// },\n\ +// {\n\ +// Key = \"KP_8\",\n\ +// Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ +// Name = \"Pluto HeightExaggeration +\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"CTRL+I\",\n\ +// Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ +// Name = \"Pluto HeightExaggeration +\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"KP_2\",\n\ +// Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ +// Name = \"Pluto HeightExaggeration -\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"CTRL+K\",\n\ +// Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ +// Name = \"Pluto HeightExaggeration -\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"KP_9\",\n\ +// Documentation = \"Increases the height map exaggeration on Charon.\",\n\ +// Name = \"Charon HeightExaggeration +\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"CTRL+O\",\n\ +// Documentation = \"Increases the height map exaggeration on Charon.\",\n\ +// Name = \"Charon HeightExaggeration +\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"KP_3\",\n\ +// Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ +// Name = \"Charon HeightExaggeration -\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"CTRL+L\",\n\ +// Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ +// Name = \"Charon HeightExaggeration -\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ +// },\n\ +// {\n\ +// Key = \"o\",\n\ +// Documentation = \"Toggles the visibility of the trail behind Pluto.\",\n\ +// Name = \"Toggle Pluto Trail\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ +// },\n\ +// {\n\ +// Key = \"j\",\n\ +// Documentation = \"Toggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\",\n\ +// Name = \"Toggle Pluto Labels\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = renderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ +// },\n\ +// {\n\ +// Key = \"l\",\n\ +// Documentation = \"Toggles the visibility of the labels for the New Horizons instruments.\",\n\ +// Name = \"Toggle New Horizons Labels\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ +// },\n\ +// {\n\ +// Key = \"m\",\n\ +// Documentation = \"Draws the instrument field of views in a solid color or as lines.\",\n\ +// Name = \"Toggle instrument FOVs\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = propertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ +// },\n\ +// {\n\ +// Key = \"Shift+t\",\n\ +// Documentation = \"Toggles the visibility of the shadow visualization of Pluto and Charon.\",\n\ +// Name = \"Toggle Shadows\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = renderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ +// },\n\ +// {\n\ +// Key = \"t\",\n\ +// Documentation = \"Toggles the trail of New Horizons.\",\n\ +// Name = \"Toggle NH Trail\",\n\ +// GuiPath = \"/New Horizons\",\n\ +// Local = false,\n\ +// Command = renderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ +// },\n\ +// {\n\ +// Key = \"h\",\n\ +// Documentation = \"Disables visibility of the trails\",\n\ +// Name = \"Hide Trails\",\n\ +// GuiPath = \"/Rendering\",\n\ +// Local = false,\n\ +// Command = \"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ +// },\n\ +// {\n\ +// Key = \"1\",\n\ +// Documentation = \"Setting the simulation speed to 1 seconds per realtime second\",\n\ +// Name = \"Set sim speed 1\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(1)\"\n\ +// },\n\ +// {\n\ +// Key = \"2\",\n\ +// Documentation = \"Setting the simulation speed to 5 seconds per realtime second\",\n\ +// Name = \"Set sim speed 5\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(5)\"\n\ +// },\n\ +// {\n\ +// Key = \"3\",\n\ +// Documentation = \"Setting the simulation speed to 10 seconds per realtime second\",\n\ +// Name = \"Set sim speed 10\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(10)\"\n\ +// },\n\ +// {\n\ +// Key = \"4\",\n\ +// Documentation = \"Setting the simulation speed to 20 seconds per realtime second\",\n\ +// Name = \"Set sim speed 20\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(20)\"\n\ +// },\n\ +// {\n\ +// Key = \"5\",\n\ +// Documentation = \"Setting the simulation speed to 40 seconds per realtime second\",\n\ +// Name = \"Set sim speed 40\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(40)\"\n\ +// },\n\ +// {\n\ +// Key = \"6\",\n\ +// Documentation = \"Setting the simulation speed to 60 seconds per realtime second\",\n\ +// Name = \"Set sim speed 60\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(60)\"\n\ +// },\n\ +// {\n\ +// Key = \"7\",\n\ +// Documentation = \"Setting the simulation speed to 120 seconds per realtime second\",\n\ +// Name = \"Set sim speed 120\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(120)\"\n\ +// },\n\ +// {\n\ +// Key = \"8\",\n\ +// Documentation = \"Setting the simulation speed to 360 seconds per realtime second\",\n\ +// Name = \"Set sim speed 360\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(360)\"\n\ +// },\n\ +// {\n\ +// Key = \"9\",\n\ +// Documentation = \"Setting the simulation speed to 540 seconds per realtime second\",\n\ +// Name = \"Set sim speed 540\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(540)\"\n\ +// },\n\ +// {\n\ +// Key = \"0\",\n\ +// Documentation = \"Setting the simulation speed to 1080 seconds per realtime second\",\n\ +// Name = \"Set sim speed 1080\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(1080)\"\n\ +// },\n\ +// {\n\ +// Key = \"Shift+1\",\n\ +// Documentation = \"Setting the simulation speed to 2160 seconds per realtime second\",\n\ +// Name = \"Set sim speed 2160\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(2160)\"\n\ +// },\n\ +// {\n\ +// Key = \"Shift+2\",\n\ +// Documentation = \"Setting the simulation speed to 4320 seconds per realtime second\",\n\ +// Name = \"Set sim speed 4320\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(4320)\"\n\ +// },\n\ +// {\n\ +// Key = \"Shift+3\",\n\ +// Documentation = \"Setting the simulation speed to 8640 seconds per realtime second\",\n\ +// Name = \"Set sim speed 8640\",\n\ +// GuiPath = \"/Simulation Speed\",\n\ +// Local = false,\n\ +// Command = \"openspace.time.interpolateDeltaTime(8640)\"\n\ +// },\n\ +//}\n\ +//\n\ +//asset.onInitialize(function ()\n\ +// openspace.time.setTime(\"2015-07-14T08:00:00.00\")\n\ +//\n\ +// sceneHelper.bindKeys(Keybindings)\n\ +//\n\ +// openspace.markInterestingNodes({\"Pluto\", \"NewHorizons\", \"Charon\", })\n\ +//\n\ +// openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\", 20.000000)\n\ +// openspace.setPropertyValueSingle(\"Scene.Pluto.Renderable.Enabled\", false)\n\ +// openspace.setPropertyValueSingle(\"Scene.Charon.Renderable.Enabled\", false)\n\ +// openspace.setPropertyValueSingle(\"Scene.PlutoBarycenterTrail.Renderable.Enabled\", false)\n\ +//\n\ +// openspace.navigation.setNavigationState({Anchor = \"NewHorizons\", ReferenceFrame = \"Root\", Position = {-6.572656E1, -7.239404E1, -2.111890E1}, Up = {0.102164, -0.362945, 0.926193}, })\n\ +//end)"; +// +//const std::string detectChangedPropsResult_1 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//initialized 1st\t123\n\ +//initialized 2nd\t3.14159\n\ +//initialized 3rd\ttested.\n\ +//initialized fourth\tfalse.\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//const std::string detectChangedAssetsResult_1 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//initialization\trequested\n\ +//test2\trequested\n\ +//test3\trequested\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//const std::string detectChangedAssetsResult_2 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//test3\trequested\n\ +//test4\trequested\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//const std::string detectChangedAssetsResult_3 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//test2\trequested\n\ +//test4\trequested\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//const std::string detectChangedAssetsResult_4 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//test2\trequested\n\ +//test4\trequested\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//const std::string detectChangedAssetsResult_5 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//test2\trequested\n\ +//test4\trequested\n\ +//test5\tremoved\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//const std::string detectChangedAssetsResult_6 = "\ +//#Version\n\ +//" + std::string(Profile::FormatVersion) + "\n\ +//\n\ +//#Module\n\ +//\n\ +//#Asset\n\ +//scene/solarsystem/planets/earth/earth\trequired\n\ +//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ +//test2\trequested\n\ +//test4\trequested\n\ +//scene/solarsystem/planets/earth/earth\tremoved\n\ +//scene/solarsystem/planets/earth/satellites/satellites\tremoved\n\ +//\n\ +//#Property\n\ +//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ +//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ +//\n\ +//#Keybinding\n\ +//\n\ +//#Time\n\ +//absolute\t2020-02-29T01:23:45.00\n\ +//\n\ +//#Camera\n\ +//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ +//\n\ +//#MarkNodes\n\ +//Earth\n\ +//Mars\n\ +//Moon\n\ +//Sun\n\ +//"; +// +//testProfileFormat buildTestProfile1(); +//std::string stringFromSingleProfileSection(std::vector& section, +// bool blankLineSeparator); +//std::string stringFromTestProfileFormat(testProfileFormat& tpf); +//ProfileFile makeProfileFromString(std::string s); +// +//class StringPerLineReader { +//public: +// StringPerLineReader(std::string s); +// bool getNextLine(std::string& line); +// +//private: +// std::istringstream _iss; +//}; +// #endif //__OPENSPACE_TEST___PROFILE_COMMON___H__ diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 2cbb587a4f..524cfb2214 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -45,308 +45,308 @@ using namespace openspace; -namespace { - int passTest(lua_State* state) { - bool* test = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); - *test = true; - return 0; - } -} // namespace - -class Profile2 : public Profile { -public: - Profile2(AssetLoader& refAssetLoader) : _assLoader(refAssetLoader) {} - std::string currentTimeUTC() const override { - return "2020-02-29T01:23:45.00"; - } - interaction::NavigationHandler::NavigationState currentCameraState() const override { - interaction::NavigationHandler::NavigationState n; - n.anchor = "Earth"; - n.aim = "Sun"; - n.referenceFrame = "root"; - n.position = {-1.0, -2.0, -3.0}; - n.up = {0.0, 0.0, 1.0}; - n.pitch = 0.0; - n.yaw = 0.0; - return n; - } - void addPropertiesMarkedAsChanged(std::string formattedLine) { - _scenegraphProps.push_back(formattedLine); - } - std::vector changedPropertiesFormatted() override { - std::vector formattedLines; - for (std::string s : _scenegraphProps) { - formattedLines.push_back(s); - } - return formattedLines; - } - bool usingProfile() const override { - return true; - } - std::string initialProfile() const override { - return _initProfile; - } - void setInitialProfile(std::string file) { - _initProfile = file; - } - std::vector assetEvents() const override { - return _assLoader.assetEvents(); - } - void setProfileBaseDirectory(std::string dir) { - _profileBaseDirectory = dir; - } -private: - std::vector _scenegraphProps; - std::string _initProfile; - AssetLoader& _assLoader; -}; - -static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { - s = "@line " + std::to_string(lineNumber) + ": '" + s + "'"; -} - -TEST_CASE("profile: Convert profileFile to asset", "[profile]") { - testProfileFormat test = buildTestProfile1(); - std::string testFull_string = stringFromTestProfileFormat(test); - std::string testFilePath = absPath("${TEMPORARY}/test-profile-convert.profile"); - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - - ProfileFile pf(testFilePath); - Profile p; - REQUIRE_NOTHROW( - p.convertToScene(pf) - ); -} - -TEST_CASE("profile: Verify conversion to scene", "[profile]") { - std::istringstream iss(newHorizonsProfileInput); - ProfileFile pf(newHorizonsProfileInput); - Profile p; - std::string result; - REQUIRE_NOTHROW( - result = p.convertToScene(pf) - ); - - if (result != newHorizonsExpectedSceneOutput) { - std::string testing, comparing; - StringPerLineReader sr_result(result); - StringPerLineReader sr_standard(newHorizonsExpectedSceneOutput); - - size_t lineN = 1; - while (sr_result.getNextLine(testing)) { - sr_standard.getNextLine(comparing); - addLineHeaderForFailureMessage(testing, lineN); - addLineHeaderForFailureMessage(comparing, lineN); - REQUIRE(testing == comparing); - lineN++; - } - //If this fails there are extra lines in the comparison string that weren't in result - REQUIRE(sr_standard.getNextLine(comparing) == false); - } - //REQUIRE(result == newHorizonsExpectedSceneOutput); -} - -TEST_CASE("profile: Detect new properties", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - p.addPropertiesMarkedAsChanged("initialized 1st\t123"); - p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); - p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); - p.addPropertiesMarkedAsChanged("initialized fourth\tfalse."); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedPropsResult_1); -} - -TEST_CASE("profile: Detect new added assets", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - std::shared_ptr asset = assetLoader.add("initialization"); - asset->initialize(); - std::shared_ptr asset2 = assetLoader.add("test2"); - asset2->initialize(); - std::shared_ptr asset3 = assetLoader.add("test3"); - asset3->initialize(); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_1); -} - -TEST_CASE("profile: Detect new added assets after reset", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - std::shared_ptr asset = assetLoader.add("initialization"); - asset->initialize(); - std::shared_ptr asset2 = assetLoader.add("test2"); - asset2->initialize(); - assetLoader.resetAssetEvents(); - std::shared_ptr asset3 = assetLoader.add("test3"); - asset3->initialize(); - std::shared_ptr asset4 = assetLoader.add("test4"); - asset4->initialize(); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_2); -} - -TEST_CASE("profile: Detect repeat added assets from new", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - std::shared_ptr asset = assetLoader.add("test2"); - asset->initialize(); - std::shared_ptr asset2 = assetLoader.add("test4"); - asset2->initialize(); - std::shared_ptr asset3 = assetLoader.add("test2"); - asset3->initialize(); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_3); -} - -TEST_CASE("profile: Detect repeat added assets from base", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - std::shared_ptr asset = assetLoader.add("test2"); - asset->initialize(); - std::shared_ptr asset2 = assetLoader.add("test4"); - asset2->initialize(); - std::shared_ptr asset3 = assetLoader.add("scene/solarsystem/planets/earth/earth"); - asset3->initialize(); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_4); -} - -TEST_CASE("profile: Detect removed assets not already loaded", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - std::shared_ptr asset = assetLoader.add("test2"); - asset->initialize(); - std::shared_ptr asset2 = assetLoader.add("test4"); - asset2->initialize(); - assetLoader.remove("test5"); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_5); -} - -TEST_CASE("profile: Detect removed assets from already loaded", "[profile]") { - openspace::Scene scene(std::make_unique()); - ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); - openspace::SynchronizationWatcher syncWatcher; - AssetLoader assetLoader( - state, - &syncWatcher, - FileSys.absolutePath("${TESTDIR}/profile/") - ); - - bool passed; - lua_pushlightuserdata(*state, &passed); - lua_pushcclosure(*state, &passTest, 1); - lua_setglobal(*state, "passTest"); - - std::shared_ptr asset = assetLoader.add("test2"); - asset->initialize(); - std::shared_ptr asset2 = assetLoader.add("test4"); - asset2->initialize(); - assetLoader.remove("scene/solarsystem/planets/earth/earth"); - assetLoader.remove("scene/solarsystem/planets/earth/satellites/satellites"); - - Profile2 p(assetLoader); - p.setProfileBaseDirectory("${TESTDIR}/profile"); - p.setInitialProfile("test2"); - std::string output = p.saveCurrentSettingsToProfile_string(); - REQUIRE(output == detectChangedAssetsResult_6); -} +//namespace { +// int passTest(lua_State* state) { +// bool* test = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +// *test = true; +// return 0; +// } +//} // namespace +// +//class Profile2 : public Profile { +//public: +// Profile2(AssetLoader& refAssetLoader) : _assLoader(refAssetLoader) {} +// std::string currentTimeUTC() const override { +// return "2020-02-29T01:23:45.00"; +// } +// interaction::NavigationHandler::NavigationState currentCameraState() const override { +// interaction::NavigationHandler::NavigationState n; +// n.anchor = "Earth"; +// n.aim = "Sun"; +// n.referenceFrame = "root"; +// n.position = {-1.0, -2.0, -3.0}; +// n.up = {0.0, 0.0, 1.0}; +// n.pitch = 0.0; +// n.yaw = 0.0; +// return n; +// } +// void addPropertiesMarkedAsChanged(std::string formattedLine) { +// _scenegraphProps.push_back(formattedLine); +// } +// std::vector changedPropertiesFormatted() override { +// std::vector formattedLines; +// for (std::string s : _scenegraphProps) { +// formattedLines.push_back(s); +// } +// return formattedLines; +// } +// bool usingProfile() const override { +// return true; +// } +// std::string initialProfile() const override { +// return _initProfile; +// } +// void setInitialProfile(std::string file) { +// _initProfile = file; +// } +// std::vector assetEvents() const override { +// return _assLoader.assetEvents(); +// } +// void setProfileBaseDirectory(std::string dir) { +// _profileBaseDirectory = dir; +// } +//private: +// std::vector _scenegraphProps; +// std::string _initProfile; +// AssetLoader& _assLoader; +//}; +// +//static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { +// s = "@line " + std::to_string(lineNumber) + ": '" + s + "'"; +//} +// +//TEST_CASE("profile: Convert profileFile to asset", "[profile]") { +// testProfileFormat test = buildTestProfile1(); +// std::string testFull_string = stringFromTestProfileFormat(test); +// std::string testFilePath = absPath("${TEMPORARY}/test-profile-convert.profile"); +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// +// ProfileFile pf(testFilePath); +// Profile p; +// REQUIRE_NOTHROW( +// p.convertToScene(pf) +// ); +//} +// +//TEST_CASE("profile: Verify conversion to scene", "[profile]") { +// std::istringstream iss(newHorizonsProfileInput); +// ProfileFile pf(newHorizonsProfileInput); +// Profile p; +// std::string result; +// REQUIRE_NOTHROW( +// result = p.convertToScene(pf) +// ); +// +// if (result != newHorizonsExpectedSceneOutput) { +// std::string testing, comparing; +// StringPerLineReader sr_result(result); +// StringPerLineReader sr_standard(newHorizonsExpectedSceneOutput); +// +// size_t lineN = 1; +// while (sr_result.getNextLine(testing)) { +// sr_standard.getNextLine(comparing); +// addLineHeaderForFailureMessage(testing, lineN); +// addLineHeaderForFailureMessage(comparing, lineN); +// REQUIRE(testing == comparing); +// lineN++; +// } +// //If this fails there are extra lines in the comparison string that weren't in result +// REQUIRE(sr_standard.getNextLine(comparing) == false); +// } +// //REQUIRE(result == newHorizonsExpectedSceneOutput); +//} +// +//TEST_CASE("profile: Detect new properties", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// p.addPropertiesMarkedAsChanged("initialized 1st\t123"); +// p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); +// p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); +// p.addPropertiesMarkedAsChanged("initialized fourth\tfalse."); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedPropsResult_1); +//} +// +//TEST_CASE("profile: Detect new added assets", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// std::shared_ptr asset = assetLoader.add("initialization"); +// asset->initialize(); +// std::shared_ptr asset2 = assetLoader.add("test2"); +// asset2->initialize(); +// std::shared_ptr asset3 = assetLoader.add("test3"); +// asset3->initialize(); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedAssetsResult_1); +//} +// +//TEST_CASE("profile: Detect new added assets after reset", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// std::shared_ptr asset = assetLoader.add("initialization"); +// asset->initialize(); +// std::shared_ptr asset2 = assetLoader.add("test2"); +// asset2->initialize(); +// assetLoader.resetAssetEvents(); +// std::shared_ptr asset3 = assetLoader.add("test3"); +// asset3->initialize(); +// std::shared_ptr asset4 = assetLoader.add("test4"); +// asset4->initialize(); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedAssetsResult_2); +//} +// +//TEST_CASE("profile: Detect repeat added assets from new", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// std::shared_ptr asset = assetLoader.add("test2"); +// asset->initialize(); +// std::shared_ptr asset2 = assetLoader.add("test4"); +// asset2->initialize(); +// std::shared_ptr asset3 = assetLoader.add("test2"); +// asset3->initialize(); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedAssetsResult_3); +//} +// +//TEST_CASE("profile: Detect repeat added assets from base", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// std::shared_ptr asset = assetLoader.add("test2"); +// asset->initialize(); +// std::shared_ptr asset2 = assetLoader.add("test4"); +// asset2->initialize(); +// std::shared_ptr asset3 = assetLoader.add("scene/solarsystem/planets/earth/earth"); +// asset3->initialize(); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedAssetsResult_4); +//} +// +//TEST_CASE("profile: Detect removed assets not already loaded", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// std::shared_ptr asset = assetLoader.add("test2"); +// asset->initialize(); +// std::shared_ptr asset2 = assetLoader.add("test4"); +// asset2->initialize(); +// assetLoader.remove("test5"); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedAssetsResult_5); +//} +// +//TEST_CASE("profile: Detect removed assets from already loaded", "[profile]") { +// openspace::Scene scene(std::make_unique()); +// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); +// openspace::SynchronizationWatcher syncWatcher; +// AssetLoader assetLoader( +// state, +// &syncWatcher, +// FileSys.absolutePath("${TESTDIR}/profile/") +// ); +// +// bool passed; +// lua_pushlightuserdata(*state, &passed); +// lua_pushcclosure(*state, &passTest, 1); +// lua_setglobal(*state, "passTest"); +// +// std::shared_ptr asset = assetLoader.add("test2"); +// asset->initialize(); +// std::shared_ptr asset2 = assetLoader.add("test4"); +// asset2->initialize(); +// assetLoader.remove("scene/solarsystem/planets/earth/earth"); +// assetLoader.remove("scene/solarsystem/planets/earth/satellites/satellites"); +// +// Profile2 p(assetLoader); +// p.setProfileBaseDirectory("${TESTDIR}/profile"); +// p.setInitialProfile("test2"); +// std::string output = p.saveCurrentSettingsToProfile_string(); +// REQUIRE(output == detectChangedAssetsResult_6); +//} diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index 1d5833e471..7d1dd24f71 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -24,188 +24,184 @@ #include "catch2/catch.hpp" -#include "openspace/scene/profilefile.h" #include "test_common.h" #include #include #include #include -using namespace openspace; +//using namespace openspace; -namespace { -} - -TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { - testProfileFormat test = buildTestProfile1(); - std::string testFile = absPath("${TEMPORARY}/profile-test-simple"); - { - std::string testFull_string = stringFromTestProfileFormat(test); - std::ofstream f(testFile); - f << testFull_string; - } - - ProfileFile pf(testFile); - - std::vector tVect; - - REQUIRE(pf.version() == test.tsv[1]); - REQUIRE(pf.time() == test.tst[1]); - REQUIRE(pf.camera() == test.tsc[1]); - tVect = pf.modules(); - REQUIRE(tVect[0] == test.tsm[1]); - REQUIRE(tVect[1] == test.tsm[2]); - REQUIRE(tVect[2] == test.tsm[3]); - tVect = pf.assets(); - REQUIRE(tVect[0] == test.tsa[1]); - REQUIRE(tVect[1] == test.tsa[2]); - REQUIRE(tVect[2] == test.tsa[3]); - tVect = pf.properties(); - REQUIRE(tVect[0] == test.tsp[1]); - REQUIRE(tVect[1] == test.tsp[2]); - REQUIRE(tVect[2] == test.tsp[3]); - REQUIRE(tVect[3] == test.tsp[4]); - tVect = pf.keybindings(); - REQUIRE(tVect[0] == test.tsk[1]); - REQUIRE(tVect[1] == test.tsk[2]); - REQUIRE(tVect[2] == test.tsk[3]); - REQUIRE(tVect[3] == test.tsk[4]); - tVect = pf.markNodes(); - REQUIRE(tVect[0] == test.tsn[1]); - REQUIRE(tVect[1] == test.tsn[2]); - REQUIRE(tVect[2] == test.tsn[3]); -} - -TEST_CASE("profileFile: Unrecognized header", "[profileFile]") { - std::string testFilePath = absPath("${TEMPORARY}/test-profile-unrec-header.profile"); - testProfileFormat test = buildTestProfile1(); - test.tsa[0] = "#Azzet"; - std::string testFull_string = stringFromTestProfileFormat(test); - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - - REQUIRE_THROWS_WITH( - ProfileFile(testFilePath), - Catch::Matchers::Contains("Invalid section header") && - Catch::Matchers::Contains("#Azzet") - ); -} - -TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { - { - std::string testFilePath = absPath( - "${TEMPORARY}/test-profile-bad-n-fields-1.profile" - ); - testProfileFormat test = buildTestProfile1(); - test.tsm[1] = "globebrowsing\t\t\t"; - std::string testFull_string = stringFromTestProfileFormat(test); - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - REQUIRE_THROWS_WITH( - ProfileFile(testFilePath), - Catch::Matchers::Contains("fields required in a Module entry") - ); - } - - { - std::string testFilePath = absPath( - "${TEMPORARY}/test-profile-bad-n-fields-2.profile" - ); - - testProfileFormat test = buildTestProfile1(); - test.tsm[1] = "globebrowsing\t\t"; - test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"; - std::string testFull_string = stringFromTestProfileFormat(test); - - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - REQUIRE_THROWS_WITH( - ProfileFile(testFilePath), - Catch::Matchers::Contains("fields required in Camera entry") - ); - } -} - -TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") { - testProfileFormat test = buildTestProfile1(); - test.tst.push_back("relative\t\"-1 day\""); - std::string testFull_string = stringFromTestProfileFormat(test); - std::string testFilePath = absPath( - "${TEMPORARY}/test-profile-too-many-lines-time.profile" - ); - - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - { - REQUIRE_THROWS_WITH( - ProfileFile(testFilePath), - Catch::Matchers::Contains("Too many lines in time section") - ); - } -} - -TEST_CASE("profileFile: Required field missing", "[profileFile]") { - { - testProfileFormat test = buildTestProfile1(); - test.tsc[1] = "setNavigationState\t\"NewHorizons\"\ttest\t\"Root\"\t\t0.102164, -0.362945, 0.926193\t\t"; - std::string testFull_string = stringFromTestProfileFormat(test); - std::string testFilePath = absPath( - "${TEMPORARY}/test-profile-required-field-missing-1.profile" - ); - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - - { - REQUIRE_THROWS_WITH( - ProfileFile(testFilePath), - Catch::Matchers::Contains("Camera navigation setNavigationState position vector(arg 4/8) is required") - ); - } - } - - { - testProfileFormat test = buildTestProfile1(); - test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t1, 2, 3\t0.102164, -0.362945, 0.926193\t\t"; - test.tsk[3] = "F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\t\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""; - std::string testFull_string = stringFromTestProfileFormat(test); - std::string testFilePath = absPath( - "${TEMPORARY}/test-profile-required-field-missing-2.profile" - ); - { - std::ofstream testFile(testFilePath); - testFile << testFull_string; - } - { - ProfileFile pf("default.profile"); - REQUIRE_THROWS_WITH( - ProfileFile(testFilePath), - Catch::Matchers::Contains("Keybinding local(T/F)(arg 4/6) is required") - ); - } - } -} - -TEST_CASE("profileFile: Write test", "[profileFile]") { - testProfileFormat test = buildTestProfile1(); - std::string testFile = absPath("${TEMPORARY}/profile-test-write-test"); - std::string testFull_string = stringFromTestProfileFormat(test); - { - std::ofstream f(testFile); - f << testFull_string; - } - - ProfileFile pf(testFile); - - std::string result = serialize(pf.profile); - REQUIRE(testFull_string == result); -} +//TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { +// testProfileFormat test = buildTestProfile1(); +// std::string testFile = absPath("${TEMPORARY}/profile-test-simple"); +// { +// std::string testFull_string = stringFromTestProfileFormat(test); +// std::ofstream f(testFile); +// f << testFull_string; +// } +// +// ProfileFile pf(testFile); +// +// std::vector tVect; +// +// REQUIRE(pf.version() == test.tsv[1]); +// REQUIRE(pf.time() == test.tst[1]); +// REQUIRE(pf.camera() == test.tsc[1]); +// tVect = pf.modules(); +// REQUIRE(tVect[0] == test.tsm[1]); +// REQUIRE(tVect[1] == test.tsm[2]); +// REQUIRE(tVect[2] == test.tsm[3]); +// tVect = pf.assets(); +// REQUIRE(tVect[0] == test.tsa[1]); +// REQUIRE(tVect[1] == test.tsa[2]); +// REQUIRE(tVect[2] == test.tsa[3]); +// tVect = pf.properties(); +// REQUIRE(tVect[0] == test.tsp[1]); +// REQUIRE(tVect[1] == test.tsp[2]); +// REQUIRE(tVect[2] == test.tsp[3]); +// REQUIRE(tVect[3] == test.tsp[4]); +// tVect = pf.keybindings(); +// REQUIRE(tVect[0] == test.tsk[1]); +// REQUIRE(tVect[1] == test.tsk[2]); +// REQUIRE(tVect[2] == test.tsk[3]); +// REQUIRE(tVect[3] == test.tsk[4]); +// tVect = pf.markNodes(); +// REQUIRE(tVect[0] == test.tsn[1]); +// REQUIRE(tVect[1] == test.tsn[2]); +// REQUIRE(tVect[2] == test.tsn[3]); +//} +// +//TEST_CASE("profileFile: Unrecognized header", "[profileFile]") { +// std::string testFilePath = absPath("${TEMPORARY}/test-profile-unrec-header.profile"); +// testProfileFormat test = buildTestProfile1(); +// test.tsa[0] = "#Azzet"; +// std::string testFull_string = stringFromTestProfileFormat(test); +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// +// REQUIRE_THROWS_WITH( +// ProfileFile(testFilePath), +// Catch::Matchers::Contains("Invalid section header") && +// Catch::Matchers::Contains("#Azzet") +// ); +//} +// +//TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { +// { +// std::string testFilePath = absPath( +// "${TEMPORARY}/test-profile-bad-n-fields-1.profile" +// ); +// testProfileFormat test = buildTestProfile1(); +// test.tsm[1] = "globebrowsing\t\t\t"; +// std::string testFull_string = stringFromTestProfileFormat(test); +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// REQUIRE_THROWS_WITH( +// ProfileFile(testFilePath), +// Catch::Matchers::Contains("fields required in a Module entry") +// ); +// } +// +// { +// std::string testFilePath = absPath( +// "${TEMPORARY}/test-profile-bad-n-fields-2.profile" +// ); +// +// testProfileFormat test = buildTestProfile1(); +// test.tsm[1] = "globebrowsing\t\t"; +// test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"; +// std::string testFull_string = stringFromTestProfileFormat(test); +// +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// REQUIRE_THROWS_WITH( +// ProfileFile(testFilePath), +// Catch::Matchers::Contains("fields required in Camera entry") +// ); +// } +//} +// +//TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") { +// testProfileFormat test = buildTestProfile1(); +// test.tst.push_back("relative\t\"-1 day\""); +// std::string testFull_string = stringFromTestProfileFormat(test); +// std::string testFilePath = absPath( +// "${TEMPORARY}/test-profile-too-many-lines-time.profile" +// ); +// +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// { +// REQUIRE_THROWS_WITH( +// ProfileFile(testFilePath), +// Catch::Matchers::Contains("Too many lines in time section") +// ); +// } +//} +// +//TEST_CASE("profileFile: Required field missing", "[profileFile]") { +// { +// testProfileFormat test = buildTestProfile1(); +// test.tsc[1] = "setNavigationState\t\"NewHorizons\"\ttest\t\"Root\"\t\t0.102164, -0.362945, 0.926193\t\t"; +// std::string testFull_string = stringFromTestProfileFormat(test); +// std::string testFilePath = absPath( +// "${TEMPORARY}/test-profile-required-field-missing-1.profile" +// ); +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// +// { +// REQUIRE_THROWS_WITH( +// ProfileFile(testFilePath), +// Catch::Matchers::Contains("Camera navigation setNavigationState position vector(arg 4/8) is required") +// ); +// } +// } +// +// { +// testProfileFormat test = buildTestProfile1(); +// test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t1, 2, 3\t0.102164, -0.362945, 0.926193\t\t"; +// test.tsk[3] = "F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\t\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""; +// std::string testFull_string = stringFromTestProfileFormat(test); +// std::string testFilePath = absPath( +// "${TEMPORARY}/test-profile-required-field-missing-2.profile" +// ); +// { +// std::ofstream testFile(testFilePath); +// testFile << testFull_string; +// } +// { +// ProfileFile pf("default.profile"); +// REQUIRE_THROWS_WITH( +// ProfileFile(testFilePath), +// Catch::Matchers::Contains("Keybinding local(T/F)(arg 4/6) is required") +// ); +// } +// } +//} +// +//TEST_CASE("profileFile: Write test", "[profileFile]") { +// testProfileFormat test = buildTestProfile1(); +// std::string testFile = absPath("${TEMPORARY}/profile-test-write-test"); +// std::string testFull_string = stringFromTestProfileFormat(test); +// { +// std::ofstream f(testFile); +// f << testFull_string; +// } +// +// ProfileFile pf(testFile); +// +// std::string result = serialize(pf.profile); +// REQUIRE(testFull_string == result); +//} From 15db67bb59d237188da94a362f26e725a51b5a55 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 20 Jun 2020 15:28:51 +0200 Subject: [PATCH 35/61] Port basic profile unit testing --- include/openspace/scene/profile.h | 5 +- src/scene/profile.cpp | 181 +++++++++--------- tests/profile/basic_assets.profile | 7 + tests/profile/basic_camera_gotogeo.profile | 5 + .../basic_camera_gotogeo_altitude.profile | 5 + tests/profile/basic_camera_navstate.profile | 5 + tests/profile/basic_keybindings.profile | 7 + tests/profile/basic_mark_nodes.profile | 7 + tests/profile/basic_modules.profile | 7 + tests/profile/basic_properties.profile | 10 + tests/profile/basic_time_absolute.profile | 5 + tests/profile/basic_time_relative.profile | 5 + tests/profile/minimal.profile | 2 + tests/profile/test_profile.cpp | 172 +++++++++++++++-- 14 files changed, 316 insertions(+), 107 deletions(-) create mode 100644 tests/profile/basic_assets.profile create mode 100644 tests/profile/basic_camera_gotogeo.profile create mode 100644 tests/profile/basic_camera_gotogeo_altitude.profile create mode 100644 tests/profile/basic_camera_navstate.profile create mode 100644 tests/profile/basic_keybindings.profile create mode 100644 tests/profile/basic_mark_nodes.profile create mode 100644 tests/profile/basic_modules.profile create mode 100644 tests/profile/basic_properties.profile create mode 100644 tests/profile/basic_time_absolute.profile create mode 100644 tests/profile/basic_time_relative.profile create mode 100644 tests/profile/minimal.profile diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 4cf257e609..eb9c7f61b3 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -114,7 +114,7 @@ public: double longitude; std::optional altitude; }; - using CameraType = std::variant; + using CameraType = std::variant; enum class AssetEventType { Add, @@ -159,7 +159,7 @@ public: static scripting::LuaLibrary luaLibrary(); private: - static constexpr const Version CurrentVersion = Version{ 1, 0, 0 }; + static constexpr const Version CurrentVersion = Version { 1, 0, 0 }; Version version = CurrentVersion; std::vector modules; std::vector assets; @@ -169,7 +169,6 @@ private: CameraType camera; std::vector markNodes; - bool _ignoreUpdates = false; }; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 88b6616fce..5f206479b3 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -341,7 +341,7 @@ namespace { throw ProfileParsingError(lineNumber, "No values specified for Camera location"); } Profile::CameraType camera = [&](const std::string& type) -> - std::variant + std::variant { if (type == Profile::CameraNavState::Type) { if (fields.size() != 8) { @@ -580,45 +580,57 @@ std::string Profile::serialize() const { ); } } - - output += fmt::format("\n{}\n", headerTime); - { - const std::string type = [](Time::Type t) { - switch (t) { + + if (time.type != Time::Type::None) { + output += fmt::format("\n{}\n", headerTime); + { + const std::string type = [](Time::Type t) { + switch (t) { case Time::Type::Absolute: return "absolute"; case Time::Type::Relative: return "relative"; default: throw ghoul::MissingCaseException(); - } - }(time.type); - output += fmt::format("{}\t{}\n", type, time.time); + } + }(time.type); + output += fmt::format("{}\t{}\n", type, time.time); + } } - output += fmt::format("\n{}\n", headerCamera); - output += std::visit( - overloaded{ - [](const CameraNavState& camera) { - return fmt::format( - "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", - CameraNavState::Type, - camera.anchor, camera.aim, camera.referenceFrame, camera.position, - camera.up, camera.yaw, camera.pitch - ); - }, - [](const Profile::CameraGoToGeo& camera) { - std::string altitude; - if (camera.altitude.has_value()) { - altitude = std::to_string(*camera.altitude); + if (!std::holds_alternative(camera)) { + output += fmt::format("\n{}\n", headerCamera); + output += std::visit( + overloaded{ + [](const std::monostate&) { + return std::string(); + }, + [](const CameraNavState& camera) { + return fmt::format( + "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\n", + CameraNavState::Type, + camera.anchor, camera.aim, camera.referenceFrame, camera.position, + camera.up, camera.yaw, camera.pitch + ); + }, + [](const Profile::CameraGoToGeo& camera) { + if (camera.altitude.has_value()) { + return fmt::format( + "{}\t{}\t{}\t{}\t{}\n", + CameraGoToGeo::Type, + camera.anchor, camera.latitude, camera.longitude, + *camera.altitude + ); + } + else { + return fmt::format( + "{}\t{}\t{}\t{}\t\n", + CameraGoToGeo::Type, + camera.anchor, camera.latitude, camera.longitude + ); + } } - - return fmt::format( - "{}\t{}\t{}\t{}\t{}\n", - CameraGoToGeo::Type, - camera.anchor, camera.latitude, camera.longitude, altitude - ); - } - }, - camera - ); + }, + camera + ); + } if (!markNodes.empty()) { output += fmt::format("\n{}\n", headerMarkNodes); @@ -633,7 +645,6 @@ std::string Profile::serialize() const { Profile::Profile(const std::vector& content) { Section currentSection = Section::None; bool foundVersion = false; - bool foundCamera = false; for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { std::string line = content[lineNum - 1]; @@ -643,52 +654,51 @@ Profile::Profile(const std::vector& content) { } switch (currentSection) { - case Section::None: - currentSection = parseSection(line, lineNum); - break; - case Section::Version: - version = parseVersion(line, lineNum); - foundVersion = true; - break; - case Section::Module: - { - Module m = parseModule(line, lineNum); - modules.push_back(std::move(m)); - break; - } - case Section::Asset: - { - Asset a = parseAsset(line, lineNum); - assets.push_back(std::move(a)); - break; - } - case Section::Property: - { - Property p = parseProperty(line, lineNum); - properties.push_back(std::move(p)); - break; - } - case Section::Keybinding: - { - Keybinding kb = parseKeybinding(line, lineNum); - keybindings.push_back(std::move(kb)); - break; - } - case Section::Time: - time = parseTime(line, lineNum); - break; - case Section::Camera: - camera = parseCamera(line, lineNum); - foundCamera = true; - break; - case Section::MarkNodes: - { - std::string m = parseMarkNodes(line, lineNum); - markNodes.push_back(std::move(m)); - break; - } - default: - throw ghoul::MissingCaseException(); + case Section::None: + currentSection = parseSection(line, lineNum); + break; + case Section::Version: + version = parseVersion(line, lineNum); + foundVersion = true; + break; + case Section::Module: + { + Module m = parseModule(line, lineNum); + modules.push_back(std::move(m)); + break; + } + case Section::Asset: + { + Asset a = parseAsset(line, lineNum); + assets.push_back(std::move(a)); + break; + } + case Section::Property: + { + Property p = parseProperty(line, lineNum); + properties.push_back(std::move(p)); + break; + } + case Section::Keybinding: + { + Keybinding kb = parseKeybinding(line, lineNum); + keybindings.push_back(std::move(kb)); + break; + } + case Section::Time: + time = parseTime(line, lineNum); + break; + case Section::Camera: + camera = parseCamera(line, lineNum); + break; + case Section::MarkNodes: + { + std::string m = parseMarkNodes(line, lineNum); + markNodes.push_back(std::move(m)); + break; + } + default: + throw ghoul::MissingCaseException(); } } @@ -697,12 +707,6 @@ Profile::Profile(const std::vector& content) { "Did not find Version information when loading profile" ); } - - if (!foundCamera) { - throw ghoul::RuntimeError( - "Did not find Camera information when loading profile" - ); - } } std::string Profile::convertToScene() const { @@ -798,6 +802,9 @@ std::string Profile::convertToScene() const { // Camera output += std::visit( overloaded{ + [](const std::monostate&) { + return std::string(); + }, [](const CameraNavState& camera) { std::string result; result += "openspace.navigation.setNavigationState({"; diff --git a/tests/profile/basic_assets.profile b/tests/profile/basic_assets.profile new file mode 100644 index 0000000000..62fec23682 --- /dev/null +++ b/tests/profile/basic_assets.profile @@ -0,0 +1,7 @@ +#Version +12.13.14 + +#Asset +folder1/folder2/asset require +folder3/folder4/asset2 require variable +folder5/folder6/asset3 request diff --git a/tests/profile/basic_camera_gotogeo.profile b/tests/profile/basic_camera_gotogeo.profile new file mode 100644 index 0000000000..cbf5d7f670 --- /dev/null +++ b/tests/profile/basic_camera_gotogeo.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +goToGeo "anchor" 1.0 2.0 diff --git a/tests/profile/basic_camera_gotogeo_altitude.profile b/tests/profile/basic_camera_gotogeo_altitude.profile new file mode 100644 index 0000000000..069d94a230 --- /dev/null +++ b/tests/profile/basic_camera_gotogeo_altitude.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +goToGeo "anchor" 1.0 2.0 4.0 diff --git a/tests/profile/basic_camera_navstate.profile b/tests/profile/basic_camera_navstate.profile new file mode 100644 index 0000000000..02a9783733 --- /dev/null +++ b/tests/profile/basic_camera_navstate.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 diff --git a/tests/profile/basic_keybindings.profile b/tests/profile/basic_keybindings.profile new file mode 100644 index 0000000000..7f309a4b0f --- /dev/null +++ b/tests/profile/basic_keybindings.profile @@ -0,0 +1,7 @@ +#Version +12.13.14 + +#Keybinding +T T documentation T name T Gui-Path true T script +U U documentation U name U Gui-Path false U script +CTRL+V CTRL+V documentation CTRL+V name CTRL+V Gui-Path false CTRL+V script diff --git a/tests/profile/basic_mark_nodes.profile b/tests/profile/basic_mark_nodes.profile new file mode 100644 index 0000000000..5deecdfc31 --- /dev/null +++ b/tests/profile/basic_mark_nodes.profile @@ -0,0 +1,7 @@ +#Version +12.13.14 + +#MarkNodes +node-1 +node-2 +node-3 diff --git a/tests/profile/basic_modules.profile b/tests/profile/basic_modules.profile new file mode 100644 index 0000000000..2ba1c93dfb --- /dev/null +++ b/tests/profile/basic_modules.profile @@ -0,0 +1,7 @@ +#Version +12.13.14 + +#Module +abc-module +def-module +ghi-module diff --git a/tests/profile/basic_properties.profile b/tests/profile/basic_properties.profile new file mode 100644 index 0000000000..abc6c35ec0 --- /dev/null +++ b/tests/profile/basic_properties.profile @@ -0,0 +1,10 @@ +#Version +12.13.14 + +#Property +setPropertyValue property_name_1 property_value_1 +setPropertyValue property_name_2 property_value_2 +setPropertyValue property_name_3 property_value_3 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 diff --git a/tests/profile/basic_time_absolute.profile b/tests/profile/basic_time_absolute.profile new file mode 100644 index 0000000000..269a06319a --- /dev/null +++ b/tests/profile/basic_time_absolute.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Time +absolute 2020-06-01T12:00:00 diff --git a/tests/profile/basic_time_relative.profile b/tests/profile/basic_time_relative.profile new file mode 100644 index 0000000000..253aff665b --- /dev/null +++ b/tests/profile/basic_time_relative.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Time +relative -1d diff --git a/tests/profile/minimal.profile b/tests/profile/minimal.profile new file mode 100644 index 0000000000..7ec5af0497 --- /dev/null +++ b/tests/profile/minimal.profile @@ -0,0 +1,2 @@ +#Version +12.13.14 diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index 524cfb2214..bc25117b7d 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -23,28 +23,166 @@ ****************************************************************************************/ #include "catch2/catch.hpp" -#include "test_common.h" -#include -#include -#include +//#include "test_common.h" +//#include +//#include +//#include +// +//#include +//#include +//#include "openspace/scene/profile.h" +//#include +//#include +//#include +//#include +//#include +//#include +// +//#include +//#include +//#include -#include -#include -#include "openspace/scene/profile.h" -#include -#include -#include -#include + +#include #include -#include -#include - -#include -#include -#include +#include using namespace openspace; +namespace { + Profile loadProfile(const std::string& filename) { + std::ifstream f(absPath(filename)); + + std::vector lines; + std::string line; + while (std::getline(f, line)) { + lines.push_back(std::move(line)); + } + + return Profile(lines); + } + + std::string loadFile(const std::string& filename) { + std::ifstream f(absPath(filename)); + std::string content( + (std::istreambuf_iterator(f)), + std::istreambuf_iterator() + ); + return content; + } +} // namespace + +TEST_CASE("Minimal", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/minimal.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Module", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_modules.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Assets", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_assets.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Properties", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_properties.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Keybindings", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_keybindings.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Time Relative", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_time_relative.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Time Absolute", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_time_absolute.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Camera NavState", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_camera_navstate.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Camera GoToGeo", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_camera_gotogeo.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Camera GoToGeo altitude", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/basic_camera_gotogeo_altitude.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Mark Nodes", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/basic_mark_nodes.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + //namespace { // int passTest(lua_State* state) { // bool* test = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); From 5e6489419ec448617353ac4ffdbb844d48173ba0 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 20 Jun 2020 22:04:13 +0200 Subject: [PATCH 36/61] Adding the first version of the unit tests for the profiles --- src/scene/profile.cpp | 75 ++- .../basic_version_one_component.profile | 2 + .../basic_version_three_components.profile | 2 + .../basic_version_two_components.profile | 2 + tests/profile/default.profile | 21 - ..._camera_gotogeo_too_few_parameters.profile | 5 + ...camera_gotogeo_too_many_parameters.profile | 5 + ...camera_navstate_too_few_parameters.profile | 5 + ...amera_navstate_too_many_parameters.profile | 5 + ..._camera_wrong_parameter_value_type.profile | 5 + ...rror_keybinding_too_few_parameters.profile | 5 + ...ror_keybinding_too_many_parameters.profile | 5 + ...binding_wrong_parameter_type_local.profile | 5 + .../error_module_too_few_parameters.profile | 5 + .../error_module_too_many_parameters.profile | 5 + .../error_property_too_few_parameters.profile | 5 + ...error_property_too_many_parameters.profile | 5 + ...roperty_wrong_parameter_value_type.profile | 5 + .../error_time_too_few_parameters.profile | 5 + .../error_time_too_many_parameters.profile | 5 + ...or_time_wrong_parameter_value_type.profile | 5 + .../profile/error_two_camera_sections.profile | 8 + tests/profile/error_two_time_sections.profile | 8 + .../error_two_version_sections.profile | 5 + .../profile/error_unrecognized_header.profile | 7 + .../error_version_malformed_component.profile | 2 + tests/profile/error_version_not_first.profile | 7 + .../error_version_too_many_components.profile | 2 + tests/profile/integration_full_test.profile | 40 ++ ...ntegration_full_test_permutation_1.profile | 41 ++ ...gration_full_test_permutation_base.profile | 40 ++ tests/profile/test1.asset | 1 - tests/profile/test2.asset | 1 - tests/profile/test2.profile | 23 - tests/profile/test3.asset | 1 - tests/profile/test4.asset | 1 - tests/profile/test_profile.cpp | 588 +++++++++--------- tests/profile/test_profilefile.cpp | 76 --- 38 files changed, 593 insertions(+), 440 deletions(-) create mode 100644 tests/profile/basic_version_one_component.profile create mode 100644 tests/profile/basic_version_three_components.profile create mode 100644 tests/profile/basic_version_two_components.profile delete mode 100644 tests/profile/default.profile create mode 100644 tests/profile/error_camera_gotogeo_too_few_parameters.profile create mode 100644 tests/profile/error_camera_gotogeo_too_many_parameters.profile create mode 100644 tests/profile/error_camera_navstate_too_few_parameters.profile create mode 100644 tests/profile/error_camera_navstate_too_many_parameters.profile create mode 100644 tests/profile/error_camera_wrong_parameter_value_type.profile create mode 100644 tests/profile/error_keybinding_too_few_parameters.profile create mode 100644 tests/profile/error_keybinding_too_many_parameters.profile create mode 100644 tests/profile/error_keybinding_wrong_parameter_type_local.profile create mode 100644 tests/profile/error_module_too_few_parameters.profile create mode 100644 tests/profile/error_module_too_many_parameters.profile create mode 100644 tests/profile/error_property_too_few_parameters.profile create mode 100644 tests/profile/error_property_too_many_parameters.profile create mode 100644 tests/profile/error_property_wrong_parameter_value_type.profile create mode 100644 tests/profile/error_time_too_few_parameters.profile create mode 100644 tests/profile/error_time_too_many_parameters.profile create mode 100644 tests/profile/error_time_wrong_parameter_value_type.profile create mode 100644 tests/profile/error_two_camera_sections.profile create mode 100644 tests/profile/error_two_time_sections.profile create mode 100644 tests/profile/error_two_version_sections.profile create mode 100644 tests/profile/error_unrecognized_header.profile create mode 100644 tests/profile/error_version_malformed_component.profile create mode 100644 tests/profile/error_version_not_first.profile create mode 100644 tests/profile/error_version_too_many_components.profile create mode 100644 tests/profile/integration_full_test.profile create mode 100644 tests/profile/integration_full_test_permutation_1.profile create mode 100644 tests/profile/integration_full_test_permutation_base.profile delete mode 100644 tests/profile/test1.asset delete mode 100644 tests/profile/test2.asset delete mode 100644 tests/profile/test2.profile delete mode 100644 tests/profile/test3.asset delete mode 100644 tests/profile/test4.asset diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index 5f206479b3..b135542104 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -189,24 +189,38 @@ namespace { ); } - [[ nodiscard ]] Profile::Version parseVersion(const std::string& line, int lineNumber) { + [[ nodiscard ]] Profile::Version parseVersion(const std::string& line, int lineNumber) + { std::vector parts = ghoul::tokenizeString(line, '.'); - if (parts.empty() || parts.size() > 3) { + if (parts.size() > 3) { throw ProfileParsingError( lineNumber, fmt::format("Expected 1-3 version components, got {}", parts.size()) ); } - Profile::Version version; - version.major = std::stoi(parts[0]); - if (parts.size() > 1) { - version.minor = std::stoi(parts[1]); + try { + Profile::Version version; + if (parts.empty()) { + version.major = std::stoi(line); + } + else { + version.major = std::stoi(parts[0]); + } + if (parts.size() > 1) { + version.minor = std::stoi(parts[1]); + } + if (parts.size() > 2) { + version.patch = std::stoi(parts[2]); + } + return version; } - if (parts.size() > 2) { - version.patch = std::stoi(parts[2]); + catch (const std::invalid_argument&) { + throw ProfileParsingError( + lineNumber, + "Error parsing Version. Version number is not a number" + ); } - return version; } [[ nodiscard ]] Profile::Module parseModule(const std::string& line, int lineNumber) { @@ -271,7 +285,7 @@ namespace { lineNumber, fmt::format( "Expected property set type 'setPropertyValue' or " - "'setPropertyValueSingle', got {}", + "'setPropertyValueSingle', got '{}'", type ) ); @@ -337,9 +351,6 @@ namespace { [[ nodiscard ]] Profile::CameraType parseCamera(const std::string& line, int lineNumber) { std::vector fields = ghoul::tokenizeString(line, '\t'); - if (fields.empty()) { - throw ProfileParsingError(lineNumber, "No values specified for Camera location"); - } Profile::CameraType camera = [&](const std::string& type) -> std::variant { @@ -405,13 +416,9 @@ void Profile::saveCurrentSettingsToProfile() { // // Update properties // - //std::vector nodes = - // global::renderEngine.scene()->allSceneGraphNodes(); std::vector changedProps; - //for (SceneGraphNode* n : nodes) { checkForChangedProps(changedProps, &global::rootPropertyOwner); - //} std::vector formattedLines; for (properties::Property* prop : changedProps) { @@ -645,6 +652,8 @@ std::string Profile::serialize() const { Profile::Profile(const std::vector& content) { Section currentSection = Section::None; bool foundVersion = false; + bool foundTime = false; + bool foundCamera = false; for (int lineNum = 1; lineNum <= static_cast(content.size()); ++lineNum) { std::string line = content[lineNum - 1]; @@ -656,8 +665,24 @@ Profile::Profile(const std::vector& content) { switch (currentSection) { case Section::None: currentSection = parseSection(line, lineNum); + + if (!foundVersion && currentSection != Section::Version) { + throw ProfileParsingError( + lineNum, + fmt::format( + "First header in the file must be Version, but got {}", line + ) + ); + } break; case Section::Version: + if (foundVersion) { + throw ProfileParsingError( + lineNum, + "Version section can only appear once per profile" + ); + } + version = parseVersion(line, lineNum); foundVersion = true; break; @@ -686,10 +711,26 @@ Profile::Profile(const std::vector& content) { break; } case Section::Time: + if (foundTime) { + throw ProfileParsingError( + lineNum, + "Time section can only appear once per profile" + ); + } + time = parseTime(line, lineNum); + foundTime = true; break; case Section::Camera: + if (foundCamera) { + throw ProfileParsingError( + lineNum, + "Camera section can only appear once per profile" + ); + } + camera = parseCamera(line, lineNum); + foundCamera = true; break; case Section::MarkNodes: { diff --git a/tests/profile/basic_version_one_component.profile b/tests/profile/basic_version_one_component.profile new file mode 100644 index 0000000000..5f5885ce1d --- /dev/null +++ b/tests/profile/basic_version_one_component.profile @@ -0,0 +1,2 @@ +#Version +100 diff --git a/tests/profile/basic_version_three_components.profile b/tests/profile/basic_version_three_components.profile new file mode 100644 index 0000000000..ccca608644 --- /dev/null +++ b/tests/profile/basic_version_three_components.profile @@ -0,0 +1,2 @@ +#Version +100.200.300 diff --git a/tests/profile/basic_version_two_components.profile b/tests/profile/basic_version_two_components.profile new file mode 100644 index 0000000000..4b3361a6fd --- /dev/null +++ b/tests/profile/basic_version_two_components.profile @@ -0,0 +1,2 @@ +#Version +100.200 diff --git a/tests/profile/default.profile b/tests/profile/default.profile deleted file mode 100644 index 7d10fb2b71..0000000000 --- a/tests/profile/default.profile +++ /dev/null @@ -1,21 +0,0 @@ -#Version -1.0 - -#Asset -scene/solarsystem/planets/earth/earth required -scene/solarsystem/planets/earth/satellites/satellites required - -#Property -setPropertyValue {earth_satellites}.Renderable.Enabled false - -#Time -relative -1d - -#Camera -goToGeo "Earth" 58.5877 16.1924 20000000 - -#MarkNodes -Earth -Mars -Moon -Sun diff --git a/tests/profile/error_camera_gotogeo_too_few_parameters.profile b/tests/profile/error_camera_gotogeo_too_few_parameters.profile new file mode 100644 index 0000000000..cce7f8aa85 --- /dev/null +++ b/tests/profile/error_camera_gotogeo_too_few_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +goToGeo diff --git a/tests/profile/error_camera_gotogeo_too_many_parameters.profile b/tests/profile/error_camera_gotogeo_too_many_parameters.profile new file mode 100644 index 0000000000..9ef08b7d54 --- /dev/null +++ b/tests/profile/error_camera_gotogeo_too_many_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +goToGeo A B C D E diff --git a/tests/profile/error_camera_navstate_too_few_parameters.profile b/tests/profile/error_camera_navstate_too_few_parameters.profile new file mode 100644 index 0000000000..584d7b362f --- /dev/null +++ b/tests/profile/error_camera_navstate_too_few_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +setNavigationState diff --git a/tests/profile/error_camera_navstate_too_many_parameters.profile b/tests/profile/error_camera_navstate_too_many_parameters.profile new file mode 100644 index 0000000000..443cf9ea37 --- /dev/null +++ b/tests/profile/error_camera_navstate_too_many_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +setNavigationState A B C D E F G diff --git a/tests/profile/error_camera_wrong_parameter_value_type.profile b/tests/profile/error_camera_wrong_parameter_value_type.profile new file mode 100644 index 0000000000..71be78c531 --- /dev/null +++ b/tests/profile/error_camera_wrong_parameter_value_type.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Camera +ER diff --git a/tests/profile/error_keybinding_too_few_parameters.profile b/tests/profile/error_keybinding_too_few_parameters.profile new file mode 100644 index 0000000000..c75591d3f6 --- /dev/null +++ b/tests/profile/error_keybinding_too_few_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Keybinding +T diff --git a/tests/profile/error_keybinding_too_many_parameters.profile b/tests/profile/error_keybinding_too_many_parameters.profile new file mode 100644 index 0000000000..0c7b677168 --- /dev/null +++ b/tests/profile/error_keybinding_too_many_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Keybinding +A B C D E F diff --git a/tests/profile/error_keybinding_wrong_parameter_type_local.profile b/tests/profile/error_keybinding_wrong_parameter_type_local.profile new file mode 100644 index 0000000000..6aa4c96de4 --- /dev/null +++ b/tests/profile/error_keybinding_wrong_parameter_type_local.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Keybinding +T T documentation T name T Gui-Path ER T script diff --git a/tests/profile/error_module_too_few_parameters.profile b/tests/profile/error_module_too_few_parameters.profile new file mode 100644 index 0000000000..fbdfbad35c --- /dev/null +++ b/tests/profile/error_module_too_few_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Module +abc-module diff --git a/tests/profile/error_module_too_many_parameters.profile b/tests/profile/error_module_too_many_parameters.profile new file mode 100644 index 0000000000..184c770d31 --- /dev/null +++ b/tests/profile/error_module_too_many_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Module +abc-module diff --git a/tests/profile/error_property_too_few_parameters.profile b/tests/profile/error_property_too_few_parameters.profile new file mode 100644 index 0000000000..94dc7d4941 --- /dev/null +++ b/tests/profile/error_property_too_few_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Property +setPropertyValue diff --git a/tests/profile/error_property_too_many_parameters.profile b/tests/profile/error_property_too_many_parameters.profile new file mode 100644 index 0000000000..71d98f5e42 --- /dev/null +++ b/tests/profile/error_property_too_many_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Property +setPropertyValue property_name_1 property_value_1 diff --git a/tests/profile/error_property_wrong_parameter_value_type.profile b/tests/profile/error_property_wrong_parameter_value_type.profile new file mode 100644 index 0000000000..1bc20b03ab --- /dev/null +++ b/tests/profile/error_property_wrong_parameter_value_type.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Property +unknown-set-property-command property_name_1 property_value_1 diff --git a/tests/profile/error_time_too_few_parameters.profile b/tests/profile/error_time_too_few_parameters.profile new file mode 100644 index 0000000000..75a649fa37 --- /dev/null +++ b/tests/profile/error_time_too_few_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Time +absolute diff --git a/tests/profile/error_time_too_many_parameters.profile b/tests/profile/error_time_too_many_parameters.profile new file mode 100644 index 0000000000..b51e9d2acb --- /dev/null +++ b/tests/profile/error_time_too_many_parameters.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Time +absolute 2020-06-01T12:00:00 diff --git a/tests/profile/error_time_wrong_parameter_value_type.profile b/tests/profile/error_time_wrong_parameter_value_type.profile new file mode 100644 index 0000000000..cea8f3d75c --- /dev/null +++ b/tests/profile/error_time_wrong_parameter_value_type.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Time +ER 2020-06-01T12:00:00 diff --git a/tests/profile/error_two_camera_sections.profile b/tests/profile/error_two_camera_sections.profile new file mode 100644 index 0000000000..556927f461 --- /dev/null +++ b/tests/profile/error_two_camera_sections.profile @@ -0,0 +1,8 @@ +#Version +12.13.14 + +#Camera +setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 + +#Camera +setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 diff --git a/tests/profile/error_two_time_sections.profile b/tests/profile/error_two_time_sections.profile new file mode 100644 index 0000000000..c3376eb6ff --- /dev/null +++ b/tests/profile/error_two_time_sections.profile @@ -0,0 +1,8 @@ +#Version +12.13.14 + +#Time +relative -1d + +#Time +relative -1d diff --git a/tests/profile/error_two_version_sections.profile b/tests/profile/error_two_version_sections.profile new file mode 100644 index 0000000000..c12af6be99 --- /dev/null +++ b/tests/profile/error_two_version_sections.profile @@ -0,0 +1,5 @@ +#Version +12.13.14 + +#Version +22.23.24 diff --git a/tests/profile/error_unrecognized_header.profile b/tests/profile/error_unrecognized_header.profile new file mode 100644 index 0000000000..7f0ecf6a81 --- /dev/null +++ b/tests/profile/error_unrecognized_header.profile @@ -0,0 +1,7 @@ +#Version +12.13.14 + +#Azzet +folder1/folder2/asset require +folder3/folder4/asset2 require variable +folder5/folder6/asset3 request diff --git a/tests/profile/error_version_malformed_component.profile b/tests/profile/error_version_malformed_component.profile new file mode 100644 index 0000000000..96d4c99ce8 --- /dev/null +++ b/tests/profile/error_version_malformed_component.profile @@ -0,0 +1,2 @@ +#Version +abcxyz diff --git a/tests/profile/error_version_not_first.profile b/tests/profile/error_version_not_first.profile new file mode 100644 index 0000000000..5b4fdf8136 --- /dev/null +++ b/tests/profile/error_version_not_first.profile @@ -0,0 +1,7 @@ +#Asset +folder1/folder2/asset require +folder3/folder4/asset2 require variable +folder5/folder6/asset3 request + +#Version +12.13.14 diff --git a/tests/profile/error_version_too_many_components.profile b/tests/profile/error_version_too_many_components.profile new file mode 100644 index 0000000000..4fedeb6d46 --- /dev/null +++ b/tests/profile/error_version_too_many_components.profile @@ -0,0 +1,2 @@ +#Version +1.0.0.0 diff --git a/tests/profile/integration_full_test.profile b/tests/profile/integration_full_test.profile new file mode 100644 index 0000000000..7f0dd12b95 --- /dev/null +++ b/tests/profile/integration_full_test.profile @@ -0,0 +1,40 @@ +#Version +22.21.20 + +#Module +abc-module +def-module +ghi-module + +#Asset +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/earth/satellites/satellites require +folder1/folder2/asset require +folder3/folder4/asset2 require variable +folder5/folder6/asset3 request + +#Property +setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValue property_name_1 property_value_1 +setPropertyValue property_name_2 property_value_2 +setPropertyValue property_name_3 property_value_3 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 + +#Keybinding +T T documentation T name T Gui-Path true T script +U U documentation U name U Gui-Path false U script +CTRL+V CTRL+V documentation CTRL+V name CTRL+V Gui-Path false CTRL+V script + +#Time +relative -1d + +#Camera +goToGeo "Earth" 58.5877 16.1924 2.0e+07 + +#MarkNodes +Earth +Mars +Moon +Sun diff --git a/tests/profile/integration_full_test_permutation_1.profile b/tests/profile/integration_full_test_permutation_1.profile new file mode 100644 index 0000000000..1b78c06c7c --- /dev/null +++ b/tests/profile/integration_full_test_permutation_1.profile @@ -0,0 +1,41 @@ +#Version +22.21.20 + +#MarkNodes +Earth +Mars +Moon +Sun + +#Time +relative -1d + +#Camera +goToGeo "Earth" 58.5877 16.1924 2.0e+07 + +#Property +setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValue property_name_1 property_value_1 +setPropertyValue property_name_2 property_value_2 +setPropertyValue property_name_3 property_value_3 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 + +#Asset +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/earth/satellites/satellites require +folder1/folder2/asset require +folder3/folder4/asset2 require variable +folder5/folder6/asset3 request + +#Keybinding +T T documentation T name T Gui-Path true T script +U U documentation U name U Gui-Path false U script +CTRL+V CTRL+V documentation CTRL+V name CTRL+V Gui-Path false CTRL+V script + +#Module +abc-module +def-module +ghi-module + diff --git a/tests/profile/integration_full_test_permutation_base.profile b/tests/profile/integration_full_test_permutation_base.profile new file mode 100644 index 0000000000..7f0dd12b95 --- /dev/null +++ b/tests/profile/integration_full_test_permutation_base.profile @@ -0,0 +1,40 @@ +#Version +22.21.20 + +#Module +abc-module +def-module +ghi-module + +#Asset +scene/solarsystem/planets/earth/earth require +scene/solarsystem/planets/earth/satellites/satellites require +folder1/folder2/asset require +folder3/folder4/asset2 require variable +folder5/folder6/asset3 request + +#Property +setPropertyValue {earth_satellites}.Renderable.Enabled false +setPropertyValue property_name_1 property_value_1 +setPropertyValue property_name_2 property_value_2 +setPropertyValue property_name_3 property_value_3 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 +setPropertyValueSingle property_name_4 property_value_5 + +#Keybinding +T T documentation T name T Gui-Path true T script +U U documentation U name U Gui-Path false U script +CTRL+V CTRL+V documentation CTRL+V name CTRL+V Gui-Path false CTRL+V script + +#Time +relative -1d + +#Camera +goToGeo "Earth" 58.5877 16.1924 2.0e+07 + +#MarkNodes +Earth +Mars +Moon +Sun diff --git a/tests/profile/test1.asset b/tests/profile/test1.asset deleted file mode 100644 index 3acea7c194..0000000000 --- a/tests/profile/test1.asset +++ /dev/null @@ -1 +0,0 @@ -assert (true) \ No newline at end of file diff --git a/tests/profile/test2.asset b/tests/profile/test2.asset deleted file mode 100644 index 3acea7c194..0000000000 --- a/tests/profile/test2.asset +++ /dev/null @@ -1 +0,0 @@ -assert (true) \ No newline at end of file diff --git a/tests/profile/test2.profile b/tests/profile/test2.profile deleted file mode 100644 index c5e8fab1c3..0000000000 --- a/tests/profile/test2.profile +++ /dev/null @@ -1,23 +0,0 @@ -#Version -1.0 - -#Asset -scene/solarsystem/planets/earth/earth required -scene/solarsystem/planets/earth/satellites/satellites required - -#Property -setPropertyValue {earth_satellites}.Renderable.Enabled false -setPropertyValueSingle Scene.Pluto.Renderable.Enabled false -setPropertyValueSingle Scene.Charon.Renderable.Enabled false - -#Time -relative -1d - -#Camera -goToGeo "Earth" 58.5877 16.1924 20000000 - -#MarkNodes -Earth -Mars -Moon -Sun diff --git a/tests/profile/test3.asset b/tests/profile/test3.asset deleted file mode 100644 index 3acea7c194..0000000000 --- a/tests/profile/test3.asset +++ /dev/null @@ -1 +0,0 @@ -assert (true) \ No newline at end of file diff --git a/tests/profile/test4.asset b/tests/profile/test4.asset deleted file mode 100644 index 3acea7c194..0000000000 --- a/tests/profile/test4.asset +++ /dev/null @@ -1 +0,0 @@ -assert (true) \ No newline at end of file diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp index bc25117b7d..ae8a76089b 100644 --- a/tests/profile/test_profile.cpp +++ b/tests/profile/test_profile.cpp @@ -45,12 +45,17 @@ #include #include +#include #include using namespace openspace; namespace { Profile loadProfile(const std::string& filename) { + if (!std::filesystem::exists(absPath(filename))) { + throw std::runtime_error("Could not find file)"); + } + std::ifstream f(absPath(filename)); std::vector lines; @@ -72,6 +77,9 @@ namespace { } } // namespace +// +// Minimal +// TEST_CASE("Minimal", "[profile]") { constexpr const char* TestFile = "${TESTDIR}/profile/minimal.profile"; Profile p = loadProfile(TestFile); @@ -82,6 +90,39 @@ TEST_CASE("Minimal", "[profile]") { REQUIRE(serialized == contents); } +// +// Basic functionality +// +TEST_CASE("Basic Version One Component", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/basic_version_one_component.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + constexpr const char* contents = "#Version\n100.0.0\n"; + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Version Two Components", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/basic_version_two_components.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + constexpr const char* contents = "#Version\n100.200.0\n"; + REQUIRE(serialized == contents); +} + +TEST_CASE("Basic Version Three Components", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/basic_version_three_components.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + constexpr const char* contents = "#Version\n100.200.300\n"; + REQUIRE(serialized == contents); +} + TEST_CASE("Basic Module", "[profile]") { constexpr const char* TestFile = "${TESTDIR}/profile/basic_modules.profile"; Profile p = loadProfile(TestFile); @@ -183,308 +224,257 @@ TEST_CASE("Basic Mark Nodes", "[profile]") { REQUIRE(serialized == contents); } -//namespace { -// int passTest(lua_State* state) { -// bool* test = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); -// *test = true; -// return 0; -// } -//} // namespace // -//class Profile2 : public Profile { -//public: -// Profile2(AssetLoader& refAssetLoader) : _assLoader(refAssetLoader) {} -// std::string currentTimeUTC() const override { -// return "2020-02-29T01:23:45.00"; -// } -// interaction::NavigationHandler::NavigationState currentCameraState() const override { -// interaction::NavigationHandler::NavigationState n; -// n.anchor = "Earth"; -// n.aim = "Sun"; -// n.referenceFrame = "root"; -// n.position = {-1.0, -2.0, -3.0}; -// n.up = {0.0, 0.0, 1.0}; -// n.pitch = 0.0; -// n.yaw = 0.0; -// return n; -// } -// void addPropertiesMarkedAsChanged(std::string formattedLine) { -// _scenegraphProps.push_back(formattedLine); -// } -// std::vector changedPropertiesFormatted() override { -// std::vector formattedLines; -// for (std::string s : _scenegraphProps) { -// formattedLines.push_back(s); -// } -// return formattedLines; -// } -// bool usingProfile() const override { -// return true; -// } -// std::string initialProfile() const override { -// return _initProfile; -// } -// void setInitialProfile(std::string file) { -// _initProfile = file; -// } -// std::vector assetEvents() const override { -// return _assLoader.assetEvents(); -// } -// void setProfileBaseDirectory(std::string dir) { -// _profileBaseDirectory = dir; -// } -//private: -// std::vector _scenegraphProps; -// std::string _initProfile; -// AssetLoader& _assLoader; -//}; +// Integration // -//static void addLineHeaderForFailureMessage(std::string& s, size_t lineNumber) { -// s = "@line " + std::to_string(lineNumber) + ": '" + s + "'"; -//} +TEST_CASE("Integration Full Test", "[profile]") { + constexpr const char* TestFile = "${TESTDIR}/profile/integration_full_test.profile"; + Profile p = loadProfile(TestFile); + + std::string serialized = p.serialize(); + std::string contents = loadFile(TestFile); + + REQUIRE(serialized == contents); +} + +TEST_CASE("Integration Full Test Permutation 1", "[profile]") { + constexpr const char* TestFileOriginal = + "${TESTDIR}/profile/integration_full_test_permutation_base.profile"; + constexpr const char* TestFilePermutation = + "${TESTDIR}/profile/integration_full_test_permutation_1.profile"; + Profile original = loadProfile(TestFileOriginal); + Profile permutation = loadProfile(TestFilePermutation); + + std::string originalSerialized = original.serialize(); + std::string permutationSerialized = permutation.serialize(); + REQUIRE(originalSerialized == permutationSerialized); +} + // -//TEST_CASE("profile: Convert profileFile to asset", "[profile]") { -// testProfileFormat test = buildTestProfile1(); -// std::string testFull_string = stringFromTestProfileFormat(test); -// std::string testFilePath = absPath("${TEMPORARY}/test-profile-convert.profile"); -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } +// Adding assets // -// ProfileFile pf(testFilePath); -// Profile p; -// REQUIRE_NOTHROW( -// p.convertToScene(pf) -// ); -//} + + // -//TEST_CASE("profile: Verify conversion to scene", "[profile]") { -// std::istringstream iss(newHorizonsProfileInput); -// ProfileFile pf(newHorizonsProfileInput); -// Profile p; -// std::string result; -// REQUIRE_NOTHROW( -// result = p.convertToScene(pf) -// ); -// -// if (result != newHorizonsExpectedSceneOutput) { -// std::string testing, comparing; -// StringPerLineReader sr_result(result); -// StringPerLineReader sr_standard(newHorizonsExpectedSceneOutput); +// Error states // -// size_t lineN = 1; -// while (sr_result.getNextLine(testing)) { -// sr_standard.getNextLine(comparing); -// addLineHeaderForFailureMessage(testing, lineN); -// addLineHeaderForFailureMessage(comparing, lineN); -// REQUIRE(testing == comparing); -// lineN++; -// } -// //If this fails there are extra lines in the comparison string that weren't in result -// REQUIRE(sr_standard.getNextLine(comparing) == false); -// } -// //REQUIRE(result == newHorizonsExpectedSceneOutput); -//} -// -//TEST_CASE("profile: Detect new properties", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// p.addPropertiesMarkedAsChanged("initialized 1st\t123"); -// p.addPropertiesMarkedAsChanged("initialized 2nd\t3.14159"); -// p.addPropertiesMarkedAsChanged("initialized 3rd\ttested."); -// p.addPropertiesMarkedAsChanged("initialized fourth\tfalse."); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedPropsResult_1); -//} -// -//TEST_CASE("profile: Detect new added assets", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// std::shared_ptr asset = assetLoader.add("initialization"); -// asset->initialize(); -// std::shared_ptr asset2 = assetLoader.add("test2"); -// asset2->initialize(); -// std::shared_ptr asset3 = assetLoader.add("test3"); -// asset3->initialize(); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedAssetsResult_1); -//} -// -//TEST_CASE("profile: Detect new added assets after reset", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// std::shared_ptr asset = assetLoader.add("initialization"); -// asset->initialize(); -// std::shared_ptr asset2 = assetLoader.add("test2"); -// asset2->initialize(); -// assetLoader.resetAssetEvents(); -// std::shared_ptr asset3 = assetLoader.add("test3"); -// asset3->initialize(); -// std::shared_ptr asset4 = assetLoader.add("test4"); -// asset4->initialize(); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedAssetsResult_2); -//} -// -//TEST_CASE("profile: Detect repeat added assets from new", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// std::shared_ptr asset = assetLoader.add("test2"); -// asset->initialize(); -// std::shared_ptr asset2 = assetLoader.add("test4"); -// asset2->initialize(); -// std::shared_ptr asset3 = assetLoader.add("test2"); -// asset3->initialize(); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedAssetsResult_3); -//} -// -//TEST_CASE("profile: Detect repeat added assets from base", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// std::shared_ptr asset = assetLoader.add("test2"); -// asset->initialize(); -// std::shared_ptr asset2 = assetLoader.add("test4"); -// asset2->initialize(); -// std::shared_ptr asset3 = assetLoader.add("scene/solarsystem/planets/earth/earth"); -// asset3->initialize(); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedAssetsResult_4); -//} -// -//TEST_CASE("profile: Detect removed assets not already loaded", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// std::shared_ptr asset = assetLoader.add("test2"); -// asset->initialize(); -// std::shared_ptr asset2 = assetLoader.add("test4"); -// asset2->initialize(); -// assetLoader.remove("test5"); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedAssetsResult_5); -//} -// -//TEST_CASE("profile: Detect removed assets from already loaded", "[profile]") { -// openspace::Scene scene(std::make_unique()); -// ghoul::lua::LuaState* state = openspace::global::scriptEngine.luaState(); -// openspace::SynchronizationWatcher syncWatcher; -// AssetLoader assetLoader( -// state, -// &syncWatcher, -// FileSys.absolutePath("${TESTDIR}/profile/") -// ); -// -// bool passed; -// lua_pushlightuserdata(*state, &passed); -// lua_pushcclosure(*state, &passTest, 1); -// lua_setglobal(*state, "passTest"); -// -// std::shared_ptr asset = assetLoader.add("test2"); -// asset->initialize(); -// std::shared_ptr asset2 = assetLoader.add("test4"); -// asset2->initialize(); -// assetLoader.remove("scene/solarsystem/planets/earth/earth"); -// assetLoader.remove("scene/solarsystem/planets/earth/satellites/satellites"); -// -// Profile2 p(assetLoader); -// p.setProfileBaseDirectory("${TESTDIR}/profile"); -// p.setInitialProfile("test2"); -// std::string output = p.saveCurrentSettingsToProfile_string(); -// REQUIRE(output == detectChangedAssetsResult_6); -//} +TEST_CASE("Error Unrecognized Header", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_unrecognized_header.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Invalid section header") && + Catch::Matchers::Contains("#Azzet") + ); +} + +TEST_CASE("Error version not first header", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_version_not_first.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("First header in the file must be Version") && + Catch::Matchers::Contains("#Asset") + ); +} + +TEST_CASE("Error two version sections", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_two_version_sections.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Version section can only appear once per profile") + ); +} + +TEST_CASE("Error two camera sections", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_two_camera_sections.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Camera section can only appear once per profile") + ); +} + +TEST_CASE("Error two time sections", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_two_time_sections.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Time section can only appear once per profile") + ); +} + +TEST_CASE("Error version malformed component", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_version_malformed_component.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Error parsing Version. Version number is not a number") + ); +} + +TEST_CASE("Error version too many components", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_version_too_many_components.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 1-3 version components, got 4") + ); +} + +TEST_CASE("Error module too few parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_module_too_few_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 3 fields in a Module entry, got 1") + ); +} + +TEST_CASE("Error module too many parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_module_too_many_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 3 fields in a Module entry, got 4") + ); +} + +TEST_CASE("Error profile too few parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_property_too_few_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 3 fields in Property entry, got 1") + ); +} + +TEST_CASE("Error profile too many parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_property_too_many_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 3 fields in Property entry, got 4") + ); +} + +TEST_CASE("Error profile wrong parameter type 'type'", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_property_wrong_parameter_value_type.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains( + "Expected property set type 'setPropertyValue' or " + "'setPropertyValueSingle', got 'unknown-set-property-command'" + ) + ); +} + +TEST_CASE("Error keybinding too few parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_keybinding_too_few_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 6 fields in Keybinding entry, got 1") + ); +} + +TEST_CASE("Error keybinding too many parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_keybinding_too_many_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 6 fields in Keybinding entry, got 7") + ); +} + +TEST_CASE("Error keybinding wrong parameter type 'local'", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_keybinding_wrong_parameter_type_local.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 'false' or 'true' for the local path, got ER") + ); +} + +TEST_CASE("Error time too few parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_time_too_few_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 2 fields in Time entry, got 1") + ); +} + +TEST_CASE("Error time too many parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_time_too_many_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 2 fields in Time entry, got 3") + ); +} + +TEST_CASE("Error time wrong parameter type 'type'", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_time_wrong_parameter_value_type.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains( + "Expected 'absolute' or 'relative' for the type, got ER" + ) + ); +} + +TEST_CASE("Error camera navigation state too few parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_camera_navstate_too_few_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 8 fields in the Camera entry, got 1") + ); +} + +TEST_CASE("Error camera navigation state too many parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_camera_navstate_too_many_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 8 fields in the Camera entry, got 9") + ); +} + +TEST_CASE("Error camera goToGeo too few parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_camera_gotogeo_too_few_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 5 fields in the Camera entry, got 1") + ); +} + +TEST_CASE("Error camera goToGeo too many parameters", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_camera_gotogeo_too_many_parameters.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains("Expected 5 fields in the Camera entry, got 6") + ); +} + +TEST_CASE("Error camera wrong parameter value 'type'", "[profile]") { + constexpr const char* TestFile = + "${TESTDIR}/profile/error_camera_wrong_parameter_value_type.profile"; + REQUIRE_THROWS_WITH( + loadProfile(TestFile), + Catch::Matchers::Contains( + "Expected 'setNavigationState' or 'goToGeo' for the type, got ER" + ) + ); +} + + + + + diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp index 7d1dd24f71..ee144d7b35 100644 --- a/tests/profile/test_profilefile.cpp +++ b/tests/profile/test_profilefile.cpp @@ -32,63 +32,6 @@ //using namespace openspace; -//TEST_CASE("profileFile: Simple read and verify", "[profileFile]") { -// testProfileFormat test = buildTestProfile1(); -// std::string testFile = absPath("${TEMPORARY}/profile-test-simple"); -// { -// std::string testFull_string = stringFromTestProfileFormat(test); -// std::ofstream f(testFile); -// f << testFull_string; -// } -// -// ProfileFile pf(testFile); -// -// std::vector tVect; -// -// REQUIRE(pf.version() == test.tsv[1]); -// REQUIRE(pf.time() == test.tst[1]); -// REQUIRE(pf.camera() == test.tsc[1]); -// tVect = pf.modules(); -// REQUIRE(tVect[0] == test.tsm[1]); -// REQUIRE(tVect[1] == test.tsm[2]); -// REQUIRE(tVect[2] == test.tsm[3]); -// tVect = pf.assets(); -// REQUIRE(tVect[0] == test.tsa[1]); -// REQUIRE(tVect[1] == test.tsa[2]); -// REQUIRE(tVect[2] == test.tsa[3]); -// tVect = pf.properties(); -// REQUIRE(tVect[0] == test.tsp[1]); -// REQUIRE(tVect[1] == test.tsp[2]); -// REQUIRE(tVect[2] == test.tsp[3]); -// REQUIRE(tVect[3] == test.tsp[4]); -// tVect = pf.keybindings(); -// REQUIRE(tVect[0] == test.tsk[1]); -// REQUIRE(tVect[1] == test.tsk[2]); -// REQUIRE(tVect[2] == test.tsk[3]); -// REQUIRE(tVect[3] == test.tsk[4]); -// tVect = pf.markNodes(); -// REQUIRE(tVect[0] == test.tsn[1]); -// REQUIRE(tVect[1] == test.tsn[2]); -// REQUIRE(tVect[2] == test.tsn[3]); -//} -// -//TEST_CASE("profileFile: Unrecognized header", "[profileFile]") { -// std::string testFilePath = absPath("${TEMPORARY}/test-profile-unrec-header.profile"); -// testProfileFormat test = buildTestProfile1(); -// test.tsa[0] = "#Azzet"; -// std::string testFull_string = stringFromTestProfileFormat(test); -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } -// -// REQUIRE_THROWS_WITH( -// ProfileFile(testFilePath), -// Catch::Matchers::Contains("Invalid section header") && -// Catch::Matchers::Contains("#Azzet") -// ); -//} -// //TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { // { // std::string testFilePath = absPath( @@ -128,25 +71,6 @@ // } //} // -//TEST_CASE("profileFile: Too many lines in time entry", "[profileFile]") { -// testProfileFormat test = buildTestProfile1(); -// test.tst.push_back("relative\t\"-1 day\""); -// std::string testFull_string = stringFromTestProfileFormat(test); -// std::string testFilePath = absPath( -// "${TEMPORARY}/test-profile-too-many-lines-time.profile" -// ); -// -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } -// { -// REQUIRE_THROWS_WITH( -// ProfileFile(testFilePath), -// Catch::Matchers::Contains("Too many lines in time section") -// ); -// } -//} // //TEST_CASE("profileFile: Required field missing", "[profileFile]") { // { From a367148b1ddfe44f651a906415f92ba2a62af3ac Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 20 Jun 2020 22:14:10 +0200 Subject: [PATCH 37/61] Remove patch component from profile version --- include/openspace/scene/profile.h | 1 - src/scene/profile.cpp | 11 +- tests/CMakeLists.txt | 6 +- tests/profile/basic_assets.profile | 2 +- tests/profile/basic_camera_gotogeo.profile | 2 +- .../basic_camera_gotogeo_altitude.profile | 2 +- tests/profile/basic_camera_navstate.profile | 2 +- tests/profile/basic_keybindings.profile | 2 +- tests/profile/basic_mark_nodes.profile | 2 +- tests/profile/basic_modules.profile | 2 +- tests/profile/basic_properties.profile | 2 +- tests/profile/basic_time_absolute.profile | 2 +- tests/profile/basic_time_relative.profile | 2 +- .../basic_version_three_components.profile | 2 - ..._camera_gotogeo_too_few_parameters.profile | 2 +- ...camera_gotogeo_too_many_parameters.profile | 2 +- ...camera_navstate_too_few_parameters.profile | 2 +- ...amera_navstate_too_many_parameters.profile | 2 +- ..._camera_wrong_parameter_value_type.profile | 2 +- ...rror_keybinding_too_few_parameters.profile | 2 +- ...ror_keybinding_too_many_parameters.profile | 2 +- ...binding_wrong_parameter_type_local.profile | 2 +- .../error_module_too_few_parameters.profile | 2 +- .../error_module_too_many_parameters.profile | 2 +- .../error_property_too_few_parameters.profile | 2 +- ...error_property_too_many_parameters.profile | 2 +- ...roperty_wrong_parameter_value_type.profile | 2 +- .../error_time_too_few_parameters.profile | 2 +- .../error_time_too_many_parameters.profile | 2 +- ...or_time_wrong_parameter_value_type.profile | 2 +- .../profile/error_two_camera_sections.profile | 2 +- tests/profile/error_two_time_sections.profile | 2 +- .../error_two_version_sections.profile | 4 +- .../profile/error_unrecognized_header.profile | 2 +- tests/profile/error_version_not_first.profile | 2 +- .../error_version_too_many_components.profile | 2 +- tests/profile/initialization.asset | 3 - tests/profile/integration_full_test.profile | 2 +- ...ntegration_full_test_permutation_1.profile | 2 +- ...gration_full_test_permutation_base.profile | 2 +- tests/profile/minimal.profile | 2 +- .../solarsystem/planets/earth/earth.asset | 1 - tests/profile/test_common.cpp | 145 ---- tests/profile/test_common.h | 667 ------------------ tests/profile/test_profile.cpp | 480 ------------- tests/profile/test_profilefile.cpp | 131 ---- 46 files changed, 42 insertions(+), 1479 deletions(-) delete mode 100644 tests/profile/basic_version_three_components.profile delete mode 100644 tests/profile/initialization.asset delete mode 100644 tests/profile/scene/solarsystem/planets/earth/earth.asset delete mode 100644 tests/profile/test_common.cpp delete mode 100644 tests/profile/test_common.h delete mode 100644 tests/profile/test_profile.cpp delete mode 100644 tests/profile/test_profilefile.cpp diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index eb9c7f61b3..cf81fc461e 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -50,7 +50,6 @@ public: struct Version { int major = 0; int minor = 0; - int patch = 0; }; struct Module { std::string name; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index b135542104..104d6a9b9c 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -192,10 +192,10 @@ namespace { [[ nodiscard ]] Profile::Version parseVersion(const std::string& line, int lineNumber) { std::vector parts = ghoul::tokenizeString(line, '.'); - if (parts.size() > 3) { + if (parts.size() > 2) { throw ProfileParsingError( lineNumber, - fmt::format("Expected 1-3 version components, got {}", parts.size()) + fmt::format("Expected 1-2 version components, got {}", parts.size()) ); } @@ -210,9 +210,6 @@ namespace { if (parts.size() > 1) { version.minor = std::stoi(parts[1]); } - if (parts.size() > 2) { - version.patch = std::stoi(parts[2]); - } return version; } catch (const std::invalid_argument&) { @@ -532,9 +529,7 @@ scripting::LuaLibrary Profile::luaLibrary() { std::string Profile::serialize() const { std::string output; output += fmt::format("{}\n", headerVersion); - output += fmt::format( - "{}.{}.{}\n", version.major, version.minor, version.patch - ); + output += fmt::format("{}.{}\n", version.major, version.minor); if (!modules.empty()) { output += fmt::format("\n{}\n", headerModule); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 75e310568c..ddb279b890 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,9 +34,7 @@ add_executable( test_lrucache.cpp test_luaconversions.cpp test_optionproperty.cpp - profile/test_common.cpp - profile/test_profilefile.cpp - profile/test_profile.cpp + test_profile.cpp test_rawvolumeio.cpp test_scriptscheduler.cpp test_spicemanager.cpp @@ -50,7 +48,7 @@ add_executable( set_openspace_compile_settings(OpenSpaceTest) target_include_directories(OpenSpaceTest PUBLIC -"${GHOUL_BASE_DIR}/ext/catch2/single_include" + "${GHOUL_BASE_DIR}/ext/catch2/single_include" ) target_compile_definitions(OpenSpaceTest PUBLIC "GHL_THROW_ON_ASSERT") target_link_libraries(OpenSpaceTest openspace-core) diff --git a/tests/profile/basic_assets.profile b/tests/profile/basic_assets.profile index 62fec23682..55629812d8 100644 --- a/tests/profile/basic_assets.profile +++ b/tests/profile/basic_assets.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Asset folder1/folder2/asset require diff --git a/tests/profile/basic_camera_gotogeo.profile b/tests/profile/basic_camera_gotogeo.profile index cbf5d7f670..ec048ba679 100644 --- a/tests/profile/basic_camera_gotogeo.profile +++ b/tests/profile/basic_camera_gotogeo.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera goToGeo "anchor" 1.0 2.0 diff --git a/tests/profile/basic_camera_gotogeo_altitude.profile b/tests/profile/basic_camera_gotogeo_altitude.profile index 069d94a230..1e2d0f8ba4 100644 --- a/tests/profile/basic_camera_gotogeo_altitude.profile +++ b/tests/profile/basic_camera_gotogeo_altitude.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera goToGeo "anchor" 1.0 2.0 4.0 diff --git a/tests/profile/basic_camera_navstate.profile b/tests/profile/basic_camera_navstate.profile index 02a9783733..e83d7faedf 100644 --- a/tests/profile/basic_camera_navstate.profile +++ b/tests/profile/basic_camera_navstate.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 diff --git a/tests/profile/basic_keybindings.profile b/tests/profile/basic_keybindings.profile index 7f309a4b0f..9e4bb2306f 100644 --- a/tests/profile/basic_keybindings.profile +++ b/tests/profile/basic_keybindings.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Keybinding T T documentation T name T Gui-Path true T script diff --git a/tests/profile/basic_mark_nodes.profile b/tests/profile/basic_mark_nodes.profile index 5deecdfc31..bfd4d6be44 100644 --- a/tests/profile/basic_mark_nodes.profile +++ b/tests/profile/basic_mark_nodes.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #MarkNodes node-1 diff --git a/tests/profile/basic_modules.profile b/tests/profile/basic_modules.profile index 2ba1c93dfb..a33b666a61 100644 --- a/tests/profile/basic_modules.profile +++ b/tests/profile/basic_modules.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Module abc-module diff --git a/tests/profile/basic_properties.profile b/tests/profile/basic_properties.profile index abc6c35ec0..48840fd5c3 100644 --- a/tests/profile/basic_properties.profile +++ b/tests/profile/basic_properties.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Property setPropertyValue property_name_1 property_value_1 diff --git a/tests/profile/basic_time_absolute.profile b/tests/profile/basic_time_absolute.profile index 269a06319a..aa3300facb 100644 --- a/tests/profile/basic_time_absolute.profile +++ b/tests/profile/basic_time_absolute.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Time absolute 2020-06-01T12:00:00 diff --git a/tests/profile/basic_time_relative.profile b/tests/profile/basic_time_relative.profile index 253aff665b..9be50d289f 100644 --- a/tests/profile/basic_time_relative.profile +++ b/tests/profile/basic_time_relative.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Time relative -1d diff --git a/tests/profile/basic_version_three_components.profile b/tests/profile/basic_version_three_components.profile deleted file mode 100644 index ccca608644..0000000000 --- a/tests/profile/basic_version_three_components.profile +++ /dev/null @@ -1,2 +0,0 @@ -#Version -100.200.300 diff --git a/tests/profile/error_camera_gotogeo_too_few_parameters.profile b/tests/profile/error_camera_gotogeo_too_few_parameters.profile index cce7f8aa85..4fcbbe9f1d 100644 --- a/tests/profile/error_camera_gotogeo_too_few_parameters.profile +++ b/tests/profile/error_camera_gotogeo_too_few_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera goToGeo diff --git a/tests/profile/error_camera_gotogeo_too_many_parameters.profile b/tests/profile/error_camera_gotogeo_too_many_parameters.profile index 9ef08b7d54..1d968ac8b6 100644 --- a/tests/profile/error_camera_gotogeo_too_many_parameters.profile +++ b/tests/profile/error_camera_gotogeo_too_many_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera goToGeo A B C D E diff --git a/tests/profile/error_camera_navstate_too_few_parameters.profile b/tests/profile/error_camera_navstate_too_few_parameters.profile index 584d7b362f..4706283410 100644 --- a/tests/profile/error_camera_navstate_too_few_parameters.profile +++ b/tests/profile/error_camera_navstate_too_few_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera setNavigationState diff --git a/tests/profile/error_camera_navstate_too_many_parameters.profile b/tests/profile/error_camera_navstate_too_many_parameters.profile index 443cf9ea37..7b79d8f5b5 100644 --- a/tests/profile/error_camera_navstate_too_many_parameters.profile +++ b/tests/profile/error_camera_navstate_too_many_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera setNavigationState A B C D E F G diff --git a/tests/profile/error_camera_wrong_parameter_value_type.profile b/tests/profile/error_camera_wrong_parameter_value_type.profile index 71be78c531..cacb736f72 100644 --- a/tests/profile/error_camera_wrong_parameter_value_type.profile +++ b/tests/profile/error_camera_wrong_parameter_value_type.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera ER diff --git a/tests/profile/error_keybinding_too_few_parameters.profile b/tests/profile/error_keybinding_too_few_parameters.profile index c75591d3f6..b80118e4a1 100644 --- a/tests/profile/error_keybinding_too_few_parameters.profile +++ b/tests/profile/error_keybinding_too_few_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Keybinding T diff --git a/tests/profile/error_keybinding_too_many_parameters.profile b/tests/profile/error_keybinding_too_many_parameters.profile index 0c7b677168..1a539a8368 100644 --- a/tests/profile/error_keybinding_too_many_parameters.profile +++ b/tests/profile/error_keybinding_too_many_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Keybinding A B C D E F diff --git a/tests/profile/error_keybinding_wrong_parameter_type_local.profile b/tests/profile/error_keybinding_wrong_parameter_type_local.profile index 6aa4c96de4..dd6c29b377 100644 --- a/tests/profile/error_keybinding_wrong_parameter_type_local.profile +++ b/tests/profile/error_keybinding_wrong_parameter_type_local.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Keybinding T T documentation T name T Gui-Path ER T script diff --git a/tests/profile/error_module_too_few_parameters.profile b/tests/profile/error_module_too_few_parameters.profile index fbdfbad35c..b30bacc2a7 100644 --- a/tests/profile/error_module_too_few_parameters.profile +++ b/tests/profile/error_module_too_few_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Module abc-module diff --git a/tests/profile/error_module_too_many_parameters.profile b/tests/profile/error_module_too_many_parameters.profile index 184c770d31..c4735b9847 100644 --- a/tests/profile/error_module_too_many_parameters.profile +++ b/tests/profile/error_module_too_many_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Module abc-module diff --git a/tests/profile/error_property_too_few_parameters.profile b/tests/profile/error_property_too_few_parameters.profile index 94dc7d4941..d25c53a869 100644 --- a/tests/profile/error_property_too_few_parameters.profile +++ b/tests/profile/error_property_too_few_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Property setPropertyValue diff --git a/tests/profile/error_property_too_many_parameters.profile b/tests/profile/error_property_too_many_parameters.profile index 71d98f5e42..b1c0baf3fc 100644 --- a/tests/profile/error_property_too_many_parameters.profile +++ b/tests/profile/error_property_too_many_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Property setPropertyValue property_name_1 property_value_1 diff --git a/tests/profile/error_property_wrong_parameter_value_type.profile b/tests/profile/error_property_wrong_parameter_value_type.profile index 1bc20b03ab..b5471500e9 100644 --- a/tests/profile/error_property_wrong_parameter_value_type.profile +++ b/tests/profile/error_property_wrong_parameter_value_type.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Property unknown-set-property-command property_name_1 property_value_1 diff --git a/tests/profile/error_time_too_few_parameters.profile b/tests/profile/error_time_too_few_parameters.profile index 75a649fa37..3683be625d 100644 --- a/tests/profile/error_time_too_few_parameters.profile +++ b/tests/profile/error_time_too_few_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Time absolute diff --git a/tests/profile/error_time_too_many_parameters.profile b/tests/profile/error_time_too_many_parameters.profile index b51e9d2acb..3b6e14aaff 100644 --- a/tests/profile/error_time_too_many_parameters.profile +++ b/tests/profile/error_time_too_many_parameters.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Time absolute 2020-06-01T12:00:00 diff --git a/tests/profile/error_time_wrong_parameter_value_type.profile b/tests/profile/error_time_wrong_parameter_value_type.profile index cea8f3d75c..f6f071b0b3 100644 --- a/tests/profile/error_time_wrong_parameter_value_type.profile +++ b/tests/profile/error_time_wrong_parameter_value_type.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Time ER 2020-06-01T12:00:00 diff --git a/tests/profile/error_two_camera_sections.profile b/tests/profile/error_two_camera_sections.profile index 556927f461..42088995e6 100644 --- a/tests/profile/error_two_camera_sections.profile +++ b/tests/profile/error_two_camera_sections.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Camera setNavigationState "node" "root" 1.0, 2.0, 3.0 4.0, 5.0, 6.0 diff --git a/tests/profile/error_two_time_sections.profile b/tests/profile/error_two_time_sections.profile index c3376eb6ff..5d41296d14 100644 --- a/tests/profile/error_two_time_sections.profile +++ b/tests/profile/error_two_time_sections.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Time relative -1d diff --git a/tests/profile/error_two_version_sections.profile b/tests/profile/error_two_version_sections.profile index c12af6be99..ae59d5f695 100644 --- a/tests/profile/error_two_version_sections.profile +++ b/tests/profile/error_two_version_sections.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Version -22.23.24 +22.23 diff --git a/tests/profile/error_unrecognized_header.profile b/tests/profile/error_unrecognized_header.profile index 7f0ecf6a81..f9cafb2996 100644 --- a/tests/profile/error_unrecognized_header.profile +++ b/tests/profile/error_unrecognized_header.profile @@ -1,5 +1,5 @@ #Version -12.13.14 +12.13 #Azzet folder1/folder2/asset require diff --git a/tests/profile/error_version_not_first.profile b/tests/profile/error_version_not_first.profile index 5b4fdf8136..ec65de1fba 100644 --- a/tests/profile/error_version_not_first.profile +++ b/tests/profile/error_version_not_first.profile @@ -4,4 +4,4 @@ folder3/folder4/asset2 require variable folder5/folder6/asset3 request #Version -12.13.14 +12.13 diff --git a/tests/profile/error_version_too_many_components.profile b/tests/profile/error_version_too_many_components.profile index 4fedeb6d46..91848a5a2e 100644 --- a/tests/profile/error_version_too_many_components.profile +++ b/tests/profile/error_version_too_many_components.profile @@ -1,2 +1,2 @@ #Version -1.0.0.0 +1.0.0 diff --git a/tests/profile/initialization.asset b/tests/profile/initialization.asset deleted file mode 100644 index 186dee561b..0000000000 --- a/tests/profile/initialization.asset +++ /dev/null @@ -1,3 +0,0 @@ -asset.onInitialize(function () - passTest() -end) \ No newline at end of file diff --git a/tests/profile/integration_full_test.profile b/tests/profile/integration_full_test.profile index 7f0dd12b95..bd5f95b5e9 100644 --- a/tests/profile/integration_full_test.profile +++ b/tests/profile/integration_full_test.profile @@ -1,5 +1,5 @@ #Version -22.21.20 +22.21 #Module abc-module diff --git a/tests/profile/integration_full_test_permutation_1.profile b/tests/profile/integration_full_test_permutation_1.profile index 1b78c06c7c..94facf52d8 100644 --- a/tests/profile/integration_full_test_permutation_1.profile +++ b/tests/profile/integration_full_test_permutation_1.profile @@ -1,5 +1,5 @@ #Version -22.21.20 +22.21 #MarkNodes Earth diff --git a/tests/profile/integration_full_test_permutation_base.profile b/tests/profile/integration_full_test_permutation_base.profile index 7f0dd12b95..bd5f95b5e9 100644 --- a/tests/profile/integration_full_test_permutation_base.profile +++ b/tests/profile/integration_full_test_permutation_base.profile @@ -1,5 +1,5 @@ #Version -22.21.20 +22.21 #Module abc-module diff --git a/tests/profile/minimal.profile b/tests/profile/minimal.profile index 7ec5af0497..6f85c12a1f 100644 --- a/tests/profile/minimal.profile +++ b/tests/profile/minimal.profile @@ -1,2 +1,2 @@ #Version -12.13.14 +12.13 diff --git a/tests/profile/scene/solarsystem/planets/earth/earth.asset b/tests/profile/scene/solarsystem/planets/earth/earth.asset deleted file mode 100644 index 3acea7c194..0000000000 --- a/tests/profile/scene/solarsystem/planets/earth/earth.asset +++ /dev/null @@ -1 +0,0 @@ -assert (true) \ No newline at end of file diff --git a/tests/profile/test_common.cpp b/tests/profile/test_common.cpp deleted file mode 100644 index e334d3f33e..0000000000 --- a/tests/profile/test_common.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 "catch2/catch.hpp" -#include "test_common.h" - -#include "openspace/scene/profile.h" -#include -#include -#include -#include -#include - -using namespace openspace; - -constexpr const char* TestProfile1Text = "" -"#Version\n" -"123.4\n" -"\n" -"#Module\n" -"globebrowsing\t\t\n" -"gaia\tprint(\"success.\")\t\n" -"volume\t\tquit\n" -"\n" -"#Asset" -"scene/solarsystem/planets/earth/moon/moon\trequire\t\n" -"scene/solarsystem/missions/apollo/apollo8\trequest\t\n" -"scene/solarsystem/planets/earth/earth\trequire\t\n" -"\n" -"#Property\n" -"setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000\n" -"setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n" -"setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse\n" -"setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse\n" -"\n" -"#Keybinding\n" -"F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\"\n" -"F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\"\n" -"F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\"\n" -"F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\"\n" -"\n" -"#Time\n" -"absolute\t1977-12-21T12:51:51.0\n" -"\n" -"#Camera\n" -"setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t\n" -"\n" -"#MarkNodes\n" -"Pluto\n" -"NewHorizons\n" -"Charon\n"; - -// -//testProfileFormat buildTestProfile1() { -// testProfileFormat tp1; -// tp1.tsv.push_back("#Version"); -// tp1.tsv.push_back("123.4"); -// tp1.tsm.push_back("#Module"); -// tp1.tsm.push_back("globebrowsing\t\t"); -// tp1.tsm.push_back("gaia\tprint(\"success.\")\t"); -// tp1.tsm.push_back("volume\t\tquit"); -// tp1.tsa.push_back("#Asset"); -// tp1.tsa.push_back("scene/solarsystem/planets/earth/moon/moon\trequired"); -// tp1.tsa.push_back("scene/solarsystem/missions/apollo/apollo8\trequested"); -// tp1.tsa.push_back("scene/solarsystem/planets/earth/earth\t"); -// tp1.tsp.push_back("#Property"); -// tp1.tsp.push_back("setPropertyValue\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000"); -// tp1.tsp.push_back("setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse"); -// tp1.tsp.push_back("setPropertyValue\tScene.Charon.Renderable.Enabled\tfalse"); -// tp1.tsp.push_back("setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse"); -// tp1.tsk.push_back("#Keybinding"); -// tp1.tsk.push_back("F8\tSets the time to the approach at Bennu.\tSet Bennu approach time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Approach'); openspace.time.setTime('2018-SEP-11 21:31:01.183')\""); -// tp1.tsk.push_back("F9\tSets the time to the preliminary survey of Bennu.\tSet Bennu survey time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183')\""); -// tp1.tsk.push_back("F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""); -// tp1.tsk.push_back("F11\tSets the time to the recon event.\tSet recon event time\t/Missions/Osiris Rex\tfalse\t\"openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195')\""); -// tp1.tst.push_back("#Time"); -// tp1.tst.push_back("absolute\t1977-12-21T12:51:51.0"); -// tp1.tsc.push_back("#Camera"); -// tp1.tsc.push_back("setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"); -// tp1.tsn.push_back("#MarkNodes"); -// tp1.tsn.push_back("Pluto"); -// tp1.tsn.push_back("NewHorizons"); -// tp1.tsn.push_back("Charon"); -// -// return tp1; -//} -// -//std::string stringFromSingleProfileSection(std::vector& section, -// bool blankLineSeparator) -//{ -// std::string result; -// for (std::string s : section) { -// result += s + "\n"; -// } -// if (blankLineSeparator) { -// result += "\n"; -// } -// return result; -//} -// -//std::string stringFromTestProfileFormat(testProfileFormat& tpf) { -// std::string fullProfile; -// -// fullProfile += stringFromSingleProfileSection(tpf.tsv, true); -// fullProfile += stringFromSingleProfileSection(tpf.tsm, true); -// fullProfile += stringFromSingleProfileSection(tpf.tsa, true); -// fullProfile += stringFromSingleProfileSection(tpf.tsp, true); -// fullProfile += stringFromSingleProfileSection(tpf.tsk, true); -// fullProfile += stringFromSingleProfileSection(tpf.tst, true); -// fullProfile += stringFromSingleProfileSection(tpf.tsc, true); -// fullProfile += stringFromSingleProfileSection(tpf.tsn, false); -// -// return fullProfile; -//} -// -//StringPerLineReader::StringPerLineReader(std::string s) : _iss(s) { -//} -// -//bool StringPerLineReader::getNextLine(std::string& line) { -// if (getline(_iss, line)) -// return true; -// else -// return false; -//} diff --git a/tests/profile/test_common.h b/tests/profile/test_common.h deleted file mode 100644 index 9ecba1f68b..0000000000 --- a/tests/profile/test_common.h +++ /dev/null @@ -1,667 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_TEST___PROFILE_COMMON___H__ -#define __OPENSPACE_TEST___PROFILE_COMMON___H__ - -//#include "catch2/catch.hpp" -//#include "openspace/scene/profile.h" -//#include -//#include -//#include -//#include -//#include -// -//using namespace openspace; -// -//namespace { -//} -// -//struct testProfileFormat { -// std::vector tsv; -// std::vector tsm; -// std::vector tsa; -// std::vector tsp; -// std::vector tsk; -// std::vector tst; -// std::vector tsc; -// std::vector tsn; -//}; -// -//const std::string newHorizonsProfileInput ="\ -//#Version\n\ -//1.0\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/missions/newhorizons/newhorizons\trequired\n\ -//scene/solarsystem/missions/newhorizons/model\trequired\n\ -//\n\ -//#Property\n\ -//setPropertyValueSingle\tNavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\t20.000000\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.PlutoBarycenterTrail.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//a\tSets the focus of the camera on 'NewHorizons'.\tFocus on New Horizons\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -//SHIFT+a\tSets the focus of the camera on 'NewHorizons'.\tAnchor at New Horizons, Aim at Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -//s\tSets the focus of the camera on 'Pluto'\tFocus on Pluto\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -//d\tSets the focus of the camera on 'Charon'.\tFocus on New Charon\t/New Horizons\tfalse\t\"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -//F7\tToggles New Horizons image projection.\tToggle NH Image Projection\t/New Horizons\tfalse\t[[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ -//F8\tRemoves all image projections from Pluto and Charon.\tClear image projections\t/New Horizons\tfalse\t\"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ -//F9\tJumps to the 14th of July 2015 at 0900 UTC and clears all projections.\tReset time and projections\t/New Horizons\tfalse\t\"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ -//KP_8\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -//CTRL+I\tIncreases the height map exaggeration on Pluto.\tPluto HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -//KP_2\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -//CTRL+K\tDecreases the height map exaggeration on Pluto.\tPluto HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -//KP_9\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -//CTRL+O\tIncreases the height map exaggeration on Charon.\tCharon HeightExaggeration +\t/New Horizons\tfalse\tpropertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -//KP_3\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -//CTRL+L\tDecreases the height map exaggeration on Charon.\tCharon HeightExaggeration -\t/New Horizons\tfalse\tpropertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -//o\tToggles the visibility of the trail behind Pluto.\tToggle Pluto Trail\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ -//j\tToggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\tToggle Pluto Labels\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ -//l\tToggles the visibility of the labels for the New Horizons instruments.\tToggle New Horizons Labels\t/New Horizons\tfalse\tpropertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ -//m\tDraws the instrument field of views in a solid color or as lines.\tToggle instrument FOVs\t/New Horizons\tfalse\tpropertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ -//Shift+t\tToggles the visibility of the shadow visualization of Pluto and Charon.\tToggle Shadows\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ -//t\tToggles the trail of New Horizons.\tToggle NH Trail\t/New Horizons\tfalse\trenderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ -//h\tDisables visibility of the trails\tHide Trails\t/Rendering\tfalse\t\"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ -//1\tSetting the simulation speed to 1 seconds per realtime second\tSet sim speed 1\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1)\"\n\ -//2\tSetting the simulation speed to 5 seconds per realtime second\tSet sim speed 5\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(5)\"\n\ -//3\tSetting the simulation speed to 10 seconds per realtime second\tSet sim speed 10\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(10)\"\n\ -//4\tSetting the simulation speed to 20 seconds per realtime second\tSet sim speed 20\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(20)\"\n\ -//5\tSetting the simulation speed to 40 seconds per realtime second\tSet sim speed 40\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(40)\"\n\ -//6\tSetting the simulation speed to 60 seconds per realtime second\tSet sim speed 60\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(60)\"\n\ -//7\tSetting the simulation speed to 120 seconds per realtime second\tSet sim speed 120\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(120)\"\n\ -//8\tSetting the simulation speed to 360 seconds per realtime second\tSet sim speed 360\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(360)\"\n\ -//9\tSetting the simulation speed to 540 seconds per realtime second\tSet sim speed 540\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(540)\"\n\ -//0\tSetting the simulation speed to 1080 seconds per realtime second\tSet sim speed 1080\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(1080)\"\n\ -//Shift+1\tSetting the simulation speed to 2160 seconds per realtime second\tSet sim speed 2160\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(2160)\"\n\ -//Shift+2\tSetting the simulation speed to 4320 seconds per realtime second\tSet sim speed 4320\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(4320)\"\n\ -//Shift+3\tSetting the simulation speed to 8640 seconds per realtime second\tSet sim speed 8640\t/Simulation Speed\tfalse\t\"openspace.time.interpolateDeltaTime(8640)\"\n\ -//\n\ -//#Time\n\ -//absolute\t2015-07-14T08:00:00.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t\n\ -//\n\ -//#MarkNodes\n\ -//Pluto\n\ -//NewHorizons\n\ -//Charon"; -// -//const std::string newHorizonsExpectedSceneOutput = "\ -//\n\ -//asset.require(\"base\");\n\ -//local assetHelper = asset.require(\"util/asset_helper\")\n\ -//local propertyHelper = asset.require(\"util/property_helper\")\n\ -//local sceneHelper = asset.require(\"util/scene_helper\")\n\ -//local renderableHelper = asset.require(\"util/renderable_helper\")\n\ -//asset.require(\"scene/solarsystem/missions/newhorizons/newhorizons\")\n\ -//asset.require(\"scene/solarsystem/missions/newhorizons/model\")\n\ -//\n\ -//local Keybindings = {\n\ -// {\n\ -// Key = \"a\",\n\ -// Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ -// Name = \"Focus on New Horizons\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -// },\n\ -// {\n\ -// Key = \"SHIFT+a\",\n\ -// Documentation = \"Sets the focus of the camera on 'NewHorizons'.\",\n\ -// Name = \"Anchor at New Horizons, Aim at Pluto\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -// },\n\ -// {\n\ -// Key = \"s\",\n\ -// Documentation = \"Sets the focus of the camera on 'Pluto'\",\n\ -// Name = \"Focus on Pluto\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Pluto') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -// },\n\ -// {\n\ -// Key = \"d\",\n\ -// Documentation = \"Sets the focus of the camera on 'Charon'.\",\n\ -// Name = \"Focus on New Charon\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = \"openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)\"\n\ -// },\n\ -// {\n\ -// Key = \"F7\",\n\ -// Documentation = \"Toggles New Horizons image projection.\",\n\ -// Name = \"Toggle NH Image Projection\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = [[local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled)]]\n\ -// },\n\ -// {\n\ -// Key = \"F8\",\n\ -// Documentation = \"Removes all image projections from Pluto and Charon.\",\n\ -// Name = \"Clear image projections\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = \"openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ -// },\n\ -// {\n\ -// Key = \"F9\",\n\ -// Documentation = \"Jumps to the 14th of July 2015 at 0900 UTC and clears all projections.\",\n\ -// Name = \"Reset time and projections\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true)\"\n\ -// },\n\ -// {\n\ -// Key = \"KP_8\",\n\ -// Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ -// Name = \"Pluto HeightExaggeration +\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"CTRL+I\",\n\ -// Documentation = \"Increases the height map exaggeration on Pluto.\",\n\ -// Name = \"Pluto HeightExaggeration +\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.increment('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"KP_2\",\n\ -// Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ -// Name = \"Pluto HeightExaggeration -\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"CTRL+K\",\n\ -// Documentation = \"Decreases the height map exaggeration on Pluto.\",\n\ -// Name = \"Pluto HeightExaggeration -\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.decrement('Scene.PlutoProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"KP_9\",\n\ -// Documentation = \"Increases the height map exaggeration on Charon.\",\n\ -// Name = \"Charon HeightExaggeration +\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"CTRL+O\",\n\ -// Documentation = \"Increases the height map exaggeration on Charon.\",\n\ -// Name = \"Charon HeightExaggeration +\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.increment('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"KP_3\",\n\ -// Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ -// Name = \"Charon HeightExaggeration -\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"CTRL+L\",\n\ -// Documentation = \"Decreases the height map exaggeration on Charon.\",\n\ -// Name = \"Charon HeightExaggeration -\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.decrement('Scene.CharonProjection.Renderable.HeightExaggeration', 5000)\n\ -// },\n\ -// {\n\ -// Key = \"o\",\n\ -// Documentation = \"Toggles the visibility of the trail behind Pluto.\",\n\ -// Name = \"Toggle Pluto Trail\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.invert('Scene.PlutoBarycentricTrail.Renderable.Enabled')\n\ -// },\n\ -// {\n\ -// Key = \"j\",\n\ -// Documentation = \"Toggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.\",\n\ -// Name = \"Toggle Pluto Labels\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = renderableHelper.toggle('Scene.PlutoText') .. renderableHelper.toggle('Scene.CharonText') .. renderableHelper.toggle('Scene.HydraText') .. renderableHelper.toggle('Scene.NixText') .. renderableHelper.toggle('Scene.KerberosText') .. renderableHelper.toggle('Scene.StyxText')\n\ -// },\n\ -// {\n\ -// Key = \"l\",\n\ -// Documentation = \"Toggles the visibility of the labels for the New Horizons instruments.\",\n\ -// Name = \"Toggle New Horizons Labels\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.fadeInOut('Scene.Labels.Renderable.Opacity', 2.0)\n\ -// },\n\ -// {\n\ -// Key = \"m\",\n\ -// Documentation = \"Draws the instrument field of views in a solid color or as lines.\",\n\ -// Name = \"Toggle instrument FOVs\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = propertyHelper.invert('Scene.NH_LORRI.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_LEISA.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw') .. propertyHelper.invert('Scene.NH_ALICE_SOC.Renderable.SolidDraw')\n\ -// },\n\ -// {\n\ -// Key = \"Shift+t\",\n\ -// Documentation = \"Toggles the visibility of the shadow visualization of Pluto and Charon.\",\n\ -// Name = \"Toggle Shadows\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = renderableHelper.toggle('Scene.PlutoShadow') .. renderableHelper.toggle('Scene.CharonShadow')\n\ -// },\n\ -// {\n\ -// Key = \"t\",\n\ -// Documentation = \"Toggles the trail of New Horizons.\",\n\ -// Name = \"Toggle NH Trail\",\n\ -// GuiPath = \"/New Horizons\",\n\ -// Local = false,\n\ -// Command = renderableHelper.toggle('Scene.NewHorizonsTrailPluto')\n\ -// },\n\ -// {\n\ -// Key = \"h\",\n\ -// Documentation = \"Disables visibility of the trails\",\n\ -// Name = \"Hide Trails\",\n\ -// GuiPath = \"/Rendering\",\n\ -// Local = false,\n\ -// Command = \"local list = openspace.getProperty('*Trail.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\"\n\ -// },\n\ -// {\n\ -// Key = \"1\",\n\ -// Documentation = \"Setting the simulation speed to 1 seconds per realtime second\",\n\ -// Name = \"Set sim speed 1\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(1)\"\n\ -// },\n\ -// {\n\ -// Key = \"2\",\n\ -// Documentation = \"Setting the simulation speed to 5 seconds per realtime second\",\n\ -// Name = \"Set sim speed 5\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(5)\"\n\ -// },\n\ -// {\n\ -// Key = \"3\",\n\ -// Documentation = \"Setting the simulation speed to 10 seconds per realtime second\",\n\ -// Name = \"Set sim speed 10\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(10)\"\n\ -// },\n\ -// {\n\ -// Key = \"4\",\n\ -// Documentation = \"Setting the simulation speed to 20 seconds per realtime second\",\n\ -// Name = \"Set sim speed 20\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(20)\"\n\ -// },\n\ -// {\n\ -// Key = \"5\",\n\ -// Documentation = \"Setting the simulation speed to 40 seconds per realtime second\",\n\ -// Name = \"Set sim speed 40\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(40)\"\n\ -// },\n\ -// {\n\ -// Key = \"6\",\n\ -// Documentation = \"Setting the simulation speed to 60 seconds per realtime second\",\n\ -// Name = \"Set sim speed 60\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(60)\"\n\ -// },\n\ -// {\n\ -// Key = \"7\",\n\ -// Documentation = \"Setting the simulation speed to 120 seconds per realtime second\",\n\ -// Name = \"Set sim speed 120\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(120)\"\n\ -// },\n\ -// {\n\ -// Key = \"8\",\n\ -// Documentation = \"Setting the simulation speed to 360 seconds per realtime second\",\n\ -// Name = \"Set sim speed 360\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(360)\"\n\ -// },\n\ -// {\n\ -// Key = \"9\",\n\ -// Documentation = \"Setting the simulation speed to 540 seconds per realtime second\",\n\ -// Name = \"Set sim speed 540\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(540)\"\n\ -// },\n\ -// {\n\ -// Key = \"0\",\n\ -// Documentation = \"Setting the simulation speed to 1080 seconds per realtime second\",\n\ -// Name = \"Set sim speed 1080\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(1080)\"\n\ -// },\n\ -// {\n\ -// Key = \"Shift+1\",\n\ -// Documentation = \"Setting the simulation speed to 2160 seconds per realtime second\",\n\ -// Name = \"Set sim speed 2160\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(2160)\"\n\ -// },\n\ -// {\n\ -// Key = \"Shift+2\",\n\ -// Documentation = \"Setting the simulation speed to 4320 seconds per realtime second\",\n\ -// Name = \"Set sim speed 4320\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(4320)\"\n\ -// },\n\ -// {\n\ -// Key = \"Shift+3\",\n\ -// Documentation = \"Setting the simulation speed to 8640 seconds per realtime second\",\n\ -// Name = \"Set sim speed 8640\",\n\ -// GuiPath = \"/Simulation Speed\",\n\ -// Local = false,\n\ -// Command = \"openspace.time.interpolateDeltaTime(8640)\"\n\ -// },\n\ -//}\n\ -//\n\ -//asset.onInitialize(function ()\n\ -// openspace.time.setTime(\"2015-07-14T08:00:00.00\")\n\ -//\n\ -// sceneHelper.bindKeys(Keybindings)\n\ -//\n\ -// openspace.markInterestingNodes({\"Pluto\", \"NewHorizons\", \"Charon\", })\n\ -//\n\ -// openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.FollowAnchorNodeRotationDistance\", 20.000000)\n\ -// openspace.setPropertyValueSingle(\"Scene.Pluto.Renderable.Enabled\", false)\n\ -// openspace.setPropertyValueSingle(\"Scene.Charon.Renderable.Enabled\", false)\n\ -// openspace.setPropertyValueSingle(\"Scene.PlutoBarycenterTrail.Renderable.Enabled\", false)\n\ -//\n\ -// openspace.navigation.setNavigationState({Anchor = \"NewHorizons\", ReferenceFrame = \"Root\", Position = {-6.572656E1, -7.239404E1, -2.111890E1}, Up = {0.102164, -0.362945, 0.926193}, })\n\ -//end)"; -// -//const std::string detectChangedPropsResult_1 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//initialized 1st\t123\n\ -//initialized 2nd\t3.14159\n\ -//initialized 3rd\ttested.\n\ -//initialized fourth\tfalse.\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//const std::string detectChangedAssetsResult_1 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//initialization\trequested\n\ -//test2\trequested\n\ -//test3\trequested\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//const std::string detectChangedAssetsResult_2 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//test3\trequested\n\ -//test4\trequested\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//const std::string detectChangedAssetsResult_3 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//test2\trequested\n\ -//test4\trequested\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//const std::string detectChangedAssetsResult_4 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//test2\trequested\n\ -//test4\trequested\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//const std::string detectChangedAssetsResult_5 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//test2\trequested\n\ -//test4\trequested\n\ -//test5\tremoved\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//const std::string detectChangedAssetsResult_6 = "\ -//#Version\n\ -//" + std::string(Profile::FormatVersion) + "\n\ -//\n\ -//#Module\n\ -//\n\ -//#Asset\n\ -//scene/solarsystem/planets/earth/earth\trequired\n\ -//scene/solarsystem/planets/earth/satellites/satellites\trequired\n\ -//test2\trequested\n\ -//test4\trequested\n\ -//scene/solarsystem/planets/earth/earth\tremoved\n\ -//scene/solarsystem/planets/earth/satellites/satellites\tremoved\n\ -//\n\ -//#Property\n\ -//setPropertyValue\t{earth_satellites}.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Pluto.Renderable.Enabled\tfalse\n\ -//setPropertyValueSingle\tScene.Charon.Renderable.Enabled\tfalse\n\ -//\n\ -//#Keybinding\n\ -//\n\ -//#Time\n\ -//absolute\t2020-02-29T01:23:45.00\n\ -//\n\ -//#Camera\n\ -//setNavigationState\t\"Earth\"\t\"Sun\"\t\"root\"\t-1.000000,-2.000000,-3.000000\t0.000000,0.000000,1.000000\t0.000000\t0.000000\n\ -//\n\ -//#MarkNodes\n\ -//Earth\n\ -//Mars\n\ -//Moon\n\ -//Sun\n\ -//"; -// -//testProfileFormat buildTestProfile1(); -//std::string stringFromSingleProfileSection(std::vector& section, -// bool blankLineSeparator); -//std::string stringFromTestProfileFormat(testProfileFormat& tpf); -//ProfileFile makeProfileFromString(std::string s); -// -//class StringPerLineReader { -//public: -// StringPerLineReader(std::string s); -// bool getNextLine(std::string& line); -// -//private: -// std::istringstream _iss; -//}; -// -#endif //__OPENSPACE_TEST___PROFILE_COMMON___H__ diff --git a/tests/profile/test_profile.cpp b/tests/profile/test_profile.cpp deleted file mode 100644 index ae8a76089b..0000000000 --- a/tests/profile/test_profile.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 "catch2/catch.hpp" -//#include "test_common.h" -//#include -//#include -//#include -// -//#include -//#include -//#include "openspace/scene/profile.h" -//#include -//#include -//#include -//#include -//#include -//#include -// -//#include -//#include -//#include - - -#include -#include -#include -#include - -using namespace openspace; - -namespace { - Profile loadProfile(const std::string& filename) { - if (!std::filesystem::exists(absPath(filename))) { - throw std::runtime_error("Could not find file)"); - } - - std::ifstream f(absPath(filename)); - - std::vector lines; - std::string line; - while (std::getline(f, line)) { - lines.push_back(std::move(line)); - } - - return Profile(lines); - } - - std::string loadFile(const std::string& filename) { - std::ifstream f(absPath(filename)); - std::string content( - (std::istreambuf_iterator(f)), - std::istreambuf_iterator() - ); - return content; - } -} // namespace - -// -// Minimal -// -TEST_CASE("Minimal", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/minimal.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -// -// Basic functionality -// -TEST_CASE("Basic Version One Component", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/basic_version_one_component.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - constexpr const char* contents = "#Version\n100.0.0\n"; - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Version Two Components", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/basic_version_two_components.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - constexpr const char* contents = "#Version\n100.200.0\n"; - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Version Three Components", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/basic_version_three_components.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - constexpr const char* contents = "#Version\n100.200.300\n"; - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Module", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_modules.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Assets", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_assets.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Properties", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_properties.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Keybindings", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_keybindings.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Time Relative", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_time_relative.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Time Absolute", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_time_absolute.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Camera NavState", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_camera_navstate.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Camera GoToGeo", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_camera_gotogeo.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Camera GoToGeo altitude", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/basic_camera_gotogeo_altitude.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Basic Mark Nodes", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/basic_mark_nodes.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -// -// Integration -// -TEST_CASE("Integration Full Test", "[profile]") { - constexpr const char* TestFile = "${TESTDIR}/profile/integration_full_test.profile"; - Profile p = loadProfile(TestFile); - - std::string serialized = p.serialize(); - std::string contents = loadFile(TestFile); - - REQUIRE(serialized == contents); -} - -TEST_CASE("Integration Full Test Permutation 1", "[profile]") { - constexpr const char* TestFileOriginal = - "${TESTDIR}/profile/integration_full_test_permutation_base.profile"; - constexpr const char* TestFilePermutation = - "${TESTDIR}/profile/integration_full_test_permutation_1.profile"; - Profile original = loadProfile(TestFileOriginal); - Profile permutation = loadProfile(TestFilePermutation); - - std::string originalSerialized = original.serialize(); - std::string permutationSerialized = permutation.serialize(); - REQUIRE(originalSerialized == permutationSerialized); -} - -// -// Adding assets -// - - -// -// Error states -// -TEST_CASE("Error Unrecognized Header", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_unrecognized_header.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Invalid section header") && - Catch::Matchers::Contains("#Azzet") - ); -} - -TEST_CASE("Error version not first header", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_version_not_first.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("First header in the file must be Version") && - Catch::Matchers::Contains("#Asset") - ); -} - -TEST_CASE("Error two version sections", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_two_version_sections.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Version section can only appear once per profile") - ); -} - -TEST_CASE("Error two camera sections", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_two_camera_sections.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Camera section can only appear once per profile") - ); -} - -TEST_CASE("Error two time sections", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_two_time_sections.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Time section can only appear once per profile") - ); -} - -TEST_CASE("Error version malformed component", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_version_malformed_component.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Error parsing Version. Version number is not a number") - ); -} - -TEST_CASE("Error version too many components", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_version_too_many_components.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 1-3 version components, got 4") - ); -} - -TEST_CASE("Error module too few parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_module_too_few_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 3 fields in a Module entry, got 1") - ); -} - -TEST_CASE("Error module too many parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_module_too_many_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 3 fields in a Module entry, got 4") - ); -} - -TEST_CASE("Error profile too few parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_property_too_few_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 3 fields in Property entry, got 1") - ); -} - -TEST_CASE("Error profile too many parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_property_too_many_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 3 fields in Property entry, got 4") - ); -} - -TEST_CASE("Error profile wrong parameter type 'type'", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_property_wrong_parameter_value_type.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains( - "Expected property set type 'setPropertyValue' or " - "'setPropertyValueSingle', got 'unknown-set-property-command'" - ) - ); -} - -TEST_CASE("Error keybinding too few parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_keybinding_too_few_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 6 fields in Keybinding entry, got 1") - ); -} - -TEST_CASE("Error keybinding too many parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_keybinding_too_many_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 6 fields in Keybinding entry, got 7") - ); -} - -TEST_CASE("Error keybinding wrong parameter type 'local'", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_keybinding_wrong_parameter_type_local.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 'false' or 'true' for the local path, got ER") - ); -} - -TEST_CASE("Error time too few parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_time_too_few_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 2 fields in Time entry, got 1") - ); -} - -TEST_CASE("Error time too many parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_time_too_many_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 2 fields in Time entry, got 3") - ); -} - -TEST_CASE("Error time wrong parameter type 'type'", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_time_wrong_parameter_value_type.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains( - "Expected 'absolute' or 'relative' for the type, got ER" - ) - ); -} - -TEST_CASE("Error camera navigation state too few parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_camera_navstate_too_few_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 8 fields in the Camera entry, got 1") - ); -} - -TEST_CASE("Error camera navigation state too many parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_camera_navstate_too_many_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 8 fields in the Camera entry, got 9") - ); -} - -TEST_CASE("Error camera goToGeo too few parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_camera_gotogeo_too_few_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 5 fields in the Camera entry, got 1") - ); -} - -TEST_CASE("Error camera goToGeo too many parameters", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_camera_gotogeo_too_many_parameters.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains("Expected 5 fields in the Camera entry, got 6") - ); -} - -TEST_CASE("Error camera wrong parameter value 'type'", "[profile]") { - constexpr const char* TestFile = - "${TESTDIR}/profile/error_camera_wrong_parameter_value_type.profile"; - REQUIRE_THROWS_WITH( - loadProfile(TestFile), - Catch::Matchers::Contains( - "Expected 'setNavigationState' or 'goToGeo' for the type, got ER" - ) - ); -} - - - - - diff --git a/tests/profile/test_profilefile.cpp b/tests/profile/test_profilefile.cpp deleted file mode 100644 index ee144d7b35..0000000000 --- a/tests/profile/test_profilefile.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2020 * - * * - * 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 "catch2/catch.hpp" - -#include "test_common.h" -#include -#include -#include -#include - -//using namespace openspace; - -//TEST_CASE("profileFile: Bad number of fields", "[profileFile]") { -// { -// std::string testFilePath = absPath( -// "${TEMPORARY}/test-profile-bad-n-fields-1.profile" -// ); -// testProfileFormat test = buildTestProfile1(); -// test.tsm[1] = "globebrowsing\t\t\t"; -// std::string testFull_string = stringFromTestProfileFormat(test); -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } -// REQUIRE_THROWS_WITH( -// ProfileFile(testFilePath), -// Catch::Matchers::Contains("fields required in a Module entry") -// ); -// } -// -// { -// std::string testFilePath = absPath( -// "${TEMPORARY}/test-profile-bad-n-fields-2.profile" -// ); -// -// testProfileFormat test = buildTestProfile1(); -// test.tsm[1] = "globebrowsing\t\t"; -// test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\"Root\"\t-6.572656E1, -7.239404E1, -2.111890E1\t0.102164, -0.362945, 0.926193\t\t"; -// std::string testFull_string = stringFromTestProfileFormat(test); -// -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } -// REQUIRE_THROWS_WITH( -// ProfileFile(testFilePath), -// Catch::Matchers::Contains("fields required in Camera entry") -// ); -// } -//} -// -// -//TEST_CASE("profileFile: Required field missing", "[profileFile]") { -// { -// testProfileFormat test = buildTestProfile1(); -// test.tsc[1] = "setNavigationState\t\"NewHorizons\"\ttest\t\"Root\"\t\t0.102164, -0.362945, 0.926193\t\t"; -// std::string testFull_string = stringFromTestProfileFormat(test); -// std::string testFilePath = absPath( -// "${TEMPORARY}/test-profile-required-field-missing-1.profile" -// ); -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } -// -// { -// REQUIRE_THROWS_WITH( -// ProfileFile(testFilePath), -// Catch::Matchers::Contains("Camera navigation setNavigationState position vector(arg 4/8) is required") -// ); -// } -// } -// -// { -// testProfileFormat test = buildTestProfile1(); -// test.tsc[1] = "setNavigationState\t\"NewHorizons\"\t\t\"Root\"\t1, 2, 3\t0.102164, -0.362945, 0.926193\t\t"; -// test.tsk[3] = "F10\tSets the time to the orbital B event.\tSet orbital B event time\t/Missions/Osiris Rex\t\t\"openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186')\""; -// std::string testFull_string = stringFromTestProfileFormat(test); -// std::string testFilePath = absPath( -// "${TEMPORARY}/test-profile-required-field-missing-2.profile" -// ); -// { -// std::ofstream testFile(testFilePath); -// testFile << testFull_string; -// } -// { -// ProfileFile pf("default.profile"); -// REQUIRE_THROWS_WITH( -// ProfileFile(testFilePath), -// Catch::Matchers::Contains("Keybinding local(T/F)(arg 4/6) is required") -// ); -// } -// } -//} -// -//TEST_CASE("profileFile: Write test", "[profileFile]") { -// testProfileFormat test = buildTestProfile1(); -// std::string testFile = absPath("${TEMPORARY}/profile-test-write-test"); -// std::string testFull_string = stringFromTestProfileFormat(test); -// { -// std::ofstream f(testFile); -// f << testFull_string; -// } -// -// ProfileFile pf(testFile); -// -// std::string result = serialize(pf.profile); -// REQUIRE(testFull_string == result); -//} From 18a53e66053771f7dde8b9bd9889cd8063a5fb3d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 20 Jun 2020 22:21:09 +0200 Subject: [PATCH 38/61] Replace explicit Time::Type::None by using an optional --- include/openspace/scene/profile.h | 9 ++++----- src/scene/profile.cpp | 22 +++++++++------------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index cf81fc461e..63d924f852 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -87,11 +87,10 @@ public: struct Time { enum class Type { Absolute, - Relative, - None + Relative }; - Type type = Type::None; + Type type; std::string time; }; struct CameraNavState { @@ -158,13 +157,13 @@ public: static scripting::LuaLibrary luaLibrary(); private: - static constexpr const Version CurrentVersion = Version { 1, 0, 0 }; + static constexpr const Version CurrentVersion = Version { 1, 0 }; Version version = CurrentVersion; std::vector modules; std::vector assets; std::vector properties; std::vector keybindings; - Time time; + std::optional