Skip to content

Commit

Permalink
Merge pull request #359 from agri-gaia/refactor-hdf5-core
Browse files Browse the repository at this point in the history
Refactoring in seerep_hdf5_core and seerep_core
  • Loading branch information
jarkenau authored Dec 21, 2023
2 parents 793129c + 759a812 commit 83325dc
Show file tree
Hide file tree
Showing 19 changed files with 232 additions and 276 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,21 @@ class Hdf5CoreCameraIntrinsics : public Hdf5CoreGeneral
* @return true If camera intrinsics exist
* @return false If camera intrinsics do not exist
*/
bool checkCameraIntrinsicsExists(const boost::uuids::uuid& cameraintrinsics_uuid);
bool cameraIntrinsicExists(const boost::uuids::uuid& camera_intrinsic_uuid) const;

private:
const std::shared_ptr<HighFive::DataSet> generateDatasetPointer(const std::string& attribute);
const std::string getHdf5GroupPath(const std::string& id) const;
const std::string getHdf5DataSetPath(const std::string& id) const;
/**
* @brief Returns the HDF5 group path for a given camera intrinsics UUID.
*@param uuid The UUID string of a camera intrinsic.
*@return The HDF5 group path.
*/
const std::string cameraIntrinsicPath(const std::string& camera_intrinsic_uuid) const;

public:
// datatype group names in hdf5
/* HDF5 group name to store the camera instrinsics */
inline static const std::string HDF5_GROUP_CAMINTRINSICS = "cameraintrinsics";
inline static const std::string SIZE = "size";

/* HDF5 attribute names to store the camera instrinsics information */
inline static const std::string HEIGHT = "height";
inline static const std::string WIDTH = "width";
inline static const std::string DISTORTION_MODEL = "distortion_model";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,70 @@ class Hdf5CoreGeneral
void checkExists(const std::string& id);

/**
* @brief Checks if a DataSet or DataGroup exists in the file
* @param id The id of the DataSet or DataGroup
* @return true if the DataSet or DataGroup exists
* @brief Checks if a HDF5 path exists in the file.
*
* Wrapper around HighFive::File::exist() for logging purposes.
*
* @param path The HDF5 path to check
* @return True if the dataset exists, false otherwise.
*/
bool exists(const std::string& id);
bool exists(const std::string& path) const;

std::optional<std::string> readFrameId(const std::string& datatypeGroup, const std::string& uuid);
// ################
// Attributes
// ################
/**
* @brief Reads an attribute from an HDF5 object.
*
* @tparam T The type of the attribute to read.
* @tparam C The type of the HDF5 object to read from.
* @param object The HDF5 object to read from.
* @param attribute_name The name of the attribute to read.
* @param path The path to the HDF5 object, only used for logging.
* @return T The value of the attribute.
*/
template <typename T, class C>
T readAttributeFromHdf5(const std::string& id, const HighFive::AnnotateTraits<C>& object, std::string attributeField);
T readAttributeFromHdf5(const HighFive::AnnotateTraits<C>& object, const std::string& attribute_name,
const std::string& path);

/**
* @brief Writes an attribute to an HDF5 object.
*
* @tparam T The type of the attribute to write.
* @tparam C The type of the HDF5 object.
* @param object The HDF5 object to write the attribute to.
* @param attribute_name The name of the attribute.
* @param attribute_val The value of the attribute.
*/
template <typename T, class C>
void writeAttributeToHdf5(HighFive::AnnotateTraits<C>& object, std::string attributeField, T attributeValue);
void writeAttributeToHdf5(HighFive::AnnotateTraits<C>& object, const std::string& attribute_name, T attribute_val);

void deleteAttribute(const std::shared_ptr<HighFive::DataSet> dataSetPtr, std::string attributeField);
/**
* @brief Returns a tf2 compliant frame ID.
*
* @param frame_id The frame ID to check.
* @return The corresponding tf2 frame ID.
*/
const std::string tf2_frame_id(const std::string& frame_id) const;

/**
* @brief Reads a tf2 compliant frame ID from an HDF5 object.
*
* @tparam C The type of the HDF5 object to read from.
* @param object The HDF5 object to read from.
* @param frame_field The name of HDF5 attribute to read the frame ID from.
* @param id The path to the HDF5 object, only used for logging.
* @return The frame ID as a string.
*/
template <class C>
std::string readFrameId(const std::string& id, const HighFive::AnnotateTraits<C>& object,
const std::string& frame_field);
std::string readFrameId(const HighFive::AnnotateTraits<C>& object, const std::string& frame_field,
const std::string& path);

/**
* @brief Writes a tf2 compliant frame ID to an HDF5 object.
*
* @tparam C The type of the HDF5 object to write to.
* @param object The HDF5 object to write to.
* @param frame_field The name of the HDF5 attribute to write the frame ID to.
* @param frame_id The frame ID to write.
*/
template <class C>
void writeFrameId(HighFive::AnnotateTraits<C>& object, const std::string& frame_field, const std::string& frame_id);

Expand Down Expand Up @@ -94,14 +136,6 @@ class Hdf5CoreGeneral
template <class T>
void writeHeader(HighFive::AnnotateTraits<T>& object, seerep_core_msgs::Header header);

/*
* @brief Corrects a frame_id to be valid for tf2.
*
* @param [in] frame_id frame_id to check
* @param [out] frame_id which complies with tf2
*/
const std::string tf2_frame_id(std::string frame_id);

/**
* @brief Read header from a group within an hd5f file
*
Expand Down Expand Up @@ -161,59 +195,72 @@ class Hdf5CoreGeneral
void writeVersion(const std::string& version);
const std::optional<std::string> readVersion();

// ################
// Geodetic Coordinates
// ################
/**
* @brief Writes Geodetic location of the project to its HDF5 file.
* @brief Writes a geodetic coordinate to an HDF5 file.
*
* Note: The data is written to the root group of the HDF5 file, since the geo-reference applies to complete project.
*
* @param geocoords seerep_core_msgs Geodetic Coordinates object.
* @param geo_coordinates The geodetic coordinate to write to the file.
*/
void writeGeodeticLocation(const seerep_core_msgs::GeodeticCoordinates geocoords);
void writeGeodeticLocation(const seerep_core_msgs::GeodeticCoordinates& geo_coordinates);

/**
* @brief Read Geodetic location of the project from its HDF5 file.
* @brief Reads a geodetic coodrinate from HDF5 file.
*
* Note: The data is expected to be stored in the root group of the HDF5 file.
*
* @return std::optional<seerep_core_msgs::GeodeticCoordinates> Optional return of Geodetic Coordinates
* @return std::optional<seerep_core_msgs::GeodeticCoordinates> Geodetic coordinate if available, empty optional otherwise.
*/
std::optional<seerep_core_msgs::GeodeticCoordinates> readGeodeticLocation();

// ################
// Hdf5
// ################
/**
* @brief Get a shared pointer to a hdf5 group
* @brief Returns a shared pointer to an HDF5 group object.
*
* @param hdf5GroupPath path to the data group
* @param create create a new group if the group path can't be found?
* @return std::shared_ptr<HighFive::Group> shared pointer to the group
* @param group_path The path to the HDF5 group.
* @param create If true, the group will be created if it does not already exist.
* @return std::shared_ptr<HighFive::Group> A shared pointer to the HDF5 group object. Nullptr if the group does not
* exist and create is false.
*/
std::shared_ptr<HighFive::Group> getHdf5Group(const std::string& hdf5GroupPath, bool create = true);
std::shared_ptr<HighFive::Group> getHdf5Group(const std::string& group_path, bool create = true);

/**
* @brief Get a shared pointer to a hdf5 data set specified by the hdf5DataSetPath
* @brief Returns a shared pointer to a HighFive::DataSet object for the given dataset path.
*
* @tparam T type of the dataset
* @param hdf5DataSetPath path to the dataset
* @param dataSpace the data space to specify the dimensions of the dataset
* @return std::shared_ptr<HighFive::DataSet> shared pointer to the data set
* @param dataset_path The path to the dataset.
* @return std::shared_ptr<HighFive::DataSet> A shared pointer to the dataset object. Nullptr if the dataset does not exist.
*/
std::shared_ptr<HighFive::DataSet> getHdf5DataSet(const std::string& dataset_path);

/**
* @brief Returns a shared pointer to a HighFive::DataSet object for the given dataset path and data space.
*
* A new dataset will be created if it does not already exist.
*
* @tparam T The data type of the dataset.
* @param dataset_path The path to the dataset.
* @param dataspace The data space of the dataset.
* @return std::shared_ptr<HighFive::DataSet> A shared pointer to the HighFive dataset object.
*/
template <class T>
std::shared_ptr<HighFive::DataSet> getHdf5DataSet(const std::string& hdf5DataSetPath, HighFive::DataSpace& dataSpace);
std::shared_ptr<HighFive::DataSet> getHdf5DataSet(const std::string& dataset_path,
const HighFive::DataSpace& dataspace);

/**
* @brief Get a shared pointer to a hdf5 data set specified by the hdf5DataSetPath
* @brief Get a shared pointer to a HighFive::Dataset object for the given path, dataspace, and properties.
*
* @tparam T type of the dataset
* @param hdf5DataSetPath path to the dataset
* @param dataSpace the data space to specify the dimensions of the dataset
* @param createProps properties for creation of the dataset
* @return std::shared_ptr<HighFive::DataSet> shared pointer to the data set
* A new dataset will be created if it does not already exist.
*
* @tparam T The datatype of the dataset.
* @param dataset_path The path to the dataset.
* @param dataspace The dataspace of the dataset.
* @param properties The properties of the dataset.
* @return std::shared_ptr<HighFive::DataSet> A shared pointer to the HDF5 dataset.
*/
template <class T>
std::shared_ptr<HighFive::DataSet> getHdf5DataSet(const std::string& hdf5DataSetPath, HighFive::DataSpace& dataSpace,
HighFive::DataSetCreateProps& createProps);
std::shared_ptr<HighFive::DataSet> getHdf5DataSet(const std::string& dataset_path,
const HighFive::DataSpace& dataspace,
const HighFive::DataSetCreateProps& properties);

std::shared_ptr<HighFive::DataSet> getHdf5DataSet(const std::string& hdf5DataSetPath);
/**
* @brief get the labels of a group/dataset matching the general prefix (label type) and return the labels matching
* the specified type. Also extract the category from the postfix
Expand Down Expand Up @@ -268,7 +315,9 @@ class Hdf5CoreGeneral
protected:
std::shared_ptr<HighFive::File> m_file;
std::shared_ptr<std::mutex> m_write_mtx;
boost::log::sources::severity_logger<boost::log::trivial::severity_level> m_logger;

/* The logger does not change the state of the object, thus we can make it mutable, to use it in const functions */
mutable boost::log::sources::severity_logger<boost::log::trivial::severity_level> m_logger;
};

} // namespace seerep_hdf5_core
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,40 @@
namespace seerep_hdf5_core
{
template <typename T, class C>
T Hdf5CoreGeneral::readAttributeFromHdf5(const std::string& id, const HighFive::AnnotateTraits<C>& object,
std::string attributeField)
T Hdf5CoreGeneral::readAttributeFromHdf5(const HighFive::AnnotateTraits<C>& object, const std::string& attribute_name,
const std::string& path)
{
T attributeValue;
if (object.hasAttribute(attributeField))
T attribute_value;
if (object.hasAttribute(attribute_name))
{
object.getAttribute(attributeField).read(attributeValue);
object.getAttribute(attribute_name).read(attribute_value);
}
else
{
throw std::invalid_argument("id " + id + " has no attribute " + attributeField);
throw std::invalid_argument("Path: " + path + " has no attribute:" + attribute_name);
}
return attributeValue;
return attribute_value;
}

template <typename T, class C>
void Hdf5CoreGeneral::writeAttributeToHdf5(HighFive::AnnotateTraits<C>& object, std::string attributeField,
T attributeValue)
void Hdf5CoreGeneral::writeAttributeToHdf5(HighFive::AnnotateTraits<C>& object, const std::string& attribute_name,
T attribute_val)
{
if (object.hasAttribute(attributeField))
if (object.hasAttribute(attribute_name))
{
object.getAttribute(attributeField).write(attributeValue);
object.getAttribute(attribute_name).write(attribute_val);
}
else
{
object.createAttribute(attributeField, attributeValue);
object.createAttribute(attribute_name, attribute_val);
}
}

template <class C>
std::string Hdf5CoreGeneral::readFrameId(const std::string& uuid, const HighFive::AnnotateTraits<C>& object,
const std::string& frame_field)
std::string Hdf5CoreGeneral::readFrameId(const HighFive::AnnotateTraits<C>& object, const std::string& frame_field,
const std::string& path)
{
return tf2_frame_id(readAttributeFromHdf5<std::string>(uuid, object, frame_field));
return tf2_frame_id(readAttributeFromHdf5<std::string>(object, frame_field, path));
}

template <class C>
Expand All @@ -48,30 +48,21 @@ void Hdf5CoreGeneral::writeFrameId(HighFive::AnnotateTraits<C>& object, const st

template <class T>
std::shared_ptr<HighFive::DataSet> Hdf5CoreGeneral::getHdf5DataSet(const std::string& hdf5DataSetPath,
HighFive::DataSpace& dataSpace)
const HighFive::DataSpace& dataSpace)
{
HighFive::DataSetCreateProps emptyProps;
return getHdf5DataSet<T>(hdf5DataSetPath, dataSpace, emptyProps);
return getHdf5DataSet<T>(hdf5DataSetPath, dataSpace, HighFive::DataSetCreateProps());
}

template <class T>
std::shared_ptr<HighFive::DataSet> Hdf5CoreGeneral::getHdf5DataSet(const std::string& hdf5DataSetPath,
HighFive::DataSpace& dataSpace,
HighFive::DataSetCreateProps& createProps)
std::shared_ptr<HighFive::DataSet> Hdf5CoreGeneral::getHdf5DataSet(const std::string& dataset_path,
const HighFive::DataSpace& dataspace,
const HighFive::DataSetCreateProps& properties)
{
try
{
checkExists(hdf5DataSetPath);
BOOST_LOG_SEV(m_logger, boost::log::trivial::severity_level::trace)
<< "hdf5 group" << hdf5DataSetPath << " already exists!";
return std::make_shared<HighFive::DataSet>(m_file->getDataSet(hdf5DataSetPath));
}
catch (std::invalid_argument const& e)
if (exists(dataset_path))
{
BOOST_LOG_SEV(m_logger, boost::log::trivial::severity_level::trace)
<< "hdf5 group " << hdf5DataSetPath << " does not exist! Creating a new group";
return std::make_shared<HighFive::DataSet>(m_file->createDataSet<T>(hdf5DataSetPath, dataSpace, createProps));
return std::make_shared<HighFive::DataSet>(m_file->getDataSet(dataset_path));
}
return std::make_shared<HighFive::DataSet>(m_file->createDataSet<T>(dataset_path, dataspace, properties));
}

template <class T>
Expand All @@ -92,9 +83,9 @@ void Hdf5CoreGeneral::readHeader(const std::string& id, HighFive::AnnotateTraits
std::string uuidproject_str = std::filesystem::path(m_file->getName()).filename().stem();
header.uuidProject = boost::lexical_cast<boost::uuids::uuid>(uuidproject_str);

header.timestamp.seconds = Hdf5CoreGeneral::readAttributeFromHdf5<int32_t>(id, object, HEADER_STAMP_SECONDS);
header.timestamp.nanos = Hdf5CoreGeneral::readAttributeFromHdf5<int32_t>(id, object, HEADER_STAMP_NANOS);
header.frameId = Hdf5CoreGeneral::readFrameId(id, object, HEADER_FRAME_ID);
header.sequence = Hdf5CoreGeneral::readAttributeFromHdf5<int32_t>(id, object, HEADER_SEQ);
header.timestamp.seconds = Hdf5CoreGeneral::readAttributeFromHdf5<int32_t>(object, HEADER_STAMP_SECONDS, id);
header.timestamp.nanos = Hdf5CoreGeneral::readAttributeFromHdf5<int32_t>(object, HEADER_STAMP_NANOS, id);
header.frameId = Hdf5CoreGeneral::readFrameId(object, HEADER_FRAME_ID, id);
header.sequence = Hdf5CoreGeneral::readAttributeFromHdf5<int32_t>(object, HEADER_SEQ, id);
}
} // namespace seerep_hdf5_core
Loading

0 comments on commit 83325dc

Please sign in to comment.