From 6ace92812771d9dd0715304f82183a0df8c65df9 Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Mon, 30 Jan 2023 14:59:43 +0100
Subject: [PATCH] Allow specifying scenes as normal ArmarX data path in
 ObjectMemory

---
 .../armem_objects/server/instance/Segment.cpp | 86 +++++++++++++------
 .../armem_objects/server/instance/Segment.h   |  4 +-
 2 files changed, 64 insertions(+), 26 deletions(-)

diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
index a55ed9167..4f9ab4cf1 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
@@ -119,10 +119,20 @@ namespace armarx::armem::server::obj::instance
                        "Scene snapshots are expected to be located in Package/data/Package/Scenes/*.json.");
         defs->optional(p.sceneSnapshotsDirectory, prefix + "scene.11_Directory",
                        "Directory in Package/data/Package/ containing the scene snapshots.");
-        defs->optional(p.sceneSnapshotToLoad, prefix + "scene.12_SnapshotToLoad",
-                       "Scene to load on startup (e.g. 'Scene_2021-06-24_20-20-03').\n"
-                       "You can also specify paths relative to 'Package/scenes/'. \n"
-                       "You can also specify a ; separated list of scenes.");
+
+        std::vector<std::string> sceneSnapshotToLoadDescription =
+        {
+            "Scene(s) to load on startup.",
+            "Specify multiple scenes in a ; separated list.",
+            "Each entry must be one of the following:",
+            "(1) A scene file in 'Package/scenes/' (with or without '.json' extension), "
+            "e.g. 'MyScene', 'MyScene.json'",
+            "(2) A path to a scene file relative to 'Package/scenes/' (with or without '.json' extension), "
+            "e.g. 'path/to/MyScene', 'path/to/MyScene.json'",
+            "(3) An ArmarX data path to a scene file, e.g. 'Package/scenes/path/to/MyScene.json'",
+        };
+        defs->optional(p.sceneSnapshotsToLoad, prefix + "scene.12_SnapshotToLoad",
+                       simox::alg::join(sceneSnapshotToLoadDescription, " \n"));
 
         decay.defineProperties(defs, prefix + "decay.");
     }
@@ -132,10 +142,10 @@ namespace armarx::armem::server::obj::instance
     {
         SpecializedCoreSegment::init();
 
-        if (not p.sceneSnapshotToLoad.empty())
+        if (not p.sceneSnapshotsToLoad.empty())
         {
             bool trim = true;
-            const std::vector<std::string> scenes = simox::alg::split(p.sceneSnapshotToLoad, ";", trim);
+            const std::vector<std::string> scenes = simox::alg::split(p.sceneSnapshotsToLoad, ";", trim);
             for (const std::string& scene : scenes)
             {
                 const bool lockMemory = false;
@@ -934,7 +944,7 @@ namespace armarx::armem::server::obj::instance
 
     void Segment::storeScene(const std::string& filename, const armarx::objects::Scene& scene)
     {
-        if (const std::optional<std::filesystem::path> path = resolveSceneFilename(filename))
+        if (const std::optional<std::filesystem::path> path = resolveSceneFilepath(filename))
         {
 
             ARMARX_INFO << "Storing scene snapshot at: \n" << path.value();
@@ -953,7 +963,7 @@ namespace armarx::armem::server::obj::instance
     std::optional<armarx::objects::Scene>
     Segment::loadScene(const std::string& filename)
     {
-        if (const std::optional<std::filesystem::path> path = resolveSceneFilename(filename))
+        if (const std::optional<std::filesystem::path> path = resolveSceneFilepath(filename))
         {
             return loadScene(path.value());
         }
@@ -983,17 +993,18 @@ namespace armarx::armem::server::obj::instance
 
 
     std::optional<std::filesystem::path>
-    Segment::resolveSceneFilename(const std::string& _filename)
+    Segment::resolveSceneFilepath(const std::string& _filename)
     {
-        std::string filename = _filename;
+        std::string filepath = _filename;
 
-        filename = simox::alg::replace_all(filename, timestampPlaceholder,
+        filepath = simox::alg::replace_all(filepath, timestampPlaceholder,
                                            Time::Now().toString("%Y-%m-%d_%H-%M-%S"));
-        if (not simox::alg::ends_with(filename, ".json"))
+        if (not simox::alg::ends_with(filepath, ".json"))
         {
-            filename += ".json";
+            filepath += ".json";
         }
 
+        // Try to interprete it as relative to 'Package/scenes/'.
         if (!finder)
         {
             finder.reset(new CMakePackageFinder(p.sceneSnapshotsPackage));
@@ -1004,14 +1015,26 @@ namespace armarx::armem::server::obj::instance
         }
         if (finder->packageFound())
         {
-            std::filesystem::path dataDir = finder->getDataDir();
-            std::filesystem::path path = dataDir / p.sceneSnapshotsPackage / p.sceneSnapshotsDirectory / filename;
-            return path;
+            std::filesystem::path absDataDir = finder->getDataDir();
+            std::filesystem::path absPath = absDataDir / p.sceneSnapshotsPackage
+                    / p.sceneSnapshotsDirectory / filepath;
+            if (std::filesystem::is_regular_file(absPath))
+            {
+                return absPath;
+            }
         }
-        else
+
+        // Try to interprete it as ArmarXDataPath.
         {
-            return std::nullopt;
+            std::string resolved = ArmarXDataPath::resolvePath(filepath);
+            if (resolved != filepath)
+            {
+                return resolved;
+            }
         }
+
+        // Else: Fail
+        return std::nullopt;
     }
 
 
@@ -1114,25 +1137,40 @@ namespace armarx::armem::server::obj::instance
 
     void Segment::commitSceneSnapshotFromFilename(const std::string& filename, bool lockMemory)
     {
-        ARMARX_INFO << "Loading scene snapshot '" << filename << "' ...";
-        if (auto path = resolveSceneFilename(filename))
+        std::stringstream ss;
+        ss << "Loading scene '" << filename << "' ...";
+        if (std::optional<std::filesystem::path> path = resolveSceneFilepath(filename))
         {
+            ARMARX_INFO << ss.str() << "\nfrom " << path.value();
+
             if (const auto snapshot = loadScene(path.value()))
             {
-                std::filesystem::path filename = path->filename();
-                filename.replace_extension();  // Removes extension
+                auto makeSceneName = [](const std::filesystem::path& path)
+                {
+                    std::filesystem::path filename = path.filename();
+                    filename.replace_extension();  // Removes extension
+                    return filename.string();
+                };
+                std::string sceneName = makeSceneName(path.value());
 
                 // The check seems useless?
                 if (lockMemory)
                 {
-                    commitSceneSnapshot(snapshot.value(), filename.string());
+                    segmentPtr->doLocked([this,&snapshot, &sceneName]()
+                    {
+                        commitSceneSnapshot(snapshot.value(), sceneName);
+                    });
                 }
                 else
                 {
-                    commitSceneSnapshot(snapshot.value(), filename.string());
+                    commitSceneSnapshot(snapshot.value(), sceneName);
                 }
             }
         }
+        else
+        {
+            ARMARX_INFO << ss.str() << " failed: Could not resolve scene name or path.";
+        }
     }
 
 
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
index b9c5a6d37..c5e62d975 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
@@ -160,7 +160,7 @@ namespace armarx::armem::server::obj::instance
         void storeScene(const std::string& filename, const armarx::objects::Scene& scene);
         std::optional<armarx::objects::Scene> loadScene(const std::string& filename);
         std::optional<armarx::objects::Scene> loadScene(const std::filesystem::path& path);
-        std::optional<std::filesystem::path> resolveSceneFilename(const std::string& filename);
+        std::optional<std::filesystem::path> resolveSceneFilepath(const std::string& filename);
 
         armarx::objects::Scene getSceneSnapshot() const;
         void commitSceneSnapshot(const armarx::objects::Scene& scene, const std::string& sceneName);
@@ -200,7 +200,7 @@ namespace armarx::armem::server::obj::instance
             /// Package containing the scene snapshots
             std::string sceneSnapshotsPackage = armarx::ObjectFinder::DefaultObjectsPackageName;
             std::string sceneSnapshotsDirectory = "scenes";
-            std::string sceneSnapshotToLoad = "";
+            std::string sceneSnapshotsToLoad = "";
         };
         Properties p;
 
-- 
GitLab