diff --git a/src/esp/core/Configuration.h b/src/esp/core/Configuration.h index 3f0267b0b1..d93bdd75aa 100644 --- a/src/esp/core/Configuration.h +++ b/src/esp/core/Configuration.h @@ -125,8 +125,9 @@ constexpr bool isConfigValTypeNonTrivial(ConfigValType type) { */ template constexpr ConfigValType configValTypeFor() { - static_assert(sizeof(T) == 0, "unsupported type "); - return {}; + static_assert(sizeof(T) == 0, + "unknown/unsupported type specified for ConfigValue"); + return ConfigValType::Unknown; } /** @@ -694,6 +695,21 @@ class Configuration { return {}; } + /** + * @brief Remove all values from this Configuration of the specified type. + */ + template + void removeAllOfType() { + const ConfigValType desiredType = configValTypeFor(); + for (auto mapIter = valueMap_.cbegin(), nextIter = mapIter; + mapIter != valueMap_.cend(); mapIter = nextIter) { + ++nextIter; + if (mapIter->second.getType() == desiredType) { + valueMap_.erase(mapIter); + } + } + } + // ************************* Queries ************************** /** @@ -934,18 +950,18 @@ class Configuration { /** * @brief Retrieve the number of entries held by the subconfig with the - * given name, recursing subordinate subconfigs - * @param name The name of the subconfig to query. If not found, returns 0 + * given @p cfgName , recursing subordinate subconfigs + * @param cfgName The name of the subconfig to query. If not found, returns 0 * with a warning. * @return The number of entries in the named subconfig, including all * subconfigs */ - int getSubconfigTreeNumEntries(const std::string& name) const { - auto configIter = configMap_.find(name); + int getSubconfigTreeNumEntries(const std::string& cfgName) const { + auto configIter = configMap_.find(cfgName); if (configIter != configMap_.end()) { return configIter->second->getConfigTreeNumEntries(); } - ESP_WARNING() << "No Subconfig found named :" << name; + ESP_WARNING() << "No Subconfig found named :" << cfgName; return 0; } @@ -989,6 +1005,57 @@ class Configuration { return std::make_pair(configMap_.cbegin(), configMap_.cend()); } + /** + * @brief Get all values of passed type held within subconfig specified by + * given tag @p subCfgName and place the values into a vector. + * + * This assumes the subconfig's values of the specified type are all intended + * to be considered as part of a vector of data. + * @tparam The type of data within the specified subconfig we wish to + * retrieve. + * @param subCfgName The handle of the + */ + template + std::vector getSubconfigValsOfTypeInVector( + const std::string& subCfgName) const { + const ConfigValType desiredType = configValTypeFor(); + const auto subCfg = getSubconfigView(subCfgName); + const auto& subCfgTags = subCfg->getKeysByType(desiredType, true); + std::vector res; + res.reserve(subCfgTags.size()); + for (const auto& tag : subCfgTags) { + res.emplace_back(subCfg->get(tag)); + } + return res; + } // getSubconfigValsOfTypeInVector + /** + * @brief Set all values from vector of passed type into subconfig specified + * by given tag @p subCfgName as key-value pairs where the key is the index in + * the vector as a string (to preserve vector ordering). This function will + * remove all existing values of specified type from the subconfig before + * adding the values specified in the given map. + * + * This assumes the subconfig's values of the specified type are all intended + * to be considered as part of a vector of data. + * @tparam The type of data within the specified subConfig we wish to + * set from the passed vector. + * @param subCfgName The handle of the desired subconfig to add the values to. + * @param values The vector of values of type @p T to add to the specified + * subconfig. + */ + template + void setSubconfigValsOfTypeInVector(const std::string& subCfgName, + const std::vector& values) { + auto subCfg = editSubconfig(subCfgName); + // remove existing values in subconfig of specified type + subCfg->removeAllOfType(); + // add new values, building string key from index in values array of each + // value. + for (std::size_t i = 0; i < values.size(); ++i) { + const std::string& key = Cr::Utility::formatString("{:.03d}", i); + subCfg->set(key, values[i]); + } + } // ==================== load from and save to json ========================= /** diff --git a/src/esp/metadata/attributes/AttributesBase.h b/src/esp/metadata/attributes/AttributesBase.h index 83b97f129c..3ab4da69da 100644 --- a/src/esp/metadata/attributes/AttributesBase.h +++ b/src/esp/metadata/attributes/AttributesBase.h @@ -103,9 +103,12 @@ class AbstractAttributes } /** - * @brief Unique ID referencing attributes + * @brief Set the unique ID referencing attributes */ void setID(int ID) override { set("ID", ID); } + /** + * @brief Get the unique ID referencing attributes + */ int getID() const override { return get("ID"); } /** diff --git a/src/esp/metadata/attributes/MarkerSets.h b/src/esp/metadata/attributes/MarkerSets.h index ee4e67acc0..1b5be6d992 100644 --- a/src/esp/metadata/attributes/MarkerSets.h +++ b/src/esp/metadata/attributes/MarkerSets.h @@ -34,29 +34,14 @@ class MarkerSet : public esp::core::config::Configuration { * @brief Returns a list of all the marker points in this MarkerSet */ std::vector getAllPoints() const { - const auto markersPtr = getSubconfigView("markers"); - // Get all vector3 keys from subconfig in sorted vector - std::vector markerTags = markersPtr->getKeysByType( - esp::core::config::ConfigValType::MagnumVec3, true); - std::vector res; - res.reserve(markerTags.size()); - for (const auto& tag : markerTags) { - res.emplace_back(markersPtr->get(tag)); - } - return res; + return getSubconfigValsOfTypeInVector("markers"); } /** * @brief Set the list of all the marker points for this MarkerSet */ void setAllPoints(const std::vector& markers) { - auto markersPtr = editSubconfig("markers"); - // Remove all existing marker points - markersPtr->_clearAllValues(); - for (std::size_t i = 0; i < markers.size(); ++i) { - const std::string& key = Cr::Utility::formatString("{:.03d}", i); - markersPtr->set(key, markers[i]); - } + setSubconfigValsOfTypeInVector("markers", markers); } /** diff --git a/src/esp/metadata/attributes/SemanticAttributes.cpp b/src/esp/metadata/attributes/SemanticAttributes.cpp index 02b08db174..ad411af12f 100644 --- a/src/esp/metadata/attributes/SemanticAttributes.cpp +++ b/src/esp/metadata/attributes/SemanticAttributes.cpp @@ -21,13 +21,13 @@ SemanticVolumeAttributes::SemanticVolumeAttributes(const std::string& handle) std::string SemanticVolumeAttributes::getObjectInfoHeaderInternal() const { std::string res = "Name,Label,Floor Height,Extrusion Height,Min Bounds,Max Bounds,"; - int iter = 0; - for (const auto& it : polyLoop_) { + const auto& polyLoop = getPolyLoop(); + for (int iter = 0; iter < polyLoop.size(); ++iter) { Cr::Utility::formatInto(res, res.size(), "Poly Vert {} XYZ,", - std::to_string(iter++)); + std::to_string(iter)); } return res; -} +} // namespace attributes std::string SemanticVolumeAttributes::getObjectInfoInternal() const { std::string res = Cr::Utility::formatString( @@ -35,7 +35,8 @@ std::string SemanticVolumeAttributes::getObjectInfoInternal() const { getAsString("floor_height"), getAsString("extrusion_height"), getAsString("min_bounds"), getAsString("max_bounds")); Cr::Utility::formatInto(res, res.size(), "["); - for (const Magnum::Vector3& pt : polyLoop_) { + const auto& polyLoop = getPolyLoop(); + for (const auto& pt : polyLoop) { Cr::Utility::formatInto(res, res.size(), "[{} {} {}],", pt.x(), pt.y(), pt.z()); } @@ -55,10 +56,6 @@ void SemanticVolumeAttributes::writeValuesToJson( writeValueToJson("extrusion_height", jsonObj, allocator); writeValueToJson("min_bounds", jsonObj, allocator); writeValueToJson("max_bounds", jsonObj, allocator); - // write out poly loop point array. - if (!polyLoop_.empty()) { - io::addMember(jsonObj, "poly_loop", polyLoop_, allocator); - } } // SemanticVolumeAttributes::writeValuesToJson diff --git a/src/esp/metadata/attributes/SemanticAttributes.h b/src/esp/metadata/attributes/SemanticAttributes.h index c78242e64c..5c0120d165 100644 --- a/src/esp/metadata/attributes/SemanticAttributes.h +++ b/src/esp/metadata/attributes/SemanticAttributes.h @@ -87,18 +87,18 @@ class SemanticVolumeAttributes : public AbstractAttributes { set("max_bounds", _max_bounds); } - //// TODO : Replace vector with configuration? - /** * @brief retrieve a const reference to the vector holding the poly loop * points. */ - const std::vector& getPolyLoop() const { return polyLoop_; } + std::vector getPolyLoop() const { + return getSubconfigValsOfTypeInVector("poly_loop"); + } /** * @brief Set the vector holding the poly loop points. */ - void setPolyLoop(std::vector _polyLoop) { - polyLoop_ = std::move(_polyLoop); + void setPolyLoop(const std::vector& _polyLoop) { + setSubconfigValsOfTypeInVector("poly_loop", _polyLoop); } /** @@ -122,12 +122,6 @@ class SemanticVolumeAttributes : public AbstractAttributes { */ std::string getObjectInfoInternal() const override; - /** - * @brief Vector of points making up the poly loop that describes the - * extrusion base. - */ - std::vector polyLoop_{}; - public: ESP_SMART_POINTERS(SemanticVolumeAttributes) diff --git a/src/esp/metadata/managers/AttributesManagerBase.h b/src/esp/metadata/managers/AttributesManagerBase.h index fe72a70be5..aca6138ecd 100644 --- a/src/esp/metadata/managers/AttributesManagerBase.h +++ b/src/esp/metadata/managers/AttributesManagerBase.h @@ -282,7 +282,7 @@ class AttributesManager : public ManagedFileBasedContainer { /** * @brief Set a filename attribute to hold the appropriate data if the * existing attribute's given path contains the sentinel tag value defined at - * @ref esp::metadata::CONFIG_NAME_AS_ASSET_FILENAME. This will be called from + * @ref esp::metadata::CONFIG_NAME_AS_ASSET_FILENAME. This will be specified in * the Scene Dataset configuration file in the "default_attributes" tag for * any attributes which consume file names to specify that the name specified * as the instanced attributes should also be used to build the name of the @@ -297,7 +297,9 @@ class AttributesManager : public ManagedFileBasedContainer { * * This will only be called from the specified manager's initNewObjectInternal * function, where the attributes is initially built from a default attributes - * (if such an attributes exists). + * (if such an attributes exists), since it is only within the default + * attributes that the tag in question would be specified. + * * @param attributes The AbstractAttributes being worked with. * @param srcAssetFilename The given asset's stored filename to be queried for * the specified tag. If the tag exists, replace it with the simplified handle diff --git a/src/esp/metadata/managers/SemanticAttributesManager.cpp b/src/esp/metadata/managers/SemanticAttributesManager.cpp index 25f0ed70cb..5733b62aad 100644 --- a/src/esp/metadata/managers/SemanticAttributesManager.cpp +++ b/src/esp/metadata/managers/SemanticAttributesManager.cpp @@ -126,7 +126,9 @@ void SemanticAttributesManager::setSemanticVolumeAttributesFromJson( // read values into vector io::readMember(jCell, "poly_loop", polyLoop); instanceAttrs->setPolyLoop(polyLoop); - + } else if (polyLoopJSONIter->value.IsObject()) { + auto config = instanceAttrs->editSubconfig("poly_loop"); + config->loadFromJson(polyLoopJSONIter->value); } else { ESP_WARNING() << ": Unknown format for " "poly_loop specified for region instance" diff --git a/src/esp/scene/SemanticScene.cpp b/src/esp/scene/SemanticScene.cpp index e8fd81511f..6f70482e9d 100644 --- a/src/esp/scene/SemanticScene.cpp +++ b/src/esp/scene/SemanticScene.cpp @@ -167,8 +167,7 @@ bool SemanticScene:: const Mn::Vector3 max = regionInstance->getMaxBounds(); regionPtr->setBBox(min, max); // Set polyloop points and precalc polyloop edge vectors - const std::vector& loopPoints = - regionInstance->getPolyLoop(); + const auto loopPoints = regionInstance->getPolyLoop(); std::size_t numPts = loopPoints.size(); regionPtr->polyLoopPoints_ = std::vector(numPts);