source: vendor/trolltech/current/src/kernel/qpointarray.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 28.4 KB
Line 
1/****************************************************************************
2** $Id: qpointarray.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QPointArray class
5**
6** Created : 940213
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qpointarray.h"
39#include "qrect.h"
40#include "qdatastream.h"
41#include "qwmatrix.h"
42#include <stdarg.h>
43
44const double Q_PI = 3.14159265358979323846; // pi // one more useful comment
45
46
47/*!
48 \class QPointArray qpointarray.h
49 \brief The QPointArray class provides an array of points.
50
51 \ingroup images
52 \ingroup graphics
53 \ingroup shared
54
55 A QPointArray is an array of QPoint objects. In addition to the
56 functions provided by QMemArray, QPointArray provides some
57 point-specific functions.
58
59 For convenient reading and writing of the point data use
60 setPoints(), putPoints(), point(), and setPoint().
61
62 For geometry operations use boundingRect() and translate(). There
63 is also the QWMatrix::map() function for more general
64 transformations of QPointArrays. You can also create arcs and
65 ellipses with makeArc() and makeEllipse().
66
67 Among others, QPointArray is used by QPainter::drawLineSegments(),
68 QPainter::drawPolyline(), QPainter::drawPolygon() and
69 QPainter::drawCubicBezier().
70
71 Note that because this class is a QMemArray, copying an array and
72 modifying the copy modifies the original as well, i.e. a shallow
73 copy. If you need a deep copy use copy() or detach(), for example:
74
75 \code
76 void drawGiraffe( const QPointArray & r, QPainter * p )
77 {
78 QPointArray tmp = r;
79 tmp.detach();
80 // some code that modifies tmp
81 p->drawPoints( tmp );
82 }
83 \endcode
84
85 If you forget the tmp.detach(), the const array will be modified.
86
87 \sa QPainter QWMatrix QMemArray
88*/
89
90
91/*****************************************************************************
92 QPointArray member functions
93 *****************************************************************************/
94
95/*!
96 \fn QPointArray::QPointArray()
97
98 Constructs a null point array.
99
100 \sa isNull()
101*/
102
103/*!
104 \fn QPointArray::QPointArray( int size )
105
106 Constructs a point array with room for \a size points. Makes a
107 null array if \a size == 0.
108
109 \sa resize(), isNull()
110*/
111
112/*!
113 \fn QPointArray::QPointArray( const QPointArray &a )
114
115 Constructs a shallow copy of the point array \a a.
116
117 \sa copy() detach()
118*/
119
120/*!
121 Constructs a point array from the rectangle \a r.
122
123 If \a closed is FALSE, then the point array just contains the
124 following four points in the listed order: r.topLeft(),
125 r.topRight(), r.bottomRight() and r.bottomLeft().
126
127 If \a closed is TRUE, then a fifth point is set to r.topLeft().
128*/
129
130QPointArray::QPointArray( const QRect &r, bool closed )
131{
132 setPoints( 4, r.left(), r.top(),
133 r.right(), r.top(),
134 r.right(), r.bottom(),
135 r.left(), r.bottom() );
136 if ( closed ) {
137 resize( 5 );
138 setPoint( 4, r.left(), r.top() );
139 }
140}
141
142/*!
143 \internal
144 Constructs a point array with \a nPoints points, taken from the
145 \a points array.
146
147 Equivalent to setPoints(nPoints, points).
148*/
149
150QPointArray::QPointArray( int nPoints, const QCOORD *points )
151{
152 setPoints( nPoints, points );
153}
154
155
156/*!
157 \fn QPointArray::~QPointArray()
158
159 Destroys the point array.
160*/
161
162
163/*!
164 \fn QPointArray &QPointArray::operator=( const QPointArray &a )
165
166 Assigns a shallow copy of \a a to this point array and returns a
167 reference to this point array.
168
169 Equivalent to assign(a).
170
171 \sa copy() detach()
172*/
173
174/*!
175 \fn QPointArray QPointArray::copy() const
176
177 Creates a deep copy of the array.
178
179 \sa detach()
180*/
181
182
183
184/*!
185 Translates all points in the array by \a (dx, dy).
186*/
187
188void QPointArray::translate( int dx, int dy )
189{
190 register QPoint *p = data();
191 register int i = size();
192 QPoint pt( dx, dy );
193 while ( i-- ) {
194 *p += pt;
195 p++;
196 }
197}
198
199
200/*!
201 Reads the coordinates of the point at position \a index within the
202 array and writes them into \a *x and \a *y.
203*/
204
205void QPointArray::point( uint index, int *x, int *y ) const
206{
207 QPoint p = QMemArray<QPoint>::at( index );
208 if ( x )
209 *x = (int)p.x();
210 if ( y )
211 *y = (int)p.y();
212}
213
214/*!
215 \overload
216
217 Returns the point at position \a index within the array.
218*/
219
220QPoint QPointArray::point( uint index ) const
221{ // #### index out of bounds
222 return QMemArray<QPoint>::at( index );
223}
224
225/*!
226 \fn void QPointArray::setPoint( uint i, const QPoint &p )
227
228 \overload
229
230 Sets the point at array index \a i to \a p.
231*/
232
233/*!
234 Sets the point at position \a index in the array to \a (x, y).
235*/
236
237void QPointArray::setPoint( uint index, int x, int y )
238{ // #### index out of bounds
239 QMemArray<QPoint>::at( index ) = QPoint( x, y );
240}
241
242/*!
243 \internal
244 Resizes the array to \a nPoints and sets the points in the array to
245 the values taken from \a points.
246
247 Returns TRUE if successful, or FALSE if the array could not be
248 resized (normally due to lack of memory).
249
250 The example code creates an array with two points (1,2) and (3,4):
251 \code
252 static QCOORD points[] = { 1,2, 3,4 };
253 QPointArray a;
254 a.setPoints( 2, points );
255 \endcode
256
257 \sa resize(), putPoints()
258*/
259
260bool QPointArray::setPoints( int nPoints, const QCOORD *points )
261{
262 if ( !resize(nPoints) )
263 return FALSE;
264 int i = 0;
265 while ( nPoints-- ) { // make array of points
266 setPoint( i++, *points, *(points+1) );
267 points++;
268 points++;
269 }
270 return TRUE;
271}
272
273/*!
274 \overload
275
276 Resizes the array to \a nPoints and sets the points in the array
277 to the values taken from the variable argument list.
278
279 Returns TRUE if successful, or FALSE if the array could not be
280 resized (typically due to lack of memory).
281
282 The example code creates an array with two points (1,2) and (3,4):
283
284 \code
285 QPointArray a;
286 a.setPoints( 2, 1,2, 3,4 );
287 \endcode
288
289 The points are given as a sequence of integers, starting with \a
290 firstx then \a firsty, and so on.
291
292 \sa resize(), putPoints()
293*/
294
295bool QPointArray::setPoints( int nPoints, int firstx, int firsty, ... )
296{
297 va_list ap;
298 if ( !resize(nPoints) )
299 return FALSE;
300 setPoint( 0, firstx, firsty ); // set first point
301 int i = 1, x, y;
302 nPoints--;
303 va_start( ap, firsty );
304 while ( nPoints-- ) {
305 x = va_arg( ap, int );
306 y = va_arg( ap, int );
307 setPoint( i++, x, y );
308 }
309 va_end( ap );
310 return TRUE;
311}
312
313/*! \overload
314 \internal
315 Copies \a nPoints points from the \a points coord array into
316 this point array, and resizes the point array if
317 \c{index+nPoints} exceeds the size of the array.
318
319 Returns TRUE if successful, or FALSE if the array could not be
320 resized (typically due to lack of memory).
321
322*/
323
324bool QPointArray::putPoints( int index, int nPoints, const QCOORD *points )
325{
326 if ( index + nPoints > (int)size() ) { // extend array
327 if ( !resize( index + nPoints ) )
328 return FALSE;
329 }
330 int i = index;
331 while ( nPoints-- ) { // make array of points
332 setPoint( i++, *points, *(points+1) );
333 points++;
334 points++;
335 }
336 return TRUE;
337}
338
339/*!
340 Copies \a nPoints points from the variable argument list into this
341 point array from position \a index, and resizes the point array if
342 \c{index+nPoints} exceeds the size of the array.
343
344 Returns TRUE if successful, or FALSE if the array could not be
345 resized (typically due to lack of memory).
346
347 The example code creates an array with three points (4,5), (6,7)
348 and (8,9), by expanding the array from 1 to 3 points:
349
350 \code
351 QPointArray a( 1 );
352 a[0] = QPoint( 4, 5 );
353 a.putPoints( 1, 2, 6,7, 8,9 ); // index == 1, points == 2
354 \endcode
355
356 This has the same result, but here putPoints overwrites rather
357 than extends:
358 \code
359 QPointArray a( 3 );
360 a.putPoints( 0, 3, 4,5, 0,0, 8,9 );
361 a.putPoints( 1, 1, 6,7 );
362 \endcode
363
364 The points are given as a sequence of integers, starting with \a
365 firstx then \a firsty, and so on.
366
367 \sa resize()
368*/
369
370bool QPointArray::putPoints( int index, int nPoints, int firstx, int firsty,
371 ... )
372{
373 va_list ap;
374 if ( index + nPoints > (int)size() ) { // extend array
375 if ( !resize(index + nPoints) )
376 return FALSE;
377 }
378 if ( nPoints <= 0 )
379 return TRUE;
380 setPoint( index, firstx, firsty ); // set first point
381 int i = index + 1, x, y;
382 nPoints--;
383 va_start( ap, firsty );
384 while ( nPoints-- ) {
385 x = va_arg( ap, int );
386 y = va_arg( ap, int );
387 setPoint( i++, x, y );
388 }
389 va_end( ap );
390 return TRUE;
391}
392
393
394/*!
395 \overload
396
397 This version of the function copies \a nPoints from \a from into
398 this array, starting at \a index in this array and \a fromIndex in
399 \a from. \a fromIndex is 0 by default.
400
401 \code
402 QPointArray a;
403 a.putPoints( 0, 3, 1,2, 0,0, 5,6 );
404 // a is now the three-point array ( 1,2, 0,0, 5,6 );
405 QPointArray b;
406 b.putPoints( 0, 3, 4,4, 5,5, 6,6 );
407 // b is now ( 4,4, 5,5, 6,6 );
408 a.putPoints( 2, 3, b );
409 // a is now ( 1,2, 0,0, 4,4, 5,5, 6,6 );
410 \endcode
411*/
412
413bool QPointArray::putPoints( int index, int nPoints,
414 const QPointArray & from, int fromIndex )
415{
416 if ( index + nPoints > (int)size() ) { // extend array
417 if ( !resize(index + nPoints) )
418 return FALSE;
419 }
420 if ( nPoints <= 0 )
421 return TRUE;
422 int n = 0;
423 while( n < nPoints ) {
424 setPoint( index+n, from[fromIndex+n] );
425 n++;
426 }
427 return TRUE;
428}
429
430
431/*!
432 Returns the bounding rectangle of the points in the array, or
433 QRect(0,0,0,0) if the array is empty.
434*/
435
436QRect QPointArray::boundingRect() const
437{
438 if ( isEmpty() )
439 return QRect( 0, 0, 0, 0 ); // null rectangle
440 register QPoint *pd = data();
441 int minx, maxx, miny, maxy;
442 minx = maxx = pd->x();
443 miny = maxy = pd->y();
444 pd++;
445 for ( int i=1; i<(int)size(); i++ ) { // find min+max x and y
446 if ( pd->x() < minx )
447 minx = pd->x();
448 else if ( pd->x() > maxx )
449 maxx = pd->x();
450 if ( pd->y() < miny )
451 miny = pd->y();
452 else if ( pd->y() > maxy )
453 maxy = pd->y();
454 pd++;
455 }
456 return QRect( QPoint(minx,miny), QPoint(maxx,maxy) );
457}
458
459
460static inline int fix_angle( int a )
461{
462 if ( a > 16*360 )
463 a %= 16*360;
464 else if ( a < -16*360 ) {
465 a = -( (-a) % (16*360) );
466 }
467 return a;
468}
469
470/*!
471 Sets the points of the array to those describing an arc of an
472 ellipse with size, width \a w by height \a h, and position (\a x,
473 \a y), starting from angle \a a1 and spanning by angle \a a2. The
474 resulting array has sufficient resolution for pixel accuracy (see
475 the overloaded function which takes an additional QWMatrix
476 parameter).
477
478 Angles are specified in 16ths of a degree, i.e. a full circle
479 equals 5760 (16*360). Positive values mean counter-clockwise,
480 whereas negative values mean the clockwise direction. Zero degrees
481 is at the 3 o'clock position.
482
483 See the \link qcanvas.html#anglediagram angle diagram\endlink.
484*/
485
486void QPointArray::makeArc( int x, int y, int w, int h, int a1, int a2 )
487{
488#if !defined(QT_OLD_MAKEELLIPSE) && !defined(QT_NO_TRANSFORMATIONS)
489 QWMatrix unit;
490 makeArc(x,y,w,h,a1,a2,unit);
491#else
492 a1 = fix_angle( a1 );
493 if ( a1 < 0 )
494 a1 += 16*360;
495 a2 = fix_angle( a2 );
496 int a3 = a2 > 0 ? a2 : -a2; // abs angle
497 makeEllipse( x, y, w, h );
498 int npts = a3*size()/(16*360); // # points in arc array
499 QPointArray a(npts);
500 int i = a1*size()/(16*360);
501 int j = 0;
502 if ( a2 > 0 ) {
503 while ( npts-- ) {
504 if ( i >= (int)size() ) // wrap index
505 i = 0;
506 a.QMemArray<QPoint>::at( j++ ) = QMemArray<QPoint>::at( i++ );
507 }
508 } else {
509 while ( npts-- ) {
510 if ( i < 0 ) // wrap index
511 i = (int)size()-1;
512 a.QMemArray<QPoint>::at( j++ ) = QMemArray<QPoint>::at( i-- );
513 }
514 }
515 *this = a;
516 return;
517#endif
518}
519
520#ifndef QT_NO_TRANSFORMATIONS
521// Based upon:
522// parelarc.c from Graphics Gems III
523// VanAken / Simar, "A Parametric Elliptical Arc Algorithm"
524//
525static void
526qtr_elips(QPointArray& a, int off, double dxP, double dyP, double dxQ, double dyQ, double dxK, double dyK, int m)
527{
528#define PIV2 102944 /* fixed point PI/2 */
529#define TWOPI 411775 /* fixed point 2*PI */
530#define HALF 32768 /* fixed point 1/2 */
531
532 int xP, yP, xQ, yQ, xK, yK;
533 xP = int(dxP * 65536.0); yP = int(dyP * 65536.0);
534 xQ = int(dxQ * 65536.0); yQ = int(dyQ * 65536.0);
535 xK = int(dxK * 65536.0); yK = int(dyK * 65536.0);
536
537 int i;
538 int vx, ux, vy, uy, xJ, yJ;
539
540 vx = xK - xQ; /* displacements from center */
541 ux = xK - xP;
542 vy = yK - yQ;
543 uy = yK - yP;
544 xJ = xP - vx + HALF; /* center of ellipse J */
545 yJ = yP - vy + HALF;
546
547 int r;
548 ux -= (r = ux >> (2*m + 3)); /* cancel 2nd-order error */
549 ux -= (r >>= (2*m + 4)); /* cancel 4th-order error */
550 ux -= r >> (2*m + 3); /* cancel 6th-order error */
551 ux += vx >> (m + 1); /* cancel 1st-order error */
552 uy -= (r = uy >> (2*m + 3)); /* cancel 2nd-order error */
553 uy -= (r >>= (2*m + 4)); /* cancel 4th-order error */
554 uy -= r >> (2*m + 3); /* cancel 6th-order error */
555 uy += vy >> (m + 1); /* cancel 1st-order error */
556
557 const int qn = a.size()/4;
558 for (i = 0; i < qn; i++) {
559 a[off+i] = QPoint((xJ + vx) >> 16, (yJ + vy) >> 16);
560 ux -= vx >> m;
561 vx += ux >> m;
562 uy -= vy >> m;
563 vy += uy >> m;
564 }
565
566#undef PIV2
567#undef TWOPI
568#undef HALF
569}
570
571
572/*!
573 \overload
574
575 Sets the points of the array to those describing an arc of an
576 ellipse with width \a w and height \a h and position (\a x, \a y),
577 starting from angle \a a1, and spanning angle by \a a2, and
578 transformed by the matrix \a xf. The resulting array has
579 sufficient resolution for pixel accuracy.
580
581 Angles are specified in 16ths of a degree, i.e. a full circle
582 equals 5760 (16*360). Positive values mean counter-clockwise,
583 whereas negative values mean the clockwise direction. Zero degrees
584 is at the 3 o'clock position.
585
586 See the \link qcanvas.html#anglediagram angle diagram\endlink.
587*/
588void QPointArray::makeArc( int x, int y, int w, int h,
589 int a1, int a2,
590 const QWMatrix& xf )
591{
592#define PIV2 102944 /* fixed point PI/2 */
593 if ( --w < 0 || --h < 0 || !a2 ) {
594 resize( 0 );
595 return;
596 }
597
598 bool rev = a2 < 0;
599 if ( rev ) {
600 a1 += a2;
601 a2 = -a2;
602 }
603 a1 = fix_angle( a1 );
604 if ( a1 < 0 )
605 a1 += 16*360;
606 a2 = fix_angle( a2 );
607
608 bool arc = a1 != 0 || a2 != 360*16 || rev;
609
610 double xP, yP, xQ, yQ, xK, yK;
611
612 xf.map(x+w, y+h/2.0, &xP, &yP);
613 xf.map(x+w/2.0, y, &xQ, &yQ);
614 xf.map(x+w, y, &xK, &yK);
615
616 int m = 3;
617 int max;
618 int q = int(QMAX(QABS(xP-xQ),QABS(yP-yQ)));
619 if ( arc )
620 q *= 2;
621 do {
622 m++;
623 max = 4*(1 + (PIV2 >> (16 - m)) );
624 } while (max < q && m < 16); // 16 limits memory usage on HUGE arcs
625
626 double inc = 1.0/(1<<m);
627
628 const int qn = (PIV2 >> (16 - m));
629 resize(qn*4);
630
631 qtr_elips(*this, 0, xP, yP, xQ, yQ, xK, yK, m);
632 xP = xQ; yP = yQ;
633 xf.map(x, y+h/2.0, &xQ, &yQ);
634 xf.map(x, y, &xK, &yK);
635 qtr_elips(*this, qn, xP, yP, xQ, yQ, xK, yK, m);
636 xP = xQ; yP = yQ;
637 xf.map(x+w/2.0, y+h, &xQ, &yQ);
638 xf.map(x, y+h, &xK, &yK);
639 qtr_elips(*this, qn*2, xP, yP, xQ, yQ, xK, yK, m);
640 xP = xQ; yP = yQ;
641 xf.map(x+w, y+h/2.0, &xQ, &yQ);
642 xf.map(x+w, y+h, &xK, &yK);
643 qtr_elips(*this, qn*3, xP, yP, xQ, yQ, xK, yK, m);
644
645 int n = size();
646
647 if ( arc ) {
648 double da1 = double(a1)*Q_PI / (360*8);
649 double da3 = double(a2+a1)*Q_PI / (360*8);
650 int i = int(da1/inc+0.5);
651 int l = int(da3/inc+0.5);
652 int k = (l-i)+1;
653 QPointArray r(k);
654 int j = 0;
655
656 if ( rev ) {
657 while ( k-- )
658 r[j++] = at((i+k)%n);
659 } else {
660 while ( j < k ) {
661 r[j] = at((i+j)%n);
662 j++;
663 }
664 }
665 *this = r;
666 }
667#undef PIV2
668}
669
670#endif // QT_NO_TRANSFORMATIONS
671
672/*!
673 Sets the points of the array to those describing an ellipse with
674 size, width \a w by height \a h, and position (\a x, \a y).
675
676 The returned array has sufficient resolution for use as pixels.
677*/
678void QPointArray::makeEllipse( int x, int y, int w, int h )
679{ // midpoint, 1/4 ellipse
680#if !defined(QT_OLD_MAKEELLIPSE) && !defined(QT_NO_TRANSFORMATIONS)
681 QWMatrix unit;
682 makeArc(x,y,w,h,0,360*16,unit);
683 return;
684#else
685 if ( w <= 0 || h <= 0 ) {
686 if ( w == 0 || h == 0 ) {
687 resize( 0 );
688 return;
689 }
690 if ( w < 0 ) { // negative width
691 w = -w;
692 x -= w;
693 }
694 if ( h < 0 ) { // negative height
695 h = -h;
696 y -= h;
697 }
698 }
699 int s = (w+h+2)/2; // max size of xx,yy array
700 int *px = new int[s]; // 1/4th of ellipse
701 int *py = new int[s];
702 int xx, yy, i=0;
703 double d1, d2;
704 double a2=(w/2)*(w/2), b2=(h/2)*(h/2);
705 xx = 0;
706 yy = int(h/2);
707 d1 = b2 - a2*(h/2) + 0.25*a2;
708 px[i] = xx;
709 py[i] = yy;
710 i++;
711 while ( a2*(yy-0.5) > b2*(xx+0.5) ) { // region 1
712 if ( d1 < 0 ) {
713 d1 = d1 + b2*(3.0+2*xx);
714 xx++;
715 } else {
716 d1 = d1 + b2*(3.0+2*xx) + 2.0*a2*(1-yy);
717 xx++;
718 yy--;
719 }
720 px[i] = xx;
721 py[i] = yy;
722 i++;
723 }
724 d2 = b2*(xx+0.5)*(xx+0.5) + a2*(yy-1)*(yy-1) - a2*b2;
725 while ( yy > 0 ) { // region 2
726 if ( d2 < 0 ) {
727 d2 = d2 + 2.0*b2*(xx+1) + a2*(3-2*yy);
728 xx++;
729 yy--;
730 } else {
731 d2 = d2 + a2*(3-2*yy);
732 yy--;
733 }
734 px[i] = xx;
735 py[i] = yy;
736 i++;
737 }
738 s = i;
739 resize( 4*s ); // make full point array
740 x += w/2;
741 y += h/2;
742 for ( i=0; i<s; i++ ) { // mirror
743 xx = px[i];
744 yy = py[i];
745 setPoint( s-i-1, x+xx, y-yy );
746 setPoint( s+i, x-xx, y-yy );
747 setPoint( 3*s-i-1, x-xx, y+yy );
748 setPoint( 3*s+i, x+xx, y+yy );
749 }
750 delete[] px;
751 delete[] py;
752#endif
753}
754
755#ifndef QT_NO_BEZIER
756// Work functions for QPointArray::cubicBezier()
757static
758void split(const double *p, double *l, double *r)
759{
760 double tmpx;
761 double tmpy;
762
763 l[0] = p[0];
764 l[1] = p[1];
765 r[6] = p[6];
766 r[7] = p[7];
767
768 l[2] = (p[0]+ p[2])/2;
769 l[3] = (p[1]+ p[3])/2;
770 tmpx = (p[2]+ p[4])/2;
771 tmpy = (p[3]+ p[5])/2;
772 r[4] = (p[4]+ p[6])/2;
773 r[5] = (p[5]+ p[7])/2;
774
775 l[4] = (l[2]+ tmpx)/2;
776 l[5] = (l[3]+ tmpy)/2;
777 r[2] = (tmpx + r[4])/2;
778 r[3] = (tmpy + r[5])/2;
779
780 l[6] = (l[4]+ r[2])/2;
781 l[7] = (l[5]+ r[3])/2;
782 r[0] = l[6];
783 r[1] = l[7];
784}
785
786// Based on:
787//
788// A Fast 2D Point-On-Line Test
789// by Alan Paeth
790// from "Graphics Gems", Academic Press, 1990
791static
792int pnt_on_line( const int* p, const int* q, const int* t )
793{
794/*
795 * given a line through P:(px,py) Q:(qx,qy) and T:(tx,ty)
796 * return 0 if T is not on the line through <--P--Q-->
797 * 1 if T is on the open ray ending at P: <--P
798 * 2 if T is on the closed interior along: P--Q
799 * 3 if T is on the open ray beginning at Q: Q-->
800 *
801 * Example: consider the line P = (3,2), Q = (17,7). A plot
802 * of the test points T(x,y) (with 0 mapped onto '.') yields:
803 *
804 * 8| . . . . . . . . . . . . . . . . . 3 3
805 * Y 7| . . . . . . . . . . . . . . 2 2 Q 3 3 Q = 2
806 * 6| . . . . . . . . . . . 2 2 2 2 2 . . .
807 * a 5| . . . . . . . . 2 2 2 2 2 2 . . . . .
808 * x 4| . . . . . 2 2 2 2 2 2 . . . . . . . .
809 * i 3| . . . 2 2 2 2 2 . . . . . . . . . . .
810 * s 2| 1 1 P 2 2 . . . . . . . . . . . . . . P = 2
811 * 1| 1 1 . . . . . . . . . . . . . . . . .
812 * +--------------------------------------
813 * 1 2 3 4 5 X-axis 10 15 19
814 *
815 * Point-Line distance is normalized with the Infinity Norm
816 * avoiding square-root code and tightening the test vs the
817 * Manhattan Norm. All math is done on the field of integers.
818 * The latter replaces the initial ">= MAX(...)" test with
819 * "> (ABS(qx-px) + ABS(qy-py))" loosening both inequality
820 * and norm, yielding a broader target line for selection.
821 * The tightest test is employed here for best discrimination
822 * in merging collinear (to grid coordinates) vertex chains
823 * into a larger, spanning vectors within the Lemming editor.
824 */
825
826 // if all points are coincident, return condition 2 (on line)
827 if(q[0]==p[0] && q[1]==p[1] && q[0]==t[0] && q[1]==t[1]) {
828 return 2;
829 }
830
831 if ( QABS((q[1]-p[1])*(t[0]-p[0])-(t[1]-p[1])*(q[0]-p[0])) >=
832 (QMAX(QABS(q[0]-p[0]), QABS(q[1]-p[1])))) return 0;
833
834 if (((q[0]<p[0])&&(p[0]<t[0])) || ((q[1]<p[1])&&(p[1]<t[1])))
835 return 1 ;
836 if (((t[0]<p[0])&&(p[0]<q[0])) || ((t[1]<p[1])&&(p[1]<q[1])))
837 return 1 ;
838 if (((p[0]<q[0])&&(q[0]<t[0])) || ((p[1]<q[1])&&(q[1]<t[1])))
839 return 3 ;
840 if (((t[0]<q[0])&&(q[0]<p[0])) || ((t[1]<q[1])&&(q[1]<p[1])))
841 return 3 ;
842
843 return 2 ;
844}
845static
846void polygonizeQBezier( double* acc, int& accsize, const double ctrl[],
847 int maxsize )
848{
849 if ( accsize > maxsize / 2 )
850 {
851 // This never happens in practice.
852
853 if ( accsize >= maxsize-4 )
854 return;
855 // Running out of space - approximate by a line.
856 acc[accsize++] = ctrl[0];
857 acc[accsize++] = ctrl[1];
858 acc[accsize++] = ctrl[6];
859 acc[accsize++] = ctrl[7];
860 return;
861 }
862
863 //intersects:
864 double l[8];
865 double r[8];
866 split( ctrl, l, r);
867
868 // convert to integers for line condition check
869 int c0[2]; c0[0] = int(ctrl[0]); c0[1] = int(ctrl[1]);
870 int c1[2]; c1[0] = int(ctrl[2]); c1[1] = int(ctrl[3]);
871 int c2[2]; c2[0] = int(ctrl[4]); c2[1] = int(ctrl[5]);
872 int c3[2]; c3[0] = int(ctrl[6]); c3[1] = int(ctrl[7]);
873
874 // #### Duplication needed?
875 if ( QABS(c1[0]-c0[0]) <= 1 && QABS(c1[1]-c0[1]) <= 1
876 && QABS(c2[0]-c0[0]) <= 1 && QABS(c2[1]-c0[1]) <= 1
877 && QABS(c3[0]-c1[0]) <= 1 && QABS(c3[1]-c0[1]) <= 1 )
878 {
879 // Approximate by one line.
880 // Dont need to write last pt as it is the same as first pt
881 // on the next segment
882 acc[accsize++] = l[0];
883 acc[accsize++] = l[1];
884 return;
885 }
886
887 if ( ( pnt_on_line( c0, c3, c1 ) == 2 && pnt_on_line( c0, c3, c2 ) == 2 )
888 || ( QABS(c1[0]-c0[0]) <= 1 && QABS(c1[1]-c0[1]) <= 1
889 && QABS(c2[0]-c0[0]) <= 1 && QABS(c2[1]-c0[1]) <= 1
890 && QABS(c3[0]-c1[0]) <= 1 && QABS(c3[1]-c0[1]) <= 1 ) )
891 {
892 // Approximate by one line.
893 // Dont need to write last pt as it is the same as first pt
894 // on the next segment
895 acc[accsize++] = l[0];
896 acc[accsize++] = l[1];
897 return;
898 }
899
900 // Too big and too curved - recusively subdivide.
901 polygonizeQBezier( acc, accsize, l, maxsize );
902 polygonizeQBezier( acc, accsize, r, maxsize );
903}
904
905/*!
906 Returns the Bezier points for the four control points in this
907 array.
908*/
909
910QPointArray QPointArray::cubicBezier() const
911{
912#ifdef USE_SIMPLE_QBEZIER_CODE
913 if ( size() != 4 ) {
914#if defined(QT_CHECK_RANGE)
915 qWarning( "QPointArray::bezier: The array must have 4 control points" );
916#endif
917 QPointArray p;
918 return p;
919 }
920
921 int v;
922 float xvec[4];
923 float yvec[4];
924 for ( v=0; v<4; v++ ) { // store all x,y in xvec,yvec
925 int x, y;
926 point( v, &x, &y );
927 xvec[v] = (float)x;
928 yvec[v] = (float)y;
929 }
930
931 QRect r = boundingRect();
932 int m = QMAX(r.width(),r.height())/2;
933 m = QMIN(m,30); // m = number of result points
934 if ( m < 2 ) // at least two points
935 m = 2;
936 QPointArray p( m ); // p = Bezier point array
937 register QPointData *pd = p.data();
938
939 float x0 = xvec[0], y0 = yvec[0];
940 float dt = 1.0F/m;
941 float cx = 3.0F * (xvec[1] - x0);
942 float bx = 3.0F * (xvec[2] - xvec[1]) - cx;
943 float ax = xvec[3] - (x0 + cx + bx);
944 float cy = 3.0F * (yvec[1] - y0);
945 float by = 3.0F * (yvec[2] - yvec[1]) - cy;
946 float ay = yvec[3] - (y0 + cy + by);
947 float t = dt;
948
949 pd->rx() = (QCOORD)xvec[0];
950 pd->ry() = (QCOORD)yvec[0];
951 pd++;
952 m -= 2;
953
954 while ( m-- ) {
955 pd->rx() = (QCOORD)qRound( ((ax * t + bx) * t + cx) * t + x0 );
956 pd->ry() = (QCOORD)qRound( ((ay * t + by) * t + cy) * t + y0 );
957 pd++;
958 t += dt;
959 }
960
961 pd->rx() = (QCOORD)xvec[3];
962 pd->ry() = (QCOORD)yvec[3];
963
964 return p;
965#else
966
967 if ( size() != 4 ) {
968#if defined(QT_CHECK_RANGE)
969 qWarning( "QPointArray::bezier: The array must have 4 control points" );
970#endif
971 QPointArray pa;
972 return pa;
973 } else {
974 QRect r = boundingRect();
975 int m = 4+2*QMAX(r.width(),r.height());
976 double *p = new double[m];
977 double ctrl[8];
978 int i;
979 for (i=0; i<4; i++) {
980 ctrl[i*2] = at(i).x();
981 ctrl[i*2+1] = at(i).y();
982 }
983 int len=0;
984 polygonizeQBezier( p, len, ctrl, m );
985 QPointArray pa((len/2)+1); // one extra point for last point on line
986 int j=0;
987 for (i=0; j<len; i++) {
988 int x = qRound(p[j++]);
989 int y = qRound(p[j++]);
990 pa[i] = QPoint(x,y);
991 }
992 // add last pt on the line, which will be at the last control pt
993 pa[(int)pa.size()-1] = at(3);
994 delete[] p;
995
996 return pa;
997 }
998
999#endif
1000}
1001#endif //QT_NO_BEZIER
1002
1003/*****************************************************************************
1004 QPointArray stream functions
1005 *****************************************************************************/
1006#ifndef QT_NO_DATASTREAM
1007/*!
1008 \relates QPointArray
1009
1010 Writes the point array, \a a to the stream \a s and returns a
1011 reference to the stream.
1012
1013 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
1014*/
1015
1016QDataStream &operator<<( QDataStream &s, const QPointArray &a )
1017{
1018 register uint i;
1019 uint len = a.size();
1020 s << len; // write size of array
1021 for ( i=0; i<len; i++ ) // write each point
1022 s << a.point( i );
1023 return s;
1024}
1025
1026/*!
1027 \relates QPointArray
1028
1029 Reads a point array, \a a from the stream \a s and returns a
1030 reference to the stream.
1031
1032 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
1033*/
1034
1035QDataStream &operator>>( QDataStream &s, QPointArray &a )
1036{
1037 register uint i;
1038 uint len;
1039 s >> len; // read size of array
1040 if ( !a.resize( len ) ) // no memory
1041 return s;
1042 QPoint p;
1043 for ( i=0; i<len; i++ ) { // read each point
1044 s >> p;
1045 a.setPoint( i, p );
1046 }
1047 return s;
1048}
1049#endif //QT_NO_DATASTREAM
1050
1051
1052
1053struct QShortPoint { // Binary compatible with XPoint
1054 short x, y;
1055};
1056
1057uint QPointArray::splen = 0;
1058void* QPointArray::sp = 0; // Really a QShortPoint*
1059
1060/*!
1061 \internal
1062
1063 Converts the point coords to short (16bit) size, compatible with
1064 X11's XPoint structure. The pointer returned points to a static
1065 array, so its contents will be overwritten the next time this
1066 function is called.
1067*/
1068
1069void* QPointArray::shortPoints( int index, int nPoints ) const
1070{
1071
1072 if ( isNull() || !nPoints )
1073 return 0;
1074 QPoint* p = data();
1075 p += index;
1076 uint i = nPoints < 0 ? size() : nPoints;
1077 if ( splen < i ) {
1078 if ( sp )
1079 delete[] ((QShortPoint*)sp);
1080 sp = new QShortPoint[i];
1081 splen = i;
1082 }
1083 QShortPoint* ps = (QShortPoint*)sp;
1084 while ( i-- ) {
1085 ps->x = (short)p->x();
1086 ps->y = (short)p->y();
1087 p++;
1088 ps++;
1089 }
1090 return sp;
1091}
1092
1093
1094/*!
1095 \internal
1096
1097 Deallocates the internal buffer used by shortPoints().
1098*/
1099
1100void QPointArray::cleanBuffers()
1101{
1102 if ( sp )
1103 delete[] ((QShortPoint*)sp);
1104 sp = 0;
1105 splen = 0;
1106}
Note: See TracBrowser for help on using the repository browser.