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