๐Ÿ“ฆ sbuggay / boids

๐Ÿ“„ quadtree.js ยท 120 lines
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

class Rect {
    constructor(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

    contains(point) {
        return (point.x >= this.x - this.w &&
            point.x < this.x + this.w &&
            point.y >= this.y - this.h &&
            point.y < this.y + this.h);
    }

    intersects(range) {
        return !(range.x - range.w > this.x + this.w ||
            range.x + range.w < this.x - this.w ||
            range.y - range.h > this.y + this.h ||
            range.y + range.h < this.y - this.h);
    }
}

class QuadTree {
    constructor(boundary, capacity) {
        this.boundary = boundary;
        this.capacity = capacity;
        this.list = [];
        this.divided = false;
    }

    insert(boid) {

        const point = boid.position;

        if (!this.boundary.contains(point)) return;

        if (this.list.length < this.capacity) {
            this.list.push(boid);
        }
        else {
            if (!this.divided) {
                this.subdivide();
            }

            this.ne.insert(boid);
            this.nw.insert(boid);
            this.sw.insert(boid);
            this.se.insert(boid);
        }
    }

    query(range, found) {
        if (!found) {
            found = [];
        }

        if (!this.boundary.intersects(range)) {
            return;
        } else {
            for (let p of this.list) {
                if (range.contains(p.position)) {
                    found.push(p);
                }
            }
            if (this.divided) {
                this.nw.query(range, found);
                this.ne.query(range, found);
                this.se.query(range, found);
                this.sw.query(range, found);
            }
        }
        return found;
    }

    subdivide() {
        let x = this.boundary.x;
        let y = this.boundary.y;
        let w = this.boundary.w;
        let h = this.boundary.h;

        let neRect = new Rect(x + w / 2, y + h / 2, w / 2, h / 2);
        let nwRect = new Rect(x - w / 2, y + h / 2, w / 2, h / 2);
        let swRect = new Rect(x - w / 2, y - h / 2, w / 2, h / 2);
        let seRect = new Rect(x + w / 2, y - h / 2, w / 2, h / 2);
        this.ne = new QuadTree(neRect, this.capacity);
        this.nw = new QuadTree(nwRect, this.capacity);
        this.sw = new QuadTree(swRect, this.capacity);
        this.se = new QuadTree(seRect, this.capacity);
        this.divided = true;

    }

    render() {

        if (this.ne) this.ne.render();
        if (this.nw) this.nw.render();
        if (this.se) this.se.render();
        if (this.sw) this.sw.render();

        if (this.ne && this.nw && this.se && this.sw) return; // Don't render if we render all children

        push();
        stroke(200, 200, 200, 100);
        fill(0, 0, 0, 0);
        rectMode(CENTER);
        translate(this.boundary.x, this.boundary.y);
        rect(0, 0, this.boundary.w * 2, this.boundary.h * 2)
        pop();
    }
}