ObjectFinder.cpp
Go to the documentation of this file.
1#include "ObjectFinder.h"
2
3#include <filesystem>
4#include <functional>
5#include <map>
6#include <optional>
7#include <sstream>
8#include <string>
9#include <unordered_map>
10#include <vector>
11
12#include <SimoxUtility/algorithm/string.h>
13#include <SimoxUtility/filesystem/list_directory.h>
14#include <VirtualRobot/VirtualRobot.h>
15#include <VirtualRobot/XML/ObjectIO.h>
16
20
25
26namespace armarx
27{
28 namespace fs = std::filesystem;
29
30 ObjectFinder::ObjectFinder(const std::string& objectsPackageName,
31 const ObjectFinder::path& relObjectsDir) :
32 packageName(objectsPackageName), relObjectsDir(relObjectsDir)
33 {
34 Logging::setTag("ObjectFinder");
35 }
36
37 void
38 ObjectFinder::setPath(const std::string& path)
39 {
40 packageName = path;
41 absPackageDataDir.clear();
42 }
43
44 std::string
46 {
47 return packageName;
48 }
49
50 void
51 ObjectFinder::init() const
52 {
53 if (absPackageDataDir.empty())
54 {
55 CMakePackageFinder packageFinder(packageName);
56 absPackageDataDir = packageFinder.getDataDir();
57 if (absPackageDataDir.empty())
58 {
59 ARMARX_WARNING << "Could not find package '" << packageName << "'.";
60 // throw LocalException() << "Could not find package '" << packageName << "'.";
61 }
62 else
63 {
64 ARMARX_VERBOSE << "Objects root directory: " << _rootDirAbs();
65
66 // make sure this data path is available => e.g. for findArticulatedObjects
67 armarx::ArmarXDataPath::addDataPaths(std::vector<std::string>{absPackageDataDir});
68 }
69 }
70 }
71
72 bool
73 ObjectFinder::isDatasetDirValid(const path& path) const
74 {
75 return std::filesystem::is_directory(path);
76 }
77
78 std::optional<ObjectInfo>
79 ObjectFinder::findObject(const std::string& dataset, const std::string& name) const
80 {
81 init();
82 if (!_ready())
83 {
84 return std::nullopt;
85 }
86 if (!dataset.empty())
87 {
88 return ObjectInfo(packageName, absPackageDataDir, relObjectsDir, dataset, name);
89 }
90 // Search for object in datasets.
91 const std::vector<std::string>& datasets = getDatasets();
92 for (const std::string& ds : datasets)
93 {
94 if (fs::is_directory(_rootDirAbs() / ds / name))
95 {
96 return ObjectInfo(packageName, absPackageDataDir, relObjectsDir, ds, name);
97 }
98 }
99
100 std::stringstream ss;
101 ss << "Did not find object '" << name << "' in any of these datasets:\n";
102 for (const auto& ds : datasets)
103 {
104 ss << "- " << ds << "\n";
105 }
106 ss << "Objects root directory: " << _rootDirAbs();
107 ARMARX_VERBOSE << ss.str();
108
109 return std::nullopt;
110 }
111
112 std::optional<ObjectInfo>
113 ObjectFinder::findObject(const std::string& nameOrID) const
114 {
115 return findObject(ObjectID(nameOrID));
116 }
117
118 std::optional<ObjectInfo>
120 {
121 return findObject(id.dataset(), id.className());
122 }
123
124 std::optional<ObjectInfo>
126 {
127 return findObject(obj.objectID);
128 }
129
130 std::vector<std::string>
132 {
133 // init(); // Done by called methods.
134 std::vector<std::string> datasets;
135 for (const path& dir : getDatasetDirectories())
136 {
137 datasets.push_back(dir.filename());
138 }
139 return datasets;
140 }
141
142 std::vector<ObjectFinder::path>
144 {
145 init();
146 if (!_ready())
147 {
148 return {};
149 }
150 const bool local = false;
151 std::vector<path> dirs = simox::fs::list_directory(_rootDirAbs(), local);
152 std::vector<path> datasetDirs;
153 for (const path& p : dirs)
154 {
155 if (isDatasetDirValid(p))
156 {
157 datasetDirs.push_back(p);
158 }
159 }
160 return datasetDirs;
161 }
162
163 std::vector<ObjectInfo>
164 ObjectFinder::findAllObjects(bool checkPaths) const
165 {
166 init();
167 if (!_ready())
168 {
169 return {};
170 }
171 const bool local = true;
172 std::vector<ObjectInfo> objects;
173 for (const path& datasetDir : simox::fs::list_directory(_rootDirAbs(), local))
174 {
175 if (isDatasetDirValid(_rootDirAbs() / datasetDir))
176 {
177 std::vector<ObjectInfo> dataset = findAllObjectsOfDataset(datasetDir, checkPaths);
178 for (const auto& o : dataset)
179 {
180 objects.push_back(o);
181 }
182 }
183 }
184 return objects;
185 }
186
187 std::vector<armem::articulated_object::ArticulatedObjectDescription>
189 {
190 init();
191 if (!_ready())
192 {
193 return {};
194 }
195
196 const bool local = true;
197
198 std::vector<armem::articulated_object::ArticulatedObjectDescription> objects;
199 for (const path& datasetDir : simox::fs::list_directory(_rootDirAbs(), local))
200 {
201 if (isDatasetDirValid(_rootDirAbs() / datasetDir))
202 {
203 const auto dataset = findAllArticulatedObjectsOfDataset(datasetDir, checkPaths);
204 objects.insert(objects.end(), dataset.begin(), dataset.end());
205 }
206 }
207 return objects;
208 }
209
210 std::map<std::string, std::vector<ObjectInfo>>
212 {
213 // init(); // Done by called methods.
214 std::map<std::string, std::vector<ObjectInfo>> objects;
215 for (const std::string& dataset : getDatasets())
216 {
217 objects[dataset] = findAllObjectsOfDataset(dataset, checkPaths);
218 }
219 return objects;
220 }
221
222 std::vector<ObjectInfo>
223 ObjectFinder::findAllObjectsOfDataset(const std::string& dataset, bool checkPaths) const
224 {
225 init();
226 if (!_ready())
227 {
228 return {};
229 }
230 path datasetDir = _rootDirAbs() / dataset;
231 if (!fs::is_directory(datasetDir))
232 {
233 ARMARX_WARNING << "Expected dataset directory for dataset '" << dataset << "': \n"
234 << datasetDir;
235 return {};
236 }
237
238 std::vector<ObjectInfo> objects;
239 const bool local = true;
240 for (const path& dir : simox::fs::list_directory(datasetDir, local))
241 {
242 if (fs::is_directory(datasetDir / dir))
243 {
244 ObjectInfo object(packageName,
245 absPackageDataDir,
246 relObjectsDir,
247 dataset,
248 dir.filename());
249 object.setLogError(logObjectDiscoveryError);
250
251 if (!checkPaths || object.checkPaths())
252 {
253 objects.push_back(object);
254 }
255 }
256 }
257 return objects;
258 }
259
260 std::unordered_map<std::string,
261 std::vector<armem::articulated_object::ArticulatedObjectDescription>>
263 {
264 init();
265 if (!_ready())
266 {
267 return {};
268 }
269
270 const bool local = true;
271
272 std::unordered_map<std::string,
273 std::vector<armem::articulated_object::ArticulatedObjectDescription>>
274 datasets;
275 for (const path& datasetDir : simox::fs::list_directory(_rootDirAbs(), local))
276 {
277 if (isDatasetDirValid(_rootDirAbs() / datasetDir))
278 {
279 const auto dataset = findAllArticulatedObjectsOfDataset(datasetDir, checkPaths);
280 datasets[datasetDir] = dataset;
281 }
282 }
283 return datasets;
284 }
285
286 std::vector<armem::articulated_object::ArticulatedObjectDescription>
288 bool /*checkPaths*/) const
289 {
290 init();
291 if (!_ready())
292 {
293 return {};
294 }
295 path datasetDir = _rootDirAbs() / dataset;
296 if (!isDatasetDirValid(datasetDir))
297 {
298 ARMARX_WARNING << "Expected dataset directory for dataset '" << dataset << "': \n"
299 << datasetDir;
300 return {};
301 }
302
303 std::vector<armem::articulated_object::ArticulatedObjectDescription> objects;
304 const bool local = true;
305 for (const path& dir : simox::fs::list_directory(datasetDir, local))
306 {
307 if (fs::is_directory(datasetDir / dir))
308 {
309 ObjectInfo object(packageName,
310 absPackageDataDir,
311 relObjectsDir,
312 dataset,
313 dir.filename());
314 std::optional<PackageFileLocation> modelFile = object.getArticulatedModel();
315 if (modelFile.has_value())
316 {
318 .name = object.idStr(),
319 .xml = {modelFile->package, modelFile->relativePath},
320 .visualization = {},
321 .info = {}
322 // .dataset = dataset
323 });
324 }
325 }
326 }
327 return objects;
328 }
329
330 VirtualRobot::ManipulationObjectPtr
331 ObjectFinder::loadManipulationObject(const std::optional<ObjectInfo>& ts,
332 const VirtualRobot::ObjectIO::ObjectDescription loadMode)
333 {
334 if (!ts)
335 {
336 return nullptr;
337 }
338 const auto data = ts->simoxXML();
340 std::string abs;
341 if (!ArmarXDataPath::SearchReadableFile(data.relativePath, abs))
342 {
343 return nullptr;
344 }
345 return VirtualRobot::ObjectIO::loadManipulationObject(abs, loadMode);
346 }
347
348 VirtualRobot::ManipulationObjectPtr
350 const objpose::ObjectPose& obj,
351 const VirtualRobot::ObjectIO::ObjectDescription loadMode) const
352 {
353 return loadManipulationObject(findObject(obj), loadMode);
354 }
355
356 VirtualRobot::ObstaclePtr
357 ObjectFinder::loadObstacle(const std::optional<ObjectInfo>& ts)
358 {
359 if (!ts)
360 {
361 return nullptr;
362 }
363 const auto data = ts->simoxXML();
365 std::string abs;
366 if (!ArmarXDataPath::SearchReadableFile(data.relativePath, abs))
367 {
368 return nullptr;
369 }
370 return VirtualRobot::ObjectIO::loadObstacle(abs);
371 }
372
373 VirtualRobot::ObstaclePtr
375 {
376 return loadObstacle(findObject(obj));
377 }
378
379 static std::vector<std::string>
380 _loadNames(
381 const ObjectFinder& finder,
382 const ObjectID& objectID,
383 const bool includeClassName,
384 const std::function<std::optional<std::vector<std::string>>(const ObjectInfo&)> loadNamesFn)
385 {
386 std::vector<std::string> names;
387 if (includeClassName)
388 {
389 names.push_back(simox::alg::to_lower(objectID.className()));
390 }
391 if (std::optional<ObjectInfo> info = finder.findObject(objectID))
392 {
393 if (std::optional<std::vector<std::string>> loadedNames = loadNamesFn(*info))
394 {
395 // Source: https://stackoverflow.com/a/201729
396 names.insert(names.end(), loadedNames->begin(), loadedNames->end());
397 }
398 }
399 return names;
400 }
401
402 std::vector<std::string>
403 ObjectFinder::loadRecognizedNames(const ObjectID& objectID, bool includeClassName) const
404 {
405 return _loadNames(*this,
406 objectID,
407 includeClassName,
408 [](const ObjectInfo& info) { return info.loadRecognizedNames(); });
409 }
410
411 std::vector<std::string>
412 ObjectFinder::loadSpokenNames(const ObjectID& objectID, bool includeClassName) const
413 {
414 return _loadNames(*this,
415 objectID,
416 includeClassName,
417 [](const ObjectInfo& info) { return info.loadSpokenNames(); });
418 }
419
420 void
422 {
423 logObjectDiscoveryError = logEnabled;
424 }
425
427 ObjectFinder::_rootDirAbs() const
428 {
429 return absPackageDataDir / packageName / relObjectsDir;
430 }
431
433 ObjectFinder::_rootDirRel() const
434 {
435 return packageName;
436 }
437
438 bool
439 ObjectFinder::_ready() const
440 {
441 return !absPackageDataDir.empty();
442 }
443
444} // namespace armarx
static bool SearchReadableFile(const std::string &querryFileName, std::string &resultFileName, bool verbose=true)
static void addDataPaths(const std::string &dataPathList)
static bool FindPackageAndAddDataPath(const std::string &packageName)
Search for the package and add its data path if it was found.
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
void setTag(const LogTag &tag)
Definition Logging.cpp:54
Used to find objects in the ArmarX objects repository [1] (formerly [2]).
std::vector< path > getDatasetDirectories() const
std::vector< std::string > loadSpokenNames(const ObjectID &objectID, bool includeClassName=false) const
Load names to use when verbalizing an object name.
ObjectFinder(const std::string &objectsPackageName=DefaultObjectsPackageName, const path &relObjectsDir=DefaultObjectsDirectory)
std::vector< std::string > getDatasets() const
static VirtualRobot::ObstaclePtr loadObstacle(const std::optional< ObjectInfo > &ts)
std::vector< std::string > loadRecognizedNames(const ObjectID &objectID, bool includeClassName=false) const
Load names to use when matched when recognizing an object by name.
std::vector< ObjectInfo > findAllObjects(bool checkPaths=true) const
std::unordered_map< std::string, std::vector< armem::articulated_object::ArticulatedObjectDescription > > findAllArticulatedObjectsByDataset(bool checkPaths=true) const
std::string getPackageName() const
void setPath(const std::string &path)
std::filesystem::path path
static VirtualRobot::ManipulationObjectPtr loadManipulationObject(const std::optional< ObjectInfo > &ts, VirtualRobot::ObjectIO::ObjectDescription loadMode=VirtualRobot::ObjectIO::ObjectDescription::eFull)
std::vector< armem::articulated_object::ArticulatedObjectDescription > findAllArticulatedObjects(bool checkPaths) const
std::vector< armem::articulated_object::ArticulatedObjectDescription > findAllArticulatedObjectsOfDataset(const std::string &dataset, bool checkPaths) const
void setLogObjectDiscoveryError(bool logEnabled)
std::vector< ObjectInfo > findAllObjectsOfDataset(const std::string &dataset, bool checkPaths=true) const
std::map< std::string, std::vector< ObjectInfo > > findAllObjectsByDataset(bool checkPaths=true) const
std::optional< ObjectInfo > findObject(const std::string &dataset, const std::string &name) const
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
Definition ObjectID.h:11
std::string className() const
Definition ObjectID.h:30
Accessor for the object files.
Definition ObjectInfo.h:37
std::optional< std::vector< std::string > > loadSpokenNames() const
Load names to use when verbalizing an object name.
std::optional< std::vector< std::string > > loadRecognizedNames() const
Load names to use when matched when recognizing an object by name.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
armarx::armem::robot_state::description::RobotDescription ArticulatedObjectDescription
Definition types.h:138
const simox::meta::IntEnumNames names
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::vector< T > abs(const std::vector< T > &v)
An object pose as stored by the ObjectPoseStorage.
Definition ObjectPose.h:34
armarx::ObjectID objectID
The object ID, i.e. dataset, class name and instance name.
Definition ObjectPose.h:56