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}