25#include <RobotAPI/gui-plugins/ObjectPoseGui/ui_ObjectPoseGuiWidget.h>
41 static const int OBJECTS_COLUMN_ATTACHMENT = 6;
45 widget = std::make_unique<Ui::ObjectPoseGuiWidget>();
48 widget->objectsTree->clear();
49 widget->objectsTree->sortItems(0, Qt::SortOrder::AscendingOrder);
50 widget->objectsTree->setContextMenuPolicy(Qt::CustomContextMenu);
52 widget->requestTree->clear();
53 widget->requestTree->sortItems(0, Qt::SortOrder::AscendingOrder);
58 connect(widget->updateButton, &QPushButton::pressed,
this, &This::updateTab);
59 connect(widget->tabWidget, &QTabWidget::currentChanged,
this, &This::updateTab);
60 connect(widget->detchAllButton,
61 &QPushButton::pressed,
63 this->detachAllObjectsFromRobotNodes(
64 widget->detchAllCommitAttachedCheckBox->isChecked());
67 connect(widget->objectsTree,
68 &QTreeWidget::customContextMenuRequested,
70 &This::prepareObjectContextMenu);
72 connect(widget->requestButton, &QPushButton::pressed,
this, &This::requestSelectedObjects);
74 QTimer* timer =
new QTimer(
this);
75 timer->setInterval(500);
76 connect(timer, &QTimer::timeout,
this, &This::updateTab);
77 connect(widget->autoUpdateCheckBox,
112 return "ArMem.ObjectPoseGui";
115 static const std::string CONFIG_KEY_OBJECT_POSE_STORAGE =
"ObjectPoseStorage";
123 configDialog->addProxyFinder<armarx::objpose::ObjectPoseStorageInterfacePrx>(
124 {CONFIG_KEY_OBJECT_POSE_STORAGE,
"Object pose storage",
"Object*"});
126 return qobject_cast<QDialog*>(configDialog);
134 objectPoseStorageName = configDialog->getProxyName(CONFIG_KEY_OBJECT_POSE_STORAGE);
135 if (objectPoseStorageName.empty())
137 objectPoseStorageName =
"ObjectMemory";
145 if (!objectPoseStorageName.empty())
154 if (!objectPoseStorageName.empty())
156 getProxy(ObjectPoseStorage, objectPoseStorageName);
159 this->attachableFrames = ObjectPoseStorage->getAttachableFrames();
160 std::sort(attachableFrames.begin(),
161 attachableFrames.end(),
162 [](
const auto& lhs,
const auto& rhs) { return lhs.agent < rhs.agent; });
163 for (objpose::AgentFrames& frames : attachableFrames)
165 std::sort(frames.frames.begin(), frames.frames.end());
175 ObjectPoseStorage =
nullptr;
181 if (widget->tabWidget->currentWidget() == widget->tabObjects)
185 else if (widget->tabWidget->currentWidget() == widget->tabRequest)
194 if (!ObjectPoseStorage)
201 IceUtil::Time start = IceUtil::Time::now();
203 const objpose::data::ObjectPoseSeq objectPosesIce = ObjectPoseStorage->getObjectPoses();
204 ARMARX_VERBOSE <<
"Got " << objectPosesIce.size() <<
" object poses. "
205 <<
"(Took " << (IceUtil::Time::now() - start).toMilliSecondsDouble()
210 std::map<std::string, objpose::ObjectPoseSeq> objectPosesByProvider;
211 for (
const auto& pose : objectPoses)
213 objectPosesByProvider[pose.providerName].push_back(pose);
216 start = IceUtil::Time::now();
218 QTreeWidget* tree = widget->objectsTree;
224 QTreeWidgetItem* item =
new QTreeWidgetItem({QString::fromStdString(provider)});
230 bool expand = item->childCount() == 0;
238 QTreeWidgetItem* item =
new QTreeWidgetItem(QStringList{});
245 item->setText(col++, QString::fromStdString(pose.
objectID.
str()));
246 item->setText(col++, QString::fromStdString(pose.
providerName));
248 QString::fromStdString(
252 std::stringstream ss;
255 static const Eigen::IOFormat iof(5, 0,
"",
" x ",
"",
"",
"",
"");
256 ss << pose.
localOOBB->dimensions().format(iof);
262 item->setText(col++, QString::fromStdString(ss.str()));
264 item->setText(col++, QString::number(
double(pose.
confidence),
'g', 2));
269 std::stringstream ss;
275 item->setText(col++, QString::fromStdString(ss.str()));
284 item->setExpanded(
true);
289 builder.
updateTree(tree, objectPosesByProvider);
292 << (IceUtil::Time::now() - start).toMilliSecondsDouble() <<
" ms.";
298 if (!ObjectPoseStorage)
305 IceUtil::Time start = IceUtil::Time::now();
306 objpose::ProviderInfoMap availableProvidersInfo =
307 ObjectPoseStorage->getAvailableProvidersInfo();
308 ARMARX_VERBOSE <<
"Got infos of " << availableProvidersInfo.size()
309 <<
" object pose providers. "
310 <<
"(Took " << (IceUtil::Time::now() - start).toMilliSecondsDouble()
315 std::map<std::string, std::set<std::pair<std::string, std::string>>>
data;
316 for (
const auto& [providerName, info] : availableProvidersInfo)
318 for (
const auto&
id : info.supportedObjects)
320 data[
id.dataset].insert(std::make_pair(
id.className, providerName));
324 start = IceUtil::Time::now();
326 QTreeWidget* tree = widget->requestTree;
330 [](
const std::string& dataset,
const auto&)
332 QTreeWidgetItem* item =
new QTreeWidgetItem({QString::fromStdString(dataset)});
337 const std::string& dataset,
const auto& datasetData, QTreeWidgetItem* datasetItem)
343 [](
const std::pair<std::string, std::string>& lhs, QTreeWidgetItem* item)
345 auto rhs = std::make_pair(item->text(0).toStdString(),
346 item->text(1).toStdString());
351 return lhs == rhs ? 0 : 1;
354 [](
const std::pair<std::string, std::string>& element)
356 QTreeWidgetItem* item =
357 new QTreeWidgetItem({QString::fromStdString(element.first),
358 QString::fromStdString(element.second)});
362 [tree](
const std::pair<std::string, std::string>& element,
363 QTreeWidgetItem* item)
366 if (!tree->itemWidget(item, 2))
368 QCheckBox* requestCheckBox =
new QCheckBox();
369 tree->setItemWidget(item, 2, requestCheckBox);
380 << (IceUtil::Time::now() - start).toMilliSecondsDouble() <<
" ms.";
386 QTreeWidget* tree = widget->objectsTree;
387 QTreeWidgetItem* item = tree->itemAt(pos);
389 if (item ==
nullptr || item->parent() ==
nullptr)
395 QString providerName = item->parent()->text(0);
396 QString objectID = item->text(0);
398 QMenu* attachMenu =
new QMenu(
"Attach to robot node", tree);
399 for (
const objpose::AgentFrames& agentFrames : attachableFrames)
401 QMenu* agentMenu =
new QMenu(QString::fromStdString(agentFrames.agent), tree);
403 for (
const std::string& frame : agentFrames.frames)
405 QAction* attachAgentAction =
new QAction(QString::fromStdString(frame), tree);
407 connect(attachAgentAction,
411 providerName, objectID, agentFrames.agent, frame);
413 agentMenu->addAction(attachAgentAction);
415 attachMenu->addMenu(agentMenu);
418 QAction* detachAction =
new QAction(tr(
"Detach from to robot node"), tree);
419 detachAction->setEnabled(!item->text(OBJECTS_COLUMN_ATTACHMENT).isEmpty());
420 connect(detachAction,
425 menu.addMenu(attachMenu);
426 menu.addAction(detachAction);
428 menu.exec(tree->mapToGlobal(pos));
434 const std::string& agentName,
435 const std::string& frameName)
437 ARMARX_VERBOSE <<
"Attaching " << objectID <<
" by '" << providerName <<
"' to robot node '"
438 << frameName <<
"' of agent '" << agentName <<
"'.";
440 objpose::AttachObjectToRobotNodeInput input;
441 input.providerName = providerName.toStdString();
443 input.agentName = agentName;
444 input.frameName = frameName;
448 objpose::AttachObjectToRobotNodeOutput output =
449 ObjectPoseStorage->attachObjectToRobotNode(input);
452 catch (
const IceUtil::Exception& e)
454 ARMARX_WARNING <<
"Failed to attach object '" << input.objectID <<
"' to robot node '"
455 << input.frameName <<
"' of agent '" << input.agentName <<
"'."
456 <<
"\nReason: " << e.what();
463 ARMARX_VERBOSE <<
"Detaching " << objectID <<
" by '" << providerName
464 <<
"' from robot node.";
466 objpose::DetachObjectFromRobotNodeInput input;
467 input.providerName = providerName.toStdString();
472 objpose::DetachObjectFromRobotNodeOutput output =
473 ObjectPoseStorage->detachObjectFromRobotNode(input);
476 catch (
const IceUtil::Exception& e)
479 <<
"' from a robot node."
480 <<
"\nReason: " << e.what();
488 objpose::DetachAllObjectsFromRobotNodesInput input;
489 input.commitAttachedPose = commitAttachedPose;
493 objpose::DetachAllObjectsFromRobotNodesOutput output =
494 ObjectPoseStorage->detachAllObjectsFromRobotNodes(input);
495 ARMARX_VERBOSE <<
"Detached " << output.numDetached <<
" objects from robot nodes.";
497 catch (
const IceUtil::Exception& e)
499 ARMARX_WARNING <<
"Failed to detach all objects from robot nodes.";
506 std::map<std::string, objpose::observer::RequestObjectsInput> requestsPerProvider;
508 QTreeWidget* tree = widget->requestTree;
509 for (
int i = 0; i < tree->topLevelItemCount(); ++i)
511 QTreeWidgetItem* datasetItem = tree->topLevelItem(i);
512 for (
int j = 0; j < datasetItem->childCount(); ++j)
514 QTreeWidgetItem* classItem = datasetItem->child(j);
515 QCheckBox* selected =
dynamic_cast<QCheckBox*
>(tree->itemWidget(classItem, 2));
517 if (selected->isChecked())
519 std::string providerName = classItem->text(1).toStdString();
520 objpose::observer::RequestObjectsInput& requests =
521 requestsPerProvider[providerName];
522 data::ObjectID&
id = requests.request.objectIDs.emplace_back();
523 id.dataset = datasetItem->text(0).toStdString();
524 id.className = classItem->text(0).toStdString();
530 if (!widget->requestInfiniteCheckBox->isChecked())
532 timeoutMS = long(widget->requestTimeoutSpinBox->value() * 1000);
535 for (
auto& [providerName, request] : requestsPerProvider)
537 request.provider = providerName;
538 request.request.relativeTimeoutMS = timeoutMS;
540 ARMARX_INFO <<
"Requesting " << request.request.objectIDs.size() <<
" objects for "
541 << request.request.relativeTimeoutMS <<
" ms.";
542 objpose::observer::RequestObjectsOutput output =
543 ObjectPoseStorage->requestObjects(request);
545 for (
const auto& [
id, result] : output.results)
547 successful += int(!result.providerName.empty() && result.result.success);
549 ARMARX_INFO << successful <<
" of " << request.request.objectIDs.size()
550 <<
" object request successful.";
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
std::string str() const
Return "dataset/className" or "dataset/className/instanceName".
A config-dialog containing one (or multiple) proxy finders.
std::string toDateTimeString() const
#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< ObjectPose > ObjectPoseSeq
void fromIce(const Box &box, simox::OrientedBox< float > &oobb)
const simox::meta::EnumNames< objpose::ObjectType > ObjectTypeNames
This file offers overloads of toIce() and fromIce() functions for STL container types.
void toIce(std::map< IceKeyT, IceValueT > &iceMap, const boost::container::flat_map< CppKeyT, CppValueT > &cppMap)
An object pose as stored by the ObjectPoseStorage.
float confidence
Confidence in [0, 1] (1 = full, 0 = none).
armarx::ObjectID objectID
The object ID, i.e. dataset, class name and instance name.
std::optional< ObjectAttachmentInfo > attachment
Attachment information.
std::string providerName
Name of the providing component.
DateTime timestamp
Source timestamp.
ObjectType objectType
Known or unknown object.
std::optional< simox::OrientedBoxf > localOOBB
Object bounding box in object's local coordinate frame.