aff5997d |
1 | /**************************************************************************** |
2 | ** |
967905a3 |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
aff5997d |
5 | ** |
967905a3 |
6 | ** This file is part of the examples of the Qt Toolkit. |
aff5997d |
7 | ** |
967905a3 |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
9 | ** You may use this file under the terms of the BSD license as follows: |
aff5997d |
10 | ** |
967905a3 |
11 | ** "Redistribution and use in source and binary forms, with or without |
12 | ** modification, are permitted provided that the following conditions are |
13 | ** met: |
14 | ** * Redistributions of source code must retain the above copyright |
15 | ** notice, this list of conditions and the following disclaimer. |
16 | ** * Redistributions in binary form must reproduce the above copyright |
17 | ** notice, this list of conditions and the following disclaimer in |
18 | ** the documentation and/or other materials provided with the |
19 | ** distribution. |
20 | ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names |
21 | ** of its contributors may be used to endorse or promote products derived |
22 | ** from this software without specific prior written permission. |
aff5997d |
23 | ** |
967905a3 |
24 | ** |
25 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
26 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
27 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
28 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
29 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
30 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
31 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
32 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
33 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
34 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
35 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
36 | ** |
37 | ** $QT_END_LICENSE$ |
aff5997d |
38 | ** |
39 | ****************************************************************************/ |
40 | |
55a40de8 |
41 | #include <Standard_WarningsDisable.hxx> |
aff5997d |
42 | #include <QPainter> |
55a40de8 |
43 | #include <Standard_WarningsRestore.hxx> |
aff5997d |
44 | |
45 | #include "edge.h" |
46 | #include "node.h" |
47 | |
48 | #include <math.h> |
49 | |
50 | static const double Pi = 3.14159265358979323846264338327950288419717; |
51 | static double TwoPi = 2.0 * Pi; |
52 | |
53 | Edge::Edge(Node *sourceNode, Node *destNode) |
54 | : arrowSize(10) |
55 | { |
56 | setAcceptedMouseButtons(0); |
57 | source = sourceNode; |
58 | dest = destNode; |
59 | source->addEdge(this); |
60 | dest->addEdge(this); |
61 | adjust(); |
62 | } |
63 | |
aff5997d |
64 | Node *Edge::sourceNode() const |
65 | { |
66 | return source; |
67 | } |
68 | |
aff5997d |
69 | Node *Edge::destNode() const |
70 | { |
71 | return dest; |
72 | } |
73 | |
aff5997d |
74 | void Edge::adjust() |
75 | { |
76 | if (!source || !dest) |
77 | return; |
78 | |
79 | QLineF line(mapFromItem(source, 0, 0), mapFromItem(dest, 0, 0)); |
80 | qreal length = line.length(); |
aff5997d |
81 | |
82 | prepareGeometryChange(); |
967905a3 |
83 | |
84 | if (length > qreal(20.)) { |
85 | QPointF edgeOffset((line.dx() * 10) / length, (line.dy() * 10) / length); |
86 | sourcePoint = line.p1() + edgeOffset; |
87 | destPoint = line.p2() - edgeOffset; |
88 | } else { |
89 | sourcePoint = destPoint = line.p1(); |
90 | } |
aff5997d |
91 | } |
92 | |
93 | QRectF Edge::boundingRect() const |
94 | { |
95 | if (!source || !dest) |
96 | return QRectF(); |
97 | |
98 | qreal penWidth = 1; |
99 | qreal extra = (penWidth + arrowSize) / 2.0; |
100 | |
101 | return QRectF(sourcePoint, QSizeF(destPoint.x() - sourcePoint.x(), |
102 | destPoint.y() - sourcePoint.y())) |
103 | .normalized() |
104 | .adjusted(-extra, -extra, extra, extra); |
105 | } |
106 | |
107 | void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) |
108 | { |
109 | if (!source || !dest) |
110 | return; |
111 | |
967905a3 |
112 | QLineF line(sourcePoint, destPoint); |
113 | if (qFuzzyCompare(line.length(), qreal(0.))) |
114 | return; |
aff5997d |
115 | |
116 | // Draw the line itself |
aff5997d |
117 | painter->setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); |
118 | painter->drawLine(line); |
119 | |
967905a3 |
120 | // Draw the arrows |
aff5997d |
121 | double angle = ::acos(line.dx() / line.length()); |
122 | if (line.dy() >= 0) |
123 | angle = TwoPi - angle; |
124 | |
967905a3 |
125 | QPointF sourceArrowP1 = sourcePoint + QPointF(sin(angle + Pi / 3) * arrowSize, |
126 | cos(angle + Pi / 3) * arrowSize); |
127 | QPointF sourceArrowP2 = sourcePoint + QPointF(sin(angle + Pi - Pi / 3) * arrowSize, |
128 | cos(angle + Pi - Pi / 3) * arrowSize); |
aff5997d |
129 | QPointF destArrowP1 = destPoint + QPointF(sin(angle - Pi / 3) * arrowSize, |
130 | cos(angle - Pi / 3) * arrowSize); |
131 | QPointF destArrowP2 = destPoint + QPointF(sin(angle - Pi + Pi / 3) * arrowSize, |
132 | cos(angle - Pi + Pi / 3) * arrowSize); |
133 | |
134 | painter->setBrush(Qt::black); |
967905a3 |
135 | painter->drawPolygon(QPolygonF() << line.p1() << sourceArrowP1 << sourceArrowP2); |
136 | painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); |
aff5997d |
137 | } |