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*/