PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/andengine/util/spatial/quadtree/IntQuadTree.java

https://bitbucket.org/cng1985/andengine
Java | 431 lines | 312 code | 71 blank | 48 comment | 12 complexity | 4445edfe9dbc6fb686f5f099aa800546 MD5 | raw file
  1. package org.andengine.util.spatial.quadtree;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.andengine.util.IMatcher;
  5. import org.andengine.util.spatial.ISpatialItem;
  6. import org.andengine.util.spatial.adt.bounds.BoundsSplit;
  7. import org.andengine.util.spatial.adt.bounds.BoundsSplit.BoundsSplitException;
  8. import org.andengine.util.spatial.adt.bounds.IIntBounds;
  9. import org.andengine.util.spatial.adt.bounds.IntBounds;
  10. import org.andengine.util.spatial.adt.bounds.util.IntBoundsUtils;
  11. /**
  12. * (c) Zynga 2011
  13. *
  14. * @author Nicolas Gramlich <ngramlich@zynga.com>
  15. * @since 20:22:18 - 10.10.2011
  16. */
  17. public class IntQuadTree<T extends ISpatialItem<IIntBounds>> extends QuadTree<IIntBounds, T> implements IIntBounds {
  18. // ===========================================================
  19. // Constants
  20. // ===========================================================
  21. // ===========================================================
  22. // Fields
  23. // ===========================================================
  24. private final IntBounds mQueryIntBounds = new IntBounds(0, 0, 0, 0);
  25. // ===========================================================
  26. // Constructors
  27. // ===========================================================
  28. public IntQuadTree(final IIntBounds pIntBounds) {
  29. super(pIntBounds);
  30. }
  31. public IntQuadTree(final IIntBounds pIntBounds, final int pMaxLevel) {
  32. super(pIntBounds, pMaxLevel);
  33. }
  34. @Override
  35. protected IntQuadTreeNode initRoot(final IIntBounds pIntBounds) {
  36. return new IntQuadTreeNode(QuadTree.LEVEL_ROOT, pIntBounds);
  37. }
  38. // ===========================================================
  39. // Getter & Setter
  40. // ===========================================================
  41. @Override
  42. public int getXMin() {
  43. return this.getRoot().getXMin();
  44. }
  45. @Override
  46. public int getYMin() {
  47. return this.getRoot().getYMin();
  48. }
  49. @Override
  50. public int getXMax() {
  51. return this.getRoot().getXMax();
  52. }
  53. @Override
  54. public int getYMax() {
  55. return this.getRoot().getYMax();
  56. }
  57. // ===========================================================
  58. // Methods for/from SuperClass/Interfaces
  59. // ===========================================================
  60. @SuppressWarnings("unchecked")
  61. @Override
  62. protected IntQuadTreeNode getRoot() {
  63. return (IntQuadTreeNode) this.mRoot;
  64. }
  65. // ===========================================================
  66. // Methods
  67. // ===========================================================
  68. public synchronized ArrayList<T> query(final int pX, final int pY) {
  69. this.mQueryIntBounds.set(pX, pY);
  70. return this.query(this.mQueryIntBounds);
  71. }
  72. public synchronized <L extends List<T>> L query(final int pX, final int pY, final L pResult) {
  73. this.mQueryIntBounds.set(pX, pY);
  74. return this.query(this.mQueryIntBounds, pResult);
  75. }
  76. public synchronized ArrayList<T> query(final int pX, final int pY, final IMatcher<T> pMatcher) {
  77. this.mQueryIntBounds.set(pX, pY);
  78. return this.query(this.mQueryIntBounds, pMatcher);
  79. }
  80. public synchronized <L extends List<T>> L query(final int pX, final int pY, final IMatcher<T> pMatcher, final L pResult) {
  81. this.mQueryIntBounds.set(pX, pY);
  82. return this.query(this.mQueryIntBounds, pMatcher, pResult);
  83. }
  84. public synchronized ArrayList<T> query(final int pXMin, final int pYMin, final int pXMax, final int pYMax) {
  85. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  86. return this.query(this.mQueryIntBounds);
  87. }
  88. public synchronized <L extends List<T>> L query(final int pXMin, final int pYMin, final int pXMax, final int pYMax, final L pResult) {
  89. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  90. return this.query(this.mQueryIntBounds, pResult);
  91. }
  92. public synchronized ArrayList<T> query(final int pXMin, final int pYMin, final int pXMax, final int pYMax, final IMatcher<T> pMatcher) {
  93. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  94. return this.query(this.mQueryIntBounds, pMatcher);
  95. }
  96. public synchronized <L extends List<T>> L query(final int pXMin, final int pYMin, final int pXMax, final int pYMax, final IMatcher<T> pMatcher, final L pResult) {
  97. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  98. return this.query(this.mQueryIntBounds, pMatcher, pResult);
  99. }
  100. public synchronized <L extends List<S>, S extends T> L queryForSubclass(final int pX, final int pY, final IMatcher<T> pMatcher, final L pResult) throws ClassCastException {
  101. this.mQueryIntBounds.set(pX, pY);
  102. return this.queryForSubclass(this.mQueryIntBounds, pMatcher, pResult);
  103. }
  104. public synchronized <L extends List<S>, S extends T> L queryForSubclass(final int pXMin, final int pYMin, final int pXMax, final int pYMax, final IMatcher<T> pMatcher, final L pResult) throws ClassCastException {
  105. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  106. return this.queryForSubclass(this.mQueryIntBounds, pMatcher, pResult);
  107. }
  108. public synchronized boolean containsAny(final int pX, final int pY) {
  109. this.mQueryIntBounds.set(pX, pY);
  110. return this.containsAny(this.mQueryIntBounds);
  111. }
  112. public synchronized boolean containsAny(final int pXMin, final int pYMin, final int pXMax, final int pYMax) {
  113. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  114. return this.containsAny(this.mQueryIntBounds);
  115. }
  116. public synchronized boolean containsAny(final int pX, final int pY, final IMatcher<T> pMatcher) {
  117. this.mQueryIntBounds.set(pX, pY);
  118. return this.containsAny(this.mQueryIntBounds, pMatcher);
  119. }
  120. public synchronized boolean containsAny(final int pXMin, final int pYMin, final int pXMax, final int pYMax, final IMatcher<T> pMatcher) {
  121. this.mQueryIntBounds.set(pXMin, pYMin, pXMax, pYMax);
  122. return this.containsAny(this.mQueryIntBounds, pMatcher);
  123. }
  124. // ===========================================================
  125. // Inner and Anonymous Classes
  126. // ===========================================================
  127. public class IntQuadTreeNode extends QuadTreeNode implements IIntBounds {
  128. // ===========================================================
  129. // Constants
  130. // ===========================================================
  131. // ===========================================================
  132. // Fields
  133. // ===========================================================
  134. private final int mXMin;
  135. private final int mYMin;
  136. private final int mXMax;
  137. private final int mYMax;
  138. // ===========================================================
  139. // Constructors
  140. // ===========================================================
  141. public IntQuadTreeNode(final int pLevel, final IIntBounds pIntBounds) {
  142. this(pLevel, pIntBounds.getXMin(), pIntBounds.getYMin(), pIntBounds.getXMax(), pIntBounds.getYMax());
  143. }
  144. public IntQuadTreeNode(final int pLevel, final int pXMin, final int pYMin, final int pXMax, final int pYMax) {
  145. super(pLevel);
  146. this.mXMin = pXMin;
  147. this.mYMin = pYMin;
  148. this.mXMax = pXMax;
  149. this.mYMax = pYMax;
  150. if(pXMin > pXMax) {
  151. throw new IllegalArgumentException("pXMin must be smaller or equal to pXMax.");
  152. }
  153. if(pYMin > pYMax) {
  154. throw new IllegalArgumentException("pYMin must be smaller or equal to pYMax.");
  155. }
  156. }
  157. // ===========================================================
  158. // Getter & Setter
  159. // ===========================================================
  160. @Override
  161. public int getXMin() {
  162. return this.mXMin;
  163. }
  164. @Override
  165. public int getYMin() {
  166. return this.mYMin;
  167. }
  168. @Override
  169. public int getXMax() {
  170. return this.mXMax;
  171. }
  172. @Override
  173. public int getYMax() {
  174. return this.mYMax;
  175. }
  176. public int getWidth() {
  177. return this.mXMax - this.mXMin + 1;
  178. }
  179. public int getHeight() {
  180. return this.mYMax - this.mYMin + 1;
  181. }
  182. // ===========================================================
  183. // Methods for/from SuperClass/Interfaces
  184. // ===========================================================
  185. @Override
  186. protected IntQuadTreeNode split(final BoundsSplit pBoundsSplit) {
  187. final int width = this.getWidth();
  188. final int height = this.getHeight();
  189. if(width <= 2 && height <= 2) {
  190. throw new BoundsSplitException();
  191. }
  192. final int xMin = this.getXMin(pBoundsSplit);
  193. final int yMin = this.getYMin(pBoundsSplit);
  194. final int xMax = this.getXMax(pBoundsSplit);
  195. final int yMax = this.getYMax(pBoundsSplit);
  196. return new IntQuadTreeNode(this.mLevel + 1, xMin, yMin, xMax, yMax);
  197. }
  198. @Override
  199. protected boolean contains(final IIntBounds pIntBounds) {
  200. return this.contains(pIntBounds.getXMin(), pIntBounds.getYMin(), pIntBounds.getXMax(), pIntBounds.getYMax());
  201. }
  202. @Override
  203. protected boolean contains(final BoundsSplit pBoundsSplit, final IIntBounds pIntBounds) {
  204. return IntBoundsUtils.contains(this.getXMin(pBoundsSplit), this.getYMin(pBoundsSplit), this.getXMax(pBoundsSplit), this.getYMax(pBoundsSplit), pIntBounds.getXMin(), pIntBounds.getYMin(), pIntBounds.getXMax(), pIntBounds.getYMax());
  205. }
  206. @Override
  207. protected boolean intersects(final IIntBounds pIntBounds) {
  208. return IntBoundsUtils.intersects(this.mXMin, this.mYMin, this.mXMax, this.mYMax, pIntBounds.getXMin(), pIntBounds.getYMin(), pIntBounds.getXMax(), pIntBounds.getYMax());
  209. }
  210. @Override
  211. protected boolean intersects(final IIntBounds pIntBoundsA, final IIntBounds pIntBoundsB) {
  212. return IntBoundsUtils.intersects(pIntBoundsA, pIntBoundsB);
  213. }
  214. @Override
  215. protected boolean containedBy(final IIntBounds pBounds) {
  216. return IntBoundsUtils.contains(pBounds.getXMin(), pBounds.getYMin(), pBounds.getXMax(), pBounds.getYMax(), this.mXMin, this.mYMin, this.mXMax, this.mYMax);
  217. }
  218. @Override
  219. protected void appendBoundsToString(final StringBuilder pStringBuilder) {
  220. pStringBuilder
  221. .append("[XMin: ")
  222. .append(this.mXMin)
  223. .append(", YMin: ")
  224. .append(this.mYMin)
  225. .append(", XMax: ")
  226. .append(this.mXMax)
  227. .append(", YMax: ")
  228. .append(this.mYMax)
  229. .append("]");
  230. }
  231. // ===========================================================
  232. // Methods
  233. // ===========================================================
  234. private int getXMin(final BoundsSplit pBoundsSplit) {
  235. final int width = this.getWidth();
  236. final int halfWidth = width / 2;
  237. if(width <= 2) {
  238. switch(pBoundsSplit) {
  239. case TOP_LEFT:
  240. case BOTTOM_LEFT:
  241. return this.mXMin;
  242. case BOTTOM_RIGHT:
  243. case TOP_RIGHT:
  244. throw new BoundsSplitException();
  245. default:
  246. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  247. }
  248. } else {
  249. switch(pBoundsSplit) {
  250. case TOP_LEFT:
  251. return this.mXMin;
  252. case TOP_RIGHT:
  253. return this.mXMin + halfWidth;
  254. case BOTTOM_LEFT:
  255. return this.mXMin;
  256. case BOTTOM_RIGHT:
  257. return this.mXMin + halfWidth;
  258. default:
  259. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  260. }
  261. }
  262. }
  263. private int getYMin(final BoundsSplit pBoundsSplit) {
  264. final int height = this.getHeight();
  265. final int halfHeight = height / 2;
  266. if(height <= 2) {
  267. switch(pBoundsSplit) {
  268. case TOP_LEFT:
  269. case TOP_RIGHT:
  270. return this.mYMin;
  271. case BOTTOM_LEFT:
  272. case BOTTOM_RIGHT:
  273. throw new BoundsSplitException();
  274. default:
  275. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  276. }
  277. } else {
  278. switch(pBoundsSplit) {
  279. case TOP_LEFT:
  280. return this.mYMin;
  281. case TOP_RIGHT:
  282. return this.mYMin;
  283. case BOTTOM_LEFT:
  284. return this.mYMin + halfHeight;
  285. case BOTTOM_RIGHT:
  286. return this.mYMin + halfHeight;
  287. default:
  288. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  289. }
  290. }
  291. }
  292. private int getXMax(final BoundsSplit pBoundsSplit) {
  293. final int width = this.getWidth();
  294. final int halfWidth = width / 2;
  295. if(width <= 2) {
  296. switch(pBoundsSplit) {
  297. case TOP_LEFT:
  298. case BOTTOM_LEFT:
  299. return this.mXMax;
  300. case BOTTOM_RIGHT:
  301. case TOP_RIGHT:
  302. throw new BoundsSplitException();
  303. default:
  304. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  305. }
  306. } else {
  307. switch(pBoundsSplit) {
  308. case TOP_LEFT:
  309. return this.mXMin + halfWidth;
  310. case TOP_RIGHT:
  311. return this.mXMax;
  312. case BOTTOM_LEFT:
  313. return this.mXMin + halfWidth;
  314. case BOTTOM_RIGHT:
  315. return this.mXMax;
  316. default:
  317. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  318. }
  319. }
  320. }
  321. private int getYMax(final BoundsSplit pBoundsSplit) {
  322. final int height = this.getHeight();
  323. final int halfHeight = height / 2;
  324. if(height <= 2) {
  325. switch(pBoundsSplit) {
  326. case TOP_LEFT:
  327. case TOP_RIGHT:
  328. return this.mYMax;
  329. case BOTTOM_LEFT:
  330. case BOTTOM_RIGHT:
  331. throw new BoundsSplitException();
  332. default:
  333. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  334. }
  335. } else {
  336. switch(pBoundsSplit) {
  337. case TOP_LEFT:
  338. return this.mYMin + halfHeight;
  339. case TOP_RIGHT:
  340. return this.mYMin + halfHeight;
  341. case BOTTOM_LEFT:
  342. return this.mYMax;
  343. case BOTTOM_RIGHT:
  344. return this.mYMax;
  345. default:
  346. throw new IllegalArgumentException("Unexpected " + BoundsSplit.class.getSimpleName() + ": '" + pBoundsSplit + "'.");
  347. }
  348. }
  349. }
  350. public boolean intersects(final int pXMin, final int pYMin, final int pXMax, final int pYMax) {
  351. return IntBoundsUtils.intersects(this.mXMin, this.mYMin, this.mXMax, this.mYMax, pXMin, pYMin, pXMax, pYMax);
  352. }
  353. public boolean contains(final int pXMin, final int pYMin, final int pXMax, final int pYMax) {
  354. return IntBoundsUtils.contains(this.mXMin, this.mYMin, this.mXMax, this.mYMax, pXMin, pYMin, pXMax, pYMax);
  355. }
  356. // ===========================================================
  357. // Inner and Anonymous Classes
  358. // ===========================================================
  359. }
  360. }