Tidy up multiconnection drawing
MODIFY
src/graphics/connection.cpp
src/graphics/connection.cpp
#include "connection.h"
#include "shape.h"
+#include <QDebug>
#include <QFontMetrics>
#include <QPainter>
namespace Graphics {
static constexpr float Pi = 3.1415926535;
+namespace {
+inline double pointDistance(QPointF a, QPointF b) {
+ return sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2));
+}
+}
+
Connection::Connection(Shape* source, QPointF* sourcePoint, Shape* dest, QPointF* destPoint)
: QObject(), m_source(source), m_sourcePointPtr(sourcePoint) {
m_dests << QPair<Shape*, QPointF*>(dest, destPoint);
@@ -14,37 +21,42 @@ Connection::Connection(Shape* source, QPointF* sourcePoint, Shape* dest, QPointF
m_label.m_drawPos = sourcePoint;
}
-Connection::Connection(Shape* source, QPointF* sourcePoint, QList<QPair<Shape*, QPointF*>> dests) : QObject(), m_source(source),m_sourcePointPtr(sourcePoint){
+Connection::Connection(Shape* source, QPointF* sourcePoint, QList<PointPair> dests)
+ : QObject(), m_source(source), m_sourcePointPtr(sourcePoint) {
m_dests = dests;
m_label.m_source = source;
m_label.m_drawPos = sourcePoint;
}
QRectF Connection::boundingRect() const {
- qreal penWidth = 1;
- qreal extra = (penWidth + m_arrowSize) / 2.0;
- QPointF sourcePoint = mapFromItem(m_source, *m_sourcePointPtr);
- QPointF destPoint = mapFromItem(m_dests[0].first, *m_dests[0].second);
-
- if ((destPoint.x() - sourcePoint.x()) > 0) {
- return QRectF(sourcePoint, QSizeF(destPoint.x() - sourcePoint.x(), destPoint.y() - sourcePoint.y()))
- .normalized()
- .adjusted(-extra, -extra, extra, extra);
- } else if (m_kinkBiases.size() > 0) {
- return QRectF(QPointF(destPoint.x() - m_destStubLen, sourcePoint.y() + m_feedbackDir * m_kinkBiases[0]),
- QPointF(sourcePoint.x() + m_sourceStubLen, destPoint.y()))
- .normalized()
- .adjusted(-extra, -extra, extra, extra);
+ double left, top, bot, right;
+ // Iterate through all points in the connection line to find bounding rect
+ for (const auto& pointVec : m_polyLines) {
+ for (const auto& point : pointVec) {
+ left = point.x() < left ? point.x() : left;
+ right = point.x() > right ? point.x() : right;
+ top = point.y() < top ? point.y() : top;
+ bot = point.y() > bot ? point.y() : bot;
}
- return QRectF();
+ }
+ return QRectF(left, top, right - left, bot - top);
}
QPair<QPointF, QPointF> Connection::getPoints() const {
- return QPair<QPointF, QPointF>(mapFromItem(m_source, *m_sourcePointPtr), mapFromItem(m_dests[0].first, *m_dests[0].second));
+ return QPair<QPointF, QPointF>(mapFromItem(m_source, *m_sourcePointPtr),
+ mapFromItem(m_dests[0].first, *m_dests[0].second));
}
-void Connection::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
+void Connection::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) {
QPointF sourcePoint = mapFromItem(m_source, *m_sourcePointPtr);
+
+ // sort destinations
+ if (m_dests.size() > 1) {
+ std::sort(m_dests.begin(), m_dests.end(), [=](const PointPair& a, const PointPair& b) {
+ return pointDistance(sourcePoint, mapFromItem(a.first, *a.second)) <
+ pointDistance(sourcePoint, mapFromItem(b.first, *b.second));
+ });
+ }
QPointF destPoint = mapFromItem(m_dests[0].first, *m_dests[0].second);
// Number of kinks depends on the directon of the line. If its left to right,
@@ -52,45 +64,77 @@ void Connection::paint(QPainter* painter, const QStyleOptionGraphicsItem* option
bool dir = (destPoint.x() - sourcePoint.x()) > 0 ? true : false;
// Generate polygon from calculated points
- QVector<QPointF> polyLine;
- polyLine << sourcePoint;
+ m_polyLines.clear();
if (dir) {
// Feed forward connection
- int bias = m_kinkBiases.size() > 0 ? m_kinkBiases[0] : 0;
- int xDiff = destPoint.x() - sourcePoint.x();
- QPointF point(sourcePoint.x() + xDiff / 2 + bias, sourcePoint.y());
- QPointF point2(point.x(), destPoint.y());
+ QList<QPointF> sourcePoints = QList<QPointF>() << sourcePoint;
+ for (int i = 0; i < m_dests.length(); i++) {
+ QVector<QPointF> polyLine;
+ QPointF dest = mapFromItem(m_dests[i].first, *m_dests[i].second);
+
+ // Get bias for the given connection
+ int bias = m_kinkBiases.size() > i ? m_kinkBiases[i] : 0;
+
+ // Find closest available source point
+ QPointF source = sourcePoint;
+ for (const auto& p : sourcePoints) {
+ source = pointDistance(dest, p) < pointDistance(dest, source) ? p : source;
+ }
+ polyLine << source;
+
+ int xDiff = dest.x() - source.x();
+ if (i == 0) {
+ // do kink for first line
+ QPointF point(source.x() + xDiff / 2 + bias, source.y());
+ QPointF point2(point.x(), dest.y());
+ sourcePoints << point << point2;
polyLine << point << point2;
+ } else {
+ QPointF point(source.x(), dest.y());
+ sourcePoints << point;
+ polyLine << point;
+ }
+ polyLine << dest;
+ m_polyLines.append(polyLine);
+ }
} else {
// Feedback connection
// 1. traverse to the right of the input
if (m_kinkBiases.size() >= 1) {
+ QVector<QPointF> polyLine;
QPointF point(sourcePoint.x() + m_sourceStubLen, sourcePoint.y());
QPointF point2(point.x(), point.y() + m_feedbackDir * m_kinkBiases[0]);
QPointF point3(destPoint.x() - m_destStubLen, point2.y());
QPointF point4(point3.x(), destPoint.y());
- polyLine << point << point2 << point3 << point4;
+ polyLine << sourcePoint << point << point2 << point3 << point4;
+ polyLine << destPoint;
+ m_polyLines.append(polyLine);
}
}
- polyLine << destPoint;
- // Draw connection polyline
painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
- painter->drawPolyline(QPolygonF(polyLine));
- // Draw destination arrow
+ for (const auto& line : m_polyLines) {
+ // Draw connection polyline
+
+ painter->drawPolyline(QPolygonF(line));
+ // Draw destination arrows
qreal angle = 0;
- QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * m_arrowSize, cos(angle - Pi / 3) * m_arrowSize);
+ QPointF destArrowP1 =
+ *(line.end() - 1) + QPointF(sin(angle - Pi / 3) * m_arrowSize, cos(angle - Pi / 3) * m_arrowSize);
QPointF destArrowP2 =
- destPoint + QPointF(sin(angle - Pi + Pi / 3) * m_arrowSize, cos(angle - Pi + Pi / 3) * m_arrowSize);
+ *(line.end() - 1) + QPointF(sin(angle - Pi + Pi / 3) * m_arrowSize, cos(angle - Pi + Pi / 3) * m_arrowSize);
painter->setBrush(Qt::black);
- painter->drawPolygon(QPolygonF() << destPoint << destArrowP1 << destArrowP2);
+ painter->drawPolygon(QPolygonF() << *(line.end() - 1) << destArrowP1 << destArrowP2);
+ }
// Draw kink points
painter->setPen(QPen(Qt::black, 6, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
+ /*
for (const auto& point : m_kinkPoints) {
painter->drawPoint(polyLine[point + 1]);
}
+ */
}
void Connection::setValue(uint32_t value) {

MODIFY
src/graphics/connection.h
src/graphics/connection.h
#include <QGraphicsItem>
#include <QObject>
+#include <algorithm>
+
#include "pipelinewidget.h"
namespace Graphics {
class Shape;
+typedef QPair<Shape*,QPointF*> PointPair;
+
enum class ValueDrawPos { Source, Middle, Destination };
// Class for drawing labels for connections. Disattached from connection, such that tooltips for connections are only
@@ -39,7 +43,7 @@ class Connection : public QObject, public QGraphicsItem {
Q_OBJECT
public:
Connection(Shape* source, QPointF* sourcePoint, Shape* dest, QPointF* destPoint);
- Connection(Shape* source, QPointF* sourcePoint, QList<QPair<Shape*, QPointF*>> dests);
+ Connection(Shape* source, QPointF* sourcePoint, QList<PointPair> dests);
void setValueDrawPos(ValueDrawPos pos) { m_valuePos = pos, update(); }
void setValue(uint32_t value);
@@ -83,10 +87,10 @@ private:
ValueDrawPos m_valuePos = ValueDrawPos::Source;
int m_arrowSize = 10;
-
+ QList<QVector<QPointF>> m_polyLines;
Shape* m_source;
QPointF* m_sourcePointPtr;
- QList<QPair<Shape*,QPointF*>> m_dests;
+ QList<PointPair> m_dests;
Label m_label;
};

MODIFY
src/graphics/pipelinewidget.cpp
src/graphics/pipelinewidget.cpp
@@ -151,13 +151,11 @@ PipelineWidget::PipelineWidget(QWidget* parent) : QGraphicsView(parent) {
Graphics::Connection* connPtr;
// IF
createConnection(mux1, 0, pc, 0);
- createConnection(pc, 0, instr_mem, 0);
- createConnection(pc, 0, alu1, 0);
+ createConnection(pc, 0, QList<ShapePair>() << ShapePair(instr_mem, 0) << ShapePair(ifid, 0) << ShapePair(alu1, 0));
connPtr = createConnection(alu1, 0, mux1, 0);
- connPtr->setFeedbackSettings(false, minConnectionLen - 20, minConnectionLen - 20);
+ connPtr->setFeedbackSettings(false, minConnectionLen, minConnectionLen - 10);
connPtr->setKinkBias(100);
createConnection(instr_mem, 0, ifid, 1);
- createConnection(pc, 0, ifid, 0);
// ID
createConnection(ifid, 0,
QList<ShapePair>() << ShapePair(registers, 0) << ShapePair(registers, 1) << ShapePair(registers, 2)
@@ -184,15 +182,15 @@ PipelineWidget::PipelineWidget(QWidget* parent) : QGraphicsView(parent) {
connPtr->setFeedbackSettings(false, minConnectionLen - 20, minConnectionLen);
connPtr->setKinkBias(70);
- createConnection(exmem, 1, data_mem, 0);
- createConnection(exmem, 2, data_mem, 1);
+ createConnection(exmem, 1, QList<ShapePair>() << ShapePair(data_mem, 0) << ShapePair(memwb, 1));
+ connPtr = createConnection(exmem, 2, data_mem, 1);
+ connPtr->setKinkBias(-20);
createConnection(data_mem, 0, memwb, 0);
- createConnection(exmem, 1, memwb, 1);
// WB
createConnection(memwb, 0, mux3, 0);
createConnection(memwb, 1, mux3, 1);
connPtr = createConnection(mux3, 0, registers, 3);
- connPtr->setFeedbackSettings(true, minConnectionLen - 20, minConnectionLen - 20);
+ connPtr->setFeedbackSettings(true, minConnectionLen - 20, minConnectionLen - 10);
connPtr->setKinkBias(430);
// ------- ITEM POSITIONING ------

MODIFY
src/graphics/pipelinewidget.h
src/graphics/pipelinewidget.h
@@ -18,7 +18,7 @@ public:
PipelineWidget(QWidget* parent = nullptr);
void wheelEvent(QWheelEvent* event);
- void expandToView() { fitInView(scene()->sceneRect().adjusted(-10, 0, 10, 0), Qt::KeepAspectRatio); }
+ void expandToView() { fitInView(scene()->sceneRect().adjusted(-30, 0, 10, 0), Qt::KeepAspectRatio); }
void displayAllValues(bool state);
signals:

Tidy up multiconnection drawing