qtcanvas.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Solutions component.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
19 ** distribution.
20 ** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 ** of its contributors may be used to endorse or promote products derived
22 ** from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qtcanvas.h"
42 #include <QApplication>
43 #include <QBitmap>
44 #include <QDesktopWidget>
45 #include <QImage>
46 #include <QPainter>
47 #include <QTimer>
48 #include <qhash.h>
49 #include <qset.h>
50 #include <qalgorithms.h>
51 #include <qevent.h>
52 #include <qpainterpath.h>
53 
54 #include <stdlib.h>
55 using namespace Qt;
56 
57 class QtCanvasData
58 {
59 public:
61  {
62  }
63 
64  QList<QtCanvasView*> viewList;
65  QSet<QtCanvasItem*> itemDict;
66  QSet<QtCanvasItem*> animDict;
67 };
68 
69 class QtCanvasViewData
70 {
71 public:
73  QMatrix xform;
74  QMatrix ixform;
75  bool highQuality;
76 };
77 
78 // clusterizer
79 
81 {
82 public:
83  QtCanvasClusterizer(int maxclusters);
85 
86  void add(int x, int y); // 1x1 rectangle (point)
87  void add(int x, int y, int w, int h);
88  void add(const QRect& rect);
89 
90  void clear();
91  int clusters() const
92  {
93  return count;
94  }
95  const QRect& operator[](int i) const;
96 
97 private:
98  QRect* cluster;
99  int count;
100  const int maxcl;
101 };
102 
103 static
104 void include(QRect& r, const QRect& rect)
105 {
106  if (rect.left() < r.left())
107  {
108  r.setLeft(rect.left());
109  }
110 
111  if (rect.right() > r.right())
112  {
113  r.setRight(rect.right());
114  }
115 
116  if (rect.top() < r.top())
117  {
118  r.setTop(rect.top());
119  }
120 
121  if (rect.bottom() > r.bottom())
122  {
123  r.setBottom(rect.bottom());
124  }
125 }
126 
127 /*
128 A QtCanvasClusterizer groups rectangles (QRects) into non-overlapping rectangles
129 by a merging heuristic.
130 */
132  cluster(new QRect[maxclusters]),
133  count(0),
134  maxcl(maxclusters)
135 { }
136 
138 {
139  delete [] cluster;
140 }
141 
143 {
144  count = 0;
145 }
146 
147 void QtCanvasClusterizer::add(int x, int y)
148 {
149  add(QRect(x, y, 1, 1));
150 }
151 
152 void QtCanvasClusterizer::add(int x, int y, int w, int h)
153 {
154  add(QRect(x, y, w, h));
155 }
156 
157 void QtCanvasClusterizer::add(const QRect& rect)
158 {
159  QRect biggerrect(rect.x() - 1, rect.y() - 1, rect.width() + 2, rect.height() + 2);
160 
161  //assert(rect.width()>0 && rect.height()>0);
162 
163  int cursor;
164 
165  for (cursor = 0; cursor < count; cursor++)
166  {
167  if (cluster[cursor].contains(rect))
168  {
169  // Wholly contained already.
170  return;
171  }
172  }
173 
174  int lowestcost = 9999999;
175  int cheapest = -1;
176  cursor = 0;
177 
178  while (cursor < count)
179  {
180  if (cluster[cursor].intersects(biggerrect))
181  {
182  QRect larger = cluster[cursor];
183  include(larger, rect);
184  int cost = larger.width() * larger.height() -
185  cluster[cursor].width() * cluster[cursor].height();
186 
187  if (cost < lowestcost)
188  {
189  bool bad = false;
190 
191  for (int c = 0; c < count && !bad; c++)
192  {
193  bad = cluster[c].intersects(larger) && c != cursor;
194  }
195 
196  if (!bad)
197  {
198  cheapest = cursor;
199  lowestcost = cost;
200  }
201  }
202  }
203 
204  cursor++;
205  }
206 
207  if (cheapest >= 0)
208  {
209  include(cluster[cheapest], rect);
210  return;
211  }
212 
213  if (count < maxcl)
214  {
215  cluster[count++] = rect;
216  return;
217  }
218 
219  // Do cheapest of:
220  // add to closest cluster
221  // do cheapest cluster merge, add to new cluster
222 
223  lowestcost = 9999999;
224  cheapest = -1;
225  cursor = 0;
226 
227  while (cursor < count)
228  {
229  QRect larger = cluster[cursor];
230  include(larger, rect);
231  int cost = larger.width() * larger.height()
232  - cluster[cursor].width() * cluster[cursor].height();
233 
234  if (cost < lowestcost)
235  {
236  bool bad = false;
237 
238  for (int c = 0; c < count && !bad; c++)
239  {
240  bad = cluster[c].intersects(larger) && c != cursor;
241  }
242 
243  if (!bad)
244  {
245  cheapest = cursor;
246  lowestcost = cost;
247  }
248  }
249 
250  cursor++;
251  }
252 
253  // ###
254  // could make an heuristic guess as to whether we need to bother
255  // looking for a cheap merge.
256 
257  int cheapestmerge1 = -1;
258  int cheapestmerge2 = -1;
259 
260  int merge1 = 0;
261 
262  while (merge1 < count)
263  {
264  int merge2 = 0;
265 
266  while (merge2 < count)
267  {
268  if (merge1 != merge2)
269  {
270  QRect larger = cluster[merge1];
271  include(larger, cluster[merge2]);
272  int cost = larger.width() * larger.height()
273  - cluster[merge1].width() * cluster[merge1].height()
274  - cluster[merge2].width() * cluster[merge2].height();
275 
276  if (cost < lowestcost)
277  {
278  bool bad = false;
279 
280  for (int c = 0; c < count && !bad; c++)
281  {
282  bad = cluster[c].intersects(larger) && c != cursor;
283  }
284 
285  if (!bad)
286  {
287  cheapestmerge1 = merge1;
288  cheapestmerge2 = merge2;
289  lowestcost = cost;
290  }
291  }
292  }
293 
294  merge2++;
295  }
296 
297  merge1++;
298  }
299 
300  if (cheapestmerge1 >= 0)
301  {
302  include(cluster[cheapestmerge1], cluster[cheapestmerge2]);
303  cluster[cheapestmerge2] = cluster[count--];
304  }
305  else
306  {
307  // if (!cheapest) debugRectangles(rect);
308  include(cluster[cheapest], rect);
309  }
310 
311  // NB: clusters do not intersect (or intersection will
312  // overwrite). This is a result of the above algorithm,
313  // given the assumption that (x, y) are ordered topleft
314  // to bottomright.
315 
316  // ###
317  //
318  // add explicit x/y ordering to that comment, move it to the top
319  // and rephrase it as pre-/post-conditions.
320 }
321 
322 const QRect& QtCanvasClusterizer::operator[](int i) const
323 {
324  return cluster[i];
325 }
326 
327 // end of clusterizer
328 
329 
330 class QtCanvasItemLess
331 {
332 public:
333  inline bool operator()(const QtCanvasItem* i1, const QtCanvasItem* i2) const
334  {
335  if (i1->z() == i2->z())
336  {
337  return i1 > i2;
338  }
339 
340  return (i1->z() > i2->z());
341  }
342 };
343 
344 
345 class QtCanvasChunk
346 {
347 public:
348  QtCanvasChunk() : changed(true) { }
349  // Other code assumes lists are not deleted. Assignment is also
350  // done on ChunkRecs. So don't add that sort of thing here.
351 
352  void sort()
353  {
354  qSort(m_list.begin(), m_list.end(), QtCanvasItemLess());
355  }
356 
357  const QtCanvasItemList& list() const
358  {
359  return m_list;
360  }
361 
362  void add(QtCanvasItem* item)
363  {
364  m_list.prepend(item);
365  changed = true;
366  }
367 
368  void remove(QtCanvasItem* item)
369  {
370  m_list.removeAll(item);
371  changed = true;
372  }
373 
374  void change()
375  {
376  changed = true;
377  }
378 
379  bool hasChanged() const
380  {
381  return changed;
382  }
383 
384  bool takeChange()
385  {
386  bool y = changed;
387  changed = false;
388  return y;
389  }
390 
391 private:
392  QtCanvasItemList m_list;
393  bool changed;
394 };
395 
396 
397 static int gcd(int a, int b)
398 {
399  int r;
400 
401  while ((r = a % b))
402  {
403  a = b;
404  b = r;
405  }
406 
407  return b;
408 }
409 
410 static int scm(int a, int b)
411 {
412  int g = gcd(a, b);
413  return a / g * b;
414 }
415 
416 
417 
418 /*
419  \class QtCanvas qtcanvas.h
420  \brief The QtCanvas class provides a 2D area that can contain QtCanvasItem objects.
421 
422  The QtCanvas class manages its 2D graphic area and all the canvas
423  items the area contains. The canvas has no visual appearance of
424  its own. Instead, it is displayed on screen using a QtCanvasView.
425  Multiple QtCanvasView widgets may be associated with a canvas to
426  provide multiple views of the same canvas.
427 
428  The canvas is optimized for large numbers of items, particularly
429  where only a small percentage of the items change at any
430  one time. If the entire display changes very frequently, you should
431  consider using your own custom QtScrollView subclass.
432 
433  Qt provides a rich
434  set of canvas item classes, e.g. QtCanvasEllipse, QtCanvasLine,
435  QtCanvasPolygon, QtCanvasPolygonalItem, QtCanvasRectangle, QtCanvasSpline,
436  QtCanvasSprite and QtCanvasText. You can subclass to create your own
437  canvas items; QtCanvasPolygonalItem is the most common base class used
438  for this purpose.
439 
440  Items appear on the canvas after their \link QtCanvasItem::show()
441  show()\endlink function has been called (or \link
442  QtCanvasItem::setVisible() setVisible(true)\endlink), and \e after
443  update() has been called. The canvas only shows items that are
444  \link QtCanvasItem::setVisible() visible\endlink, and then only if
445  \l update() is called. (By default the canvas is white and so are
446  canvas items, so if nothing appears try changing colors.)
447 
448  If you created the canvas without passing a width and height to
449  the constructor you must also call resize().
450 
451  Although a canvas may appear to be similar to a widget with child
452  widgets, there are several notable differences:
453 
454  \list
455  \i Canvas items are usually much faster to manipulate and redraw than
456  child widgets, with the speed advantage becoming especially great when
457  there are \e many canvas items and non-rectangular items. In most
458  situations canvas items are also a lot more memory efficient than child
459  widgets.
460 
461  \i It's easy to detect overlapping items (collision detection).
462 
463  \i The canvas can be larger than a widget. A million-by-million canvas
464  is perfectly possible. At such a size a widget might be very
465  inefficient, and some window systems might not support it at all,
466  whereas QtCanvas scales well. Even with a billion pixels and a million
467  items, finding a particular canvas item, detecting collisions, etc.,
468  is still fast (though the memory consumption may be prohibitive
469  at such extremes).
470 
471  \i Two or more QtCanvasView objects can view the same canvas.
472 
473  \i An arbitrary transformation matrix can be set on each QtCanvasView
474  which makes it easy to zoom, rotate or shear the viewed canvas.
475 
476  \i Widgets provide a lot more functionality, such as input (QKeyEvent,
477  QMouseEvent etc.) and layout management (QGridLayout etc.).
478 
479  \endlist
480 
481  A canvas consists of a background, a number of canvas items organized by
482  x, y and z coordinates, and a foreground. A canvas item's z coordinate
483  can be treated as a layer number -- canvas items with a higher z
484  coordinate appear in front of canvas items with a lower z coordinate.
485 
486  The background is white by default, but can be set to a different color
487  using setBackgroundColor(), or to a repeated pixmap using
488  setBackgroundPixmap() or to a mosaic of smaller pixmaps using
489  setTiles(). Individual tiles can be set with setTile(). There
490  are corresponding get functions, e.g. backgroundColor() and
491  backgroundPixmap().
492 
493  Note that QtCanvas does not inherit from QWidget, even though it has some
494  functions which provide the same functionality as those in QWidget. One
495  of these is setBackgroundPixmap(); some others are resize(), size(),
496  width() and height(). \l QtCanvasView is the widget used to display a
497  canvas on the screen.
498 
499  Canvas items are added to a canvas by constructing them and passing the
500  canvas to the canvas item's constructor. An item can be moved to a
501  different canvas using QtCanvasItem::setCanvas().
502 
503  Canvas items are movable (and in the case of QtCanvasSprites, animated)
504  objects that inherit QtCanvasItem. Each canvas item has a position on the
505  canvas (x, y coordinates) and a height (z coordinate), all of which are
506  held as floating-point numbers. Moving canvas items also have x and y
507  velocities. It's possible for a canvas item to be outside the canvas
508  (for example QtCanvasItem::x() is greater than width()). When a canvas
509  item is off the canvas, onCanvas() returns false and the canvas
510  disregards the item. (Canvas items off the canvas do not slow down any
511  of the common operations on the canvas.)
512 
513  Canvas items can be moved with QtCanvasItem::move(). The advance()
514  function moves all QtCanvasItem::animated() canvas items and
515  setAdvancePeriod() makes QtCanvas move them automatically on a periodic
516  basis. In the context of the QtCanvas classes, to `animate' a canvas item
517  is to set it in motion, i.e. using QtCanvasItem::setVelocity(). Animation
518  of a canvas item itself, i.e. items which change over time, is enabled
519  by calling QtCanvasSprite::setFrameAnimation(), or more generally by
520  subclassing and reimplementing QtCanvasItem::advance(). To detect collisions
521  use one of the QtCanvasItem::collisions() functions.
522 
523  The changed parts of the canvas are redrawn (if they are visible in a
524  canvas view) whenever update() is called. You can either call update()
525  manually after having changed the contents of the canvas, or force
526  periodic updates using setUpdatePeriod(). If you have moving objects on
527  the canvas, you must call advance() every time the objects should
528  move one step further. Periodic calls to advance() can be forced using
529  setAdvancePeriod(). The advance() function will call
530  QtCanvasItem::advance() on every item that is \link
531  QtCanvasItem::animated() animated\endlink and trigger an update of the
532  affected areas afterwards. (A canvas item that is `animated' is simply
533  a canvas item that is in motion.)
534 
535  QtCanvas organizes its canvas items into \e chunks; these are areas on
536  the canvas that are used to speed up most operations. Many operations
537  start by eliminating most chunks (i.e. those which haven't changed)
538  and then process only the canvas items that are in the few interesting
539  (i.e. changed) chunks. A valid chunk, validChunk(), is one which is on
540  the canvas.
541 
542  The chunk size is a key factor to QtCanvas's speed: if there are too many
543  chunks, the speed benefit of grouping canvas items into chunks is
544  reduced. If the chunks are too large, it takes too long to process each
545  one. The QtCanvas constructor tries to pick a suitable size, but you
546  can call retune() to change it at any time. The chunkSize() function
547  returns the current chunk size. The canvas items always make sure
548  they're in the right chunks; all you need to make sure of is that
549  the canvas uses the right chunk size. A good rule of thumb is that
550  the size should be a bit smaller than the average canvas item
551  size. If you have moving objects, the chunk size should be a bit
552  smaller than the average size of the moving items.
553 
554  The foreground is normally nothing, but if you reimplement
555  drawForeground(), you can draw things in front of all the canvas
556  items.
557 
558  Areas can be set as changed with setChanged() and set unchanged with
559  setUnchanged(). The entire canvas can be set as changed with
560  setAllChanged(). A list of all the items on the canvas is returned by
561  allItems().
562 
563  An area can be copied (painted) to a QPainter with drawArea().
564 
565  If the canvas is resized it emits the resized() signal.
566 
567  The examples/canvas application and the 2D graphics page of the
568  examples/demo application demonstrate many of QtCanvas's facilities.
569 
570  \sa QtCanvasView QtCanvasItem
571 */
572 void QtCanvas::init(int w, int h, int chunksze, int mxclusters)
573 {
574  d = new QtCanvasData;
575  awidth = w;
576  aheight = h;
577  chunksize = chunksze;
578  maxclusters = mxclusters;
579  chwidth = (w + chunksize - 1) / chunksize;
580  chheight = (h + chunksize - 1) / chunksize;
581  chunks = new QtCanvasChunk[chwidth * chheight];
582  update_timer = 0;
583  bgcolor = white;
584  grid = 0;
585  htiles = 0;
586  vtiles = 0;
587  debug_redraw_areas = false;
588 }
589 
590 /*
591  Create a QtCanvas with no size. \a parent is passed to the QObject
592  superclass.
593 
594  \warning You \e must call resize() at some time after creation to
595  be able to use the canvas.
596 */
597 QtCanvas::QtCanvas(QObject* parent)
598  : QObject(parent)
599 {
600  init(0, 0);
601 }
602 
603 /*
604  Constructs a QtCanvas that is \a w pixels wide and \a h pixels high.
605 */
606 QtCanvas::QtCanvas(int w, int h)
607 {
608  init(w, h);
609 }
610 
611 /*
612  Constructs a QtCanvas which will be composed of \a h tiles
613  horizontally and \a v tiles vertically. Each tile will be an image
614  \a tilewidth by \a tileheight pixels taken from pixmap \a p.
615 
616  The pixmap \a p is a list of tiles, arranged left to right, (and
617  in the case of pixmaps that have multiple rows of tiles, top to
618  bottom), with tile 0 in the top-left corner, tile 1 next to the
619  right, and so on, e.g.
620 
621  \table
622  \row \i 0 \i 1 \i 2 \i 3
623  \row \i 4 \i 5 \i 6 \i 7
624  \endtable
625 
626  The QtCanvas is initially sized to show exactly the given number of
627  tiles horizontally and vertically. If it is resized to be larger,
628  the entire matrix of tiles will be repeated as often as necessary
629  to cover the area. If it is smaller, tiles to the right and bottom
630  will not be visible.
631 
632  \sa setTiles()
633 */
634 QtCanvas::QtCanvas(QPixmap p,
635  int h, int v, int tilewidth, int tileheight)
636 {
637  init(h * tilewidth, v * tileheight, scm(tilewidth, tileheight));
638  setTiles(p, h, v, tilewidth, tileheight);
639 }
640 
641 /*
642  Destroys the canvas and all the canvas's canvas items.
643 */
645 {
646  for (int i = 0; i < d->viewList.size(); ++i)
647  {
648  d->viewList[i]->viewing = 0;
649  }
650 
652 
653  for (QtCanvasItemList::Iterator it = all.begin(); it != all.end(); ++it)
654  {
655  delete *it;
656  }
657 
658  delete [] chunks;
659  delete [] grid;
660  delete d;
661 }
662 
663 /*
664 \internal
665 Returns the chunk at a chunk position \a i, \a j.
666 */
667 QtCanvasChunk& QtCanvas::chunk(int i, int j) const
668 {
669  return chunks[i + chwidth * j];
670 }
671 
672 /*
673 \internal
674 Returns the chunk at a pixel position \a x, \a y.
675 */
676 QtCanvasChunk& QtCanvas::chunkContaining(int x, int y) const
677 {
678  return chunk(x / chunksize, y / chunksize);
679 }
680 
681 /*
682  Returns a list of all the items in the canvas.
683 */
685 {
686  return d->itemDict.toList();
687 }
688 
689 
690 /*
691  Changes the size of the canvas to have a width of \a w and a
692  height of \a h. This is a slow operation.
693 */
694 void QtCanvas::resize(int w, int h)
695 {
696  if (awidth == w && aheight == h)
697  {
698  return;
699  }
700 
701  QList<QtCanvasItem*> hidden;
702 
703  for (QSet<QtCanvasItem*>::const_iterator it = d->itemDict.begin(); it != d->itemDict.end(); ++it)
704  {
705  if ((*it)->isVisible())
706  {
707  (*it)->hide();
708  hidden.append(*it);
709  }
710  }
711 
712  int nchwidth = (w + chunksize - 1) / chunksize;
713  int nchheight = (h + chunksize - 1) / chunksize;
714 
715  QtCanvasChunk* newchunks = new QtCanvasChunk[nchwidth * nchheight];
716 
717  // Commit the new values.
718  //
719  awidth = w;
720  aheight = h;
721  chwidth = nchwidth;
722  chheight = nchheight;
723  delete [] chunks;
724  chunks = newchunks;
725 
726  for (int i = 0; i < hidden.size(); ++i)
727  {
728  hidden.at(i)->show();
729  }
730 
731  setAllChanged();
732 
733  emit resized();
734 }
735 
736 /*
737  \fn void QtCanvas::resized()
738 
739  This signal is emitted whenever the canvas is resized. Each
740  QtCanvasView connects to this signal to keep the scrollview's size
741  correct.
742 */
743 
744 /*
745  Change the efficiency tuning parameters to \a mxclusters clusters,
746  each of size \a chunksze. This is a slow operation if there are
747  many objects on the canvas.
748 
749  The canvas is divided into chunks which are rectangular areas \a
750  chunksze wide by \a chunksze high. Use a chunk size which is about
751  the average size of the canvas items. If you choose a chunk size
752  which is too small it will increase the amount of calculation
753  required when drawing since each change will affect many chunks.
754  If you choose a chunk size which is too large the amount of
755  drawing required will increase because for each change, a lot of
756  drawing will be required since there will be many (unchanged)
757  canvas items which are in the same chunk as the changed canvas
758  items.
759 
760  Internally, a canvas uses a low-resolution "chunk matrix" to keep
761  track of all the items in the canvas. A 64x64 chunk matrix is the
762  default for a 1024x1024 pixel canvas, where each chunk collects
763  canvas items in a 16x16 pixel square. This default is also
764  affected by setTiles(). You can tune this default using this
765  function. For example if you have a very large canvas and want to
766  trade off speed for memory then you might set the chunk size to 32
767  or 64.
768 
769  The \a mxclusters argument is the number of rectangular groups of
770  chunks that will be separately drawn. If the canvas has a large
771  number of small, dispersed items, this should be about that
772  number. Our testing suggests that a large number of clusters is
773  almost always best.
774 
775 */
776 void QtCanvas::retune(int chunksze, int mxclusters)
777 {
778  maxclusters = mxclusters;
779 
780  if (chunksize != chunksze)
781  {
782  QList<QtCanvasItem*> hidden;
783 
784  for (QSet<QtCanvasItem*>::const_iterator it = d->itemDict.begin(); it != d->itemDict.end(); ++it)
785  {
786  if ((*it)->isVisible())
787  {
788  (*it)->hide();
789  hidden.append(*it);
790  }
791  }
792 
793  chunksize = chunksze;
794 
795  int nchwidth = (awidth + chunksize - 1) / chunksize;
796  int nchheight = (aheight + chunksize - 1) / chunksize;
797 
798  QtCanvasChunk* newchunks = new QtCanvasChunk[nchwidth * nchheight];
799 
800  // Commit the new values.
801  //
802  chwidth = nchwidth;
803  chheight = nchheight;
804  delete [] chunks;
805  chunks = newchunks;
806 
807  for (int i = 0; i < hidden.size(); ++i)
808  {
809  hidden.at(i)->show();
810  }
811  }
812 }
813 
814 /*
815  \fn int QtCanvas::width() const
816 
817  Returns the width of the canvas, in pixels.
818 */
819 
820 /*
821  \fn int QtCanvas::height() const
822 
823  Returns the height of the canvas, in pixels.
824 */
825 
826 /*
827  \fn QSize QtCanvas::size() const
828 
829  Returns the size of the canvas, in pixels.
830 */
831 
832 /*
833  \fn QRect QtCanvas::rect() const
834 
835  Returns a rectangle the size of the canvas.
836 */
837 
838 
839 /*
840  \fn bool QtCanvas::onCanvas(int x, int y) const
841 
842  Returns true if the pixel position (\a x, \a y) is on the canvas;
843  otherwise returns false.
844 
845  \sa validChunk()
846 */
847 
848 /*
849  \fn bool QtCanvas::onCanvas(const QPoint& p) const
850  \overload
851 
852  Returns true if the pixel position \a p is on the canvas;
853  otherwise returns false.
854 
855  \sa validChunk()
856 */
857 
858 /*
859  \fn bool QtCanvas::validChunk(int x, int y) const
860 
861  Returns true if the chunk position (\a x, \a y) is on the canvas;
862  otherwise returns false.
863 
864  \sa onCanvas()
865 */
866 
867 /*
868  \fn bool QtCanvas::validChunk(const QPoint& p) const
869  \overload
870 
871  Returns true if the chunk position \a p is on the canvas; otherwise
872  returns false.
873 
874  \sa onCanvas()
875 */
876 
877 /*
878  \fn int QtCanvas::chunkSize() const
879 
880  Returns the chunk size of the canvas.
881 
882  \sa retune()
883 */
884 
885 /*
886 \fn bool QtCanvas::sameChunk(int x1, int y1, int x2, int y2) const
887 \internal
888 Tells if the points (\a x1, \a y1) and (\a x2, \a y2) are within the same chunk.
889 */
890 
891 /*
892 \internal
893 This method adds an the item \a item to the list of QtCanvasItem objects
894 in the QtCanvas. The QtCanvasItem class calls this.
895 */
897 {
898  d->itemDict.insert(item);
899 }
900 
901 /*
902 \internal
903 This method adds the item \a item to the list of QtCanvasItem objects
904 to be moved. The QtCanvasItem class calls this.
905 */
907 {
908  d->animDict.insert(item);
909 }
910 
911 /*
912 \internal
913 This method adds the item \a item to the list of QtCanvasItem objects
914 which are no longer to be moved. The QtCanvasItem class calls this.
915 */
917 {
918  d->animDict.remove(item);
919 }
920 
921 /*
922 \internal
923 This method removes the item \a item from the list of QtCanvasItem objects
924 in this QtCanvas. The QtCanvasItem class calls this.
925 */
927 {
928  d->itemDict.remove(item);
929 }
930 
931 /*
932 \internal
933 This method adds the view \a view to the list of QtCanvasView objects
934 viewing this QtCanvas. The QtCanvasView class calls this.
935 */
937 {
938  d->viewList.append(view);
939 
940  if (htiles > 1 || vtiles > 1 || pm.isNull())
941  {
942  QPalette::ColorRole role = view->widget()->backgroundRole();
943  QPalette viewPalette = view->widget()->palette();
944  viewPalette.setColor(role, backgroundColor());
945  view->widget()->setPalette(viewPalette);
946  }
947 }
948 
949 /*
950 \internal
951 This method removes the view \a view from the list of QtCanvasView objects
952 viewing this QtCanvas. The QtCanvasView class calls this.
953 */
955 {
956  d->viewList.removeAll(view);
957 }
958 
959 /*
960  Sets the canvas to call advance() every \a ms milliseconds. Any
961  previous setting by setAdvancePeriod() or setUpdatePeriod() is
962  overridden.
963 
964  If \a ms is less than 0 advancing will be stopped.
965 */
966 void QtCanvas::setAdvancePeriod(int ms)
967 {
968  if (ms < 0)
969  {
970  if (update_timer)
971  {
972  update_timer->stop();
973  }
974  }
975  else
976  {
977  if (update_timer)
978  {
979  delete update_timer;
980  }
981 
982  update_timer = new QTimer(this);
983  connect(update_timer, SIGNAL(timeout()), this, SLOT(advance()));
984  update_timer->start(ms);
985  }
986 }
987 
988 /*
989  Sets the canvas to call update() every \a ms milliseconds. Any
990  previous setting by setAdvancePeriod() or setUpdatePeriod() is
991  overridden.
992 
993  If \a ms is less than 0 automatic updating will be stopped.
994 */
995 void QtCanvas::setUpdatePeriod(int ms)
996 {
997  if (ms < 0)
998  {
999  if (update_timer)
1000  {
1001  update_timer->stop();
1002  }
1003  }
1004  else
1005  {
1006  if (update_timer)
1007  {
1008  delete update_timer;
1009  }
1010 
1011  update_timer = new QTimer(this);
1012  connect(update_timer, SIGNAL(timeout()), this, SLOT(update()));
1013  update_timer->start(ms);
1014  }
1015 }
1016 
1017 /*
1018  Moves all QtCanvasItem::animated() canvas items on the canvas and
1019  refreshes all changes to all views of the canvas. (An `animated'
1020  item is an item that is in motion; see setVelocity().)
1021 
1022  The advance takes place in two phases. In phase 0, the
1023  QtCanvasItem::advance() function of each QtCanvasItem::animated()
1024  canvas item is called with paramater 0. Then all these canvas
1025  items are called again, with parameter 1. In phase 0, the canvas
1026  items should not change position, merely examine other items on
1027  the canvas for which special processing is required, such as
1028  collisions between items. In phase 1, all canvas items should
1029  change positions, ignoring any other items on the canvas. This
1030  two-phase approach allows for considerations of "fairness",
1031  although no QtCanvasItem subclasses supplied with Qt do anything
1032  interesting in phase 0.
1033 
1034  The canvas can be configured to call this function periodically
1035  with setAdvancePeriod().
1036 
1037  \sa update()
1038 */
1039 void QtCanvas::advance()
1040 {
1041  QSetIterator<QtCanvasItem*> it = d->animDict;
1042 
1043  while (it.hasNext())
1044  {
1045  QtCanvasItem* i = it.next();
1046 
1047  if (i)
1048  {
1049  i->advance(0);
1050  }
1051  }
1052 
1053  // we expect the dict contains the exact same items as in the
1054  // first pass.
1055  it.toFront();
1056 
1057  while (it.hasNext())
1058  {
1059  QtCanvasItem* i = it.next();
1060 
1061  if (i)
1062  {
1063  i->advance(1);
1064  }
1065  }
1066 
1067  update();
1068 }
1069 
1070 // Don't call this unless you know what you're doing.
1071 // p is in the content's co-ordinate example.
1072 /*
1073  \internal
1074 */
1075 void QtCanvas::drawViewArea(QtCanvasView* view, QPainter* p, const QRect& vr, bool)
1076 {
1077  QMatrix wm = view->worldMatrix();
1078  QMatrix iwm = wm.inverted();
1079  // ivr = covers all chunks in vr
1080  QRect ivr = iwm.mapRect(vr);
1081 
1082  p->setMatrix(wm);
1083  drawCanvasArea(ivr, p, false);
1084 }
1085 
1086 /*
1087  Repaints changed areas in all views of the canvas.
1088 
1089  \sa advance()
1090 */
1091 void QtCanvas::update()
1092 {
1093  QRect r = changeBounds();
1094 
1095  for (int i = 0; i < d->viewList.size(); ++i)
1096  {
1097  QtCanvasView* view = d->viewList.at(i);
1098 
1099  if (!r.isEmpty())
1100  {
1101  QRect tr = view->worldMatrix().mapRect(r);
1102  view->widget()->update(tr);
1103  }
1104  }
1105 
1106  setUnchanged(r);
1107 }
1108 
1109 
1110 /*
1111  Marks the whole canvas as changed.
1112  All views of the canvas will be entirely redrawn when
1113  update() is called next.
1114 */
1116 {
1117  setChanged(QRect(0, 0, width(), height()));
1118 }
1119 
1120 /*
1121  Marks \a area as changed. This \a area will be redrawn in all
1122  views that are showing it when update() is called next.
1123 */
1124 void QtCanvas::setChanged(const QRect& area)
1125 {
1126  QRect thearea = area.intersected(QRect(0, 0, width(), height()));
1127 
1128  int mx = (thearea.x() + thearea.width() + chunksize) / chunksize;
1129  int my = (thearea.y() + thearea.height() + chunksize) / chunksize;
1130 
1131  if (mx > chwidth)
1132  {
1133  mx = chwidth;
1134  }
1135 
1136  if (my > chheight)
1137  {
1138  my = chheight;
1139  }
1140 
1141  int x = thearea.x() / chunksize;
1142 
1143  while (x < mx)
1144  {
1145  int y = thearea.y() / chunksize;
1146 
1147  while (y < my)
1148  {
1149  chunk(x, y).change();
1150  y++;
1151  }
1152 
1153  x++;
1154  }
1155 }
1156 
1157 /*
1158  Marks \a area as \e unchanged. The area will \e not be redrawn in
1159  the views for the next update(), unless it is marked or changed
1160  again before the next call to update().
1161 */
1162 void QtCanvas::setUnchanged(const QRect& area)
1163 {
1164  QRect thearea = area.intersected(QRect(0, 0, width(), height()));
1165 
1166  int mx = (thearea.x() + thearea.width() + chunksize) / chunksize;
1167  int my = (thearea.y() + thearea.height() + chunksize) / chunksize;
1168 
1169  if (mx > chwidth)
1170  {
1171  mx = chwidth;
1172  }
1173 
1174  if (my > chheight)
1175  {
1176  my = chheight;
1177  }
1178 
1179  int x = thearea.x() / chunksize;
1180 
1181  while (x < mx)
1182  {
1183  int y = thearea.y() / chunksize;
1184 
1185  while (y < my)
1186  {
1187  chunk(x, y).takeChange();
1188  y++;
1189  }
1190 
1191  x++;
1192  }
1193 }
1194 
1195 
1196 /*
1197  \internal
1198 */
1199 QRect QtCanvas::changeBounds()
1200 {
1201  QRect area = QRect(0, 0, width(), height());
1202 
1203  int mx = (area.x() + area.width() + chunksize) / chunksize;
1204  int my = (area.y() + area.height() + chunksize) / chunksize;
1205 
1206  if (mx > chwidth)
1207  {
1208  mx = chwidth;
1209  }
1210 
1211  if (my > chheight)
1212  {
1213  my = chheight;
1214  }
1215 
1216  QRect result;
1217 
1218  int x = area.x() / chunksize;
1219 
1220  while (x < mx)
1221  {
1222  int y = area.y() / chunksize;
1223 
1224  while (y < my)
1225  {
1226  QtCanvasChunk& ch = chunk(x, y);
1227 
1228  if (ch.hasChanged())
1229  {
1230  result |= QRect(x * chunksize, y * chunksize, chunksize + 1, chunksize + 1);
1231  }
1232 
1233  y++;
1234  }
1235 
1236  x++;
1237  }
1238 
1239  return result;
1240 }
1241 
1242 /*
1243  Paints all canvas items that are in the area \a clip to \a
1244  painter, using double-buffering if \a dbuf is true.
1245 
1246  e.g. to print the canvas to a printer:
1247  \code
1248  QPrinter pr;
1249  if (pr.setup()) {
1250  QPainter p(&pr);
1251  canvas.drawArea(canvas.rect(), &p);
1252  }
1253  \endcode
1254 */
1255 void QtCanvas::drawArea(const QRect& clip, QPainter* painter, bool dbuf)
1256 {
1257  if (painter)
1258  {
1259  drawCanvasArea(clip, painter, dbuf);
1260  }
1261 }
1262 
1263 #include <QDebug>
1264 /*
1265  \internal
1266 */
1267 void QtCanvas::drawCanvasArea(const QRect& inarea, QPainter* p, bool /*double_buffer*/)
1268 {
1269  QRect area = inarea.intersected(QRect(0, 0, width(), height()));
1270 
1271  if (!p)
1272  {
1273  return; // Nothing to do.
1274  }
1275 
1276  int lx = area.x() / chunksize;
1277  int ly = area.y() / chunksize;
1278  int mx = area.right() / chunksize;
1279  int my = area.bottom() / chunksize;
1280 
1281  if (mx >= chwidth)
1282  {
1283  mx = chwidth - 1;
1284  }
1285 
1286  if (my >= chheight)
1287  {
1288  my = chheight - 1;
1289  }
1290 
1291  QtCanvasItemList allvisible;
1292 
1293  // Stores the region within area that need to be drawn. It is relative
1294  // to area.topLeft() (so as to keep within bounds of 16-bit XRegions)
1295  QRegion rgn;
1296 
1297  for (int x = lx; x <= mx; x++)
1298  {
1299  for (int y = ly; y <= my; y++)
1300  {
1301  // Only reset change if all views updating, and
1302  // wholy within area. (conservative: ignore entire boundary)
1303  //
1304  // Disable this to help debugging.
1305  //
1306  if (!p)
1307  {
1308  if (chunk(x, y).takeChange())
1309  {
1310  // ### should at least make bands
1311  rgn |= QRegion(x * chunksize - area.x(), y * chunksize - area.y(),
1312  chunksize, chunksize);
1313  allvisible += chunk(x, y).list();
1314  }
1315  }
1316  else
1317  {
1318  allvisible += chunk(x, y).list();
1319  }
1320  }
1321  }
1322 
1323  qSort(allvisible.begin(), allvisible.end(), QtCanvasItemLess());
1324 
1325  drawBackground(*p, area);
1326 
1327  if (!allvisible.isEmpty())
1328  {
1329  QtCanvasItem* prev = 0;
1330 
1331  for (int i = allvisible.size() - 1; i >= 0; --i)
1332  {
1333  QtCanvasItem* g = allvisible[i];
1334 
1335  if (g != prev)
1336  {
1337  g->draw(*p);
1338  prev = g;
1339  }
1340  }
1341  }
1342 
1343  drawForeground(*p, area);
1344 }
1345 
1346 /*
1347 \internal
1348 This method to informs the QtCanvas that a given chunk is
1349 `dirty' and needs to be redrawn in the next Update.
1350 
1351 (\a x, \a y) is a chunk location.
1352 
1353 The sprite classes call this. Any new derived class of QtCanvasItem
1354 must do so too. SetChangedChunkContaining can be used instead.
1355 */
1356 void QtCanvas::setChangedChunk(int x, int y)
1357 {
1358  if (validChunk(x, y))
1359  {
1360  QtCanvasChunk& ch = chunk(x, y);
1361  ch.change();
1362  }
1363 }
1364 
1365 /*
1366 \internal
1367 This method to informs the QtCanvas that the chunk containing a given
1368 pixel is `dirty' and needs to be redrawn in the next Update.
1369 
1370 (\a x, \a y) is a pixel location.
1371 
1372 The item classes call this. Any new derived class of QtCanvasItem must
1373 do so too. SetChangedChunk can be used instead.
1374 */
1375 void QtCanvas::setChangedChunkContaining(int x, int y)
1376 {
1377  if (x >= 0 && x < width() && y >= 0 && y < height())
1378  {
1379  QtCanvasChunk& chunk = chunkContaining(x, y);
1380  chunk.change();
1381  }
1382 }
1383 
1384 /*
1385 \internal
1386 This method adds the QtCanvasItem \a g to the list of those which need to be
1387 drawn if the given chunk at location (\a x, \a y) is redrawn. Like
1388 SetChangedChunk and SetChangedChunkContaining, this method marks the
1389 chunk as `dirty'.
1390 */
1391 void QtCanvas::addItemToChunk(QtCanvasItem* g, int x, int y)
1392 {
1393  if (validChunk(x, y))
1394  {
1395  chunk(x, y).add(g);
1396  }
1397 }
1398 
1399 /*
1400 \internal
1401 This method removes the QtCanvasItem \a g from the list of those which need to
1402 be drawn if the given chunk at location (\a x, \a y) is redrawn. Like
1403 SetChangedChunk and SetChangedChunkContaining, this method marks the chunk
1404 as `dirty'.
1405 */
1406 void QtCanvas::removeItemFromChunk(QtCanvasItem* g, int x, int y)
1407 {
1408  if (validChunk(x, y))
1409  {
1410  chunk(x, y).remove(g);
1411  }
1412 }
1413 
1414 
1415 /*
1416 \internal
1417 This method adds the QtCanvasItem \a g to the list of those which need to be
1418 drawn if the chunk containing the given pixel (\a x, \a y) is redrawn. Like
1419 SetChangedChunk and SetChangedChunkContaining, this method marks the
1420 chunk as `dirty'.
1421 */
1422 void QtCanvas::addItemToChunkContaining(QtCanvasItem* g, int x, int y)
1423 {
1424  if (x >= 0 && x < width() && y >= 0 && y < height())
1425  {
1426  chunkContaining(x, y).add(g);
1427  }
1428 }
1429 
1430 /*
1431 \internal
1432 This method removes the QtCanvasItem \a g from the list of those which need to
1433 be drawn if the chunk containing the given pixel (\a x, \a y) is redrawn.
1434 Like SetChangedChunk and SetChangedChunkContaining, this method
1435 marks the chunk as `dirty'.
1436 */
1438 {
1439  if (x >= 0 && x < width() && y >= 0 && y < height())
1440  {
1441  chunkContaining(x, y).remove(g);
1442  }
1443 }
1444 
1445 /*
1446  Returns the color set by setBackgroundColor(). By default, this is
1447  white.
1448 
1449  This function is not a reimplementation of
1450  QWidget::backgroundColor() (QtCanvas is not a subclass of QWidget),
1451  but all QtCanvasViews that are viewing the canvas will set their
1452  backgrounds to this color.
1453 
1454  \sa setBackgroundColor(), backgroundPixmap()
1455 */
1456 QColor QtCanvas::backgroundColor() const
1457 {
1458  return bgcolor;
1459 }
1460 
1461 /*
1462  Sets the solid background to be the color \a c.
1463 
1464  \sa backgroundColor(), setBackgroundPixmap(), setTiles()
1465 */
1466 void QtCanvas::setBackgroundColor(const QColor& c)
1467 {
1468  if (bgcolor != c)
1469  {
1470  bgcolor = c;
1471 
1472  for (int i = 0; i < d->viewList.size(); ++i)
1473  {
1474  QtCanvasView* view = d->viewList.at(i);
1475  QPalette::ColorRole role = view->widget()->backgroundRole();
1476  QPalette viewPalette = view->widget()->palette();
1477  viewPalette.setColor(role, bgcolor);
1478  view->widget()->setPalette(viewPalette);
1479  }
1480 
1481  setAllChanged();
1482  }
1483 }
1484 
1485 /*
1486  Returns the pixmap set by setBackgroundPixmap(). By default,
1487  this is a null pixmap.
1488 
1489  \sa setBackgroundPixmap(), backgroundColor()
1490 */
1491 QPixmap QtCanvas::backgroundPixmap() const
1492 {
1493  return pm;
1494 }
1495 
1496 /*
1497  Sets the solid background to be the pixmap \a p repeated as
1498  necessary to cover the entire canvas.
1499 
1500  \sa backgroundPixmap(), setBackgroundColor(), setTiles()
1501 */
1502 void QtCanvas::setBackgroundPixmap(const QPixmap& p)
1503 {
1504  setTiles(p, 1, 1, p.width(), p.height());
1505 
1506  for (int i = 0; i < d->viewList.size(); ++i)
1507  {
1508  QtCanvasView* view = d->viewList.at(i);
1509  view->widget()->update();
1510  }
1511 }
1512 
1513 /*
1514  This virtual function is called for all updates of the canvas. It
1515  renders any background graphics using the painter \a painter, in
1516  the area \a clip. If the canvas has a background pixmap or a tiled
1517  background, that graphic is used, otherwise the canvas is cleared
1518  using the background color.
1519 
1520  If the graphics for an area change, you must explicitly call
1521  setChanged(const QRect&) for the result to be visible when
1522  update() is next called.
1523 
1524  \sa setBackgroundColor(), setBackgroundPixmap(), setTiles()
1525 */
1526 void QtCanvas::drawBackground(QPainter& painter, const QRect& clip)
1527 {
1528  if (pm.isNull())
1529  {
1530  painter.fillRect(clip, bgcolor);
1531  }
1532  else if (!grid)
1533  {
1534  for (int x = clip.x() / pm.width();
1535  x < (clip.x() + clip.width() + pm.width() - 1) / pm.width(); x++)
1536  {
1537  for (int y = clip.y() / pm.height();
1538  y < (clip.y() + clip.height() + pm.height() - 1) / pm.height(); y++)
1539  {
1540  painter.drawPixmap(x * pm.width(), y * pm.height(), pm);
1541  }
1542  }
1543  }
1544  else
1545  {
1546  const int x1 = clip.left() / tilew;
1547  int x2 = clip.right() / tilew;
1548  const int y1 = clip.top() / tileh;
1549  int y2 = clip.bottom() / tileh;
1550 
1551  const int roww = pm.width() / tilew;
1552 
1553  for (int j = y1; j <= y2; j++)
1554  {
1555  int jj = j % tilesVertically();
1556 
1557  for (int i = x1; i <= x2; i++)
1558  {
1559  int t = tile(i % tilesHorizontally(), jj);
1560  int tx = t % roww;
1561  int ty = t / roww;
1562  painter.drawPixmap(i * tilew, j * tileh, pm,
1563  tx * tilew, ty * tileh, tilew, tileh);
1564  }
1565  }
1566  }
1567 }
1568 
1569 /*
1570  This virtual function is called for all updates of the canvas. It
1571  renders any foreground graphics using the painter \a painter, in
1572  the area \a clip.
1573 
1574  If the graphics for an area change, you must explicitly call
1575  setChanged(const QRect&) for the result to be visible when
1576  update() is next called.
1577 
1578  The default is to draw nothing.
1579 */
1580 void QtCanvas::drawForeground(QPainter& painter, const QRect& clip)
1581 {
1582  if (debug_redraw_areas)
1583  {
1584  painter.setPen(red);
1585  painter.setBrush(NoBrush);
1586  painter.drawRect(clip);
1587  }
1588 }
1589 
1590 /*
1591  Sets the QtCanvas to be composed of \a h tiles horizontally and \a
1592  v tiles vertically. Each tile will be an image \a tilewidth by \a
1593  tileheight pixels from pixmap \a p.
1594 
1595  The pixmap \a p is a list of tiles, arranged left to right, (and
1596  in the case of pixmaps that have multiple rows of tiles, top to
1597  bottom), with tile 0 in the top-left corner, tile 1 next to the
1598  right, and so on, e.g.
1599 
1600  \table
1601  \row \i 0 \i 1 \i 2 \i 3
1602  \row \i 4 \i 5 \i 6 \i 7
1603  \endtable
1604 
1605  If the canvas is larger than the matrix of tiles, the entire
1606  matrix is repeated as necessary to cover the whole canvas. If it
1607  is smaller, tiles to the right and bottom are not visible.
1608 
1609  The width and height of \a p must be a multiple of \a tilewidth
1610  and \a tileheight. If they are not the function will do nothing.
1611 
1612  If you want to unset any tiling set, then just pass in a null
1613  pixmap and 0 for \a h, \a v, \a tilewidth, and
1614  \a tileheight.
1615 */
1616 void QtCanvas::setTiles(QPixmap p,
1617  int h, int v, int tilewidth, int tileheight)
1618 {
1619  if (!p.isNull() && (!tilewidth || !tileheight ||
1620  p.width() % tilewidth != 0 || p.height() % tileheight != 0))
1621  {
1622  return;
1623  }
1624 
1625  htiles = h;
1626  vtiles = v;
1627  delete[] grid;
1628  pm = p;
1629 
1630  if (h && v && !p.isNull())
1631  {
1632  grid = new ushort[h * v];
1633  memset(grid, 0, h * v * sizeof(ushort));
1634  tilew = tilewidth;
1635  tileh = tileheight;
1636  }
1637  else
1638  {
1639  grid = 0;
1640  }
1641 
1642  if (h + v > 10)
1643  {
1644  int s = scm(tilewidth, tileheight);
1645  retune(s < 128 ? s : qMax(tilewidth, tileheight));
1646  }
1647 
1648  setAllChanged();
1649 }
1650 
1651 /*
1652  \fn int QtCanvas::tile(int x, int y) const
1653 
1654  Returns the tile at position (\a x, \a y). Initially, all tiles
1655  are 0.
1656 
1657  The parameters must be within range, i.e.
1658  0 < \a x < tilesHorizontally() and
1659  0 < \a y < tilesVertically().
1660 
1661  \sa setTile()
1662 */
1663 
1664 /*
1665  \fn int QtCanvas::tilesHorizontally() const
1666 
1667  Returns the number of tiles horizontally.
1668 */
1669 
1670 /*
1671  \fn int QtCanvas::tilesVertically() const
1672 
1673  Returns the number of tiles vertically.
1674 */
1675 
1676 /*
1677  \fn int QtCanvas::tileWidth() const
1678 
1679  Returns the width of each tile.
1680 */
1681 
1682 /*
1683  \fn int QtCanvas::tileHeight() const
1684 
1685  Returns the height of each tile.
1686 */
1687 
1688 
1689 /*
1690  Sets the tile at (\a x, \a y) to use tile number \a tilenum, which
1691  is an index into the tile pixmaps. The canvas will update
1692  appropriately when update() is next called.
1693 
1694  The images are taken from the pixmap set by setTiles() and are
1695  arranged left to right, (and in the case of pixmaps that have
1696  multiple rows of tiles, top to bottom), with tile 0 in the
1697  top-left corner, tile 1 next to the right, and so on, e.g.
1698 
1699  \table
1700  \row \i 0 \i 1 \i 2 \i 3
1701  \row \i 4 \i 5 \i 6 \i 7
1702  \endtable
1703 
1704  \sa tile() setTiles()
1705 */
1706 void QtCanvas::setTile(int x, int y, int tilenum)
1707 {
1708  ushort& t = grid[x + y * htiles];
1709 
1710  if (t != tilenum)
1711  {
1712  t = tilenum;
1713 
1714  if (tilew == tileh && tilew == chunksize)
1715  {
1716  setChangedChunk(x, y); // common case
1717  }
1718  else
1719  {
1720  setChanged(QRect(x * tilew, y * tileh, tilew, tileh));
1721  }
1722  }
1723 }
1724 
1725 
1726 // lesser-used data in canvas item, plus room for extension.
1727 // Be careful adding to this - check all usages.
1728 class QtCanvasItemExtra
1729 {
1730  QtCanvasItemExtra() : vx(0.0), vy(0.0) { }
1731  double vx, vy;
1732  friend class QtCanvasItem;
1733 };
1734 
1735 
1736 /*
1737  \class QtCanvasItem qtcanvas.h
1738  \brief The QtCanvasItem class provides an abstract graphic object on a QtCanvas.
1739 
1740  A variety of QtCanvasItem subclasses provide immediately usable
1741  behaviour. This class is a pure abstract superclass providing the
1742  behaviour that is shared among all the concrete canvas item classes.
1743  QtCanvasItem is not intended for direct subclassing. It is much easier
1744  to subclass one of its subclasses, e.g. QtCanvasPolygonalItem (the
1745  commonest base class), QtCanvasRectangle, QtCanvasSprite, QtCanvasEllipse
1746  or QtCanvasText.
1747 
1748  Canvas items are added to a canvas by constructing them and passing the
1749  canvas to the canvas item's constructor. An item can be moved to a
1750  different canvas using setCanvas().
1751 
1752  Items appear on the canvas after their \link show() show()\endlink
1753  function has been called (or \link setVisible()
1754  setVisible(true)\endlink), and \e after update() has been called. The
1755  canvas only shows items that are \link setVisible() visible\endlink,
1756  and then only if \l update() is called. If you created the canvas
1757  without passing a width and height to the constructor you'll also need
1758  to call \link QtCanvas::resize() resize()\endlink. Since the canvas
1759  background defaults to white and canvas items default to white,
1760  you may need to change colors to see your items.
1761 
1762  A QtCanvasItem object can be moved in the x(), y() and z() dimensions
1763  using functions such as move(), moveBy(), setX(), setY() and setZ(). A
1764  canvas item can be set in motion, `animated', using setAnimated() and
1765  given a velocity in the x and y directions with setXVelocity() and
1766  setYVelocity() -- the same effect can be achieved by calling
1767  setVelocity(). Use the collidesWith() function to see if the canvas item
1768  will collide on the \e next advance(1) and use collisions() to see what
1769  collisions have occurred.
1770 
1771  Use QtCanvasSprite or your own subclass of QtCanvasSprite to create canvas
1772  items which are animated, i.e. which change over time.
1773 
1774  The size of a canvas item is given by boundingRect(). Use
1775  boundingRectAdvanced() to see what the size of the canvas item will be
1776  \e after the next advance(1) call.
1777 
1778  The rtti() function is used for identifying subclasses of QtCanvasItem.
1779  The canvas() function returns a pointer to the canvas which contains the
1780  canvas item.
1781 
1782  QtCanvasItem provides the show() and isVisible() functions like those in
1783  QWidget.
1784 
1785  QtCanvasItem also provides the setEnabled(), setActive() and
1786  setSelected() functions; these functions set the relevant boolean and
1787  cause a repaint but the boolean values they set are not used in
1788  QtCanvasItem itself. You can make use of these booleans in your subclasses.
1789 
1790  By default, canvas items have no velocity, no size, and are not in
1791  motion. The subclasses provided in Qt do not change these defaults
1792  except where noted.
1793 
1794 */
1795 
1796 /*
1797  \enum QtCanvasItem::RttiValues
1798 
1799  This enum is used to name the different types of canvas item.
1800 
1801  \value Rtti_Item Canvas item abstract base class
1802  \value Rtti_Ellipse
1803  \value Rtti_Line
1804  \value Rtti_Polygon
1805  \value Rtti_PolygonalItem
1806  \value Rtti_Rectangle
1807  \value Rtti_Spline
1808  \value Rtti_Sprite
1809  \value Rtti_Text
1810 
1811 */
1812 
1813 /*
1814  \fn void QtCanvasItem::update()
1815 
1816  Call this function to repaint the canvas's changed chunks.
1817 */
1818 
1819 /*
1820  Constructs a QtCanvasItem on canvas \a canvas.
1821 
1822  \sa setCanvas()
1823 */
1825  cnv(canvas),
1826  myx(0), myy(0), myz(0)
1827 {
1828  ani = 0;
1829  vis = 0;
1830  val = 0;
1831  sel = 0;
1832  ena = 0;
1833  act = 0;
1834 
1835  ext = 0;
1836 
1837  if (cnv)
1838  {
1839  cnv->addItem(this);
1840  }
1841 }
1842 
1843 /*
1844  Destroys the QtCanvasItem and removes it from its canvas.
1845 */
1847 {
1848  if (cnv)
1849  {
1850  cnv->removeItem(this);
1851  cnv->removeAnimation(this);
1852  }
1853 
1854  delete ext;
1855 }
1856 
1857 QtCanvasItemExtra& QtCanvasItem::extra()
1858 {
1859  if (!ext)
1860  {
1861  ext = new QtCanvasItemExtra;
1862  }
1863 
1864  return *ext;
1865 }
1866 
1867 /*
1868  \fn double QtCanvasItem::x() const
1869 
1870  Returns the horizontal position of the canvas item. Note that
1871  subclasses often have an origin other than the top-left corner.
1872 */
1873 
1874 /*
1875  \fn double QtCanvasItem::y() const
1876 
1877  Returns the vertical position of the canvas item. Note that
1878  subclasses often have an origin other than the top-left corner.
1879 */
1880 
1881 /*
1882  \fn double QtCanvasItem::z() const
1883 
1884  Returns the z index of the canvas item, which is used for visual
1885  order: higher-z items obscure (are in front of) lower-z items.
1886 */
1887 
1888 /*
1889  \fn void QtCanvasItem::setX(double x)
1890 
1891  Moves the canvas item so that its x-position is \a x.
1892 
1893  \sa x(), move()
1894 */
1895 
1896 /*
1897  \fn void QtCanvasItem::setY(double y)
1898 
1899  Moves the canvas item so that its y-position is \a y.
1900 
1901  \sa y(), move()
1902 */
1903 
1904 /*
1905  \fn void QtCanvasItem::setZ(double z)
1906 
1907  Sets the z index of the canvas item to \a z. Higher-z items
1908  obscure (are in front of) lower-z items.
1909 
1910  \sa z(), move()
1911 */
1912 
1913 
1914 /*
1915  Moves the canvas item relative to its current position by (\a dx,
1916  \a dy).
1917 */
1918 void QtCanvasItem::moveBy(double dx, double dy)
1919 {
1920  if (dx || dy)
1921  {
1922  removeFromChunks();
1923  myx += dx;
1924  myy += dy;
1925  addToChunks();
1926  }
1927 }
1928 
1929 
1930 /*
1931  Moves the canvas item to the absolute position (\a x, \a y).
1932 */
1933 void QtCanvasItem::move(double x, double y)
1934 {
1935  moveBy(x - myx, y - myy);
1936 }
1937 
1938 
1939 /*
1940  Returns true if the canvas item is in motion; otherwise returns
1941  false.
1942 
1943  \sa setVelocity(), setAnimated()
1944 */
1945 bool QtCanvasItem::animated() const
1946 {
1947  return (bool)ani;
1948 }
1949 
1950 /*
1951  Sets the canvas item to be in motion if \a y is true, or not if \a
1952  y is false. The speed and direction of the motion is set with
1953  setVelocity(), or with setXVelocity() and setYVelocity().
1954 
1955  \sa advance(), QtCanvas::advance()
1956 */
1957 void QtCanvasItem::setAnimated(bool y)
1958 {
1959  if (y != (bool)ani)
1960  {
1961  ani = (uint)y;
1962 
1963  if (y)
1964  {
1965  cnv->addAnimation(this);
1966  }
1967  else
1968  {
1969  cnv->removeAnimation(this);
1970  }
1971  }
1972 }
1973 
1974 /*
1975  \fn void QtCanvasItem::setXVelocity(double vx)
1976 
1977  Sets the horizontal component of the canvas item's velocity to \a vx.
1978 
1979  \sa setYVelocity() setVelocity()
1980 */
1981 
1982 /*
1983  \fn void QtCanvasItem::setYVelocity(double vy)
1984 
1985  Sets the vertical component of the canvas item's velocity to \a vy.
1986 
1987  \sa setXVelocity() setVelocity()
1988 */
1989 
1990 /*
1991  Sets the canvas item to be in motion, moving by \a vx and \a vy
1992  pixels in the horizontal and vertical directions respectively.
1993 
1994  \sa advance() setXVelocity() setYVelocity()
1995 */
1996 void QtCanvasItem::setVelocity(double vx, double vy)
1997 {
1998  if (ext || vx != 0.0 || vy != 0.0)
1999  {
2000  if (!ani)
2001  {
2002  setAnimated(true);
2003  }
2004 
2005  extra().vx = vx;
2006  extra().vy = vy;
2007  }
2008 }
2009 
2010 /*
2011  Returns the horizontal velocity component of the canvas item.
2012 */
2013 double QtCanvasItem::xVelocity() const
2014 {
2015  return ext ? ext->vx : 0;
2016 }
2017 
2018 /*
2019  Returns the vertical velocity component of the canvas item.
2020 */
2021 double QtCanvasItem::yVelocity() const
2022 {
2023  return ext ? ext->vy : 0;
2024 }
2025 
2026 /*
2027  The default implementation moves the canvas item, if it is
2028  animated(), by the preset velocity if \a phase is 1, and does
2029  nothing if \a phase is 0.
2030 
2031  Note that if you reimplement this function, the reimplementation
2032  must not change the canvas in any way, for example it must not add
2033  or remove items.
2034 
2035  \sa QtCanvas::advance() setVelocity()
2036 */
2037 void QtCanvasItem::advance(int phase)
2038 {
2039  if (ext && phase == 1)
2040  {
2041  moveBy(ext->vx, ext->vy);
2042  }
2043 }
2044 
2045 /*
2046  \fn void QtCanvasItem::draw(QPainter& painter)
2047 
2048  This abstract virtual function draws the canvas item using \a painter.
2049 */
2050 
2051 /*
2052  Sets the QtCanvas upon which the canvas item is to be drawn to \a c.
2053 
2054  \sa canvas()
2055 */
2057 {
2058  bool v = isVisible();
2059  setVisible(false);
2060 
2061  if (cnv)
2062  {
2063  if (ext)
2064  {
2065  cnv->removeAnimation(this);
2066  }
2067 
2068  cnv->removeItem(this);
2069  }
2070 
2071  cnv = c;
2072 
2073  if (cnv)
2074  {
2075  cnv->addItem(this);
2076 
2077  if (ext)
2078  {
2079  cnv->addAnimation(this);
2080  }
2081  }
2082 
2083  setVisible(v);
2084 }
2085 
2086 /*
2087  \fn QtCanvas* QtCanvasItem::canvas() const
2088 
2089  Returns the canvas containing the canvas item.
2090 */
2091 
2092 /* Shorthand for setVisible(true). */
2093 void QtCanvasItem::show()
2094 {
2095  setVisible(true);
2096 }
2097 
2098 /* Shorthand for setVisible(false). */
2099 void QtCanvasItem::hide()
2100 {
2101  setVisible(false);
2102 }
2103 
2104 /*
2105  Makes the canvas item visible if \a yes is true, or invisible if
2106  \a yes is false. The change takes effect when QtCanvas::update() is
2107  next called.
2108 */
2109 void QtCanvasItem::setVisible(bool yes)
2110 {
2111  if ((bool)vis != yes)
2112  {
2113  if (yes)
2114  {
2115  vis = (uint)yes;
2116  addToChunks();
2117  }
2118  else
2119  {
2120  removeFromChunks();
2121  vis = (uint)yes;
2122  }
2123  }
2124 }
2125 /*
2126  \obsolete
2127  \fn bool QtCanvasItem::visible() const
2128  Use isVisible() instead.
2129 */
2130 
2131 /*
2132  \fn bool QtCanvasItem::isVisible() const
2133 
2134  Returns true if the canvas item is visible; otherwise returns
2135  false.
2136 
2137  Note that in this context true does \e not mean that the canvas
2138  item is currently in a view, merely that if a view is showing the
2139  area where the canvas item is positioned, and the item is not
2140  obscured by items with higher z values, and the view is not
2141  obscured by overlaying windows, it would be visible.
2142 
2143  \sa setVisible(), z()
2144 */
2145 
2146 /*
2147  \obsolete
2148  \fn bool QtCanvasItem::selected() const
2149  Use isSelected() instead.
2150 */
2151 
2152 /*
2153  \fn bool QtCanvasItem::isSelected() const
2154 
2155  Returns true if the canvas item is selected; otherwise returns false.
2156 */
2157 
2158 /*
2159  Sets the selected flag of the item to \a yes. If this changes the
2160  item's selected state the item will be redrawn when
2161  QtCanvas::update() is next called.
2162 
2163  The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem
2164  subclasses do not make use of this value. The setSelected()
2165  function is supplied because many applications need it, but it is
2166  up to you how you use the isSelected() value.
2167 */
2168 void QtCanvasItem::setSelected(bool yes)
2169 {
2170  if ((bool)sel != yes)
2171  {
2172  sel = (uint)yes;
2173  changeChunks();
2174  }
2175 }
2176 
2177 /*
2178  \obsolete
2179  \fn bool QtCanvasItem::enabled() const
2180  Use isEnabled() instead.
2181 */
2182 
2183 /*
2184  \fn bool QtCanvasItem::isEnabled() const
2185 
2186  Returns true if the QtCanvasItem is enabled; otherwise returns false.
2187 */
2188 
2189 /*
2190  Sets the enabled flag of the item to \a yes. If this changes the
2191  item's enabled state the item will be redrawn when
2192  QtCanvas::update() is next called.
2193 
2194  The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem
2195  subclasses do not make use of this value. The setEnabled()
2196  function is supplied because many applications need it, but it is
2197  up to you how you use the isEnabled() value.
2198 */
2199 void QtCanvasItem::setEnabled(bool yes)
2200 {
2201  if (ena != (uint)yes)
2202  {
2203  ena = (uint)yes;
2204  changeChunks();
2205  }
2206 }
2207 
2208 /*
2209  \obsolete
2210  \fn bool QtCanvasItem::active() const
2211  Use isActive() instead.
2212 */
2213 
2214 /*
2215  \fn bool QtCanvasItem::isActive() const
2216 
2217  Returns true if the QtCanvasItem is active; otherwise returns false.
2218 */
2219 
2220 /*
2221  Sets the active flag of the item to \a yes. If this changes the
2222  item's active state the item will be redrawn when
2223  QtCanvas::update() is next called.
2224 
2225  The QtCanvas, QtCanvasItem and the Qt-supplied QtCanvasItem
2226  subclasses do not make use of this value. The setActive() function
2227  is supplied because many applications need it, but it is up to you
2228  how you use the isActive() value.
2229 */
2230 void QtCanvasItem::setActive(bool yes)
2231 {
2232  if (act != (uint)yes)
2233  {
2234  act = (uint)yes;
2235  changeChunks();
2236  }
2237 }
2238 
2240 {
2241  const QImage* s2image = s2->imageAdvanced()->collision_mask;
2242  QRect s2area = s2->boundingRectAdvanced();
2243 
2244  QRect cyourarea(s2area.x(), s2area.y(),
2245  s2area.width(), s2area.height());
2246 
2247  QImage* s1image = s1->imageAdvanced()->collision_mask;
2248 
2249  QRect s1area = s1->boundingRectAdvanced();
2250 
2251  QRect ourarea = s1area.intersected(cyourarea);
2252 
2253  if (ourarea.isEmpty())
2254  {
2255  return false;
2256  }
2257 
2258  int x2 = ourarea.x() - cyourarea.x();
2259  int y2 = ourarea.y() - cyourarea.y();
2260  int x1 = ourarea.x() - s1area.x();
2261  int y1 = ourarea.y() - s1area.y();
2262  int w = ourarea.width();
2263  int h = ourarea.height();
2264 
2265  if (!s2image)
2266  {
2267  if (!s1image)
2268  {
2269  return w > 0 && h > 0;
2270  }
2271 
2272  // swap everything around
2273  int t;
2274  t = x1;
2275  x1 = x2;
2276  x2 = t;
2277  t = y1;
2278  x1 = y2;
2279  y2 = t;
2280  s2image = s1image;
2281  s1image = 0;
2282  }
2283 
2284  // s2image != 0
2285 
2286  // A non-linear search may be more efficient.
2287  // Perhaps spiralling out from the center, or a simpler
2288  // vertical expansion from the centreline.
2289 
2290  // We assume that sprite masks don't have
2291  // different bit orders.
2292  //
2293  // Q_ASSERT(s1image->bitOrder() == s2image->bitOrder());
2294 
2295  if (s1image)
2296  {
2297  if (s1image->format() == QImage::Format_MonoLSB)
2298  {
2299  for (int j = 0; j < h; j++)
2300  {
2301  uchar* ml = s1image->scanLine(y1 + j);
2302  const uchar* yl = s2image->scanLine(y2 + j);
2303 
2304  for (int i = 0; i < w; i++)
2305  {
2306  if (*(yl + ((x2 + i) >> 3)) & (1 << ((x2 + i) & 7))
2307  && *(ml + ((x1 + i) >> 3)) & (1 << ((x1 + i) & 7)))
2308  {
2309  return true;
2310  }
2311  }
2312  }
2313  }
2314  else
2315  {
2316  for (int j = 0; j < h; j++)
2317  {
2318  uchar* ml = s1image->scanLine(y1 + j);
2319  const uchar* yl = s2image->scanLine(y2 + j);
2320 
2321  for (int i = 0; i < w; i++)
2322  {
2323  if (*(yl + ((x2 + i) >> 3)) & (1 << (7 - ((x2 + i) & 7)))
2324  && *(ml + ((x1 + i) >> 3)) & (1 << (7 - ((x1 + i) & 7))))
2325  {
2326  return true;
2327  }
2328  }
2329  }
2330  }
2331  }
2332  else
2333  {
2334  if (s2image->format() == QImage::Format_MonoLSB)
2335  {
2336  for (int j = 0; j < h; j++)
2337  {
2338  const uchar* yl = s2image->scanLine(y2 + j);
2339 
2340  for (int i = 0; i < w; i++)
2341  {
2342  if (*(yl + ((x2 + i) >> 3)) & (1 << ((x2 + i) & 7)))
2343  {
2344  return true;
2345  }
2346  }
2347  }
2348  }
2349  else
2350  {
2351  for (int j = 0; j < h; j++)
2352  {
2353  const uchar* yl = s2image->scanLine(y2 + j);
2354 
2355  for (int i = 0; i < w; i++)
2356  {
2357  if (*(yl + ((x2 + i) >> 3)) & (1 << (7 - ((x2 + i) & 7))))
2358  {
2359  return true;
2360  }
2361  }
2362  }
2363  }
2364  }
2365 
2366  return false;
2367 }
2368 
2369 static bool collision_double_dispatch(const QtCanvasSprite* s1,
2370  const QtCanvasPolygonalItem* p1,
2371  const QtCanvasRectangle* r1,
2372  const QtCanvasEllipse* e1,
2373  const QtCanvasText* t1,
2374  const QtCanvasSprite* s2,
2375  const QtCanvasPolygonalItem* p2,
2376  const QtCanvasRectangle* r2,
2377  const QtCanvasEllipse* e2,
2378  const QtCanvasText* t2)
2379 {
2380  const QtCanvasItem* i1 = s1 ?
2381  (const QtCanvasItem*)s1 : p1 ?
2382  (const QtCanvasItem*)p1 : r1 ?
2383  (const QtCanvasItem*)r1 : e1 ?
2384  (const QtCanvasItem*)e1 : (const QtCanvasItem*)t1;
2385  const QtCanvasItem* i2 = s2 ?
2386  (const QtCanvasItem*)s2 : p2 ?
2387  (const QtCanvasItem*)p2 : r2 ?
2388  (const QtCanvasItem*)r2 : e2 ?
2389  (const QtCanvasItem*)e2 : (const QtCanvasItem*)t2;
2390 
2391  if (s1 && s2)
2392  {
2393  // a
2394  return qt_testCollision(s1, s2);
2395  }
2396  else if ((r1 || t1 || s1) && (r2 || t2 || s2))
2397  {
2398  // b
2399  QRect rc1 = i1->boundingRectAdvanced();
2400  QRect rc2 = i2->boundingRectAdvanced();
2401  return rc1.intersects(rc2);
2402  }
2403  else if (e1 && e2
2404  && e1->angleLength() >= 360 * 16 && e2->angleLength() >= 360 * 16
2405  && e1->width() == e1->height()
2406  && e2->width() == e2->height())
2407  {
2408  // c
2409  double xd = (e1->x() + e1->xVelocity()) - (e2->x() + e1->xVelocity());
2410  double yd = (e1->y() + e1->yVelocity()) - (e2->y() + e1->yVelocity());
2411  double rd = (e1->width() + e2->width()) / 2;
2412  return xd * xd + yd * yd <= rd * rd;
2413  }
2414  else if (p1 && (p2 || s2 || t2))
2415  {
2416  // d
2417  QPolygon pa1 = p1->areaPointsAdvanced();
2418  QPolygon pa2 = p2 ? p2->areaPointsAdvanced()
2419  : QPolygon(i2->boundingRectAdvanced());
2420  bool col = !(QRegion(pa1) & QRegion(pa2, Qt::WindingFill)).isEmpty();
2421 
2422  return col;
2423  }
2424  else
2425  {
2426  return collision_double_dispatch(s2, p2, r2, e2, t2,
2427  s1, p1, r1, e1, t1);
2428  }
2429 }
2430 
2431 /*
2432  \fn bool QtCanvasItem::collidesWith(const QtCanvasItem* other) const
2433 
2434  Returns true if the canvas item will collide with the \a other
2435  item \e after they have moved by their current velocities;
2436  otherwise returns false.
2437 
2438  \sa collisions()
2439 */
2440 
2441 
2442 /*
2443  \class QtCanvasSprite qtcanvas.h
2444  \brief The QtCanvasSprite class provides an animated canvas item on a QtCanvas.
2445 
2446  A canvas sprite is an object which can contain any number of images
2447  (referred to as frames), only one of which is current, i.e.
2448  displayed, at any one time. The images can be passed in the
2449  constructor or set or changed later with setSequence(). If you
2450  subclass QtCanvasSprite you can change the frame that is displayed
2451  periodically, e.g. whenever QtCanvasItem::advance(1) is called to
2452  create the effect of animation.
2453 
2454  The current frame can be set with setFrame() or with move(). The
2455  number of frames available is given by frameCount(). The bounding
2456  rectangle of the current frame is returned by boundingRect().
2457 
2458  The current frame's image can be retrieved with image(); use
2459  imageAdvanced() to retrieve the image for the frame that will be
2460  shown after advance(1) is called. Use the image() overload passing
2461  it an integer index to retrieve a particular image from the list of
2462  frames.
2463 
2464  Use width() and height() to retrieve the dimensions of the current
2465  frame.
2466 
2467  Use leftEdge() and rightEdge() to retrieve the current frame's
2468  left-hand and right-hand x-coordinates respectively. Use
2469  bottomEdge() and topEdge() to retrieve the current frame's bottom
2470  and top y-coordinates respectively. These functions have an overload
2471  which will accept an integer frame number to retrieve the
2472  coordinates of a particular frame.
2473 
2474  QtCanvasSprite draws very quickly, at the expense of memory.
2475 
2476  The current frame's image can be drawn on a painter with draw().
2477 
2478  Like any other canvas item, canvas sprites can be moved with
2479  move() which sets the x and y coordinates and the frame number, as
2480  well as with QtCanvasItem::move() and QtCanvasItem::moveBy(), or by
2481  setting coordinates with QtCanvasItem::setX(), QtCanvasItem::setY()
2482  and QtCanvasItem::setZ().
2483 
2484 */
2485 
2486 
2487 /*
2488  \reimp
2489 */
2490 bool QtCanvasSprite::collidesWith(const QtCanvasItem* i) const
2491 {
2492  return i->collidesWith(this, 0, 0, 0, 0);
2493 }
2494 
2495 /*
2496  Returns true if the canvas item collides with any of the given
2497  items; otherwise returns false. The parameters, \a s, \a p, \a r,
2498  \a e and \a t, are all the same object, this is just a type
2499  resolution trick.
2500 */
2502  const QtCanvasPolygonalItem* p,
2503  const QtCanvasRectangle* r,
2504  const QtCanvasEllipse* e,
2505  const QtCanvasText* t) const
2506 {
2507  return collision_double_dispatch(s, p, r, e, t, this, 0, 0, 0, 0);
2508 }
2509 
2510 /*
2511  \reimp
2512 */
2514 {
2515  return i->collidesWith(0, this, 0, 0, 0);
2516 }
2517 
2519  const QtCanvasPolygonalItem* p,
2520  const QtCanvasRectangle* r,
2521  const QtCanvasEllipse* e,
2522  const QtCanvasText* t) const
2523 {
2524  return collision_double_dispatch(s, p, r, e, t, 0, this, 0, 0, 0);
2525 }
2526 
2527 /*
2528  \reimp
2529 */
2530 bool QtCanvasRectangle::collidesWith(const QtCanvasItem* i) const
2531 {
2532  return i->collidesWith(0, this, this, 0, 0);
2533 }
2534 
2536  const QtCanvasPolygonalItem* p,
2537  const QtCanvasRectangle* r,
2538  const QtCanvasEllipse* e,
2539  const QtCanvasText* t) const
2540 {
2541  return collision_double_dispatch(s, p, r, e, t, 0, this, this, 0, 0);
2542 }
2543 
2544 
2545 /*
2546  \reimp
2547 */
2548 bool QtCanvasEllipse::collidesWith(const QtCanvasItem* i) const
2549 {
2550  return i->collidesWith(0, this, 0, this, 0);
2551 }
2552 
2554  const QtCanvasPolygonalItem* p,
2555  const QtCanvasRectangle* r,
2556  const QtCanvasEllipse* e,
2557  const QtCanvasText* t) const
2558 {
2559  return collision_double_dispatch(s, p, r, e, t, 0, this, 0, this, 0);
2560 }
2561 
2562 /*
2563  \reimp
2564 */
2565 bool QtCanvasText::collidesWith(const QtCanvasItem* i) const
2566 {
2567  return i->collidesWith(0, 0, 0, 0, this);
2568 }
2569 
2571  const QtCanvasPolygonalItem* p,
2572  const QtCanvasRectangle* r,
2573  const QtCanvasEllipse* e,
2574  const QtCanvasText* t) const
2575 {
2576  return collision_double_dispatch(s, p, r, e, t, 0, 0, 0, 0, this);
2577 }
2578 
2579 /*
2580  Returns the list of canvas items that this canvas item has
2581  collided with.
2582 
2583  A collision is generally defined as occurring when the pixels of
2584  one item draw on the pixels of another item, but not all
2585  subclasses are so precise. Also, since pixel-wise collision
2586  detection can be slow, this function works in either exact or
2587  inexact mode, according to the \a exact parameter.
2588 
2589  If \a exact is true, the canvas items returned have been
2590  accurately tested for collision with the canvas item.
2591 
2592  If \a exact is false, the canvas items returned are \e near the
2593  canvas item. You can test the canvas items returned using
2594  collidesWith() if any are interesting collision candidates. By
2595  using this approach, you can ignore some canvas items for which
2596  collisions are not relevant.
2597 
2598  The returned list is a list of QtCanvasItems, but often you will
2599  need to cast the items to their subclass types. The safe way to do
2600  this is to use rtti() before casting. This provides some of the
2601  functionality of the standard C++ dynamic cast operation even on
2602  compilers where dynamic casts are not available.
2603 
2604  Note that a canvas item may be `on' a canvas, e.g. it was created
2605  with the canvas as parameter, even though its coordinates place it
2606  beyond the edge of the canvas's area. Collision detection only
2607  works for canvas items which are wholly or partly within the
2608  canvas's area.
2609 
2610  Note that if items have a velocity (see \l setVelocity()), then
2611  collision testing is done based on where the item \e will be when
2612  it moves, not its current location. For example, a "ball" item
2613  doesn't need to actually embed into a "wall" item before a
2614  collision is detected. For items without velocity, plain
2615  intersection is used.
2616 */
2618 {
2619  return canvas()->collisions(chunks(), this, exact);
2620 }
2621 
2622 /*
2623  Returns a list of canvas items that collide with the point \a p.
2624  The list is ordered by z coordinates, from highest z coordinate
2625  (front-most item) to lowest z coordinate (rear-most item).
2626 */
2627 QtCanvasItemList QtCanvas::collisions(const QPoint& p) const
2628 {
2629  return collisions(QRect(p, QSize(1, 1)));
2630 }
2631 
2632 /*
2633  \overload
2634 
2635  Returns a list of items which collide with the rectangle \a r. The
2636  list is ordered by z coordinates, from highest z coordinate
2637  (front-most item) to lowest z coordinate (rear-most item).
2638 */
2639 QtCanvasItemList QtCanvas::collisions(const QRect& r) const
2640 {
2641  QtCanvasRectangle i(r, (QtCanvas*)this);
2642  i.setPen(NoPen);
2643  i.show(); // doesn't actually show, since we destroy it
2644  QtCanvasItemList l = i.collisions(true);
2645  qSort(l.begin(), l.end(), QtCanvasItemLess());
2646  return l;
2647 }
2648 
2649 /*
2650  \overload
2651 
2652  Returns a list of canvas items which intersect with the chunks
2653  listed in \a chunklist, excluding \a item. If \a exact is true,
2654  only those which actually \link QtCanvasItem::collidesWith()
2655  collide with\endlink \a item are returned; otherwise canvas items
2656  are included just for being in the chunks.
2657 
2658  This is a utility function mainly used to implement the simpler
2659  QtCanvasItem::collisions() function.
2660 */
2661 QtCanvasItemList QtCanvas::collisions(const QPolygon& chunklist,
2662  const QtCanvasItem* item, bool exact) const
2663 {
2664  QSet<QtCanvasItem*> seen;
2665  QtCanvasItemList result;
2666 
2667  for (int i = 0; i < (int)chunklist.count(); i++)
2668  {
2669  int x = chunklist[i].x();
2670  int y = chunklist[i].y();
2671 
2672  if (validChunk(x, y))
2673  {
2674  const QtCanvasItemList& l = chunk(x, y).list();
2675 
2676  for (int i = 0; i < l.size(); ++i)
2677  {
2678  QtCanvasItem* g = l.at(i);
2679 
2680  if (g != item)
2681  {
2682  if (!seen.contains(g))
2683  {
2684  seen.insert(g);
2685 
2686  if (!exact || item->collidesWith(g))
2687  {
2688  result.append(g);
2689  }
2690  }
2691  }
2692  }
2693  }
2694  }
2695 
2696  return result;
2697 }
2698 
2699 /*
2700  \internal
2701  Adds the item to all the chunks it covers.
2702 */
2703 void QtCanvasItem::addToChunks()
2704 {
2705  if (isVisible() && canvas())
2706  {
2707  QPolygon pa = chunks();
2708 
2709  for (int i = 0; i < (int)pa.count(); i++)
2710  {
2711  canvas()->addItemToChunk(this, pa[i].x(), pa[i].y());
2712  }
2713 
2714  val = (uint)true;
2715  }
2716 }
2717 
2718 /*
2719  \internal
2720  Removes the item from all the chunks it covers.
2721 */
2722 void QtCanvasItem::removeFromChunks()
2723 {
2724  if (isVisible() && canvas())
2725  {
2726  QPolygon pa = chunks();
2727 
2728  for (int i = 0; i < (int)pa.count(); i++)
2729  {
2730  canvas()->removeItemFromChunk(this, pa[i].x(), pa[i].y());
2731  }
2732  }
2733 }
2734 
2735 /*
2736  \internal
2737  Sets all the chunks covered by the item to be refreshed with QtCanvas::update()
2738  is next called.
2739 */
2740 void QtCanvasItem::changeChunks()
2741 {
2742  if (isVisible() && canvas())
2743  {
2744  if (!val)
2745  {
2746  addToChunks();
2747  }
2748 
2749  QPolygon pa = chunks();
2750 
2751  for (int i = 0; i < (int)pa.count(); i++)
2752  {
2753  canvas()->setChangedChunk(pa[i].x(), pa[i].y());
2754  }
2755  }
2756 }
2757 
2758 /*
2759  \fn QRect QtCanvasItem::boundingRect() const
2760 
2761  Returns the bounding rectangle in pixels that the canvas item covers.
2762 
2763  \sa boundingRectAdvanced()
2764 */
2765 
2766 /*
2767  Returns the bounding rectangle of pixels that the canvas item \e
2768  will cover after advance(1) is called.
2769 
2770  \sa boundingRect()
2771 */
2773 {
2774  int dx = int(x() + xVelocity()) - int(x());
2775  int dy = int(y() + yVelocity()) - int(y());
2776  QRect r = boundingRect();
2777  r.translate(dx, dy);
2778  return r;
2779 }
2780 
2781 /*
2782  \class QtCanvasPixmap qtcanvas.h
2783  \brief The QtCanvasPixmap class provides pixmaps for QtCanvasSprites.
2784 
2785  If you want to show a single pixmap on a QtCanvas use a
2786  QtCanvasSprite with just one pixmap.
2787 
2788  When pixmaps are inserted into a QtCanvasPixmapArray they are held
2789  as QtCanvasPixmaps. \l{QtCanvasSprite}s are used to show pixmaps on
2790  \l{QtCanvas}es and hold their pixmaps in a QtCanvasPixmapArray. If
2791  you retrieve a frame (pixmap) from a QtCanvasSprite it will be
2792  returned as a QtCanvasPixmap.
2793 
2794  The pixmap is a QPixmap and can only be set in the constructor.
2795  There are three different constructors, one taking a QPixmap, one
2796  a QImage and one a file name that refers to a file in any
2797  supported file format (see QImageReader).
2798 
2799  QtCanvasPixmap can have a hotspot which is defined in terms of an (x,
2800  y) offset. When you create a QtCanvasPixmap from a PNG file or from
2801  a QImage that has a QImage::offset(), the offset() is initialized
2802  appropriately, otherwise the constructor leaves it at (0, 0). You
2803  can set it later using setOffset(). When the QtCanvasPixmap is used
2804  in a QtCanvasSprite, the offset position is the point at
2805  QtCanvasItem::x() and QtCanvasItem::y(), not the top-left corner of
2806  the pixmap.
2807 
2808  Note that for QtCanvasPixmap objects created by a QtCanvasSprite, the
2809  position of each QtCanvasPixmap object is set so that the hotspot
2810  stays in the same position.
2811 
2812  \sa QtCanvasPixmapArray QtCanvasItem QtCanvasSprite
2813 */
2814 
2815 
2816 /*
2817  Constructs a QtCanvasPixmap that uses the image stored in \a
2818  datafilename.
2819 */
2820 QtCanvasPixmap::QtCanvasPixmap(const QString& datafilename)
2821 {
2822  QImage image(datafilename);
2823  init(image);
2824 }
2825 
2826 
2827 /*
2828  Constructs a QtCanvasPixmap from the image \a image.
2829 */
2830 QtCanvasPixmap::QtCanvasPixmap(const QImage& image)
2831 {
2832  init(image);
2833 }
2834 /*
2835  Constructs a QtCanvasPixmap from the pixmap \a pm using the offset
2836  \a offset.
2837 */
2838 QtCanvasPixmap::QtCanvasPixmap(const QPixmap& pm, const QPoint& offset)
2839 {
2840  init(pm, offset.x(), offset.y());
2841 }
2842 
2843 void QtCanvasPixmap::init(const QImage& image)
2844 {
2845  this->QPixmap::operator = (QPixmap::fromImage(image));
2846  hotx = image.offset().x();
2847  hoty = image.offset().y();
2848 #ifndef QT_NO_IMAGE_DITHER_TO_1
2849 
2850  if (image.hasAlphaChannel())
2851  {
2852  QImage i = image.createAlphaMask();
2853  collision_mask = new QImage(i);
2854  }
2855  else
2856 #endif
2857  collision_mask = 0;
2858 }
2859 
2860 void QtCanvasPixmap::init(const QPixmap& pixmap, int hx, int hy)
2861 {
2862  (QPixmap&)*this = pixmap;
2863  hotx = hx;
2864  hoty = hy;
2865 
2866  if (pixmap.hasAlphaChannel())
2867  {
2868  QImage i = mask().toImage();
2869  collision_mask = new QImage(i);
2870  }
2871  else
2872  {
2873  collision_mask = 0;
2874  }
2875 }
2876 
2877 /*
2878  Destroys the pixmap.
2879 */
2881 {
2882  delete collision_mask;
2883 }
2884 
2885 /*
2886  \fn int QtCanvasPixmap::offsetX() const
2887 
2888  Returns the x-offset of the pixmap's hotspot.
2889 
2890  \sa setOffset()
2891 */
2892 
2893 /*
2894  \fn int QtCanvasPixmap::offsetY() const
2895 
2896  Returns the y-offset of the pixmap's hotspot.
2897 
2898  \sa setOffset()
2899 */
2900 
2901 /*
2902  \fn void QtCanvasPixmap::setOffset(int x, int y)
2903 
2904  Sets the offset of the pixmap's hotspot to (\a x, \a y).
2905 
2906  \warning Do not call this function if any QtCanvasSprites are
2907  currently showing this pixmap.
2908 */
2909 
2910 /*
2911  \class QtCanvasPixmapArray qtcanvas.h
2912  \brief The QtCanvasPixmapArray class provides an array of QtCanvasPixmaps.
2913 
2914  This class is used by QtCanvasSprite to hold an array of pixmaps.
2915  It is used to implement animated sprites, i.e. images that change
2916  over time, with each pixmap in the array holding one frame.
2917 
2918  Depending on the constructor you use you can load multiple pixmaps
2919  into the array either from a directory (specifying a wildcard
2920  pattern for the files), or from a list of QPixmaps. You can also
2921  read in a set of pixmaps after construction using readPixmaps().
2922 
2923  Individual pixmaps can be set with setImage() and retrieved with
2924  image(). The number of pixmaps in the array is returned by
2925  count().
2926 
2927  QtCanvasSprite uses an image's mask for collision detection. You
2928  can change this by reading in a separate set of image masks using
2929  readCollisionMasks().
2930 
2931 */
2932 
2933 /*
2934  Constructs an invalid array (i.e. isValid() will return false).
2935  You must call readPixmaps() before being able to use this
2936  QtCanvasPixmapArray.
2937 */
2939  : framecount(0), img(0)
2940 {
2941 }
2942 
2943 /*
2944  Constructs a QtCanvasPixmapArray from files.
2945 
2946  The \a fc parameter sets the number of frames to be loaded for
2947  this image.
2948 
2949  If \a fc is not 0, \a datafilenamepattern should contain "%1",
2950  e.g. "foo%1.png". The actual filenames are formed by replacing the
2951  %1 with four-digit integers from 0 to (fc - 1), e.g. foo0000.png,
2952  foo0001.png, foo0002.png, etc.
2953 
2954  If \a fc is 0, \a datafilenamepattern is asssumed to be a
2955  filename, and the image contained in this file will be loaded as
2956  the first (and only) frame.
2957 
2958  If \a datafilenamepattern does not exist, is not readable, isn't
2959  an image, or some other error occurs, the array ends up empty and
2960  isValid() returns false.
2961 */
2962 
2963 QtCanvasPixmapArray::QtCanvasPixmapArray(const QString& datafilenamepattern,
2964  int fc)
2965  : framecount(0), img(0)
2966 {
2967  readPixmaps(datafilenamepattern, fc);
2968 }
2969 
2970 /*
2971  \obsolete
2972  Use QtCanvasPixmapArray::QtCanvasPixmapArray(QtValueList<QPixmap>, QPolygon)
2973  instead.
2974 
2975  Constructs a QtCanvasPixmapArray from the list of QPixmaps \a
2976  list. The \a hotspots list has to be of the same size as \a list.
2977 */
2978 QtCanvasPixmapArray::QtCanvasPixmapArray(const QList<QPixmap>& list, const QPolygon& hotspots)
2979  : framecount(list.count()),
2980  img(new QtCanvasPixmap * [list.count()])
2981 {
2982  if (list.count() != hotspots.count())
2983  {
2984  qWarning("QtCanvasPixmapArray: lists have different lengths");
2985  reset();
2986  img = 0;
2987  }
2988  else
2989  {
2990  for (int i = 0; i < framecount; i++)
2991  {
2992  img[i] = new QtCanvasPixmap(list.at(i), hotspots.at(i));
2993  }
2994  }
2995 }
2996 
2997 
2998 /*
2999  Destroys the pixmap array and all the pixmaps it contains.
3000 */
3002 {
3003  reset();
3004 }
3005 
3006 void QtCanvasPixmapArray::reset()
3007 {
3008  for (int i = 0; i < framecount; i++)
3009  {
3010  delete img[i];
3011  }
3012 
3013  delete [] img;
3014  img = 0;
3015  framecount = 0;
3016 }
3017 
3018 /*
3019  Reads one or more pixmaps into the pixmap array.
3020 
3021  If \a fc is not 0, \a filenamepattern should contain "%1", e.g.
3022  "foo%1.png". The actual filenames are formed by replacing the %1
3023  with four-digit integers from 0 to (fc - 1), e.g. foo0000.png,
3024  foo0001.png, foo0002.png, etc.
3025 
3026  If \a fc is 0, \a filenamepattern is asssumed to be a filename,
3027  and the image contained in this file will be loaded as the first
3028  (and only) frame.
3029 
3030  If \a filenamepattern does not exist, is not readable, isn't an
3031  image, or some other error occurs, this function will return
3032  false, and isValid() will return false; otherwise this function
3033  will return true.
3034 
3035  \sa isValid()
3036 */
3037 bool QtCanvasPixmapArray::readPixmaps(const QString& filenamepattern,
3038  int fc)
3039 {
3040  return readPixmaps(filenamepattern, fc, false);
3041 }
3042 
3043 /*
3044  Reads new collision masks for the array.
3045 
3046  By default, QtCanvasSprite uses the image mask of a sprite to
3047  detect collisions. Use this function to set your own collision
3048  image masks.
3049 
3050  If count() is 1 \a filename must specify a real filename to read
3051  the mask from. If count() is greater than 1, the \a filename must
3052  contain a "%1" that will get replaced by the number of the mask to
3053  be loaded, just like QtCanvasPixmapArray::readPixmaps().
3054 
3055  All collision masks must be 1-bit images or this function call
3056  will fail.
3057 
3058  If the file isn't readable, contains the wrong number of images,
3059  or there is some other error, this function will return false, and
3060  the array will be flagged as invalid; otherwise this function
3061  returns true.
3062 
3063  \sa isValid()
3064 */
3066 {
3067  return readPixmaps(filename, framecount, true);
3068 }
3069 
3070 
3071 bool QtCanvasPixmapArray::readPixmaps(const QString& datafilenamepattern,
3072  int fc, bool maskonly)
3073 {
3074  if (!maskonly)
3075  {
3076  reset();
3077  framecount = fc;
3078 
3079  if (!framecount)
3080  {
3081  framecount = 1;
3082  }
3083 
3084  img = new QtCanvasPixmap*[framecount];
3085  }
3086 
3087  if (!img)
3088  {
3089  return false;
3090  }
3091 
3092  bool ok = true;
3093  bool arg = fc > 1;
3094 
3095  if (!arg)
3096  {
3097  framecount = 1;
3098  }
3099 
3100  for (int i = 0; i < framecount; i++)
3101  {
3102  QString r;
3103  r.sprintf("%04d", i);
3104 
3105  if (maskonly)
3106  {
3107  if (!img[i]->collision_mask)
3108  {
3109  img[i]->collision_mask = new QImage();
3110  }
3111 
3112  img[i]->collision_mask->load(
3113  arg ? datafilenamepattern.arg(r) : datafilenamepattern);
3114  ok = ok
3115  && !img[i]->collision_mask->isNull()
3116  && img[i]->collision_mask->depth() == 1;
3117  }
3118  else
3119  {
3120  img[i] = new QtCanvasPixmap(
3121  arg ? datafilenamepattern.arg(r) : datafilenamepattern);
3122  ok = ok && !img[i]->isNull();
3123  }
3124  }
3125 
3126  if (!ok)
3127  {
3128  reset();
3129  }
3130 
3131  return ok;
3132 }
3133 
3134 /*
3135  \obsolete
3136 
3137  Use isValid() instead.
3138 
3139  This returns false if the array is valid, and true if it is not.
3140 */
3142 {
3143  return img == 0;
3144 }
3145 
3146 /*
3147  Returns true if the pixmap array is valid; otherwise returns
3148  false.
3149 */
3150 bool QtCanvasPixmapArray::isValid() const
3151 {
3152  return (img != 0);
3153 }
3154 
3155 /*
3156  \fn QtCanvasPixmap* QtCanvasPixmapArray::image(int i) const
3157 
3158  Returns pixmap \a i in the array, if \a i is non-negative and less
3159  than than count(), and returns an unspecified value otherwise.
3160 */
3161 
3162 // ### wouldn't it be better to put empty QtCanvasPixmaps in there instead of
3163 // initializing the additional elements in the array to 0? Lars
3164 /*
3165  Replaces the pixmap at index \a i with pixmap \a p.
3166 
3167  The array takes ownership of \a p and will delete \a p when the
3168  array itself is deleted.
3169 
3170  If \a i is beyond the end of the array the array is extended to at
3171  least i+1 elements, with elements count() to i-1 being initialized
3172  to 0.
3173 */
3175 {
3176  if (i >= framecount)
3177  {
3178  QtCanvasPixmap** newimg = new QtCanvasPixmap*[i + 1];
3179  memcpy(newimg, img, sizeof(QtCanvasPixmap*)*framecount);
3180  memset(newimg + framecount, 0, sizeof(QtCanvasPixmap*) * (i + 1 - framecount));
3181  framecount = i + 1;
3182  delete [] img;
3183  img = newimg;
3184  }
3185 
3186  delete img[i];
3187  img[i] = p;
3188 }
3189 
3190 /*
3191  \fn uint QtCanvasPixmapArray::count() const
3192 
3193  Returns the number of pixmaps in the array.
3194 */
3195 
3196 /*
3197  Returns the x-coordinate of the current left edge of the sprite.
3198  (This may change as the sprite animates since different frames may
3199  have different left edges.)
3200 
3201  \sa rightEdge() bottomEdge() topEdge()
3202 */
3203 int QtCanvasSprite::leftEdge() const
3204 {
3205  return int(x()) - image()->hotx;
3206 }
3207 
3208 /*
3209  \overload
3210 
3211  Returns what the x-coordinate of the left edge of the sprite would
3212  be if the sprite (actually its hotspot) were moved to x-position
3213  \a nx.
3214 
3215  \sa rightEdge() bottomEdge() topEdge()
3216 */
3217 int QtCanvasSprite::leftEdge(int nx) const
3218 {
3219  return nx - image()->hotx;
3220 }
3221 
3222 /*
3223  Returns the y-coordinate of the top edge of the sprite. (This may
3224  change as the sprite animates since different frames may have
3225  different top edges.)
3226 
3227  \sa leftEdge() rightEdge() bottomEdge()
3228 */
3229 int QtCanvasSprite::topEdge() const
3230 {
3231  return int(y()) - image()->hoty;
3232 }
3233 
3234 /*
3235  \overload
3236 
3237  Returns what the y-coordinate of the top edge of the sprite would
3238  be if the sprite (actually its hotspot) were moved to y-position
3239  \a ny.
3240 
3241  \sa leftEdge() rightEdge() bottomEdge()
3242 */
3243 int QtCanvasSprite::topEdge(int ny) const
3244 {
3245  return ny - image()->hoty;
3246 }
3247 
3248 /*
3249  Returns the x-coordinate of the current right edge of the sprite.
3250  (This may change as the sprite animates since different frames may
3251  have different right edges.)
3252 
3253  \sa leftEdge() bottomEdge() topEdge()
3254 */
3255 int QtCanvasSprite::rightEdge() const
3256 {
3257  return leftEdge() + image()->width() - 1;
3258 }
3259 
3260 /*
3261  \overload
3262 
3263  Returns what the x-coordinate of the right edge of the sprite
3264  would be if the sprite (actually its hotspot) were moved to
3265  x-position \a nx.
3266 
3267  \sa leftEdge() bottomEdge() topEdge()
3268 */
3269 int QtCanvasSprite::rightEdge(int nx) const
3270 {
3271  return leftEdge(nx) + image()->width() - 1;
3272 }
3273 
3274 /*
3275  Returns the y-coordinate of the current bottom edge of the sprite.
3276  (This may change as the sprite animates since different frames may
3277  have different bottom edges.)
3278 
3279  \sa leftEdge() rightEdge() topEdge()
3280 */
3281 int QtCanvasSprite::bottomEdge() const
3282 {
3283  return topEdge() + image()->height() - 1;
3284 }
3285 
3286 /*
3287  \overload
3288 
3289  Returns what the y-coordinate of the top edge of the sprite would
3290  be if the sprite (actually its hotspot) were moved to y-position
3291  \a ny.
3292 
3293  \sa leftEdge() rightEdge() topEdge()
3294 */
3295 int QtCanvasSprite::bottomEdge(int ny) const
3296 {
3297  return topEdge(ny) + image()->height() - 1;
3298 }
3299 
3300 /*
3301  \fn QtCanvasPixmap* QtCanvasSprite::image() const
3302 
3303  Returns the current frame's image.
3304 
3305  \sa frame(), setFrame()
3306 */
3307 
3308 /*
3309  \fn QtCanvasPixmap* QtCanvasSprite::image(int f) const
3310  \overload
3311 
3312  Returns the image for frame \a f. Does not do any bounds checking on \a f.
3313 */
3314 
3315 /*
3316  Returns the image the sprite \e will have after advance(1) is
3317  called. By default this is the same as image().
3318 */
3320 {
3321  return image();
3322 }
3323 
3324 /*
3325  Returns the bounding rectangle for the image in the sprite's
3326  current frame. This assumes that the images are tightly cropped
3327  (i.e. do not have transparent pixels all along a side).
3328 */
3329 QRect QtCanvasSprite::boundingRect() const
3330 {
3331  return QRect(leftEdge(), topEdge(), width(), height());
3332 }
3333 
3334 
3335 /*
3336  \internal
3337  Returns the chunks covered by the item.
3338 */
3339 QPolygon QtCanvasItem::chunks() const
3340 {
3341  QPolygon r;
3342  int n = 0;
3343  QRect br = boundingRect();
3344 
3345  if (isVisible() && canvas())
3346  {
3347  int chunksize = canvas()->chunkSize();
3348  br &= QRect(0, 0, canvas()->width(), canvas()->height());
3349 
3350  if (br.isValid())
3351  {
3352  r.resize((br.width() / chunksize + 2) * (br.height() / chunksize + 2));
3353 
3354  for (int j = br.top() / chunksize; j <= br.bottom() / chunksize; j++)
3355  {
3356  for (int i = br.left() / chunksize; i <= br.right() / chunksize; i++)
3357  {
3358  r[n++] = QPoint(i, j);
3359  }
3360  }
3361  }
3362  }
3363 
3364  r.resize(n);
3365  return r;
3366 }
3367 
3368 
3369 /*
3370  \internal
3371  Add the sprite to the chunks in its QtCanvas which it overlaps.
3372 */
3373 void QtCanvasSprite::addToChunks()
3374 {
3375  if (isVisible() && canvas())
3376  {
3377  int chunksize = canvas()->chunkSize();
3378 
3379  for (int j = topEdge() / chunksize; j <= bottomEdge() / chunksize; j++)
3380  {
3381  for (int i = leftEdge() / chunksize; i <= rightEdge() / chunksize; i++)
3382  {
3383  canvas()->addItemToChunk(this, i, j);
3384  }
3385  }
3386  }
3387 }
3388 
3389 /*
3390  \internal
3391  Remove the sprite from the chunks in its QtCanvas which it overlaps.
3392 
3393  \sa addToChunks()
3394 */
3395 void QtCanvasSprite::removeFromChunks()
3396 {
3397  if (isVisible() && canvas())
3398  {
3399  int chunksize = canvas()->chunkSize();
3400 
3401  for (int j = topEdge() / chunksize; j <= bottomEdge() / chunksize; j++)
3402  {
3403  for (int i = leftEdge() / chunksize; i <= rightEdge() / chunksize; i++)
3404  {
3405  canvas()->removeItemFromChunk(this, i, j);
3406  }
3407  }
3408  }
3409 }
3410 
3411 /*
3412  The width of the sprite for the current frame's image.
3413 
3414  \sa frame()
3415 */
3416 //### mark: Why don't we have width(int) and height(int) to be
3417 //consistent with leftEdge() and leftEdge(int)?
3418 int QtCanvasSprite::width() const
3419 {
3420  return image()->width();
3421 }
3422 
3423 /*
3424  The height of the sprite for the current frame's image.
3425 
3426  \sa frame()
3427 */
3428 int QtCanvasSprite::height() const
3429 {
3430  return image()->height();
3431 }
3432 
3433 
3434 /*
3435  Draws the current frame's image at the sprite's current position
3436  on painter \a painter.
3437 */
3438 void QtCanvasSprite::draw(QPainter& painter)
3439 {
3440  painter.drawPixmap(leftEdge(), topEdge(), *image());
3441 }
3442 
3443 /*
3444  \class QtCanvasView qtcanvas.h
3445  \brief The QtCanvasView class provides an on-screen view of a QtCanvas.
3446 
3447  A QtCanvasView is widget which provides a view of a QtCanvas.
3448 
3449  If you want users to be able to interact with a canvas view,
3450  subclass QtCanvasView. You might then reimplement
3451  QtScrollView::contentsMousePressEvent(). For example:
3452 
3453  \code
3454  void MyCanvasView::contentsMousePressEvent(QMouseEvent* e)
3455  {
3456  QtCanvasItemList l = canvas()->collisions(e->pos());
3457  for (QtCanvasItemList::Iterator it = l.begin(); it!= l.end(); ++it) {
3458  if ((*it)->rtti() == QtCanvasRectangle::RTTI)
3459  qDebug("A QtCanvasRectangle lies somewhere at this point");
3460  }
3461  }
3462  \endcode
3463 
3464  The canvas view shows canvas canvas(); this can be changed using
3465  setCanvas().
3466 
3467  A transformation matrix can be used to transform the view of the
3468  canvas in various ways, for example, zooming in or out or rotating.
3469  For example:
3470 
3471  \code
3472  QMatrix wm;
3473  wm.scale(2, 2); // Zooms in by 2 times
3474  wm.rotate(90); // Rotates 90 degrees counter clockwise
3475  // around the origin.
3476  wm.translate(0, -canvas->height());
3477  // moves the canvas down so what was visible
3478  // before is still visible.
3479  myCanvasView->setWorldMatrix(wm);
3480  \endcode
3481 
3482  Use setWorldMatrix() to set the canvas view's world matrix: you must
3483  ensure that the world matrix is invertible. The current world matrix
3484  is retrievable with worldMatrix(), and its inversion is retrievable
3485  with inverseWorldMatrix().
3486 
3487  Example:
3488 
3489  The following code finds the part of the canvas that is visible in
3490  this view, i.e. the bounding rectangle of the view in canvas coordinates.
3491 
3492  \code
3493  QRect rc = QRect(myCanvasView->contentsX(), myCanvasView->contentsY(),
3494  myCanvasView->visibleWidth(), myCanvasView->visibleHeight());
3495  QRect canvasRect = myCanvasView->inverseWorldMatrix().mapRect(rc);
3496  \endcode
3497 
3498  \sa QMatrix QPainter::setWorldMatrix()
3499 
3500 */
3501 
3502 class QtCanvasWidget : public QWidget
3503 {
3504 public:
3505  QtCanvasWidget(QtCanvasView* view) : QWidget(view)
3506  {
3507  m_view = view;
3508  }
3509 protected:
3510  void paintEvent(QPaintEvent* e);
3511  void mousePressEvent(QMouseEvent* e)
3512  {
3514  }
3515  void mouseMoveEvent(QMouseEvent* e)
3516  {
3518  }
3519  void mouseReleaseEvent(QMouseEvent* e)
3520  {
3522  }
3523  void mouseDoubleClickEvent(QMouseEvent* e)
3524  {
3526  }
3527  void dragEnterEvent(QDragEnterEvent* e)
3528  {
3530  }
3531  void dragMoveEvent(QDragMoveEvent* e)
3532  {
3534  }
3535  void dragLeaveEvent(QDragLeaveEvent* e)
3536  {
3538  }
3539  void dropEvent(QDropEvent* e)
3540  {
3542  }
3543  void wheelEvent(QWheelEvent* e)
3544  {
3546  }
3547  void contextMenuEvent(QContextMenuEvent* e)
3548  {
3550  }
3551 
3553 };
3554 
3555 void QtCanvasWidget::paintEvent(QPaintEvent* e)
3556 {
3557  QPainter p(this);
3558 
3559  if (m_view->d->highQuality)
3560  {
3561  p.setRenderHint(QPainter::Antialiasing);
3562  p.setRenderHint(QPainter::SmoothPixmapTransform);
3563  }
3564 
3565  m_view->drawContents(&p, e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
3566 }
3567 
3568 /*
3569  Constructs a QtCanvasView with parent \a parent. The canvas view
3570  is not associated with a canvas, so you must to call setCanvas()
3571  to view a canvas.
3572 */
3573 QtCanvasView::QtCanvasView(QWidget* parent)
3574  : QScrollArea(parent)
3575 {
3576  d = new QtCanvasViewData;
3577  setWidget(new QtCanvasWidget(this));
3578  d->highQuality = false;
3579  viewing = 0;
3580  setCanvas(0);
3581 }
3582 
3583 /*
3584  \overload
3585 
3586  Constructs a QtCanvasView which views canvas \a canvas, with parent
3587  \a parent.
3588 */
3589 QtCanvasView::QtCanvasView(QtCanvas* canvas, QWidget* parent)
3590  : QScrollArea(parent)
3591 {
3592  d = new QtCanvasViewData;
3593  d->highQuality = false;
3594  setWidget(new QtCanvasWidget(this));
3595  viewing = 0;
3596  setCanvas(canvas);
3597 }
3598 
3599 /*
3600  Destroys the canvas view. The associated canvas is \e not deleted.
3601 */
3603 {
3604  delete d;
3605  d = 0;
3606  setCanvas(0);
3607 }
3608 
3609 /*
3610  \property QtCanvasView::highQualityRendering
3611  \brief whether high quality rendering is turned on
3612 
3613  If high quality rendering is turned on, the canvas view will paint itself
3614  using the QPainter::Antialiasing and QPainter::SmoothPixmapTransform
3615  rendering flags.
3616 
3617  Enabling these flag will usually improve the visual appearance on the screen
3618  at the cost of rendering speed.
3619 */
3621 {
3622  return d->highQuality;
3623 }
3624 
3625 void QtCanvasView::setHighQualityRendering(bool enable)
3626 {
3627  d->highQuality = enable;
3628  widget()->update();
3629 }
3630 
3631 
3632 void QtCanvasView::contentsMousePressEvent(QMouseEvent* e)
3633 {
3634  e->ignore();
3635 }
3636 
3637 void QtCanvasView::contentsMouseReleaseEvent(QMouseEvent* e)
3638 {
3639  e->ignore();
3640 }
3641 
3643 {
3644  e->ignore();
3645 }
3646 
3647 void QtCanvasView::contentsMouseMoveEvent(QMouseEvent* e)
3648 {
3649  e->ignore();
3650 }
3651 
3652 void QtCanvasView::contentsDragEnterEvent(QDragEnterEvent*)
3653 {
3654 }
3655 
3656 void QtCanvasView::contentsDragMoveEvent(QDragMoveEvent*)
3657 {
3658 }
3659 
3660 void QtCanvasView::contentsDragLeaveEvent(QDragLeaveEvent*)
3661 {
3662 }
3663 
3664 void QtCanvasView::contentsDropEvent(QDropEvent*)
3665 {
3666 }
3667 
3668 void QtCanvasView::contentsWheelEvent(QWheelEvent* e)
3669 {
3670  e->ignore();
3671 }
3672 
3673 void QtCanvasView::contentsContextMenuEvent(QContextMenuEvent* e)
3674 {
3675  e->ignore();
3676 }
3677 
3678 /*
3679  \fn QtCanvas* QtCanvasView::canvas() const
3680 
3681  Returns a pointer to the canvas which the QtCanvasView is currently
3682  showing.
3683 */
3684 
3685 
3686 /*
3687  Sets the canvas that the QtCanvasView is showing to the canvas \a
3688  canvas.
3689 */
3690 void QtCanvasView::setCanvas(QtCanvas* canvas)
3691 {
3692  if (viewing == canvas)
3693  {
3694  return;
3695  }
3696 
3697  if (viewing)
3698  {
3699  disconnect(viewing);
3700  viewing->removeView(this);
3701  }
3702 
3703  viewing = canvas;
3704 
3705  if (viewing)
3706  {
3707  connect(viewing, SIGNAL(resized()), this, SLOT(updateContentsSize()));
3708  viewing->addView(this);
3709  }
3710 
3711  if (d) // called by d'tor
3712  {
3713  updateContentsSize();
3714  }
3715 
3716  update();
3717 }
3718 
3719 /*
3720  Returns a reference to the canvas view's current transformation matrix.
3721 
3722  \sa setWorldMatrix() inverseWorldMatrix()
3723 */
3724 const QMatrix& QtCanvasView::worldMatrix() const
3725 {
3726  return d->xform;
3727 }
3728 
3729 /*
3730  Returns a reference to the inverse of the canvas view's current
3731  transformation matrix.
3732 
3733  \sa setWorldMatrix() worldMatrix()
3734 */
3735 const QMatrix& QtCanvasView::inverseWorldMatrix() const
3736 {
3737  return d->ixform;
3738 }
3739 
3740 /*
3741  Sets the transformation matrix of the QtCanvasView to \a wm. The
3742  matrix must be invertible (i.e. if you create a world matrix that
3743  zooms out by 2 times, then the inverse of this matrix is one that
3744  will zoom in by 2 times).
3745 
3746  When you use this, you should note that the performance of the
3747  QtCanvasView will decrease considerably.
3748 
3749  Returns false if \a wm is not invertable; otherwise returns true.
3750 
3751  \sa worldMatrix() inverseWorldMatrix() QMatrix::isInvertible()
3752 */
3753 bool QtCanvasView::setWorldMatrix(const QMatrix& wm)
3754 {
3755  bool ok = wm.isInvertible();
3756 
3757  if (ok)
3758  {
3759  d->xform = wm;
3760  d->ixform = wm.inverted();
3761  updateContentsSize();
3762  widget()->update();
3763  }
3764 
3765  return ok;
3766 }
3767 
3768 void QtCanvasView::updateContentsSize()
3769 {
3770  if (viewing)
3771  {
3772  QRect br;
3773  br = d->xform.mapRect(QRect(0, 0, viewing->width(), viewing->height()));
3774 
3775  widget()->resize(br.size());
3776  }
3777  else
3778  {
3779  widget()->resize(size());
3780  }
3781 }
3782 
3783 /*
3784  Repaints part of the QtCanvas that the canvas view is showing
3785  starting at \a cx by \a cy, with a width of \a cw and a height of \a
3786  ch using the painter \a p.
3787 */
3788 void QtCanvasView::drawContents(QPainter* p, int cx, int cy, int cw, int ch)
3789 {
3790  if (!viewing)
3791  {
3792  return;
3793  }
3794 
3795  QPainterPath clipPath;
3796  clipPath.addRect(viewing->rect());
3797  p->setClipPath(d->xform.map(clipPath), Qt::IntersectClip);
3798  viewing->drawViewArea(this, p, QRect(cx, cy, cw, ch), false);
3799 }
3800 
3801 /*
3802  Suggests a size sufficient to view the entire canvas.
3803 */
3804 QSize QtCanvasView::sizeHint() const
3805 {
3806  if (!canvas())
3807  {
3808  return QScrollArea::sizeHint();
3809  }
3810 
3811  // should maybe take transformations into account
3812  return (canvas()->size() + 2 * QSize(frameWidth(), frameWidth()))
3813  .boundedTo(3 * QApplication::desktop()->size() / 4);
3814 }
3815 
3816 /*
3817  \class QtCanvasPolygonalItem qtcanvas.h
3818  \brief The QtCanvasPolygonalItem class provides a polygonal canvas item
3819  on a QtCanvas.
3820 
3821  The mostly rectangular classes, such as QtCanvasSprite and
3822  QtCanvasText, use the object's bounding rectangle for movement,
3823  repainting and collision calculations. For most other items, the
3824  bounding rectangle can be far too large -- a diagonal line being
3825  the worst case, and there are many other cases which are also bad.
3826  QtCanvasPolygonalItem provides polygon-based bounding rectangle
3827  handling, etc., which is much faster for non-rectangular items.
3828 
3829  Derived classes should try to define as small an area as possible
3830  to maximize efficiency, but the polygon must \e definitely be
3831  contained completely within the polygonal area. Calculating the
3832  exact requirements is usually difficult, but if you allow a small
3833  overestimate it can be easy and quick, while still getting almost
3834  all of QtCanvasPolygonalItem's speed.
3835 
3836  Note that all subclasses \e must call hide() in their destructor
3837  since hide() needs to be able to access areaPoints().
3838 
3839  Normally, QtCanvasPolygonalItem uses the odd-even algorithm for
3840  determining whether an object intersects this object. You can
3841  change this to the winding algorithm using setWinding().
3842 
3843  The bounding rectangle is available using boundingRect(). The
3844  points bounding the polygonal item are retrieved with
3845  areaPoints(). Use areaPointsAdvanced() to retrieve the bounding
3846  points the polygonal item \e will have after
3847  QtCanvasItem::advance(1) has been called.
3848 
3849  If the shape of the polygonal item is about to change while the
3850  item is visible, call invalidate() before updating with a
3851  different result from \l areaPoints().
3852 
3853  By default, QtCanvasPolygonalItem objects have a black pen and no
3854  brush (the default QPen and QBrush constructors). You can change
3855  this with setPen() and setBrush(), but note that some
3856  QtCanvasPolygonalItem subclasses only use the brush, ignoring the
3857  pen setting.
3858 
3859  The polygonal item can be drawn on a painter with draw().
3860  Subclasses must reimplement drawShape() to draw themselves.
3861 
3862  Like any other canvas item polygonal items can be moved with
3863  QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting coordinates
3864  with QtCanvasItem::setX(), QtCanvasItem::setY() and QtCanvasItem::setZ().
3865 
3866 */
3867 
3868 
3869 /*
3870  Since most polygonal items don't have a pen, the default is
3871  NoPen and a black brush.
3872 */
3873 static const QPen& defaultPolygonPen()
3874 {
3875  static QPen* dp = 0;
3876 
3877  if (!dp)
3878  {
3879  dp = new QPen;
3880  }
3881 
3882  return *dp;
3883 }
3884 
3885 static const QBrush& defaultPolygonBrush()
3886 {
3887  static QBrush* db = 0;
3888 
3889  if (!db)
3890  {
3891  db = new QBrush;
3892  }
3893 
3894  return *db;
3895 }
3896 
3897 /*
3898  Constructs a QtCanvasPolygonalItem on the canvas \a canvas.
3899 */
3901  QtCanvasItem(canvas),
3902  br(defaultPolygonBrush()),
3903  pn(defaultPolygonPen())
3904 {
3905  wind = 0;
3906 }
3907 
3908 /*
3909  Note that all subclasses \e must call hide() in their destructor
3910  since hide() needs to be able to access areaPoints().
3911 */
3913 {
3914 }
3915 
3916 /*
3917  Returns true if the polygonal item uses the winding algorithm to
3918  determine the "inside" of the polygon. Returns false if it uses
3919  the odd-even algorithm.
3920 
3921  The default is to use the odd-even algorithm.
3922 
3923  \sa setWinding()
3924 */
3925 bool QtCanvasPolygonalItem::winding() const
3926 {
3927  return wind;
3928 }
3929 
3930 /*
3931  If \a enable is true, the polygonal item will use the winding
3932  algorithm to determine the "inside" of the polygon; otherwise the
3933  odd-even algorithm will be used.
3934 
3935  The default is to use the odd-even algorithm.
3936 
3937  \sa winding()
3938 */
3939 void QtCanvasPolygonalItem::setWinding(bool enable)
3940 {
3941  wind = enable;
3942 }
3943 
3944 /*
3945  Invalidates all information about the area covered by the canvas
3946  item. The item will be updated automatically on the next call that
3947  changes the item's status, for example, move() or update(). Call
3948  this function if you are going to change the shape of the item (as
3949  returned by areaPoints()) while the item is visible.
3950 */
3952 {
3953  val = (uint)false;
3954  removeFromChunks();
3955 }
3956 
3957 /*
3958  \fn QtCanvasPolygonalItem::isValid() const
3959 
3960  Returns true if the polygonal item's area information has not been
3961  invalidated; otherwise returns false.
3962 
3963  \sa invalidate()
3964 */
3965 
3966 /*
3967  Returns the points the polygonal item \e will have after
3968  QtCanvasItem::advance(1) is called, i.e. what the points are when
3969  advanced by the current xVelocity() and yVelocity().
3970 */
3972 {
3973  int dx = int(x() + xVelocity()) - int(x());
3974  int dy = int(y() + yVelocity()) - int(y());
3975  QPolygon r = areaPoints();
3976  r.detach(); // Explicit sharing is stupid.
3977 
3978  if (dx || dy)
3979  {
3980  r.translate(dx, dy);
3981  }
3982 
3983  return r;
3984 }
3985 
3986 //#define QCANVAS_POLYGONS_DEBUG
3987 #ifdef QCANVAS_POLYGONS_DEBUG
3988 static QWidget* dbg_wid = 0;
3989 static QPainter* dbg_ptr = 0;
3990 #endif
3991 
3992 class QPolygonalProcessor
3993 {
3994 public:
3995  QPolygonalProcessor(QtCanvas* c, const QPolygon& pa) :
3996  canvas(c)
3997  {
3998  QRect pixelbounds = pa.boundingRect();
3999  int cs = canvas->chunkSize();
4000  QRect canvasbounds = pixelbounds.intersected(canvas->rect());
4001  bounds.setLeft(canvasbounds.left() / cs);
4002  bounds.setRight(canvasbounds.right() / cs);
4003  bounds.setTop(canvasbounds.top() / cs);
4004  bounds.setBottom(canvasbounds.bottom() / cs);
4005  bitmap = QImage(bounds.width(), bounds.height(), QImage::Format_MonoLSB);
4006  pnt = 0;
4007  bitmap.fill(0);
4008 #ifdef QCANVAS_POLYGONS_DEBUG
4009  dbg_start();
4010 #endif
4011  }
4012 
4013  inline void add(int x, int y)
4014  {
4015  if (pnt >= (int)result.size())
4016  {
4017  result.resize(pnt * 2 + 10);
4018  }
4019 
4020  result[pnt++] = QPoint(x + bounds.x(), y + bounds.y());
4021 #ifdef QCANVAS_POLYGONS_DEBUG
4022 
4023  if (dbg_ptr)
4024  {
4025  int cs = canvas->chunkSize();
4026  QRect r(x * cs + bounds.x()*cs, y * cs + bounds.y()*cs, cs - 1, cs - 1);
4027  dbg_ptr->setPen(Qt::blue);
4028  dbg_ptr->drawRect(r);
4029  }
4030 
4031 #endif
4032  }
4033 
4034  inline void addBits(int x1, int x2, uchar newbits, int xo, int yo)
4035  {
4036  for (int i = x1; i <= x2; i++)
4037  if (newbits & (1 << i))
4038  {
4039  add(xo + i, yo);
4040  }
4041  }
4042 
4043 #ifdef QCANVAS_POLYGONS_DEBUG
4044  void dbg_start()
4045  {
4046  if (!dbg_wid)
4047  {
4048  dbg_wid = new QWidget;
4049  dbg_wid->resize(800, 600);
4050  dbg_wid->show();
4051  dbg_ptr = new QPainter(dbg_wid);
4052  dbg_ptr->setBrush(Qt::NoBrush);
4053  }
4054 
4055  dbg_ptr->fillRect(dbg_wid->rect(), Qt::white);
4056  }
4057 #endif
4058 
4059  void doSpans(int n, QPoint* pt, int* w)
4060  {
4061  int cs = canvas->chunkSize();
4062 
4063  for (int j = 0; j < n; j++)
4064  {
4065  int y = pt[j].y() / cs - bounds.y();
4066 
4067  if (y >= bitmap.height() || y < 0)
4068  {
4069  continue;
4070  }
4071 
4072  uchar* l = bitmap.scanLine(y);
4073  int x = pt[j].x();
4074  int x1 = x / cs - bounds.x();
4075 
4076  if (x1 > bounds.width())
4077  {
4078  continue;
4079  }
4080 
4081  x1 = qMax(0, x1);
4082  int x2 = (x + w[j]) / cs - bounds.x();
4083 
4084  if (x2 < 0)
4085  {
4086  continue;
4087  }
4088 
4089  x2 = qMin(bounds.width(), x2);
4090  int x1q = x1 / 8;
4091  int x1r = x1 % 8;
4092  int x2q = x2 / 8;
4093  int x2r = x2 % 8;
4094 #ifdef QCANVAS_POLYGONS_DEBUG
4095 
4096  if (dbg_ptr)
4097  {
4098  dbg_ptr->setPen(Qt::yellow);
4099  }
4100 
4101 #endif
4102 
4103  if (x1q == x2q)
4104  {
4105  uchar newbits = (~l[x1q]) & (((2 << (x2r - x1r)) - 1) << x1r);
4106 
4107  if (newbits)
4108  {
4109 #ifdef QCANVAS_POLYGONS_DEBUG
4110 
4111  if (dbg_ptr)
4112  {
4113  dbg_ptr->setPen(Qt::darkGreen);
4114  }
4115 
4116 #endif
4117  addBits(x1r, x2r, newbits, x1q * 8, y);
4118  l[x1q] |= newbits;
4119  }
4120  }
4121  else
4122  {
4123 #ifdef QCANVAS_POLYGONS_DEBUG
4124 
4125  if (dbg_ptr)
4126  {
4127  dbg_ptr->setPen(Qt::blue);
4128  }
4129 
4130 #endif
4131  uchar newbits1 = (~l[x1q]) & (0xff << x1r);
4132 
4133  if (newbits1)
4134  {
4135 #ifdef QCANVAS_POLYGONS_DEBUG
4136 
4137  if (dbg_ptr)
4138  {
4139  dbg_ptr->setPen(Qt::green);
4140  }
4141 
4142 #endif
4143  addBits(x1r, 7, newbits1, x1q * 8, y);
4144  l[x1q] |= newbits1;
4145  }
4146 
4147  for (int i = x1q + 1; i < x2q; i++)
4148  {
4149  if (l[i] != 0xff)
4150  {
4151  addBits(0, 7, ~l[i], i * 8, y);
4152  l[i] = 0xff;
4153  }
4154  }
4155 
4156  uchar newbits2 = (~l[x2q]) & (0xff >> (7 - x2r));
4157 
4158  if (newbits2)
4159  {
4160 #ifdef QCANVAS_POLYGONS_DEBUG
4161 
4162  if (dbg_ptr)
4163  {
4164  dbg_ptr->setPen(Qt::red);
4165  }
4166 
4167 #endif
4168  addBits(0, x2r, newbits2, x2q * 8, y);
4169  l[x2q] |= newbits2;
4170  }
4171  }
4172 
4173 #ifdef QCANVAS_POLYGONS_DEBUG
4174 
4175  if (dbg_ptr)
4176  {
4177  dbg_ptr->drawLine(pt[j], pt[j] + QPoint(w[j], 0));
4178  }
4179 
4180 #endif
4181  }
4182 
4183  result.resize(pnt);
4184  }
4185 
4186  int pnt;
4187  QPolygon result;
4188  QtCanvas* canvas;
4189  QRect bounds;
4190  QImage bitmap;
4191 };
4192 
4193 
4194 QPolygon QtCanvasPolygonalItem::chunks() const
4195 {
4196  QPolygon pa = areaPoints();
4197 
4198  if (!pa.size())
4199  {
4200  pa.detach(); // Explicit sharing is stupid.
4201  return pa;
4202  }
4203 
4204  QPolygonalProcessor processor(canvas(), pa);
4205 
4206  scanPolygon(pa, wind, processor);
4207 
4208  return processor.result;
4209 }
4210 /*
4211  Simply calls QtCanvasItem::chunks().
4212 */
4213 QPolygon QtCanvasRectangle::chunks() const
4214 {
4215  // No need to do a polygon scan!
4216  return QtCanvasItem::chunks();
4217 }
4218 
4219 /*
4220  Returns the bounding rectangle of the polygonal item, based on
4221  areaPoints().
4222 */
4224 {
4225  return areaPoints().boundingRect();
4226 }
4227 
4228 /*
4229  Reimplemented from QtCanvasItem, this draws the polygonal item by
4230  setting the pen and brush for the item on the painter \a p and
4231  calling drawShape().
4232 */
4233 void QtCanvasPolygonalItem::draw(QPainter& p)
4234 {
4235  p.setPen(pn);
4236  p.setBrush(br);
4237  drawShape(p);
4238 }
4239 
4240 /*
4241  \fn void QtCanvasPolygonalItem::drawShape(QPainter & p)
4242 
4243  Subclasses must reimplement this function to draw their shape. The
4244  pen and brush of \a p are already set to pen() and brush() prior
4245  to calling this function.
4246 
4247  \sa draw()
4248 */
4249 
4250 /*
4251  \fn QPen QtCanvasPolygonalItem::pen() const
4252 
4253  Returns the QPen used to draw the outline of the item, if any.
4254 
4255  \sa setPen()
4256 */
4257 
4258 /*
4259  \fn QBrush QtCanvasPolygonalItem::brush() const
4260 
4261  Returns the QBrush used to fill the item, if filled.
4262 
4263  \sa setBrush()
4264 */
4265 
4266 /*
4267  Sets the QPen used when drawing the item to the pen \a p.
4268  Note that many QtCanvasPolygonalItems do not use the pen value.
4269 
4270  \sa setBrush(), pen(), drawShape()
4271 */
4272 void QtCanvasPolygonalItem::setPen(QPen p)
4273 {
4274  if (pn != p)
4275  {
4276  removeFromChunks();
4277  pn = p;
4278  addToChunks();
4279  }
4280 }
4281 
4282 /*
4283  Sets the QBrush used when drawing the polygonal item to the brush \a b.
4284 
4285  \sa setPen(), brush(), drawShape()
4286 */
4287 void QtCanvasPolygonalItem::setBrush(QBrush b)
4288 {
4289  if (br != b)
4290  {
4291  br = b;
4292  changeChunks();
4293  }
4294 }
4295 
4296 
4297 /*
4298  \class QtCanvasPolygon qtcanvas.h
4299  \brief The QtCanvasPolygon class provides a polygon on a QtCanvas.
4300 
4301  Paints a polygon with a QBrush. The polygon's points can be set in
4302  the constructor or set or changed later using setPoints(). Use
4303  points() to retrieve the points, or areaPoints() to retrieve the
4304  points relative to the canvas's origin.
4305 
4306  The polygon can be drawn on a painter with drawShape().
4307 
4308  Like any other canvas item polygons can be moved with
4309  QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting
4310  coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and
4311  QtCanvasItem::setZ().
4312 
4313  Note: QtCanvasPolygon does not use the pen.
4314 */
4315 
4316 /*
4317  Constructs a point-less polygon on the canvas \a canvas. You
4318  should call setPoints() before using it further.
4319 */
4321  QtCanvasPolygonalItem(canvas)
4322 {
4323 }
4324 
4325 /*
4326  Destroys the polygon.
4327 */
4329 {
4330  hide();
4331 }
4332 
4333 /*
4334  Draws the polygon using the painter \a p.
4335 
4336  Note that QtCanvasPolygon does not support an outline (the pen is
4337  always NoPen).
4338 */
4339 void QtCanvasPolygon::drawShape(QPainter& p)
4340 {
4341  // ### why can't we draw outlines? We could use drawPolyline for it. Lars
4342  // ### see other message. Warwick
4343 
4344  p.setPen(NoPen); // since QRegion(QPolygon) excludes outline :-()-:
4345  p.drawPolygon(poly);
4346 }
4347 
4348 /*
4349  Sets the points of the polygon to be \a pa. These points will have
4350  their x and y coordinates automatically translated by x(), y() as
4351  the polygon is moved.
4352 */
4353 void QtCanvasPolygon::setPoints(QPolygon pa)
4354 {
4355  removeFromChunks();
4356  poly = pa;
4357  poly.detach(); // Explicit sharing is stupid.
4358  poly.translate((int)x(), (int)y());
4359  addToChunks();
4360 }
4361 
4362 /*
4363  \reimp
4364 */
4365 void QtCanvasPolygon::moveBy(double dx, double dy)
4366 {
4367  // Note: does NOT call QtCanvasPolygonalItem::moveBy(), since that
4368  // only does half this work.
4369  //
4370  int idx = int(x() + dx) - int(x());
4371  int idy = int(y() + dy) - int(y());
4372 
4373  if (idx || idy)
4374  {
4375  removeFromChunks();
4376  poly.translate(idx, idy);
4377  }
4378 
4379  myx += dx;
4380  myy += dy;
4381 
4382  if (idx || idy)
4383  {
4384  addToChunks();
4385  }
4386 }
4387 
4388 /*
4389  \class QtCanvasSpline qtcanvas.h
4390  \brief The QtCanvasSpline class provides multi-bezier splines on a QtCanvas.
4391 
4392  A QtCanvasSpline is a sequence of 4-point bezier curves joined
4393  together to make a curved shape.
4394 
4395  You set the control points of the spline with setControlPoints().
4396 
4397  If the bezier is closed(), then the first control point will be
4398  re-used as the last control point. Therefore, a closed bezier must
4399  have a multiple of 3 control points and an open bezier must have
4400  one extra point.
4401 
4402  The beziers are not necessarily joined "smoothly". To ensure this,
4403  set control points appropriately (general reference texts about
4404  beziers will explain this in detail).
4405 
4406  Like any other canvas item splines can be moved with
4407  QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting
4408  coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and
4409  QtCanvasItem::setZ().
4410 
4411 */
4412 
4413 /*
4414  Create a spline with no control points on the canvas \a canvas.
4415 
4416  \sa setControlPoints()
4417 */
4419  QtCanvasPolygon(canvas),
4420  cl(true)
4421 {
4422 }
4423 
4424 /*
4425  Destroy the spline.
4426 */
4428 {
4429 }
4430 
4431 /*
4432  Set the spline control points to \a ctrl.
4433 
4434  If \a close is true, then the first point in \a ctrl will be
4435  re-used as the last point, and the number of control points must
4436  be a multiple of 3. If \a close is false, one additional control
4437  point is required, and the number of control points must be one of
4438  (4, 7, 10, 13, ...).
4439 
4440  If the number of control points doesn't meet the above conditions,
4441  the number of points will be truncated to the largest number of
4442  points that do meet the requirement.
4443 */
4444 void QtCanvasSpline::setControlPoints(QPolygon ctrl, bool close)
4445 {
4446  if ((int)ctrl.count() % 3 != (close ? 0 : 1))
4447  {
4448  qWarning("QtCanvasSpline::setControlPoints(): Number of points doesn't fit.");
4449  int numCurves = (ctrl.count() - (close ? 0 : 1)) / 3;
4450  ctrl.resize(numCurves * 3 + (close ? 0 : 1));
4451  }
4452 
4453  cl = close;
4454  bez = ctrl;
4455  recalcPoly();
4456 }
4457 
4458 /*
4459  Returns the current set of control points.
4460 
4461  \sa setControlPoints(), closed()
4462 */
4463 QPolygon QtCanvasSpline::controlPoints() const
4464 {
4465  return bez;
4466 }
4467 
4468 /*
4469  Returns true if the control points are a closed set; otherwise
4470  returns false.
4471 */
4472 bool QtCanvasSpline::closed() const
4473 {
4474  return cl;
4475 }
4476 
4477 void QtCanvasSpline::recalcPoly()
4478 {
4479  if (bez.count() == 0)
4480  {
4481  return;
4482  }
4483 
4484  QPainterPath path;
4485  path.moveTo(bez[0]);
4486 
4487  for (int i = 1; i < (int)bez.count() - 1; i += 3)
4488  {
4489  path.cubicTo(bez[i], bez[i + 1], cl ? bez[(i + 2) % bez.size()] : bez[i + 2]);
4490  }
4491 
4492  QPolygon p = path.toFillPolygon().toPolygon();
4494 }
4495 
4496 /*
4497  \fn QPolygon QtCanvasPolygonalItem::areaPoints() const
4498 
4499  This function must be reimplemented by subclasses. It \e must
4500  return the points bounding (i.e. outside and not touching) the
4501  shape or drawing errors will occur.
4502 */
4503 
4504 /*
4505  \fn QPolygon QtCanvasPolygon::points() const
4506 
4507  Returns the vertices of the polygon, not translated by the position.
4508 
4509  \sa setPoints(), areaPoints()
4510 */
4511 QPolygon QtCanvasPolygon::points() const
4512 {
4513  QPolygon pa = areaPoints();
4514  pa.translate(int(-x()), int(-y()));
4515  return pa;
4516 }
4517 
4518 /*
4519  Returns the vertices of the polygon translated by the polygon's
4520  current x(), y() position, i.e. relative to the canvas's origin.
4521 
4522  \sa setPoints(), points()
4523 */
4524 QPolygon QtCanvasPolygon::areaPoints() const
4525 {
4526  return poly;
4527 }
4528 
4529 /*
4530  \class QtCanvasLine qtcanvas.h
4531  \brief The QtCanvasLine class provides a line on a QtCanvas.
4532 
4533  The line inherits functionality from QtCanvasPolygonalItem, for
4534  example the setPen() function. The start and end points of the
4535  line are set with setPoints().
4536 
4537  Like any other canvas item lines can be moved with
4538  QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting
4539  coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and
4540  QtCanvasItem::setZ().
4541 */
4542 
4543 /*
4544  Constructs a line from (0, 0) to (0, 0) on \a canvas.
4545 
4546  \sa setPoints()
4547 */
4549  QtCanvasPolygonalItem(canvas)
4550 {
4551  x1 = y1 = x2 = y2 = 0;
4552 }
4553 
4554 /*
4555  Destroys the line.
4556 */
4558 {
4559  hide();
4560 }
4561 
4562 /*
4563  \reimp
4564 */
4565 void QtCanvasLine::setPen(QPen p)
4566 {
4568 }
4569 
4570 /*
4571  \fn QPoint QtCanvasLine::startPoint () const
4572 
4573  Returns the start point of the line.
4574 
4575  \sa setPoints(), endPoint()
4576 */
4577 
4578 /*
4579  \fn QPoint QtCanvasLine::endPoint () const
4580 
4581  Returns the end point of the line.
4582 
4583  \sa setPoints(), startPoint()
4584 */
4585 
4586 /*
4587  Sets the line's start point to (\a xa, \a ya) and its end point to
4588  (\a xb, \a yb).
4589 */
4590 void QtCanvasLine::setPoints(int xa, int ya, int xb, int yb)
4591 {
4592  if (x1 != xa || x2 != xb || y1 != ya || y2 != yb)
4593  {
4594  removeFromChunks();
4595  x1 = xa;
4596  y1 = ya;
4597  x2 = xb;
4598  y2 = yb;
4599  addToChunks();
4600  }
4601 }
4602 
4603 /*
4604  \reimp
4605 */
4606 void QtCanvasLine::drawShape(QPainter& p)
4607 {
4608  p.drawLine((int)(x() + x1), (int)(y() + y1), (int)(x() + x2), (int)(y() + y2));
4609 }
4610 
4611 /*
4612  \reimp
4613 
4614  Note that the area defined by the line is somewhat thicker than
4615  the line that is actually drawn.
4616 */
4617 QPolygon QtCanvasLine::areaPoints() const
4618 {
4619  QPolygon p(4);
4620  int xi = int(x());
4621  int yi = int(y());
4622  int pw = pen().width();
4623  int dx = qAbs(x1 - x2);
4624  int dy = qAbs(y1 - y2);
4625  pw = pw * 4 / 3 + 2; // approx pw*sqrt(2)
4626  int px = x1 < x2 ? -pw : pw ;
4627  int py = y1 < y2 ? -pw : pw ;
4628 
4629  if (dx && dy && (dx > dy ? (dx * 2 / dy <= 2) : (dy * 2 / dx <= 2)))
4630  {
4631  // steep
4632  if (px == py)
4633  {
4634  p[0] = QPoint(x1 + xi, y1 + yi + py);
4635  p[1] = QPoint(x2 + xi - px, y2 + yi);
4636  p[2] = QPoint(x2 + xi, y2 + yi - py);
4637  p[3] = QPoint(x1 + xi + px, y1 + yi);
4638  }
4639  else
4640  {
4641  p[0] = QPoint(x1 + xi + px, y1 + yi);
4642  p[1] = QPoint(x2 + xi, y2 + yi - py);
4643  p[2] = QPoint(x2 + xi - px, y2 + yi);
4644  p[3] = QPoint(x1 + xi, y1 + yi + py);
4645  }
4646  }
4647  else if (dx > dy)
4648  {
4649  // horizontal
4650  p[0] = QPoint(x1 + xi + px, y1 + yi + py);
4651  p[1] = QPoint(x2 + xi - px, y2 + yi + py);
4652  p[2] = QPoint(x2 + xi - px, y2 + yi - py);
4653  p[3] = QPoint(x1 + xi + px, y1 + yi - py);
4654  }
4655  else
4656  {
4657  // vertical
4658  p[0] = QPoint(x1 + xi + px, y1 + yi + py);
4659  p[1] = QPoint(x2 + xi + px, y2 + yi - py);
4660  p[2] = QPoint(x2 + xi - px, y2 + yi - py);
4661  p[3] = QPoint(x1 + xi - px, y1 + yi + py);
4662  }
4663 
4664  return p;
4665 }
4666 
4667 /*
4668  \reimp
4669 
4670 */
4671 
4672 void QtCanvasLine::moveBy(double dx, double dy)
4673 {
4675 }
4676 
4677 /*
4678  \class QtCanvasRectangle qtcanvas.h
4679  \brief The QtCanvasRectangle class provides a rectangle on a QtCanvas.
4680 
4681  This item paints a single rectangle which may have any pen() and
4682  brush(), but may not be tilted/rotated. For rotated rectangles,
4683  use QtCanvasPolygon.
4684 
4685  The rectangle's size and initial position can be set in the
4686  constructor. The size can be set or changed later using setSize().
4687  Use height() and width() to retrieve the rectangle's dimensions.
4688 
4689  The rectangle can be drawn on a painter with drawShape().
4690 
4691  Like any other canvas item rectangles can be moved with
4692  QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting
4693  coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and
4694  QtCanvasItem::setZ().
4695 
4696 */
4697 
4698 /*
4699  Constructs a rectangle at position (0,0) with both width and
4700  height set to 32 pixels on \a canvas.
4701 */
4703  QtCanvasPolygonalItem(canvas),
4704  w(32), h(32)
4705 {
4706 }
4707 
4708 /*
4709  Constructs a rectangle positioned and sized by \a r on \a canvas.
4710 */
4711 QtCanvasRectangle::QtCanvasRectangle(const QRect& r, QtCanvas* canvas) :
4712  QtCanvasPolygonalItem(canvas),
4713  w(r.width()), h(r.height())
4714 {
4715  move(r.x(), r.y());
4716 }
4717 
4718 /*
4719  Constructs a rectangle at position (\a x, \a y) and size \a width
4720  by \a height, on \a canvas.
4721 */
4722 QtCanvasRectangle::QtCanvasRectangle(int x, int y, int width, int height,
4723  QtCanvas* canvas) :
4724  QtCanvasPolygonalItem(canvas),
4725  w(width), h(height)
4726 {
4727  move(x, y);
4728 }
4729 
4730 /*
4731  Destroys the rectangle.
4732 */
4734 {
4735  hide();
4736 }
4737 
4738 
4739 /*
4740  Returns the width of the rectangle.
4741 */
4742 int QtCanvasRectangle::width() const
4743 {
4744  return w;
4745 }
4746 
4747 /*
4748  Returns the height of the rectangle.
4749 */
4750 int QtCanvasRectangle::height() const
4751 {
4752  return h;
4753 }
4754 
4755 /*
4756  Sets the \a width and \a height of the rectangle.
4757 */
4758 void QtCanvasRectangle::setSize(int width, int height)
4759 {
4760  if (w != width || h != height)
4761  {
4762  removeFromChunks();
4763  w = width;
4764  h = height;
4765  addToChunks();
4766  }
4767 }
4768 
4769 /*
4770  \fn QSize QtCanvasRectangle::size() const
4771 
4772  Returns the width() and height() of the rectangle.
4773 
4774  \sa rect(), setSize()
4775 */
4776 
4777 /*
4778  \fn QRect QtCanvasRectangle::rect() const
4779 
4780  Returns the integer-converted x(), y() position and size() of the
4781  rectangle as a QRect.
4782 */
4783 
4784 /*
4785  \reimp
4786 */
4787 QPolygon QtCanvasRectangle::areaPoints() const
4788 {
4789  QPolygon pa(4);
4790  int pw = (pen().width() + 1) / 2;
4791 
4792  if (pw < 1)
4793  {
4794  pw = 1;
4795  }
4796 
4797  if (pen() == NoPen)
4798  {
4799  pw = 0;
4800  }
4801 
4802  pa[0] = QPoint((int)x() - pw, (int)y() - pw);
4803  pa[1] = pa[0] + QPoint(w + pw * 2, 0);
4804  pa[2] = pa[1] + QPoint(0, h + pw * 2);
4805  pa[3] = pa[0] + QPoint(0, h + pw * 2);
4806  return pa;
4807 }
4808 
4809 /*
4810  Draws the rectangle on painter \a p.
4811 */
4812 void QtCanvasRectangle::drawShape(QPainter& p)
4813 {
4814  p.drawRect((int)x(), (int)y(), w, h);
4815 }
4816 
4817 
4818 /*
4819  \class QtCanvasEllipse qtcanvas.h
4820  \brief The QtCanvasEllipse class provides an ellipse or ellipse segment on a QtCanvas.
4821 
4822  A canvas item that paints an ellipse or ellipse segment with a QBrush.
4823  The ellipse's height, width, start angle and angle length can be set
4824  at construction time. The size can be changed at runtime with
4825  setSize(), and the angles can be changed (if you're displaying an
4826  ellipse segment rather than a whole ellipse) with setAngles().
4827 
4828  Note that angles are specified in 16ths of a degree.
4829 
4830  \target anglediagram
4831  \img qcanvasellipse.png Ellipse
4832 
4833  If a start angle and length angle are set then an ellipse segment
4834  will be drawn. The start angle is the angle that goes from zero in a
4835  counter-clockwise direction (shown in green in the diagram). The
4836  length angle is the angle from the start angle in a
4837  counter-clockwise direction (shown in blue in the diagram). The blue
4838  segment is the segment of the ellipse that would be drawn. If no
4839  start angle and length angle are specified the entire ellipse is
4840  drawn.
4841 
4842  The ellipse can be drawn on a painter with drawShape().
4843 
4844  Like any other canvas item ellipses can be moved with move() and
4845  moveBy(), or by setting coordinates with setX(), setY() and setZ().
4846 
4847  Note: QtCanvasEllipse does not use the pen.
4848 */
4849 
4850 /*
4851  Constructs a 32x32 ellipse, centered at (0, 0) on \a canvas.
4852 */
4854  QtCanvasPolygonalItem(canvas),
4855  w(32), h(32),
4856  a1(0), a2(360 * 16)
4857 {
4858 }
4859 
4860 /*
4861  Constructs a \a width by \a height pixel ellipse, centered at
4862  (0, 0) on \a canvas.
4863 */
4864 QtCanvasEllipse::QtCanvasEllipse(int width, int height, QtCanvas* canvas) :
4865  QtCanvasPolygonalItem(canvas),
4866  w(width), h(height),
4867  a1(0), a2(360 * 16)
4868 {
4869 }
4870 
4871 // ### add a constructor taking degrees in float. 1/16 degrees is stupid. Lars
4872 // ### it's how QPainter does it, so QtCanvas does too for consistency. If it's
4873 // ### a good idea, it should be added to QPainter, not just to QtCanvas. Warwick
4874 /*
4875  Constructs a \a width by \a height pixel ellipse, centered at
4876  (0, 0) on \a canvas. Only a segment of the ellipse is drawn,
4877  starting at angle \a startangle, and extending for angle \a angle
4878  (the angle length).
4879 
4880  Note that angles are specified in sixteenths of a degree.
4881 */
4882 QtCanvasEllipse::QtCanvasEllipse(int width, int height,
4883  int startangle, int angle, QtCanvas* canvas) :
4884  QtCanvasPolygonalItem(canvas),
4885  w(width), h(height),
4886  a1(startangle), a2(angle)
4887 {
4888 }
4889 
4890 /*
4891  Destroys the ellipse.
4892 */
4894 {
4895  hide();
4896 }
4897 
4898 /*
4899  Returns the width of the ellipse.
4900 */
4901 int QtCanvasEllipse::width() const
4902 {
4903  return w;
4904 }
4905 
4906 /*
4907  Returns the height of the ellipse.
4908 */
4909 int QtCanvasEllipse::height() const
4910 {
4911  return h;
4912 }
4913 
4914 /*
4915  Sets the \a width and \a height of the ellipse.
4916 */
4917 void QtCanvasEllipse::setSize(int width, int height)
4918 {
4919  if (w != width || h != height)
4920  {
4921  removeFromChunks();
4922  w = width;
4923  h = height;
4924  addToChunks();
4925  }
4926 }
4927 
4928 /*
4929  \fn int QtCanvasEllipse::angleStart() const
4930 
4931  Returns the start angle in 16ths of a degree. Initially
4932  this will be 0.
4933 
4934  \sa setAngles(), angleLength()
4935 */
4936 
4937 /*
4938  \fn int QtCanvasEllipse::angleLength() const
4939 
4940  Returns the length angle (the extent of the ellipse segment) in
4941  16ths of a degree. Initially this will be 360 * 16 (a complete
4942  ellipse).
4943 
4944  \sa setAngles(), angleStart()
4945 */
4946 
4947 /*
4948  Sets the angles for the ellipse. The start angle is \a start and
4949  the extent of the segment is \a length (the angle length) from the
4950  \a start. The angles are specified in 16ths of a degree. By
4951  default the ellipse will start at 0 and have an angle length of
4952  360 * 16 (a complete ellipse).
4953 
4954  \sa angleStart(), angleLength()
4955 */
4956 void QtCanvasEllipse::setAngles(int start, int length)
4957 {
4958  if (a1 != start || a2 != length)
4959  {
4960  removeFromChunks();
4961  a1 = start;
4962  a2 = length;
4963  addToChunks();
4964  }
4965 }
4966 
4967 /*
4968  \reimp
4969 */
4970 QPolygon QtCanvasEllipse::areaPoints() const
4971 {
4972  QPainterPath path;
4973  path.arcTo(QRectF(x() - w / 2.0 + 0.5 - 1, y() - h / 2.0 + 0.5 - 1, w + 3, h + 3), a1 / 16., a2 / 16.);
4974  return path.toFillPolygon().toPolygon();
4975 }
4976 
4977 /*
4978  Draws the ellipse, centered at x(), y() using the painter \a p.
4979 
4980  Note that QtCanvasEllipse does not support an outline (the pen is
4981  always NoPen).
4982 */
4983 void QtCanvasEllipse::drawShape(QPainter& p)
4984 {
4985  p.setPen(NoPen); // since QRegion(QPolygon) excludes outline :-()-:
4986 
4987  if (!a1 && a2 == 360 * 16)
4988  {
4989  p.drawEllipse(int(x() - w / 2.0 + 0.5), int(y() - h / 2.0 + 0.5), w, h);
4990  }
4991  else
4992  {
4993  p.drawPie(int(x() - w / 2.0 + 0.5), int(y() - h / 2.0 + 0.5), w, h, a1, a2);
4994  }
4995 }
4996 
4997 
4998 /*
4999  \class QtCanvasText
5000  \brief The QtCanvasText class provides a text object on a QtCanvas.
5001 
5002  A canvas text item has text with font, color and alignment
5003  attributes. The text and font can be set in the constructor or set
5004  or changed later with setText() and setFont(). The color is set
5005  with setColor() and the alignment with setTextFlags(). The text
5006  item's bounding rectangle is retrieved with boundingRect().
5007 
5008  The text can be drawn on a painter with draw().
5009 
5010  Like any other canvas item text items can be moved with
5011  QtCanvasItem::move() and QtCanvasItem::moveBy(), or by setting
5012  coordinates with QtCanvasItem::setX(), QtCanvasItem::setY() and
5013  QtCanvasItem::setZ().
5014 */
5015 
5016 /*
5017  Constructs a QtCanvasText with the text "<text>", on \a canvas.
5018 */
5020  QtCanvasItem(canvas),
5021  txt("<text>"), flags(0)
5022 {
5023  setRect();
5024 }
5025 
5026 // ### add textflags to the constructor? Lars
5027 /*
5028  Constructs a QtCanvasText with the text \a t, on canvas \a canvas.
5029 */
5030 QtCanvasText::QtCanvasText(const QString& t, QtCanvas* canvas) :
5031  QtCanvasItem(canvas),
5032  txt(t), flags(0)
5033 {
5034  setRect();
5035 }
5036 
5037 // ### see above
5038 /*
5039  Constructs a QtCanvasText with the text \a t and font \a f, on the
5040  canvas \a canvas.
5041 */
5042 QtCanvasText::QtCanvasText(const QString& t, QFont f, QtCanvas* canvas) :
5043  QtCanvasItem(canvas),
5044  txt(t), flags(0),
5045  fnt(f)
5046 {
5047  setRect();
5048 }
5049 
5050 /*
5051  Destroys the canvas text item.
5052 */
5054 {
5055  removeFromChunks();
5056 }
5057 
5058 /*
5059  Returns the bounding rectangle of the text.
5060 */
5061 QRect QtCanvasText::boundingRect() const
5062 {
5063  return brect;
5064 }
5065 
5066 void QtCanvasText::setRect()
5067 {
5068  brect = QFontMetrics(fnt).boundingRect(int(x()), int(y()), 0, 0, flags, txt);
5069 }
5070 
5071 /*
5072  \fn int QtCanvasText::textFlags() const
5073 
5074  Returns the currently set alignment flags.
5075 
5076  \sa setTextFlags() Qt::AlignmentFlag Qt::TextFlag
5077 */
5078 
5079 
5080 /*
5081  Sets the alignment flags to \a f. These are a bitwise OR of the
5082  flags available to QPainter::drawText() -- see the
5083  \l{Qt::AlignmentFlag}s and \l{Qt::TextFlag}s.
5084 
5085  \sa setFont() setColor()
5086 */
5087 void QtCanvasText::setTextFlags(int f)
5088 {
5089  if (flags != f)
5090  {
5091  removeFromChunks();
5092  flags = f;
5093  setRect();
5094  addToChunks();
5095  }
5096 }
5097 
5098 /*
5099  Returns the text item's text.
5100 
5101  \sa setText()
5102 */
5103 QString QtCanvasText::text() const
5104 {
5105  return txt;
5106 }
5107 
5108 
5109 /*
5110  Sets the text item's text to \a t. The text may contain newlines.
5111 
5112  \sa text(), setFont(), setColor() setTextFlags()
5113 */
5114 void QtCanvasText::setText(const QString& t)
5115 {
5116  if (txt != t)
5117  {
5118  removeFromChunks();
5119  txt = t;
5120  setRect();
5121  addToChunks();
5122  }
5123 }
5124 
5125 /*
5126  Returns the font in which the text is drawn.
5127 
5128  \sa setFont()
5129 */
5130 QFont QtCanvasText::font() const
5131 {
5132  return fnt;
5133 }
5134 
5135 /*
5136  Sets the font in which the text is drawn to font \a f.
5137 
5138  \sa font()
5139 */
5140 void QtCanvasText::setFont(const QFont& f)
5141 {
5142  if (f != fnt)
5143  {
5144  removeFromChunks();
5145  fnt = f;
5146  setRect();
5147  addToChunks();
5148  }
5149 }
5150 
5151 /*
5152  Returns the color of the text.
5153 
5154  \sa setColor()
5155 */
5156 QColor QtCanvasText::color() const
5157 {
5158  return col;
5159 }
5160 
5161 /*
5162  Sets the color of the text to the color \a c.
5163 
5164  \sa color(), setFont()
5165 */
5166 void QtCanvasText::setColor(const QColor& c)
5167 {
5168  col = c;
5169  changeChunks();
5170 }
5171 
5172 
5173 /*
5174  \reimp
5175 */
5176 void QtCanvasText::moveBy(double dx, double dy)
5177 {
5178  int idx = int(x() + dx) - int(x());
5179  int idy = int(y() + dy) - int(y());
5180 
5181  if (idx || idy)
5182  {
5183  removeFromChunks();
5184  }
5185 
5186  myx += dx;
5187  myy += dy;
5188 
5189  if (idx || idy)
5190  {
5191  brect.translate(idx, idy);
5192  addToChunks();
5193  }
5194 }
5195 
5196 /*
5197  Draws the text using the painter \a painter.
5198 */
5199 void QtCanvasText::draw(QPainter& painter)
5200 {
5201  painter.setFont(fnt);
5202  painter.setPen(col);
5203  painter.drawText(painter.fontMetrics().boundingRect(int(x()), int(y()), 0, 0, flags, txt), flags, txt);
5204 }
5205 
5206 /*
5207  \reimp
5208 */
5209 void QtCanvasText::changeChunks()
5210 {
5211  if (isVisible() && canvas())
5212  {
5213  int chunksize = canvas()->chunkSize();
5214 
5215  for (int j = brect.top() / chunksize; j <= brect.bottom() / chunksize; j++)
5216  {
5217  for (int i = brect.left() / chunksize; i <= brect.right() / chunksize; i++)
5218  {
5219  canvas()->setChangedChunk(i, j);
5220  }
5221  }
5222  }
5223 }
5224 
5225 /*
5226  Adds the text item to the appropriate chunks.
5227 */
5228 void QtCanvasText::addToChunks()
5229 {
5230  if (isVisible() && canvas())
5231  {
5232  int chunksize = canvas()->chunkSize();
5233 
5234  for (int j = brect.top() / chunksize; j <= brect.bottom() / chunksize; j++)
5235  {
5236  for (int i = brect.left() / chunksize; i <= brect.right() / chunksize; i++)
5237  {
5238  canvas()->addItemToChunk(this, i, j);
5239  }
5240  }
5241  }
5242 }
5243 
5244 /*
5245  Removes the text item from the appropriate chunks.
5246 */
5247 void QtCanvasText::removeFromChunks()
5248 {
5249  if (isVisible() && canvas())
5250  {
5251  int chunksize = canvas()->chunkSize();
5252 
5253  for (int j = brect.top() / chunksize; j <= brect.bottom() / chunksize; j++)
5254  {
5255  for (int i = brect.left() / chunksize; i <= brect.right() / chunksize; i++)
5256  {
5257  canvas()->removeItemFromChunk(this, i, j);
5258  }
5259  }
5260  }
5261 }
5262 
5263 
5264 /*
5265  Returns 0 (QtCanvasItem::Rtti_Item).
5266 
5267  Make your derived classes return their own values for rtti(), so
5268  that you can distinguish between objects returned by
5269  QtCanvas::at(). You should use values greater than 1000 to allow
5270  for extensions to this class.
5271 
5272  Overuse of this functionality can damage its extensibility. For
5273  example, once you have identified a base class of a QtCanvasItem
5274  found by QtCanvas::at(), cast it to that type and call meaningful
5275  methods rather than acting upon the object based on its rtti
5276  value.
5277 
5278  For example:
5279 
5280  \code
5281  QtCanvasItem* item;
5282  // Find an item, e.g. with QtCanvasItem::collisions().
5283  ...
5284  if (item->rtti() == MySprite::RTTI) {
5285  MySprite* s = (MySprite*)item;
5286  if (s->isDamagable()) s->loseHitPoints(1000);
5287  if (s->isHot()) myself->loseHitPoints(1000);
5288  ...
5289  }
5290  \endcode
5291 */
5292 int QtCanvasItem::rtti() const
5293 {
5294  return RTTI;
5295 }
5296 int QtCanvasItem::RTTI = Rtti_Item;
5297 
5298 /*
5299  Returns 1 (QtCanvasItem::Rtti_Sprite).
5300 
5301  \sa QtCanvasItem::rtti()
5302 */
5303 int QtCanvasSprite::rtti() const
5304 {
5305  return RTTI;
5306 }
5307 int QtCanvasSprite::RTTI = Rtti_Sprite;
5308 
5309 /*
5310  Returns 2 (QtCanvasItem::Rtti_PolygonalItem).
5311 
5312  \sa QtCanvasItem::rtti()
5313 */
5314 int QtCanvasPolygonalItem::rtti() const
5315 {
5316  return RTTI;
5317 }
5318 int QtCanvasPolygonalItem::RTTI = Rtti_PolygonalItem;
5319 
5320 /*
5321  Returns 3 (QtCanvasItem::Rtti_Text).
5322 
5323  \sa QtCanvasItem::rtti()
5324 */
5325 int QtCanvasText::rtti() const
5326 {
5327  return RTTI;
5328 }
5329 int QtCanvasText::RTTI = Rtti_Text;
5330 
5331 /*
5332  Returns 4 (QtCanvasItem::Rtti_Polygon).
5333 
5334  \sa QtCanvasItem::rtti()
5335 */
5336 int QtCanvasPolygon::rtti() const
5337 {
5338  return RTTI;
5339 }
5340 int QtCanvasPolygon::RTTI = Rtti_Polygon;
5341 
5342 /*
5343  Returns 5 (QtCanvasItem::Rtti_Rectangle).
5344 
5345  \sa QtCanvasItem::rtti()
5346 */
5347 int QtCanvasRectangle::rtti() const
5348 {
5349  return RTTI;
5350 }
5351 int QtCanvasRectangle::RTTI = Rtti_Rectangle;
5352 
5353 /*
5354  Returns 6 (QtCanvasItem::Rtti_Ellipse).
5355 
5356  \sa QtCanvasItem::rtti()
5357 */
5358 int QtCanvasEllipse::rtti() const
5359 {
5360  return RTTI;
5361 }
5362 int QtCanvasEllipse::RTTI = Rtti_Ellipse;
5363 
5364 /*
5365  Returns 7 (QtCanvasItem::Rtti_Line).
5366 
5367  \sa QtCanvasItem::rtti()
5368 */
5369 int QtCanvasLine::rtti() const
5370 {
5371  return RTTI;
5372 }
5373 int QtCanvasLine::RTTI = Rtti_Line;
5374 
5375 /*
5376  Returns 8 (QtCanvasItem::Rtti_Spline).
5377 
5378  \sa QtCanvasItem::rtti()
5379 */
5380 int QtCanvasSpline::rtti() const
5381 {
5382  return RTTI;
5383 }
5384 int QtCanvasSpline::RTTI = Rtti_Spline;
5385 
5386 /*
5387  Constructs a QtCanvasSprite which uses images from the
5388  QtCanvasPixmapArray \a a.
5389 
5390  The sprite in initially positioned at (0, 0) on \a canvas, using
5391  frame 0.
5392 */
5394  QtCanvasItem(canvas),
5395  frm(0),
5396  anim_val(0),
5397  anim_state(0),
5398  anim_type(0),
5399  images(a)
5400 {
5401 }
5402 
5403 
5404 /*
5405  Set the array of images used for displaying the sprite to the
5406  QtCanvasPixmapArray \a a.
5407 
5408  If the current frame() is larger than the number of images in \a
5409  a, the current frame will be reset to 0.
5410 */
5412 {
5413  bool isvisible = isVisible();
5414 
5415  if (isvisible && images)
5416  {
5417  hide();
5418  }
5419 
5420  images = a;
5421 
5422  if (frm >= (int)images->count())
5423  {
5424  frm = 0;
5425  }
5426 
5427  if (isvisible)
5428  {
5429  show();
5430  }
5431 }
5432 
5433 /*
5434 \internal
5435 
5436 Marks any chunks the sprite touches as changed.
5437 */
5438 void QtCanvasSprite::changeChunks()
5439 {
5440  if (isVisible() && canvas())
5441  {
5442  int chunksize = canvas()->chunkSize();
5443 
5444  for (int j = topEdge() / chunksize; j <= bottomEdge() / chunksize; j++)
5445  {
5446  for (int i = leftEdge() / chunksize; i <= rightEdge() / chunksize; i++)
5447  {
5448  canvas()->setChangedChunk(i, j);
5449  }
5450  }
5451  }
5452 }
5453 
5454 /*
5455  Destroys the sprite and removes it from the canvas. Does \e not
5456  delete the images.
5457 */
5459 {
5460  removeFromChunks();
5461 }
5462 
5463 /*
5464  Sets the animation frame used for displaying the sprite to \a f,
5465  an index into the QtCanvasSprite's QtCanvasPixmapArray. The call
5466  will be ignored if \a f is larger than frameCount() or smaller
5467  than 0.
5468 
5469  \sa frame() move()
5470 */
5471 void QtCanvasSprite::setFrame(int f)
5472 {
5473  move(x(), y(), f);
5474 }
5475 
5476 /*
5477  \enum QtCanvasSprite::FrameAnimationType
5478 
5479  This enum is used to identify the different types of frame
5480  animation offered by QtCanvasSprite.
5481 
5482  \value Cycle at each advance the frame number will be incremented by
5483  1 (modulo the frame count).
5484  \value Oscillate at each advance the frame number will be
5485  incremented by 1 up to the frame count then decremented to by 1 to
5486  0, repeating this sequence forever.
5487 */
5488 
5489 /*
5490  Sets the animation characteristics for the sprite.
5491 
5492  For \a type == \c Cycle, the frames will increase by \a step
5493  at each advance, modulo the frameCount().
5494 
5495  For \a type == \c Oscillate, the frames will increase by \a step
5496  at each advance, up to the frameCount(), then decrease by \a step
5497  back to 0, repeating forever.
5498 
5499  The \a state parameter is for internal use.
5500 */
5501 void QtCanvasSprite::setFrameAnimation(FrameAnimationType type, int step, int state)
5502 {
5503  anim_val = step;
5504  anim_type = type;
5505  anim_state = state;
5506  setAnimated(true);
5507 }
5508 
5509 /*
5510  Extends the default QtCanvasItem implementation to provide the
5511  functionality of setFrameAnimation().
5512 
5513  The \a phase is 0 or 1: see QtCanvasItem::advance() for details.
5514 
5515  \sa QtCanvasItem::advance() setVelocity()
5516 */
5517 void QtCanvasSprite::advance(int phase)
5518 {
5519  if (phase == 1)
5520  {
5521  int nf = frame();
5522 
5523  if (anim_type == Oscillate)
5524  {
5525  if (anim_state)
5526  {
5527  nf += anim_val;
5528  }
5529  else
5530  {
5531  nf -= anim_val;
5532  }
5533 
5534  if (nf < 0)
5535  {
5536  nf = abs(anim_val);
5537  anim_state = !anim_state;
5538  }
5539  else if (nf >= frameCount())
5540  {
5541  nf = frameCount() - 1 - abs(anim_val);
5542  anim_state = !anim_state;
5543  }
5544  }
5545  else
5546  {
5547  nf = (nf + anim_val + frameCount()) % frameCount();
5548  }
5549 
5550  move(x() + xVelocity(), y() + yVelocity(), nf);
5551  }
5552 }
5553 
5554 
5555 /*
5556  \fn int QtCanvasSprite::frame() const
5557 
5558  Returns the index of the current animation frame in the
5559  QtCanvasSprite's QtCanvasPixmapArray.
5560 
5561  \sa setFrame(), move()
5562 */
5563 
5564 /*
5565  \fn int QtCanvasSprite::frameCount() const
5566 
5567  Returns the number of frames in the QtCanvasSprite's
5568  QtCanvasPixmapArray.
5569 */
5570 
5571 
5572 /*
5573  Moves the sprite to (\a x, \a y).
5574 */
5575 void QtCanvasSprite::move(double x, double y)
5576 {
5578 }
5579 
5580 /*
5581  \fn void QtCanvasSprite::move(double nx, double ny, int nf)
5582 
5583  Moves the sprite to (\a nx, \a ny) and sets the current
5584  frame to \a nf. \a nf will be ignored if it is larger than
5585  frameCount() or smaller than 0.
5586 */
5587 void QtCanvasSprite::move(double nx, double ny, int nf)
5588 {
5589  if (isVisible() && canvas())
5590  {
5591  hide();
5592  QtCanvasItem::move(nx, ny);
5593 
5594  if (nf >= 0 && nf < frameCount())
5595  {
5596  frm = nf;
5597  }
5598 
5599  show();
5600  }
5601  else
5602  {
5603  QtCanvasItem::move(nx, ny);
5604 
5605  if (nf >= 0 && nf < frameCount())
5606  {
5607  frm = nf;
5608  }
5609  }
5610 }
5611 
5612 
5613 class QPoint;
5614 
5615 class QtPolygonScanner
5616 {
5617 public:
5618  virtual ~QtPolygonScanner() {}
5619  void scan(const QPolygon& pa, bool winding, int index = 0, int npoints = -1);
5620  void scan(const QPolygon& pa, bool winding, int index, int npoints, bool stitchable);
5621  enum Edge { Left = 1, Right = 2, Top = 4, Bottom = 8 };
5622  void scan(const QPolygon& pa, bool winding, int index, int npoints, Edge edges);
5623  virtual void processSpans(int n, QPoint* point, int* width) = 0;
5624 };
5625 
5626 
5627 // Based on Xserver code miFillGeneralPoly...
5628 /*
5629  *
5630  * Written by Brian Kelleher; Oct. 1985
5631  *
5632  * Routine to fill a polygon. Two fill rules are
5633  * supported: frWINDING and frEVENODD.
5634  *
5635  * See fillpoly.h for a complete description of the algorithm.
5636  */
5637 
5638 /*
5639  * These are the data structures needed to scan
5640  * convert regions. Two different scan conversion
5641  * methods are available -- the even-odd method, and
5642  * the winding number method.
5643  * The even-odd rule states that a point is inside
5644  * the polygon if a ray drawn from that point in any
5645  * direction will pass through an odd number of
5646  * path segments.
5647  * By the winding number rule, a point is decided
5648  * to be inside the polygon if a ray drawn from that
5649  * point in any direction passes through a different
5650  * number of clockwise and counterclockwise path
5651  * segments.
5652  *
5653  * These data structures are adapted somewhat from
5654  * the algorithm in (Foley/Van Dam) for scan converting
5655  * polygons.
5656  * The basic algorithm is to start at the top (smallest y)
5657  * of the polygon, stepping down to the bottom of
5658  * the polygon by incrementing the y coordinate. We
5659  * keep a list of edges which the current scanline crosses,
5660  * sorted by x. This list is called the Active Edge Table (AET)
5661  * As we change the y-coordinate, we update each entry in
5662  * in the active edge table to reflect the edges new xcoord.
5663  * This list must be sorted at each scanline in case
5664  * two edges intersect.
5665  * We also keep a data structure known as the Edge Table (ET),
5666  * which keeps track of all the edges which the current
5667  * scanline has not yet reached. The ET is basically a
5668  * list of ScanLineList structures containing a list of
5669  * edges which are entered at a given scanline. There is one
5670  * ScanLineList per scanline at which an edge is entered.
5671  * When we enter a new edge, we move it from the ET to the AET.
5672  *
5673  * From the AET, we can implement the even-odd rule as in
5674  * (Foley/Van Dam).
5675  * The winding number rule is a little trickier. We also
5676  * keep the EdgeTableEntries in the AET linked by the
5677  * nextWETE (winding EdgeTableEntry) link. This allows
5678  * the edges to be linked just as before for updating
5679  * purposes, but only uses the edges linked by the nextWETE
5680  * link as edges representing spans of the polygon to
5681  * drawn (as with the even-odd rule).
5682  */
5683 
5684 /* $XConsortium: miscanfill.h, v 1.5 94/04/17 20:27:50 dpw Exp $ */
5685 /*
5686 
5687 Copyright (c) 1987 X Consortium
5688 
5689 Permission is hereby granted, free of charge, to any person obtaining
5690 a copy of this software and associated documentation files (the
5691 "Software"), to deal in the Software without restriction, including
5692 without limitation the rights to use, copy, modify, merge, publish,
5693 distribute, sublicense, and/or sell copies of the Software, and to
5694 permit persons to whom the Software is furnished to do so, subject to
5695 the following conditions:
5696 
5697 The above copyright notice and this permission notice shall be included
5698 in all copies or substantial portions of the Software.
5699 
5700 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
5701 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5702 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5703 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
5704 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
5705 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
5706 OTHER DEALINGS IN THE SOFTWARE.
5707 
5708 Except as contained in this notice, the name of the X Consortium shall
5709 not be used in advertising or otherwise to promote the sale, use or
5710 other dealings in this Software without prior written authorization
5711 from the X Consortium.
5712 
5713 */
5714 
5715 
5716 /*
5717  * scanfill.h
5718  *
5719  * Written by Brian Kelleher; Jan 1985
5720  *
5721  * This file contains a few macros to help track
5722  * the edge of a filled object. The object is assumed
5723  * to be filled in scanline order, and thus the
5724  * algorithm used is an extension of Bresenham's line
5725  * drawing algorithm which assumes that y is always the
5726  * major axis.
5727  * Since these pieces of code are the same for any filled shape,
5728  * it is more convenient to gather the library in one
5729  * place, but since these pieces of code are also in
5730  * the inner loops of output primitives, procedure call
5731  * overhead is out of the question.
5732  * See the author for a derivation if needed.
5733  */
5734 
5735 /*
5736  * In scan converting polygons, we want to choose those pixels
5737  * which are inside the polygon. Thus, we add .5 to the starting
5738  * x coordinate for both left and right edges. Now we choose the
5739  * first pixel which is inside the pgon for the left edge and the
5740  * first pixel which is outside the pgon for the right edge.
5741  * Draw the left pixel, but not the right.
5742  *
5743  * How to add .5 to the starting x coordinate:
5744  * If the edge is moving to the right, then subtract dy from the
5745  * error term from the general form of the algorithm.
5746  * If the edge is moving to the left, then add dy to the error term.
5747  *
5748  * The reason for the difference between edges moving to the left
5749  * and edges moving to the right is simple: If an edge is moving
5750  * to the right, then we want the algorithm to flip immediately.
5751  * If it is moving to the left, then we don't want it to flip until
5752  * we traverse an entire pixel.
5753  */
5754 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
5755  int dx; /* local storage */ \
5756  \
5757  /* \
5758  * if the edge is horizontal, then it is ignored \
5759  * and assumed not to be processed. Otherwise, do this stuff. \
5760  */ \
5761  if ((dy) != 0) { \
5762  xStart = (x1); \
5763  dx = (x2) - xStart; \
5764  if (dx < 0) { \
5765  m = dx / (dy); \
5766  m1 = m - 1; \
5767  incr1 = -2 * dx + 2 * (dy) * m1; \
5768  incr2 = -2 * dx + 2 * (dy) * m; \
5769  d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
5770  } else { \
5771  m = dx / (dy); \
5772  m1 = m + 1; \
5773  incr1 = 2 * dx - 2 * (dy) * m1; \
5774  incr2 = 2 * dx - 2 * (dy) * m; \
5775  d = -2 * m * (dy) + 2 * dx; \
5776  } \
5777  } \
5778  }
5779 
5780 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
5781  if (m1 > 0) { \
5782  if (d > 0) { \
5783  minval += m1; \
5784  d += incr1; \
5785  } \
5786  else { \
5787  minval += m; \
5788  d += incr2; \
5789  } \
5790  } else {\
5791  if (d >= 0) { \
5792  minval += m1; \
5793  d += incr1; \
5794  } \
5795  else { \
5796  minval += m; \
5797  d += incr2; \
5798  } \
5799  } \
5800  }
5801 
5802 
5803 /*
5804  * This structure contains all of the information needed
5805  * to run the bresenham algorithm.
5806  * The variables may be hardcoded into the declarations
5807  * instead of using this structure to make use of
5808  * register declarations.
5809  */
5810 typedef struct
5811 {
5812  int minor; /* minor axis */
5813  int d; /* decision variable */
5814  int m, m1; /* slope and slope+1 */
5815  int incr1, incr2; /* error increments */
5817 
5818 
5819 #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
5820  BRESINITPGON(dmaj, min1, min2, bres.minor, bres.d, \
5821  bres.m, bres.m1, bres.incr1, bres.incr2)
5822 
5823 #define BRESINCRPGONSTRUCT(bres) \
5824  BRESINCRPGON(bres.d, bres.minor, bres.m, bres.m1, bres.incr1, bres.incr2)
5825 
5826 
5827 typedef struct _EdgeTableEntry
5828 {
5829  int ymax; /* ycoord at which we exit this edge. */
5830  BRESINFO bres; /* Bresenham info to run the edge */
5831  struct _EdgeTableEntry* next; /* next in the list */
5832  struct _EdgeTableEntry* back; /* for insertion sort */
5833  struct _EdgeTableEntry* nextWETE; /* for winding num rule */
5834  int ClockWise; /* flag for winding number rule */
5835 } EdgeTableEntry;
5836 
5837 
5838 typedef struct _ScanLineList
5839 {
5840  int scanline; /* the scanline represented */
5841  EdgeTableEntry* edgelist; /* header node */
5842  struct _ScanLineList* next; /* next in the list */
5843 } ScanLineList;
5844 
5845 
5846 typedef struct
5847 {
5848  int ymax; /* ymax for the polygon */
5849  int ymin; /* ymin for the polygon */
5850  ScanLineList scanlines; /* header node */
5851 } EdgeTable;
5852 
5853 
5854 /*
5855  * Here is a struct to help with storage allocation
5856  * so we can allocate a big chunk at a time, and then take
5857  * pieces from this heap when we need to.
5858  */
5859 #define SLLSPERBLOCK 25
5860 
5861 typedef struct _ScanLineListBlock
5862 {
5864  struct _ScanLineListBlock* next;
5866 
5867 /*
5868  * number of points to buffer before sending them off
5869  * to scanlines() : Must be an even number
5870  */
5871 #define NUMPTSTOBUFFER 200
5872 
5873 /*
5874  *
5875  * a few macros for the inner loops of the fill code where
5876  * performance considerations don't allow a procedure call.
5877  *
5878  * Evaluate the given edge at the given scanline.
5879  * If the edge has expired, then we leave it and fix up
5880  * the active edge table; otherwise, we increment the
5881  * x value to be ready for the next scanline.
5882  * The winding number rule is in effect, so we must notify
5883  * the caller when the edge has been removed so he
5884  * can reorder the Winding Active Edge Table.
5885  */
5886 #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
5887  if (pAET->ymax == y) { /* leaving this edge */ \
5888  pPrevAET->next = pAET->next; \
5889  pAET = pPrevAET->next; \
5890  fixWAET = 1; \
5891  if (pAET) \
5892  pAET->back = pPrevAET; \
5893  } \
5894  else { \
5895  BRESINCRPGONSTRUCT(pAET->bres); \
5896  pPrevAET = pAET; \
5897  pAET = pAET->next; \
5898  } \
5899  }
5900 
5901 
5902 /*
5903  * Evaluate the given edge at the given scanline.
5904  * If the edge has expired, then we leave it and fix up
5905  * the active edge table; otherwise, we increment the
5906  * x value to be ready for the next scanline.
5907  * The even-odd rule is in effect.
5908  */
5909 #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
5910  if (pAET->ymax == y) { /* leaving this edge */ \
5911  pPrevAET->next = pAET->next; \
5912  pAET = pPrevAET->next; \
5913  if (pAET) \
5914  pAET->back = pPrevAET; \
5915  } \
5916  else { \
5917  BRESINCRPGONSTRUCT(pAET->bres) \
5918  pPrevAET = pAET; \
5919  pAET = pAET->next; \
5920  } \
5921  }
5922 
5923 /***********************************************************
5924 
5925 Copyright (c) 1987 X Consortium
5926 
5927 Permission is hereby granted, free of charge, to any person obtaining a copy
5928 of this software and associated documentation files (the "Software"), to deal
5929 in the Software without restriction, including without limitation the rights
5930 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5931 copies of the Software, and to permit persons to whom the Software is
5932 furnished to do so, subject to the following conditions:
5933 
5934 The above copyright notice and this permission notice shall be included in
5935 all copies or substantial portions of the Software.
5936 
5937 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5938 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5939 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5940 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
5941 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
5942 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5943 
5944 Except as contained in this notice, the name of the X Consortium shall not be
5945 used in advertising or otherwise to promote the sale, use or other dealings
5946 in this Software without prior written authorization from the X Consortium.
5947 
5948 
5949 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
5950 
5951  All Rights Reserved
5952 
5953 Permission to use, copy, modify, and distribute this software and its
5954 documentation for any purpose and without fee is hereby granted,
5955 provided that the above copyright notice appear in all copies and that
5956 both that copyright notice and this permission notice appear in
5957 supporting documentation, and that the name of Digital not be
5958 used in advertising or publicity pertaining to distribution of the
5959 software without specific, written prior permission.
5960 
5961 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
5962 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
5963 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
5964 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
5965 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
5966 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
5967 SOFTWARE.
5969 ******************************************************************/
5970 
5971 #define MAXINT 0x7fffffff
5972 #define MININT -MAXINT
5973 
5974 /*
5975  * fillUtils.c
5976  *
5977  * Written by Brian Kelleher; Oct. 1985
5978  *
5979  * This module contains all of the utility functions
5980  * needed to scan convert a polygon.
5981  *
5982  */
5983 /*
5984  * InsertEdgeInET
5985  *
5986  * Insert the given edge into the edge table.
5987  * First we must find the correct bucket in the
5988  * Edge table, then find the right slot in the
5989  * bucket. Finally, we can insert it.
5990  *
5991  */
5992 static bool
5993 miInsertEdgeInET(EdgeTable* ET, EdgeTableEntry* ETE,
5994  int scanline, ScanLineListBlock** SLLBlock, int* iSLLBlock)
5995 {
5996  register EdgeTableEntry* start, *prev;
5997  register ScanLineList* pSLL, *pPrevSLL;
5998  ScanLineListBlock* tmpSLLBlock;
5999 
6000  /*
6001  * find the right bucket to put the edge into
6002  */
6003  pPrevSLL = &ET->scanlines;
6004  pSLL = pPrevSLL->next;
6005 
6006  while (pSLL && (pSLL->scanline < scanline))
6007  {
6008  pPrevSLL = pSLL;
6009  pSLL = pSLL->next;
6010  }
6011 
6012  /*
6013  * reassign pSLL (pointer to ScanLineList) if necessary
6014  */
6015  if ((!pSLL) || (pSLL->scanline > scanline))
6016  {
6017  if (*iSLLBlock > SLLSPERBLOCK - 1)
6018  {
6019  tmpSLLBlock =
6020  (ScanLineListBlock*)malloc(sizeof(ScanLineListBlock));
6021 
6022  if (!tmpSLLBlock)
6023  {
6024  return false;
6025  }
6026 
6027  (*SLLBlock)->next = tmpSLLBlock;
6028  tmpSLLBlock->next = 0;
6029  *SLLBlock = tmpSLLBlock;
6030  *iSLLBlock = 0;
6031  }
6032 
6033  pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
6034 
6035  pSLL->next = pPrevSLL->next;
6036  pSLL->edgelist = 0;
6037  pPrevSLL->next = pSLL;
6038  }
6039 
6040  pSLL->scanline = scanline;
6041 
6042  /*
6043  * now insert the edge in the right bucket
6044  */
6045  prev = 0;
6046  start = pSLL->edgelist;
6047 
6048  while (start && (start->bres.minor < ETE->bres.minor))
6049  {
6050  prev = start;
6051  start = start->next;
6052  }
6053 
6054  ETE->next = start;
6055 
6056  if (prev)
6057  {
6058  prev->next = ETE;
6059  }
6060  else
6061  {
6062  pSLL->edgelist = ETE;
6063  }
6064 
6065  return true;
6066 }
6067 
6068 /*
6069  * CreateEdgeTable
6070  *
6071  * This routine creates the edge table for
6072  * scan converting polygons.
6073  * The Edge Table (ET) looks like:
6074  *
6075  * EdgeTable
6076  * --------
6077  * | ymax | ScanLineLists
6078  * |scanline|-->------------>-------------->...
6079  * -------- |scanline| |scanline|
6080  * |edgelist| |edgelist|
6081  * --------- ---------
6082  * | |
6083  * | |
6084  * V V
6085  * list of ETEs list of ETEs
6086  *
6087  * where ETE is an EdgeTableEntry data structure,
6088  * and there is one ScanLineList per scanline at
6089  * which an edge is initially entered.
6090  *
6091  */
6092 
6093 typedef struct
6094 {
6095 #if defined(Q_OS_MAC)
6096  int y, x;
6097 #else
6098  int x, y;
6099 #endif
6100 
6102 
6103 /*
6104  * Clean up our act.
6105  */
6106 static void
6107 miFreeStorage(ScanLineListBlock* pSLLBlock)
6108 {
6109  register ScanLineListBlock* tmpSLLBlock;
6110 
6111  while (pSLLBlock)
6112  {
6113  tmpSLLBlock = pSLLBlock->next;
6114  free(pSLLBlock);
6115  pSLLBlock = tmpSLLBlock;
6116  }
6117 }
6118 
6119 static bool
6120 miCreateETandAET(int count, DDXPointPtr pts, EdgeTable* ET,
6121  EdgeTableEntry* AET, EdgeTableEntry* pETEs, ScanLineListBlock* pSLLBlock)
6122 {
6123  register DDXPointPtr top, bottom;
6124  register DDXPointPtr PrevPt, CurrPt;
6125  int iSLLBlock = 0;
6126 
6127  int dy;
6128 
6129  if (count < 2)
6130  {
6131  return true;
6132  }
6133 
6134  /*
6135  * initialize the Active Edge Table
6136  */
6137  AET->next = 0;
6138  AET->back = 0;
6139  AET->nextWETE = 0;
6140  AET->bres.minor = MININT;
6141 
6142  /*
6143  * initialize the Edge Table.
6144  */
6145  ET->scanlines.next = 0;
6146  ET->ymax = MININT;
6147  ET->ymin = MAXINT;
6148  pSLLBlock->next = 0;
6149 
6150  PrevPt = &pts[count - 1];
6151 
6152  /*
6153  * for each vertex in the array of points.
6154  * In this loop we are dealing with two vertices at
6155  * a time -- these make up one edge of the polygon.
6156  */
6157  while (count--)
6158  {
6159  CurrPt = pts++;
6160 
6161  /*
6162  * find out which point is above and which is below.
6163  */
6164  if (PrevPt->y > CurrPt->y)
6165  {
6166  bottom = PrevPt, top = CurrPt;
6167  pETEs->ClockWise = 0;
6168  }
6169  else
6170  {
6171  bottom = CurrPt, top = PrevPt;
6172  pETEs->ClockWise = 1;
6173  }
6174 
6175  /*
6176  * don't add horizontal edges to the Edge table.
6177  */
6178  if (bottom->y != top->y)
6179  {
6180  pETEs->ymax = bottom->y - 1; /* -1 so we don't get last scanline */
6181 
6182  /*
6183  * initialize integer edge algorithm
6184  */
6185  dy = bottom->y - top->y;
6186  BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres)
6187 
6188  if (!miInsertEdgeInET(ET, pETEs, top->y, &pSLLBlock, &iSLLBlock))
6189  {
6190  miFreeStorage(pSLLBlock->next);
6191  return false;
6192  }
6193 
6194  ET->ymax = qMax(ET->ymax, PrevPt->y);
6195  ET->ymin = qMin(ET->ymin, PrevPt->y);
6196  pETEs++;
6197  }
6198 
6199  PrevPt = CurrPt;
6200  }
6201 
6202  return true;
6203 }
6204 
6205 /*
6206  * loadAET
6207  *
6208  * This routine moves EdgeTableEntries from the
6209  * EdgeTable into the Active Edge Table,
6210  * leaving them sorted by smaller x coordinate.
6211  *
6212  */
6213 
6214 static void
6215 miloadAET(EdgeTableEntry* AET, EdgeTableEntry* ETEs)
6216 {
6217  register EdgeTableEntry* pPrevAET;
6218  register EdgeTableEntry* tmp;
6219 
6220  pPrevAET = AET;
6221  AET = AET->next;
6222 
6223  while (ETEs)
6224  {
6225  while (AET && (AET->bres.minor < ETEs->bres.minor))
6226  {
6227  pPrevAET = AET;
6228  AET = AET->next;
6229  }
6230 
6231  tmp = ETEs->next;
6232  ETEs->next = AET;
6233 
6234  if (AET)
6235  {
6236  AET->back = ETEs;
6237  }
6238 
6239  ETEs->back = pPrevAET;
6240  pPrevAET->next = ETEs;
6241  pPrevAET = ETEs;
6242 
6243  ETEs = tmp;
6244  }
6245 }
6246 
6247 /*
6248  * computeWAET
6249  *
6250  * This routine links the AET by the
6251  * nextWETE (winding EdgeTableEntry) link for
6252  * use by the winding number rule. The final
6253  * Active Edge Table (AET) might look something
6254  * like:
6255  *
6256  * AET
6257  * ---------- --------- ---------
6258  * |ymax | |ymax | |ymax |
6259  * | ... | |... | |... |
6260  * |next |->|next |->|next |->...
6261  * |nextWETE| |nextWETE| |nextWETE|
6262  * --------- --------- ^--------
6263  * | | |
6264  * V-------------------> V---> ...
6265  *
6266  */
6267 static void
6268 micomputeWAET(EdgeTableEntry* AET)
6269 {
6270  register EdgeTableEntry* pWETE;
6271  register int inside = 1;
6272  register int isInside = 0;
6273 
6274  AET->nextWETE = 0;
6275  pWETE = AET;
6276  AET = AET->next;
6277 
6278  while (AET)
6279  {
6280  if (AET->ClockWise)
6281  {
6282  isInside++;
6283  }
6284  else
6285  {
6286  isInside--;
6287  }
6288 
6289  if ((!inside && !isInside) ||
6290  (inside && isInside))
6291  {
6292  pWETE->nextWETE = AET;
6293  pWETE = AET;
6294  inside = !inside;
6295  }
6296 
6297  AET = AET->next;
6298  }
6299 
6300  pWETE->nextWETE = 0;
6301 }
6302 
6303 /*
6304  * InsertionSort
6305  *
6306  * Just a simple insertion sort using
6307  * pointers and back pointers to sort the Active
6308  * Edge Table.
6309  *
6310  */
6311 
6312 static int
6313 miInsertionSort(EdgeTableEntry* AET)
6314 {
6315  register EdgeTableEntry* pETEchase;
6316  register EdgeTableEntry* pETEinsert;
6317  register EdgeTableEntry* pETEchaseBackTMP;
6318  register int changed = 0;
6319 
6320  AET = AET->next;
6321 
6322  while (AET)
6323  {
6324  pETEinsert = AET;
6325  pETEchase = AET;
6326 
6327  while (pETEchase->back->bres.minor > AET->bres.minor)
6328  {
6329  pETEchase = pETEchase->back;
6330  }
6331 
6332  AET = AET->next;
6333 
6334  if (pETEchase != pETEinsert)
6335  {
6336  pETEchaseBackTMP = pETEchase->back;
6337  pETEinsert->back->next = AET;
6338 
6339  if (AET)
6340  {
6341  AET->back = pETEinsert->back;
6342  }
6343 
6344  pETEinsert->next = pETEchase;
6345  pETEchase->back->next = pETEinsert;
6346  pETEchase->back = pETEinsert;
6347  pETEinsert->back = pETEchaseBackTMP;
6348  changed = 1;
6349  }
6350  }
6351 
6352  return changed;
6353 }
6354 
6355 /*
6356  \overload
6357 */
6358 void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints)
6359 {
6360  scan(pa, winding, index, npoints, true);
6361 }
6362 
6363 /*
6364  \overload
6365 
6366  If \a stitchable is false, the right and bottom edges of the
6367  polygon are included. This causes adjacent polygons to overlap.
6368 */
6369 void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints, bool stitchable)
6370 {
6371  scan(pa, winding, index, npoints,
6372  stitchable ? Edge(Left + Top) : Edge(Left + Right + Top + Bottom));
6373 }
6374 
6375 /*
6376  Calls processSpans() for all scanlines of the polygon defined by
6377  \a npoints starting at \a index in \a pa.
6378 
6379  If \a winding is true, the Winding algorithm rather than the
6380  Odd-Even rule is used.
6381 
6382  The \a edges is any bitwise combination of:
6383  \list
6384  \i QtPolygonScanner::Left
6385  \i QtPolygonScanner::Right
6386  \i QtPolygonScanner::Top
6387  \i QtPolygonScanner::Bottom
6388  \endlist
6389  \a edges determines which edges are included.
6390 
6391  \warning The edges feature does not work properly.
6392 
6393 */
6394 void QtPolygonScanner::scan(const QPolygon& pa, bool winding, int index, int npoints, Edge edges)
6395 {
6396 
6397 
6398  DDXPointPtr ptsIn = (DDXPointPtr)pa.data();
6399  ptsIn += index;
6400  register EdgeTableEntry* pAET; /* the Active Edge Table */
6401  register int y; /* the current scanline */
6402  register int nPts = 0; /* number of pts in buffer */
6403  register EdgeTableEntry* pWETE; /* Winding Edge Table */
6404  register ScanLineList* pSLL; /* Current ScanLineList */
6405  register DDXPointPtr ptsOut; /* ptr to output buffers */
6406  int* width;
6407  DDXPointRec FirstPoint[NUMPTSTOBUFFER]; /* the output buffers */
6408  int FirstWidth[NUMPTSTOBUFFER];
6409  EdgeTableEntry* pPrevAET; /* previous AET entry */
6410  EdgeTable ET; /* Edge Table header node */
6411  EdgeTableEntry AET; /* Active ET header node */
6412  EdgeTableEntry* pETEs; /* Edge Table Entries buff */
6413  ScanLineListBlock SLLBlock; /* header for ScanLineList */
6414  int fixWAET = 0;
6415  int edge_l = (edges & Left) ? 1 : 0;
6416  int edge_r = (edges & Right) ? 1 : 0;
6417  int edge_t = 1; //#### (edges & Top) ? 1 : 0;
6418  int edge_b = (edges & Bottom) ? 1 : 0;
6419 
6420  if (npoints == -1)
6421  {
6422  npoints = pa.size();
6423  }
6424 
6425  if (npoints < 3)
6426  {
6427  return;
6428  }
6429 
6430  if (!(pETEs = (EdgeTableEntry*)
6431  malloc(sizeof(EdgeTableEntry) * npoints)))
6432  {
6433  return;
6434  }
6435 
6436  ptsOut = FirstPoint;
6437  width = FirstWidth;
6438 
6439  if (!miCreateETandAET(npoints, ptsIn, &ET, &AET, pETEs, &SLLBlock))
6440  {
6441  free(pETEs);
6442  return;
6443  }
6444 
6445  pSLL = ET.scanlines.next;
6446 
6447  if (!winding)
6448  {
6449  /*
6450  * for each scanline
6451  */
6452  for (y = ET.ymin + 1 - edge_t; y < ET.ymax + edge_b; y++)
6453  {
6454  /*
6455  * Add a new edge to the active edge table when we
6456  * get to the next edge.
6457  */
6458  if (pSLL && y == pSLL->scanline)
6459  {
6460  miloadAET(&AET, pSLL->edgelist);
6461  pSLL = pSLL->next;
6462  }
6463 
6464  pPrevAET = &AET;
6465  pAET = AET.next;
6466 
6467  /*
6468  * for each active edge
6469  */
6470  while (pAET)
6471  {
6472  ptsOut->x = pAET->bres.minor + 1 - edge_l;
6473  ptsOut++->y = y;
6474  *width++ = pAET->next->bres.minor - pAET->bres.minor
6475  - 1 + edge_l + edge_r;
6476  nPts++;
6477 
6478  /*
6479  * send out the buffer when its full
6480  */
6481  if (nPts == NUMPTSTOBUFFER)
6482  {
6483  processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
6484  ptsOut = FirstPoint;
6485  width = FirstWidth;
6486  nPts = 0;
6487  }
6488 
6489  EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
6490  EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
6491  }
6492 
6493  miInsertionSort(&AET);
6494  }
6495  }
6496  else /* default to WindingNumber */
6497  {
6498  /*
6499  * for each scanline
6500  */
6501  for (y = ET.ymin + 1 - edge_t; y < ET.ymax + edge_b; y++)
6502  {
6503  /*
6504  * Add a new edge to the active edge table when we
6505  * get to the next edge.
6506  */
6507  if (pSLL && y == pSLL->scanline)
6508  {
6509  miloadAET(&AET, pSLL->edgelist);
6510  micomputeWAET(&AET);
6511  pSLL = pSLL->next;
6512  }
6513 
6514  pPrevAET = &AET;
6515  pAET = AET.next;
6516  pWETE = pAET;
6517 
6518  /*
6519  * for each active edge
6520  */
6521  while (pAET)
6522  {
6523  /*
6524  * if the next edge in the active edge table is
6525  * also the next edge in the winding active edge
6526  * table.
6527  */
6528  if (pWETE == pAET)
6529  {
6530  ptsOut->x = pAET->bres.minor + 1 - edge_l;
6531  ptsOut++->y = y;
6532  *width++ = pAET->nextWETE->bres.minor - pAET->bres.minor - 1 + edge_l + edge_r;
6533  nPts++;
6534 
6535  /*
6536  * send out the buffer
6537  */
6538  if (nPts == NUMPTSTOBUFFER)
6539  {
6540  processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
6541  ptsOut = FirstPoint;
6542  width = FirstWidth;
6543  nPts = 0;
6544  }
6545 
6546  pWETE = pWETE->nextWETE;
6547 
6548  while (pWETE != pAET)
6549  {
6550  EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
6551  }
6552 
6553  pWETE = pWETE->nextWETE;
6554  }
6555 
6556  EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
6557  }
6558 
6559  /*
6560  * reevaluate the Winding active edge table if we
6561  * just had to resort it or if we just exited an edge.
6562  */
6563  if (miInsertionSort(&AET) || fixWAET)
6564  {
6565  micomputeWAET(&AET);
6566  fixWAET = 0;
6567  }
6568  }
6569  }
6570 
6571  /*
6572  * Get any spans that we missed by buffering
6573  */
6574 
6575 
6576  processSpans(nPts, (QPoint*)FirstPoint, FirstWidth);
6577  free(pETEs);
6578  miFreeStorage(SLLBlock.next);
6579 }
6580 /***** END OF X11-based CODE *****/
6581 
6582 
6583 
6584 
6585 
6588  QPolygonalProcessor& processor;
6589 public:
6591  processor(p)
6592  {
6593  }
6594  void processSpans(int n, QPoint* point, int* width)
6595  {
6596  processor.doSpans(n, point, width);
6597  }
6598 };
6599 
6600 void QtCanvasPolygonalItem::scanPolygon(const QPolygon& pa, int winding, QPolygonalProcessor& process) const
6601 {
6602  QtCanvasPolygonScanner scanner(process);
6603  scanner.scan(pa, winding);
6604 }
QtCanvasSprite::Oscillate
@ Oscillate
Definition: qtcanvas.h:550
QtCanvasPolygonScanner
Definition: qtcanvas.cpp:6583
_EdgeTableEntry
Definition: qtcanvas.cpp:5824
QtCanvasPolygonalItem::drawShape
virtual void drawShape(QPainter &)=0
QtCanvasView::contentsMouseMoveEvent
virtual void contentsMouseMoveEvent(QMouseEvent *)
Definition: qtcanvas.cpp:3647
QtCanvas::backgroundColor
QColor backgroundColor() const
Definition: qtcanvas.cpp:1456
QtCanvasPixmapArray::operator!
bool operator!()
Definition: qtcanvas.cpp:3141
QtCanvasSprite::move
void move(double x, double y)
Definition: qtcanvas.cpp:5575
QtCanvas::addView
virtual void addView(QtCanvasView *)
Definition: qtcanvas.cpp:936
QtCanvasViewData::ixform
QMatrix ixform
Definition: qtcanvas.cpp:74
QtCanvasItem::boundingRect
virtual QRect boundingRect() const =0
QtPolygonScanner::Right
@ Right
Definition: qtcanvas.cpp:5621
QtCanvasItem::setEnabled
virtual void setEnabled(bool yes)
Definition: qtcanvas.cpp:2199
QtCanvasItem::setActive
virtual void setActive(bool yes)
Definition: qtcanvas.cpp:2230
QtCanvasItem::boundingRectAdvanced
virtual QRect boundingRectAdvanced() const
Definition: qtcanvas.cpp:2772
QtCanvasLine::rtti
int rtti() const
Definition: qtcanvas.cpp:5369
QtCanvasClusterizer::QtCanvasClusterizer
QtCanvasClusterizer(int maxclusters)
Definition: qtcanvas.cpp:131
SLLSPERBLOCK
#define SLLSPERBLOCK
Definition: qtcanvas.cpp:5856
QtCanvasPolygon::~QtCanvasPolygon
~QtCanvasPolygon()
Definition: qtcanvas.cpp:4328
QtCanvas::rect
QRect rect() const
Definition: qtcanvas.h:288
QtCanvasView::contentsContextMenuEvent
virtual void contentsContextMenuEvent(QContextMenuEvent *)
Definition: qtcanvas.cpp:3673
QtCanvasPixmap
Definition: qtcanvas.h:456
QtCanvasData::viewList
QList< QtCanvasView * > viewList
Definition: qtcanvas.cpp:64
QtCanvasRectangle::height
int height() const
Definition: qtcanvas.cpp:4750
QtCanvasView::setCanvas
void setCanvas(QtCanvas *v)
Definition: qtcanvas.cpp:3690
EVALUATEEDGEEVENODD
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y)
Definition: qtcanvas.cpp:5906
QtCanvas::update
virtual void update()
Definition: qtcanvas.cpp:1091
QtCanvas::chunkSize
int chunkSize() const
Definition: qtcanvas.h:309
DDXPointRec::y
int y
Definition: qtcanvas.cpp:6095
armarx::navigation::algorithm::astar::intersects
bool intersects(const VirtualRobot::BoundingBox &bb1, const VirtualRobot::BoundingBox &bb2)
Definition: AStarPlanner.cpp:33
QtCanvasText::setFont
void setFont(const QFont &)
Definition: qtcanvas.cpp:5140
QtCanvasPolygon::poly
QPolygon poly
Definition: qtcanvas.h:737
QtCanvas::drawArea
void drawArea(const QRect &, QPainter *p, bool double_buffer=false)
Definition: qtcanvas.cpp:1255
QtCanvasText::collidesWith
bool collidesWith(const QtCanvasItem *) const
Definition: qtcanvas.cpp:2565
EdgeTable::ymin
int ymin
Definition: qtcanvas.cpp:5846
QtCanvasChunk::takeChange
bool takeChange()
Definition: qtcanvas.cpp:384
QtCanvasPixmapArray::~QtCanvasPixmapArray
~QtCanvasPixmapArray()
Definition: qtcanvas.cpp:3001
DDXPointPtr
struct DDXPointRec * DDXPointPtr
QPolygonalProcessor::bounds
QRect bounds
Definition: qtcanvas.cpp:4189
QtCanvasEllipse::~QtCanvasEllipse
~QtCanvasEllipse()
Definition: qtcanvas.cpp:4893
QtCanvasItem::x
double x() const
Definition: qtcanvas.h:73
QtCanvasSpline::~QtCanvasSpline
~QtCanvasSpline()
Definition: qtcanvas.cpp:4427
QtCanvasItem::QtCanvasLine
friend class QtCanvasLine
Definition: qtcanvas.h:204
QtCanvasSpline::RTTI
static int RTTI
Definition: qtcanvas.h:752
QtCanvasChunk::change
void change()
Definition: qtcanvas.cpp:374
QtCanvas::addItemToChunk
void addItemToChunk(QtCanvasItem *, int i, int j)
Definition: qtcanvas.cpp:1391
QtCanvasItem::QtCanvasItem
QtCanvasItem(QtCanvas *canvas)
Definition: qtcanvas.cpp:1824
QtCanvasEllipse::width
int width() const
Definition: qtcanvas.cpp:4901
QtCanvasView::setHighQualityRendering
void setHighQualityRendering(bool enable)
Definition: qtcanvas.cpp:3625
index
uint8_t index
Definition: EtherCATFrame.h:59
QtCanvas::drawBackground
virtual void drawBackground(QPainter &, const QRect &area)
Definition: qtcanvas.cpp:1526
QPolygonalProcessor
Definition: qtcanvas.cpp:3992
QtCanvasText::boundingRect
QRect boundingRect() const
Definition: qtcanvas.cpp:5061
_ScanLineListBlock::SLLs
ScanLineList SLLs[SLLSPERBLOCK]
Definition: qtcanvas.cpp:5860
QtCanvas::removeItemFromChunk
void removeItemFromChunk(QtCanvasItem *, int i, int j)
Definition: qtcanvas.cpp:1406
QtCanvasItem::QtCanvasPolygonalItem
friend class QtCanvasPolygonalItem
Definition: qtcanvas.h:198
QtCanvasPolygon
Definition: qtcanvas.h:721
QtCanvasEllipse::areaPoints
QPolygon areaPoints() const
Definition: qtcanvas.cpp:4970
QtCanvasRectangle::width
int width() const
Definition: qtcanvas.cpp:4742
QtCanvasSprite::rightEdge
int rightEdge() const
Definition: qtcanvas.cpp:3255
QtCanvas::drawViewArea
void drawViewArea(QtCanvasView *view, QPainter *p, const QRect &r, bool dbuf)
Definition: qtcanvas.cpp:1075
list
list(APPEND SOURCES ${QT_RESOURCES}) set(COMPONENT_LIBS ArmarXGui ArmarXCoreObservers ArmarXCoreEigen3Variants PlotterController $
Definition: CMakeLists.txt:49
QtCanvasWidget::paintEvent
void paintEvent(QPaintEvent *e)
Definition: qtcanvas.cpp:3555
QtCanvasItem::moveBy
virtual void moveBy(double dx, double dy)
Definition: qtcanvas.cpp:1918
qt_testCollision
bool qt_testCollision(const QtCanvasSprite *s1, const QtCanvasSprite *s2)
Definition: qtcanvas.cpp:2239
QtCanvasEllipse::angleLength
int angleLength() const
Definition: qtcanvas.h:811
QPolygonalProcessor::addBits
void addBits(int x1, int x2, uchar newbits, int xo, int yo)
Definition: qtcanvas.cpp:4034
QtCanvasPolygon::moveBy
void moveBy(double dx, double dy)
Definition: qtcanvas.cpp:4365
DDXPointRec
Definition: qtcanvas.cpp:6090
QtCanvasLine::moveBy
void moveBy(double dx, double dy)
Definition: qtcanvas.cpp:4672
QtCanvasRectangle::collidesWith
bool collidesWith(const QtCanvasItem *) const
Definition: qtcanvas.cpp:2530
QtCanvasLine::areaPoints
QPolygon areaPoints() const
Definition: qtcanvas.cpp:4617
QPolygonalProcessor::QPolygonalProcessor
QPolygonalProcessor(QtCanvas *c, const QPolygon &pa)
Definition: qtcanvas.cpp:3995
QtCanvas::removeAnimation
virtual void removeAnimation(QtCanvasItem *)
Definition: qtcanvas.cpp:916
QtCanvas::setChanged
virtual void setChanged(const QRect &area)
Definition: qtcanvas.cpp:1124
QtCanvasLine::setPoints
void setPoints(int x1, int y1, int x2, int y2)
Definition: qtcanvas.cpp:4590
QtCanvasData
Definition: qtcanvas.cpp:57
QtCanvas::removeItemFromChunkContaining
void removeItemFromChunkContaining(QtCanvasItem *, int x, int y)
Definition: qtcanvas.cpp:1437
DDXPointRec::x
int x
Definition: qtcanvas.cpp:6095
QtCanvasView::setWorldMatrix
bool setWorldMatrix(const QMatrix &)
Definition: qtcanvas.cpp:3753
QtCanvasView::contentsDragLeaveEvent
virtual void contentsDragLeaveEvent(QDragLeaveEvent *)
Definition: qtcanvas.cpp:3660
QtPolygonScanner::Top
@ Top
Definition: qtcanvas.cpp:5621
QtCanvasItem::setCanvas
virtual void setCanvas(QtCanvas *)
Definition: qtcanvas.cpp:2056
QtCanvasItem::isVisible
bool isVisible() const
Definition: qtcanvas.h:129
QtCanvas::QtCanvas
QtCanvas(QObject *parent=0)
Definition: qtcanvas.cpp:597
QtCanvasViewData::highQuality
bool highQuality
Definition: qtcanvas.cpp:75
QtCanvasSprite::width
int width() const
Definition: qtcanvas.cpp:3418
QtCanvasWidget::dragMoveEvent
void dragMoveEvent(QDragMoveEvent *e)
Definition: qtcanvas.cpp:3531
QtCanvas::setTile
virtual void setTile(int x, int y, int tilenum)
Definition: qtcanvas.cpp:1706
QtCanvasText::setColor
void setColor(const QColor &)
Definition: qtcanvas.cpp:5166
QtCanvasText::text
QString text() const
Definition: qtcanvas.cpp:5103
_ScanLineListBlock::next
struct _ScanLineListBlock * next
Definition: qtcanvas.cpp:5861
QtCanvas::width
int width() const
Definition: qtcanvas.h:276
_EdgeTableEntry::ymax
int ymax
Definition: qtcanvas.cpp:5826
QPolygonalProcessor::pnt
int pnt
Definition: qtcanvas.cpp:4186
QtCanvas::setTiles
virtual void setTiles(QPixmap tiles, int h, int v, int tilewidth, int tileheight)
Definition: qtcanvas.cpp:1616
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:43
QtCanvasWidget::contextMenuEvent
void contextMenuEvent(QContextMenuEvent *e)
Definition: qtcanvas.cpp:3547
QtCanvasPolygonalItem::RTTI
static int RTTI
Definition: qtcanvas.h:647
EVALUATEEDGEWINDING
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET)
Definition: qtcanvas.cpp:5883
QtCanvasItemExtra
Definition: qtcanvas.cpp:1728
QtCanvasViewData
Definition: qtcanvas.cpp:69
QtCanvasView::drawContents
virtual void drawContents(QPainter *p, int cx, int cy, int cw, int ch)
Definition: qtcanvas.cpp:3788
_EdgeTableEntry::ClockWise
int ClockWise
Definition: qtcanvas.cpp:5831
QtCanvasEllipse::collidesWith
bool collidesWith(const QtCanvasItem *) const
Definition: qtcanvas.cpp:2548
QtCanvasItem::collidesWith
virtual bool collidesWith(const QtCanvasItem *) const =0
QtCanvasItem::QtCanvasText
friend class QtCanvasText
Definition: qtcanvas.h:203
_ScanLineList::next
struct _ScanLineList * next
Definition: qtcanvas.cpp:5839
QtCanvas::collisions
QtCanvasItemList collisions(const QPoint &) const
Definition: qtcanvas.cpp:2627
QtCanvasSpline::rtti
int rtti() const
Definition: qtcanvas.cpp:5380
QtCanvasPixmapArray::count
uint count() const
Definition: qtcanvas.h:520
MININT
#define MININT
Definition: qtcanvas.cpp:5969
armarx::armem::contains
bool contains(const MemoryID &general, const MemoryID &specific)
Indicates whether general is "less specific" than, or equal to, specific, i.e.
Definition: MemoryID.cpp:558
QtCanvasPixmapArray::setImage
void setImage(int i, QtCanvasPixmap *p)
Definition: qtcanvas.cpp:3174
QtCanvasSprite::height
int height() const
Definition: qtcanvas.cpp:3428
visionx::imrecman::ok
@ ok
Definition: ImageRecordingManagerInterface.ice:46
QtCanvasRectangle::setSize
void setSize(int w, int h)
Definition: qtcanvas.cpp:4758
QtCanvasWidget::mouseDoubleClickEvent
void mouseDoubleClickEvent(QMouseEvent *e)
Definition: qtcanvas.cpp:3523
QtCanvasChunk::hasChanged
bool hasChanged() const
Definition: qtcanvas.cpp:379
QtPolygonScanner
Definition: qtcanvas.cpp:5615
QtCanvasChunk
Definition: qtcanvas.cpp:345
QtCanvasPolygonalItem::setWinding
void setWinding(bool)
Definition: qtcanvas.cpp:3939
QtCanvasChunk::add
void add(QtCanvasItem *item)
Definition: qtcanvas.cpp:362
QtCanvas::advance
virtual void advance()
Definition: qtcanvas.cpp:1039
QtCanvasSprite::advance
virtual void advance(int stage)
Definition: qtcanvas.cpp:5517
QtCanvasSpline::setControlPoints
void setControlPoints(QPolygon, bool closed=true)
Definition: qtcanvas.cpp:4444
QtCanvasChunk::QtCanvasChunk
QtCanvasChunk()
Definition: qtcanvas.cpp:348
QtCanvasRectangle::rtti
int rtti() const
Definition: qtcanvas.cpp:5347
QtCanvasView::contentsDragEnterEvent
virtual void contentsDragEnterEvent(QDragEnterEvent *)
Definition: qtcanvas.cpp:3652
QtCanvasLine::RTTI
static int RTTI
Definition: qtcanvas.h:778
QtCanvasClusterizer::clear
void clear()
Definition: qtcanvas.cpp:142
_ScanLineList::edgelist
EdgeTableEntry * edgelist
Definition: qtcanvas.cpp:5838
QtCanvas::resized
void resized()
QtCanvasPixmapArray::readCollisionMasks
bool readCollisionMasks(const QString &filenamepattern)
Definition: qtcanvas.cpp:3065
_EdgeTableEntry::nextWETE
struct _EdgeTableEntry * nextWETE
Definition: qtcanvas.cpp:5830
QtCanvas::height
int height() const
Definition: qtcanvas.h:280
QtCanvasPolygonalItem
Definition: qtcanvas.h:622
QtCanvasViewData::xform
QMatrix xform
Definition: qtcanvas.cpp:73
QtPolygonScanner::processSpans
virtual void processSpans(int n, QPoint *point, int *width)=0
QtCanvasPolygonalItem::~QtCanvasPolygonalItem
virtual ~QtCanvasPolygonalItem()
Definition: qtcanvas.cpp:3912
QtCanvas::allItems
QtCanvasItemList allItems()
Definition: qtcanvas.cpp:684
QtCanvasWidget::QtCanvasWidget
QtCanvasWidget(QtCanvasView *view)
Definition: qtcanvas.cpp:3505
QPolygonalProcessor::canvas
QtCanvas * canvas
Definition: qtcanvas.cpp:4188
armarx::armem::client::query_fns::all
auto all()
Definition: query_fns.h:10
armarx::ctrlutil::a
double a(double t, double a0, double j)
Definition: CtrlUtil.h:45
QtCanvasItem::hide
void hide()
Definition: qtcanvas.cpp:2099
QtCanvasText::rtti
int rtti() const
Definition: qtcanvas.cpp:5325
QtCanvasText::color
QColor color() const
Definition: qtcanvas.cpp:5156
QtCanvasSprite::RTTI
static int RTTI
Definition: qtcanvas.h:562
QtCanvas::setChangedChunkContaining
virtual void setChangedChunkContaining(int x, int y)
Definition: qtcanvas.cpp:1375
QtCanvas::resize
virtual void resize(int width, int height)
Definition: qtcanvas.cpp:694
armarx::abs
std::vector< T > abs(const std::vector< T > &v)
Definition: VectorHelpers.h:253
QtCanvas::setBackgroundPixmap
virtual void setBackgroundPixmap(const QPixmap &p)
Definition: qtcanvas.cpp:1502
QtCanvasViewData::QtCanvasViewData
QtCanvasViewData()
Definition: qtcanvas.cpp:72
QtCanvasClusterizer::~QtCanvasClusterizer
~QtCanvasClusterizer()
Definition: qtcanvas.cpp:137
QtCanvasWidget::mousePressEvent
void mousePressEvent(QMouseEvent *e)
Definition: qtcanvas.cpp:3511
QtCanvasPolygonalItem::setPen
virtual void setPen(QPen p)
Definition: qtcanvas.cpp:4272
QtCanvas::removeItem
virtual void removeItem(QtCanvasItem *)
Definition: qtcanvas.cpp:926
if
if(!yyvaluep)
Definition: Grammar.cpp:724
QtCanvasSprite::~QtCanvasSprite
virtual ~QtCanvasSprite()
Definition: qtcanvas.cpp:5458
QtCanvasItem::draw
virtual void draw(QPainter &)=0
QtCanvas::validChunk
bool validChunk(int x, int y) const
Definition: qtcanvas.h:300
QtCanvasRectangle
Definition: qtcanvas.h:679
QtCanvasPolygon::setPoints
void setPoints(QPolygon)
Definition: qtcanvas.cpp:4353
QtCanvasView::contentsMouseDoubleClickEvent
virtual void contentsMouseDoubleClickEvent(QMouseEvent *)
Definition: qtcanvas.cpp:3642
QtCanvasItem::QtCanvasEllipse
friend class QtCanvasEllipse
Definition: qtcanvas.h:202
QtCanvasView::contentsDragMoveEvent
virtual void contentsDragMoveEvent(QDragMoveEvent *)
Definition: qtcanvas.cpp:3656
QtCanvasClusterizer::add
void add(int x, int y)
Definition: qtcanvas.cpp:147
QtCanvasItem
Definition: qtcanvas.h:67
QtCanvasItem::RTTI
static int RTTI
Definition: qtcanvas.h:179
QtCanvasItem::setVelocity
virtual void setVelocity(double vx, double vy)
Definition: qtcanvas.cpp:1996
QtCanvasWidget::m_view
QtCanvasView * m_view
Definition: qtcanvas.cpp:3552
QtCanvasEllipse::rtti
int rtti() const
Definition: qtcanvas.cpp:5358
QtCanvasSprite::leftEdge
int leftEdge() const
Definition: qtcanvas.cpp:3203
QtCanvasChunk::list
const QtCanvasItemList & list() const
Definition: qtcanvas.cpp:357
QtCanvasPolygonalItem::areaPoints
virtual QPolygon areaPoints() const =0
EdgeTable::ymax
int ymax
Definition: qtcanvas.cpp:5845
QtCanvasSprite::frame
int frame() const
Definition: qtcanvas.h:552
QtCanvasItem::yVelocity
double yVelocity() const
Definition: qtcanvas.cpp:2021
QtCanvasView::sizeHint
virtual QSize sizeHint() const
Definition: qtcanvas.cpp:3804
ScanLineList
struct _ScanLineList ScanLineList
QtCanvasView::highQualityRendering
bool highQualityRendering
Definition: qtcanvas.h:404
QtCanvasView::contentsMousePressEvent
virtual void contentsMousePressEvent(QMouseEvent *)
Definition: qtcanvas.cpp:3632
QtCanvasView::contentsMouseReleaseEvent
virtual void contentsMouseReleaseEvent(QMouseEvent *)
Definition: qtcanvas.cpp:3637
QtCanvasRectangle::drawShape
void drawShape(QPainter &)
Definition: qtcanvas.cpp:4812
_EdgeTableEntry::next
struct _EdgeTableEntry * next
Definition: qtcanvas.cpp:5828
QtCanvasItem::y
double y() const
Definition: qtcanvas.h:77
QtCanvas::setChangedChunk
virtual void setChangedChunk(int i, int j)
Definition: qtcanvas.cpp:1356
QtCanvasSpline::controlPoints
QPolygon controlPoints() const
Definition: qtcanvas.cpp:4463
QtCanvasItem::advance
virtual void advance(int stage)
Definition: qtcanvas.cpp:2037
QtCanvasEllipse::setAngles
void setAngles(int start, int length)
Definition: qtcanvas.cpp:4956
QtCanvasItemLess
Definition: qtcanvas.cpp:330
QtCanvasPixmapArray
Definition: qtcanvas.h:496
QtCanvas::setUnchanged
virtual void setUnchanged(const QRect &area)
Definition: qtcanvas.cpp:1162
QtCanvas::setBackgroundColor
virtual void setBackgroundColor(const QColor &c)
Definition: qtcanvas.cpp:1466
filename
std::string filename
Definition: VisualizationRobot.cpp:83
QtCanvasPolygonalItem::boundingRect
QRect boundingRect() const
Definition: qtcanvas.cpp:4223
QtCanvasItem::canvas
QtCanvas * canvas() const
Definition: qtcanvas.h:184
QtCanvasEllipse::setSize
void setSize(int w, int h)
Definition: qtcanvas.cpp:4917
QtCanvasView::inverseWorldMatrix
const QMatrix & inverseWorldMatrix() const
Definition: qtcanvas.cpp:3735
QtCanvasSprite::setFrameAnimation
virtual void setFrameAnimation(FrameAnimationType=Cycle, int step=1, int state=0)
Definition: qtcanvas.cpp:5501
QtCanvasText::setText
void setText(const QString &)
Definition: qtcanvas.cpp:5114
QtCanvasChunk::sort
void sort()
Definition: qtcanvas.cpp:352
QtCanvas::tilesHorizontally
int tilesHorizontally() const
Definition: qtcanvas.h:257
QtCanvasItem::show
void show()
Definition: qtcanvas.cpp:2093
ScanLineListBlock
struct _ScanLineListBlock ScanLineListBlock
_EdgeTableEntry::bres
BRESINFO bres
Definition: qtcanvas.cpp:5827
QtCanvasItem::QtCanvasSprite
friend class QtCanvasSprite
Definition: qtcanvas.h:199
QtCanvasRectangle::RTTI
static int RTTI
Definition: qtcanvas.h:704
QPolygonalProcessor::bitmap
QImage bitmap
Definition: qtcanvas.cpp:4190
BRESINFO::minor
int minor
Definition: qtcanvas.cpp:5809
QtCanvasPolygonalItem::draw
void draw(QPainter &)
Definition: qtcanvas.cpp:4233
_EdgeTableEntry::back
struct _EdgeTableEntry * back
Definition: qtcanvas.cpp:5829
QtCanvasPolygonalItem::pen
QPen pen() const
Definition: qtcanvas.h:633
QtCanvasItemList
QList< QtCanvasItem * > QtCanvasItemList
Definition: qtcanvas.h:62
QtCanvasSpline::closed
bool closed() const
Definition: qtcanvas.cpp:4472
EdgeTableEntry
struct _EdgeTableEntry EdgeTableEntry
armarx::armem::server::ltm::util::mongodb::detail::update
bool update(mongocxx::collection &coll, const nlohmann::json &query, const nlohmann::json &update)
Definition: mongodb.cpp:67
qtcanvas.h
QtCanvasText::RTTI
static int RTTI
Definition: qtcanvas.h:867
QtCanvas::drawForeground
virtual void drawForeground(QPainter &, const QRect &area)
Definition: qtcanvas.cpp:1580
QtCanvasRectangle::~QtCanvasRectangle
~QtCanvasRectangle()
Definition: qtcanvas.cpp:4733
armarx::red
QColor red()
Definition: StyleSheets.h:76
EdgeTable
Definition: qtcanvas.cpp:5843
QtCanvasPolygonalItem::areaPointsAdvanced
virtual QPolygon areaPointsAdvanced() const
Definition: qtcanvas.cpp:3971
QtCanvasLine::~QtCanvasLine
~QtCanvasLine()
Definition: qtcanvas.cpp:4557
QtCanvasChunk::remove
void remove(QtCanvasItem *item)
Definition: qtcanvas.cpp:368
QtCanvasEllipse::RTTI
static int RTTI
Definition: qtcanvas.h:820
QtCanvasWidget::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *e)
Definition: qtcanvas.cpp:3515
QtCanvasWidget::wheelEvent
void wheelEvent(QWheelEvent *e)
Definition: qtcanvas.cpp:3543
QtCanvasSprite::imageAdvanced
virtual QtCanvasPixmap * imageAdvanced() const
Definition: qtcanvas.cpp:3319
QtCanvasItem::rtti
virtual int rtti() const
Definition: qtcanvas.cpp:5292
QtCanvasPolygonalItem::invalidate
void invalidate()
Definition: qtcanvas.cpp:3951
QtPolygonScanner::Left
@ Left
Definition: qtcanvas.cpp:5621
QPolygonalProcessor::add
void add(int x, int y)
Definition: qtcanvas.cpp:4013
QtCanvas::~QtCanvas
virtual ~QtCanvas()
Definition: qtcanvas.cpp:644
QtCanvasItemLess::operator()
bool operator()(const QtCanvasItem *i1, const QtCanvasItem *i2) const
Definition: qtcanvas.cpp:333
QtCanvas
Definition: qtcanvas.h:233
QtCanvasSpline::QtCanvasSpline
QtCanvasSpline(QtCanvas *canvas)
Definition: qtcanvas.cpp:4418
QtCanvasItem::z
double z() const
Definition: qtcanvas.h:81
QtCanvasText::font
QFont font() const
Definition: qtcanvas.cpp:5130
QtCanvas::backgroundPixmap
QPixmap backgroundPixmap() const
Definition: qtcanvas.cpp:1491
armarx::ctrlutil::v
double v(double t, double v0, double a0, double j)
Definition: CtrlUtil.h:39
QtCanvasView::contentsDropEvent
virtual void contentsDropEvent(QDropEvent *)
Definition: qtcanvas.cpp:3664
QtCanvasPolygonalItem::setBrush
virtual void setBrush(QBrush b)
Definition: qtcanvas.cpp:4287
QtCanvasData::animDict
QSet< QtCanvasItem * > animDict
Definition: qtcanvas.cpp:66
QtCanvasItem::animated
bool animated() const
Definition: qtcanvas.cpp:1945
QtCanvasItem::setAnimated
virtual void setAnimated(bool y)
Definition: qtcanvas.cpp:1957
QtCanvasWidget::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *e)
Definition: qtcanvas.cpp:3519
QtCanvasRectangle::areaPoints
QPolygon areaPoints() const
Definition: qtcanvas.cpp:4787
QtCanvasView::contentsWheelEvent
virtual void contentsWheelEvent(QWheelEvent *)
Definition: qtcanvas.cpp:3668
QtCanvas::addItem
virtual void addItem(QtCanvasItem *)
Definition: qtcanvas.cpp:896
QtCanvasSprite::collidesWith
bool collidesWith(const QtCanvasItem *) const
Definition: qtcanvas.cpp:2490
QtCanvasSprite::setFrame
void setFrame(int)
Definition: qtcanvas.cpp:5471
QtCanvas::drawCanvasArea
void drawCanvasArea(const QRect &, QPainter *p=0, bool double_buffer=true)
Definition: qtcanvas.cpp:1267
BRESINITPGONSTRUCT
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres)
Definition: qtcanvas.cpp:5816
QtCanvasPixmap::QtCanvasPixmap
QtCanvasPixmap(const QString &datafilename)
Definition: qtcanvas.cpp:2820
QtCanvasItem::QtCanvasRectangle
friend class QtCanvasRectangle
Definition: qtcanvas.h:200
QtCanvasClusterizer::operator[]
const QRect & operator[](int i) const
Definition: qtcanvas.cpp:322
QtCanvas::addItemToChunkContaining
void addItemToChunkContaining(QtCanvasItem *, int x, int y)
Definition: qtcanvas.cpp:1422
_ScanLineListBlock
Definition: qtcanvas.cpp:5858
QtCanvasSprite::frameCount
int frameCount() const
Definition: qtcanvas.h:556
QtCanvasEllipse::drawShape
void drawShape(QPainter &)
Definition: qtcanvas.cpp:4983
QtCanvasWidget
Definition: qtcanvas.cpp:3502
QtCanvasClusterizer
Definition: qtcanvas.cpp:80
QtCanvasLine::drawShape
void drawShape(QPainter &)
Definition: qtcanvas.cpp:4606
QtCanvasItem::setVisible
virtual void setVisible(bool yes)
Definition: qtcanvas.cpp:2109
MAXINT
#define MAXINT
Definition: qtcanvas.cpp:5968
QtCanvasSprite::boundingRect
QRect boundingRect() const
Definition: qtcanvas.cpp:3329
angle
double angle(const Point &a, const Point &b, const Point &c)
Definition: point.hpp:100
QtCanvasData::itemDict
QSet< QtCanvasItem * > itemDict
Definition: qtcanvas.cpp:65
QtCanvasPixmapArray::readPixmaps
bool readPixmaps(const QString &datafilenamepattern, int framecount=0)
Definition: qtcanvas.cpp:3037
NUMPTSTOBUFFER
#define NUMPTSTOBUFFER
Definition: qtcanvas.cpp:5868
QtCanvasSprite::topEdge
int topEdge() const
Definition: qtcanvas.cpp:3229
_ScanLineList
Definition: qtcanvas.cpp:5835
QtCanvasPixmapArray::isValid
bool isValid() const
Definition: qtcanvas.cpp:3150
QtCanvas::setUpdatePeriod
virtual void setUpdatePeriod(int ms)
Definition: qtcanvas.cpp:995
QtCanvasItem::setSelected
virtual void setSelected(bool yes)
Definition: qtcanvas.cpp:2168
_ScanLineList::scanline
int scanline
Definition: qtcanvas.cpp:5837
QtCanvasSprite::rtti
int rtti() const
Definition: qtcanvas.cpp:5303
QtCanvas::tile
int tile(int x, int y) const
Definition: qtcanvas.h:252
QtCanvasSprite::image
QtCanvasPixmap * image() const
Definition: qtcanvas.h:583
QtCanvasView
Definition: qtcanvas.h:401
QtCanvas::setAllChanged
virtual void setAllChanged()
Definition: qtcanvas.cpp:1115
QtCanvasLine::setPen
void setPen(QPen p)
Definition: qtcanvas.cpp:4565
QtCanvasView::worldMatrix
const QMatrix & worldMatrix() const
Definition: qtcanvas.cpp:3724
QtCanvasItem::xVelocity
double xVelocity() const
Definition: qtcanvas.cpp:2013
QtCanvasPolygon::rtti
int rtti() const
Definition: qtcanvas.cpp:5336
QtCanvas::addAnimation
virtual void addAnimation(QtCanvasItem *)
Definition: qtcanvas.cpp:906
QtCanvasEllipse
Definition: qtcanvas.h:792
QPolygonalProcessor::result
QPolygon result
Definition: qtcanvas.cpp:4187
QtPolygonScanner::Bottom
@ Bottom
Definition: qtcanvas.cpp:5621
QtCanvasPolygonScanner::processSpans
void processSpans(int n, QPoint *point, int *width)
Definition: qtcanvas.cpp:6591
QtCanvasWidget::dragLeaveEvent
void dragLeaveEvent(QDragLeaveEvent *e)
Definition: qtcanvas.cpp:3535
QtCanvasView::canvas
QtCanvas * canvas() const
Definition: qtcanvas.h:411
QtCanvasPolygonalItem::collidesWith
bool collidesWith(const QtCanvasItem *) const
Definition: qtcanvas.cpp:2513
QtCanvasPolygonalItem::rtti
int rtti() const
Definition: qtcanvas.cpp:5314
QtCanvasItem::~QtCanvasItem
virtual ~QtCanvasItem()
Definition: qtcanvas.cpp:1846
QtCanvasEllipse::height
int height() const
Definition: qtcanvas.cpp:4909
QtPolygonScanner::Edge
Edge
Definition: qtcanvas.cpp:5621
QtCanvasText::setTextFlags
void setTextFlags(int)
Definition: qtcanvas.cpp:5087
QtCanvasPolygonalItem::winding
bool winding() const
Definition: qtcanvas.cpp:3925
QtCanvas::removeView
virtual void removeView(QtCanvasView *)
Definition: qtcanvas.cpp:954
QtCanvasText::moveBy
void moveBy(double dx, double dy)
Definition: qtcanvas.cpp:5176
QtCanvasRectangle::chunks
QPolygon chunks() const
Definition: qtcanvas.cpp:4213
QtCanvasSprite
Definition: qtcanvas.h:538
QtCanvasText
Definition: qtcanvas.h:838
QtCanvasPolygon::areaPoints
QPolygon areaPoints() const
Definition: qtcanvas.cpp:4524
QtCanvasWidget::dropEvent
void dropEvent(QDropEvent *e)
Definition: qtcanvas.cpp:3539
QPolygonalProcessor::doSpans
void doSpans(int n, QPoint *pt, int *w)
Definition: qtcanvas.cpp:4059
QtCanvasItem::move
void move(double x, double y)
Definition: qtcanvas.cpp:1933
QtCanvasPolygon::points
QPolygon points() const
Definition: qtcanvas.cpp:4511
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
QtCanvasItem::collisions
QtCanvasItemList collisions(bool exact) const
Definition: qtcanvas.cpp:2617
QtCanvasWidget::dragEnterEvent
void dragEnterEvent(QDragEnterEvent *e)
Definition: qtcanvas.cpp:3527
QtCanvasText::draw
virtual void draw(QPainter &)
Definition: qtcanvas.cpp:5199
QtCanvasView::QtCanvasView
QtCanvasView(QWidget *parent=0)
Definition: qtcanvas.cpp:3573
QtCanvas::tilesVertically
int tilesVertically() const
Definition: qtcanvas.h:261
QtCanvasData::QtCanvasData
QtCanvasData()
Definition: qtcanvas.cpp:60
QtCanvasPolygonScanner::QtCanvasPolygonScanner
QtCanvasPolygonScanner(QPolygonalProcessor &p)
Definition: qtcanvas.cpp:6587
QtCanvasText::~QtCanvasText
virtual ~QtCanvasText()
Definition: qtcanvas.cpp:5053
QtCanvasPixmap::~QtCanvasPixmap
~QtCanvasPixmap()
Definition: qtcanvas.cpp:2880
QtCanvasPolygon::drawShape
void drawShape(QPainter &)
Definition: qtcanvas.cpp:4339
QtCanvasClusterizer::clusters
int clusters() const
Definition: qtcanvas.cpp:91
QtPolygonScanner::scan
void scan(const QPolygon &pa, bool winding, int index=0, int npoints=-1)
Definition: qtcanvas.cpp:6355
QtCanvasSprite::draw
void draw(QPainter &painter)
Definition: qtcanvas.cpp:3438
QtCanvas::retune
virtual void retune(int chunksize, int maxclusters=100)
Definition: qtcanvas.cpp:776
cxxopts::minor
uint8_t minor
Definition: cxxopts.hpp:54
QtCanvas::setAdvancePeriod
virtual void setAdvancePeriod(int ms)
Definition: qtcanvas.cpp:966
QtCanvasView::~QtCanvasView
~QtCanvasView()
Definition: qtcanvas.cpp:3602
QtPolygonScanner::~QtPolygonScanner
virtual ~QtPolygonScanner()
Definition: qtcanvas.cpp:5618
armarx::green
QColor green()
Definition: StyleSheets.h:72
armarx::control::common::MPStatus::reset
@ reset
EdgeTable::scanlines
ScanLineList scanlines
Definition: qtcanvas.cpp:5847
QtCanvasItem::QtCanvasPolygon
friend class QtCanvasPolygon
Definition: qtcanvas.h:201
QtCanvasPixmapArray::QtCanvasPixmapArray
QtCanvasPixmapArray()
Definition: qtcanvas.cpp:2938
BRESINFO
Definition: qtcanvas.cpp:5807
QtCanvasSprite::bottomEdge
int bottomEdge() const
Definition: qtcanvas.cpp:3281
QtCanvasPolygon::RTTI
static int RTTI
Definition: qtcanvas.h:733
QtCanvasSprite::setSequence
void setSequence(QtCanvasPixmapArray *seq)
Definition: qtcanvas.cpp:5411