diff options
Diffstat (limited to 'doc/coordsys.doc')
-rw-r--r-- | doc/coordsys.doc | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/doc/coordsys.doc b/doc/coordsys.doc new file mode 100644 index 000000000..f614116a3 --- /dev/null +++ b/doc/coordsys.doc @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Qt Coordinate System Documentation +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing retquirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +/*! +\page coordsys.html + +\title The Coordinate System + +A \link QPaintDevice paint device\endlink in Qt is a drawable 2D +surface. \l QWidget, \l QPixmap, \l QPicture and \l QPrinter are all +paint devices. A \l QPainter is an object which can draw on such +devices. + +The default coordinate system of a paint device has its origin at the +top left corner. X increases to the right and Y increases downwards. +The unit is one pixel on pixel-based devices and one point on +printers. + +\section1 An Example + +The illustration below shows a highly magnified portion of the top +left corner of a paint device. + +\img coordsys.png + +The rectangle and the line were drawn by this code (with the grid +added and colors touched up in the illustration): + +\code + void MyWidget::paintEvent( QPaintEvent * ) + { + QPainter p( this ); + p.setPen( darkGray ); + p.drawRect( 1,2, 5,4 ); + p.setPen( lightGray ); + p.drawLine( 9,2, 7,7 ); + } +\endcode + +Note that all of the pixels drawn by drawRect() are inside the size +specified (5*4 pixels). This is different from some toolkits; in Qt +the size you specify exactly encompasses the pixels drawn. This +applies to all the relevant functions in QPainter. + +Similarly, the drawLine() call draws both endpoints of the line, not +just one. + +Here are the classes that relate most closely to the coordinate +system: + +\table + +\row \i \l QPoint + \i A single 2D point in the coordinate system. Most functions in + Qt that deal with points can accept either a QPoint argument + or two ints, for example \l QPainter::drawPoint(). +\row \i \l QSize + \i A single 2D vector. Internally, QPoint and QSize are the same, + but a point is not the same as a size, so both classes exist. + Again, most functions accept either a QSize or two ints, for + example \l QWidget::resize(). +\row \i \l QRect + \i A 2D rectangle. Most functions accept either a QRect or four + ints, for example \l QWidget::setGeometry(). +\row \i \l QRegion + \i An arbitrary set of points, including all the normal set + operations, e.g. \l QRegion::intersect(), and also a less + usual function to return a list of rectangles whose union is + equal to the region. QRegion is used e.g. by \l + QPainter::setClipRegion(), \l QWidget::repaint() and \l + QPaintEvent::region(). +\row \i \l QPainter + \i The class that paints. It can paint on any device with the + same code. There are differences between devices, \l + QPrinter::newPage() is a good example, but QPainter works the + same way on all devices. +\row \i \l QPaintDevice + \i A device on which QPainter can paint. There are two internal + devices, both pixel-based, and two external devices, \l + QPrinter and \l QPicture (which records QPainter commands to a + file or other \l QIODevice, and plays them back). Other + devices can be defined. +\endtable + +\section1 Transformations + +Although Qt's default coordinate system works as described above, \l +QPainter also supports arbitrary transformations. + +This transformation engine is a three-step pipeline, closely following +the model outlined in books such as +\link http://www.amazon.com/exec/obidos/ASIN/0201848406/trolltech/t +Foley \& Van Dam \endlink and the +\link http://www.amazon.com/exec/obidos/ASIN/0201604582/trolltech/t +OpenGL Programming Guide.\endlink Refer to those for in-depth +coverage; here we give just a brief overview and an example. + +The first step uses the world transformation matrix. Use this matrix +to orient and position your objects in your model. Qt provides +methods such as \l QPainter::rotate(), \l QPainter::scale(), \l +QPainter::translate() and so on to operate on this matrix. + +\l QPainter::save() and \l QPainter::restore() save and restore this +matrix. You can also use \l QWMatrix objects, \l +QPainter::worldMatrix() and \l QPainter::setWorldMatrix() to store and +use named matrices. + +The second step uses the window. The window describes the view +boundaries in model coordinates. The matrix positions the \e objects +and \l QPainter::setWindow() positions the \e window, deciding what +coordinates will be visible. (If you have 3D experience, the window +is what's usually called projection in 3D.) + +The third step uses the viewport. The viewport too, describes the view +boundaries, but in device coordinates. The viewport and the windows +describe the same rectangle, but in different coordinate systems. + +On-screen, the default is the entire \l QWidget or \l QPixmap where +you are drawing, which is usually appropriate. For printing this +function is vital, since very few printers can print over the entire +physical page. + +So each object to be drawn is transformed into model +coordinates using \l QPainter::worldMatrix(), then positioned +on the drawing device using \l QPainter::window() and +\l QPainter::viewport(). + +It is perfectly possible to do without one or two of the stages. If, +for example, your goal is to draw something scaled, then just using \l +QPainter::scale() makes perfect sense. If your goal is to use a +fixed-size coordinate system, \l QPainter::setWindow() is +ideal. And so on. + +Here is a short example that uses all three mechanisms: the function +that draws the clock face in the \l aclock/aclock.cpp example. We +recommend compiling and running the example before you read any +further. In particular, try resizing the window to different sizes. + +\quotefile aclock/aclock.cpp +\skipto ::drawClock +\printline ::drawClock +\printline { +\printline save + +Firstly, we save the painter's state, so that the calling function +is guaranteed not to be disturbed by the transformations we're going +to use. + +\printline setWindow + +We set the model coordinate system we want a 1000*1000 window where +0,0 is in the middle. + +\printline viewport +\printline QMIN + +The device may not be square and we want the clock to be, so we find +its current viewport and compute its shortest side. + +\printline setViewport +\printline height + +Then we set a new square viewport, centered in the old one. + +We're now done with our view. From this point on, when we draw in a +1000*1000 area around 0,0, what we draw will show up in the largest +possible square that'll fit in the output device. + +Time to start drawing. + +\skipto pts +\printline pts + +\e pts is just a temporary variable to hold some points. + +Next come three drawing blocks, one for the hour hand, one for the +minute hand and finally one for the clock face itself. First we draw +the hour hand: + +\skipto save +\printline save +\printline rotate + +We save the painter and then rotate it so that one axis points along +the hour hand. + +\printline setPoints +\printline drawConvexPolygon + +We set \e pts to a four-point polygon that looks like the hour hand at +three o'clock, and draw it. Because of the rotation, it's drawn +pointed in the right direction. + +\printline restore + +We restore the saved painter, undoing the rotation. We could also +call rotate( -30 ) but that might introduce rounding errors, so it's +better to use save() and restore(). Next, the minute hand, drawn +almost the same way: + +\printline save +\printline rotate +\printline setPoints +\printline drawConvexPolygon +\printline restore + +The only differences are how the rotation angle is computed and the +shape of the polygon. + +The last part to be drawn is the clock face itself. + +\printline for +\printline drawLine +\printline rotate +\printline } + +Twelve short hour lines at thirty-degree intervals. At the end of +that, the painter is rotated in a way which isn't very useful, but +we're done with painting so that doesn't matter. + +\printline restore +\printline } + +The final line of the function restores the painter, so that the +caller won't be affected by all the transformations we've done. + +*/ |