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