25 #include <VirtualRobot/MathTools.h>
39 #include <QPushButton>
42 #include <QHBoxLayout>
49 #include <unordered_set>
54 #include <MemoryX/gui-plugins/GraphVisualizerPlugin/ui_GraphVisualizerConfigDialog.h>
63 #define DEFAULT_PRIOR_KNOWLEDGE_NAME "PriorKnowledge"
64 #define DEFAULT_DEBUG_DRAWER_NAME "DebugDrawerUpdates"
65 #define DEFAULT_DEBUG_DRAWER_LAYER_NAME "DebugDrawerUpdates_Graph"
79 static const ::armarx::DrawColor COLOR_DEFAULT = {0.5f, 0.5f, 1.f, 0.2f};
83 static const ::armarx::DrawColor COLOR_HIGHLIGHT = {1.f, 0.0f, 0.f, 1.f};
88 static const float SCENE_SCALE_FACTOR = 2;
92 static const float SCENE_NODES_SCALE_FACTOR = 3 * SCENE_SCALE_FACTOR;
96 static const float SCENE_LINE_SCALE_FACTOR = SCENE_SCALE_FACTOR;
107 static const float VIEW_ROTATE_STEP_SIZE_CC = 45;
109 static const QString SETTING_LAST_SCENE =
"lastScene";
119 s <<
"edge_" << edge.first <<
"_" << edge.second;
136 addWidget<GraphVisualizerWidget>();
146 settings {
"KIT",
"GraphVisualizerGuiPlugin"}
148 loadAutomaticSettings();
149 editStartNodeNext =
true;
152 ui.setupUi(getWidget());
154 std::unique_ptr<QGraphicsScene> scenePtr{
new QGraphicsScene};
155 scene = scenePtr.get();
156 ui.graphicsViewGraph->setScene(scenePtr.release());
158 ui.graphicsViewGraph->installEventFilter(mep);
180 debugDrawer = getTopic<armarx::DebugDrawerInterfacePrx>(debugDrawerTopicName);
181 priorKnowledgePrx = getProxy<memoryx::PriorKnowledgeInterfacePrx>(priorKnowledgeProxyName);
182 getProxy(gnpr,
"GraphNodePoseResolver");
184 if (priorKnowledgePrx->hasGraphSegment())
187 graphSeg = priorKnowledgePrx->getGraphSegment();
188 ui.sceneGroupBox->setEnabled(
true);
189 ui.sceneGroupBox->setTitle(
"Scenes from graph memory segment");
191 ui.b->setEnabled(
true);
195 ui.sceneGroupBox->setEnabled(
false);
196 ui.sceneGroupBox->setTitle(
"Scenes from graph memory segment (No graph memory segment available)");
198 ui.b->setEnabled(
false);
201 ui.tableWidgetNodes->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
202 ui.tableWidgetEdges->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
204 ui.tableWidgetNodes->setContextMenuPolicy(Qt::CustomContextMenu);
205 ui.tableWidgetEdges->setContextMenuPolicy(Qt::CustomContextMenu);
208 QObject::connect(
ui.b, SIGNAL(clicked()),
this, SLOT(addKitchenGraph()), Qt::UniqueConnection);
211 QObject::connect(
ui.tableWidgetNodes, SIGNAL(cellDoubleClicked(
int,
int)),
this, SLOT(nodeTableDoubleClicked(
int,
int)), Qt::UniqueConnection);
213 QObject::connect(
ui.tableWidgetEdges, SIGNAL(cellDoubleClicked(
int,
int)),
this, SLOT(edgeTableDoubleClicked(
int,
int)), Qt::UniqueConnection);
216 QObject::connect(
ui.btnAdd, SIGNAL(clicked()),
this, SLOT(addNewGraphNode()), Qt::UniqueConnection);
217 QObject::connect(
ui.btnAddEdge, SIGNAL(clicked()),
this, SLOT(addNewEdgeBoth()), Qt::UniqueConnection);
218 QObject::connect(
ui.btnAddEdgeStartEnd, SIGNAL(clicked()),
this, SLOT(addNewEdgeStartEnd()), Qt::UniqueConnection);
219 QObject::connect(
ui.btnAddEdgeEndStart, SIGNAL(clicked()),
this, SLOT(addNewEdgeEndStart()), Qt::UniqueConnection);
220 QObject::connect(
ui.btnEdit, SIGNAL(clicked()),
this, SLOT(editGraphNode()), Qt::UniqueConnection);
223 QObject::connect(
ui.viewZoomFactor, SIGNAL(valueChanged(
double)),
this, SLOT(transformView()), Qt::UniqueConnection);
225 QObject::connect(
ui.buttonRotateClock, SIGNAL(clicked()),
this, SLOT(viewRotatedClock()), Qt::UniqueConnection);
226 QObject::connect(
ui.buttonRotateCounterClock, SIGNAL(clicked()),
this, SLOT(viewRotatedCounterClock()), Qt::UniqueConnection);
228 QObject::connect(
ui.buttonRedraw, SIGNAL(clicked()),
this, SLOT(
redraw()), Qt::UniqueConnection);
229 QObject::connect(
ui.buttonClear, SIGNAL(clicked()),
this, SLOT(
clearGraph()), Qt::UniqueConnection);
231 QObject::connect(
ui.buttonAutoAdjust, SIGNAL(clicked()),
this, SLOT(adjustView()), Qt::UniqueConnection);
233 QObject::connect(
ui.refreshScenesButton, SIGNAL(clicked()),
this, SLOT(updateSceneList()), Qt::UniqueConnection);
234 QObject::connect(
ui.drawSceneButton, SIGNAL(clicked()),
this, SLOT(drawScene()), Qt::UniqueConnection);
235 QObject::connect(
ui.scenesComboBox, SIGNAL(currentIndexChanged(
int)),
this, SLOT(selectedSceneChanged(
int)), Qt::UniqueConnection);
253 dialog->ui->editDebugDrawerProxyName->setText(QString::fromStdString(debugDrawerTopicName));
254 dialog->ui->editDebugDrawerLayerName->setText(QString::fromStdString(debugDrawerLayerName));
255 dialog->ui->editPriorKnowledgeProxyName->setText(QString::fromStdString(priorKnowledgeProxyName));
256 return qobject_cast<GraphVisualizerConfigDialog*>(dialog);
261 debugDrawerTopicName = dialog->ui->editDebugDrawerProxyName->text().toStdString();
262 debugDrawerLayerName = dialog->ui->editDebugDrawerLayerName->text().toStdString();
263 priorKnowledgeProxyName = dialog->ui->editPriorKnowledgeProxyName->text().toStdString();
269 debugDrawerTopicName = settings->value(
"debugDrawerTopicName", QString::fromStdString(debugDrawerTopicName)).toString().toStdString();
270 debugDrawerLayerName = settings->value(
"debugDrawerLayerName", QString::fromStdString(debugDrawerLayerName)).toString().toStdString();
275 settings->setValue(
"debugDrawerTopicName", QString::fromStdString(debugDrawerTopicName));
276 settings->setValue(
"debugDrawerLayerName", QString::fromStdString(debugDrawerLayerName));
281 lastSelectedSceneName = settings.value(SETTING_LAST_SCENE, lastSelectedSceneName).toString();
286 settings.setValue(SETTING_LAST_SCENE, lastSelectedSceneName);
293 ARMARX_WARNING <<
"Edge: " << node1Id <<
", " << node2Id <<
" can't be created! Node " << node1Id <<
" does not exist.";
299 ARMARX_WARNING <<
"Edge: " << node1Id <<
", " << node2Id <<
" can't be created! Node " << node2Id <<
" does not exist.";
303 auto node1dat = nodes.at(node1Id);
304 auto node2dat = nodes.at(node2Id);
309 ARMARX_WARNING <<
"Edge: '" << node1dat.node->getName() <<
"' -> '" << node2dat.node->getName() <<
"' already exists.";
313 auto edgeId = toEdge(node1Id, node2Id);
317 int row =
ui.tableWidgetEdges->rowCount();
318 ui.tableWidgetEdges->setRowCount(row + 1);
319 ui.tableWidgetEdges->setItem(row, 0,
new QTableWidgetItem {QString::fromStdString(node1dat.node->getName())});
320 ui.tableWidgetEdges->setItem(row, 1,
new QTableWidgetItem {QString::fromStdString(node2dat.node->getName())});
326 node1dat.pose->position->x, -node1dat.pose->position->y,
327 node2dat.pose->position->x, -node2dat.pose->position->y
331 scene->addItem(graphicsItem);
333 dynamic_cast<QGraphicsItem*
>(graphicsItem)->setToolTip(QString {
"Edge:"} +QString::fromStdString(node1dat.node->getName()) +
334 QString {
" <-> "} +QString::fromStdString(node2dat.node->getName()));
336 EdgeData
data {graphicsItem, row,
false};
337 edges[edgeId] =
data;
345 auto nodeId = node->getId();
350 globalNodePose = armarx::FramedPosePtr::dynamicCast(gnpr->resolveToGlobalPose(node));
359 NodeData& oldNode = nodes.at(nodeId);
361 << oldNode.pose->position->x <<
", " << oldNode.pose->position->y <<
", " << getYawAngle(oldNode.pose) <<
"| New: "
362 << globalNodePose->position->x <<
", " << globalNodePose->position->y <<
", " << getYawAngle(globalNodePose);
365 ui.tableWidgetNodes->setItem(oldNode.tableWidgetNodesIndex, 1,
new QTableWidgetItem {QString::number(globalNodePose->position->x)});
366 ui.tableWidgetNodes->setItem(oldNode.tableWidgetNodesIndex, 2,
new QTableWidgetItem {QString::number(globalNodePose->position->y)});
367 ui.tableWidgetNodes->setItem(oldNode.tableWidgetNodesIndex, 3,
new QTableWidgetItem {QString::number(getYawAngle(globalNodePose))});
370 oldNode.pose = globalNodePose;
373 for (
const auto& edge : edges)
375 if ((edge.first.first == nodeId) || (edge.first.second == nodeId))
377 updateEdge(edge.first);
385 int row =
ui.tableWidgetNodes->rowCount();
386 ui.tableWidgetNodes->setRowCount(row + 1);
387 ui.tableWidgetNodes->setItem(row, 0,
new QTableWidgetItem {QString::fromStdString(node->getName())});
388 ui.tableWidgetNodes->setItem(row, 1,
new QTableWidgetItem {QString::number(globalNodePose->position->x)});
389 ui.tableWidgetNodes->setItem(row, 2,
new QTableWidgetItem {QString::number(globalNodePose->position->y)});
390 ui.tableWidgetNodes->setItem(row, 3,
new QTableWidgetItem {QString::number(getYawAngle(globalNodePose))});
394 *
this, node->getName(),
395 globalNodePose->position->x, -globalNodePose->position->y, 0, 0
398 scene->addItem(graphicsItem);
401 dynamic_cast<QGraphicsItem*
>(graphicsItem)->setToolTip(QString {
"Node:"} +QString::fromStdString(node->getName()));
404 NodeData
data {node, globalNodePose, graphicsItem, row,
false};
405 nodes.insert({nodeId,
data});
413 for (
auto& edge : edges)
416 scene->removeItem(edge.second.graphicsItem);
417 delete edge.second.graphicsItem;
419 debugDrawer->removePoseVisu(debugDrawerLayerName,
iceName(edge.first));
423 ui.tableWidgetEdges->clearContents();
424 ui.tableWidgetEdges->setRowCount(0);
432 for (
auto& edge : edges)
434 debugDrawer->removeLineVisu(debugDrawerLayerName,
iceName(edge.first));
437 for (
auto& node : nodes)
439 debugDrawer->removeArrowVisu(debugDrawerLayerName,
iceName(node.first));
440 debugDrawer->removeTextVisu(debugDrawerLayerName,
iceName(node.first) +
"text");
441 debugDrawer->removePoseVisu(debugDrawerLayerName,
iceName(node.first));
447 ui.tableWidgetEdges->clearContents();
448 ui.tableWidgetEdges->setRowCount(0);
449 ui.tableWidgetNodes->clearContents();
450 ui.tableWidgetNodes->setRowCount(0);
459 for (
auto& edge : edges)
461 if (edge.second.highlighted)
463 edge.second.highlighted =
false;
464 updateEdge(edge.first);
468 for (
auto& node : nodes)
470 if (node.second.highlighted)
472 node.second.highlighted =
false;
473 updateNode(node.first);
478 void GraphVisualizerWidget::updateEdge(
const EdgeId&
id)
480 const EdgeData&
data = edges.at(
id);
481 auto color = (
data.highlighted) ? COLOR_HIGHLIGHT : COLOR_DEFAULT;
483 qColor.setRedF(color.r);
484 qColor.setGreenF(color.g);
485 qColor.setBlueF(color.b);
487 auto lineWidth = (
data.highlighted) ? LINE_WIDTH_SELECTED : LINE_WIDTH_DEFAULT;
489 posStart->z += posStart->z < 1 ? 10 : 0;
491 posEnd->z += posEnd->z < 1 ? 10 : 0;
493 debugDrawer->setLineVisu(debugDrawerLayerName,
500 data.graphicsItem->setLine(nodes[
id.first].pose->position->x, -nodes[
id.first].pose->position->y,
501 nodes[
id.second].pose->position->x, -nodes[
id.second].pose->position->y);
505 pen.setWidthF(lineWidth * SCENE_LINE_SCALE_FACTOR);
506 data.graphicsItem->setPen(pen);
509 font.setBold(
data.highlighted);
510 ui.tableWidgetEdges->item(
data.tableWidgetEdgesIndex, 0)->setData(Qt::BackgroundRole, qColor);
511 ui.tableWidgetEdges->item(
data.tableWidgetEdgesIndex, 0)->setFont(font);
512 ui.tableWidgetEdges->item(
data.tableWidgetEdgesIndex, 1)->setData(Qt::BackgroundRole, qColor);
513 ui.tableWidgetEdges->item(
data.tableWidgetEdgesIndex, 1)->setFont(font);
516 void GraphVisualizerWidget::updateNode(
const NodeId&
id)
518 NodeData&
data = nodes.at(
id);
520 if (editStartNodeNext)
522 ui.editStartNodeId->setText(QString::fromStdString(
data.node->getId()));
523 ui.editStartNodeName->setText(QString::fromStdString(
data.node->getName()));
527 ui.editEndNodeId->setText(QString::fromStdString(
data.node->getId()));
528 ui.editEndNodeName->setText(QString::fromStdString(
data.node->getName()));
533 editStartNodeNext = !editStartNodeNext;
535 auto color = (
data.highlighted) ? COLOR_HIGHLIGHT : COLOR_DEFAULT;
537 qColor.setRedF(color.r);
538 qColor.setGreenF(color.g);
539 qColor.setBlueF(color.b);
541 auto lineWidth = (
data.highlighted) ? LINE_WIDTH_SELECTED : LINE_WIDTH_DEFAULT;
544 float yaw = getYawAngle(
data.pose) / 180 *
M_PI;
545 Eigen::AngleAxisf aa(yaw, Eigen::Vector3f(0, 0, 1));
546 Eigen::Vector3f dir {0, 1, 0};
547 dir = aa.toRotationMatrix() * dir;
548 debugDrawer->setArrowVisu(debugDrawerLayerName,
iceName(
id),
data.pose->position,
550 armarx::DrawColor {0, 0, 1, 1},
553 debugDrawer->setTextVisu(debugDrawerLayerName,
iceName(
id) +
"text",
data.node->getName(),
data.pose->position, armarx::DrawColor {0, 0, 1, 1}, 10);
556 data.graphicsItem->setPen(QPen {qColor});
557 data.graphicsItem->setBrush(QBrush {qColor});
558 data.graphicsItem->setRect(
data.pose->position->x - lineWidth * SCENE_NODES_SCALE_FACTOR / 2,
559 -
data.pose->position->y - lineWidth * SCENE_NODES_SCALE_FACTOR / 2,
560 lineWidth * SCENE_NODES_SCALE_FACTOR,
561 lineWidth * SCENE_NODES_SCALE_FACTOR);
564 font.setBold(
data.highlighted);
565 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 0)->setData(Qt::BackgroundRole, qColor);
566 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 0)->setFont(font);
567 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 1)->setData(Qt::BackgroundRole, qColor);
568 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 1)->setFont(font);
569 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 2)->setData(Qt::BackgroundRole, qColor);
570 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 2)->setFont(font);
571 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 3)->setData(Qt::BackgroundRole, qColor);
572 ui.tableWidgetNodes->item(
data.tableWidgetNodesIndex, 3)->setFont(font);
575 std::vector<GraphNodeBasePtr> highlightedNodes;
576 for (
const auto& nodeData : nodes)
578 if (nodeData.second.highlighted)
580 highlightedNodes.push_back(nodeData.second.node);
584 for (
auto& edge : edges)
586 if (edge.second.highlighted)
588 edge.second.highlighted =
false;
589 updateEdge(edge.first);
593 for (
const auto& nodeFrom : highlightedNodes)
595 for (
const auto& nodeTo : highlightedNodes)
597 const auto nodeFromId = nodeFrom->getId();
598 const auto nodeToId = nodeTo->getId();
599 if (
hasEdge(nodeFromId, nodeToId))
601 auto edgeId = toEdge(nodeFromId, nodeToId);
602 auto& edge = edges[edgeId];
603 edge.highlighted =
true;
610 float GraphVisualizerWidget::getYawAngle(
const armarx::PoseBasePtr& pose)
const
614 VirtualRobot::MathTools::eigen4f2rpy(p->toEigen(), rpy);
615 return VirtualRobot::MathTools::rad2deg(rpy[2]);
620 if (!
hasEdge(node1Id, node2Id))
622 ARMARX_WARNING <<
"No edge for: " << node1Id <<
" and " << node2Id <<
" [file: " << __FILE__ <<
" | line: " << __LINE__ <<
" | function: " << __PRETTY_FUNCTION__ <<
"]";
626 EdgeId edge = toEdge(node1Id, node2Id);
628 if (edges.at(edge).highlighted != highlighted)
630 edges.at(edge).highlighted = highlighted;
639 ARMARX_WARNING <<
"No node: " << nodeId <<
" [pushBfile: " << __FILE__ <<
" | line: " << __LINE__ <<
" | function: " << __PRETTY_FUNCTION__ <<
"]";
643 if (nodes.at(nodeId).highlighted != highlighted)
645 nodes.at(nodeId).highlighted = highlighted;
651 void GraphVisualizerWidget::nodeTableDoubleClicked(
int row,
int)
653 auto nodeIt = std::find_if(nodes.cbegin(), nodes.cend(), [&](
const std::pair<std::string, NodeData>& d)
656 return d.second.tableWidgetNodesIndex == row;
658 auto nodeId = nodeIt->second.node->getId();
659 nodeDoubleClicked(nodeId);
662 void GraphVisualizerWidget::edgeTableDoubleClicked(
int row,
int)
664 auto edgeIt = std::find_if(edges.cbegin(), edges.cend(), [&](
const std::pair<EdgeId, EdgeData>& d)
666 return d.second.tableWidgetEdgesIndex == row;
669 edgeDoubleClicked(edgeIt->first);
672 void GraphVisualizerWidget::nodeDoubleClicked(NodeId
id)
674 nodes.at(
id).highlighted ^=
true;
678 void GraphVisualizerWidget::edgeDoubleClicked(
EdgeId id)
682 bool highlight = !nodes.at(
id.first).highlighted && !nodes.at(
id.second).highlighted;
683 nodes.at(
id.first).highlighted = highlight;
684 nodes.at(
id.second).highlighted = highlight;
685 updateNode(
id.first);
686 updateNode(
id.second);
694 void GraphVisualizerWidget::setEditFields(
const NodeData& nodeData)
696 ui.editNodeId->setText(QString::fromStdString(nodeData.node->getId()));
697 ui.editSceneName->setText(QString::fromStdString(nodeData.node->getScene()));
698 ui.editNodeName->setText(QString::fromStdString(nodeData.node->getName()));
699 ui.editFrameName->setText(QString::fromStdString(nodeData.pose->frame));
700 ui.editAgentName->setText(QString::fromStdString(nodeData.pose->agent));
703 VirtualRobot::MathTools::eigen4f2rpy(nodeData.pose->toEigen(), rpy);
704 ui.spinBoxX->setValue(nodeData.pose->position->x);
705 ui.spinBoxY->setValue(nodeData.pose->position->y);
706 ui.spinBoxZ->setValue(nodeData.pose->position->z);
708 ui.spinBoxRoll->setValue(VirtualRobot::MathTools::rad2deg(rpy[0]));
709 ui.spinBoxPitch->setValue(VirtualRobot::MathTools::rad2deg(rpy[1]));
710 ui.spinBoxYaw->setValue(VirtualRobot::MathTools::rad2deg(rpy[2]));
719 void GraphVisualizerWidget::transformView()
721 double d =
ui.viewZoomFactor->value();
722 ui.graphicsViewGraph->setTransform(QTransform::fromScale(d, d).rotate(viewAngle));
725 void GraphVisualizerWidget::viewRotatedClock()
727 viewAngle = std::fmod(viewAngle + VIEW_ROTATE_STEP_SIZE_CC, 360);
731 void GraphVisualizerWidget::viewRotatedCounterClock()
733 viewAngle = std::fmod(viewAngle + 360 - VIEW_ROTATE_STEP_SIZE_CC, 360);
737 void GraphVisualizerWidget::adjustView()
745 for (
const auto& node : nodes)
747 maxX = (maxX < node.second.pose->position->x) ? node.second.pose->position->x : maxX;
748 minX = (minX > node.second.pose->position->x) ? node.second.pose->position->x : minX;
749 maxY = (maxY < node.second.pose->position->y) ? node.second.pose->position->y : maxY;
750 minY = (minY > node.second.pose->position->y) ? node.second.pose->position->y : minY;
753 auto deltaX = maxX - minX;
754 auto deltaY = maxY - minY;
757 if (std::signbit(deltaX / deltaY - 1) == std::signbit(
ui.graphicsViewGraph->width() /
ui.graphicsViewGraph->height() - 1))
760 viewAngle = (viewAngle <
std::abs(180 - viewAngle)) ? 0 : 180;
762 ui.viewZoomFactor->setValue(
std::min(
ui.graphicsViewGraph->width() / deltaX,
763 ui.graphicsViewGraph->height() / deltaY) * 0.9);
768 viewAngle = (
std::abs(90 - viewAngle) <
std::abs(270 - viewAngle)) ? 90 : 270;
770 ui.viewZoomFactor->setValue(
std::min(
ui.graphicsViewGraph->width() / deltaY,
771 ui.graphicsViewGraph->height() / deltaX) * 0.9);
776 bool GraphVisualizerWidget::addNewEdge(
const std::string& fromId,
const std::string& toId)
778 std::string errorMsg;
780 if (!graphSeg->hasEntityById(fromId))
782 errorMsg =
"start node with Id '" + fromId +
"' not found in segment";
784 else if (!graphSeg->hasEntityById(toId))
786 errorMsg =
"end node with Id '" + toId +
"' not found in segment";
789 else if (fromId == toId)
791 errorMsg =
"starting and ending node are the same";
795 auto fromNode = graphSeg->getNodeById(fromId);
796 for (
const auto& adjacent : fromNode->getAdjacentNodes())
798 if (toId == adjacent->getId())
800 errorMsg =
"edge '" + fromNode->getName() +
"' -> '" + adjacent->getName() +
"' already exists";
806 if (errorMsg.empty())
808 ui.labelAddEdgeStatus->setText(QString::fromStdString(
"Ok"));
809 graphSeg->addEdge(fromId, toId);
810 gnpr->forceRefetch(fromId);
811 gnpr->forceRefetch(toId);
815 ui.labelAddEdgeStatus->setStyleSheet(
"QLabel { background-color : lime; }");
820 ui.labelAddEdgeStatus->setText(QString::fromStdString(errorMsg));
821 ui.labelAddEdgeStatus->setStyleSheet(
"QLabel { background-color : orange; }");
824 return errorMsg.empty();
827 void GraphVisualizerWidget::addNewEdgeBoth()
829 std::string startId =
ui.editStartNodeId->text().toStdString();
830 std::string endId =
ui.editEndNodeId->text().toStdString();
831 addNewEdge(startId, endId);
832 addNewEdge(endId, startId);
835 void GraphVisualizerWidget::addNewEdgeStartEnd()
837 std::string startId =
ui.editStartNodeId->text().toStdString();
838 std::string endId =
ui.editEndNodeId->text().toStdString();
839 addNewEdge(startId, endId);
842 void GraphVisualizerWidget::addNewEdgeEndStart()
844 std::string startId =
ui.editEndNodeId->text().toStdString();
845 std::string endId =
ui.editStartNodeId->text().toStdString();
846 addNewEdge(startId, endId);
849 void GraphVisualizerWidget::selectedSceneChanged(
int i)
851 const auto current =
ui.scenesComboBox->currentText();
852 if (!current.isEmpty())
854 lastSelectedSceneName = current;
858 void GraphVisualizerWidget::updateSceneList()
860 auto scenes = graphSeg->getScenes();
861 ui.scenesComboBox->clear();
864 for (std::size_t i = 0; i < scenes.size(); i++)
866 const auto currentScene = QString::fromStdString(scenes[i]);
867 ui.scenesComboBox->addItem(currentScene);
869 if (currentScene == lastSelectedSceneName)
875 ui.scenesComboBox->setCurrentIndex(idx);
878 void GraphVisualizerWidget::drawScene()
880 std::vector<std::string> highlightedNodes;
881 for (
const auto& nodeData : nodes)
883 bool sameScene =
ui.scenesComboBox->currentText().toStdString() == nodeData.second.node->getScene();
884 if (nodeData.second.highlighted && sameScene)
886 highlightedNodes.push_back(nodeData.first);
891 auto graphNodes = graphSeg->getNodesByScene(
ui.scenesComboBox->currentText().toStdString());
894 for (
auto& node : graphNodes)
896 auto pos = armarx::FramedPosePtr::dynamicCast(node->getPose());
898 if (!pos || node->isMetaEntity())
907 for (
auto& node : graphNodes)
909 auto nodeId = node->getId();
911 for (
int i = 0; i < node->getOutdegree(); i++)
913 auto adjacent = memoryx::GraphNodeBasePtr::dynamicCast(node->getAdjacentNode(i)->getEntity());
915 auto adjacentId = adjacent->getId();
921 for (
const auto& nodeId : highlightedNodes)
923 auto nodeIt = std::find_if(nodes.begin(), nodes.end(), [&](
const std::pair<std::string, NodeData>& d)
925 return d.first == nodeId;
928 if (nodeIt != nodes.end())
930 nodeIt->second.highlighted =
true;
931 updateNode(nodeIt->first);
938 void GraphVisualizerWidget::selectScene()
945 void GraphVisualizerWidget::loadScene(
const std::string& xmlFile)
950 std::ifstream in(xmlFile.c_str());
958 std::stringstream buffer;
959 buffer << in.rdbuf();
960 std::string sceneXML(buffer.str());
961 std::filesystem::path filenameBaseComplete(xmlFile);
962 std::filesystem::path filenameBasePath = filenameBaseComplete.parent_path();
963 std::string basePath = filenameBasePath.string();
974 void GraphVisualizerWidget::addKitchenGraph()
976 std::string scene {
"GraphKitchen"};
977 graphSeg->clearScene(scene);
980 auto addNode = [&](
const std::string & name,
float x,
float y,
float angle)
983 ARMARX_INFO_S <<
"added node '" << name <<
"' at (" << x <<
", " << y <<
", " <<
angle <<
"rad)";
986 auto addEdges = [&](
const std::string & nodeFromName,
const std::string & nodeToName,
bool bidirectional)
988 auto nodeFrom = graphSeg->getNodeFromSceneByName(scene, nodeFromName);
989 auto nodeTo = graphSeg->getNodeFromSceneByName(scene, nodeToName);
992 ARMARX_INFO_S <<
"'" << nodeFrom->getName() <<
"' -> '" << nodeTo->getName() <<
"', status: " << graphSeg->addEdge(nodeFrom->getId(), nodeTo->getId());
995 ARMARX_INFO_S <<
"'" << nodeTo->getName() <<
"' -> '" << nodeFrom->getName() <<
"', status: " << graphSeg->addEdge(nodeTo->getId(), nodeFrom->getId());
1000 addNode(
"initialnode", 2900, 7000, 0);
1001 addNode(
"sideboard", 3400, 7000, 0);
1002 addEdges(
"initialnode",
"sideboard",
true);
1005 void GraphVisualizerWidget::addNewGraphNode()
1008 Eigen::Vector3f rpy;
1009 Eigen::Vector3f pos;
1010 rpy << VirtualRobot::MathTools::deg2rad(
ui.spinBoxRoll->value()),
1011 VirtualRobot::MathTools::deg2rad(
ui.spinBoxPitch->value()),
1012 VirtualRobot::MathTools::deg2rad(
ui.spinBoxYaw->value());
1013 pos <<
ui.spinBoxX->value(),
1014 ui.spinBoxY->value(),
1015 ui.spinBoxZ->value();
1016 VirtualRobot::MathTools::posrpy2eigen4f(pos, rpy, mat);
1018 ui.editFrameName->text().toStdString(),
1019 ui.editAgentName->text().toStdString());
1021 ui.editNodeName->text().toStdString(),
1022 ui.editSceneName->text().toStdString());
1023 auto entityId = graphSeg->addNode(node);
1024 gnpr->forceRefetch(entityId);
1025 node->setId(entityId);
1026 if (
ui.scenesComboBox->currentText().toStdString() ==
ui.editSceneName->text().toStdString())
1028 ui.editNodeId->setText(QString::fromStdString(entityId));
1033 void GraphVisualizerWidget::editGraphNode()
1036 Eigen::Vector3f rpy;
1037 Eigen::Vector3f pos;
1038 rpy << VirtualRobot::MathTools::deg2rad(
ui.spinBoxRoll->value()),
1039 VirtualRobot::MathTools::deg2rad(
ui.spinBoxPitch->value()),
1040 VirtualRobot::MathTools::deg2rad(
ui.spinBoxYaw->value());
1041 pos <<
ui.spinBoxX->value(),
1042 ui.spinBoxY->value(),
1043 ui.spinBoxZ->value();
1044 VirtualRobot::MathTools::posrpy2eigen4f(pos, rpy, mat);
1046 ui.editFrameName->text().toStdString(),
1047 ui.editAgentName->text().toStdString());
1049 ui.editNodeName->text().toStdString(),
1050 ui.editSceneName->text().toStdString());
1051 auto id =
ui.editNodeId->text().toStdString();
1054 graphSeg->updateEntity(
id, node);
1055 gnpr->forceRefetch(
id);
1056 if (
ui.scenesComboBox->currentText().toStdString() ==
ui.editSceneName->text().toStdString())
1064 int row =
ui.tableWidgetNodes->rowAt(pos.y());
1065 auto nodeIt = std::find_if(nodes.begin(), nodes.end(), [&](
const std::pair<std::string, NodeData>& d)
1067 return d.second.tableWidgetNodesIndex == row;
1070 QAction* deleteAction = menu.addAction(
"Delete Node");
1072 if (menu.exec(QCursor::pos()) == deleteAction)
1075 graphSeg->removeNode(nodeIt->second.node->getId());
1082 int row =
ui.tableWidgetEdges->rowAt(pos.y());
1083 auto edgeIt = std::find_if(edges.begin(), edges.end(), [&](
const std::pair<EdgeId, EdgeData>& d)
1085 return d.second.tableWidgetEdgesIndex == row;
1088 QAction* deleteAction = menu.addAction(
"Delete Edge");
1090 if (menu.exec(QCursor::pos()) == deleteAction)
1093 graphSeg->removeEdge(edgeIt->first.first, edgeIt->first.second);
1100 if (obj ==
gvw->
ui.graphicsViewGraph && event->type() == QEvent::MouseButtonPress)
1102 QMouseEvent* me =
static_cast<QMouseEvent*
>(event);
1103 if (me->button() == Qt::LeftButton)
1105 QPointF scenePoint =
gvw->
ui.graphicsViewGraph->mapToScene(me->pos());
1106 scenePoint.setY(-scenePoint.y());
1109 auto bestIt =
gvw->nodes.cend();
1111 for (
auto it =
gvw->nodes.cbegin(); it !=
gvw->nodes.cend(); ++it)
1113 float deltaX = it->second.pose->position->x - scenePoint.x();
1114 float deltaY = it->second.pose->position->y - scenePoint.y();
1115 float dist =
std::sqrt(deltaX * deltaX + deltaY * deltaY);
1124 if (bestIt !=
gvw->nodes.cend())
1126 gvw->nodeDoubleClicked(bestIt->first);
1130 else if (event->type() == QEvent::Resize)
1134 return QObject::eventFilter(obj, event);