Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
coordsys.qdoc
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
4
/*!
5
\page coordsys.html
6
\title Coordinate System
7
\ingroup qt-graphics
8
\ingroup best-practices
9
\brief Information about the coordinate system used by the paint
10
system.
11
12
The coordinate system is controlled by the QPainter
13
class. Together with the QPaintDevice and QPaintEngine classes,
14
QPainter form the basis of Qt's painting system, Arthur. QPainter
15
is used to perform drawing operations, QPaintDevice is an
16
abstraction of a two-dimensional space that can be painted on
17
using a QPainter, and QPaintEngine provides the interface that the
18
painter uses to draw onto different types of devices.
19
20
The QPaintDevice class is the base class of objects that can be
21
painted: Its drawing capabilities are inherited by the QWidget,
22
QImage, QPixmap, QPicture, and QOpenGLPaintDevice classes. The
23
default coordinate system of a paint device has its origin at the
24
top-left corner. The \e x values increase to the right and the \e
25
y values increase downwards. The default unit is one pixel on
26
pixel-based devices and one point (1/72 of an inch) on printers.
27
28
The mapping of the logical QPainter coordinates to the physical
29
QPaintDevice coordinates are handled by QPainter's transformation
30
matrix, viewport and "window". The logical and physical coordinate
31
systems coincide by default. QPainter also supports coordinate
32
transformations (e.g. rotation and scaling).
33
34
\section1 Rendering
35
36
\section2 Logical Representation
37
38
The size (width and height) of a graphics primitive always
39
correspond to its mathematical model, ignoring the width of the
40
pen it is rendered with:
41
42
\table
43
\row
44
\li \inlineimage coordinatesystem-rect.svg
45
\li \inlineimage coordinatesystem-line.svg
46
\row
47
\li QRect(QPoint(1, 2), QPoint(7, 6))
48
\li QLine(QPoint(2, 7), QPoint(6, 1))
49
\row
50
\li
51
\li QLine(2, 7, 6, 1)
52
\row
53
\li QRect(QPoint(1, 2), QSize(6, 4))
54
\row
55
\li QRect(1, 2, 6, 4)
56
\endtable
57
58
\section2 Aliased Painting
59
60
When drawing, the pixel rendering is controlled by the
61
QPainter::Antialiasing render hint.
62
63
The \l {QPainter::RenderHint}{RenderHint} enum is used to specify
64
flags to QPainter that may or may not be respected by any given
65
engine. The QPainter::Antialiasing value indicates that the engine
66
should antialias edges of primitives if possible, i.e. smoothing
67
the edges by using different color intensities.
68
69
But by default the painter is \e aliased and other rules apply:
70
When rendering with a one pixel wide pen the pixels will be
71
rendered to the \e {right and below the mathematically defined
72
points}. For example:
73
74
\table
75
\row
76
\li \inlineimage coordinatesystem-rect-raster.svg
77
\li \inlineimage coordinatesystem-line-raster.svg
78
79
\row
80
\li
81
\snippet code/doc_src_coordsys.cpp 0
82
83
\li
84
\snippet code/doc_src_coordsys.cpp 1
85
\endtable
86
87
When rendering with a pen with an even number of pixels, the
88
pixels will be rendered symmetrically around the mathematical
89
defined points, while rendering with a pen with an odd number of
90
pixels, the spare pixel will be rendered to the right and below
91
the mathematical point as in the one pixel case. See the QRectF
92
diagrams below for concrete examples.
93
94
\table
95
\header
96
\li {2,1} QRectF
97
\row
98
\li \inlineimage qrect-diagram-zero.png
99
\li \inlineimage qrectf-diagram-one.png
100
\row
101
\li Logical representation
102
\li One pixel wide pen
103
\row
104
\li \inlineimage qrectf-diagram-two.png
105
\li \inlineimage qrectf-diagram-three.png
106
\row
107
\li Two pixel wide pen
108
\li Three pixel wide pen
109
\endtable
110
111
Note that for historical reasons the return value of the
112
QRect::right() and QRect::bottom() functions deviate from the true
113
bottom-right corner of the rectangle.
114
115
QRect's \l {QRect::right()}{right()} function returns \l
116
{QRect::left()}{left()} + \l {QRect::width()}{width()} - 1 and the
117
\l {QRect::bottom()}{bottom()} function returns \l
118
{QRect::top()}{top()} + \l {QRect::height()}{height()} - 1. The
119
bottom-right green point in the diagrams shows the return
120
coordinates of these functions.
121
122
We recommend that you simply use QRectF instead: The QRectF class
123
defines a rectangle in the plane using floating point coordinates
124
for accuracy (QRect uses integer coordinates), and the
125
QRectF::right() and QRectF::bottom() functions \e do return the
126
true bottom-right corner.
127
128
Alternatively, using QRect, apply \l {QRect::x()}{x()} + \l
129
{QRect::width()}{width()} and \l {QRect::y()}{y()} + \l
130
{QRect::height()}{height()} to find the bottom-right corner, and
131
avoid the \l {QRect::right()}{right()} and \l
132
{QRect::bottom()}{bottom()} functions.
133
134
\section2 Anti-aliased Painting
135
136
If you set QPainter's \l {QPainter::Antialiasing}{anti-aliasing}
137
render hint, the pixels will be rendered symmetrically on both
138
sides of the mathematically defined points:
139
140
\table
141
\row
142
\li \inlineimage coordinatesystem-rect-antialias.svg
143
\li \inlineimage coordinatesystem-line-antialias.svg
144
\row
145
\li
146
147
\snippet code/doc_src_coordsys.cpp 2
148
149
\li
150
\snippet code/doc_src_coordsys.cpp 3
151
\endtable
152
153
\section1 Transformations
154
155
By default, the QPainter operates on the associated device's own
156
coordinate system, but it also has complete support for affine
157
coordinate transformations.
158
159
You can scale the coordinate system by a given offset using the
160
QPainter::scale() function, you can rotate it clockwise using the
161
QPainter::rotate() function and you can translate it (i.e. adding
162
a given offset to the points) using the QPainter::translate()
163
function.
164
165
\table
166
\row
167
\li \inlineimage qpainter-clock.png
168
\li \inlineimage qpainter-rotation.png
169
\li \inlineimage qpainter-scale.png
170
\li \inlineimage qpainter-translation.png
171
\row
172
\li nop
173
\li \l {QPainter::rotate()}{rotate()}
174
\li \l {QPainter::scale()}{scale()}
175
\li \l {QPainter::translate()}{translate()}
176
\endtable
177
178
You can also twist the coordinate system around the origin using
179
the QPainter::shear() function. All the transformation operations
180
operate on QPainter's transformation matrix that you can retrieve
181
using the QPainter::worldTransform() function. A matrix transforms
182
a point in the plane to another point.
183
184
If you need the same transformations over and over, you can also
185
use QTransform objects and the QPainter::worldTransform() and
186
QPainter::setWorldTransform() functions. You can at any time save the
187
QPainter's transformation matrix by calling the QPainter::save()
188
function which saves the matrix on an internal stack. The
189
QPainter::restore() function pops it back.
190
191
One frequent need for the transformation matrix is when reusing
192
the same drawing code on a variety of paint devices. Without
193
transformations, the results are tightly bound to the resolution
194
of the paint device. Printers have high resolution, e.g. 600 dots
195
per inch, whereas screens often have between 72 and 100 dots per
196
inch.
197
198
\table 100%
199
\header
200
\li {2,1} Analog Clock Example
201
\row
202
\li \inlineimage coordinatesystem-analogclock.png
203
\li
204
The Analog Clock example shows how to draw the contents of a
205
custom widget using QPainter's transformation matrix.
206
207
We recommend compiling and running this example before you read
208
any further. In particular, try resizing the window to different
209
sizes.
210
211
\row
212
\li {2,1}
213
214
\snippet ../widgets/widgets/analogclock/analogclock.cpp 9
215
216
We translate the coordinate system so that point (0, 0) is in the
217
widget's center, instead of being at the top-left corner. We also
218
scale the system by \c side / 200, where \c side is either the
219
widget's width or the height, whichever is shortest. We want the
220
clock to be square, even if the device isn't.
221
222
This will give us a 200 x 200 square area, with the origin (0, 0)
223
in the center, that we can draw on. What we draw will show up in
224
the largest possible square that will fit in the widget.
225
226
See also the \l {Window-Viewport Conversion} section.
227
228
\snippet ../widgets/widgets/analogclock/analogclock.cpp 18
229
230
We draw the clock's hour hand by rotating the coordinate system
231
and calling QPainter::drawConvexPolygon(). Thank's to the
232
rotation, it's drawn pointed in the right direction.
233
234
The polygon is specified as an array of alternating \e x, \e y
235
values, stored in the \c hourHand static variable (defined at the
236
beginning of the function), which corresponds to the three points
237
(7, 8), (-7, 8), (0, -40).
238
239
The calls to QPainter::save() and QPainter::restore() surrounding
240
the code guarantees that the code that follows won't be disturbed
241
by the transformations we've used.
242
243
\snippet ../widgets/widgets/analogclock/analogclock.cpp 21
244
245
After that, we draw the hour markers for the clock face, which
246
consists of twelve short lines at 30-degree intervals. When that
247
loop is done, the painter has been rotated a full circle back to
248
its original state, so we don't need to save and restore the state.
249
250
\snippet ../widgets/widgets/analogclock/analogclock.cpp 24
251
252
We do the same for the clock's minute hand, which is defined by
253
the three points (7, 8), (-7, 8), (0, -70). These
254
coordinates specify a hand that is thinner and longer than the
255
minute hand.
256
257
\snippet ../widgets/widgets/analogclock/analogclock.cpp 27
258
259
Finally, we draw the minute markers for the clock face, which
260
consists of sixty short lines at 6-degree intervals. We skip every
261
fifth minute marker because we don't want to draw over the hour
262
markers. At the end of that, the painter is rotated in a way which
263
isn't very useful, but we're done with painting so that doesn't
264
matter.
265
\endtable
266
267
For more information about the transformation matrix, see the
268
QTransform documentation.
269
270
\section1 Window-Viewport Conversion
271
272
When drawing with QPainter, we specify points using logical
273
coordinates which then are converted into the physical coordinates
274
of the paint device.
275
276
The mapping of the logical coordinates to the physical coordinates
277
are handled by QPainter's world transformation \l
278
{QPainter::worldTransform()}{worldTransform()} (described in the \l
279
Transformations section), and QPainter's \l
280
{QPainter::viewport()}{viewport()} and \l
281
{QPainter::window()}{window()}. The viewport represents the
282
physical coordinates specifying an arbitrary rectangle. The
283
"window" describes the same rectangle in logical coordinates. By
284
default the logical and physical coordinate systems coincide, and
285
are equivalent to the paint device's rectangle.
286
287
Using window-viewport conversion you can make the logical
288
coordinate system fit your preferences. The mechanism can also be
289
used to make the drawing code independent of the paint device. You
290
can, for example, make the logical coordinates extend from (-50,
291
-50) to (50, 50) with (0, 0) in the center by calling the
292
QPainter::setWindow() function:
293
294
\snippet code/doc_src_coordsys.cpp 4
295
296
Now, the logical coordinates (-50,-50) correspond to the paint
297
device's physical coordinates (0, 0). Independent of the paint
298
device, your painting code will always operate on the specified
299
logical coordinates.
300
301
By setting the "window" or viewport rectangle, you perform a
302
linear transformation of the coordinates. Note that each corner of
303
the "window" maps to the corresponding corner of the viewport, and
304
vice versa. For that reason it normally is a good idea to let the
305
viewport and "window" maintain the same aspect ratio to prevent
306
deformation:
307
308
\snippet code/doc_src_coordsys.cpp 5
309
310
If we make the logical coordinate system a square, we should also
311
make the viewport a square using the QPainter::setViewport()
312
function. In the example above we make it equivalent to the
313
largest square that fit into the paint device's rectangle. By
314
taking the paint device's size into consideration when setting the
315
window or viewport, it is possible to keep the drawing code
316
independent of the paint device.
317
318
Note that the window-viewport conversion is only a linear
319
transformation, i.e. it does not perform clipping. This means that
320
if you paint outside the currently set "window", your painting is
321
still transformed to the viewport using the same linear algebraic
322
approach.
323
324
\image coordinatesystem-transformations.png {Illustration showing
325
how coordinates are mapped using viewport, "window" and
326
transformation matrix}
327
328
The viewport, "window" and transformation matrix determine how
329
logical QPainter coordinates map to the paint device's physical
330
coordinates. By default the world transformation matrix is the
331
identity matrix, and the "window" and viewport settings are
332
equivalent to the paint device's settings, i.e. the world,
333
"window" and device coordinate systems are equivalent, but as we
334
have seen, the systems can be manipulated using transformation
335
operations and window-viewport conversion. The illustration above
336
describes the process.
337
338
\omit
339
\section1 Related Classes
340
341
Qt's paint system, Arthur, is primarily based on the QPainter,
342
QPaintDevice, and QPaintEngine classes:
343
344
\table
345
\header \li Class \li Description
346
\row
347
\li QPainter
348
\li
349
The QPainter class performs low-level painting on widgets and
350
other paint devices. QPainter can operate on any object that
351
inherits the QPaintDevice class, using the same code.
352
\row
353
\li QPaintDevice
354
\li
355
The QPaintDevice class is the base class of objects that can be
356
painted. Qt provides several devices: QWidget, QImage, QPixmap,
357
QPrinter and QPicture, and other devices can also be defined by
358
subclassing QPaintDevice.
359
\row
360
\li QPaintEngine
361
\li
362
The QPaintEngine class provides an abstract definition of how
363
QPainter draws to a given device on a given platform. Qt 4
364
provides several premade implementations of QPaintEngine for the
365
different painter backends we support; it provides one paint
366
engine for each supported window system and painting
367
frameworkt. You normally don't need to use this class directly.
368
\endtable
369
370
The 2D transformations of the coordinate system are specified
371
using the QTransform class:
372
373
\table
374
\header \li Class \li Description
375
\row
376
\li QTransform
377
\li
378
A 3 x 3 transformation matrix. Use QTransform to rotate, shear,
379
scale, or translate the coordinate system.
380
\endtable
381
382
In addition Qt provides several graphics primitive classes. Some
383
of these classes exist in two versions: an \c{int}-based version
384
and a \c{qreal}-based version. For these, the \c qreal version's
385
name is suffixed with an \c F.
386
387
\table
388
\header \li Class \li Description
389
\row
390
\li \l{QPoint}(\l{QPointF}{F})
391
\li
392
A single 2D point in the coordinate system. Most functions in Qt
393
that deal with points can accept either a QPoint, a QPointF, two
394
\c{int}s, or two \c{qreal}s.
395
\row
396
\li \l{QSize}(\l{QSizeF}{F})
397
\li
398
A single 2D vector. Internally, QPoint and QSize are the same, but
399
a point is not the same as a size, so both classes exist. Again,
400
most functions accept either QSizeF, a QSize, two \c{int}s, or two
401
\c{qreal}s.
402
\row
403
\li \l{QRect}(\l{QRectF}{F})
404
\li
405
A 2D rectangle. Most functions accept either a QRectF, a QRect,
406
four \c{int}s, or four \c {qreal}s.
407
\row
408
\li \l{QLine}(\l{QLineF}{F})
409
\li
410
A 2D finite-length line, characterized by a start point and an end
411
point.
412
\row
413
\li \l{QPolygon}(\l{QPolygonF}{F})
414
\li
415
A 2D polygon. A polygon is a vector of \c{QPoint(F)}s. If the
416
first and last points are the same, the polygon is closed.
417
\row
418
\li QPainterPath
419
\li
420
A vectorial specification of a 2D shape. Painter paths are the
421
ultimate painting primitive, in the sense that any shape
422
(rectangle, ellipse, spline) or combination of shapes can be
423
expressed as a path. A path specifies both an outline and an area.
424
\row
425
\li QRegion
426
\li
427
An area in a paint device, expressed as a list of
428
\l{QRect}s. In general, we recommend using the vectorial
429
QPainterPath class instead of QRegion for specifying areas,
430
because QPainterPath handles painter transformations much better.
431
\endtable
432
\endomit
433
434
\sa {Analog Clock}
435
*/
qtbase
src
gui
doc
src
coordsys.qdoc
Generated on
for Qt by
1.14.0