28#include <SimoxUtility/algorithm/string/string_tools.h>
40#include <range/v3/algorithm/contains.hpp>
41#include <range/v3/range/conversion.hpp>
42#include <range/v3/view/concat.hpp>
43#include <range/v3/view/filter.hpp>
44#include <range/v3/view/map.hpp>
45#include <range/v3/view/transform.hpp>
54 std::optional<ResolvedLocation>
55 resolveFromObject(
const std::string& locationName,
59 const auto objectPoseStorage = services.objectPoseClient.getObjectPoseStorage();
60 const auto objectPosesIce = objectPoseStorage->getObjectPoses();
62 const std::map<armarx::ObjectID, armem::clazz::ObjectClass> objectClasses =
63 services.objectClassReader->getAllObjectClasses();
69 const auto isMatchingObject = [&](
const objpose::ObjectPose& pose) ->
bool
72 if (not ranges::contains(ranges::views::keys(objectClasses),
73 pose.objectID.getClassID(),
74 [](
const armarx::ObjectID& oid)
75 { return oid.getClassID(); }))
77 ARMARX_VERBOSE <<
"Requested to match object but there is no match";
81 const auto& objectClass = objectClasses.at(pose.objectID.getClassID());
82 const auto& recognizedNames = objectClass.names.recognized;
85 return ranges::contains(recognizedNames,
86 simox::alg::to_lower(locationName),
87 simox::alg::to_lower);
91 const std::vector<objpose::ObjectPose> matchingObjects =
92 objectPoses | ranges::views::filter(isMatchingObject) | ranges::to<std::vector>();
94 ARMARX_INFO <<
"Found " << matchingObjects.size() <<
" objects matching location name '"
95 << locationName <<
"'.";
97 const auto locations = services.locationReader->locations();
99 const auto getMatchingLocation =
100 [&](
const objpose::ObjectPose& pose) -> std::vector<core::Location>
102 const std::string inFrontOfName = pose.objectID.getClassID().str() +
"/inFrontOf";
103 const std::string inFrontOfNameWithInstance =
104 pose.objectID.getClassID().str() +
"/inFrontOf:" + pose.objectID.instanceName();
106 const auto matchingLocations =
108 ARMARX_INFO <<
"Found " << matchingLocations.size() <<
" locations matching name "
109 <<
QUOTED(inFrontOfName) <<
".";
112 locations, inFrontOfNameWithInstance, std::nullopt);
113 ARMARX_INFO <<
"Found " << matchingLocationsWithInstance.size()
114 <<
" locations matching name " <<
QUOTED(inFrontOfNameWithInstance)
117 const auto appendLocationInstanceName = [&pose](core::Location loc) -> core::Location
119 loc.name +=
":" + pose.objectID.instanceName();
124 const auto matchingLocationsWithAppendedInstance =
125 matchingLocations | ranges::views::transform(appendLocationInstanceName) |
126 ranges::to<std::vector>();
128 return ranges::views::concat(matchingLocationsWithAppendedInstance,
129 matchingLocationsWithInstance) |
130 ranges::to<std::vector>();
134 std::vector<core::Location> associatedLocations;
135 for (
const auto& matchingObject : matchingObjects)
137 const auto locationsForObject = getMatchingLocation(matchingObject);
138 for (
const core::Location& loc : locationsForObject)
141 <<
" for matching object " <<
QUOTED(matchingObject.objectID.str())
143 associatedLocations.push_back(loc);
147 ARMARX_INFO <<
"Found total of " << associatedLocations.size()
148 <<
" associated locations for matching objects.";
150 for (
const auto& loc : associatedLocations)
155 if (associatedLocations.empty())
160 if (associatedLocations.size() > 1)
162 ARMARX_WARNING <<
"Multiple associated locations found for matching objects. Using "
166 const auto& firstLocation = *associatedLocations.begin();
168 return ResolvedLocation{.name = firstLocation.name, .provider = firstLocation.provider};
172 std::optional<ResolvedLocation>
173 resolveFromKnownLocations(
const std::string& locationName,
175 double minMatchRatio)
177 std::stringstream log;
179 services.locationReader->resolveLocationName(locationName, minMatchRatio, &log);
182 ARMARX_CHECK(matchResult.resolved.has_value() xor matchResult.errorMessage.has_value());
184 if (matchResult.errorMessage.has_value())
186 ARMARX_INFO <<
"Failed to resolve location name '" << locationName
187 <<
"'. Reason: " << matchResult.errorMessage.value();
192 return ResolvedLocation{.name = matchResult.resolved->locationId.entityName,
194 matchResult.resolved->locationId.providerSegmentName};
199 std::optional<ResolvedLocation>
202 const double minMatchRatio,
203 const bool useObjectLocations)
208 if (useObjectLocations)
210 if (
const auto resolved = resolveFromObject(locationName, services))
212 ARMARX_INFO <<
"Resolved location name '" << locationName
213 <<
"' to location associated with matching object.";
218 if (
const auto resolved =
219 resolveFromKnownLocations(locationName, services, minMatchRatio))
221 ARMARX_INFO <<
"Resolved location name '" << locationName <<
"' to known location: "
222 <<
QUOTED(resolved->provider +
"::" + resolved->name) <<
".";
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
std::vector< core::Location > findMatchingLocations(const std::vector< core::Location > &locations, const std::string &locationName, const std::optional< std::string > &provider)
std::optional< ResolvedLocation > resolveLocationName(const std::string &locationName, const LocationNameResolverServices &services, const double minMatchRatio, const bool useObjectLocations)
Resolve a human-readable place onto a location, the way NavigateToNamedLocation does.
std::vector< ObjectPose > ObjectPoseSeq
void fromIce(const Box &box, simox::OrientedBox< float > &oobb)
Everything needed to turn a spoken place into a location.
memory::client::graph::Reader * locationReader
armarx::armem::obj::clazz::ClassReader * objectClassReader
A location in the navigation memory, identified the way the memory identifies it.