source: anuga_core/source/anuga/visualiser/offline.py @ 3549

Last change on this file since 3549 was 3549, checked in by jack, 18 years ago

Resizing now works on the visualiser.

File size: 6.5 KB
Line 
1from Numeric import array, Float, ravel, zeros
2from Scientific.IO.NetCDF import NetCDFFile
3from Tkinter import Button, E, W
4from visualiser import Visualiser
5from vtk import vtkCellArray, vtkPoints, vtkPolyData
6
7class OfflineVisualiser(Visualiser):
8    """A VTK-powered offline 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    precache_height_quantities() - Precache all the vtkpoints
13    structures for any dynamic height based quantities to render.
14    """
15    def __init__(self, source):
16        """The source parameter is assumed to be a NetCDF sww file.
17        """
18        Visualiser.__init__(self, source)
19
20        self.frameNumber = 0
21        fin = NetCDFFile(self.source, 'r')
22        self.maxFrameNumber = fin.variables['time'].shape[0] - 1
23        fin.close()
24
25        self.vtk_heightQuantityCache = []
26        for i in range(self.maxFrameNumber + 1): # maxFrameNumber is zero indexed.
27            self.vtk_heightQuantityCache.append({})
28
29        self.paused = False
30        self.tk_root.after(100, self.animateForward)
31
32    def setup_grid(self):
33        fin = NetCDFFile(self.source, 'r')
34        self.vtk_cells = vtkCellArray()
35        N_tri = fin.variables['volumes'].shape[0]
36        for v in range(N_tri):
37            self.vtk_cells.InsertNextCell(3)
38            for i in range(3):
39                self.vtk_cells.InsertCellPoint(fin.variables['volumes'][v][i])
40        fin.close()
41
42    def update_height_quantity(self, quantityName, dynamic=True):
43        polydata = self.vtk_polyData[quantityName] = vtkPolyData()
44        if dynamic is True:
45            if not self.vtk_heightQuantityCache[self.frameNumber].has_key(quantityName):
46                self.vtk_heightQuantityCache[self.frameNumber][quantityName]\
47                    = self.read_height_quantity(quantityName, True, self.frameNumber);
48            polydata.SetPoints(self.vtk_heightQuantityCache[self.frameNumber][quantityName])
49        else:
50            polydata.SetPoints(self.read_height_quantity(quantityName, False))
51        polydata.SetPolys(self.vtk_cells)
52           
53    def read_height_quantity(self, quantityName, dynamic=True, frameNumber=0):
54        """Read in a height based quantity from the NetCDF source file
55        and return a vtkPoints object. frameNumber is ignored if
56        dynamic is false."""
57        fin = NetCDFFile(self.source, 'r')
58        points = vtkPoints()
59        if dynamic is True:
60            N_vert = fin.variables[quantityName].shape[1]
61        else:
62            N_vert = len(fin.variables[quantityName])
63        x = ravel(array(fin.variables['x'], Float))
64        y = ravel(array(fin.variables['y'], Float))
65        if dynamic is True:
66            q = array(fin.variables[quantityName][frameNumber], Float)
67        else:
68            q = ravel(array(fin.variables[quantityName], Float))
69
70        q *= self.height_zScales[quantityName]
71        q += self.height_offset[quantityName]
72
73        for v in range(N_vert):
74            points.InsertNextPoint(x[v], y[v], q[v])
75        fin.close()
76        return points
77
78    def precache_height_quantities(self):
79        """Precache any height-based quantities. Call before rendering
80        beigns."""
81        for q in self.height_quantities:
82            if self.height_dynamic[q] is True:
83                print 'Precaching %s' % q
84                for i in range(self.maxFrameNumber + 1): # maxFrameNumber is zero-indexed
85                    print ' - Frame %d of %d' % (i, self.maxFrameNumber)
86                    self.vtk_heightQuantityCache[i][q]\
87                        = self.read_height_quantity(q, True, i)
88
89    def build_quantity_dict(self):
90        quantities = {}
91        fin = NetCDFFile(self.source, 'r')
92        for q in filter(lambda n:n != 'x' and n != 'y' and n != 'z' and n != 'time' and n != 'volumes', fin.variables.keys()):
93            if len(fin.variables[q].shape) == 1: # Not a time-varying quantity
94                quantities[q] = ravel(array(fin.variables[q], Float))
95            else: # Time-varying, get the current timestep data
96                quantities[q] = array(fin.variables[q][self.frameNumber], Float)
97        fin.close()
98        return quantities
99
100    def setup_gui(self):
101        Visualiser.setup_gui(self)
102        self.tk_quit.grid(row=0, column=0, columnspan=6, sticky=W+E)
103        self.tk_restart = Button(self.tk_controlFrame, text="<<<", command=self.restart)
104        self.tk_restart.grid(row=1, column=0, sticky=W+E)
105        self.tk_back10 = Button(self.tk_controlFrame, text="<<", command=self.back10)
106        self.tk_back10.grid(row=1, column=1, sticky=W+E)
107        self.tk_back = Button(self.tk_controlFrame, text="<", command=self.back)
108        self.tk_back.grid(row=1, column=2, sticky=W+E)
109        self.tk_pauseResume = Button(self.tk_controlFrame, text="Pause", command=self.pauseResume)
110        self.tk_pauseResume.grid(row=1, column=3, sticky=W+E)
111        self.tk_forward = Button(self.tk_controlFrame, text=">", command=self.forward)
112        self.tk_forward.grid(row=1, column=4, sticky=W+E)
113        self.tk_forward10 = Button(self.tk_controlFrame, text=">>", command=self.forward10)
114        self.tk_forward10.grid(row=1, column=5, sticky=W+E)
115
116        # Make the buttons stretch to fill all available space
117        for i in range(6):
118            self.tk_controlFrame.grid_columnconfigure(i, weight=1)
119
120    def restart(self):
121        self.frameNumber = 0
122        self.redraw_quantities(True)
123
124    def back10(self):
125        if self.frameNumber - 10 >= 0:
126            self.frameNumber -= 10
127        else:
128            self.frameNumber = 0
129        self.redraw_quantities(True)
130
131    def back(self):
132        if self.frameNumber > 0:
133            self.frameNumber -= 1
134            self.redraw_quantities(True)
135
136    def pauseResume(self):
137        if self.paused is True:
138            self.tk_pauseResume.config(text="Pause")
139            self.paused = False
140            self.tk_root.after(100, self.animateForward)
141        else:
142            self.tk_pauseResume.config(text="Resume")
143            self.paused = True
144
145    def forward(self):
146        if self.frameNumber < self.maxFrameNumber:
147            self.frameNumber += 1
148            self.redraw_quantities(True)
149
150    def forward10(self):
151        if self.frameNumber + 10 <= self.maxFrameNumber:
152            self.frameNumber += 10
153        else:
154            self.frameNumber = self.maxFrameNumber
155        self.redraw_quantities(True)
156
157    def animateForward(self):
158        if self.paused is not True:
159            self.forward()
160            self.tk_root.after(100, self.animateForward)
Note: See TracBrowser for help on using the repository browser.