From fa15a7c30af58f015f2db035e669b65d9e9f4fc6 Mon Sep 17 00:00:00 2001 From: dmatetelki Date: Mon, 11 Aug 2014 15:22:57 +0200 Subject: [PATCH] Adding/removing nodes, adding edges. --- lib/graph/graph.hpp | 12 +++++- lib/qtgraph/graphwidget.cpp | 82 +++++++++++++++++++++++++++++-------- lib/qtgraph/node.cpp | 40 +++++++++++------- lib/qtgraph/node.hpp | 16 ++++---- 4 files changed, 109 insertions(+), 41 deletions(-) diff --git a/lib/graph/graph.hpp b/lib/graph/graph.hpp index 4f6e8b2..5ea2941 100644 --- a/lib/graph/graph.hpp +++ b/lib/graph/graph.hpp @@ -72,6 +72,7 @@ public: // Lookup bool contains(const_reference data) const { return m_vertices.find(data) != m_vertices.end(); } std::vector vertices() const; + bool connected(const_reference source, const_reference destination) const; std::vector neighboursOf(const_reference data) const; std::vector edges() const; @@ -251,6 +252,13 @@ inline std::vector::value_type> Graph::vertices() const return retval; } +template +inline bool Graph::connected(const_reference source, const_reference destination) const +{ + std::vector neightbours = neighboursOf(source); + return std::find(neightbours.begin(), neightbours.end(), destination) != neightbours.end(); +} + template inline std::vector Graph::neighboursOf(const_reference data) const { @@ -281,7 +289,9 @@ inline std::vector::Edge> Graph::edges() const template inline void Graph::eraseEdge(edge_container& v, const_reference data) { - v.erase(std::remove(v.begin(), v.end()), v.end()); + v.erase(std::remove_if(v.begin(), v.end(), + [&data](const_reference d) { return d == data; }), + v.end()); } diff --git a/lib/qtgraph/graphwidget.cpp b/lib/qtgraph/graphwidget.cpp index 6eb4a7b..10afedf 100644 --- a/lib/qtgraph/graphwidget.cpp +++ b/lib/qtgraph/graphwidget.cpp @@ -12,6 +12,8 @@ #include +#include + namespace std { template <> struct hash @@ -25,17 +27,26 @@ namespace std { }; } +namespace { + // for the map -bool operator< (const float2& v1, const float2& v2) -{ - return length(v1) < length(v2); -} +// bool operator< (const float2& v1, const float2& v2) +// { +// return length(v1) < length(v2); +// } float2 inline float2FromQPointF(const QPointF& p) { return float2(p.x(), p.y()); } +QPointF inline QPointFFromfloat2(const float2& f) +{ + return QPointF(f.x, f.y); +} + +} // anonym namespace + GraphWidget::GraphWidget(Graph* graph, QWidget *p) : QGraphicsView(p) @@ -59,24 +70,23 @@ void GraphWidget::itemMoved(const QPointF oldPos, const QPointF newPos) { float2 old_v = float2FromQPointF(oldPos); float2 new_v = float2FromQPointF(newPos); + + // if old_pos not found, returns silently m_graph->modifyVertex(old_v, new_v); } void GraphWidget::updateFromGraph() { - // scene()->itemAt returns the topmost only which can be an Edge - QMap node_map; for (Graph::iterator cit = m_graph->begin(); cit != m_graph->end(); ++cit) { Node *node = new Node(this); scene()->addItem(node); - node->setPos(cit->x, cit->y); - node_map.insert(*cit, node); + node->setPos(QPointFFromfloat2(*cit)); } for (Graph::iterator cit = m_graph->begin(); cit != m_graph->end(); ++cit) { for (const auto cit2 : m_graph->neighboursOf(*cit)) { - Node* node1 = node_map.find(*cit).value(); - Node* node2 = node_map.find(cit2).value(); + Node* node1 = dynamic_cast(scene()->itemAt(QPointFFromfloat2(*cit))); + Node* node2 = dynamic_cast(scene()->itemAt(QPointFFromfloat2(cit2))); scene()->addItem(new Edge(node1, node2)); } } @@ -91,6 +101,25 @@ void GraphWidget::keyPressEvent(QKeyEvent *e) case Qt::Key_Minus: zoomOut(); break; + + case Qt::Key_Delete: { + QList selectedItems = scene()->selectedItems(); + if (selectedItems.isEmpty()) + break; + + QGraphicsItem* selectedItem = selectedItems.first(); + m_graph->removeVertex(float2FromQPointF(selectedItem->pos())); + + Node* selectedNode = dynamic_cast(selectedItem); + QList edges_of_selected = selectedNode->edges(); + for (Edge* edge : edges_of_selected) { + edge->sourceNode()->removeEdge(selectedNode); + edge->destNode()->removeEdge(selectedNode); + scene()->removeItem(edge); + } + + scene()->removeItem(selectedItem); + } case Qt::Key_Insert: { QList selectedItems = scene()->selectedItems(); if (selectedItems.isEmpty()) @@ -103,14 +132,31 @@ void GraphWidget::keyPressEvent(QKeyEvent *e) const QPoint widget_p = mapFromGlobal(global_p); const QPointF scene_p = mapToScene(widget_p); - Node *node = new Node(this); - scene()->addItem(node); - node->setPos(scene_p.x(), scene_p.y()); - scene()->addItem(new Edge(selectedNode, node)); - - const float2 source_pos = float2FromQPointF(selectedItem->pos()); - const float2 destination_pos = float2FromQPointF(scene_p); - m_graph->addEdge(source_pos, destination_pos); + /// @bug no hit deteced (hover works) on bottom right corner + QGraphicsItem* item_under_mouse = scene()->itemAt(scene_p); + Node* node_under_mouse = dynamic_cast(item_under_mouse); + if (node_under_mouse != 0) { // insert Edge + + const float2 source_pos = float2FromQPointF(selectedItem->pos()); + const float2 destination_pos = float2FromQPointF(node_under_mouse->pos()); + if (m_graph->connected(source_pos, destination_pos)) + return; + + scene()->addItem(new Edge(selectedNode, node_under_mouse)); + m_graph->addEdge(source_pos, destination_pos); + } else { // insert new node + Node *node = new Node(this); + scene()->addItem(node); + node->setPos(scene_p.x(), scene_p.y()); + scene()->addItem(new Edge(selectedNode, node)); + + const float2 source_pos = float2FromQPointF(selectedItem->pos()); + const float2 destination_pos = float2FromQPointF(scene_p); + m_graph->addEdge(source_pos, destination_pos); + + selectedItem->setSelected(false); + node->setSelected(true); + } } default: QGraphicsView::keyPressEvent(e); diff --git a/lib/qtgraph/node.cpp b/lib/qtgraph/node.cpp index ad67c0d..cb134b5 100644 --- a/lib/qtgraph/node.cpp +++ b/lib/qtgraph/node.cpp @@ -14,8 +14,9 @@ Node::Node(GraphWidget *graphWidget) setFlag(ItemIsMovable); setFlag(ItemSendsGeometryChanges); setFlag(ItemIsSelectable); + setAcceptHoverEvents(true); setCacheMode(DeviceCoordinateCache); - setZValue(-1); + setZValue(1); // higher than the edge } void Node::addEdge(Edge *edge) @@ -24,6 +25,18 @@ void Node::addEdge(Edge *edge) edge->adjust(); } +void Node::removeEdge(Node* node) +{ +// QMutableListIterator i(edgeList); +// while (i.hasNext()) +// if (i.next()->sourceNode() == node || i.next()->destNode() == node) +// i.remove(); + + edgeList.erase(std::remove_if(edgeList.begin(), edgeList.end(), + [node](Edge* e) { return e->sourceNode() == node || e->destNode() == node; }), + edgeList.end()); +} + QList Node::edges() const { return edgeList; @@ -43,24 +56,23 @@ QPainterPath Node::shape() const return path; } -void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem* /*option*/, QWidget *) +void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem* option, QWidget *) { - painter->setPen(Qt::NoPen); - painter->setBrush(Qt::darkGray); - painter->drawEllipse(-7, -7, 20, 20); - QRadialGradient gradient(-3, -3, 10); if (isSelected()) { - gradient.setCenter(3, 3); - gradient.setFocalPoint(3, 3); - gradient.setColorAt(0, Qt::red); - gradient.setColorAt(1, Qt::darkRed); + gradient.setCenter(3, 3); + gradient.setFocalPoint(3, 3); + gradient.setColorAt(0, Qt::red); + gradient.setColorAt(1, Qt::darkRed); + } else if (option->state & QStyle::State_MouseOver) { + gradient.setColorAt(0, Qt::green); + gradient.setColorAt(1, Qt::darkGreen); } else { - gradient.setColorAt(0, Qt::yellow); - gradient.setColorAt(1, Qt::darkYellow); + gradient.setColorAt(0, Qt::yellow); + gradient.setColorAt(1, Qt::darkYellow); } - painter->setBrush(gradient); + painter->setBrush(gradient); painter->setPen(QPen(Qt::black, 0)); painter->drawEllipse(-10, -10, 20, 20); } @@ -94,4 +106,4 @@ void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { update(); QGraphicsItem::mouseReleaseEvent(event); -} \ No newline at end of file +} diff --git a/lib/qtgraph/node.hpp b/lib/qtgraph/node.hpp index 2bd0285..d515198 100644 --- a/lib/qtgraph/node.hpp +++ b/lib/qtgraph/node.hpp @@ -14,20 +14,20 @@ public: Node(GraphWidget *graphWidget); void addEdge(Edge *edge); + void removeEdge(Node* node); QList edges() const; enum { Type = UserType + 1 }; - int type() const { return Type; } + int type() const override { return Type; } - QRectF boundingRect() const; - QPainterPath shape() const; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + QRectF boundingRect() const override; + QPainterPath shape() const override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; protected: - QVariant itemChange(GraphicsItemChange change, const QVariant &value); - - void mousePressEvent(QGraphicsSceneMouseEvent *event); - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; + void mousePressEvent(QGraphicsSceneMouseEvent *event) override; + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; private: QList edgeList;