handleSetTrans(object obj, cpSpaceHash *hash) { if(hash.pooledHandles.num == 0){ // handle pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(cpHandle); // cpAssertHard(count, "Internal Error: Buffer size is too small."); cpHandle *buffer = (cpHandle *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(hash.allocatedBuffers, buffer); for(int i=0; i<count; i++) cpArrayPush(hash.pooledHandles, buffer + i); } cpHandle *hand = cpHandleInit((cpHandle *)cpArrayPop(hash.pooledHandles), obj); cpHandleRetain(hand); return hand; }
cpSpaceHashRemove(cpSpaceHash *hash, object obj, cpHashValue hashid) { cpHandle *hand = (cpHandle *)cpHashSetRemove(hash.handleSet, hashid, obj); if(hand){ hand.obj = null; cpHandleRelease(hand, hash.pooledHandles); } }
rehash_helper(cpHandle *hand, cpSpaceHash *hash) { hashHandle(hash, hand, hash.spatialIndex.bbfunc(hand.obj)); }
cpSpaceHashRehash(cpSpaceHash *hash) { clearTable(hash); cpHashSetEach(hash.handleSet, (cpHashSetIteratorFunc)rehash_helper, hash); }
hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb) { // Find the dimensions in cell coordinates. double dim = hash.celldim; int l = floor_int(bb.l/dim); // Fix by ShiftZ int r = floor_int(bb.r/dim); int b = floor_int(bb.b/dim); int t = floor_int(bb.t/dim); int n = hash.numcells; for(int i=l; i<=r; i++){ for(int j=b; j<=t; j++){ cpHashValue idx = hash_func(i,j,n); cpSpaceHashBin *bin = hash.table[idx]; // Don't add an object twice to the same cell. if(containsHandle(bin, hand)) continue; cpHandleRetain(hand); // Insert a new bin for the handle in this cell. cpSpaceHashBin *newBin = getEmptyBin(hash); newBin.handle = hand; newBin.next = bin; hash.table[idx] = newBin; } } }
cpSpaceHashInsert(cpSpaceHash *hash, object obj, cpHashValue hashid) { cpHandle *hand = (cpHandle *)cpHashSetInsert(hash.handleSet, hashid, obj, hash, (cpHashSetTransFunc)handleSetTrans); hashHandle(hash, hand, hash.spatialIndex.bbfunc(obj)); }
cpSpaceHashInit(cpSpaceHash *hash, double celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex) { cpSpatialIndexInit((cpSpatialIndex *)hash, Klass(), bbfunc, staticIndex); cpSpaceHashAllocTable(hash, next_prime(numcells)); hash.celldim = celldim; hash.handleSet = cpHashSetNew(0, (cpHashSetEqlFunc)handleSetEql); hash.pooledHandles = cpArrayNew(0); hash.pooledBins = null; hash.allocatedBuffers = cpArrayNew(0); hash.stamp = 1; return (cpSpatialIndex *)hash; }
cpSpaceHashDestroy(cpSpaceHash *hash) { if(hash.table) clearTable(hash); cpfree(hash.table); cpHashSetFree(hash.handleSet); cpArrayFreeEach(hash.allocatedBuffers, cpfree); cpArrayFree(hash.allocatedBuffers); cpArrayFree(hash.pooledHandles); }
cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells) { cpfree(hash.table); hash.numcells = numcells; hash.table = (cpSpaceHashBin **)cpcalloc(numcells, sizeof(cpSpaceHashBin *)); }
getEmptyBin(cpSpaceHash *hash) { cpSpaceHashBin *bin = hash.pooledBins; if(bin){ hash.pooledBins = bin.next; return bin; } else { // Pool is exhausted, make more int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin); // cpAssertHard(count, "Internal Error: Buffer size is too small."); cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpcalloc(1, CP_BUFFER_BYTES); cpArrayPush(hash.allocatedBuffers, buffer); // push all but the first one, return the first instead for(int i=1; i<count; i++) recycleBin(hash, buffer + i); return buffer; } }
clearTable(cpSpaceHash *hash) { for(int i=0; i<hash.numcells; i++) clearTableCell(hash, i); }
clearTableCell(cpSpaceHash *hash, int idx) { cpSpaceHashBin *bin = hash.table[idx]; while(bin){ cpSpaceHashBin *next = bin.next; cpHandleRelease(bin.handle, hash.pooledHandles); recycleBin(hash, bin); bin = next; } hash.table[idx] = null; }
recycleBin(cpSpaceHash *hash, cpSpaceHashBin *bin) { bin.next = hash.pooledBins; hash.pooledBins = bin; }