From cb322a3acee9debf40c48ad1e3fb4458b0f51b7f Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Tue, 28 Feb 2017 14:46:39 +0100 Subject: generic nodes --- tikzit/src/data/edge.cpp | 211 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) (limited to 'tikzit/src/data/edge.cpp') diff --git a/tikzit/src/data/edge.cpp b/tikzit/src/data/edge.cpp index 9068a1c..b999f8a 100644 --- a/tikzit/src/data/edge.cpp +++ b/tikzit/src/data/edge.cpp @@ -1,12 +1,22 @@ #include "edge.h" +#include "tikzit.h" #include +#include +#include Edge::Edge(Node *s, Node *t, QObject *parent) : QObject(parent), _source(s), _target(t) { _data = new GraphElementData(); _edgeNode = 0; + _dirty = true; + _basicBendMode = true; + _bend = 0; + _inAngle = 0; + _outAngle = 0; + _weight = 0.4f; + updateControls(); } Edge::~Edge() @@ -25,6 +35,16 @@ Node *Edge::target() const return _target; } +bool Edge::isSelfLoop() +{ + return (_source == _target); +} + +bool Edge::isStraight() +{ + return (_basicBendMode && _bend == 0); +} + GraphElementData *Edge::data() const { return _data; @@ -34,6 +54,7 @@ void Edge::setData(GraphElementData *data) { delete _data; _data = data; + setAttributesFromData(); } QString Edge::sourceAnchor() const @@ -72,4 +93,194 @@ bool Edge::hasEdgeNode() return _edgeNode != 0; } +void Edge::updateControls() { + //if (_dirty) { + QPointF src = _source->point(); + QPointF targ = _target->point(); + + float dx = (targ.x() - src.x()); + float dy = (targ.y() - src.y()); + + float outAngleR = 0.0f; + float inAngleR = 0.0f; + + if (_basicBendMode) { + float angle = std::atan2(dy, dx); + float bnd = (float)_bend * (M_PI / 180.0f); + outAngleR = angle - bnd; + inAngleR = M_PI + angle + bnd; + _outAngle = outAngleR * (180.f / M_PI); + _inAngle = inAngleR * (180.f / M_PI); + } else { + outAngleR = (float)_outAngle * (M_PI / 180.0f); + inAngleR = (float)_inAngle * (M_PI / 180.0f); + } + + // TODO: calculate head and tail properly, not just for circles + if (_source->style().isNone()) { + _tail = src; + } else { + _tail = QPointF(src.x() + std::cos(outAngleR) * 0.1, + src.y() + std::sin(outAngleR) * 0.1); + } + + if (_target->style().isNone()) { + _head = targ; + } else { + _head = QPointF(targ.x() + std::cos(inAngleR) * 0.1, + targ.y() + std::sin(inAngleR) * 0.1); + } + + // give a default distance for self-loops + _cpDist = (dx==0.0f && dy==0.0f) ? _weight : std::sqrt(dx*dx + dy*dy) * _weight; + + _cp1 = QPointF(src.x() + (_cpDist * std::cos(outAngleR)), + src.y() + (_cpDist * std::sin(outAngleR))); + + _cp2 = QPointF(targ.x() + (_cpDist * std::cos(inAngleR)), + targ.y() + (_cpDist * std::sin(inAngleR))); + + _mid = bezierInterpolateFull (0.5f, _tail, _cp1, _cp2, _head); +// midTan = [self _findTanFor:mid usingSpanFrom:0.4f to:0.6f]; + +// tailTan = [self _findTanFor:tail usingSpanFrom:0.0f to:0.1f]; +// headTan = [self _findTanFor:head usingSpanFrom:1.0f to:0.9f]; + //_dirty = false; + //} +} + +void Edge::setAttributesFromData() +{ + _basicBendMode = true; + bool ok = true; + + if (_data->atom("bend left")) { + _bend = -30; + } else if (_data->atom("bend right")) { + _bend = 30; + } else if (_data->property("bend left") != 0) { + _bend = -_data->property("bend left").toInt(&ok); + if (!ok) _bend = -30; + } else if (_data->property("bend right") != 0) { + _bend = _data->property("bend right").toInt(&ok); + if (!ok) _bend = 30; + } else { + _bend = 0; + + if (_data->property("in") != 0 && _data->property("out") != 0) { + _basicBendMode = false; + _inAngle = _data->property("in").toInt(&ok); + if (!ok) _inAngle = 0; + _outAngle = _data->property("out").toInt(&ok); + if (!ok) _outAngle = 180; + } + } + + if (_data->property("looseness") != 0) { + _weight = _data->property("looseness").toFloat(&ok) / 2.5f; + if (!ok) _weight = 0.4f; + } else { + _weight = (isSelfLoop()) ? 1.0f : 0.4f; + } + + //qDebug() << "bend: " << _bend << " in: " << _inAngle << " out: " << _outAngle; + _dirty = true; +} + +void Edge::updateData() +{ + _data->unsetAtom("loop"); + _data->unsetProperty("in"); + _data->unsetProperty("out"); + _data->unsetAtom("bend left"); + _data->unsetAtom("bend right"); + _data->unsetProperty("bend left"); + _data->unsetProperty("bend right"); + _data->unsetProperty("looseness"); + + // TODO: style handling? + + if (_basicBendMode && _bend != 0) { + QString bendKey; + int b; + if (_bend < 0) { + bendKey = "bend left"; + b = -_bend; + } else { + bendKey = "bend right"; + b = _bend; + } + + if (b == 30) { + _data->setAtom(bendKey); + } else { + _data->setProperty(bendKey, QString::number(b)); + } + } else { + _data->setProperty("in", QString::number(_inAngle)); + _data->setProperty("out", QString::number(_outAngle)); + } + + if (_source == _target) _data->setAtom("loop"); + if (!isSelfLoop() && !isStraight() && _weight != 0.4f) + _data->setProperty("looseness", QString::number(_weight*2.5f, 'f', 2)); + +} + + +QPointF Edge::head() const +{ + return _head; +} + +QPointF Edge::tail() const +{ + return _tail; +} + +QPointF Edge::cp1() const +{ + return _cp1; +} + +QPointF Edge::cp2() const +{ + return _cp2; +} + +int Edge::bend() const +{ + return _bend; +} + +int Edge::inAngle() const +{ + return _inAngle; +} + +int Edge::outAngle() const +{ + return _outAngle; +} + +float Edge::weight() const +{ + return _weight; +} + +bool Edge::basicBendMode() const +{ + return _basicBendMode; +} + +float Edge::cpDist() const +{ + return _cpDist; +} + +QPointF Edge::mid() const +{ + return _mid; +} + -- cgit v1.2.3