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"
21 // Set class variable defaults
22 Vector Painter::origin(-10.0, -10.0);
23 double Painter::zoom = 1.0;
24 Vector Painter::screenSize(200.0, 200.0);
27 Painter::Painter(QPainter * p/*= NULL*/): painter(p)
37 Vector Painter::CartesianToQtCoords(Vector v)
39 // Convert regular Cartesian coordinates to the inverted Y-axis Qt coordinates
40 // at the current origin and zoom level.
41 return Vector((v.x - origin.x) * zoom, screenSize.y - ((v.y - origin.y) * zoom));
45 Vector Painter::QtToCartesianCoords(Vector v)
47 // Convert screen location, with inverted Y-axis coordinates, to regular
48 // Cartesian coordinates at the current zoom level.
49 return Vector((v.x / zoom) + origin.x, ((screenSize.y - v.y) / zoom) + origin.y);
53 e.g., we have a point on the screen at Qt coords of 10, 10, screenSize is 100, 100.
54 origin is -10, -10 and zoom level is 2 (200%)
56 1st, invert the Y: 10, 10 -> 10, 90
57 2nd, add origin: 10, 90 -> 0, 80 (no, not right--err, yes, it is)
58 3rd, aply zoom: 0, 80 -> 0, 40
62 1st, invert the Y: 10, 10 -> 10, 90
63 2nd, aply zoom: 10, 90 -> 5, 45
64 3rd, add origin: 5, 45 -> -5, 35
66 it depends on whether or not origin is in Qt coords or cartesian. If Qt, then the 1st
67 is correct, otherwise, the 2nd is correct.
69 The way we calculate the Cartesian to Qt shows the 2nd (origin is cartesian) to be correct.
74 void Painter::SetRenderHint(int hint)
79 painter->setRenderHint((QPainter::RenderHint)hint);
83 void Painter::SetBrush(QBrush brush)
88 painter->setBrush(brush);
92 void Painter::SetFont(QFont font)
97 painter->setFont(font);
101 void Painter::SetPen(QPen pen)
106 painter->setPen(pen);
110 void Painter::DrawAngledText(Vector center, double angle, QString text, double size)
115 // Strategy: Since Qt doesn't have any rotated text drawing functions,
116 // we instead translate the origin to the center of the text to be drawn and
117 // then rotate the frame to the desired angle.
118 center = CartesianToQtCoords(center);
120 // We may need this stuff... If dimension text is large enough.
121 // int textWidth = QFontMetrics(painter->font()).width(text);
122 // int textHeight = QFontMetrics(painter->font()).height();
123 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
125 // This is in pixels. Might not render correctly at all zoom levels.
126 // Need to figure out if dimensions are always rendered at one size
127 // regardless of zoom, or if they have a definite size, and are thus
129 float yOffset = -12.0 * zoom * size;
131 // Fix text so it isn't upside down...
132 if ((angle > PI * 0.5) && (angle < PI * 1.5))
135 yOffset = 12.0 * zoom * size;
138 textBox.translate(0, yOffset);
140 painter->translate(center.x, center.y);
141 // Angles are backwards in the Qt coord system, so we flip ours...
142 painter->rotate(-angle * RADIANS_TO_DEGREES);
143 //Need to fix this so the text scales as well...
144 painter->drawText(textBox, Qt::AlignCenter, text);
149 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
151 center = CartesianToQtCoords(center);
152 // Need to multiply scalar quantities by the zoom factor as well...
154 QRectF rectangle(QPointF(center.x - radius, center.y - radius),
155 QPointF(center.x + radius, center.y + radius));
156 int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
157 int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0);
158 painter->drawArc(rectangle, angle1, angle2);
162 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
164 // Need to multiply scalar quantities by the zoom factor as well...
165 center = CartesianToQtCoords(center);
166 painter->drawEllipse(QPointF(center.x, center.y), axis1 * zoom, axis2 * zoom);
170 // This function is for drawing object handles without regard for zoom level;
171 // we don't want our object handle size to depend on the zoom level!
172 void Painter::DrawHandle(Vector center)
174 center = CartesianToQtCoords(center);
175 painter->setBrush(Qt::NoBrush);
176 painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
180 // This function is for drawing object handles without regard for zoom level;
181 // we don't want our object handle size to depend on the zoom level!
182 void Painter::DrawArrowHandle(Vector center, double angle)
184 center = CartesianToQtCoords(center);
187 // Since we're drawing directly on the screen, the Y is inverted. So we use
188 // the mirror of the angle.
189 double orthoAngle = -angle + (PI / 2.0);
190 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
191 Vector unit = Vector(cos(-angle), sin(-angle));
193 Point p0 = center + (unit * 6.0);
194 Point p1 = center + (unit * 21.0);
195 Point p1b = center + (unit * 11.0);
196 Point p2 = p1b + (orthogonal * 5.0);
197 Point p3 = p1b - (orthogonal * 5.0);
199 painter->drawLine(p0.x, p0.y, p1.x, p1.y);
200 arrow << QPointF(p1.x, p1.y) << QPointF(p2.x, p2.y) << QPointF(p3.x, p3.y);
202 painter->drawPolygon(arrow);
206 // This function is for drawing object handles without regard for zoom level;
207 // we don't want our object handle size to depend on the zoom level!
208 void Painter::DrawArrowToLineHandle(Vector center, double angle)
210 DrawArrowHandle(center, angle);
211 center = CartesianToQtCoords(center);
213 // Since we're drawing directly on the screen, the Y is inverted. So we use
214 // the mirror of the angle.
215 double orthoAngle = -angle + (PI / 2.0);
216 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
217 Vector unit = Vector(cos(-angle), sin(-angle));
219 Point p1 = center + (unit * 21.0);
220 Point p2 = p1 + (orthogonal * 7.0);
221 Point p3 = p1 - (orthogonal * 7.0);
223 painter->drawLine(p2.x, p2.y, p3.x, p3.y);
227 void Painter::DrawLine(int x1, int y1, int x2, int y2)
232 Vector v1 = CartesianToQtCoords(Vector(x1, y1));
233 Vector v2 = CartesianToQtCoords(Vector(x2, y2));
234 painter->drawLine(v1.x, v1.y, v2.x, v2.y);
238 void Painter::DrawLine(Vector v1, Vector v2)
243 v1 = CartesianToQtCoords(v1);
244 v2 = CartesianToQtCoords(v2);
245 painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
249 void Painter::DrawPoint(int x, int y)
254 Vector v = CartesianToQtCoords(Vector(x, y));
255 painter->drawPoint(v.x, v.y);
259 // The rect passed in is in Qt coordinates...
260 void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY)
265 painter->drawRoundedRect(rect, radiusX, radiusY);
269 // The rect passed in is in Cartesian but we want to pad it by a set number of
270 // pixels (currently set at 8), so the pad looks the same regardless of zoom.
271 void Painter::DrawPaddedRect(QRectF rect)
276 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
277 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
278 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
279 screenRect.adjust(-8, 8, 8, -8); // Left/top, right/bottom
280 painter->drawRect(screenRect);
284 void Painter::DrawRect(QRectF rect)
289 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
290 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
291 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
292 painter->drawRect(screenRect);
296 void Painter::DrawText(QRectF rect, int type, QString text)
301 painter->drawText(rect, (Qt::AlignmentFlag)type, text);
305 void Painter::DrawArrowhead(Vector head, Vector tail, double size)
312 // We draw the arrowhead aligned along the line from tail to head
313 double angle = Vector(head - tail).Angle();
314 double orthoAngle = angle + (PI / 2.0);
315 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
316 Vector unit = Vector(head - tail).Unit();
318 Point p1 = head - (unit * 9.0 * size);
319 Point p2 = p1 + (orthogonal * 3.0 * size);
320 Point p3 = p1 - (orthogonal * 3.0 * size);
322 Point p4 = CartesianToQtCoords(head);
323 Point p5 = CartesianToQtCoords(p2);
324 Point p6 = CartesianToQtCoords(p3);
326 arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y);
328 painter->drawPolygon(arrow);
332 // Point is given in Cartesian coordinates
333 void Painter::DrawCrosshair(Vector point)
338 Vector screenPoint = CartesianToQtCoords(point);
339 painter->drawLine(0, screenPoint.y, screenSize.x, screenPoint.y);
340 painter->drawLine(screenPoint.x, 0, screenPoint.x, screenSize.y);
344 void Painter::DrawInformativeText(QString text)
346 painter->setFont(*Object::font);
347 QRectF bounds = painter->boundingRect(QRectF(), Qt::AlignVCenter, text);
348 bounds.moveTo(17.0, 17.0);
349 QRectF textRect = bounds;
350 textRect.adjust(-7.0, -7.0, 7.0, 7.0);
352 QPen pen = QPen(QColor(0x00, 0xFF, 0x00), 1.0, Qt::SolidLine);
353 painter->setPen(pen);
354 painter->setBrush(QBrush(QColor(0x40, 0xFF, 0x40, 0x9F)));
355 painter->drawRoundedRect(textRect, 7.0, 7.0);
357 pen = QPen(QColor(0x00, 0x5F, 0xDF));
358 painter->setPen(pen);
359 painter->drawText(bounds, Qt::AlignVCenter, text);