/src/gui/graphicsview/qgraphicsscene_bsp.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 296 lines · 216 code · 39 blank · 41 comment · 37 complexity · 8c13a971d0522a2caea8d6ec30ea3a7e MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the QtGui module of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qgraphicsscene_bsp_p.h"
  42. #ifndef QT_NO_GRAPHICSVIEW
  43. #include <QtCore/qstring.h>
  44. #include <private/qgraphicsitem_p.h>
  45. QT_BEGIN_NAMESPACE
  46. class QGraphicsSceneInsertItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
  47. {
  48. public:
  49. QGraphicsItem *item;
  50. void visit(QList<QGraphicsItem *> *items)
  51. { items->prepend(item); }
  52. };
  53. class QGraphicsSceneRemoveItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
  54. {
  55. public:
  56. QGraphicsItem *item;
  57. void visit(QList<QGraphicsItem *> *items)
  58. { items->removeAll(item); }
  59. };
  60. class QGraphicsSceneFindItemBspTreeVisitor : public QGraphicsSceneBspTreeVisitor
  61. {
  62. public:
  63. QList<QGraphicsItem *> *foundItems;
  64. bool onlyTopLevelItems;
  65. void visit(QList<QGraphicsItem *> *items)
  66. {
  67. for (int i = 0; i < items->size(); ++i) {
  68. QGraphicsItem *item = items->at(i);
  69. if (onlyTopLevelItems && item->d_ptr->parent)
  70. item = item->topLevelItem();
  71. if (!item->d_func()->itemDiscovered && item->d_ptr->visible) {
  72. item->d_func()->itemDiscovered = 1;
  73. foundItems->prepend(item);
  74. }
  75. }
  76. }
  77. };
  78. QGraphicsSceneBspTree::QGraphicsSceneBspTree()
  79. : leafCnt(0)
  80. {
  81. insertVisitor = new QGraphicsSceneInsertItemBspTreeVisitor;
  82. removeVisitor = new QGraphicsSceneRemoveItemBspTreeVisitor;
  83. findVisitor = new QGraphicsSceneFindItemBspTreeVisitor;
  84. }
  85. QGraphicsSceneBspTree::~QGraphicsSceneBspTree()
  86. {
  87. delete insertVisitor;
  88. delete removeVisitor;
  89. delete findVisitor;
  90. }
  91. void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth)
  92. {
  93. this->rect = rect;
  94. leafCnt = 0;
  95. nodes.resize((1 << (depth + 1)) - 1);
  96. nodes.fill(Node());
  97. leaves.resize(1 << depth);
  98. leaves.fill(QList<QGraphicsItem *>());
  99. initialize(rect, depth, 0);
  100. }
  101. void QGraphicsSceneBspTree::clear()
  102. {
  103. leafCnt = 0;
  104. nodes.clear();
  105. leaves.clear();
  106. }
  107. void QGraphicsSceneBspTree::insertItem(QGraphicsItem *item, const QRectF &rect)
  108. {
  109. insertVisitor->item = item;
  110. climbTree(insertVisitor, rect);
  111. }
  112. void QGraphicsSceneBspTree::removeItem(QGraphicsItem *item, const QRectF &rect)
  113. {
  114. removeVisitor->item = item;
  115. climbTree(removeVisitor, rect);
  116. }
  117. void QGraphicsSceneBspTree::removeItems(const QSet<QGraphicsItem *> &items)
  118. {
  119. for (int i = 0; i < leaves.size(); ++i) {
  120. QList<QGraphicsItem *> newItemList;
  121. const QList<QGraphicsItem *> &oldItemList = leaves[i];
  122. for (int j = 0; j < oldItemList.size(); ++j) {
  123. QGraphicsItem *item = oldItemList.at(j);
  124. if (!items.contains(item))
  125. newItemList << item;
  126. }
  127. leaves[i] = newItemList;
  128. }
  129. }
  130. QList<QGraphicsItem *> QGraphicsSceneBspTree::items(const QRectF &rect, bool onlyTopLevelItems) const
  131. {
  132. QList<QGraphicsItem *> tmp;
  133. findVisitor->foundItems = &tmp;
  134. findVisitor->onlyTopLevelItems = onlyTopLevelItems;
  135. climbTree(findVisitor, rect);
  136. // Reset discovery bits.
  137. for (int i = 0; i < tmp.size(); ++i)
  138. tmp.at(i)->d_ptr->itemDiscovered = 0;
  139. return tmp;
  140. }
  141. int QGraphicsSceneBspTree::leafCount() const
  142. {
  143. return leafCnt;
  144. }
  145. QString QGraphicsSceneBspTree::debug(int index) const
  146. {
  147. const Node *node = &nodes.at(index);
  148. QString tmp;
  149. if (node->type == Node::Leaf) {
  150. QRectF rect = rectForIndex(index);
  151. if (!leaves[node->leafIndex].isEmpty()) {
  152. tmp += QString::fromLatin1("[%1, %2, %3, %4] contains %5 items\n")
  153. .arg(rect.left()).arg(rect.top())
  154. .arg(rect.width()).arg(rect.height())
  155. .arg(leaves[node->leafIndex].size());
  156. }
  157. } else {
  158. if (node->type == Node::Horizontal) {
  159. tmp += debug(firstChildIndex(index));
  160. tmp += debug(firstChildIndex(index) + 1);
  161. } else {
  162. tmp += debug(firstChildIndex(index));
  163. tmp += debug(firstChildIndex(index) + 1);
  164. }
  165. }
  166. return tmp;
  167. }
  168. void QGraphicsSceneBspTree::initialize(const QRectF &rect, int depth, int index)
  169. {
  170. Node *node = &nodes[index];
  171. if (index == 0) {
  172. node->type = Node::Horizontal;
  173. node->offset = rect.center().x();
  174. }
  175. if (depth) {
  176. Node::Type type;
  177. QRectF rect1, rect2;
  178. qreal offset1, offset2;
  179. if (node->type == Node::Horizontal) {
  180. type = Node::Vertical;
  181. rect1.setRect(rect.left(), rect.top(), rect.width(), rect.height() / 2);
  182. rect2.setRect(rect1.left(), rect1.bottom(), rect1.width(), rect.height() - rect1.height());
  183. offset1 = rect1.center().x();
  184. offset2 = rect2.center().x();
  185. } else {
  186. type = Node::Horizontal;
  187. rect1.setRect(rect.left(), rect.top(), rect.width() / 2, rect.height());
  188. rect2.setRect(rect1.right(), rect1.top(), rect.width() - rect1.width(), rect1.height());
  189. offset1 = rect1.center().y();
  190. offset2 = rect2.center().y();
  191. }
  192. int childIndex = firstChildIndex(index);
  193. Node *child = &nodes[childIndex];
  194. child->offset = offset1;
  195. child->type = type;
  196. child = &nodes[childIndex + 1];
  197. child->offset = offset2;
  198. child->type = type;
  199. initialize(rect1, depth - 1, childIndex);
  200. initialize(rect2, depth - 1, childIndex + 1);
  201. } else {
  202. node->type = Node::Leaf;
  203. node->leafIndex = leafCnt++;
  204. }
  205. }
  206. void QGraphicsSceneBspTree::climbTree(QGraphicsSceneBspTreeVisitor *visitor, const QRectF &rect, int index) const
  207. {
  208. if (nodes.isEmpty())
  209. return;
  210. const Node &node = nodes.at(index);
  211. const int childIndex = firstChildIndex(index);
  212. switch (node.type) {
  213. case Node::Leaf: {
  214. visitor->visit(const_cast<QList<QGraphicsItem*>*>(&leaves[node.leafIndex]));
  215. break;
  216. }
  217. case Node::Vertical:
  218. if (rect.left() < node.offset) {
  219. climbTree(visitor, rect, childIndex);
  220. if (rect.right() >= node.offset)
  221. climbTree(visitor, rect, childIndex + 1);
  222. } else {
  223. climbTree(visitor, rect, childIndex + 1);
  224. }
  225. break;
  226. case Node::Horizontal:
  227. if (rect.top() < node.offset) {
  228. climbTree(visitor, rect, childIndex);
  229. if (rect.bottom() >= node.offset)
  230. climbTree(visitor, rect, childIndex + 1);
  231. } else {
  232. climbTree(visitor, rect, childIndex + 1);
  233. }
  234. }
  235. }
  236. QRectF QGraphicsSceneBspTree::rectForIndex(int index) const
  237. {
  238. if (index <= 0)
  239. return rect;
  240. int parentIdx = parentIndex(index);
  241. QRectF rect = rectForIndex(parentIdx);
  242. const Node *parent = &nodes.at(parentIdx);
  243. if (parent->type == Node::Horizontal) {
  244. if (index & 1)
  245. rect.setRight(parent->offset);
  246. else
  247. rect.setLeft(parent->offset);
  248. } else {
  249. if (index & 1)
  250. rect.setBottom(parent->offset);
  251. else
  252. rect.setTop(parent->offset);
  253. }
  254. return rect;
  255. }
  256. QT_END_NAMESPACE
  257. #endif // QT_NO_GRAPHICSVIEW