2 // painter.cpp: Paint abstraction layer between Archtektonas and Qt
4 // Part of the Architektonas Project
5 // (C) 2011 Underground Software
6 // See the README and GPLv3 files for licensing and warranty information
8 // JLH = James Hammons <jlhamm@acm.org>
11 // --- ---------- ------------------------------------------------------------
12 // JLH 09/20/2011 Created this file
17 #include "mathconstants.h"
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);
26 Painter::Painter(QPainter * p/*= NULL*/): painter(p)
36 Vector Painter::CartesianToQtCoords(Vector v)
38 // Convert regular Cartesian coordinates to the inverted Y-axis Qt coordinates
39 // at the current origin and zoom level.
40 return Vector((v.x - Global::origin.x) * Global::zoom, Global::screenSize.y - ((v.y - Global::origin.y) * Global::zoom));
44 Vector Painter::QtToCartesianCoords(Vector v)
46 // Convert screen location, with inverted Y-axis coordinates, to regular
47 // Cartesian coordinates at the current zoom level.
48 return Vector((v.x / Global::zoom) + Global::origin.x, ((Global::screenSize.y - v.y) / Global::zoom) + Global::origin.y);
52 e.g., we have a point on the screen at Qt coords of 10, 10, screenSize is 100, 100.
53 origin is -10, -10 and zoom level is 2 (200%)
55 1st, invert the Y: 10, 10 -> 10, 90
56 2nd, add origin: 10, 90 -> 0, 80 (no, not right--err, yes, it is)
57 3rd, aply zoom: 0, 80 -> 0, 40
61 1st, invert the Y: 10, 10 -> 10, 90
62 2nd, aply zoom: 10, 90 -> 5, 45
63 3rd, add origin: 5, 45 -> -5, 35
65 it depends on whether or not origin is in Qt coords or cartesian. If Qt, then the 1st
66 is correct, otherwise, the 2nd is correct.
68 The way we calculate the Cartesian to Qt shows the 2nd (origin is cartesian) to be correct.
73 void Painter::SetRenderHint(int hint)
78 painter->setRenderHint((QPainter::RenderHint)hint);
82 void Painter::SetBrush(QBrush brush)
87 painter->setBrush(brush);
91 void Painter::SetFont(QFont font)
96 painter->setFont(font);
100 void Painter::SetPen(QPen pen)
105 painter->setPen(pen);
109 void Painter::DrawAngledText(Vector center, double angle, QString text, double size)
114 // Strategy: Since Qt doesn't have any rotated text drawing functions,
115 // we instead translate the origin to the center of the text to be drawn and
116 // then rotate the frame to the desired angle.
117 center = CartesianToQtCoords(center);
119 // We may need this stuff... If dimension text is large enough.
120 // int textWidth = QFontMetrics(painter->font()).width(text);
121 // int textHeight = QFontMetrics(painter->font()).height();
122 QRectF textBox(-100.0 * Global::zoom * size, -100.0 * Global::zoom * size, 200.0 * Global::zoom * size, 200.0 * Global::zoom * size); // x, y, w, h; x/y = upper left corner
124 // This is in pixels. Might not render correctly at all zoom levels.
125 // Need to figure out if dimensions are always rendered at one size
126 // regardless of zoom, or if they have a definite size, and are thus
128 float yOffset = -12.0 * Global::zoom * size;
130 // Fix text so it isn't upside down...
131 if ((angle > PI * 0.5) && (angle < PI * 1.5))
134 yOffset = 12.0 * Global::zoom * size;
137 textBox.translate(0, yOffset);
139 painter->translate(center.x, center.y);
140 // Angles are backwards in the Qt coord system, so we flip ours...
141 painter->rotate(-angle * RADIANS_TO_DEGREES);
142 //Need to fix this so the text scales as well...
143 painter->drawText(textBox, Qt::AlignCenter, text);
148 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
150 center = CartesianToQtCoords(center);
151 // Need to multiply scalar quantities by the zoom factor as well...
152 radius *= Global::zoom;
153 QRectF rectangle(QPointF(center.x - radius, center.y - radius),
154 QPointF(center.x + radius, center.y + radius));
155 int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
156 int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0);
157 painter->drawArc(rectangle, angle1, angle2);
161 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
163 // Need to multiply scalar quantities by the zoom factor as well...
164 center = CartesianToQtCoords(center);
165 painter->drawEllipse(QPointF(center.x, center.y), axis1 * Global::zoom, axis2 * Global::zoom);
169 // This function is for drawing object handles without regard for zoom level;
170 // we don't want our object handle size to depend on the zoom level!
171 void Painter::DrawHandle(Vector center)
173 center = CartesianToQtCoords(center);
174 painter->setBrush(Qt::NoBrush);
175 painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
179 // This function is for drawing object handles without regard for zoom level;
180 // we don't want our object handle size to depend on the zoom level!
181 void Painter::DrawArrowHandle(Vector center, double angle)
183 center = CartesianToQtCoords(center);
186 // Since we're drawing directly on the screen, the Y is inverted. So we use
187 // the mirror of the angle.
188 double orthoAngle = -angle + (PI / 2.0);
189 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
190 Vector unit = Vector(cos(-angle), sin(-angle));
192 Point p0 = center + (unit * 6.0);
193 Point p1 = center + (unit * 21.0);
194 Point p1b = center + (unit * 11.0);
195 Point p2 = p1b + (orthogonal * 5.0);
196 Point p3 = p1b - (orthogonal * 5.0);
198 painter->drawLine(p0.x, p0.y, p1.x, p1.y);
199 arrow << QPointF(p1.x, p1.y) << QPointF(p2.x, p2.y) << QPointF(p3.x, p3.y);
201 painter->drawPolygon(arrow);
205 // This function is for drawing object handles without regard for zoom level;
206 // we don't want our object handle size to depend on the zoom level!
207 void Painter::DrawArrowToLineHandle(Vector center, double angle)
209 DrawArrowHandle(center, angle);
210 center = CartesianToQtCoords(center);
212 // Since we're drawing directly on the screen, the Y is inverted. So we use
213 // the mirror of the angle.
214 double orthoAngle = -angle + (PI / 2.0);
215 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
216 Vector unit = Vector(cos(-angle), sin(-angle));
218 Point p1 = center + (unit * 21.0);
219 Point p2 = p1 + (orthogonal * 7.0);
220 Point p3 = p1 - (orthogonal * 7.0);
222 painter->drawLine(p2.x, p2.y, p3.x, p3.y);
226 void Painter::DrawLine(int x1, int y1, int x2, int y2)
231 Vector v1 = CartesianToQtCoords(Vector(x1, y1));
232 Vector v2 = CartesianToQtCoords(Vector(x2, y2));
233 painter->drawLine(v1.x, v1.y, v2.x, v2.y);
237 void Painter::DrawLine(Vector v1, Vector v2)
242 v1 = CartesianToQtCoords(v1);
243 v2 = CartesianToQtCoords(v2);
244 painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
248 void Painter::DrawPoint(int x, int y)
253 Vector v = CartesianToQtCoords(Vector(x, y));
254 painter->drawPoint(v.x, v.y);
258 // The rect passed in is in Qt coordinates...
259 void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY)
264 painter->drawRoundedRect(rect, radiusX, radiusY);
268 // The rect passed in is in Cartesian but we want to pad it by a set number of
269 // pixels (currently set at 8), so the pad looks the same regardless of zoom.
270 void Painter::DrawPaddedRect(QRectF rect)
275 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
276 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
277 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
278 screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom
279 painter->drawRect(screenRect);
283 void Painter::DrawRect(QRectF rect)
288 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
289 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
290 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
291 painter->drawRect(screenRect);
295 void Painter::DrawText(QRectF rect, int type, QString text)
300 painter->drawText(rect, (Qt::AlignmentFlag)type, text);
304 void Painter::DrawArrowhead(Vector head, Vector tail, double size)
311 // We draw the arrowhead aligned along the line from tail to head
312 double angle = Vector(head - tail).Angle();
313 double orthoAngle = angle + (PI / 2.0);
314 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
315 Vector unit = Vector(head - tail).Unit();
317 Point p1 = head - (unit * 9.0 * size);
318 Point p2 = p1 + (orthogonal * 3.0 * size);
319 Point p3 = p1 - (orthogonal * 3.0 * size);
321 Point p4 = CartesianToQtCoords(head);
322 Point p5 = CartesianToQtCoords(p2);
323 Point p6 = CartesianToQtCoords(p3);
325 arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y);
327 painter->drawPolygon(arrow);
331 // Point is given in Cartesian coordinates
332 void Painter::DrawCrosshair(Vector point)
337 Vector screenPoint = CartesianToQtCoords(point);
338 painter->drawLine(0, screenPoint.y, Global::screenSize.x, screenPoint.y);
339 painter->drawLine(screenPoint.x, 0, screenPoint.x, Global::screenSize.y);
343 void Painter::DrawInformativeText(QString text)
345 painter->setFont(*Global::font);
346 QRectF bounds = painter->boundingRect(QRectF(), Qt::AlignVCenter, text);
347 bounds.moveTo(17.0, 17.0);
348 QRectF textRect = bounds;
349 textRect.adjust(-7.0, -7.0, 7.0, 7.0);
351 QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
352 painter->setPen(pen);
353 painter->setBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
354 painter->drawRoundedRect(textRect, 7.0, 7.0);
356 pen = QPen(QColor(0x00, 0x5F, 0xDF));
357 painter->setPen(pen);
358 painter->drawText(bounds, Qt::AlignVCenter, text);