1 |
jgs |
123 |
#!/usr/bin/env python |
2 |
|
|
# $Id$ |
3 |
|
|
|
4 |
|
|
import vtk |
5 |
|
|
import sys, os, re |
6 |
|
|
import getopt |
7 |
|
|
|
8 |
|
|
(opts, args) = getopt.getopt(sys.argv[1:], |
9 |
|
|
"d:f:ph", |
10 |
|
|
["dirname=", "fnamestem=", "preproc", "help"], |
11 |
|
|
) |
12 |
|
|
|
13 |
|
|
def usage(): |
14 |
|
|
print "Usage:" |
15 |
|
|
print " velVis.py -d <dirname> -f <fnamestem> -p -i\n" |
16 |
|
|
print " Arguments:" |
17 |
|
|
print " -d/--dirname: directory of vtk files to process (req)" |
18 |
|
|
print " -f/--fnamestem: filename stem of vtk files to process (req)" |
19 |
|
|
print " -p/--preproc: preprocess vtk files to find global vector max? (opt)" |
20 |
|
|
print " -i/--interactive: interactive use of first frame? (opt)" |
21 |
|
|
|
22 |
|
|
#dirName = '/data/raid2/matt/results/050516/m3dpData/vis' |
23 |
|
|
dirName = None |
24 |
|
|
fnameStem = None |
25 |
|
|
interactive = False |
26 |
|
|
preproc = False # preprocess to find the global max of the data |
27 |
|
|
|
28 |
|
|
for option, arg in opts: |
29 |
|
|
if option in ('-d', '--dirname'): |
30 |
|
|
dirName = arg |
31 |
|
|
elif option in ('-f', '--fnamestem'): |
32 |
|
|
fnameStem = arg |
33 |
|
|
elif option in ('-p', '--preproc'): |
34 |
|
|
preproc = True |
35 |
|
|
elif option in ('-i', '--interactive'): |
36 |
|
|
interactive = True |
37 |
|
|
elif option in ('-h', '--help'): |
38 |
|
|
usage() |
39 |
|
|
sys.exit(0) |
40 |
|
|
|
41 |
|
|
if dirName is None: |
42 |
|
|
print "You must supply a directory of vtk files to process\n" |
43 |
|
|
usage() |
44 |
|
|
sys.exit(1) |
45 |
|
|
|
46 |
|
|
if fnameStem is None: |
47 |
|
|
print "You must supply the filename stem of the files to process" |
48 |
|
|
print "The filename stem is the part of the filename without the" |
49 |
|
|
print "frame number or extension\n" |
50 |
|
|
usage() |
51 |
|
|
sys.exit(1) |
52 |
|
|
|
53 |
|
|
# now need to determine the number of files to process |
54 |
|
|
dirList = os.listdir(dirName) |
55 |
|
|
r = re.compile( "%s\\d+\\.\\w+" % fnameStem ) |
56 |
|
|
count = 0 # counter for the number of files found |
57 |
|
|
fnames = [] |
58 |
|
|
for fname in dirList: |
59 |
|
|
if r.match(fname): |
60 |
|
|
fnames.append(fname) |
61 |
|
|
count += 1 |
62 |
|
|
|
63 |
|
|
# determine the first frame number and number of frames |
64 |
|
|
fnames.sort() |
65 |
|
|
firstFile = fnames[0] |
66 |
|
|
|
67 |
|
|
r = re.compile("([a-zA-Z-])(\\d+)(\\.)(\\w+)") |
68 |
|
|
firstNum = r.findall(firstFile) |
69 |
|
|
firstNum = int(firstNum[0][1]) |
70 |
|
|
|
71 |
|
|
# grab the filename extension as well, just in case |
72 |
|
|
extn = r.findall(firstFile) |
73 |
|
|
extn = extn[0][3] |
74 |
|
|
|
75 |
|
|
# the number of frames should be equal to the count |
76 |
|
|
if interactive: |
77 |
|
|
numFrames = 1 |
78 |
|
|
mesa = False |
79 |
|
|
else: |
80 |
|
|
numFrames = count |
81 |
|
|
mesa = True |
82 |
|
|
|
83 |
|
|
# try and work out the format of the zero-padded frame number |
84 |
|
|
if count < 10: |
85 |
|
|
formatString = '"%01d"' |
86 |
|
|
elif count < 100: |
87 |
|
|
formatString = '"%02d"' |
88 |
|
|
elif count < 1000: |
89 |
|
|
formatString = '"%03d"' |
90 |
|
|
elif count < 10000: |
91 |
|
|
formatString = '"%04d"' |
92 |
|
|
elif count < 100000: |
93 |
|
|
formatString = '"%05d"' |
94 |
|
|
else: |
95 |
|
|
print "Sorry, can't handle greater than 100000 input frames" |
96 |
|
|
sys.exit(1) |
97 |
|
|
|
98 |
|
|
# use mesa if required |
99 |
|
|
if mesa: |
100 |
|
|
factGraphics = vtk.vtkGraphicsFactory() |
101 |
|
|
factGraphics.SetUseMesaClasses(1) |
102 |
|
|
|
103 |
|
|
factImage = vtk.vtkImagingFactory() |
104 |
|
|
factImage.SetUseMesaClasses(1) |
105 |
|
|
|
106 |
|
|
# perform some preprocessing to find the global max of the vector data norm |
107 |
|
|
maxNorm = 0 |
108 |
|
|
if not interactive and preproc: |
109 |
|
|
print "Preprocessing vector data" |
110 |
|
|
sys.stdout.write("Completed: ") |
111 |
|
|
for i in range(numFrames): |
112 |
|
|
frameNum = eval(formatString) % i |
113 |
|
|
reader = vtk.vtkXMLUnstructuredGridReader() |
114 |
|
|
reader.SetFileName("%s/%s%s.%s" % (dirName,fnameStem,frameNum,extn)) |
115 |
|
|
reader.Update() |
116 |
|
|
|
117 |
|
|
grid = reader.GetOutput() |
118 |
|
|
norm = grid.GetPointData().GetVectors().GetMaxNorm() |
119 |
|
|
if norm > maxNorm: |
120 |
|
|
maxNorm = norm |
121 |
|
|
|
122 |
|
|
sys.stdout.write("%3.0f%%\b\b\b\b" % (float(i)/float(numFrames), )) |
123 |
|
|
print "" |
124 |
|
|
|
125 |
|
|
for i in range(firstNum, numFrames+firstNum): |
126 |
|
|
|
127 |
|
|
frameNum = eval(formatString) % i |
128 |
|
|
reader = vtk.vtkXMLUnstructuredGridReader() |
129 |
|
|
reader.SetFileName("%s/%s%s.%s" % (dirName,fnameStem,frameNum,extn)) |
130 |
|
|
reader.Update() |
131 |
|
|
|
132 |
|
|
print "Processing %s" % fnames[i] |
133 |
|
|
|
134 |
|
|
grid = reader.GetOutput() |
135 |
|
|
|
136 |
|
|
# grab the model centre and bounds |
137 |
|
|
centre = grid.GetCenter() |
138 |
|
|
bounds = grid.GetBounds() |
139 |
|
|
|
140 |
|
|
# grab the norm of the vectors |
141 |
|
|
norm = vtk.vtkVectorNorm() |
142 |
|
|
norm.SetInput(grid) |
143 |
|
|
|
144 |
|
|
if not preproc: |
145 |
|
|
maxNorm = grid.GetPointData().GetVectors().GetMaxNorm() |
146 |
|
|
|
147 |
|
|
# to make arrow glyphs need an arrow source |
148 |
|
|
arrow = vtk.vtkArrowSource() |
149 |
|
|
|
150 |
|
|
# the arrows are 3D glyphs so set that up now |
151 |
|
|
glyph = vtk.vtkGlyph3D() |
152 |
|
|
glyph.ScalingOn() |
153 |
|
|
glyph.SetScaleModeToScaleByScalar() |
154 |
|
|
glyph.SetColorModeToColorByScalar() |
155 |
|
|
glyph.SetVectorModeToUseVector() |
156 |
|
|
glyph.SetScaleFactor(0.1/maxNorm) |
157 |
|
|
glyph.SetInput(norm.GetOutput()) |
158 |
|
|
glyph.SetSource(arrow.GetOutput()) |
159 |
|
|
glyph.ClampingOff() |
160 |
|
|
|
161 |
|
|
# set up a stripper to speed up rendening |
162 |
|
|
stripper = vtk.vtkStripper() |
163 |
|
|
stripper.SetInput(glyph.GetOutput()) |
164 |
|
|
|
165 |
|
|
# make a lookup table for the colour map and invert it (colours look |
166 |
|
|
# better when it's inverted) |
167 |
|
|
lut = vtk.vtkLookupTable() |
168 |
|
|
refLut = vtk.vtkLookupTable() |
169 |
|
|
lut.Build() |
170 |
|
|
refLut.Build() |
171 |
|
|
for j in range(256): |
172 |
|
|
lut.SetTableValue(j, refLut.GetTableValue(255-j)) |
173 |
|
|
|
174 |
|
|
# set up the mapper |
175 |
|
|
mapper = vtk.vtkPolyDataMapper() |
176 |
|
|
mapper.SetInput(stripper.GetOutput()) |
177 |
|
|
mapper.SetScalarRange(0,maxNorm) |
178 |
|
|
mapper.SetLookupTable(lut) |
179 |
|
|
|
180 |
|
|
# set up the actor |
181 |
|
|
actor = vtk.vtkActor() |
182 |
|
|
actor.SetMapper(mapper) |
183 |
|
|
|
184 |
|
|
# set up the text properties for nice text |
185 |
|
|
font_size = 20 |
186 |
|
|
textProp = vtk.vtkTextProperty() |
187 |
|
|
textProp.SetFontSize(font_size) |
188 |
|
|
textProp.SetFontFamilyToArial() |
189 |
|
|
textProp.BoldOff() |
190 |
|
|
textProp.ItalicOff() |
191 |
|
|
textProp.ShadowOff() |
192 |
|
|
textProp.SetColor(0.0, 0.0, 0.0) |
193 |
|
|
|
194 |
|
|
# make a title |
195 |
|
|
title = vtk.vtkTextMapper() |
196 |
|
|
title.SetInput("Velocity flow vectors in mantle convection") |
197 |
|
|
|
198 |
|
|
# make the title text use the text properties |
199 |
|
|
titleProp = title.GetTextProperty() |
200 |
|
|
titleProp.ShallowCopy(textProp) |
201 |
|
|
titleProp.SetJustificationToCentered() |
202 |
|
|
titleProp.SetVerticalJustificationToTop() |
203 |
|
|
titleProp.BoldOn() |
204 |
|
|
|
205 |
|
|
# make the actor for the title |
206 |
|
|
titleActor = vtk.vtkTextActor() |
207 |
|
|
titleActor.SetMapper(title) |
208 |
|
|
titleActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() |
209 |
|
|
titleActor.GetPositionCoordinate().SetValue(0.5, 0.95) |
210 |
|
|
|
211 |
|
|
# make a frame counter |
212 |
|
|
counter = vtk.vtkTextMapper() |
213 |
|
|
counter.SetInput("frame: %d" % i) |
214 |
|
|
|
215 |
|
|
# make the counter use the text properties |
216 |
|
|
counterProp = counter.GetTextProperty() |
217 |
|
|
counterProp.ShallowCopy(textProp) |
218 |
|
|
counterProp.SetJustificationToLeft() |
219 |
|
|
counterProp.SetVerticalJustificationToTop() |
220 |
|
|
counterProp.SetFontSize(14) |
221 |
|
|
|
222 |
|
|
# make the actor for the frame counter |
223 |
|
|
counterActor = vtk.vtkTextActor() |
224 |
|
|
counterActor.SetMapper(counter) |
225 |
|
|
counterActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedDisplay() |
226 |
|
|
counterActor.GetPositionCoordinate().SetValue(0.05, 0.8) |
227 |
|
|
|
228 |
|
|
# use a scalar bar |
229 |
|
|
scalarBar = vtk.vtkScalarBarActor() |
230 |
|
|
scalarBar.SetLookupTable(lut) |
231 |
|
|
scalarBar.SetWidth(0.1) |
232 |
|
|
scalarBar.SetHeight(0.7) |
233 |
|
|
scalarBar.SetPosition(0.9, 0.2) |
234 |
|
|
scalarBar.SetTitle("|v|") |
235 |
|
|
|
236 |
|
|
# set up its title text properties |
237 |
|
|
scalarBarProp = scalarBar.GetTitleTextProperty() |
238 |
|
|
scalarBarProp.ShallowCopy(textProp) |
239 |
|
|
scalarBarProp.SetFontSize(10) |
240 |
|
|
|
241 |
|
|
# set up the label text properties |
242 |
|
|
scalarBarTextProp = scalarBar.GetLabelTextProperty() |
243 |
|
|
scalarBarTextProp.ShallowCopy(textProp) |
244 |
|
|
scalarBarTextProp.SetFontSize(10) |
245 |
|
|
|
246 |
|
|
# put an outline around the data |
247 |
|
|
outline = vtk.vtkOutlineSource() |
248 |
|
|
outline.SetBounds(bounds) |
249 |
|
|
|
250 |
|
|
# make its mapper |
251 |
|
|
outlineMapper = vtk.vtkPolyDataMapper() |
252 |
|
|
outlineMapper.SetInput(outline.GetOutput()) |
253 |
|
|
|
254 |
|
|
# make its actor |
255 |
|
|
outlineActor = vtk.vtkActor() |
256 |
|
|
outlineActor.SetMapper(outlineMapper) |
257 |
|
|
outlineActor.GetProperty().SetColor(0,0,0) |
258 |
|
|
|
259 |
|
|
# set up the renderer and render window |
260 |
|
|
ren = vtk.vtkRenderer() |
261 |
|
|
renWin = vtk.vtkRenderWindow() |
262 |
|
|
|
263 |
|
|
renWin.SetSize(800,600) |
264 |
|
|
renWin.AddRenderer(ren) |
265 |
|
|
ren.SetBackground(1,1,1) |
266 |
|
|
|
267 |
|
|
# add the relevant actors |
268 |
|
|
ren.AddActor(actor) |
269 |
|
|
ren.AddActor(titleActor) |
270 |
|
|
ren.AddActor(counterActor) |
271 |
|
|
ren.AddActor(scalarBar) |
272 |
|
|
ren.AddActor(outlineActor) |
273 |
|
|
|
274 |
|
|
cam = ren.GetActiveCamera() |
275 |
|
|
cam.Azimuth(0) |
276 |
|
|
cam.Elevation(-90) |
277 |
|
|
cam.Zoom(1.2) |
278 |
|
|
ren.SetActiveCamera(cam) |
279 |
|
|
ren.ResetCameraClippingRange() |
280 |
|
|
|
281 |
|
|
# add some axes |
282 |
|
|
axes = vtk.vtkCubeAxesActor2D() |
283 |
|
|
axes.SetInput(grid) |
284 |
|
|
axes.SetCamera(ren.GetActiveCamera()) |
285 |
|
|
axes.SetLabelFormat("%6.4g") |
286 |
|
|
axes.SetFlyModeToOuterEdges() |
287 |
|
|
axes.SetFontFactor(0.8) |
288 |
|
|
axes.SetAxisTitleTextProperty(textProp) |
289 |
|
|
axes.SetAxisLabelTextProperty(textProp) |
290 |
|
|
axes.SetXLabel("x") |
291 |
|
|
axes.SetYLabel("y") |
292 |
|
|
axes.SetZLabel("z") |
293 |
|
|
axes.SetNumberOfLabels(5) |
294 |
|
|
axes.GetProperty().SetColor(0,0,0) |
295 |
|
|
ren.AddProp(axes) |
296 |
|
|
|
297 |
|
|
if interactive: |
298 |
|
|
# set up stuff for interactive viewing |
299 |
|
|
iren = vtk.vtkRenderWindowInteractor() |
300 |
|
|
iren.SetRenderWindow(renWin) |
301 |
|
|
|
302 |
|
|
iren.Initialize() |
303 |
|
|
renWin.Render() |
304 |
|
|
iren.Start() |
305 |
|
|
else: |
306 |
|
|
renWin.OffScreenRenderingOn() |
307 |
|
|
renWin.Render() |
308 |
|
|
|
309 |
|
|
# the WindowToImageFilter is what one uses to save the window to an |
310 |
|
|
# image file |
311 |
|
|
win2img = vtk.vtkWindowToImageFilter() |
312 |
|
|
win2img.SetInput(renWin) |
313 |
|
|
|
314 |
|
|
# set up the PNMWriter as we're saving to pnm |
315 |
|
|
writer = vtk.vtkPNMWriter() |
316 |
|
|
writer.SetFileName("%s%04d.pnm" % (fnameStem,i)) |
317 |
|
|
writer.SetInput(win2img.GetOutput()) |
318 |
|
|
writer.Write() |
319 |
|
|
|
320 |
|
|
print "Wrote %s%04d.pnm" % (fnameStem,i) |
321 |
|
|
|
322 |
|
|
# vim: expandtab shiftwidth=4: |