1 /* Copyright (c) 2013 Scott Lembcke and Howling Moon Software
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 #include "chipmunk/chipmunk_private.h"
24 static inline cpSpatialIndexClass *Klass();
26 //MARK: Basic Structures
28 typedef struct Bounds {
32 typedef struct TableCell {
39 cpSpatialIndex spatialIndex;
47 BoundsOverlap(Bounds a, Bounds b)
49 return (a.min <= b.max && b.min <= a.max);
53 BBToBounds(cpSweep1D *sweep, cpBB bb)
55 Bounds bounds = {bb.l, bb.r};
59 static inline TableCell
60 MakeTableCell(cpSweep1D *sweep, void *obj)
62 TableCell cell = {obj, BBToBounds(sweep, sweep->spatialIndex.bbfunc(obj))};
66 //MARK: Memory Management Functions
71 return (cpSweep1D *)cpcalloc(1, sizeof(cpSweep1D));
75 ResizeTable(cpSweep1D *sweep, int size)
78 sweep->table = (TableCell *)cprealloc(sweep->table, size*sizeof(TableCell));
82 cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)
84 cpSpatialIndexInit((cpSpatialIndex *)sweep, Klass(), bbfunc, staticIndex);
87 ResizeTable(sweep, 32);
89 return (cpSpatialIndex *)sweep;
93 cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)
95 return cpSweep1DInit(cpSweep1DAlloc(), bbfunc, staticIndex);
99 cpSweep1DDestroy(cpSweep1D *sweep)
101 cpfree(sweep->table);
108 cpSweep1DCount(cpSweep1D *sweep)
114 cpSweep1DEach(cpSweep1D *sweep, cpSpatialIndexIteratorFunc func, void *data)
116 TableCell *table = sweep->table;
117 for(int i=0, count=sweep->num; i<count; i++) func(table[i].obj, data);
121 cpSweep1DContains(cpSweep1D *sweep, void *obj, cpHashValue hashid)
123 TableCell *table = sweep->table;
124 for(int i=0, count=sweep->num; i<count; i++){
125 if(table[i].obj == obj) return cpTrue;
131 //MARK: Basic Operations
134 cpSweep1DInsert(cpSweep1D *sweep, void *obj, cpHashValue hashid)
136 if(sweep->num == sweep->max) ResizeTable(sweep, sweep->max*2);
138 sweep->table[sweep->num] = MakeTableCell(sweep, obj);
143 cpSweep1DRemove(cpSweep1D *sweep, void *obj, cpHashValue hashid)
145 TableCell *table = sweep->table;
146 for(int i=0, count=sweep->num; i<count; i++){
147 if(table[i].obj == obj){
148 int num = --sweep->num;
150 table[i] = table[num];
151 table[num].obj = NULL;
158 //MARK: Reindexing Functions
161 cpSweep1DReindexObject(cpSweep1D *sweep, void *obj, cpHashValue hashid)
163 // Nothing to do here
167 cpSweep1DReindex(cpSweep1D *sweep)
169 // Nothing to do here
170 // Could perform a sort, but queries are not accelerated anyway.
173 //MARK: Query Functions
176 cpSweep1DQuery(cpSweep1D *sweep, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)
178 // Implementing binary search here would allow you to find an upper limit
179 // but not a lower limit. Probably not worth the hassle.
181 Bounds bounds = BBToBounds(sweep, bb);
183 TableCell *table = sweep->table;
184 for(int i=0, count=sweep->num; i<count; i++){
185 TableCell cell = table[i];
186 if(BoundsOverlap(bounds, cell.bounds) && obj != cell.obj) func(obj, cell.obj, 0, data);
191 cpSweep1DSegmentQuery(cpSweep1D *sweep, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)
193 cpBB bb = cpBBExpand(cpBBNew(a.x, a.y, a.x, a.y), b);
194 Bounds bounds = BBToBounds(sweep, bb);
196 TableCell *table = sweep->table;
197 for(int i=0, count=sweep->num; i<count; i++){
198 TableCell cell = table[i];
199 if(BoundsOverlap(bounds, cell.bounds)) func(obj, cell.obj, data);
203 //MARK: Reindex/Query
206 TableSort(TableCell *a, TableCell *b)
208 return (a->bounds.min < b->bounds.min ? -1 : (a->bounds.min > b->bounds.min ? 1 : 0));
212 cpSweep1DReindexQuery(cpSweep1D *sweep, cpSpatialIndexQueryFunc func, void *data)
214 TableCell *table = sweep->table;
215 int count = sweep->num;
217 // Update bounds and sort
218 for(int i=0; i<count; i++) table[i] = MakeTableCell(sweep, table[i].obj);
219 qsort(table, count, sizeof(TableCell), (int (*)(const void *, const void *))TableSort); // TODO: use insertion sort instead
221 for(int i=0; i<count; i++){
222 TableCell cell = table[i];
223 cpFloat max = cell.bounds.max;
225 for(int j=i+1; table[j].bounds.min < max && j<count; j++){
226 func(cell.obj, table[j].obj, 0, data);
230 // Reindex query is also responsible for colliding against the static index.
231 // Fortunately there is a helper function for that.
232 cpSpatialIndexCollideStatic((cpSpatialIndex *)sweep, sweep->spatialIndex.staticIndex, func, data);
235 static cpSpatialIndexClass klass = {
236 (cpSpatialIndexDestroyImpl)cpSweep1DDestroy,
238 (cpSpatialIndexCountImpl)cpSweep1DCount,
239 (cpSpatialIndexEachImpl)cpSweep1DEach,
240 (cpSpatialIndexContainsImpl)cpSweep1DContains,
242 (cpSpatialIndexInsertImpl)cpSweep1DInsert,
243 (cpSpatialIndexRemoveImpl)cpSweep1DRemove,
245 (cpSpatialIndexReindexImpl)cpSweep1DReindex,
246 (cpSpatialIndexReindexObjectImpl)cpSweep1DReindexObject,
247 (cpSpatialIndexReindexQueryImpl)cpSweep1DReindexQuery,
249 (cpSpatialIndexQueryImpl)cpSweep1DQuery,
250 (cpSpatialIndexSegmentQueryImpl)cpSweep1DSegmentQuery,
253 static inline cpSpatialIndexClass *Klass(){return &klass;}