diff options
Diffstat (limited to 'src/data')
-rw-r--r-- | src/data/edge.cpp | 11 | ||||
-rw-r--r-- | src/data/edge.h | 8 | ||||
-rw-r--r-- | src/data/graph.cpp | 117 | ||||
-rw-r--r-- | src/data/graph.h | 4 | ||||
-rw-r--r-- | src/data/graphelementdata.cpp | 26 | ||||
-rw-r--r-- | src/data/graphelementdata.h | 4 | ||||
-rw-r--r-- | src/data/path.cpp | 29 | ||||
-rw-r--r-- | src/data/path.h | 6 | ||||
-rw-r--r-- | src/data/tikzassembler.cpp | 34 | ||||
-rw-r--r-- | src/data/tikzassembler.h | 5 | ||||
-rw-r--r-- | src/data/tikzlexer.l | 1 | ||||
-rw-r--r-- | src/data/tikzparser.y | 7 |
12 files changed, 221 insertions, 31 deletions
diff --git a/src/data/edge.cpp b/src/data/edge.cpp index 0bd49e8..652b480 100644 --- a/src/data/edge.cpp +++ b/src/data/edge.cpp @@ -28,6 +28,7 @@ Edge::Edge(Node *s, Node *t, QObject *parent) : {
_data = new GraphElementData(this);
_edgeNode = nullptr;
+ _path = nullptr;
_dirty = true;
if (s != t) {
@@ -436,3 +437,13 @@ QPointF Edge::bezierTangent(qreal start, qreal end) const return QPointF(dx, dy);
}
+
+Path *Edge::path() const
+{
+ return _path;
+}
+
+void Edge::setPath(Path *path)
+{
+ _path = path;
+}
diff --git a/src/data/edge.h b/src/data/edge.h index 954145f..ad21f36 100644 --- a/src/data/edge.h +++ b/src/data/edge.h @@ -27,6 +27,8 @@ #include "node.h"
#include "style.h"
+class Path;
+
#include <QObject>
#include <QPointF>
@@ -92,12 +94,15 @@ public: void setStyleName(const QString & styleName);
Style *style() const;
+ Path *path() const;
+ void setPath(Path *path);
+
signals:
public slots:
private:
- QPointF bezierTangent(qreal start, qreal end) const;
+ QPointF bezierTangent(qreal start, qreal end) const;
QString _sourceAnchor;
QString _targetAnchor;
@@ -108,6 +113,7 @@ private: // referenced
Node *_source;
Node *_target;
+ Path *_path;
Style *_style;
diff --git a/src/data/graph.cpp b/src/data/graph.cpp index 1dd5574..354d22d 100644 --- a/src/data/graph.cpp +++ b/src/data/graph.cpp @@ -73,6 +73,17 @@ void Graph::removeEdge(Edge *e) _edges.removeOne(e);
}
+void Graph::addPath(Path *p)
+{
+ p->setParent(this);
+ _paths << p;
+}
+
+void Graph::removePath(Path *p)
+{
+ _paths.removeOne(p);
+}
+
int Graph::maxIntName()
{
int max = -1;
@@ -167,6 +178,11 @@ const QVector<Edge*> &Graph::edges() return _edges;
}
+const QVector<Path *> &Graph::paths()
+{
+ return _paths;
+}
+
QRectF Graph::bbox() const
{
return _bbox;
@@ -230,37 +246,90 @@ QString Graph::tikz() Edge *e;
+ Path *p;
foreach (e, _edges) {
e->setTikzLine(line);
e->updateData();
- code << "\t\t\\draw ";
- if (!e->data()->isEmpty())
- code << e->data()->tikz() << " ";
-
- code << "(" << e->source()->name();
- if (e->sourceAnchor() != "")
- code << "." << e->sourceAnchor();
- code << ") to ";
+ p = e->path();
+ if (p) { // if edge is part of a path
+ if (p->edges().first() == e) { // only add tikz code once per path
+ code << "\t\t\\draw ";
+
+ GraphElementData *npd = e->data()->nonPathData();
+ if (!npd->isEmpty())
+ code << npd->tikz() << " ";
+ delete npd;
+
+ code << "(" << e->source()->name();
+ if (e->sourceAnchor() != "") {
+ code << "." << e->sourceAnchor();
+ } else if (p->isCycle()) {
+ code << ".center";
+ }
+ code << ")";
+
+ foreach (Edge *e1, p->edges()) {
+ e1->updateData();
+ code << " to ";
+
+ GraphElementData *pd = e1->data()->pathData();
+ if (!pd->isEmpty())
+ code << pd->tikz() << " ";
+ delete pd;
+
+ if (e1->hasEdgeNode()) {
+ code << "node ";
+ if (!e1->edgeNode()->data()->isEmpty())
+ code << e1->edgeNode()->data()->tikz() << " ";
+ code << "{" << e1->edgeNode()->label() << "} ";
+ }
+
+ if (e->source() == e1->target()) {
+ code << "cycle";
+ } else {
+ code << "(" << e1->target()->name();
+ if (e1->targetAnchor() != "") {
+ code << "." << e1->targetAnchor();
+ } else if (e1 != p->edges().last()) {
+ code << ".center";
+ }
+ code << ")";
+ }
+ }
+ code << ";\n";
+ line++;
+ }
+ } else { // edge is not part of a path
+ code << "\t\t\\draw ";
+
+ if (!e->data()->isEmpty())
+ code << e->data()->tikz() << " ";
+
+ code << "(" << e->source()->name();
+ if (e->sourceAnchor() != "")
+ code << "." << e->sourceAnchor();
+ code << ") to ";
+
+ if (e->hasEdgeNode()) {
+ code << "node ";
+ if (!e->edgeNode()->data()->isEmpty())
+ code << e->edgeNode()->data()->tikz() << " ";
+ code << "{" << e->edgeNode()->label() << "} ";
+ }
- if (e->hasEdgeNode()) {
- code << "node ";
- if (!e->edgeNode()->data()->isEmpty())
- code << e->edgeNode()->data()->tikz() << " ";
- code << "{" << e->edgeNode()->label() << "} ";
- }
+ if (e->source() == e->target()) {
+ code << "()";
+ } else {
+ code << "(" << e->target()->name();
+ if (e->targetAnchor() != "")
+ code << "." << e->targetAnchor();
+ code << ")";
+ }
- if (e->source() == e->target()) {
- code << "()";
- } else {
- code << "(" << e->target()->name();
- if (e->targetAnchor() != "")
- code << "." << e->targetAnchor();
- code << ")";
+ code << ";\n";
+ line++;
}
-
- code << ";\n";
- line++;
}
if (!_edges.isEmpty()) {
diff --git a/src/data/graph.h b/src/data/graph.h index a996bcb..c306bb2 100644 --- a/src/data/graph.h +++ b/src/data/graph.h @@ -47,6 +47,8 @@ public: void addEdge(Edge *e);
void addEdge(Edge *e, int index);
void removeEdge(Edge *e);
+ void addPath(Path *p);
+ void removePath(Path *p);
int maxIntName();
void reorderNodes(const QVector<Node*> &newOrder);
void reorderEdges(const QVector<Edge*> &newOrder);
@@ -65,6 +67,7 @@ public: const QVector<Node *> &nodes();
const QVector<Edge*> &edges();
+ const QVector<Path*> &paths();
QRectF bbox() const;
void setBbox(const QRectF &bbox);
@@ -122,6 +125,7 @@ public slots: private:
QVector<Node*> _nodes;
QVector<Edge*> _edges;
+ QVector<Path*> _paths;
//QMultiHash<Node*,Edge*> inEdges;
//QMultiHash<Node*,Edge*> outEdges;
GraphElementData *_data;
diff --git a/src/data/graphelementdata.cpp b/src/data/graphelementdata.cpp index 931f86a..d2146d9 100644 --- a/src/data/graphelementdata.cpp +++ b/src/data/graphelementdata.cpp @@ -265,3 +265,29 @@ QVector<GraphElementProperty> GraphElementData::properties() const {
return _properties;
}
+
+GraphElementData *GraphElementData::pathData() const
+{
+ GraphElementData *d = new GraphElementData();
+ foreach(GraphElementProperty p, _properties) {
+ if (isPathProperty(p.key())) d->add(p);
+ }
+ return d;
+}
+
+GraphElementData *GraphElementData::nonPathData() const
+{
+ GraphElementData *d = new GraphElementData();
+ foreach(GraphElementProperty p, _properties) {
+ if (!isPathProperty(p.key())) d->add(p);
+ }
+ return d;
+}
+
+bool GraphElementData::isPathProperty(QString key)
+{
+ return (key == "bend left" ||
+ key == "bend right" ||
+ key == "in" ||
+ key == "out");
+}
diff --git a/src/data/graphelementdata.h b/src/data/graphelementdata.h index 8a50a93..8022a14 100644 --- a/src/data/graphelementdata.h +++ b/src/data/graphelementdata.h @@ -78,12 +78,16 @@ public: bool isEmpty();
QVector<GraphElementProperty> properties() const;
+ GraphElementData *pathData() const;
+ GraphElementData *nonPathData() const;
+
signals:
public slots:
private:
QVector<GraphElementProperty> _properties;
+ static bool isPathProperty(QString key);
};
#endif // GRAPHELEMENTDATA_H
diff --git a/src/data/path.cpp b/src/data/path.cpp index f213b22..1438d64 100644 --- a/src/data/path.cpp +++ b/src/data/path.cpp @@ -4,3 +4,32 @@ Path::Path(QObject *parent) : QObject(parent) { } + +int Path::length() const +{ + return _edges.length(); +} + +void Path::addEdge(Edge *e) +{ + e->setPath(this); + _edges << e; +} + +void Path::removeEdges() +{ + foreach(Edge *e, _edges) { + e->setPath(nullptr); + } + _edges.clear(); +} + +bool Path::isCycle() const +{ + return !_edges.isEmpty() && _edges.first()->source() == _edges.last()->target(); +} + +QVector<Edge *> Path::edges() const +{ + return _edges; +} diff --git a/src/data/path.h b/src/data/path.h index 381d486..3c83170 100644 --- a/src/data/path.h +++ b/src/data/path.h @@ -10,6 +10,12 @@ class Path : public QObject Q_OBJECT public: explicit Path(QObject *parent = nullptr); + int length() const; + void addEdge(Edge *e); + void removeEdges(); + bool isCycle() const; + + QVector<Edge *> edges() const; private: QVector<Edge*> _edges; diff --git a/src/data/tikzassembler.cpp b/src/data/tikzassembler.cpp index ee75f7b..3cb3c10 100644 --- a/src/data/tikzassembler.cpp +++ b/src/data/tikzassembler.cpp @@ -30,6 +30,7 @@ TikzAssembler::TikzAssembler(Graph *graph, QObject *parent) : yylex_init(&scanner);
yyset_extra(this, scanner);
_currentEdgeData = nullptr;
+ _currentPath = nullptr;
}
TikzAssembler::TikzAssembler(TikzStyles *tikzStyles, QObject *parent) :
@@ -38,6 +39,7 @@ TikzAssembler::TikzAssembler(TikzStyles *tikzStyles, QObject *parent) : yylex_init(&scanner);
yyset_extra(this, scanner);
_currentEdgeData = nullptr;
+ _currentPath = nullptr;
}
void TikzAssembler::addNodeToMap(Node *n) { _nodeMap.insert(n->name(), n); }
@@ -82,6 +84,15 @@ void TikzAssembler::setCurrentEdgeSource(Node *currentEdgeSource) _currentEdgeSource = currentEdgeSource;
}
+Node *TikzAssembler::currentPathSource() const
+{
+ if (_currentPath && _currentPath->length() > 0) {
+ return _currentPath->edges()[0]->source();
+ } else {
+ return nullptr;
+ }
+}
+
GraphElementData *TikzAssembler::currentEdgeData() const
{
return _currentEdgeData;
@@ -102,12 +113,31 @@ void TikzAssembler::setCurrentEdgeSourceAnchor(const QString ¤tEdgeSourceA _currentEdgeSourceAnchor = currentEdgeSourceAnchor;
}
+void TikzAssembler::addEdge(Edge *e)
+{
+ if (!_currentPath) _currentPath = new Path();
+ _currentPath->addEdge(e);
+ _graph->addEdge(e);
+}
+
void TikzAssembler::finishCurrentPath()
{
if (_currentEdgeData) {
- delete _currentEdgeData;
+ GraphElementData *d = _currentEdgeData;
_currentEdgeData = nullptr;
+ delete d;
+ }
+
+ if (_currentPath) {
+ if (_currentPath->length() < 2) {
+ _currentPath->removeEdges();
+ Path *p = _currentPath;
+ _currentPath = nullptr;
+ delete p;
+ } else {
+ _graph->addPath(_currentPath);
+ _currentPath = nullptr;
+ }
}
- // TODO: create a path and add it to graph
}
diff --git a/src/data/tikzassembler.h b/src/data/tikzassembler.h index f3cabb6..f86abcd 100644 --- a/src/data/tikzassembler.h +++ b/src/data/tikzassembler.h @@ -23,7 +23,6 @@ #ifndef TIKZASSEMBLER_H
#define TIKZASSEMBLER_H
-#include "node.h"
#include "graph.h"
#include "tikzstyles.h"
@@ -49,12 +48,15 @@ public: Node *currentEdgeSource() const;
void setCurrentEdgeSource(Node *currentEdgeSource);
+ Node *currentPathSource() const;
+
GraphElementData *currentEdgeData() const;
void setCurrentEdgeData(GraphElementData *currentEdgeData);
QString currentEdgeSourceAnchor() const;
void setCurrentEdgeSourceAnchor(const QString ¤tEdgeSourceAnchor);
+ void addEdge(Edge *e);
void finishCurrentPath();
signals:
@@ -65,6 +67,7 @@ private: QHash<QString,Node*> _nodeMap;
Graph *_graph;
TikzStyles *_tikzStyles;
+ Path *_currentPath;
Node *_currentEdgeSource;
GraphElementData *_currentEdgeData;
QString _currentEdgeSourceAnchor;
diff --git a/src/data/tikzlexer.l b/src/data/tikzlexer.l index 0d80467..615cf0d 100644 --- a/src/data/tikzlexer.l +++ b/src/data/tikzlexer.l @@ -82,6 +82,7 @@ FLOAT \-?[0-9]*(\.[0-9]+)? <INITIAL>node { return NODE; }
<INITIAL>at { return AT; }
<INITIAL>to { return TO; }
+<INITIAL>cycle { return CYCLE; }
\([ ]*{FLOAT}[ ]*,[ ]*{FLOAT}[ ]*\) {
yylloc->last_column = yylloc->first_column + 1;
diff --git a/src/data/tikzparser.y b/src/data/tikzparser.y index 895f75d..1e7b8cc 100644 --- a/src/data/tikzparser.y +++ b/src/data/tikzparser.y @@ -96,6 +96,7 @@ void yyerror(YYLTYPE *yylloc, void * /*scanner*/, const char *str) { %token NODE "node"
%token AT "at"
%token TO "to"
+%token CYCLE "cycle"
%token SEMICOLON ";"
%token COMMA ","
@@ -252,8 +253,8 @@ edgetarget: "to" optproperties optedgenode optnoderef { if ($4.loop) {
t = assembler->currentEdgeSource();
} else if ($4.cycle) {
- // TODO: should be source of first edge in path
- t = assembler->currentEdgeSource();
+ t = assembler->currentPathSource();
+ if (!t) t = s;
} else {
t = $4.node;
}
@@ -285,7 +286,7 @@ edgetarget: "to" optproperties optedgenode optnoderef { if (cd) e->setData(cd->copy());
}
e->setAttributesFromData();
- assembler->graph()->addEdge(e);
+ assembler->addEdge(e);
}
}
|