SemanticRelationViewerWidgetController.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * \package VisionX::gui-plugins::SemanticRelationViewerWidgetController
17  * \author Fabian Paus ( fabian dot paus at kit dot edu )
18  * \date 2019
19  * \copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
24 
25 #include <cfloat>
26 
27 #include <VirtualRobot/VirtualRobot.h>
28 
30 
33 
34 #include <SemanticObjectRelations/SupportAnalysis/SupportGraph.h>
35 
36 namespace armarx
37 {
38  namespace
39  {
40 
41  GraphvizLayoutedGraph
42  layoutGraph(semrel::AttributedGraph const& graph)
43  {
44  GraphvizLayout layout;
45  for (auto vertex : graph.vertices())
46  {
47  auto desc = vertex.descriptor();
48  auto& attrs = vertex.attrib().json;
49  std::string name = std::to_string(desc);
50 
51  if (auto style = attrs.find("style"); style != attrs.end())
52  {
53  auto label = style->find("label");
54  if (label != style->end() && label->is_string())
55  {
56  name = label->get<std::string>();
57  }
58  }
59  else if (auto object = attrs.find("object"); object != attrs.end())
60  {
61  auto nameValue = object->find("name");
62  if (nameValue != object->end() && nameValue->is_string())
63  {
64  name = nameValue->get<std::string>() +
65  std::to_string(object->at("id").get<int>());
66  }
67  nameValue = object->find("instance");
68  if (nameValue != object->end() && nameValue->is_string())
69  {
70  name = nameValue->get<std::string>();
71  }
72  }
73  layout.addNode(desc, name);
74  }
75  for (auto edge : graph.edges())
76  {
77  auto& attrs = edge.attrib().json;
78  std::string name;
79  if (auto style = attrs.find("style"); style != attrs.end())
80  {
81  auto label = style->find("label");
82  if (label != style->end() && label->is_string())
83  {
84  name = label->get<std::string>();
85  }
86  }
87  layout.addEdge(edge.sourceDescriptor(), edge.targetDescriptor(), name);
88  }
89  return layout.finish();
90  }
91 
92  } // namespace
93 
95  {
96  setlocale(LC_ALL, "en_US.UTF-8");
97 
98  widget.setupUi(getWidget());
99  timer = new QTimer(this);
100  widget.graphView->setScene(&graphicsScene);
101  widget.graphView->setRenderHints(QPainter::Antialiasing |
102  QPainter::HighQualityAntialiasing);
103  int propWidth = 250;
104  int graphWidth = 750;
105  widget.splitter->setSizes({graphWidth, propWidth});
106 
107  connect(timer, SIGNAL(timeout()), this, SLOT(onUpdateGraphs()));
108  connect(widget.updatePushButton, SIGNAL(clicked()), this, SLOT(onUpdateGraphs()));
109  connect(widget.autoUpdateCheckBox,
110  SIGNAL(stateChanged(int)),
111  this,
112  SLOT(onAutoUpdateChanged()));
113  connect(widget.idComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onUpdateGraphs()));
114 
115  connect(widget.zoomSpinBox,
116  QOverload<double>::of(&QDoubleSpinBox::valueChanged),
117  this,
118  &SemanticRelationViewerWidgetController::onZoomChanged);
119  }
120 
122  {
123  }
124 
125  void
127  {
128  }
129 
130  void
132  {
133  }
134 
135  static const std::string STORAGE_NAME_KEY = "SemanticGraphStorage";
136 
137  QPointer<QDialog>
139  {
140  if (!configDialog)
141  {
142  configDialog = new SimpleConfigDialog(parent);
143  configDialog->addProxyFinder<armarx::semantic::GraphStorageInterfacePrx>(
144  {STORAGE_NAME_KEY, "SemanticGraphStorage", "SemanticGraphStorage"});
145  }
146  return qobject_cast<SimpleConfigDialog*>(configDialog);
147  }
148 
149  void
151  {
152  }
153 
154  template <typename T>
155  void
156  setProxy(ManagedIceObject* object, T& proxy, std::string const& name)
157  {
158  object->usingProxy(name);
159  proxy = object->getProxy<T>(name);
160  }
161 
162  void
164  {
165  std::string storageName = configDialog->getProxyName(STORAGE_NAME_KEY);
166  setProxy(this, storage, storageName);
167  }
168 
169  void
171  {
172  timer->stop();
173  }
174 
175  void
177  {
178  graphMap.clear();
179  semantic::data::GraphMap allGraphs = storage->getAll();
180  for (auto& pair : allGraphs)
181  {
182  std::string const& id = pair.first;
183  graphMap[id] = semantic::fromIce(pair.second);
184  }
185 
186  std::string selectedID = widget.idComboBox->currentText().toStdString();
187 
188  widget.idComboBox->blockSignals(true);
189  widget.idComboBox->clear();
190  widget.idComboBox->blockSignals(false);
191 
192  if (allGraphs.empty())
193  {
194  return;
195  }
196 
197  widget.idComboBox->blockSignals(true);
198  for (auto& pair : allGraphs)
199  {
200  std::string const& id = pair.first;
201  widget.idComboBox->addItem(QString::fromStdString(id));
202  }
203 
204  int selectedIndex = widget.idComboBox->findText(QString::fromStdString(selectedID));
205  if (selectedIndex < 0)
206  {
207  selectedIndex = 0;
208  }
209  widget.idComboBox->setCurrentIndex(selectedIndex);
210  widget.idComboBox->blockSignals(false);
211 
212  selectedID = widget.idComboBox->currentText().toStdString();
213 
214  if (graphMap.count(selectedID))
215  {
216  semrel::AttributedGraph const& graph = graphMap[selectedID];
217 
218  GraphvizLayoutedGraph layoutedGraph = layoutGraph(graph);
219  drawGraph(&graphicsScene, layoutedGraph, graph);
220  widget.graphView->viewport()->update();
221 
222  setPropertyView(nlohmann::json::object());
223  }
224  else
225  {
226  std::vector<std::string> ids;
227  for (auto& entry : graphMap)
228  {
229  ids.push_back(entry.first);
230  }
231  ARMARX_WARNING << "Could not find graph with ID: " << selectedID
232  << "\nExisting IDs: " << ids;
233  }
234  }
235 
236  void
238  {
239  if (widget.autoUpdateCheckBox->checkState() == Qt::Checked)
240  {
241  timer->start(20);
242  }
243  else
244  {
245  timer->stop();
246  }
247  }
248 
249  void
251  {
252  std::string id = widget.idComboBox->currentText().toStdString();
253  if (graphMap.count(id) == 0)
254  {
255  ARMARX_WARNING << "No graph with ID: " << id;
256  return;
257  }
258  auto& graph = graphMap[id];
259  auto vertex = graph.vertex(selected->descriptor);
260  ARMARX_VERBOSE << "Vertex[" << selected->descriptor
261  << "]: " << vertex.attrib().json.dump(4);
262 
263  setPropertyView(vertex.attrib().json);
264  highlightSelected(selected);
265  }
266 
267  void
269  {
270  std::string id = widget.idComboBox->currentText().toStdString();
271  if (graphMap.count(id) == 0)
272  {
273  return;
274  }
275  auto& graph = graphMap[id];
276 
277  auto edge = graph.edge(graph.vertex(selected->sourceDescriptor),
278  graph.vertex(selected->targetDescriptor));
279  ARMARX_VERBOSE << "Edge: " << edge.attrib().json.dump(4);
280 
281  edge.attrib().json.is_null();
282  setPropertyView(edge.attrib().json);
283  highlightSelected(selected);
284  }
285 
286  void
288  {
289  std::string id = widget.idComboBox->currentText().toStdString();
290  if (graphMap.count(id) == 0)
291  {
292  ARMARX_WARNING << "No graph with ID: " << id;
293  return;
294  }
295 
296  auto& graph = graphMap[id];
297  setPropertyView(graph.attrib().json);
298  highlightSelected(selected);
299  }
300 
301  void
302  SemanticRelationViewerWidgetController::drawGraph(QGraphicsScene* graphicsScene,
303  GraphvizLayoutedGraph const& layoutedGraph,
304  semrel::AttributedGraph const& graph)
305  {
306  graphicsScene->clear();
307 
308  float minX = FLT_MAX;
309  float minY = FLT_MAX;
310 
311  for (auto& pair : layoutedGraph.nodes)
312  {
313  int id = pair.first;
314  GraphvizLayoutedNode const& layoutedNode = pair.second;
315 
317  ellipse->setRect(
318  layoutedNode.posX, layoutedNode.posY, layoutedNode.width, layoutedNode.height);
319  ellipse->text = QString::fromStdString(layoutedNode.label);
320  ellipse->descriptor = id;
321 
322  minX = std::min(layoutedNode.posX, minX);
323  minY = std::min(layoutedNode.posY, minY);
324 
325  // Get optional style information
326  auto vertex = graph.vertex(semrel::ShapeID{id});
327  auto& json = vertex.attrib().json;
328  if (json.count("style"))
329  {
330  auto& style = json["style"];
331  auto setColor = [&](std::string const& colorName, QColor* output)
332  {
333  if (style.count(colorName))
334  {
335  Eigen::Vector4i scolor = style[colorName];
336  QColor qcolor(scolor(0), scolor(1), scolor(2), scolor(3));
337  *output = qcolor;
338  }
339  };
340  setColor("fill-color", &ellipse->fillColor);
341  setColor("border-color", &ellipse->borderColor);
342  setColor("font-color", &ellipse->fontColor);
343  }
344 
345  bool connected =
346  QObject::connect(ellipse,
348  this,
350  if (!connected)
351  {
352  ARMARX_WARNING << "Failed to connect Qt slots";
353  }
354 
355  graphicsScene->addItem(ellipse);
356  }
357 
358 
359  for (auto& pair : layoutedGraph.edges)
360  {
361  int sourceID = pair.first.first;
362  int targetID = pair.first.second;
363  GraphvizLayoutedEdge const& layoutedEdge = pair.second;
364 
365  QPainterPath path;
366  if (layoutedEdge.startPoint)
367  {
368  path.lineTo(*layoutedEdge.startPoint);
369  }
370  path.addPath(SplinePath::simplePath(layoutedEdge.controlPoints));
371  if (layoutedEdge.endPoint)
372  {
373  path.lineTo(*layoutedEdge.endPoint);
374  }
375 
376  for (int i = 0; i <= 10; ++i)
377  {
378  double t = 0.1 * i;
379  QPointF point = path.pointAtPercent(t);
380 
381  minX = std::min(float(point.x()), minX);
382  minY = std::min(float(point.y()), minY);
383  }
384 
385  SemanticGraphEdgeItem* item = new SemanticGraphEdgeItem();
386  item->sourceDescriptor = sourceID;
387  item->targetDescriptor = targetID;
388  item->setPath(path);
389 
390  // Get optional style information
391  auto sourceVertex = graph.vertex(item->sourceDescriptor);
392  auto targetVertex = graph.vertex(item->targetDescriptor);
393  auto edge = graph.edge(sourceVertex, targetVertex);
394  auto& json = edge.attrib().json;
395  if (json.count("style"))
396  {
397  auto& style = json["style"];
398  if (style.count("color"))
399  {
400  Eigen::Vector4i scolor = style["color"];
401  QColor qcolor(scolor(0), scolor(1), scolor(2), scolor(3));
402  item->color = qcolor;
403  }
404  }
405  if (layoutedEdge.label.size() > 0)
406  {
407  item->label = QString::fromStdString(layoutedEdge.label);
408  item->labelPosition.setX(double(layoutedEdge.labelPosX));
409  item->labelPosition.setY(double(layoutedEdge.labelPosY));
410  }
411 
412  bool connected =
413  QObject::connect(item,
415  this,
417  if (!connected)
418  {
419  ARMARX_WARNING << "Failed to connect Qt slots";
420  }
421 
422  graphicsScene->addItem(item);
423  }
424 
425  SemanticGraphGlobalItem* global = new SemanticGraphGlobalItem();
426  global->setRect(minX - 60.0f, minY - 40.0f, 100.0f, 30.0f);
427  bool connected =
428  QObject::connect(global,
430  this,
432  if (!connected)
433  {
434  ARMARX_WARNING << "Failed to connect Qt slots";
435  }
436  graphicsScene->addItem(global);
437  }
438 
439  void
440  SemanticRelationViewerWidgetController::setPropertyView(nlohmann::json const& attrs)
441  {
442  propertyModel.setRoot(attrs);
443 
444  widget.propertiesView->setModel(&propertyModel);
445  widget.propertiesView->expandAll();
446  widget.propertiesView->resizeColumnToContents(0);
447  }
448 
449  void
450  SemanticRelationViewerWidgetController::highlightSelected(QGraphicsItem* selected)
451  {
452  for (QGraphicsItem* item : graphicsScene.items())
453  {
454  if (auto* edge = dynamic_cast<SemanticGraphEdgeItem*>(item))
455  {
456  edge->selected = (edge == selected);
457  }
458  else if (auto* vertex = dynamic_cast<SemanticGraphVertexItem*>(item))
459  {
460  vertex->selected = (vertex == selected);
461  }
462  else if (auto* global = dynamic_cast<SemanticGraphGlobalItem*>(item))
463  {
464  global->selected = (global == selected);
465  }
466  }
467  graphicsScene.update();
468  }
469 
470  void
471  SemanticRelationViewerWidgetController::onZoomChanged(double newZoom)
472  {
473  double inverseScale = 1.0 / graphicsSceneScale;
474  double zoom = inverseScale * newZoom;
475  widget.graphView->scale(zoom, zoom);
476  graphicsSceneScale = newZoom;
477  }
478 } // namespace armarx
armarx::SemanticRelationViewerWidgetController::~SemanticRelationViewerWidgetController
virtual ~SemanticRelationViewerWidgetController()
Controller destructor.
Definition: SemanticRelationViewerWidgetController.cpp:121
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::SemanticRelationViewerWidgetController::onAutoUpdateChanged
void onAutoUpdateChanged()
Definition: SemanticRelationViewerWidgetController.cpp:237
GraphvizLayout.h
armarx::GraphvizLayoutedNode::height
float height
Definition: GraphvizLayout.h:19
armarx::SemanticGraphVertexItem::text
QString text
Definition: SemanticGraphVertexItem.h:19
armarx::SemanticGraphGlobalItem
Definition: SemanticGraphGlobalItem.h:9
armarx::SemanticRelationViewerWidgetController::onDisconnectComponent
void onDisconnectComponent() override
Hook for subclass.
Definition: SemanticRelationViewerWidgetController.cpp:170
armarx::SemanticGraphEdgeItem
Definition: SemanticGraphEdgeItem.h:11
armarx::SemanticGraphVertexItem::fontColor
QColor fontColor
Definition: SemanticGraphVertexItem.h:27
armarx::GraphvizLayoutedGraph::nodes
std::map< int, GraphvizLayoutedNode > nodes
Definition: GraphvizLayout.h:36
armarx::SemanticRelationViewerWidgetController::getConfigDialog
QPointer< QDialog > getConfigDialog(QWidget *parent) override
getConfigDialog returns a pointer to the a configuration widget of this controller.
Definition: SemanticRelationViewerWidgetController.cpp:138
armarx::SemanticGraphVertexItem::borderColor
QColor borderColor
Definition: SemanticGraphVertexItem.h:26
armarx::SemanticGraphGlobalItem::onLeftClick
void onLeftClick(SemanticGraphGlobalItem *)
armarx::SemanticRelationViewerWidgetController::onUpdateGraphs
void onUpdateGraphs()
Definition: SemanticRelationViewerWidgetController.cpp:176
armarx::SplinePath::simplePath
static QPainterPath simplePath(QPointList simpleControlPoints)
simplePath Constructs a cubic Beziercurve with an arbitrary number of control points.
Definition: SplinePath.cpp:36
armarx::SemanticGraphEdgeItem::targetDescriptor
int targetDescriptor
Definition: SemanticGraphEdgeItem.h:24
armarx::SemanticGraphVertexItem
Definition: SemanticGraphVertexItem.h:9
armarx::SemanticRelationViewerWidgetController::onLeftClickEdge
void onLeftClickEdge(SemanticGraphEdgeItem *item)
Definition: SemanticRelationViewerWidgetController.cpp:268
armarx::SemanticRelationViewerWidgetController::loadSettings
void loadSettings(QSettings *settings) override
Definition: SemanticRelationViewerWidgetController.cpp:126
armarx::SemanticGraphVertexItem::onLeftClick
void onLeftClick(SemanticGraphVertexItem *)
armarx::SemanticGraphEdgeItem::onLeftClick
void onLeftClick(SemanticGraphEdgeItem *selected)
armarx::SemanticRelationViewerWidgetController::onConnectComponent
void onConnectComponent() override
Definition: SemanticRelationViewerWidgetController.cpp:163
armarx::SemanticRelationViewerWidgetController::saveSettings
void saveSettings(QSettings *settings) override
Definition: SemanticRelationViewerWidgetController.cpp:131
armarx::GraphvizLayoutedNode::posX
float posX
Definition: GraphvizLayout.h:16
armarx::to_string
const std::string & to_string(const std::string &s)
Definition: StringHelpers.h:41
armarx::SemanticGraphVertexItem::fillColor
QColor fillColor
Definition: SemanticGraphVertexItem.h:25
armarx::SemanticRelationViewerWidgetController::SemanticRelationViewerWidgetController
SemanticRelationViewerWidgetController()
Controller Constructor.
Definition: SemanticRelationViewerWidgetController.cpp:94
armarx::SemanticRelationViewerWidgetController::onInitComponent
void onInitComponent() override
Definition: SemanticRelationViewerWidgetController.cpp:150
armarx::SemanticRelationViewerWidgetController::onLeftClickVertex
void onLeftClickVertex(SemanticGraphVertexItem *item)
Definition: SemanticRelationViewerWidgetController.cpp:250
armarx::ManagedIceObject
The ManagedIceObject is the base class for all ArmarX objects.
Definition: ManagedIceObject.h:162
armarx::GraphvizLayoutedNode::posY
float posY
Definition: GraphvizLayout.h:17
SplinePath.h
armarx::setProxy
void setProxy(ManagedIceObject *object, T &proxy, std::string const &name)
Definition: SemanticRelationViewerWidgetController.cpp:156
armarx::SemanticGraphEdgeItem::sourceDescriptor
int sourceDescriptor
Definition: SemanticGraphEdgeItem.h:23
armarx::SemanticGraphVertexItem::descriptor
int descriptor
Definition: SemanticGraphVertexItem.h:23
armarx::ArmarXWidgetController::getWidget
virtual QPointer< QWidget > getWidget()
getWidget returns a pointer to the a widget of this controller.
Definition: ArmarXWidgetController.cpp:54
ice_serialization.h
T
float T
Definition: UnscentedKalmanFilterTest.cpp:38
min
T min(T t1, T t2)
Definition: gdiam.h:44
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
SemanticRelationViewerWidgetController.h
armarx::semantic::fromIce
semrel::AttributedGraph fromIce(const semantic::data::Graph &graph)
Definition: graph.h:31
armarx::GraphvizLayoutedGraph
Definition: GraphvizLayout.h:34
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
armarx::GraphvizLayoutedNode::width
float width
Definition: GraphvizLayout.h:18
armarx::GraphvizLayoutedGraph::edges
std::map< std::pair< int, int >, GraphvizLayoutedEdge > edges
Definition: GraphvizLayout.h:37
armarx::GraphvizLayoutedNode
Definition: GraphvizLayout.h:14
armarx::SemanticRelationViewerWidgetController::onLeftClickGlobal
void onLeftClickGlobal(SemanticGraphGlobalItem *item)
Definition: SemanticRelationViewerWidgetController.cpp:287
armarx::GraphvizLayoutedNode::label
std::string label
Definition: GraphvizLayout.h:20
armarx::JSONTreeModel::setRoot
void setRoot(nlohmann::json const &root)
Definition: JSONTreeModel.cpp:9
armarx::SimpleConfigDialog
A config-dialog containing one (or multiple) proxy finders.
Definition: SimpleConfigDialog.h:84