1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Qt Toolkit - The Coordinate System</title><style type="text/css"><!--
h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }
a:link { color: #004faf; text-decoration: none }
a:visited { color: #672967; text-decoration: none }body { background: white; color: black; }
--></style></head><body bgcolor="#ffffff">
<p>
<table width="100%">
<tr><td><a href="index.html">
<img width="100" height="100" src="qtlogo.png"
alt="Home" border="0"><img width="100"
height="100" src="face.png" alt="Home" border="0">
</a><td valign=top><div align=right><img src="dochead.png" width="472" height="27"><br>
<a href="classes.html"><b>Classes</b></a>
-<a href="annotated.html">Annotated</a>
- <a href="hierarchy.html">Tree</a>
-<a href="functions.html">Functions</a>
-<a href="index.html">Home</a>
-<a href="topicals.html"><b>Structure</b></a>
</div>
</table>
<h1 align=center> The Coordinate System</h1><br clear="all">
A <a href="qpaintdevice.html">paint device</a> in Qt is a drawable 2D
surface. <a href="qwidget.html">QWidget</a>, <a href="qpixmap.html">QPixmap</a>, <a href="qpicture.html">QPicture</a> and <a href="qprinter.html">QPrinter</a> are all
paint devices. A <a href="qpainter.html">QPainter</a> is an object to draw on such surfaces.
<p>
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.
<p>
<h2>An Example</h2>
<p>
The illustration below shows a strongly magnified portion of the top
left corner of a paint device.
<p>
<img src="coordsys.png" width="342" height="340">
<p>
The rectangle and the line were drawn by this code (with the grid
added and colors touched up afterwards):
<p>
<pre> void MyWidget::paintEvent( <a href="qpaintevent.html">QPaintEvent</a> * )
{
<a href="qpainter.html">QPainter</a> p( this );
p.<a href="qpainter.html#0183e4">setPen</a>( lightGray );
p.<a href="qpainter.html#4c0077">drawRect</a>( 1,2, 5,4 );
p.<a href="qpainter.html#0183e4">setPen</a>( darkGray );
p.<a href="qpainter.html#e3a489">drawLine</a>( 9,2, 7,7 );
}
</pre>
<p>
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 the pixels drawn. This
applies to all the relevant function in QPainter.
<p>
Similarly, the drawLine() call draws both endpoints of the line, not
just one.
<p>
Here are the classes that relate most closely to the coordinate
system: <ul>
<li> <a href="qpoint.html">QPoint</a> is a single 2D point in the coordinate system. Most
functions in Qt that deal with points can accept both a QPoint
argument and two ints, for example <a href="qpainter.html#8e172b">QPainter::drawPoint()</a>.
<li> <a href="qsize.html">QSize</a> is 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 both a QSize and two ints, for
example <a href="qwidget.html#8fcbbe">QWidget::resize()</a>.
<li> <a href="qrect.html">QRect</a> is a 2D rectangle. Most functions accept both a QRect
and four ints, for example <a href="qwidget.html#9ede68">QWidget::setGeometry()</a>.
<li> <a href="qregion.html">QRegion</a> is an arbitrary set of points, including all the
normal set operations, e.g. <a href="qregion.html#28e973">QRegion::intersect()</a>, 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 <a href="qpainter.html#15cc78">QPainter::setClipRegion()</a>, <a href="qwidget.html#7569b1">QWidget::repaint()</a> and <a href="qpaintevent.html#dc5fc5">QPaintEvent::region()</a>.
<li> <a href="qpainter.html">QPainter</a> is the class that paints. It can paint on any device
with the same code. There are differences between devices, <a href="qprinter.html#d4f693">QPrinter::newPage()</a> is a good example, but QPainter works the same way
on all devices.
<li> <a href="qpaintdevice.html">QPaintDevice</a> is a device on which QPainter can paint. There
are two internal devices, both pixel-based, and two external devices,
<a href="qprinter.html">QPrinter</a> and <a href="qpicture.html">QPicture</a> (which records QPainter commands to a file
or other <a href="qiodevice.html">QIODevice</a>, and plays them back). Other devices can be
defined.
<p>
</ul>
<p>
<h2>Transformations</h2>
<p>
While Qt's default coordinate system is as described above, <a href="qpainter.html">QPainter</a> supports arbitrary transformations.
<p>
This transformation engine is a three-step pipeline, closely following
the model outlined in books such as
<a href="http://www.amazon.com/exec/obidos/ASIN/0201848406/trolltech/t">
Foley & Van Dam</a> and the
<a href="http://www.amazon.com/exec/obidos/ASIN/0201604582/trolltech/t">
OpenGL Programming Guide.</a> We refer to those for an in-depth
coverage; here we give just a brief overview and an example.
<p>
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 <a href="qpainter.html#b5205c">QPainter::rotate()</a>, <a href="qpainter.html#e5ec3e">QPainter::scale()</a>, <a href="qpainter.html#eb778c">QPainter::translate()</a> and so on to operate on this matrix.
<p>
<a href="qpainter.html#938d23">QPainter::save()</a> and <a href="qpainter.html#ddb3f4">QPainter::restore()</a> save and restore this
matrix. You can also use <a href="qwmatrix.html">QWMatrix</a> objects, <a href="qpainter.html#e876ac">QPainter::worldMatrix()</a> and <a href="qpainter.html#862c4d">QPainter::setWorldMatrix()</a> to store and
use named matrices.
<p>
The second step uses the window. The window describes the view
boundaries in model coordinates. The matrix positions the <em>objects</em>
and <a href="qpainter.html#ad8b2b">QPainter::setWindow()</a> positions the <em>window,</em> deciding what
coordinates will be visible. (If you have 3D experience, the window
is what's usually called projection in 3D.)
<p>
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.
<p>
On-screen, the default is the entire <a href="qwidget.html">QWidget</a> or <a href="qpixmap.html">QPixmap</a> where
you are drawing, which is mostly suitable. For printing this function
is vital, since very few printers even <em>can</em> print on the entire
paper.
<p>
So in short, each object to be drawn is transformed into model
coordinates using <a href="qpainter.html#e876ac">QPainter::worldMatrix()</a>, then clipped by <a href="qpainter.html#99513c">QPainter::window()</a>, and finally positioned on the drawing device using
<a href="qpainter.html#3ea58a">QPainter::viewport()</a>.
<p>
It is perfectly possible to do without one or two of the stages. If,
for example, your goal is to draw something scaled, then using just <a href="qpainter.html#e5ec3e">QPainter::scale()</a> makes perfect sense. If your goal is to use a
fixed-size coordinate system, just <a href="qpainter.html#ad8b2b">QPainter::setWindow()</a> is
perfect. And so on.
<p>
Here is a short example that uses all three mechanisms: the function
that draws the clock face in the aclock/aclock.cpp example. We
recommend compiling and running the example before you read any
further. In particular, try resizing the window to different shapes. <pre>
void AnalogClock::drawClock( <a href="qpainter.html">QPainter</a> *paint )
{
paint-><a href="qpainter.html#938d23">save</a>();
</pre>
<p>
First off, 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. <pre>
paint-><a href="qpainter.html#ad8b2b">setWindow</a>( -500,-500, 1000,1000 );
</pre>
<p>
We set the model coordinate system we want: A 1000*1000 window where
0,0 is in the middle. <pre>
<a href="qrect.html">QRect</a> v = paint-><a href="qpainter.html#3ea58a">viewport</a>();
int d = QMIN( v.<a href="qrect.html#45fe95">width</a>(), v.<a href="qrect.html#581ab8">height</a>() );
</pre>
<p>
The device may not be square and we want the clock to be, so we find
its current viewport and compute its shortest side. <pre>
paint-><a href="qpainter.html#42d67a">setViewport</a>( v.<a href="qrect.html#369cab">left</a>() + (v.<a href="qrect.html#45fe95">width</a>()-d)/2,
v.<a href="qrect.html#4dd27e">top</a>() + (v.<a href="qrect.html#581ab8">height</a>()-d)/2, d, d );
</pre>
<p>
Then we set a new square viewport, centered in the old one.
<p>
We're now done with our view. From this point in, when we draw in a
1000*1000 area around 0,0, what we draw will show up in the biggest
possible square that'll fit in the output device.
<p>
Time to start drawing. <pre>
time = QTime::currentTime();
<a href="qpointarray.html">QPointArray</a> pts;
</pre>
<p>
Since we'll draw a clock, we'll need to know the time. <em>pts</em> is just
a utility variable to hold some points.
<p>
Next comes 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: <pre>
paint-><a href="qpainter.html#938d23">save</a>();
paint-><a href="qpainter.html#b5205c">rotate</a>( 30*(time.hour()%12-3) + time.minute()/2 );
</pre>
<p>
We save the painter and then rotate it so that one axis points along
the hour hand. <pre>
pts.<a href="qpointarray.html#76de1d">setPoints</a>( 4, -20,0, 0,-20, 300,0, 0,20 );
paint-><a href="qpainter.html#2efe17">drawPolygon</a>( pts );
</pre>
<p>
We set <em>pts</em> 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. <pre>
paint-><a href="qpainter.html#ddb3f4">restore</a>();
</pre>
<p>
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: <pre>
paint-><a href="qpainter.html#938d23">save</a>();
paint-><a href="qpainter.html#b5205c">rotate</a>( (time.minute()-15)*6 );
pts.<a href="qpointarray.html#76de1d">setPoints</a>( 4, -10,0, 0,-10, 400,0, 0,10 );
paint-><a href="qpainter.html#2efe17">drawPolygon</a>( pts );
paint-><a href="qpainter.html#ddb3f4">restore</a>();
</pre>
<p>
The only differences are how the rotation angle is computed and the
shape of the polygon.
<p>
The last part to be drawn is the clock face itself. <pre>
for ( int i=0; i<12; i++ ) {
paint-><a href="qpainter.html#e3a489">drawLine</a>( 440,0, 460,0 );
paint-><a href="qpainter.html#b5205c">rotate</a>( 30 );
}
</pre>
<p>
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. <pre>
paint-><a href="qpainter.html#ddb3f4">restore</a>();
}
</pre>
<p>
The final line of the function restores the painter, so that the
caller won't be bothered by all the transformations we've done.
<p><address><hr><div align="center">
<table width="100%" cellspacing="0" border="0"><tr>
<td>Copyright 2001 Trolltech<td><a href="http://www.trolltech.com/trademarks.html">Trademarks</a>
<td align="right"><div align="right">Qt version 2.3.2</div>
</table></div></address></body></html>
|