From 7bdf1bbb2b65612bd3f349562ca622f28dc1abff Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Fri, 20 Jul 2018 14:19:08 +0200 Subject: reflection --- src/data/edgestyle.h | 2 +- src/data/graph.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ src/data/graph.h | 12 +++++++++- src/data/nodestyle.h | 2 +- src/gui/mainmenu.cpp | 11 +++++++++ src/gui/mainmenu.h | 2 ++ src/gui/tikzscene.cpp | 5 ++++ src/gui/tikzscene.h | 1 + src/gui/undocommands.cpp | 31 +++++++++++++++++++++++++ src/gui/undocommands.h | 14 +++++++++++ 10 files changed, 137 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/data/edgestyle.h b/src/data/edgestyle.h index 069545e..eac060a 100644 --- a/src/data/edgestyle.h +++ b/src/data/edgestyle.h @@ -45,7 +45,7 @@ public: ArrowTipStyle arrowTail() const; DrawStyle drawStyle() const; - QPen pen() const; + QPen pen() const override; QPainterPath path() const override; QPainterPath palettePath() const override; QIcon icon() const override; diff --git a/src/data/graph.cpp b/src/data/graph.cpp index 7ed3e91..3123485 100644 --- a/src/data/graph.cpp +++ b/src/data/graph.cpp @@ -98,6 +98,29 @@ QRectF Graph::realBbox() return rect; } +QRectF Graph::boundsForNodes(QSetnds) { + QPointF p; + QPointF tl; + QPointF br; + bool hasPoints = false; + foreach (Node *n, nds) { + p = n->point(); + if (!hasPoints) { + hasPoints = true; + tl = p; + br = p; + } else { + if (p.x() < tl.x()) tl.setX(p.x()); + if (p.y() > tl.y()) tl.setY(p.y()); + if (p.x() > br.x()) br.setX(p.x()); + if (p.y() < br.y()) br.setY(p.y()); + } + } + + QRectF rect(tl, br); + return rect; +} + QString Graph::freshNodeName() { return QString::number(maxIntName() + 1); @@ -267,6 +290,43 @@ void Graph::insertGraph(Graph *graph) foreach (Edge *e, graph->edges()) addEdge(e); } +void Graph::reflectNodes(QSet nds, bool horizontal) +{ + QRectF bds = boundsForNodes(nds); + float ctr; + if (horizontal) ctr = bds.center().x(); + else ctr = bds.center().y(); + + QPointF p; + foreach(Node *n, nds) { + p = n->point(); + if (horizontal) p.setX(2 * ctr - p.x()); + else p.setY(2 * ctr - p.y()); + n->setPoint(p); + } + + foreach (Edge *e, _edges) { + if (nds.contains(e->source()) && nds.contains(e->target())) { + if (!e->basicBendMode()) { + if (horizontal) { + if (e->inAngle() < 0) e->setInAngle(-180 - e->inAngle()); + else e->setInAngle(180 - e->inAngle()); + + if (e->outAngle() < 0) e->setOutAngle(-180 - e->outAngle()); + else e->setOutAngle(180 - e->outAngle()); + } + else { + e->setInAngle(-e->inAngle()); + e->setOutAngle(-e->outAngle()); + } + } + else { + e->setBend(-e->bend()); + } + } + } +} + void Graph::setBbox(const QRectF &bbox) { _bbox = bbox; diff --git a/src/data/graph.h b/src/data/graph.h index 82e1f95..e9e2218 100644 --- a/src/data/graph.h +++ b/src/data/graph.h @@ -46,7 +46,8 @@ public: void addEdge(Edge *e, int index); void removeEdge(Edge *e); int maxIntName(); - QString freshNodeName(); + QRectF boundsForNodes(QSet ns); + QString freshNodeName(); /*! * \brief renameApart assigns fresh names to all of the nodes in "this", @@ -93,6 +94,15 @@ public: * \param graph */ void insertGraph(Graph *graph); + + /*! + * \brief reflectNodes flips the given set of nodes horizontally or vertically, + * depending on the value of the second parameter. + * \param nds a set of nodes to flip + * \param horizontal a boolean determining whether to flip horizontally or + * vertically + */ + void reflectNodes(QSet nds, bool horizontal); signals: public slots: diff --git a/src/data/nodestyle.h b/src/data/nodestyle.h index 5eeef9b..c6fc0f6 100644 --- a/src/data/nodestyle.h +++ b/src/data/nodestyle.h @@ -39,7 +39,7 @@ public: QColor fillColor() const; QBrush brush() const; - QPainterPath path() const; + QPainterPath path() const override; Shape shape() const; QPainterPath palettePath() const override; diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp index 3625338..fa52138 100644 --- a/src/gui/mainmenu.cpp +++ b/src/gui/mainmenu.cpp @@ -110,6 +110,17 @@ void MainMenu::on_actionDeselect_All_triggered() tikzit->activeWindow()->tikzScene()->deselectAll(); } +void MainMenu::on_actionReflectHorizontal_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->reflectNodes(true); +} + +void MainMenu::on_actionReflectVertical_triggered() +{ + if (tikzit->activeWindow() != 0) + tikzit->activeWindow()->tikzScene()->reflectNodes(false); +} // Tikz void MainMenu::on_actionParse_triggered() diff --git a/src/gui/mainmenu.h b/src/gui/mainmenu.h index aa5c727..79aafad 100644 --- a/src/gui/mainmenu.h +++ b/src/gui/mainmenu.h @@ -50,6 +50,8 @@ public slots: void on_actionDelete_triggered(); void on_actionSelect_All_triggered(); void on_actionDeselect_All_triggered(); + void on_actionReflectHorizontal_triggered(); + void on_actionReflectVertical_triggered(); // Tikz void on_actionParse_triggered(); diff --git a/src/gui/tikzscene.cpp b/src/gui/tikzscene.cpp index 1ddd945..9422b6b 100644 --- a/src/gui/tikzscene.cpp +++ b/src/gui/tikzscene.cpp @@ -681,6 +681,11 @@ void TikzScene::parseTikz(QString tikz) } } +void TikzScene::reflectNodes(bool horizontal) { + ReflectNodesCommand *cmd = new ReflectNodesCommand(this, getSelectedNodes(), horizontal); + tikzDocument()->undoStack()->push(cmd); +} + void TikzScene::getSelection(QSet &selNodes, QSet &selEdges) { foreach (QGraphicsItem *gi, selectedItems()) { diff --git a/src/gui/tikzscene.h b/src/gui/tikzscene.h index b6b2560..b0e3835 100644 --- a/src/gui/tikzscene.h +++ b/src/gui/tikzscene.h @@ -64,6 +64,7 @@ public: void selectAllNodes(); void deselectAll(); void parseTikz(QString tikz); + void reflectNodes(bool horizontal); bool enabled() const; void setEnabled(bool enabled); int lineNumberForSelection(); diff --git a/src/gui/undocommands.cpp b/src/gui/undocommands.cpp index c8221fe..e2502f1 100644 --- a/src/gui/undocommands.cpp +++ b/src/gui/undocommands.cpp @@ -430,3 +430,34 @@ void ReplaceGraphCommand::redo() _scene->tikzDocument()->setGraph(_newGraph); _scene->graphReplaced(); } + +ReflectNodesCommand::ReflectNodesCommand(TikzScene *scene, QSet nodes, bool horizontal, QUndoCommand *parent) : + GraphUpdateCommand(scene, parent), _nodes(nodes), _horizontal(horizontal) +{ +} + +void ReflectNodesCommand::undo() +{ + _scene->graph()->reflectNodes(_nodes, _horizontal); + foreach (NodeItem *ni, _scene->nodeItems()) { + if (_nodes.contains(ni->node())) { + ni->readPos(); + } + } + + _scene->refreshAdjacentEdges(_nodes.toList()); + GraphUpdateCommand::undo(); +} + +void ReflectNodesCommand::redo() +{ + _scene->graph()->reflectNodes(_nodes, _horizontal); + foreach (NodeItem *ni, _scene->nodeItems()) { + if (_nodes.contains(ni->node())) { + ni->readPos(); + } + } + + _scene->refreshAdjacentEdges(_nodes.toList()); + GraphUpdateCommand::redo(); +} diff --git a/src/gui/undocommands.h b/src/gui/undocommands.h index 292632e..0e7a63d 100644 --- a/src/gui/undocommands.h +++ b/src/gui/undocommands.h @@ -191,4 +191,18 @@ private: Graph *_newGraph; }; +class ReflectNodesCommand : public GraphUpdateCommand +{ +public: + explicit ReflectNodesCommand(TikzScene *scene, + QSet nodes, + bool horizontal, + QUndoCommand *parent = 0); + void undo() override; + void redo() override; +private: + QSet _nodes; + bool _horizontal; +}; + #endif // UNDOCOMMANDS_H -- cgit v1.2.3