1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
/****************************************************************************
**
** TQt Coordinate System Documentation
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the TQt GUI Toolkit.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free TQt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at sales@trolltech.com.
**
** This file may be used under the terms of the Q Public License as
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
** included in the packaging of this file. Licensees holding valid Qt
** Commercial licenses may use this file in accordance with the Qt
** Commercial License Agreement provided with the Software.
**
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/
/*!
\page coordsys.html
\title The Coordinate System
A \link QPaintDevice paint device\endlink in TQt is a drawable 2D
surface. \l TQWidget, \l QPixmap, \l QPicture and \l QPrinter are all
paint devices. A \l QPainter is an object which can draw on such
devices.
The default coordinate system of a paint device has its origin at the
top left corner. X increases to the right and Y increases downwards.
The unit is one pixel on pixel-based devices and one point on
printers.
\section1 An Example
The illustration below shows a highly magnified portion of the top
left corner of a paint device.
\img coordsys.png
The rectangle and the line were drawn by this code (with the grid
added and colors touched up in the illustration):
\code
void MyWidget::paintEvent( QPaintEvent * )
{
QPainter p( this );
p.setPen( darkGray );
p.drawRect( 1,2, 5,4 );
p.setPen( lightGray );
p.drawLine( 9,2, 7,7 );
}
\endcode
Note that all of the pixels drawn by drawRect() are inside the size
specified (5*4 pixels). This is different from some toolkits; in Qt
the size you specify exactly encompasses the pixels drawn. This
applies to all the relevant functions in QPainter.
Similarly, the drawLine() call draws both endpoints of the line, not
just one.
Here are the classes that relate most closely to the coordinate
system:
\table
\row \i \l QPoint
\i A single 2D point in the coordinate system. Most functions in
Qt that deal with points can accept either a QPoint argument
or two ints, for example \l QPainter::drawPoint().
\row \i \l QSize
\i A single 2D vector. Internally, QPoint and QSize are the same,
but a point is not the same as a size, so both classes exist.
Again, most functions accept either a QSize or two ints, for
example \l TQWidget::resize().
\row \i \l QRect
\i A 2D rectangle. Most functions accept either a QRect or four
ints, for example \l TQWidget::setGeometry().
\row \i \l QRegion
\i An arbitrary set of points, including all the normal set
operations, e.g. \l QRegion::intersect(), and also a less
usual function to return a list of rectangles whose union is
equal to the region. QRegion is used e.g. by \l
QPainter::setClipRegion(), \l TQWidget::repaint() and \l
QPaintEvent::region().
\row \i \l QPainter
\i The class that paints. It can paint on any device with the
same code. There are differences between devices, \l
QPrinter::newPage() is a good example, but QPainter works the
same way on all devices.
\row \i \l QPaintDevice
\i A device on which QPainter can paint. There are two internal
devices, both pixel-based, and two external devices, \l
QPrinter and \l QPicture (which records QPainter commands to a
file or other \l TQIODevice, and plays them back). Other
devices can be defined.
\endtable
\section1 Transformations
Although Qt's default coordinate system works as described above, \l
QPainter also supports arbitrary transformations.
This transformation engine is a three-step pipeline, closely following
the model outlined in books such as
\link http://www.amazon.com/exec/obidos/ASIN/0201848406/trolltech/t
Foley \& Van Dam \endlink and the
\link http://www.amazon.com/exec/obidos/ASIN/0201604582/trolltech/t
OpenGL Programming Guide.\endlink Refer to those for in-depth
coverage; here we give just a brief overview and an example.
The first step uses the world transformation matrix. Use this matrix
to orient and position your objects in your model. TQt provides
methods such as \l QPainter::rotate(), \l QPainter::scale(), \l
QPainter::translate() and so on to operate on this matrix.
\l QPainter::save() and \l QPainter::restore() save and restore this
matrix. You can also use \l QWMatrix objects, \l
QPainter::worldMatrix() and \l QPainter::setWorldMatrix() to store and
use named matrices.
The second step uses the window. The window describes the view
boundaries in model coordinates. The matrix positions the \e objects
and \l QPainter::setWindow() positions the \e window, deciding what
coordinates will be visible. (If you have 3D experience, the window
is what's usually called projection in 3D.)
The third step uses the viewport. The viewport too, describes the view
boundaries, but in device coordinates. The viewport and the windows
describe the same rectangle, but in different coordinate systems.
On-screen, the default is the entire \l TQWidget or \l QPixmap where
you are drawing, which is usually appropriate. For printing this
function is vital, since very few printers can print over the entire
physical page.
So each object to be drawn is transformed into model
coordinates using \l QPainter::worldMatrix(), then positioned
on the drawing device using \l QPainter::window() and
\l QPainter::viewport().
It is perfectly possible to do without one or two of the stages. If,
for example, your goal is to draw something scaled, then just using \l
QPainter::scale() makes perfect sense. If your goal is to use a
fixed-size coordinate system, \l QPainter::setWindow() is
ideal. And so on.
Here is a short example that uses all three mechanisms: the function
that draws the clock face in the \l aclock/aclock.cpp example. We
recommend compiling and running the example before you read any
further. In particular, try resizing the window to different sizes.
\quotefile aclock/aclock.cpp
\skipto ::drawClock
\printline ::drawClock
\printline {
\printline save
Firstly, we save the painter's state, so that the calling function
is guaranteed not to be disturbed by the transformations we're going
to use.
\printline setWindow
We set the model coordinate system we want a 1000*1000 window where
0,0 is in the middle.
\printline viewport
\printline QMIN
The device may not be square and we want the clock to be, so we find
its current viewport and compute its shortest side.
\printline setViewport
\printline height
Then we set a new square viewport, centered in the old one.
We're now done with our view. From this point on, when we draw in a
1000*1000 area around 0,0, what we draw will show up in the largest
possible square that'll fit in the output device.
Time to start drawing.
\skipto pts
\printline pts
\e pts is just a temporary variable to hold some points.
Next come three drawing blocks, one for the hour hand, one for the
minute hand and finally one for the clock face itself. First we draw
the hour hand:
\skipto save
\printline save
\printline rotate
We save the painter and then rotate it so that one axis points along
the hour hand.
\printline setPoints
\printline drawConvexPolygon
We set \e pts to a four-point polygon that looks like the hour hand at
three o'clock, and draw it. Because of the rotation, it's drawn
pointed in the right direction.
\printline restore
We restore the saved painter, undoing the rotation. We could also
call rotate( -30 ) but that might introduce rounding errors, so it's
better to use save() and restore(). Next, the minute hand, drawn
almost the same way:
\printline save
\printline rotate
\printline setPoints
\printline drawConvexPolygon
\printline restore
The only differences are how the rotation angle is computed and the
shape of the polygon.
The last part to be drawn is the clock face itself.
\printline for
\printline drawLine
\printline rotate
\printline }
Twelve short hour lines at thirty-degree intervals. At the end of
that, the painter is rotated in a way which isn't very useful, but
we're done with painting so that doesn't matter.
\printline restore
\printline }
The final line of the function restores the painter, so that the
caller won't be affected by all the transformations we've done.
*/
|