Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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 \tableofcontents
35
36 \section1 Rendering
37
38 \section2 Logical Representation
39
40 The size (width and height) of a graphics primitive always
41 correspond to its mathematical model, ignoring the width of the
42 pen it is rendered with:
43
44 \table
45 \row
46 \li \inlineimage coordinatesystem-rect.png
47 \li \inlineimage coordinatesystem-line.png
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.png
79 \li \inlineimage coordinatesystem-line-raster.png
80
81 \row
82 \li
83 \snippet code/doc_src_coordsys.cpp 0
84
85 \li
86 \snippet code/doc_src_coordsys.cpp 1
87 \endtable
88
89 When rendering with a pen with an even number of pixels, the
90 pixels will be rendered symmetrically around the mathematical
91 defined points, while rendering with a pen with an odd number of
92 pixels, the spare pixel will be rendered to the right and below
93 the mathematical point as in the one pixel case. See the QRectF
94 diagrams below for concrete examples.
95
96 \table
97 \header
98 \li {2,1} QRectF
99 \row
100 \li \inlineimage qrect-diagram-zero.png
101 \li \inlineimage qrectf-diagram-one.png
102 \row
103 \li Logical representation
104 \li One pixel wide pen
105 \row
106 \li \inlineimage qrectf-diagram-two.png
107 \li \inlineimage qrectf-diagram-three.png
108 \row
109 \li Two pixel wide pen
110 \li Three pixel wide pen
111 \endtable
112
113 Note that for historical reasons the return value of the
114 QRect::right() and QRect::bottom() functions deviate from the true
115 bottom-right corner of the rectangle.
116
117 QRect's \l {QRect::right()}{right()} function returns \l
118 {QRect::left()}{left()} + \l {QRect::width()}{width()} - 1 and the
119 \l {QRect::bottom()}{bottom()} function returns \l
120 {QRect::top()}{top()} + \l {QRect::height()}{height()} - 1. The
121 bottom-right green point in the diagrams shows the return
122 coordinates of these functions.
123
124 We recommend that you simply use QRectF instead: The QRectF class
125 defines a rectangle in the plane using floating point coordinates
126 for accuracy (QRect uses integer coordinates), and the
127 QRectF::right() and QRectF::bottom() functions \e do return the
128 true bottom-right corner.
129
130 Alternatively, using QRect, apply \l {QRect::x()}{x()} + \l
131 {QRect::width()}{width()} and \l {QRect::y()}{y()} + \l
132 {QRect::height()}{height()} to find the bottom-right corner, and
133 avoid the \l {QRect::right()}{right()} and \l
134 {QRect::bottom()}{bottom()} functions.
135
136 \section2 Anti-aliased Painting
137
138 If you set QPainter's \l {QPainter::Antialiasing}{anti-aliasing}
139 render hint, the pixels will be rendered symmetrically on both
140 sides of the mathematically defined points:
141
142 \table
143 \row
144 \li \inlineimage coordinatesystem-rect-antialias.png
145 \li \inlineimage coordinatesystem-line-antialias.png
146 \row
147 \li
148
149 \snippet code/doc_src_coordsys.cpp 2
150
151 \li
152 \snippet code/doc_src_coordsys.cpp 3
153 \endtable
154
155 \section1 Transformations
156
157 By default, the QPainter operates on the associated device's own
158 coordinate system, but it also has complete support for affine
159 coordinate transformations.
160
161 You can scale the coordinate system by a given offset using the
162 QPainter::scale() function, you can rotate it clockwise using the
163 QPainter::rotate() function and you can translate it (i.e. adding
164 a given offset to the points) using the QPainter::translate()
165 function.
166
167 \table
168 \row
169 \li \inlineimage qpainter-clock.png
170 \li \inlineimage qpainter-rotation.png
171 \li \inlineimage qpainter-scale.png
172 \li \inlineimage qpainter-translation.png
173 \row
174 \li nop
175 \li \l {QPainter::rotate()}{rotate()}
176 \li \l {QPainter::scale()}{scale()}
177 \li \l {QPainter::translate()}{translate()}
178 \endtable
179
180 You can also twist the coordinate system around the origin using
181 the QPainter::shear() function. All the transformation operations
182 operate on QPainter's transformation matrix that you can retrieve
183 using the QPainter::worldTransform() function. A matrix transforms
184 a point in the plane to another point.
185
186 If you need the same transformations over and over, you can also
187 use QTransform objects and the QPainter::worldTransform() and
188 QPainter::setWorldTransform() functions. You can at any time save the
189 QPainter's transformation matrix by calling the QPainter::save()
190 function which saves the matrix on an internal stack. The
191 QPainter::restore() function pops it back.
192
193 One frequent need for the transformation matrix is when reusing
194 the same drawing code on a variety of paint devices. Without
195 transformations, the results are tightly bound to the resolution
196 of the paint device. Printers have high resolution, e.g. 600 dots
197 per inch, whereas screens often have between 72 and 100 dots per
198 inch.
199
200 \table 100%
201 \header
202 \li {2,1} Analog Clock Example
203 \row
204 \li \inlineimage coordinatesystem-analogclock.png
205 \li
206 The Analog Clock example shows how to draw the contents of a
207 custom widget using QPainter's transformation matrix.
208
209 We recommend compiling and running this example before you read
210 any further. In particular, try resizing the window to different
211 sizes.
212
213 \row
214 \li {2,1}
215
216 \snippet ../widgets/widgets/analogclock/analogclock.cpp 9
217
218 We translate the coordinate system so that point (0, 0) is in the
219 widget's center, instead of being at the top-left corner. We also
220 scale the system by \c side / 200, where \c side is either the
221 widget's width or the height, whichever is shortest. We want the
222 clock to be square, even if the device isn't.
223
224 This will give us a 200 x 200 square area, with the origin (0, 0)
225 in the center, that we can draw on. What we draw will show up in
226 the largest possible square that will fit in the widget.
227
228 See also the \l {Window-Viewport Conversion} section.
229
230 \snippet ../widgets/widgets/analogclock/analogclock.cpp 18
231
232 We draw the clock's hour hand by rotating the coordinate system
233 and calling QPainter::drawConvexPolygon(). Thank's to the
234 rotation, it's drawn pointed in the right direction.
235
236 The polygon is specified as an array of alternating \e x, \e y
237 values, stored in the \c hourHand static variable (defined at the
238 beginning of the function), which corresponds to the three points
239 (7, 8), (-7, 8), (0, -40).
240
241 The calls to QPainter::save() and QPainter::restore() surrounding
242 the code guarantees that the code that follows won't be disturbed
243 by the transformations we've used.
244
245 \snippet ../widgets/widgets/analogclock/analogclock.cpp 21
246
247 After that, we draw the hour markers for the clock face, which
248 consists of twelve short lines at 30-degree intervals. When that
249 loop is done, the painter has been rotated a full circle back to
250 its original state, so we don't need to save and restore the state.
251
252 \snippet ../widgets/widgets/analogclock/analogclock.cpp 24
253
254 We do the same for the clock's minute hand, which is defined by
255 the three points (7, 8), (-7, 8), (0, -70). These
256 coordinates specify a hand that is thinner and longer than the
257 minute hand.
258
259 \snippet ../widgets/widgets/analogclock/analogclock.cpp 27
260
261 Finally, we draw the minute markers for the clock face, which
262 consists of sixty short lines at 6-degree intervals. We skip every
263 fifth minute marker because we don't want to draw over the hour
264 markers. At the end of that, the painter is rotated in a way which
265 isn't very useful, but we're done with painting so that doesn't
266 matter.
267 \endtable
268
269 For more information about the transformation matrix, see the
270 QTransform documentation.
271
272 \section1 Window-Viewport Conversion
273
274 When drawing with QPainter, we specify points using logical
275 coordinates which then are converted into the physical coordinates
276 of the paint device.
277
278 The mapping of the logical coordinates to the physical coordinates
279 are handled by QPainter's world transformation \l
280 {QPainter::worldTransform()}{worldTransform()} (described in the \l
281 Transformations section), and QPainter's \l
282 {QPainter::viewport()}{viewport()} and \l
283 {QPainter::window()}{window()}. The viewport represents the
284 physical coordinates specifying an arbitrary rectangle. The
285 "window" describes the same rectangle in logical coordinates. By
286 default the logical and physical coordinate systems coincide, and
287 are equivalent to the paint device's rectangle.
288
289 Using window-viewport conversion you can make the logical
290 coordinate system fit your preferences. The mechanism can also be
291 used to make the drawing code independent of the paint device. You
292 can, for example, make the logical coordinates extend from (-50,
293 -50) to (50, 50) with (0, 0) in the center by calling the
294 QPainter::setWindow() function:
295
296 \snippet code/doc_src_coordsys.cpp 4
297
298 Now, the logical coordinates (-50,-50) correspond to the paint
299 device's physical coordinates (0, 0). Independent of the paint
300 device, your painting code will always operate on the specified
301 logical coordinates.
302
303 By setting the "window" or viewport rectangle, you perform a
304 linear transformation of the coordinates. Note that each corner of
305 the "window" maps to the corresponding corner of the viewport, and
306 vice versa. For that reason it normally is a good idea to let the
307 viewport and "window" maintain the same aspect ratio to prevent
308 deformation:
309
310 \snippet code/doc_src_coordsys.cpp 5
311
312 If we make the logical coordinate system a square, we should also
313 make the viewport a square using the QPainter::setViewport()
314 function. In the example above we make it equivalent to the
315 largest square that fit into the paint device's rectangle. By
316 taking the paint device's size into consideration when setting the
317 window or viewport, it is possible to keep the drawing code
318 independent of the paint device.
319
320 Note that the window-viewport conversion is only a linear
321 transformation, i.e. it does not perform clipping. This means that
322 if you paint outside the currently set "window", your painting is
323 still transformed to the viewport using the same linear algebraic
324 approach.
325
326 \image coordinatesystem-transformations.png
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*/