File size: 2,133 Bytes
4a288a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
 * kd-tree based clustering
 *
 * Based on kdbush package
 */

'use strict'


module.exports = function clusterKD (points, ids, levels, weights, options) {
    let ptr = 0
    let n = ids.length
    let nodeSize = options.nodeSize

    sort(0, n - 1, 0)

    function sort(left, right, level) {
        let count = right - left
        weights[ptr] = count
        levels[ptr++] = level

        if (count <= nodeSize) return;

        let m = Math.floor((left + right) / 2);

        select(m, left, right, level % 2);

        sort(left, m - 1, level + 1);
        sort(m + 1, right, level + 1);
    }

    function select(k, left, right, inc) {
        while (right > left) {
            if (right - left > 600) {
                let n = right - left + 1;
                let m = k - left + 1;
                let z = Math.log(n);
                let s = 0.5 * Math.exp(2 * z / 3);
                let sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
                let newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
                let newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
                select(k, newLeft, newRight, inc);
            }

            let t = points[2 * k + inc];
            let i = left;
            let j = right;

            swapItem(left, k);
            if (points[2 * right + inc] > t) swapItem(left, right);

            while (i < j) {
                swapItem(i, j);
                i++;
                j--;
                while (points[2 * i + inc] < t) i++;
                while (points[2 * j + inc] > t) j--;
            }

            if (points[2 * left + inc] === t) swapItem(left, j);
            else {
                j++;
                swapItem(j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    function swapItem(i, j) {
        swap(ids, i, j);
        swap(points, 2 * i, 2 * j);
        swap(points, 2 * i + 1, 2 * j + 1);
    }

    function swap(arr, i, j) {
        let tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}