1 | from Numeric import Float, zeros |
---|
2 | from Tkinter import Button, E, Tk, W |
---|
3 | from threading import Event |
---|
4 | from visualiser import Visualiser |
---|
5 | from vtk import vtkCellArray, vtkPoints, vtkPolyData |
---|
6 | |
---|
7 | class RealtimeVisualiser(Visualiser): |
---|
8 | """A VTK-powered realtime visualiser which runs in its own thread. |
---|
9 | In addition to the functions provided by the standard visualiser, |
---|
10 | the following additional functions are provided: |
---|
11 | |
---|
12 | update() - Sync the visualiser to the current state of the model. |
---|
13 | Should be called inside the evolve loop. |
---|
14 | |
---|
15 | evolveFinished() - Clean up synchronisation constructs that tie the |
---|
16 | visualiser to the evolve loop. Call this after the evolve loop finishes |
---|
17 | to ensure a clean shutdown. |
---|
18 | """ |
---|
19 | def __init__(self, source): |
---|
20 | """The source parameter is assumed to be a Domain. |
---|
21 | """ |
---|
22 | Visualiser.__init__(self, source) |
---|
23 | |
---|
24 | self.running = True |
---|
25 | |
---|
26 | self.xmin = None |
---|
27 | self.xmax = None |
---|
28 | self.ymin = None |
---|
29 | self.ymax = None |
---|
30 | self.zmin = None |
---|
31 | self.zmax = None |
---|
32 | |
---|
33 | # Synchronisation Constructs |
---|
34 | self.sync_idle = Event() |
---|
35 | self.sync_idle.clear() |
---|
36 | self.sync_unpaused = Event() |
---|
37 | self.sync_unpaused.set() |
---|
38 | self.sync_redrawReady = Event() |
---|
39 | self.sync_redrawReady.clear() |
---|
40 | |
---|
41 | def setup_grid(self): |
---|
42 | self.vtk_cells = vtkCellArray() |
---|
43 | triangles = self.source.get_triangles() |
---|
44 | N_tri = len(self.source) |
---|
45 | verticies = self.source.get_vertex_coordinates() |
---|
46 | N_vert = len(verticies) |
---|
47 | # Also build vert_index - a list of the x & y values of each vertex |
---|
48 | self.vert_index = zeros((N_vert,2), Float) |
---|
49 | for n in range(N_tri): |
---|
50 | self.vtk_cells.InsertNextCell(3) |
---|
51 | for v in range(3): |
---|
52 | self.vert_index[triangles[n][v]] = verticies[n * 3 + v] |
---|
53 | self.vtk_cells.InsertCellPoint(triangles[n][v]) |
---|
54 | |
---|
55 | def update_height_quantity(self, quantityName, dynamic=True): |
---|
56 | N_vert = len(self.source.get_vertex_coordinates()) |
---|
57 | qty_index = zeros(N_vert, Float) |
---|
58 | triangles = self.source.get_triangles() |
---|
59 | vertex_values, _ = self.source.get_quantity(quantityName).get_vertex_values(xy=False, smooth=False) |
---|
60 | |
---|
61 | for n in range(len(triangles)): |
---|
62 | for v in range(3): |
---|
63 | #qty_index[triangles[n][v]] = self.source.get_quantity(quantityName).vertex_values[n][v] |
---|
64 | qty_index[triangles[n][v]] = vertex_values[n * 3 + v] |
---|
65 | |
---|
66 | points = vtkPoints() |
---|
67 | for v in range(N_vert): |
---|
68 | points.InsertNextPoint(self.vert_index[v][0], |
---|
69 | self.vert_index[v][1], |
---|
70 | qty_index[v] * self.height_zScales[quantityName] |
---|
71 | + self.height_offset[quantityName]) |
---|
72 | if self.xmin == None or self.xmin > self.vert_index[v][0]: |
---|
73 | self.xmin = self.vert_index[v][0] |
---|
74 | if self.xmax == None or self.xmax < self.vert_index[v][0]: |
---|
75 | self.xmax = self.vert_index[v][0] |
---|
76 | if self.ymin == None or self.ymin > self.vert_index[v][1]: |
---|
77 | self.ymin = self.vert_index[v][1] |
---|
78 | if self.ymax == None or self.ymax < self.vert_index[v][1]: |
---|
79 | self.ymax = self.vert_index[v][1] |
---|
80 | if self.zmin == None or self.zmin > qty_index[v] * self.height_zScales[quantityName] + self.height_offset[quantityName]: |
---|
81 | self.zmin = qty_index[v] * self.height_zScales[quantityName] + self.height_offset[quantityName] |
---|
82 | if self.zmax == None or self.zmax < qty_index[v] * self.height_zScales[quantityName] + self.height_offset[quantityName]: |
---|
83 | self.zmax = qty_index[v] * self.height_zScales[quantityName] + self.height_offset[quantityName] |
---|
84 | |
---|
85 | polydata = self.vtk_polyData[quantityName] = vtkPolyData() |
---|
86 | polydata.SetPoints(points) |
---|
87 | polydata.SetPolys(self.vtk_cells) |
---|
88 | |
---|
89 | def get_3d_bounds(self): |
---|
90 | return [self.xmin, self.xmax, self.ymin, self.ymax, self.zmin, self.zmax] |
---|
91 | |
---|
92 | def build_quantity_dict(self): |
---|
93 | triangles = self.source.get_triangles() |
---|
94 | quantities = {} |
---|
95 | for q in self.source.get_quantity_names(): |
---|
96 | quantities[q], _ = self.source.get_quantity(q).get_vertex_values(xy=False) |
---|
97 | return quantities |
---|
98 | |
---|
99 | def setup_gui(self): |
---|
100 | Visualiser.setup_gui(self) |
---|
101 | self.tk_pauseResume = Button(self.tk_controlFrame, text="Pause", command=self.pauseResume) |
---|
102 | self.tk_pauseResume.grid(row=1, column=0, sticky=E+W) |
---|
103 | |
---|
104 | def pauseResume(self): |
---|
105 | if self.sync_unpaused.isSet(): |
---|
106 | self.sync_unpaused.clear() |
---|
107 | self.tk_pauseResume.config(text="Resume") |
---|
108 | else: |
---|
109 | self.sync_unpaused.set() |
---|
110 | self.tk_pauseResume.config(text="Pause") |
---|
111 | |
---|
112 | def shutdown(self): |
---|
113 | Visualiser.shutdown(self) |
---|
114 | self.running = False |
---|
115 | self.sync_idle.set() |
---|
116 | self.sync_unpaused.set() |
---|
117 | |
---|
118 | def redraw(self): |
---|
119 | if self.running and self.sync_unpaused.isSet(): |
---|
120 | self.sync_redrawReady.wait() |
---|
121 | self.sync_redrawReady.clear() |
---|
122 | self.redraw_quantities() |
---|
123 | self.sync_idle.set() |
---|
124 | Visualiser.redraw(self) |
---|
125 | |
---|
126 | def update(self): |
---|
127 | """Sync the visualiser to the domain. Call this in the evolve loop.""" |
---|
128 | if self.running: |
---|
129 | self.sync_redrawReady.set() |
---|
130 | self.sync_idle.wait() |
---|
131 | self.sync_idle.clear() |
---|
132 | self.sync_unpaused.wait() |
---|
133 | |
---|
134 | def evolveFinished(self): |
---|
135 | """Stop the visualiser from waiting on signals from the evolve loop. |
---|
136 | Call this just after the evolve loop to ensure a clean shutdown.""" |
---|
137 | self.running = False |
---|
138 | self.sync_redrawReady.set() |
---|