You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
9.2 KiB
263 lines
9.2 KiB
13 years ago
|
/****************************************************************************
|
||
|
**
|
||
|
** 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.
|
||
|
|
||
|
*/
|