001package com.fs.starfarer.api.util; 002import java.util.ArrayList; 003import java.util.Iterator; 004import java.util.LinkedHashSet; 005import java.util.List; 006import java.util.Set; 007 008import org.lwjgl.util.vector.Vector2f; 009 010import com.fs.starfarer.api.combat.CollisionGridAPI; 011 012 013public class CollisionGridUtil implements CollisionGridAPI { 014 015 protected class BucketIterator implements Iterator<Object> { 016 protected Iterator<Object> curr = null; 017 protected Set<Object> objects; 018 protected BucketIterator() { 019 } 020 protected BucketIterator(int startX, int endX, int startY, int endY) { 021 objects = new LinkedHashSet<Object>(); 022 if (startX < 0) startX = 0; 023 if (endX >= width) endX = width - 1; 024 if (startY < 0) startY = 0; 025 if (endY >= height) endY = height - 1; 026 027 for (int i = startX; i <= endX; i++) { 028 for (int j = startY; j <= endY; j++) { 029 if (buckets[i][j] == null) continue; 030 objects.addAll(buckets[i][j]); 031 } 032 } 033 curr = objects.iterator(); 034 } 035 public BucketIterator createCopy() { 036 BucketIterator copy = new BucketIterator(); 037 copy.objects = objects; 038 copy.curr = copy.objects.iterator(); 039 return copy; 040 } 041 public boolean hasNext() { 042 return curr.hasNext(); 043 } 044 public Object next() { 045 return curr.next(); 046 } 047 public void remove() { 048 throw new UnsupportedOperationException(); 049 } 050 } 051 052 053 protected float cellSize; 054 protected List<Object>[][] buckets; 055 056 protected int width, height, leftOf, rightOf, below, above; 057 058 @SuppressWarnings("unchecked") 059 public CollisionGridUtil(float minX, float maxX, float minY, float maxY, float cellSize) { 060 this.cellSize = cellSize; 061 062 leftOf = -(int) Math.floor(minX / cellSize); 063 rightOf = (int) Math.ceil(maxX / cellSize); 064 below = -(int) Math.floor(minY / cellSize); 065 above = (int) Math.ceil(maxY / cellSize); 066 067 width = leftOf + rightOf; 068 height = below + above; 069 buckets = new List[width][height]; 070 } 071 072 public void addObject(Object object, Vector2f loc, float objWidth, float objHeight) { 073 int startX = (int) (leftOf + ((loc.x - objWidth/2f) / cellSize)); 074 int endX = (int) (leftOf + (loc.x + objWidth/2f) / cellSize); 075 076 int startY = (int) (below + ((loc.y - objHeight/2f) / cellSize)); 077 int endY = (int) (below + (loc.y + objHeight/2f) / cellSize); 078 079 int limit = Integer.MAX_VALUE / 2; 080 if (startX > limit) startX = limit; 081 if (endX > limit) endX = limit; 082 if (startY > limit) startY = limit; 083 if (endY > limit) endY = limit; 084 085 if (startX < -limit) startX = -limit; 086 if (endX < -limit) endX = -limit; 087 if (startY < -limit) startY = -limit; 088 if (endY < -limit) endY = -limit; 089 090 for (int i = startX; i <= endX; i++) { 091 for (int j = startY; j <= endY; j++) { 092 addToBucket(i, j, object); 093 } 094 } 095 } 096 097 public void removeObject(Object object, Vector2f loc, float objWidth, float objHeight) { 098 int startX = (int) (leftOf + ((loc.x - objWidth/2f) / cellSize)); 099 int endX = (int) (leftOf + (loc.x + objWidth/2f) / cellSize); 100 101 int startY = (int) (below + ((loc.y - objHeight/2f) / cellSize)); 102 int endY = (int) (below + (loc.y + objHeight/2f) / cellSize); 103 for (int i = startX; i <= endX; i++) { 104 for (int j = startY; j <= endY; j++) { 105 removeFromBucket(i, j, object); 106 } 107 } 108 } 109 110 protected void addToBucket(int cellX, int cellY, Object object) { 111 if (cellX < 0 || cellX >= width || cellY < 0 || cellY >= height) return; 112 if(buckets[cellX][cellY] == null) { 113 buckets[cellX][cellY] = new ArrayList<Object>(); 114 } 115 if (!buckets[cellX][cellY].contains(object)) { 116 buckets[cellX][cellY].add(object); 117 } 118 } 119 120 protected void removeFromBucket(int cellX, int cellY, Object object) { 121 if (cellX < 0 || cellX >= width || cellY < 0 || cellY >= height) return; 122 if(buckets[cellX][cellY] == null) return; 123 buckets[cellX][cellY].remove(object); 124 } 125 126 public Iterator<Object> getCheckIterator(Vector2f loc, float objWidth, float objHeight) { 127 int startX = (int) (leftOf + ((loc.x - objWidth/2f) / cellSize)); 128 //int endX = (int) (leftOf + Math.ceil((loc.x + objWidth/2f) / cellSize)); 129 int endX = (int) (leftOf + (loc.x + objWidth/2f) / cellSize); 130 131 int startY = (int) (below + ((loc.y - objHeight/2f) / cellSize)); 132 //int endY = (int) (below + Math.ceil((loc.y + objHeight/2f) / cellSize)); 133 int endY = (int) (below + (loc.y + objHeight/2f) / cellSize); 134 135 BucketIterator result = new BucketIterator(startX, endX, startY, endY); 136 return result; 137 } 138 139 140}