]> Shamusworld >> Repos - architektonas/blob - src/painter.cpp
Added new toolbar icons, added arrowhead rendering to Painter class.
[architektonas] / src / painter.cpp
1 //
2 // painter.cpp: Paint abstraction layer between Archtektonas and Qt
3 //
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // WHO  WHEN        WHAT
11 // ---  ----------  ------------------------------------------------------------
12 // JLH  09/20/2011  Created this file
13 //
14
15 #include "painter.h"
16
17 #include "mathconstants.h"
18
19
20 // Set class variable defaults
21 Vector Painter::origin(-10.0, -10.0);
22 double Painter::zoom = 1.0;
23 Vector Painter::screenSize(200.0, 200.0);
24
25
26 Painter::Painter(QPainter * p/*= NULL*/): painter(p)
27 {
28 }
29
30 Painter::~Painter()
31 {
32 }
33
34 Vector Painter::CartesianToQtCoords(Vector v)
35 {
36         // Convert regular Cartesian coordinates to the inverted Y-axis Qt coordinates
37         // at the current origin and zoom level.
38         return Vector((v.x - origin.x) * zoom, screenSize.y - ((v.y - origin.y) * zoom));
39 }
40
41 Vector Painter::QtToCartesianCoords(Vector v)
42 {
43         // Convert screen location, with inverted Y-axis coordinates, to regular
44         // Cartesian coordinates at the current zoom level.
45         return Vector((v.x / zoom) + origin.x, ((screenSize.y - v.y) / zoom) + origin.y);
46 /*
47 How to do it:
48
49 e.g., we have a point on the screen at Qt coords of 10, 10, screenSize is 100, 100.
50 origin is -10, -10 and zoom level is 2 (200%)
51
52 1st, invert the Y: 10, 10 -> 10, 90
53 2nd, add origin:   10, 90 ->  0, 80 (no, not right--err, yes, it is)
54 3rd, aply zoom:     0, 80 ->  0, 40
55
56 or, is it:
57
58 1st, invert the Y: 10, 10 -> 10, 90
59 2nd, aply zoom:    10, 90 ->  5, 45
60 3rd, add origin:    5, 45 -> -5, 35
61
62 it depends on whether or not origin is in Qt coords or cartesian. If Qt, then the 1st
63 is correct, otherwise, the 2nd is correct.
64
65 The way we calculate the Cartesian to Qt shows the 2nd (origin is cartesian) to be correct.
66 */
67 }
68
69 void Painter::SetRenderHint(int hint)
70 {
71         if (!painter)
72                 return;
73
74         painter->setRenderHint((QPainter::RenderHint)hint);
75 }
76
77 void Painter::SetBrush(QBrush brush)
78 {
79         if (!painter)
80                 return;
81
82         painter->setBrush(brush);
83 }
84
85 void Painter::SetFont(QFont font)
86 {
87         if (!painter)
88                 return;
89
90         painter->setFont(font);
91 }
92
93 void Painter::SetPen(QPen pen)
94 {
95         if (!painter)
96                 return;
97
98         painter->setPen(pen);
99 }
100
101 void Painter::DrawAngledText(Vector center, double angle, QString text)
102 {
103         if (!painter)
104                 return;
105
106         // Strategy: Since Qt doesn't have any rotated text drawing functions,
107         // we instead translate the origin to the center of the text to be drawn and
108         // then rotate the frame to the desired angle.
109         center = CartesianToQtCoords(center);
110
111         // We may need this stuff... If dimension text is large enough.
112 //      int textWidth = QFontMetrics(painter->font()).width(text);
113 //      int textHeight = QFontMetrics(painter->font()).height();
114         QRectF textBox(-100 * zoom, -100 * zoom, 200 * zoom, 200 * zoom);       // x, y, w, h; x/y = upper left corner
115
116         // This is in pixels. Might not render correctly at all zoom levels.
117         // Need to figure out if dimensions are always rendered at one size regardless of zoom,
118         // or if they have a definite size, and are thus zoomable.
119         // If zoomable, this is incorrect:
120         // (Added zoom, so this is correct now :-)
121         int yOffset = -12 * zoom;
122
123         // Fix text so it isn't upside down...
124         if ((angle > PI * 0.5) && (angle < PI * 1.5))
125         {
126                 angle += PI;
127                 yOffset = 12 * zoom;
128         }
129
130 #if 0
131         Vector offset = CartesianToQtCoords(Vector(0, yOffset));
132         textBox.translate(offset.x, offset.y);
133 #else
134         textBox.translate(0, yOffset);
135 #endif
136         painter->save();
137         painter->translate(center.x, center.y);
138         // Angles are backwards in the Qt coord system, so we flip ours...
139         painter->rotate(-angle * RADIANS_TO_DEGREES);
140 //Need to fix this so the text scales as well...
141         painter->drawText(textBox, Qt::AlignCenter, text);
142         painter->restore();
143 }
144
145 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
146 {
147         center = CartesianToQtCoords(center);
148         // Need to multiply scalar quantities by the zoom factor as well...
149         radius *= zoom;
150         QRectF rectangle(QPointF(center.x - radius, center.y - radius),
151                 QPointF(center.x + radius, center.y + radius));
152         int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
153         int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0);
154         painter->drawArc(rectangle, angle1, angle2);
155 }
156
157 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
158 {
159         // Need to multiply scalar quantities by the zoom factor as well...
160         center = CartesianToQtCoords(center);
161         painter->drawEllipse(QPointF(center.x, center.y), axis1 * zoom, axis2 * zoom);
162 }
163
164 // This function is for drawing object handles without regard for zoom level;
165 // we don't want our object handle size to depend on the zoom level!
166 void Painter::DrawHandle(Vector center)
167 {
168         center = CartesianToQtCoords(center);
169         painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
170 }
171
172 void Painter::DrawLine(int x1, int y1, int x2, int y2)
173 {
174         if (!painter)
175                 return;
176
177         Vector v1 = CartesianToQtCoords(Vector(x1, y1));
178         Vector v2 = CartesianToQtCoords(Vector(x2, y2));
179         painter->drawLine(v1.x, v1.y, v2.x, v2.y);
180 }
181
182 void Painter::DrawLine(Vector v1, Vector v2)
183 {
184         if (!painter)
185                 return;
186
187         v1 = CartesianToQtCoords(v1);
188         v2 = CartesianToQtCoords(v2);
189         painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
190 }
191
192 void Painter::DrawPoint(int x, int y)
193 {
194         if (!painter)
195                 return;
196
197         Vector v = CartesianToQtCoords(Vector(x, y));
198         painter->drawPoint(v.x, v.y);
199 }
200
201 void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY)
202 {
203         if (!painter)
204                 return;
205
206         painter->drawRoundedRect(rect, radiusX, radiusY);
207 }
208
209 void Painter::DrawText(QRectF rect, int type, QString text)
210 {
211         if (!painter)
212                 return;
213
214         painter->drawText(rect, (Qt::AlignmentFlag)type, text);
215 }
216
217 void Painter::DrawArrowhead(Vector head, Vector tail)
218 {
219         QPolygonF arrow;
220
221         // We draw the arrowhead aligned along the line from tail to head
222         double angle = Vector(head - tail).Angle();
223         double orthoAngle = angle + (PI / 2.0);
224         Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
225         Vector unit = Vector(head - tail).Unit();
226
227         Point p1 = head - (unit * 9.0);
228         Point p2 = p1 + (orthogonal * 3.0);
229         Point p3 = p1 - (orthogonal * 3.0);
230
231         Point p4 = CartesianToQtCoords(head);
232         Point p5 = CartesianToQtCoords(p2);
233         Point p6 = CartesianToQtCoords(p3);
234
235         arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y);
236
237         painter->drawPolygon(arrow);
238 }
239