'use strict' module.exports = { init: sqInit, sweepBipartite: sweepBipartite, sweepComplete: sweepComplete, scanBipartite: scanBipartite, scanComplete: scanComplete } var pool = require('typedarray-pool') var bits = require('bit-twiddle') var isort = require('./sort') //Flag for blue var BLUE_FLAG = (1<<28) //1D sweep event queue stuff (use pool to save space) var INIT_CAPACITY = 1024 var RED_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY) var RED_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY) var BLUE_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY) var BLUE_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY) var COMMON_SWEEP_QUEUE = pool.mallocInt32(INIT_CAPACITY) var COMMON_SWEEP_INDEX = pool.mallocInt32(INIT_CAPACITY) var SWEEP_EVENTS = pool.mallocDouble(INIT_CAPACITY * 8) //Reserves memory for the 1D sweep data structures function sqInit(count) { var rcount = bits.nextPow2(count) if(RED_SWEEP_QUEUE.length < rcount) { pool.free(RED_SWEEP_QUEUE) RED_SWEEP_QUEUE = pool.mallocInt32(rcount) } if(RED_SWEEP_INDEX.length < rcount) { pool.free(RED_SWEEP_INDEX) RED_SWEEP_INDEX = pool.mallocInt32(rcount) } if(BLUE_SWEEP_QUEUE.length < rcount) { pool.free(BLUE_SWEEP_QUEUE) BLUE_SWEEP_QUEUE = pool.mallocInt32(rcount) } if(BLUE_SWEEP_INDEX.length < rcount) { pool.free(BLUE_SWEEP_INDEX) BLUE_SWEEP_INDEX = pool.mallocInt32(rcount) } if(COMMON_SWEEP_QUEUE.length < rcount) { pool.free(COMMON_SWEEP_QUEUE) COMMON_SWEEP_QUEUE = pool.mallocInt32(rcount) } if(COMMON_SWEEP_INDEX.length < rcount) { pool.free(COMMON_SWEEP_INDEX) COMMON_SWEEP_INDEX = pool.mallocInt32(rcount) } var eventLength = 8 * rcount if(SWEEP_EVENTS.length < eventLength) { pool.free(SWEEP_EVENTS) SWEEP_EVENTS = pool.mallocDouble(eventLength) } } //Remove an item from the active queue in O(1) function sqPop(queue, index, count, item) { var idx = index[item] var top = queue[count-1] queue[idx] = top index[top] = idx } //Insert an item into the active queue in O(1) function sqPush(queue, index, count, item) { queue[count] = item index[item] = count } //Recursion base case: use 1D sweep algorithm function sweepBipartite( d, visit, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex) { //store events as pairs [coordinate, idx] // // red create: -(idx+1) // red destroy: idx // blue create: -(idx+BLUE_FLAG) // blue destroy: idx+BLUE_FLAG // var ptr = 0 var elemSize = 2*d var istart = d-1 var iend = elemSize-1 for(var i=redStart; iright var n = ptr >>> 1 isort(SWEEP_EVENTS, n) var redActive = 0 var blueActive = 0 for(var i=0; i= BLUE_FLAG) { //blue destroy event e = (e-BLUE_FLAG)|0 sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, e) } else if(e >= 0) { //red destroy event sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, e) } else if(e <= -BLUE_FLAG) { //blue create event e = (-e-BLUE_FLAG)|0 for(var j=0; jright var n = ptr >>> 1 isort(SWEEP_EVENTS, n) var redActive = 0 var blueActive = 0 var commonActive = 0 for(var i=0; i>1) === (SWEEP_EVENTS[2*i+3]>>1)) { color = 2 i += 1 } if(e < 0) { //Create event var id = -(e>>1) - 1 //Intersect with common for(var j=0; j>1) - 1 if(color === 0) { //Red sqPop(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive--, id) } else if(color === 1) { //Blue sqPop(BLUE_SWEEP_QUEUE, BLUE_SWEEP_INDEX, blueActive--, id) } else if(color === 2) { //Both sqPop(COMMON_SWEEP_QUEUE, COMMON_SWEEP_INDEX, commonActive--, id) } } } } //Sweep and prune/scanline algorithm: // Scan along axis, detect intersections // Brute force all boxes along axis function scanBipartite( d, axis, visit, flip, redStart, redEnd, red, redIndex, blueStart, blueEnd, blue, blueIndex) { var ptr = 0 var elemSize = 2*d var istart = axis var iend = axis+d var redShift = 1 var blueShift = 1 if(flip) { blueShift = BLUE_FLAG } else { redShift = BLUE_FLAG } for(var i=redStart; iright var n = ptr >>> 1 isort(SWEEP_EVENTS, n) var redActive = 0 for(var i=0; i= BLUE_FLAG) { isRed = !flip idx -= BLUE_FLAG } else { isRed = !!flip idx -= 1 } if(isRed) { sqPush(RED_SWEEP_QUEUE, RED_SWEEP_INDEX, redActive++, idx) } else { var blueId = blueIndex[idx] var bluePtr = elemSize * idx var b0 = blue[bluePtr+axis+1] var b1 = blue[bluePtr+axis+1+d] red_loop: for(var j=0; jright var n = ptr >>> 1 isort(SWEEP_EVENTS, n) var redActive = 0 for(var i=0; i= BLUE_FLAG) { RED_SWEEP_QUEUE[redActive++] = idx - BLUE_FLAG } else { idx -= 1 var blueId = blueIndex[idx] var bluePtr = elemSize * idx var b0 = blue[bluePtr+axis+1] var b1 = blue[bluePtr+axis+1+d] red_loop: for(var j=0; j=0; --j) { if(RED_SWEEP_QUEUE[j] === idx) { for(var k=j+1; k