From bd208d8b604dd7958152fdf4db188a0bd64146f5 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Sat, 19 Jan 2019 18:13:51 +0100 Subject: merge nodes --- src/data/edge.cpp | 10 ++++++-- src/gui/mainmenu.cpp | 6 +++++ src/gui/mainmenu.h | 1 + src/gui/mainmenu.ui | 9 +++++++ src/gui/tikzscene.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++++- src/gui/tikzscene.h | 3 ++- src/gui/undocommands.cpp | 10 +++++--- src/gui/undocommands.h | 10 ++++++-- 8 files changed, 103 insertions(+), 9 deletions(-) diff --git a/src/data/edge.cpp b/src/data/edge.cpp index 4803547..0bd49e8 100644 --- a/src/data/edge.cpp +++ b/src/data/edge.cpp @@ -57,8 +57,14 @@ Edge::Edge(Node *s, Node *t, QObject *parent) : Edge *Edge::copy(QMap *nodeTable) { Edge *e; - if (nodeTable == nullptr) e = new Edge(_source, _target); - else e = new Edge(nodeTable->value(_source), nodeTable->value(_target)); + if (nodeTable == nullptr) { + e = new Edge(_source, _target); + } else { + Node *s = nodeTable->value(_source); + Node *t = nodeTable->value(_target); + e = new Edge((s != nullptr) ? s : _source, + (t != nullptr) ? t : _target); + } e->setData(_data->copy()); e->setBasicBendMode(_basicBendMode); e->setBend(_bend); diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp index d291390..35ab736 100644 --- a/src/gui/mainmenu.cpp +++ b/src/gui/mainmenu.cpp @@ -233,6 +233,12 @@ void MainMenu::on_actionReverse_Edge_Direction_triggered() tikzit->activeWindow()->tikzScene()->reverseSelectedEdges(); } +void MainMenu::on_actionMerge_Nodes_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->mergeNodes(); +} + // Tikz void MainMenu::on_actionParse_triggered() diff --git a/src/gui/mainmenu.h b/src/gui/mainmenu.h index 287019c..51d7d3c 100644 --- a/src/gui/mainmenu.h +++ b/src/gui/mainmenu.h @@ -66,6 +66,7 @@ public slots: void on_actionExtendLeft_triggered(); void on_actionExtendRight_triggered(); void on_actionReverse_Edge_Direction_triggered(); + void on_actionMerge_Nodes_triggered(); // Tools void on_actionParse_triggered(); diff --git a/src/gui/mainmenu.ui b/src/gui/mainmenu.ui index ddba6f0..692f82e 100644 --- a/src/gui/mainmenu.ui +++ b/src/gui/mainmenu.ui @@ -73,6 +73,7 @@ + @@ -374,6 +375,14 @@ Ctrl+/ + + + Merge Nodes + + + Ctrl+M + + diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 983cf18..4577981 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -186,6 +186,66 @@ void TikzScene::extendSelectionRight() } } +void TikzScene::mergeNodes() +{ + refreshZIndices(); + QSet selNodes; + QSet selEdges; + getSelection(selNodes, selEdges); + + // build a map from locations to a chosen node at that location + QMap,Node*> m; + foreach (Node *n, selNodes) { + // used fixed precision for hashing/comparing locations + QPair fpPoint( + static_cast(n->point().x() * 1000.0), + static_cast(n->point().y() * 1000.0)); + if (!m.contains(fpPoint) || + _nodeItems[m[fpPoint]]->zValue() < _nodeItems[n]->zValue()) + { + m.insert(fpPoint, n); + } + } + + // build a second map from nodes to the node they will be merged with + QMap m1; + foreach (Node *n, graph()->nodes()) { + QPair fpPoint( + static_cast(n->point().x() * 1000.0), + static_cast(n->point().y() * 1000.0)); + Node *n1 = m[fpPoint]; + if (n1 != nullptr && n1 != n) m1.insert(n, n1); + } + + _tikzDocument->undoStack()->beginMacro("Merge nodes"); + + // copy adjacent edges from nodes that will be deleted + foreach (Edge *e, graph()->edges()) { + if (m1.contains(e->source()) || m1.contains(e->target())) { + Edge *e1 = e->copy(&m1); + AddEdgeCommand *cmd = new AddEdgeCommand(this, e1); + _tikzDocument->undoStack()->push(cmd); + } + } + + // delete nodes + QMap delNodes; + QMap delEdges; + for (int i = 0; i < _tikzDocument->graph()->nodes().length(); ++i) { + Node *n = _tikzDocument->graph()->nodes()[i]; + if (m1.contains(n)) delNodes.insert(i, n); + } + for (int i = 0; i < _tikzDocument->graph()->edges().length(); ++i) { + Edge *e = _tikzDocument->graph()->edges()[i]; + if (m1.contains(e->source()) || m1.contains(e->target())) delEdges.insert(i, e); + } + DeleteCommand *cmd = new DeleteCommand(this, delNodes, delEdges, + selNodes, selEdges); + _tikzDocument->undoStack()->push(cmd); + + _tikzDocument->undoStack()->endMacro(); +} + void TikzScene::reorderSelection(bool toFront) { QVector nodeOrd, nodeOrd1; @@ -911,7 +971,8 @@ void TikzScene::deleteSelectedItems() //qDebug() << "nodes:" << deleteNodes; //qDebug() << "edges:" << deleteEdges; - DeleteCommand *cmd = new DeleteCommand(this, deleteNodes, deleteEdges, selEdges); + DeleteCommand *cmd = new DeleteCommand(this, deleteNodes, deleteEdges, + selNodes, selEdges); _tikzDocument->undoStack()->push(cmd); } diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index 0d3aadf..f8dc7ec 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -75,6 +75,8 @@ public: void extendSelectionLeft(); void extendSelectionRight(); + void mergeNodes(); + void reorderSelection(bool toFront); void reverseSelectedEdges(); @@ -86,7 +88,6 @@ public: void refreshSceneBounds(); bool highlightHeads() const; - bool highlightTails() const; public slots: diff --git a/src/gui/undocommands.cpp b/src/gui/undocommands.cpp index 8ad15d0..c5c26af 100644 --- a/src/gui/undocommands.cpp +++ b/src/gui/undocommands.cpp @@ -128,9 +128,12 @@ void EdgeBendCommand::redo() DeleteCommand::DeleteCommand(TikzScene *scene, QMap deleteNodes, QMap deleteEdges, - QSet selEdges, QUndoCommand *parent) : + QSet selNodes, + QSet selEdges, + QUndoCommand *parent) : GraphUpdateCommand(scene, parent), - _deleteNodes(deleteNodes), _deleteEdges(deleteEdges), _selEdges(selEdges) + _deleteNodes(deleteNodes), _deleteEdges(deleteEdges), + _selNodes(selNodes), _selEdges(selEdges) {} void DeleteCommand::undo() @@ -142,7 +145,7 @@ void DeleteCommand::undo() NodeItem *ni = new NodeItem(n); _scene->nodeItems().insert(n, ni); _scene->addItem(ni); - ni->setSelected(true); + if (_selNodes.contains(n)) ni->setSelected(true); } for (auto it = _deleteEdges.begin(); it != _deleteEdges.end(); ++it) { @@ -229,6 +232,7 @@ AddEdgeCommand::AddEdgeCommand(TikzScene *scene, { } + void AddEdgeCommand::undo() { EdgeItem *ei = _scene->edgeItems()[_edge]; diff --git a/src/gui/undocommands.h b/src/gui/undocommands.h index 94b98be..40f0a3b 100644 --- a/src/gui/undocommands.h +++ b/src/gui/undocommands.h @@ -95,6 +95,7 @@ public: explicit DeleteCommand(TikzScene *scene, QMap deleteNodes, QMap deleteEdges, + QSet selNodes, QSet selEdges, QUndoCommand *parent = nullptr); void undo() override; @@ -102,6 +103,7 @@ public: private: QMap _deleteNodes; QMap _deleteEdges; + QSet _selNodes; QSet _selEdges; }; @@ -121,12 +123,16 @@ private: class AddEdgeCommand : public GraphUpdateCommand { public: - explicit AddEdgeCommand(TikzScene *scene, Edge *edge, bool selectEdge, QSet selNodes, QSet selEdges, QUndoCommand *parent = nullptr); + explicit AddEdgeCommand(TikzScene *scene, Edge *edge, + bool selectEdge=false, + QSet selNodes=QSet(), + QSet selEdges=QSet(), + QUndoCommand *parent = nullptr); void undo() override; void redo() override; private: - bool _selectEdge; Edge *_edge; + bool _selectEdge; QSet _selNodes; QSet _selEdges; }; -- cgit v1.2.3