File: voronoi.py

package info (click to toggle)
python-vispy 0.16.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,112 kB
  • sloc: python: 61,648; javascript: 6,800; ansic: 2,104; makefile: 141; sh: 6
file content (124 lines) | stat: -rw-r--r-- 3,309 bytes parent folder | download | duplicates (4)
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
120
121
122
123
124
# -*- coding: utf-8 -*-
# vispy: gallery 30
# vispy: testskip - because this example sometimes sets inactive attributes
"""Computing a Voronoi diagram on the GPU. Shows how to use uniform arrays.

Original version by Xavier Olive (xoolive).

"""

import numpy as np

from vispy import app
from vispy import gloo


# Voronoi shaders.
VS_voronoi = """
attribute vec2 a_position;

void main() {
    gl_Position = vec4(a_position, 0., 1.);
}
"""

FS_voronoi = """
uniform vec2 u_seeds[32];
uniform vec3 u_colors[32];
uniform vec2 u_screen;

void main() {
    float dist = distance(u_screen * u_seeds[0], gl_FragCoord.xy);
    vec3 color = u_colors[0];
    for (int i = 1; i < 32; i++) {
        float current = distance(u_screen * u_seeds[i], gl_FragCoord.xy);
        if (current < dist) {
            color = u_colors[i];
            dist = current;
        }
    }
    gl_FragColor = vec4(color, 1.0);
}
"""


# Seed point shaders.
VS_seeds = """
attribute vec2 a_position;
uniform float u_ps;

void main() {
    gl_Position = vec4(2. * a_position - 1., 0., 1.);
    gl_PointSize = 10. * u_ps;
}
"""

FS_seeds = """
varying vec3 v_color;
void main() {
    gl_FragColor = vec4(1., 1., 1., 1.);
}
"""


class Canvas(app.Canvas):
    def __init__(self):
        app.Canvas.__init__(self, size=(600, 600), title='Voronoi diagram',
                            keys='interactive')

        self.ps = self.pixel_scale

        self.seeds = np.random.uniform(0, 1.0 * self.ps,
                                       size=(32, 2)).astype(np.float32)
        self.colors = np.random.uniform(0.3, 0.8,
                                        size=(32, 3)).astype(np.float32)
        self.idx = 0

        # Set Voronoi program.
        self.program_v = gloo.Program(VS_voronoi, FS_voronoi)
        self.program_v['a_position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)]
        # HACK: work-around a bug related to uniform arrays until
        # issue #345 is solved.
        for i in range(32):
            self.program_v['u_seeds[%d]' % i] = self.seeds[i, :]
            self.program_v['u_colors[%d]' % i] = self.colors[i, :]

        # Set seed points program.
        self.program_s = gloo.Program(VS_seeds, FS_seeds)
        self.program_s['a_position'] = self.seeds
        self.program_s['u_ps'] = self.ps

        self.activate_zoom()

        self.show()

    def on_draw(self, event):
        gloo.clear()
        self.program_v.draw('triangle_strip')
        self.program_s.draw('points')

    def on_resize(self, event):
        self.activate_zoom()

    def activate_zoom(self):
        self.width, self.height = self.size
        gloo.set_viewport(0, 0, *self.physical_size)
        self.program_v['u_screen'] = self.physical_size

    def on_mouse_move(self, event):
        x, y = event.pos
        x, y = x / float(self.width), 1 - y / float(self.height)
        self.program_v['u_seeds[%d]' % self.idx] = x * self.ps, y * self.ps
        # TODO: just update the first line in the VBO instead of uploading the
        # whole array of seed points.
        self.seeds[self.idx, :] = x, y
        self.program_s['a_position'].set_data(self.seeds)
        self.update()

    def on_mouse_press(self, event):
        self.idx = (self.idx + 1) % 32


if __name__ == "__main__":
    c = Canvas()
    app.run()