diff --git a/source/RobotAPI/components/ObjectPoseObserver/CMakeLists.txt b/source/RobotAPI/components/ObjectPoseObserver/CMakeLists.txt index 0da706a1ce8dca46808b7f2e5a4c26664b74a819..29e894703a635024b3f31bffd08f447ad26dc2e3 100644 --- a/source/RobotAPI/components/ObjectPoseObserver/CMakeLists.txt +++ b/source/RobotAPI/components/ObjectPoseObserver/CMakeLists.txt @@ -10,9 +10,13 @@ set(COMPONENT_LIBS set(SOURCES ObjectPoseObserver.cpp + + ObjectFinder.cpp ) set(HEADERS ObjectPoseObserver.h + + ObjectFinder.h ) diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectFinder.cpp b/source/RobotAPI/components/ObjectPoseObserver/ObjectFinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6924f75836f04b4a9b5ecfaef9976f44dff3a59 --- /dev/null +++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectFinder.cpp @@ -0,0 +1,184 @@ +#include "ObjectFinder.h" + +#include <SimoxUtility/filesystem/list_directory.h> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> +#include <ArmarXCore/core/util/StringHelpers.h> + + +namespace armarx +{ + namespace fs = std::filesystem; + + ObjectInfo::ObjectInfo(const ObjectInfo::path& rootPath, const std::string& project, const std::string& name) : + rootPath(rootPath), project(project), name(name) + { + path autoObjectDir = getObjectDirectory(); + if (std::filesystem::is_directory(autoObjectDir)) + { + this->objectDirectory = autoObjectDir; + } + } + + ObjectInfo::path ObjectInfo::getObjectDirectory() const + { + return objectDirectory.empty() ? (rootPath / project / name) : objectDirectory; + } + + ObjectInfo::path ObjectInfo::getFile(const std::string& _extension, const std::string& suffix) const + { + std::string extension = _extension; + if (extension.at(0) != '.') + { + extension = "." + extension; + } + std::string filename = name + suffix + extension; + + return getObjectDirectory() / filename; + } + + ObjectInfo::path ObjectInfo::getSimoxXML() const + { + return getFile(".xml"); + } + + ObjectInfo::path ObjectInfo::getWavefrontObj() const + { + return getFile(".obj"); + } + + bool ObjectInfo::checkPaths() + { + namespace fs = std::filesystem; + + if (!fs::is_regular_file(getSimoxXML())) + { + ARMARX_WARNING << "Expected simox object file for object '" << *this << "': " << getSimoxXML(); + return false; + } + if (!fs::is_regular_file(getWavefrontObj())) + { + ARMARX_WARNING << "Expected wavefront object file (.obj) for object '" << *this << "': " << getWavefrontObj(); + return false; + } + + return true; + } + + + ObjectFinder::ObjectFinder(const std::string& objectsPackageName) : packageFinder(objectsPackageName) + { + Logging::setTag("ObjectFinder"); + + rootPath = path(packageFinder.getDataDir()) / objectsPackageName; + ARMARX_VERBOSE << "Object root directory: " << rootPath; + ARMARX_CHECK(rootPath.is_absolute()) << rootPath; + } + + std::optional<ObjectInfo> ObjectFinder::findObject(const std::string& project, const std::string& name) + { + if (!project.empty()) + { + return ObjectInfo(rootPath, project, name); + } + // Search for object in projects. + const auto& projects = getProjects(); + for (const path& project : projects) + { + if (fs::is_directory(rootPath / project / name)) + { + return ObjectInfo(rootPath, project, name); + } + } + + std::stringstream ss; + ss << "Did not find object '" << name << "' in any of these projects:\n"; + for (const path& project : projects) + { + ss << "- " << project << "\n"; + } + ss << "Root directory: " << rootPath; + ARMARX_WARNING << ss.str(); + + return std::nullopt; + } + + std::optional<ObjectInfo> ObjectFinder::findObject(const std::string& nameOrID) + { + if (nameOrID.find("/") != nameOrID.npos) + { + const std::vector<std::string> split = armarx::split(nameOrID, "/", true); + ARMARX_CHECK_EQUAL(split.size(), 2) << "Expected ID of format 'Project/Name', but got: '" << nameOrID + << "' (too many '/')."; + return findObject(split[0], split[1]); + } + else + { + return findObject("", nameOrID); + } + } + + std::vector<std::string> ObjectFinder::getProjects() + { + static const bool local = true; + std::vector<path> paths = simox::fs::list_directory(rootPath, local); + return std::vector<std::string>(paths.begin(), paths.end()); + } + + std::vector<ObjectFinder::path> ObjectFinder::getProjectDirectories() + { + static const bool local = false; + return simox::fs::list_directory(rootPath, local); + } + + std::vector<ObjectInfo> ObjectFinder::findAllObjects() + { + bool local = true; + std::vector<ObjectInfo> objects; + for (const path& projectDir : simox::fs::list_directory(rootPath, local)) + { + if (fs::is_directory(rootPath / projectDir)) + { + std::vector<ObjectInfo> project = findAllObjectsOfProject(projectDir); + objects.insert(objects.end(), project.begin(), project.end()); + } + } + return objects; + } + + std::vector<ObjectInfo> ObjectFinder::findAllObjectsOfProject(const std::string& project) + { + path projectDir = rootPath / project; + if (!fs::is_directory(projectDir)) + { + ARMARX_WARNING << "Expected project directory for project '" << project << "': \n" + << projectDir; + return {}; + } + + std::vector<ObjectInfo> objects; + bool local = true; + for (const path& dir : simox::fs::list_directory(projectDir, local)) + { + if (fs::is_directory(projectDir / dir)) + { + ObjectInfo object(rootPath, project, dir.filename()); + if (object.checkPaths()) + { + objects.push_back(object); + } + } + } + return objects; + } +} + +namespace armarx +{ + std::ostream& operator<<(std::ostream& os, const ObjectInfo& rhs) + { + return os << "'" << rhs.project << "/" << rhs.name << "'"; + } +} + diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectFinder.h b/source/RobotAPI/components/ObjectPoseObserver/ObjectFinder.h new file mode 100644 index 0000000000000000000000000000000000000000..88b639da815384f540a4f288d8a6ae4a2811d86d --- /dev/null +++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectFinder.h @@ -0,0 +1,78 @@ +#pragma once + +#include <filesystem> + +#include <ArmarXCore/core/logging/Logging.h> +#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h> + + +namespace armarx +{ + + class ObjectInfo + { + public: + using path = std::filesystem::path; + + public: + + ObjectInfo(const path& rootPath, const std::string& project, const std::string& name); + + path getObjectDirectory() const; + path getFile(const std::string& extension, const std::string& suffix = "") const; + + path getSimoxXML() const; + path getWavefrontObj() const; + + virtual bool checkPaths(); + + + public: + + path rootPath; + path objectDirectory; + + std::string project; + std::string name; + + + private: + + path _simoxXML; + path _wavefrontObj; + + + }; + + std::ostream& operator<<(std::ostream& os, const ObjectInfo& rhs); + + + class ObjectFinder : Logging + { + public: + using path = std::filesystem::path; + + + public: + + ObjectFinder(const std::string& objectsPackageName = "ArmarXObjects"); + + std::optional<ObjectInfo> findObject(const std::string& project, const std::string& name); + std::optional<ObjectInfo> findObject(const std::string& nameOrID); + + + std::vector<std::string> getProjects(); + std::vector<path> getProjectDirectories(); + + std::vector<ObjectInfo> findAllObjects(); + std::vector<ObjectInfo> findAllObjectsOfProject(const std::string& project); + + + private: + + CMakePackageFinder packageFinder; + path rootPath; + + }; + +}