UNPKG

box-intersect

Version:
142 lines (128 loc) 3.46 kB
'use strict' module.exports = findMedian var genPartition = require('./partition') var partitionStartLessThan = genPartition('lo<p0', ['p0']) var PARTITION_THRESHOLD = 8 //Cut off for using insertion sort in findMedian //Base case for median finding: Use insertion sort function insertionSort(d, axis, start, end, boxes, ids) { var elemSize = 2 * d var boxPtr = elemSize * (start+1) + axis for(var i=start+1; i<end; ++i, boxPtr+=elemSize) { var x = boxes[boxPtr] for(var j=i, ptr=elemSize*(i-1); j>start && boxes[ptr+axis] > x; --j, ptr-=elemSize) { //Swap var aPtr = ptr var bPtr = ptr+elemSize for(var k=0; k<elemSize; ++k, ++aPtr, ++bPtr) { var y = boxes[aPtr] boxes[aPtr] = boxes[bPtr] boxes[bPtr] = y } var tmp = ids[j] ids[j] = ids[j-1] ids[j-1] = tmp } } } //Find median using quick select algorithm // takes O(n) time with high probability function findMedian(d, axis, start, end, boxes, ids) { if(end <= start+1) { return start } var lo = start var hi = end var mid = ((end + start) >>> 1) var elemSize = 2*d var pivot = mid var value = boxes[elemSize*mid+axis] while(lo < hi) { if(hi - lo < PARTITION_THRESHOLD) { insertionSort(d, axis, lo, hi, boxes, ids) value = boxes[elemSize*mid+axis] break } //Select pivot using median-of-3 var count = hi - lo var pivot0 = (Math.random()*count+lo)|0 var value0 = boxes[elemSize*pivot0 + axis] var pivot1 = (Math.random()*count+lo)|0 var value1 = boxes[elemSize*pivot1 + axis] var pivot2 = (Math.random()*count+lo)|0 var value2 = boxes[elemSize*pivot2 + axis] if(value0 <= value1) { if(value2 >= value1) { pivot = pivot1 value = value1 } else if(value0 >= value2) { pivot = pivot0 value = value0 } else { pivot = pivot2 value = value2 } } else { if(value1 >= value2) { pivot = pivot1 value = value1 } else if(value2 >= value0) { pivot = pivot0 value = value0 } else { pivot = pivot2 value = value2 } } //Swap pivot to end of array var aPtr = elemSize * (hi-1) var bPtr = elemSize * pivot for(var i=0; i<elemSize; ++i, ++aPtr, ++bPtr) { var x = boxes[aPtr] boxes[aPtr] = boxes[bPtr] boxes[bPtr] = x } var y = ids[hi-1] ids[hi-1] = ids[pivot] ids[pivot] = y //Partition using pivot pivot = partitionStartLessThan( d, axis, lo, hi-1, boxes, ids, value) //Swap pivot back var aPtr = elemSize * (hi-1) var bPtr = elemSize * pivot for(var i=0; i<elemSize; ++i, ++aPtr, ++bPtr) { var x = boxes[aPtr] boxes[aPtr] = boxes[bPtr] boxes[bPtr] = x } var y = ids[hi-1] ids[hi-1] = ids[pivot] ids[pivot] = y //Swap pivot to last pivot if(mid < pivot) { hi = pivot-1 while(lo < hi && boxes[elemSize*(hi-1)+axis] === value) { hi -= 1 } hi += 1 } else if(pivot < mid) { lo = pivot + 1 while(lo < hi && boxes[elemSize*lo+axis] === value) { lo += 1 } } else { break } } //Make sure pivot is at start return partitionStartLessThan( d, axis, start, mid, boxes, ids, boxes[elemSize*mid+axis]) }