diff --git a/source/armarx/navigation/graph/Graph.cpp b/source/armarx/navigation/graph/Graph.cpp index bce79ae3d6c1222928d2b87ea764f0c24a6527e1..f8086dce0b3252e37585f034c6b44642d315f02f 100644 --- a/source/armarx/navigation/graph/Graph.cpp +++ b/source/armarx/navigation/graph/Graph.cpp @@ -36,6 +36,11 @@ namespace armarx::nav::graph return aron.globalRobotPose; } + void VertexAttribs::setPose(const Eigen::Matrix4f& pose) + { + this->aron.globalRobotPose = pose; + } + } diff --git a/source/armarx/navigation/graph/Graph.h b/source/armarx/navigation/graph/Graph.h index dd5704bcbdb82f65fa28189e249635662f0f3ea1..d895dd635e690c0c4a737b11fca9a7523faeb535 100644 --- a/source/armarx/navigation/graph/Graph.h +++ b/source/armarx/navigation/graph/Graph.h @@ -35,7 +35,9 @@ namespace armarx::nav::graph armarx::nav::graph::arondto::Vertex aron; std::string getName() const; + Eigen::Matrix4f getPose() const; + void setPose(const Eigen::Matrix4f& pose); }; struct EdgeAttribs { diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/CMakeLists.txt b/source/armarx/navigation/gui-plugins/LocationGraphEditor/CMakeLists.txt index 8235d2811d307784175818c8bb183a142e90828e..d2661dbac93f5ecba03215cc9dfad01921beffa3 100644 --- a/source/armarx/navigation/gui-plugins/LocationGraphEditor/CMakeLists.txt +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/CMakeLists.txt @@ -14,25 +14,32 @@ set(SOURCES LocationGraphEditorWidgetController.cpp FunctionalEventFilter.cpp - GraphScene.cpp GuiGraph.cpp widgets/default_colors.cpp widgets/EdgeTableWidget.cpp widgets/VertexDataWidget.cpp widgets/VertexTableWidget.cpp + + widgets/graph_scene/ControlWidget.cpp + widgets/graph_scene/Scene.cpp + widgets/graph_scene/Widget.cpp ) set(HEADERS LocationGraphEditorWidgetController.h FunctionalEventFilter.h - GraphScene.h GuiGraph.h widgets/default_colors.h widgets/EdgeTableWidget.h widgets/VertexDataWidget.h widgets/VertexTableWidget.h + + widgets/graph_scene.h + widgets/graph_scene/ControlWidget.h + widgets/graph_scene/Scene.h + widgets/graph_scene/Widget.h ) set(GUI_UIS LocationGraphEditorWidget.ui diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.cpp b/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.cpp index 377f726e295e0918776d19eb7154ed72f06b2ff1..f4fd3e1d100fe63545cb55c7fd80ae870fb52a2d 100644 --- a/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.cpp +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.cpp @@ -29,24 +29,54 @@ namespace armarx::nav::locgrapheditor { + std::optional<GuiGraph::Vertex> + GuiGraph::getVertexFromTableItem(QTableWidgetItem* item) + { + for (auto vertex : vertices()) + { + if (vertex.attrib().tableWidgetItem == item) + { + return vertex; + } + } + return std::nullopt; + } + + + std::map<QTableWidgetItem*, GuiGraph::Vertex> + GuiGraph::getTableItemToVertexMap() + { + std::map<QTableWidgetItem*, GuiGraph::Vertex> map; + + for (auto vertex : vertices()) + { + if (vertex.attrib().tableWidgetItem != nullptr) + { + map[vertex.attrib().tableWidgetItem] = vertex; + } + } + + return map; + } + } namespace armarx::nav { - float locgrapheditor::getYawAngleDegree(const Eigen::Matrix4f& pose) - { - Eigen::Vector3f rpy = simox::math::mat4f_to_rpy(pose); - return simox::math::rad_to_deg(rpy[2]); - } +float locgrapheditor::getYawAngleDegree(const Eigen::Matrix4f& pose) +{ + Eigen::Vector3f rpy = simox::math::mat4f_to_rpy(pose); + return simox::math::rad_to_deg(rpy[2]); +} - auto locgrapheditor::toGuiGraph(const graph::Graph& nav) -> GuiGraph +auto locgrapheditor::toGuiGraph(const graph::Graph& nav) -> GuiGraph +{ + GuiGraph gui; + for (auto v : nav.vertices()) { - GuiGraph gui; - for (auto v : nav.vertices()) - { - gui.addVertex(v.objectID(), { v.attrib() }); - } + gui.addVertex(v.objectID(), { v.attrib() }); + } for (auto e : nav.edges()) { gui.addEdge(e.sourceObjectID(), e.targetObjectID(), { e.attrib() }); diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.h b/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.h index f0b6e0bba09fcc68240f42eb24f9798220092950..87395a1fb13350128ea78fd1d5cffa6ed2f761e7 100644 --- a/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.h +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.h @@ -25,6 +25,9 @@ #include <SemanticObjectRelations/RelationGraph/RelationGraph.h> +#include <map> +#include <optional> + class QGraphicsEllipseItem; class QGraphicsLineItem; @@ -73,7 +76,18 @@ namespace armarx::nav::locgrapheditor }; - using GuiGraph = semrel::RelationGraph<VertexData, EdgeData, GraphData>; + class GuiGraph : public semrel::RelationGraph<VertexData, EdgeData, GraphData> + { + public: + + using RelationGraph::RelationGraph; + + + std::optional<Vertex> getVertexFromTableItem(QTableWidgetItem* item); + + std::map<QTableWidgetItem*, Vertex> getTableItemToVertexMap(); + + }; GuiGraph toGuiGraph(const graph::Graph& graph); diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidget.ui b/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidget.ui index 6a33a0128448d77ed4e8c65e410055cb448c93ad..a25894c76c31254fb42c7dc9611d2fa5d404d4f3 100644 --- a/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidget.ui +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidget.ui @@ -79,95 +79,7 @@ <number>0</number> </property> <item> - <widget class="QWidget" name="graphHead" native="true"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QLabel" name="label_graph"> - <property name="text"> - <string>Graph</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="buttonRedraw"> - <property name="text"> - <string>Repaint</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="buttonClear"> - <property name="text"> - <string>Clear Graph</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QToolButton" name="buttonRotateClock"> - <property name="text"> - <string>↻</string> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="buttonRotateCounterClock"> - <property name="text"> - <string>↺</string> - </property> - </widget> - </item> - <item> - <widget class="Line" name="line_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_zoom"> - <property name="text"> - <string>Zoom</string> - </property> - </widget> - </item> - <item> - <widget class="QDoubleSpinBox" name="viewZoomFactor"> - <property name="decimals"> - <number>5</number> - </property> - <property name="singleStep"> - <double>0.001000000000000</double> - </property> - <property name="value"> - <double>0.100000000000000</double> - </property> - </widget> - </item> - <item> - <widget class="QToolButton" name="buttonAutoAdjust"> - <property name="text"> - <string>Auto</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGraphicsView" name="graphicsViewGraph"/> + <layout class="QVBoxLayout" name="graphSceneLayout"/> </item> </layout> </widget> @@ -193,11 +105,11 @@ <widget class="QWidget" name="verticalLayout_12Widget"> <layout class="QVBoxLayout" name="verticalLayout_12"> <item> - <widget class="QGroupBox" name="locationsTableGroupBox"> + <widget class="QGroupBox" name="locationDataGroupBox"> <property name="title"> - <string>Locations (Graph Vertices)</string> + <string>Location Data</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_7"> + <layout class="QVBoxLayout" name="verticalLayout_3"> <property name="leftMargin"> <number>3</number> </property> @@ -218,11 +130,11 @@ <widget class="QWidget" name="verticalLayout_13Widget"> <layout class="QVBoxLayout" name="verticalLayout_13"> <item> - <widget class="QGroupBox" name="edgesTableGroupBox"> + <widget class="QGroupBox" name="locationsTableGroupBox"> <property name="title"> - <string>Graph Edges</string> + <string>Locations (Graph Vertices)</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_8"> + <layout class="QVBoxLayout" name="verticalLayout_7"> <property name="leftMargin"> <number>3</number> </property> @@ -243,11 +155,24 @@ <widget class="QWidget" name="verticalLayout_6Widget"> <layout class="QVBoxLayout" name="verticalLayout_6"> <item> - <widget class="QGroupBox" name="locationDataGroupBox"> + <widget class="QGroupBox" name="edgesTableGroupBox"> <property name="title"> - <string>Location Data</string> + <string>Graph Edges</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_3"/> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <property name="leftMargin"> + <number>3</number> + </property> + <property name="topMargin"> + <number>3</number> + </property> + <property name="rightMargin"> + <number>3</number> + </property> + <property name="bottomMargin"> + <number>3</number> + </property> + </layout> </widget> </item> </layout> diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.cpp b/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.cpp index 9510d82c920b9e8500e91322dbfe2aede3416466..e23d674833f93d45484578ff73f493f7a6012746 100644 --- a/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.cpp +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.cpp @@ -24,6 +24,8 @@ #include "widgets/EdgeTableWidget.h" #include "widgets/VertexDataWidget.h" #include "widgets/VertexTableWidget.h" +#include "widgets/graph_scene/Scene.h" +#include "widgets/graph_scene/Widget.h" #include <Navigation/gui-plugins/LocationGraphEditor/ui_LocationGraphEditorWidget.h> @@ -110,20 +112,22 @@ namespace armarx::nav::locgrapheditor loadAutomaticSettings(); - dataWidgets.edgeTable = new EdgeTableWidget(); - dataWidgets.vertexTable = new VertexTableWidget(); - dataWidgets.vertexData = new VertexDataWidget(); - widget.edgesTableGroupBox->layout()->addWidget(dataWidgets.edgeTable); - widget.locationsTableGroupBox->layout()->addWidget(dataWidgets.vertexTable); - widget.locationDataGroupBox->layout()->addWidget(dataWidgets.vertexData); + widget.loadGraphButton->setEnabled(false); - // Add scene - view.view = widget.graphicsViewGraph; - view.setScene(new GraphScene()); + view.edgeTable = new EdgeTableWidget(); + view.vertexTable = new VertexTableWidget(); + view.vertexData = new VertexDataWidget(); + view.vertexData->setEnabled(false); // Enable on first selection of vertex. + widget.edgesTableGroupBox->layout()->addWidget(view.edgeTable); + widget.locationsTableGroupBox->layout()->addWidget(view.vertexTable); + widget.locationDataGroupBox->layout()->addWidget(view.vertexData); + view.graph = new GraphSceneWidget(); + widget.graphSceneLayout->addWidget(view.graph); + +#if 0 auto eventFilter = [this](QObject* obj, QEvent* event) -> bool { -#if 0 if (obj == this->view.view && event->type() == QEvent::MouseButtonPress) { QMouseEvent* me = static_cast<QMouseEvent*>(event); @@ -158,54 +162,38 @@ namespace armarx::nav::locgrapheditor { this->adjustView(); } -#endif - return QObject::eventFilter(obj, event); + else + { + return false; + } }; view.view->installEventFilter(new simox::gui::FunctionalEventFilter(eventFilter)); - - - // Transform view - transformView(); +#endif // Widgets -> This // Memory Access - connect(widget.refreshGraphsButton, &QPushButton::clicked, this, &This::updateGraphList); - connect(widget.loadGraphButton, &QPushButton::clicked, this, &This::loadGraph); + connect(widget.refreshGraphsButton, &QPushButton::pressed, this, &This::updateGraphList); + connect(widget.loadGraphButton, &QPushButton::pressed, this, &This::loadGraph); #if 0 // Tables - connect(dataWidgets.vertexTable, &QTableWidget::cellDoubleClicked, this, &This::vertexTableDoubleClicked); - connect(dataWidgets.vertexTable, &QTableWidget::customContextMenuRequested, this, &This::tableWidgetVerticesCustomContextMenu); - connect(dataWidgets.edgeTable, &QTableWidget::cellDoubleClicked, this, &This::edgeTableDoubleClicked); - connect(dataWidgets.edgeTable, &QTableWidget::customContextMenuRequested, this, &This::tableWidgetEdgesCustomContextMenu); - - connect(widget.btnAdd, &QPushButton::clicked, this, &This::addNewGraphVertex); - connect(widget.btnAddEdge, &QPushButton::clicked, this, &This::addNewEdgeBoth); - connect(widget.btnAddEdgeStartEnd, &QPushButton::clicked, this, &This::addNewEdgeStartEnd); - connect(widget.btnAddEdgeEndStart, &QPushButton::clicked, this, &This::addNewEdgeEndStart); - connect(widget.btnEdit, &QPushButton::clicked, this, &This::editGraphVertex); + connect(view.vertexTable, &QTableWidget::cellDoubleClicked, this, &This::vertexTableDoubleClicked); + connect(view.vertexTable, &QTableWidget::customContextMenuRequested, this, &This::tableWidgetVerticesCustomContextMenu); + connect(view.edgeTable, &QTableWidget::cellDoubleClicked, this, &This::edgeTableDoubleClicked); + connect(view.edgeTable, &QTableWidget::customContextMenuRequested, this, &This::tableWidgetEdgesCustomContextMenu); + + connect(widget.btnAdd, &QPushButton::pressed, this, &This::addNewGraphVertex); + connect(widget.btnAddEdge, &QPushButton::pressed, this, &This::addNewEdgeBoth); + connect(widget.btnAddEdgeStartEnd, &QPushButton::pressed, this, &This::addNewEdgeStartEnd); + connect(widget.btnAddEdgeEndStart, &QPushButton::pressed, this, &This::addNewEdgeEndStart); + connect(widget.btnEdit, &QPushButton::pressed, this, &This::editGraphVertex); #endif - // Zoom - connect(widget.viewZoomFactor, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &This::transformView); - -#if 0 - // Rotation - connect(widget.buttonRotateClock, &QPushButton::clicked, this, &This::viewRotatedClock); - connect(widget.buttonRotateCounterClock, &QPushButton::clicked, this, &This::viewRotatedCounterClock); - - // Redraw+clear - connect(widget.buttonRedraw, &QPushButton::clicked, this, &This::redraw); - connect(widget.buttonClear, &QPushButton::clicked, this, &This::clearGraph); - - // Auto adjust view - connect(widget.buttonAutoAdjust, &QPushButton::clicked, this, &This::adjustView); -#endif - - connect(view.scene, &GraphScene::vertexSelected, this, &This::toggleVertexSelected); + // View + // connect(view.graph->scene(), &GraphScene::vertexSelected, this, &This::toggleVertexSelected); // This -> This @@ -213,13 +201,19 @@ namespace armarx::nav::locgrapheditor connect(this, &This::connected, this, &This::queryGraphs); connect(this, &This::memoryDataChanged, this, &This::updateGraphList); - } + connect(view.vertexData, &VertexDataWidget::vertexDataChanged, + this, &This::updateVertexView); - void LocationGraphEditorWidgetController::GraphView::setScene(GraphScene* scene) - { - this->scene = scene; - this->view->setScene(this->scene); + connect(view.vertexTable, &VertexTableWidget::currentItemChanged, + [this](QTableWidgetItem* current, QTableWidgetItem* previous) + { + (void) previous; + this->selectVertex(current); + }); + + connect(view.vertexTable, &VertexTableWidget::itemSelectionChanged, + this, &This::updateVertexHighlighting); } @@ -327,10 +321,13 @@ namespace armarx::nav::locgrapheditor { widget.graphsComboBox->clear(); - data.memory.forEachEntity([this](const armem::wm::Entity& entity) + bool enable = false; + data.memory.forEachEntity([this, &enable](const armem::wm::Entity& entity) { widget.graphsComboBox->addItem(QString::fromStdString(entity.id().str())); + enable = true; }); + widget.loadGraphButton->setEnabled(enable); } @@ -384,7 +381,7 @@ namespace armarx::nav::locgrapheditor if (vertex.objectID() == vertexID) { vertex.attrib().highlighted = true; - updateVertex(vertex); + updateVertexView(vertex); } } } @@ -399,11 +396,11 @@ namespace armarx::nav::locgrapheditor ARMARX_CHECK(not data.graph.hasVertex(vertex.objectID())); VertexData attrib { vertex.attrib() }; - attrib.graphicsItem = view.scene->addVertex(vertex); - attrib.tableWidgetItem = dataWidgets.vertexTable->addVertex(vertex); + attrib.graphicsItem = view.graph->scene()->addVertex(vertex); + attrib.tableWidgetItem = view.vertexTable->addVertex(vertex); auto guiVertex = data.graph.addVertex(vertex.objectID(), attrib); - updateVertex(guiVertex); + updateVertexView(guiVertex); return guiVertex; } @@ -420,22 +417,21 @@ namespace armarx::nav::locgrapheditor auto target = data.graph.vertex(edge.targetObjectID()); EdgeData attrib { edge.attrib() }; - attrib.tableWidgetItem = dataWidgets.edgeTable->addEdge(edge); - attrib.graphicsItem = view.scene->addEdge(edge); + attrib.tableWidgetItem = view.edgeTable->addEdge(edge); + attrib.graphicsItem = view.graph->scene()->addEdge(edge); auto guiEdge = data.graph.addEdge(source, target, attrib); - updateEdge(guiEdge); + updateEdgeView(guiEdge); return guiEdge; } - void LocationGraphEditorWidgetController::updateVertex(GuiGraph::Vertex vertex) + void LocationGraphEditorWidgetController::updateVertexView(GuiGraph::Vertex vertex) { - view.scene->updateVertex(vertex); - dataWidgets.vertexTable->updateVertex(vertex); - - setEditFields(vertex); + view.graph->scene()->updateVertex(vertex); + view.vertexTable->updateVertex(vertex); + if (/* DISABLES CODE */ (false)) // Disable this for the moment. { // Highlight all edges between highlighted vertices std::set<semrel::ShapeID> highlightedVertices; @@ -458,7 +454,7 @@ namespace armarx::nav::locgrapheditor if (edge.attrib().highlighted != verticesHighlighted) { edge.attrib().highlighted = verticesHighlighted; - updateEdge(edge); + updateEdgeView(edge); } } } @@ -480,10 +476,10 @@ namespace armarx::nav::locgrapheditor } - void LocationGraphEditorWidgetController::updateEdge(GuiGraph::Edge edge) + void LocationGraphEditorWidgetController::updateEdgeView(GuiGraph::Edge edge) { - view.scene->updateEdge(edge); - dataWidgets.edgeTable->updateEdge(edge); + view.graph->scene()->updateEdge(edge); + view.edgeTable->updateEdge(edge); #if 0 armarx::Vector3Ptr posStart = new armarx::Vector3(armarx::Vector3Ptr::dynamicCast(vertices.at(id.first).pose->position)->toEigen()); @@ -507,12 +503,12 @@ namespace armarx::nav::locgrapheditor // Remove from graphics scene for (auto edge : data.graph.edges()) { - view.scene->removeEdge(edge.attrib().graphicsItem); + view.graph->scene()->removeEdge(edge.attrib().graphicsItem); } // Clear table widget - dataWidgets.edgeTable->clearContents(); - dataWidgets.edgeTable->setRowCount(0); + view.edgeTable->clearContents(); + view.edgeTable->setRowCount(0); // Clear data structure while (data.graph.edges().begin() != data.graph.edges().end()) @@ -527,13 +523,13 @@ namespace armarx::nav::locgrapheditor void LocationGraphEditorWidgetController::clearGraph() { // Clear scene - view.scene->clear(); + view.graph->scene()->clear(); // Clear table widgets - dataWidgets.edgeTable->clearContents(); - dataWidgets.edgeTable->setRowCount(0); - dataWidgets.vertexTable->clearContents(); - dataWidgets.vertexTable->setRowCount(0); + view.edgeTable->clearContents(); + view.edgeTable->setRowCount(0); + view.vertexTable->clearContents(); + view.vertexTable->setRowCount(0); // Clear data structure data.graph.clear(); @@ -544,11 +540,10 @@ namespace armarx::nav::locgrapheditor { auto vertex = data.graph.vertex(vertexID); vertex.attrib().highlighted ^= true; - updateVertex(vertex); + updateVertexView(vertex); } - void LocationGraphEditorWidgetController::resetHighlighting() { for (auto vertex : data.graph.vertices()) @@ -556,7 +551,7 @@ namespace armarx::nav::locgrapheditor if (vertex.attrib().highlighted) { vertex.attrib().highlighted = false; - updateVertex(vertex); + updateVertexView(vertex); } } for (auto edge : data.graph.edges()) @@ -564,12 +559,32 @@ namespace armarx::nav::locgrapheditor if (edge.attrib().highlighted) { edge.attrib().highlighted = false; - updateEdge(edge); + updateEdgeView(edge); } } } + void LocationGraphEditorWidgetController::updateVertexHighlighting() + { + std::map<QTableWidgetItem*, GuiGraph::Vertex> map = data.graph.getTableItemToVertexMap(); + + for (QTableWidgetItem* selected : view.vertexTable->selectedEdgeItems()) + { + if (auto it = map.find(selected); it != map.end()) + { + it->second.attrib().highlighted = true; + updateVertexView(it->second); + map.erase(it); + } + } + for (auto& [_, unselected] : map) + { + unselected.attrib().highlighted = false; + updateVertexView(unselected); + } + } + #if 0 @@ -612,7 +627,7 @@ namespace armarx::nav::locgrapheditor { auto vertexIt = std::find_if(vertices.cbegin(), vertices.cend(), [&](const std::pair<std::string, VertexData>& d) { - // return d.attrib().vertex->getName() == dataWidgets.vertexTable->item(row, 0)->text().toStdString(); + // return d.attrib().vertex->getName() == view.vertexTable->item(row, 0)->text().toStdString(); return d.attrib().tableWidgetVerticesIndex == row; }); auto vertexId = vertexIt->second.vertex->getId(); @@ -643,35 +658,9 @@ namespace armarx::nav::locgrapheditor updateVertex(edge.attrib()); } - - void LocationGraphEditorWidgetController::redraw() - { - loadGraph(); - } #endif - void LocationGraphEditorWidgetController::setEditFields(GuiGraph::Vertex vertex) - { -#if 0 - widget.editVertexId->setText(QString::fromStdString(vertexData.vertex->getId())); - widget.editSceneName->setText(QString::fromStdString(vertexData.vertex->getScene())); - widget.editVertexName->setText(QString::fromStdString(vertexData.vertex->getName())); - widget.editFrameName->setText(QString::fromStdString(vertexData.pose->frame)); - widget.editAgentName->setText(QString::fromStdString(vertexData.pose->agent)); - - Eigen::Vector3f rpy; - VirtualRobot::MathTools::eigen4f2rpy(vertexData.pose->toEigen(), rpy); - widget.spinBoxX->setValue(vertexData.pose->position->x); - widget.spinBoxY->setValue(vertexData.pose->position->y); - widget.spinBoxZ->setValue(vertexData.pose->position->z); - - widget.spinBoxRoll->setValue(VirtualRobot::MathTools::rad2deg(rpy[0])); - widget.spinBoxPitch->setValue(VirtualRobot::MathTools::rad2deg(rpy[1])); - widget.spinBoxYaw->setValue(VirtualRobot::MathTools::rad2deg(rpy[2])); -#endif - } - #if 0 void LocationGraphEditorWidgetController::refreshGraph() { @@ -681,68 +670,19 @@ namespace armarx::nav::locgrapheditor #endif - void LocationGraphEditorWidgetController::transformView() - { - double d = widget.viewZoomFactor->value(); - widget.graphicsViewGraph->setTransform(QTransform::fromScale(d, d).rotate(view.angle)); - } - - -#if 0 - - void LocationGraphEditorWidgetController::viewRotatedClock() + void LocationGraphEditorWidgetController::selectVertex(QTableWidgetItem* vertexItem) { - viewAngle = std::fmod(viewAngle + VIEW_ROTATE_STEP_SIZE_CC, 360); - transformView(); - } - - - void LocationGraphEditorWidgetController::viewRotatedCounterClock() - { - viewAngle = std::fmod(viewAngle + 360 - VIEW_ROTATE_STEP_SIZE_CC, 360); - transformView(); - } -#endif - - void LocationGraphEditorWidgetController::adjustView() - { -#if 0 - float maxX = std::numeric_limits<float>::min(); - float minX = std::numeric_limits<float>::max(); - float maxY = std::numeric_limits<float>::min(); - float minY = std::numeric_limits<float>::max(); - - // search bounding box - for (const auto& vertex : vertices) + if (auto vertex = data.graph.getVertexFromTableItem(vertexItem)) { - maxX = (maxX < vertex.attrib().pose->position->x) ? vertex.attrib().pose->position->x : maxX; - minX = (minX > vertex.attrib().pose->position->x) ? vertex.attrib().pose->position->x : minX; - maxY = (maxY < vertex.attrib().pose->position->y) ? vertex.attrib().pose->position->y : maxY; - minY = (minY > vertex.attrib().pose->position->y) ? vertex.attrib().pose->position->y : minY; + selectVertex(vertex.value()); } + } - auto deltaX = maxX - minX; // >=0 - auto deltaY = maxY - minY; // >=0 - // compare ratio of graph and view. if both horizontal (vertical) ->rotate to 0 or 180 (90,270) - if (std::signbit(deltaX / deltaY - 1) == std::signbit(widget.graphicsViewGraph->width() / widget.graphicsViewGraph->height() - 1)) - { - // same => rotate to 0 or 180 - viewAngle = (viewAngle < std::abs(180 - viewAngle)) ? 0 : 180; - // set zoom => update - widget.viewZoomFactor->setValue(std::min(widget.graphicsViewGraph->width() / deltaX, - widget.graphicsViewGraph->height() / deltaY) * 0.9); - } - else - { - // different rotate to 90 or 270 - viewAngle = (std::abs(90 - viewAngle) < std::abs(270 - viewAngle)) ? 90 : 270; - // set zoom => update - widget.viewZoomFactor->setValue(std::min(widget.graphicsViewGraph->width() / deltaY, - widget.graphicsViewGraph->height() / deltaX) * 0.9); - } -#endif + void LocationGraphEditorWidgetController::selectVertex(GuiGraph::Vertex vertex) + { + view.vertexData->setVertex(vertex); } @@ -916,7 +856,7 @@ namespace armarx::nav::locgrapheditor void LocationGraphEditorWidgetController::tableWidgetVerticesCustomContextMenu(QPoint pos) { - int row = dataWidgets.vertexTable->rowAt(pos.y()); + int row = view.vertexTable->rowAt(pos.y()); auto vertexIt = std::find_if(vertices.begin(), vertices.end(), [&](const std::pair<std::string, VertexData>& d) { return d.attrib().tableWidgetVerticesIndex == row; @@ -935,7 +875,7 @@ namespace armarx::nav::locgrapheditor void LocationGraphEditorWidgetController::tableWidgetEdgesCustomContextMenu(QPoint pos) { - int row = dataWidgets.edgeTable->rowAt(pos.y()); + int row = view.edgeTable->rowAt(pos.y()); auto edgeIt = std::find_if(edges.begin(), edges.end(), [&](const std::pair<EdgeId, EdgeData>& d) { return d.attrib().tableWidgetEdgesIndex == row; diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.h b/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.h index d06303359ed86124fdd2f14fac4b3a8496eca329..ded79af18d0f42d05163b250f2138803822a32f4 100644 --- a/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.h +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/LocationGraphEditorWidgetController.h @@ -22,8 +22,8 @@ #pragma once #include "FunctionalEventFilter.h" -#include "GraphScene.h" #include "GuiGraph.h" +#include "widgets/graph_scene.h" #include <armarx/navigation/graph/Graph.h> @@ -142,18 +142,17 @@ namespace armarx::nav::locgrapheditor // View & Tables - void updateVertex(GuiGraph::Vertex vertex); - void updateEdge(GuiGraph::Edge edge); - - /// Applies the current transforamtion to the view. - void transformView(); - /// Adjusts the view's zoom and rotation to display most of the graph. - void adjustView(); + void updateVertexView(GuiGraph::Vertex vertex); + void updateEdgeView(GuiGraph::Edge edge); // Selection + void selectVertex(QTableWidgetItem* vertexItem); + void selectVertex(GuiGraph::Vertex vertex); + void resetHighlighting(); + void updateVertexHighlighting(); void toggleVertexSelected(const semrel::ShapeID& vertexID); @@ -184,52 +183,30 @@ namespace armarx::nav::locgrapheditor struct Data { armem::wm::Memory memory; - nav::locgrapheditor::GuiGraph graph; + GuiGraph graph; }; Data data; - struct DataWidgets + struct View { VertexTableWidget* vertexTable = nullptr; EdgeTableWidget* edgeTable = nullptr; VertexDataWidget* vertexData = nullptr; - }; - DataWidgets dataWidgets; - - - struct GraphView - { - QGraphicsView* view = nullptr; - /** - * @brief The scene displayed in the widget. - * - * For y coordinates (-y) is used to mirror the scene on the y axis. - * If (+y) would be used the graph displayed in the scene would not - * match the graph drawn to the debug layer. - */ - GraphScene* scene; - - /// The view's rotation angle. - qreal angle = 0; - - void setScene(GraphScene* scene); + GraphSceneWidget* graph = nullptr; }; - GraphView view; - + View view; // Non-refactored - #if 0 private slots: void highlightEdge(const std::string& vertex1Id, const std::string& vertex2Id, bool highlighted = true); void highlightVertex(const std::string& vertexId, bool highlighted = true); - void redraw(); void refreshGraph(); void tableWidgetVerticesCustomContextMenu(QPoint pos); @@ -281,8 +258,6 @@ namespace armarx::nav::locgrapheditor void editGraphVertex(); #endif - void setEditFields(GuiGraph::Vertex vertex); - private: diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene.h b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene.h new file mode 100644 index 0000000000000000000000000000000000000000..5edd01203df57213a8d5b0d9099d527237c6c12a --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene.h @@ -0,0 +1,17 @@ +#pragma once + + +namespace armarx::nav::locgrapheditor::graph_scene +{ + class Scene; + class Widget; +} + +namespace armarx::nav::locgrapheditor +{ + + using GraphScene = graph_scene::Scene; + using GraphSceneWidget = graph_scene::Widget; + +} + diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/ControlWidget.cpp b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/ControlWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5549b56f46afc984490bd9abbd16e2d98cbebe1d --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/ControlWidget.cpp @@ -0,0 +1,107 @@ +#include "ControlWidget.h" + +#include <ArmarXCore/core/logging/Logging.h> + +#include <QDoubleSpinBox> +#include <QFrame> +#include <QHBoxLayout> +#include <QLabel> +#include <QPushButton> + +#include <cmath> + + +namespace armarx::nav::locgrapheditor::graph_scene +{ + + ControlWidget::ControlWidget() + { + _angle.turnClockwise = new QPushButton("\u21bb"); // https://unicode-table.com/de/21BB/ + _angle.turnCounterClockwise = new QPushButton("\u21ba"); // https://unicode-table.com/de/21BA/ + std::vector<QPushButton*> turnButtons; + for (QPushButton* button : turnButtons) + { + button->setMinimumWidth(button->minimumHeight()); + button->setMaximumWidth(button->maximumHeight()); + button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); + } + + _angle.value = new QDoubleSpinBox(); + _angle.value->setMinimum(-360); + _angle.value->setMaximum(360); + _angle.value->setSingleStep(15); + _angle.value->setValue(0); + + _zoom.value = new QDoubleSpinBox(); + _zoom.value->setDecimals(5); + _zoom.value->setMinimum(1e-6); + _zoom.value->setSingleStep(0.01); + _zoom.value->setValue(0.1); + _zoom.audoAdjust = new QPushButton("Auto"); + + + QHBoxLayout* layout = new QHBoxLayout(); + this->setLayout(layout); + + layout->addWidget(new QLabel("Angle: ")); + layout->addWidget(_angle.turnClockwise); + layout->addWidget(_angle.value); + layout->addWidget(_angle.turnCounterClockwise); + + // Vertical separator line. + QFrame* line = new QFrame(); + line->setFrameShape(QFrame::VLine); + line->setFrameShadow(QFrame::Sunken); + layout->addWidget(line); + + layout->addWidget(new QLabel("Zoom: ")); + layout->addWidget(_zoom.value); + layout->addWidget(_zoom.audoAdjust); + + + // Connect + + connect(_angle.value, QOverload<double>::of(&QDoubleSpinBox::valueChanged), + this, &This::angleChanged); + + connect(_angle.turnClockwise, &QPushButton::pressed, [this]() + { + qreal newangle = std::fmod(angle() + _angle.rotateStepSize, 360.0); + ARMARX_IMPORTANT << VAROUT(newangle); + setAngle(newangle); + }); + connect(_angle.turnCounterClockwise, &QPushButton::pressed, [this]() + { + setAngle(std::fmod(angle() - _angle.rotateStepSize, 360.0)); + }); + + connect(_zoom.value, QOverload<double>::of(&QDoubleSpinBox::valueChanged), + this, &This::angleChanged); + connect(_zoom.audoAdjust, &QPushButton::pressed, + this, &This::zoomAutoAdjustRequested); + } + + + qreal ControlWidget::angle() + { + return _angle.value->value(); + } + + void ControlWidget::setAngle(qreal angle) + { + _angle.value->setValue(angle); + } + + + qreal ControlWidget::zoom() + { + return _zoom.value->value(); + } + + void ControlWidget::setZoom(qreal zoom) + { + _zoom.value->setValue(zoom); + } + +} + diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/ControlWidget.h b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/ControlWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..64d4270e8c85c8493c408235b327b39012e3e5ed --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/ControlWidget.h @@ -0,0 +1,59 @@ +#pragma once + +#include <QWidget> + +class QDoubleSpinBox; +class QHBoxLayout; +class QPushButton; + + +namespace armarx::nav::locgrapheditor::graph_scene +{ + + class ControlWidget : public QWidget + { + Q_OBJECT + using This = ControlWidget; + + + public: + + ControlWidget(); + + qreal angle(); + void setAngle(qreal angle); + qreal zoom(); + void setZoom(qreal zoom); + + + signals: + + void angleChanged(qreal value); + + void zoomChanged(qreal value); + void zoomAutoAdjustRequested(); + + + public: + + struct Angle + { + QPushButton* turnClockwise = nullptr; + QDoubleSpinBox* value = nullptr; + QPushButton* turnCounterClockwise = nullptr; + + qreal rotateStepSize = 45; + }; + Angle _angle; + + struct Zoom + { + QDoubleSpinBox* value = nullptr; + QPushButton* audoAdjust = nullptr; + }; + Zoom _zoom; + + }; + +} + diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Scene.cpp b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Scene.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d66a24e55615b8b86d8597b09c56c4a61a1db486 --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Scene.cpp @@ -0,0 +1,164 @@ +#include "Scene.h" + +#include <ArmarXCore/core/exceptions/local/ExpressionException.h> + +#include <SemanticObjectRelations/Shapes/Shape.h> + +#include <Eigen/Core> + + +namespace armarx::nav::locgrapheditor::graph_scene +{ + + QGraphicsEllipseItem* + Scene::addVertex(const graph::Graph::Vertex& vertex) + { + const Eigen::Matrix4d pose = vertex.attrib().getPose().cast<qreal>(); + + // To capture by copy + semrel::ShapeID vertexID = vertex.objectID(); + + GraphVisualizerGraphicsEllipseItem* item = new GraphVisualizerGraphicsEllipseItem + { + [this, vertexID]() { emit vertexSelected(vertexID); }, + pose(0, 3), - pose(1, 3), + 1, 1 + }; + addItem(item); + + // setToolTip on graphicsItem does not work + item->setZValue(std::numeric_limits<qreal>::max()); + // dynamic_cast<QGraphicsItem*>(item)->setToolTip(QString::fromStdString("Vertex '" + name + "'")); + item->setToolTip(QString::fromStdString("Vertex '" + vertex.attrib().getName() + "'")); + + return item; + } + + + QGraphicsLineItem* + Scene::addEdge(const graph::Graph::Edge& edge) + { + semrel::ShapeID sourceID = edge.sourceObjectID(); + semrel::ShapeID targetID = edge.targetObjectID(); + + Eigen::Matrix4d sourcePose = edge.source().attrib().getPose().cast<qreal>(); + Eigen::Matrix4d targetPose = edge.target().attrib().getPose().cast<qreal>(); + + GraphVisualizerGraphicsLineItem* item = new GraphVisualizerGraphicsLineItem + { + [this, sourceID, targetID]() { emit edgeSelected(sourceID, targetID); }, + sourcePose(0, 3), - sourcePose(1, 3), + targetPose(0, 3), - targetPose(1, 3) + }; + addItem(item); + + // setToolTip on item does not work + std::stringstream toolTip; + toolTip << "Edge '" << edge.source().attrib().getName() + << "' -> '" << edge.target().attrib().getName(); + item->setToolTip(QString::fromStdString(toolTip.str())); + + return item; + } + + + void Scene::updateVertex(GuiGraph::Vertex& vertex) + { + QGraphicsEllipseItem* item = vertex.attrib().graphicsItem; + ARMARX_CHECK_NOT_NULL(item); + + const Eigen::Matrix4d pose = vertex.attrib().getPose().cast<qreal>(); + + QColor color = vertex.attrib().highlighted ? colorSelected : colorDefault; + double lineWidth = vertex.attrib().highlighted ? lineWidthSelected : lineWidthDefault; + + item->setPen(QPen {color}); + item->setBrush(QBrush {color}); + item->setRect( pose(0, 3) - lineWidth * verticesScaleFactor / 2, + - pose(1, 3) - lineWidth * verticesScaleFactor / 2, + lineWidth * verticesScaleFactor, + lineWidth * verticesScaleFactor); + } + + + void Scene::updateEdge(GuiGraph::Edge& edge) + { + QGraphicsLineItem* item = edge.attrib().graphicsItem; + ARMARX_CHECK_NOT_NULL(item); + + Eigen::Matrix4d sourcePose = edge.source().attrib().getPose().cast<qreal>(); + Eigen::Matrix4d targetPose = edge.target().attrib().getPose().cast<qreal>(); + + QColor color = edge.attrib().highlighted ? colorSelected : colorDefault; + double lineWidth = edge.attrib().highlighted ? lineWidthSelected : lineWidthDefault; + + QPen pen {color}; + pen.setWidthF(lineWidth * lineScaleFactor); + + item->setPen(pen); + item->setLine(sourcePose(0, 3), - sourcePose(1, 3), + targetPose(0, 3), - targetPose(1, 3)); + } + + + void Scene::removeVertex(QGraphicsEllipseItem*& item) + { + removeItem(item); + delete item; + item = nullptr; + } + + + void Scene::removeEdge(QGraphicsLineItem*& item) + { + removeItem(item); + delete item; + item = nullptr; + } + + + GraphVisualizerGraphicsEllipseItem::GraphVisualizerGraphicsEllipseItem( + std::function<void(void)> onDoubleClicked, + qreal x, qreal y, + qreal width, qreal height, + QGraphicsItem* parent) : + QGraphicsEllipseItem {x, y, width, height, parent}, + onDoubleClicked{onDoubleClicked} + { + } + + + GraphVisualizerGraphicsEllipseItem::~GraphVisualizerGraphicsEllipseItem() + { + } + + + void GraphVisualizerGraphicsEllipseItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) + { + onDoubleClicked(); + } + + + + GraphVisualizerGraphicsLineItem::GraphVisualizerGraphicsLineItem( + std::function<void(void)> onDoubleClicked, + qreal x1, qreal y1, qreal x2, qreal y2, + QGraphicsItem* parent) : + QGraphicsLineItem {x1, y1, x2, y2, parent}, + onDoubleClicked{onDoubleClicked} + { + } + + + GraphVisualizerGraphicsLineItem::~GraphVisualizerGraphicsLineItem() + { + } + + + void GraphVisualizerGraphicsLineItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) + { + onDoubleClicked(); + } + +} + diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Scene.h b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Scene.h new file mode 100644 index 0000000000000000000000000000000000000000..f1b1ac37a186e289b5cea0cbcd23ced1b410f117 --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Scene.h @@ -0,0 +1,118 @@ +#pragma once + +#include <armarx/navigation/gui-plugins/LocationGraphEditor/GuiGraph.h> +#include <armarx/navigation/graph/Graph.h> + +#include <QGraphicsScene> +#include <QGraphicsEllipseItem> +#include <QGraphicsLineItem> + +#include <functional> + + +namespace semrel +{ + struct ShapeID; +} +namespace armarx::nav::locgrapheditor::graph_scene +{ + class Scene : public QGraphicsScene + { + Q_OBJECT + + public: + + using QGraphicsScene::QGraphicsScene; + + QGraphicsEllipseItem* addVertex(const graph::Graph::Vertex& vertex); + QGraphicsLineItem* addEdge(const graph::Graph::Edge& Edge); + + void updateVertex(GuiGraph::Vertex& vertex); + void updateEdge(GuiGraph::Edge& edge); + + void removeVertex(QGraphicsEllipseItem*& item); + void removeEdge(QGraphicsLineItem*& item); + + + public slots: + + + signals: + + void vertexSelected(const semrel::ShapeID& vertexID); + void edgeSelected(const semrel::ShapeID& sourceID, const semrel::ShapeID& targetID); + + + public: + + double lineWidthDefault = 5; + double lineWidthSelected = 10; + + double sceneScaleFactor = 2; + double verticesScaleFactor = 3.0 * sceneScaleFactor; + double lineScaleFactor = 1.0 * sceneScaleFactor; + + QColor colorDefault = QColor::fromRgb(128, 128, 255); + QColor colorSelected = QColor::fromRgb(255, 128, 0); + + }; + + + + /** + * @brief Required to override the double click event. + * This is required to toggle the select state. + */ + class GraphVisualizerGraphicsEllipseItem : public QGraphicsEllipseItem + { + public: + + GraphVisualizerGraphicsEllipseItem( + std::function<void(void)> onDoubleClicked, + qreal x, qreal y, qreal width, qreal height, + QGraphicsItem* parent = nullptr); + + ~GraphVisualizerGraphicsEllipseItem() override; + + + protected: + + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override; + + + std::function<void(void)> onDoubleClicked; + + }; + + + + /** + * @brief Required to override the double click event. + * This is required to toggle the select state. + */ + class GraphVisualizerGraphicsLineItem : public QGraphicsLineItem + { + public: + + GraphVisualizerGraphicsLineItem( + std::function<void(void)> onDoubleClicked, + qreal x1, qreal y1, + qreal x2, qreal y2, + QGraphicsItem* parent = nullptr); + + ~GraphVisualizerGraphicsLineItem() override; + + + protected: + + + void mouseDoubleClickEvent(QGraphicsSceneMouseEvent*) override; + + + std::function<void(void)> onDoubleClicked; + + }; + + +} + diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Widget.cpp b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Widget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e05f7e6be1fb604701496271d440503085161655 --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Widget.cpp @@ -0,0 +1,83 @@ +#include "Widget.h" +#include "Scene.h" +#include "ControlWidget.h" + +#include <QGraphicsView> +#include <QHBoxLayout> +#include <QLabel> +#include <QVBoxLayout> + + +namespace armarx::nav::locgrapheditor::graph_scene +{ + + Widget::Widget() + { + _control = new ControlWidget(); + + _scene = new Scene(); + + _view = new QGraphicsView(); + _view->setScene(_scene); + _view->setRenderHint(QPainter::Antialiasing, true); + + int margin = 0; + this->setContentsMargins(margin, margin, margin, margin); + this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QHBoxLayout* header = new QHBoxLayout(); + header->setSpacing(0); + header->addWidget(new QLabel("Graph")); + header->addStretch(); + header->addWidget(_control); + + QVBoxLayout* layout = new QVBoxLayout(); + this->setLayout(layout); + + layout->addLayout(header); + layout->addWidget(_view); + + + connect(_control, &ControlWidget::angleChanged, + this, &This::transform); + connect(_control, &ControlWidget::zoomChanged, + this, &This::transform); + connect(_control, &ControlWidget::zoomAutoAdjustRequested, + this, &This::autoAdjustZoom); + + + // Initial transform. + transform(); + } + + + QGraphicsView* Widget::view() + { + return _view; + } + + + Scene* Widget::scene() + { + return _scene; + } + + + void Widget::transform() + { + double angle = _control->angle(); + double zoom = _control->zoom(); + _view->setTransform(QTransform::fromScale(zoom, zoom).rotate(angle)); + } + + + void Widget::autoAdjustZoom() + { + int margin = 3; + QRectF rect = _scene->sceneRect() + QMargins(margin, margin, margin, margin); + _view->fitInView(rect, Qt::AspectRatioMode::KeepAspectRatio); + _control->setZoom(_view->transform().rotate(- _control->angle()).m11()); + } + +} + diff --git a/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Widget.h b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Widget.h new file mode 100644 index 0000000000000000000000000000000000000000..c8a4b649e10ac5b7e2bde4d5a680ca36c731a2b4 --- /dev/null +++ b/source/armarx/navigation/gui-plugins/LocationGraphEditor/widgets/graph_scene/Widget.h @@ -0,0 +1,58 @@ +#pragma once + +#include <QWidget> + +class QGraphicsView; + + +namespace armarx::nav::locgrapheditor::graph_scene +{ + class ControlWidget; + class Scene; + + + class Widget : public QWidget + { + Q_OBJECT + using This = Widget; + + + public: + + Widget(); + + QGraphicsView* view(); + Scene* scene(); + + + public slots: + + void transform(); + void autoAdjustZoom(); + + + private: + + /// Some buttons and input fields. + ControlWidget* _control = nullptr; + + /// The "canvas". + QGraphicsView* _view = nullptr; + + /** + * @brief The scene displayed in the widget. + * + * For y coordinates (-y) is used to mirror the scene on the y axis. + * If (+y) would be used the graph displayed in the scene would not + * match the graph drawn to the debug layer. + */ + Scene* _scene; + + + /// The view's rotation angle. + qreal _angle = 0; + + }; + +} +