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