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"
22 // Set class variable defaults
23 Vector Painter::origin(-10.0, -10.0);
24 double Painter::zoom = 1.0;
25 Vector Painter::screenSize(200.0, 200.0);
28 Painter::Painter(QPainter * p/*= NULL*/): painter(p)
38 Vector Painter::CartesianToQtCoords(Vector v)
40 // Convert regular Cartesian coordinates to the inverted Y-axis Qt coordinates
41 // at the current origin and zoom level.
42 return Vector((v.x - origin.x) * zoom, screenSize.y - ((v.y - origin.y) * zoom));
46 Vector Painter::QtToCartesianCoords(Vector v)
48 // Convert screen location, with inverted Y-axis coordinates, to regular
49 // Cartesian coordinates at the current zoom level.
50 return Vector((v.x / zoom) + origin.x, ((screenSize.y - v.y) / zoom) + origin.y);
54 e.g., we have a point on the screen at Qt coords of 10, 10, screenSize is 100, 100.
55 origin is -10, -10 and zoom level is 2 (200%)
57 1st, invert the Y: 10, 10 -> 10, 90
58 2nd, add origin: 10, 90 -> 0, 80 (no, not right--err, yes, it is)
59 3rd, aply zoom: 0, 80 -> 0, 40
63 1st, invert the Y: 10, 10 -> 10, 90
64 2nd, aply zoom: 10, 90 -> 5, 45
65 3rd, add origin: 5, 45 -> -5, 35
67 it depends on whether or not origin is in Qt coords or cartesian. If Qt, then the 1st
68 is correct, otherwise, the 2nd is correct.
70 The way we calculate the Cartesian to Qt shows the 2nd (origin is cartesian) to be correct.
75 void Painter::SetRenderHint(int hint)
80 painter->setRenderHint((QPainter::RenderHint)hint);
84 void Painter::SetBrush(QBrush brush)
89 painter->setBrush(brush);
93 void Painter::SetFont(QFont font)
98 painter->setFont(font);
102 void Painter::SetPen(QPen pen)
107 painter->setPen(pen);
111 void Painter::DrawAngledText(Vector center, double angle, QString text, double size)
116 // Strategy: Since Qt doesn't have any rotated text drawing functions,
117 // we instead translate the origin to the center of the text to be drawn and
118 // then rotate the frame to the desired angle.
119 center = CartesianToQtCoords(center);
121 // We may need this stuff... If dimension text is large enough.
122 // int textWidth = QFontMetrics(painter->font()).width(text);
123 // int textHeight = QFontMetrics(painter->font()).height();
124 QRectF textBox(-100.0 * zoom * size, -100.0 * zoom * size, 200.0 * zoom * size, 200.0 * zoom * size); // x, y, w, h; x/y = upper left corner
126 // This is in pixels. Might not render correctly at all zoom levels.
127 // Need to figure out if dimensions are always rendered at one size
128 // regardless of zoom, or if they have a definite size, and are thus
130 float yOffset = -12.0 * zoom * size;
132 // Fix text so it isn't upside down...
133 if ((angle > PI * 0.5) && (angle < PI * 1.5))
136 yOffset = 12.0 * zoom * size;
139 textBox.translate(0, yOffset);
141 painter->translate(center.x, center.y);
142 // Angles are backwards in the Qt coord system, so we flip ours...
143 painter->rotate(-angle * RADIANS_TO_DEGREES);
144 //Need to fix this so the text scales as well...
145 painter->drawText(textBox, Qt::AlignCenter, text);
150 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
152 center = CartesianToQtCoords(center);
153 // Need to multiply scalar quantities by the zoom factor as well...
155 QRectF rectangle(QPointF(center.x - radius, center.y - radius),
156 QPointF(center.x + radius, center.y + radius));
157 int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
158 int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0);
159 painter->drawArc(rectangle, angle1, angle2);
163 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
165 // Need to multiply scalar quantities by the zoom factor as well...
166 center = CartesianToQtCoords(center);
167 painter->drawEllipse(QPointF(center.x, center.y), axis1 * zoom, axis2 * zoom);
171 // This function is for drawing object handles without regard for zoom level;
172 // we don't want our object handle size to depend on the zoom level!
173 void Painter::DrawHandle(Vector center)
175 center = CartesianToQtCoords(center);
176 painter->setBrush(Qt::NoBrush);
177 painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
181 // This function is for drawing object handles without regard for zoom level;
182 // we don't want our object handle size to depend on the zoom level!
183 void Painter::DrawArrowHandle(Vector center, double angle)
185 center = CartesianToQtCoords(center);
188 // Since we're drawing directly on the screen, the Y is inverted. So we use
189 // the mirror of the angle.
190 double orthoAngle = -angle + (PI / 2.0);
191 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
192 Vector unit = Vector(cos(-angle), sin(-angle));
194 Point p0 = center + (unit * 6.0);
195 Point p1 = center + (unit * 21.0);
196 Point p1b = center + (unit * 11.0);
197 Point p2 = p1b + (orthogonal * 5.0);
198 Point p3 = p1b - (orthogonal * 5.0);
200 painter->drawLine(p0.x, p0.y, p1.x, p1.y);
201 arrow << QPointF(p1.x, p1.y) << QPointF(p2.x, p2.y) << QPointF(p3.x, p3.y);
203 painter->drawPolygon(arrow);
207 // This function is for drawing object handles without regard for zoom level;
208 // we don't want our object handle size to depend on the zoom level!
209 void Painter::DrawArrowToLineHandle(Vector center, double angle)
211 DrawArrowHandle(center, angle);
212 center = CartesianToQtCoords(center);
214 // Since we're drawing directly on the screen, the Y is inverted. So we use
215 // the mirror of the angle.
216 double orthoAngle = -angle + (PI / 2.0);
217 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
218 Vector unit = Vector(cos(-angle), sin(-angle));
220 Point p1 = center + (unit * 21.0);
221 Point p2 = p1 + (orthogonal * 7.0);
222 Point p3 = p1 - (orthogonal * 7.0);
224 painter->drawLine(p2.x, p2.y, p3.x, p3.y);
228 void Painter::DrawLine(int x1, int y1, int x2, int y2)
233 Vector v1 = CartesianToQtCoords(Vector(x1, y1));
234 Vector v2 = CartesianToQtCoords(Vector(x2, y2));
235 painter->drawLine(v1.x, v1.y, v2.x, v2.y);
239 void Painter::DrawLine(Vector v1, Vector v2)
244 v1 = CartesianToQtCoords(v1);
245 v2 = CartesianToQtCoords(v2);
246 painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
250 void Painter::DrawPoint(int x, int y)
255 Vector v = CartesianToQtCoords(Vector(x, y));
256 painter->drawPoint(v.x, v.y);
260 // The rect passed in is in Qt coordinates...
261 void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY)
266 painter->drawRoundedRect(rect, radiusX, radiusY);
270 // The rect passed in is in Cartesian but we want to pad it by a set number of
271 // pixels (currently set at 8), so the pad looks the same regardless of zoom.
272 void Painter::DrawPaddedRect(QRectF rect)
277 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
278 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
279 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
280 screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom
281 painter->drawRect(screenRect);
285 void Painter::DrawRect(QRectF rect)
290 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
291 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
292 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
293 painter->drawRect(screenRect);
297 void Painter::DrawText(QRectF rect, int type, QString text)
302 painter->drawText(rect, (Qt::AlignmentFlag)type, text);
306 void Painter::DrawArrowhead(Vector head, Vector tail, double size)
313 // We draw the arrowhead aligned along the line from tail to head
314 double angle = Vector(head - tail).Angle();
315 double orthoAngle = angle + (PI / 2.0);
316 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
317 Vector unit = Vector(head - tail).Unit();
319 Point p1 = head - (unit * 9.0 * size);
320 Point p2 = p1 + (orthogonal * 3.0 * size);
321 Point p3 = p1 - (orthogonal * 3.0 * size);
323 Point p4 = CartesianToQtCoords(head);
324 Point p5 = CartesianToQtCoords(p2);
325 Point p6 = CartesianToQtCoords(p3);
327 arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y);
329 painter->drawPolygon(arrow);
333 // Point is given in Cartesian coordinates
334 void Painter::DrawCrosshair(Vector point)
339 Vector screenPoint = CartesianToQtCoords(point);
340 painter->drawLine(0, screenPoint.y, screenSize.x, screenPoint.y);
341 painter->drawLine(screenPoint.x, 0, screenPoint.x, screenSize.y);
345 void Painter::DrawInformativeText(QString text)
347 painter->setFont(*Global::font);
348 QRectF bounds = painter->boundingRect(QRectF(), Qt::AlignVCenter, text);
349 bounds.moveTo(17.0, 17.0);
350 QRectF textRect = bounds;
351 textRect.adjust(-7.0, -7.0, 7.0, 7.0);
353 QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
354 painter->setPen(pen);
355 painter->setBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
356 painter->drawRoundedRect(textRect, 7.0, 7.0);
358 pen = QPen(QColor(0x00, 0x5F, 0xDF));
359 painter->setPen(pen);
360 painter->drawText(bounds, Qt::AlignVCenter, text);