Skip to content

Commit

Permalink
--Configuration : Add ability to handle vectors of fields within subc…
Browse files Browse the repository at this point in the history
…onfigs (#2394)

* --add Configuration function to be able to store and retrieve vectors of data.
A vector of a supported type of values can now be stored and retrieved  in a Subconfiguration, where the key of each value from the vector will be a string representation of its index. Currently supports up to 1000 values in the vector.
* --support Semantic Polyloop as subconfig instead of local vector
* --attempt to load into a subconfig directly
  • Loading branch information
jturner65 committed May 11, 2024
1 parent 8a0d336 commit 1db01c7
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 50 deletions.
81 changes: 74 additions & 7 deletions src/esp/core/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@ constexpr bool isConfigValTypeNonTrivial(ConfigValType type) {
*/
template <typename T>
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;
}

/**
Expand Down Expand Up @@ -694,6 +695,21 @@ class Configuration {
return {};
}

/**
* @brief Remove all values from this Configuration of the specified type.
*/
template <typename T>
void removeAllOfType() {
const ConfigValType desiredType = configValTypeFor<T>();
for (auto mapIter = valueMap_.cbegin(), nextIter = mapIter;
mapIter != valueMap_.cend(); mapIter = nextIter) {
++nextIter;
if (mapIter->second.getType() == desiredType) {
valueMap_.erase(mapIter);
}
}
}

// ************************* Queries **************************

/**
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 <typename T>
std::vector<T> getSubconfigValsOfTypeInVector(
const std::string& subCfgName) const {
const ConfigValType desiredType = configValTypeFor<T>();
const auto subCfg = getSubconfigView(subCfgName);
const auto& subCfgTags = subCfg->getKeysByType(desiredType, true);
std::vector<T> res;
res.reserve(subCfgTags.size());
for (const auto& tag : subCfgTags) {
res.emplace_back(subCfg->get<T>(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 <typename T>
void setSubconfigValsOfTypeInVector(const std::string& subCfgName,
const std::vector<T>& values) {
auto subCfg = editSubconfig<Configuration>(subCfgName);
// remove existing values in subconfig of specified type
subCfg->removeAllOfType<T>();
// 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 =========================

/**
Expand Down
5 changes: 4 additions & 1 deletion src/esp/metadata/attributes/AttributesBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>("ID"); }

/**
Expand Down
19 changes: 2 additions & 17 deletions src/esp/metadata/attributes/MarkerSets.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mn::Vector3> getAllPoints() const {
const auto markersPtr = getSubconfigView("markers");
// Get all vector3 keys from subconfig in sorted vector
std::vector<std::string> markerTags = markersPtr->getKeysByType(
esp::core::config::ConfigValType::MagnumVec3, true);
std::vector<Mn::Vector3> res;
res.reserve(markerTags.size());
for (const auto& tag : markerTags) {
res.emplace_back(markersPtr->get<Mn::Vector3>(tag));
}
return res;
return getSubconfigValsOfTypeInVector<Mn::Vector3>("markers");
}

/**
* @brief Set the list of all the marker points for this MarkerSet
*/
void setAllPoints(const std::vector<Mn::Vector3>& markers) {
auto markersPtr = editSubconfig<Configuration>("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);
}

/**
Expand Down
15 changes: 6 additions & 9 deletions src/esp/metadata/attributes/SemanticAttributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,22 @@ 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(
"{},{},{},{},{},{},", getAsString("handle"), getAsString("label"),
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());
}
Expand All @@ -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

Expand Down
16 changes: 5 additions & 11 deletions src/esp/metadata/attributes/SemanticAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Magnum::Vector3>& getPolyLoop() const { return polyLoop_; }
std::vector<Magnum::Vector3> getPolyLoop() const {
return getSubconfigValsOfTypeInVector<Magnum::Vector3>("poly_loop");
}
/**
* @brief Set the vector holding the poly loop points.
*/
void setPolyLoop(std::vector<Magnum::Vector3> _polyLoop) {
polyLoop_ = std::move(_polyLoop);
void setPolyLoop(const std::vector<Magnum::Vector3>& _polyLoop) {
setSubconfigValsOfTypeInVector("poly_loop", _polyLoop);
}

/**
Expand All @@ -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<Magnum::Vector3> polyLoop_{};

public:
ESP_SMART_POINTERS(SemanticVolumeAttributes)

Expand Down
6 changes: 4 additions & 2 deletions src/esp/metadata/managers/AttributesManagerBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ class AttributesManager : public ManagedFileBasedContainer<T, Access> {
/**
* @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
Expand All @@ -297,7 +297,9 @@ class AttributesManager : public ManagedFileBasedContainer<T, Access> {
*
* 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
Expand Down
4 changes: 3 additions & 1 deletion src/esp/metadata/managers/SemanticAttributesManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ void SemanticAttributesManager::setSemanticVolumeAttributesFromJson(
// read values into vector
io::readMember<Mn::Vector3>(jCell, "poly_loop", polyLoop);
instanceAttrs->setPolyLoop(polyLoop);

} else if (polyLoopJSONIter->value.IsObject()) {
auto config = instanceAttrs->editSubconfig<Configuration>("poly_loop");
config->loadFromJson(polyLoopJSONIter->value);
} else {
ESP_WARNING() << ": Unknown format for "
"poly_loop specified for region instance"
Expand Down
3 changes: 1 addition & 2 deletions src/esp/scene/SemanticScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mn::Vector3>& loopPoints =
regionInstance->getPolyLoop();
const auto loopPoints = regionInstance->getPolyLoop();

std::size_t numPts = loopPoints.size();
regionPtr->polyLoopPoints_ = std::vector<Mn::Vector2>(numPts);
Expand Down

0 comments on commit 1db01c7

Please sign in to comment.