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 - origin.x) * zoom, screenSize.y - ((v.y - origin.y) * 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 / zoom) + origin.x, ((screenSize.y - v.y) / zoom) + 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 // NOTE: SCREEN_ZOOM is a kludge to make things look right at screen resolution...
123 // QRectF textBox(-100.0 * zoom * SCREEN_ZOOM, -100.0 * zoom * SCREEN_ZOOM, 200.0 * zoom * SCREEN_ZOOM, 200.0 * zoom * SCREEN_ZOOM); // x, y, w, h; x/y = upper left corner
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 regardless of zoom,
128 // or if they have a definite size, and are thus zoomable.
129 // If zoomable, this is incorrect:
130 // (Added zoom, so this is correct now :-)
131 // float yOffset = -12.0 * zoom * SCREEN_ZOOM;
132 float yOffset = -12.0 * zoom * size;
134 // Fix text so it isn't upside down...
135 if ((angle > PI * 0.5) && (angle < PI * 1.5))
138 // yOffset = 12.0 * zoom * SCREEN_ZOOM;
139 yOffset = 12.0 * zoom * size;
143 Vector offset = CartesianToQtCoords(Vector(0, yOffset));
144 textBox.translate(offset.x, offset.y);
146 textBox.translate(0, yOffset);
149 painter->translate(center.x, center.y);
150 // Angles are backwards in the Qt coord system, so we flip ours...
151 painter->rotate(-angle * RADIANS_TO_DEGREES);
152 //Need to fix this so the text scales as well...
153 painter->drawText(textBox, Qt::AlignCenter, text);
158 void Painter::DrawArc(Vector center, double radius, double startAngle, double span)
160 center = CartesianToQtCoords(center);
161 // Need to multiply scalar quantities by the zoom factor as well...
163 QRectF rectangle(QPointF(center.x - radius, center.y - radius),
164 QPointF(center.x + radius, center.y + radius));
165 int angle1 = (int)(startAngle * RADIANS_TO_DEGREES * 16.0);
166 int angle2 = (int)(span * RADIANS_TO_DEGREES * 16.0);
167 painter->drawArc(rectangle, angle1, angle2);
171 void Painter::DrawEllipse(Vector center, double axis1, double axis2)
173 // Need to multiply scalar quantities by the zoom factor as well...
174 center = CartesianToQtCoords(center);
175 painter->drawEllipse(QPointF(center.x, center.y), axis1 * zoom, axis2 * zoom);
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::DrawHandle(Vector center)
183 center = CartesianToQtCoords(center);
184 painter->setBrush(Qt::NoBrush);
185 painter->drawEllipse(QPointF(center.x, center.y), 4.0, 4.0);
189 void Painter::DrawLine(int x1, int y1, int x2, int y2)
194 Vector v1 = CartesianToQtCoords(Vector(x1, y1));
195 Vector v2 = CartesianToQtCoords(Vector(x2, y2));
196 painter->drawLine(v1.x, v1.y, v2.x, v2.y);
200 void Painter::DrawLine(Vector v1, Vector v2)
205 v1 = CartesianToQtCoords(v1);
206 v2 = CartesianToQtCoords(v2);
207 painter->drawLine(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
211 void Painter::DrawPoint(int x, int y)
216 Vector v = CartesianToQtCoords(Vector(x, y));
217 painter->drawPoint(v.x, v.y);
221 void Painter::DrawRoundedRect(QRectF rect, double radiusX, double radiusY)
226 painter->drawRoundedRect(rect, radiusX, radiusY);
230 void Painter::DrawRect(QRectF rect)
235 Vector v1 = CartesianToQtCoords(Vector(rect.x(), rect.y()));
236 Vector v2 = CartesianToQtCoords(Vector(rect.right(), rect.bottom()));
237 QRectF screenRect(QPointF(v1.x, v1.y), QPointF(v2.x, v2.y));
238 painter->drawRect(screenRect);
242 void Painter::DrawText(QRectF rect, int type, QString text)
247 painter->drawText(rect, (Qt::AlignmentFlag)type, text);
251 void Painter::DrawArrowhead(Vector head, Vector tail, double size)
255 // We draw the arrowhead aligned along the line from tail to head
256 double angle = Vector(head - tail).Angle();
257 double orthoAngle = angle + (PI / 2.0);
258 Vector orthogonal = Vector(cos(orthoAngle), sin(orthoAngle));
259 Vector unit = Vector(head - tail).Unit();
262 // NOTE: SCREEN_ZOOM is a kludge to make things look right at scale...
263 Point p1 = head - (unit * 9.0 * SCREEN_ZOOM);
264 Point p2 = p1 + (orthogonal * 3.0 * SCREEN_ZOOM);
265 Point p3 = p1 - (orthogonal * 3.0 * SCREEN_ZOOM);
267 Point p1 = head - (unit * 9.0 * size);
268 Point p2 = p1 + (orthogonal * 3.0 * size);
269 Point p3 = p1 - (orthogonal * 3.0 * size);
272 Point p4 = CartesianToQtCoords(head);
273 Point p5 = CartesianToQtCoords(p2);
274 Point p6 = CartesianToQtCoords(p3);
276 arrow << QPointF(p4.x, p4.y) << QPointF(p5.x, p5.y) << QPointF(p6.x, p6.y);
278 painter->drawPolygon(arrow);