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::SetPen(QPen pen)
91 void Painter::SetPen(uint32_t color, float size/*= 0*/, int style/*= 0*/)
96 // We can cast style as Qt:PenStyle because they line up 1-to-1
97 painter->setPen(QPen(QColor(color >> 16, (color >> 8) & 0xFF, color & 0xFF, 255),
98 size, (Qt::PenStyle)style));
102 void Painter::SetBrush(QBrush brush)
107 painter->setBrush(brush);
111 void Painter::SetBrush(uint32_t color)
116 painter->setBrush(QBrush(QColor(color >> 16, (color >> 8) & 0xFF, color & 0xFF, 255)));
120 void Painter::SetFont(QFont font)
125 painter->setFont(font);
129 void Painter::DrawAngledText(Vector center, double angle, QString text, double size)
134 // Strategy: Since Qt doesn't have any rotated text drawing functions,
135 // we instead translate the origin to the center of the text to be drawn and
136 // then rotate the frame to the desired angle.
137 center = CartesianToQtCoords(center);
139 // We may need this stuff... If dimension text is large enough.
140 // int textWidth = QFontMetrics(painter->font()).width(text);
141 // int textHeight = QFontMetrics(painter->font()).height();
142 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
144 // This is in pixels. Might not render correctly at all zoom levels.
145 // Need to figure out if dimensions are always rendered at one size
146 // regardless of zoom, or if they have a definite size, and are thus
148 float yOffset = -12.0 * Global::zoom * size;
150 // Fix text so it isn't upside down...
151 if ((angle > PI * 0.5) && (angle < PI * 1.5))
154 yOffset = 12.0 * Global::zoom * size;
157 textBox.translate(0, yOffset);
159 painter->translate(center.x, center.y);
160 // Angles are backwards in the Qt coord system, so we flip ours...
161 painter->rotate(-angle * RADIANS_TO_DEGREES);
162 //Need to fix this so the text scales as well...
163 painter->drawText(textBox, Qt::AlignCenter, text);
169 // Draw angled text. Draws text using point p as the upper left corner.
170 // Size is point size, angle is in radians (defaults to 0).
172 void Painter::DrawTextObject(Point p, QString text, double size, double angle/*= 0*/)
177 p = CartesianToQtCoords(p);
178 painter->setFont(QFont("Arial", Global::zoom * size));
179 int textWidth = QFontMetrics(painter->font()).width(text);
180 int textHeight = QFontMetrics(painter->font()).height();
182 QRectF textBox(0, 0, textWidth, textHeight);
184 painter->translate(p.x, p.y);
185 // Angles are backwards in the Qt coord system, so we flip ours...
186 painter->rotate(-angle * RADIANS_TO_DEGREES);
187 painter->drawText(textBox, Qt::AlignLeft | Qt::AlignTop , text);
192 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
194 center = CartesianToQtCoords(center);
195 // Need to multiply scalar quantities by the zoom factor as well...
196 radius *= Global::zoom;
197 QRectF rectangle(QPointF(center.x - radius, center.y - radius),
198 QPointF(center.x + radius, center.y + radius));
199 int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
200 int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0);
201 painter->drawArc(rectangle, angle1, angle2);
205 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
207 // Need to multiply scalar quantities by the zoom factor as well...
208 center = CartesianToQtCoords(center);
209 painter->drawEllipse(QPointF(center.x, center.y), axis1 * Global::zoom, axis2 * Global::zoom);
213 // This function is for drawing object handles without regard for zoom level;
214 // we don't want our object handle size to depend on the zoom level!
215 void Painter::DrawHandle(Vector center)
217 center = CartesianToQtCoords(center);
218 painter->setBrush(Qt::NoBrush);
219 painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
223 // This function is for drawing object handles without regard for zoom level;
224 // we don't want our object handle size to depend on the zoom level!
225 void Painter::DrawArrowHandle(Vector center, double angle)
227 center = CartesianToQtCoords(center);
230 // Since we're drawing directly on the screen, the Y is inverted. So we use
231 // the mirror of the angle.
232 double orthoAngle = -angle + (PI / 2.0);
233 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
234 Vector unit = Vector(cos(-angle), sin(-angle));
236 Point p0 = center + (unit * 6.0);
237 Point p1 = center + (unit * 21.0);
238 Point p1b = center + (unit * 11.0);
239 Point p2 = p1b + (orthogonal * 5.0);
240 Point p3 = p1b - (orthogonal * 5.0);
242 painter->drawLine(p0.x, p0.y, p1.x, p1.y);
243 arrow << QPointF(p1.x, p1.y) << QPointF(p2.x, p2.y) << QPointF(p3.x, p3.y);
245 painter->drawPolygon(arrow);
249 // This function is for drawing object handles without regard for zoom level;
250 // we don't want our object handle size to depend on the zoom level!
251 void Painter::DrawArrowToLineHandle(Vector center, double angle)
253 DrawArrowHandle(center, angle);
254 center = CartesianToQtCoords(center);
256 // Since we're drawing directly on the screen, the Y is inverted. So we use
257 // the mirror of the angle.
258 double orthoAngle = -angle + (PI / 2.0);
259 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
260 Vector unit = Vector(cos(-angle), sin(-angle));
262 Point p1 = center + (unit * 21.0);
263 Point p2 = p1 + (orthogonal * 7.0);
264 Point p3 = p1 - (orthogonal * 7.0);
266 painter->drawLine(p2.x, p2.y, p3.x, p3.y);
270 void Painter::DrawLine(int x1, int y1, int x2, int y2)
275 Vector v1 = CartesianToQtCoords(Vector(x1, y1));
276 Vector v2 = CartesianToQtCoords(Vector(x2, y2));
277 painter->drawLine(v1.x, v1.y, v2.x, v2.y);
281 void Painter::DrawLine(Vector v1, Vector v2)
286 v1 = CartesianToQtCoords(v1);
287 v2 = CartesianToQtCoords(v2);
288 painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
292 void Painter::DrawPoint(int x, int y)
297 Vector v = CartesianToQtCoords(Vector(x, y));
298 painter->drawPoint(v.x, v.y);
302 // The rect passed in is in Qt coordinates...
303 void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY)
308 painter->drawRoundedRect(rect, radiusX, radiusY);
312 // The rect passed in is in Cartesian but we want to pad it by a set number of
313 // pixels (currently set at 8), so the pad looks the same regardless of zoom.
314 void Painter::DrawPaddedRect(QRectF rect)
319 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
320 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
321 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
322 screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom
323 painter->drawRect(screenRect);
327 void Painter::DrawRect(QRectF rect)
332 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
333 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
334 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
335 painter->drawRect(screenRect);
339 void Painter::DrawText(QRectF rect, int type, QString text)
344 painter->drawText(rect, (Qt::AlignmentFlag)type, text);
348 void Painter::DrawArrowhead(Vector head, Vector tail, double size)
355 // We draw the arrowhead aligned along the line from tail to head
356 double angle = Vector(head - tail).Angle();
357 double orthoAngle = angle + (PI / 2.0);
358 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
359 Vector unit = Vector(head - tail).Unit();
361 Point p1 = head - (unit * 9.0 * size);
362 Point p2 = p1 + (orthogonal * 3.0 * size);
363 Point p3 = p1 - (orthogonal * 3.0 * size);
365 Point p4 = CartesianToQtCoords(head);
366 Point p5 = CartesianToQtCoords(p2);
367 Point p6 = CartesianToQtCoords(p3);
369 arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y);
371 painter->drawPolygon(arrow);
375 // Point is given in Cartesian coordinates
376 void Painter::DrawCrosshair(Vector point)
381 Vector screenPoint = CartesianToQtCoords(point);
382 painter->drawLine(0, screenPoint.y, Global::screenSize.x, screenPoint.y);
383 painter->drawLine(screenPoint.x, 0, screenPoint.x, Global::screenSize.y);
387 void Painter::DrawInformativeText(QString text)
389 painter->setFont(*Global::font);
390 QRectF bounds = painter->boundingRect(QRectF(), Qt::AlignVCenter, text);
391 bounds.moveTo(17.0, 17.0);
392 QRectF textRect = bounds;
393 textRect.adjust(-7.0, -7.0, 7.0, 7.0);
395 QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
396 painter->setPen(pen);
397 painter->setBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
398 painter->drawRoundedRect(textRect, 7.0, 7.0);
400 pen = QPen(QColor(0x00, 0x5F, 0xDF));
401 painter->setPen(pen);
402 painter->drawText(bounds, Qt::AlignVCenter, text);