root / ase / visualize / vtk / pipeline.py @ 3
Historique | Voir | Annoter | Télécharger (6,74 ko)
1 | 1 | tkerber | |
---|---|---|---|
2 | 1 | tkerber | import numpy as np |
3 | 1 | tkerber | |
4 | 1 | tkerber | from vtk import vtkPolyDataMapper, vtkPolyDataNormals, \ |
5 | 1 | tkerber | vtkLinearSubdivisionFilter, vtkSmoothPolyDataFilter, \ |
6 | 1 | tkerber | vtkDepthSortPolyData, vtkAlgorithm, vtkAlgorithmOutput |
7 | 1 | tkerber | from ase.visualize.vtk.grid import vtkVolumeGrid |
8 | 1 | tkerber | |
9 | 1 | tkerber | # -------------------------------------------------------------------
|
10 | 1 | tkerber | |
11 | 1 | tkerber | class vtkPipeline: |
12 | 1 | tkerber | _branchable = False
|
13 | 1 | tkerber | |
14 | 1 | tkerber | def __init__(self, vtkish_data=None): |
15 | 1 | tkerber | |
16 | 1 | tkerber | self.vtkish_data = None |
17 | 1 | tkerber | self.closed = False |
18 | 1 | tkerber | self.pending = False |
19 | 1 | tkerber | self.filters = tuple() |
20 | 1 | tkerber | |
21 | 1 | tkerber | if vtkish_data is not None: |
22 | 1 | tkerber | self.set_data(vtkish_data)
|
23 | 1 | tkerber | |
24 | 1 | tkerber | def hasdata(self): |
25 | 1 | tkerber | return (self.vtkish_data is not None) |
26 | 1 | tkerber | |
27 | 1 | tkerber | def hasfilters(self): |
28 | 1 | tkerber | return len(self.filters)>0 |
29 | 1 | tkerber | |
30 | 1 | tkerber | def set_data(self, vtkish_data): |
31 | 1 | tkerber | |
32 | 1 | tkerber | assert vtkish_data is not None |
33 | 1 | tkerber | |
34 | 1 | tkerber | if self.hasdata(): |
35 | 1 | tkerber | raise RuntimeError('Pipeline already has input.') |
36 | 1 | tkerber | elif vtkish_data in self: |
37 | 1 | tkerber | raise ValueError('Pipeline loop detected.') |
38 | 1 | tkerber | |
39 | 1 | tkerber | if isinstance(vtkish_data, vtkPipeline): |
40 | 1 | tkerber | # The embedded pipeline takes over
|
41 | 1 | tkerber | vtkish_data.signal_close() |
42 | 1 | tkerber | |
43 | 1 | tkerber | self.vtkish_data = vtkish_data
|
44 | 1 | tkerber | |
45 | 1 | tkerber | if not self.hasfilters(): |
46 | 1 | tkerber | return
|
47 | 1 | tkerber | |
48 | 1 | tkerber | vtkish_inner = self.filters[0] |
49 | 1 | tkerber | |
50 | 1 | tkerber | if isinstance(vtkish_inner, vtkPipeline): |
51 | 1 | tkerber | vtkish_inner.set_data(vtkish_data) #TODO does this work?
|
52 | 1 | tkerber | else:
|
53 | 1 | tkerber | assert isinstance(vtkish_inner, vtkAlgorithm) |
54 | 1 | tkerber | |
55 | 1 | tkerber | if isinstance(vtkish_data, vtkPipeline): |
56 | 1 | tkerber | # The embedded pipeline takes over
|
57 | 1 | tkerber | vtkish_data.connect(vtkish_inner) |
58 | 1 | tkerber | else:
|
59 | 1 | tkerber | assert isinstance(vtkish_data, vtkAlgorithm) |
60 | 1 | tkerber | vtkish_inner.SetInputConnection(vtkish_data.GetOutputPort()) |
61 | 1 | tkerber | |
62 | 1 | tkerber | def isempty(self): |
63 | 1 | tkerber | return not self.hasdata() and not self.hasfilters() |
64 | 1 | tkerber | |
65 | 1 | tkerber | def isclosed(self): |
66 | 1 | tkerber | if self.pending: |
67 | 1 | tkerber | raise RuntimeError('Pipeline output port state is pending.') |
68 | 1 | tkerber | return self.closed |
69 | 1 | tkerber | |
70 | 1 | tkerber | def signal_close(self): |
71 | 1 | tkerber | if self.closed: |
72 | 1 | tkerber | raise RuntimeError('Pipeline output port is already closed.') |
73 | 1 | tkerber | elif not self._branchable: |
74 | 1 | tkerber | self.pending = True |
75 | 1 | tkerber | |
76 | 1 | tkerber | def get_output_port(self): |
77 | 1 | tkerber | if self.closed: |
78 | 1 | tkerber | raise RuntimeError('Pipeline output port is closed.') |
79 | 1 | tkerber | elif self.pending: |
80 | 1 | tkerber | self.closed = True |
81 | 1 | tkerber | self.pending = False |
82 | 1 | tkerber | |
83 | 1 | tkerber | if self.hasfilters(): |
84 | 1 | tkerber | vtkish_outer = self.filters[-1] |
85 | 1 | tkerber | elif self.hasdata(): |
86 | 1 | tkerber | vtkish_outer = self.vtkish_data
|
87 | 1 | tkerber | else:
|
88 | 1 | tkerber | raise RuntimeError('Pipeline output port unavailable.') |
89 | 1 | tkerber | |
90 | 1 | tkerber | if isinstance(vtkish_outer, vtkPipeline): |
91 | 1 | tkerber | return vtkish_outer.get_output_port()
|
92 | 1 | tkerber | else:
|
93 | 1 | tkerber | assert isinstance(vtkish_outer, vtkAlgorithm) |
94 | 1 | tkerber | return vtkish_outer.GetOutputPort()
|
95 | 1 | tkerber | |
96 | 1 | tkerber | def set_input_connection(self, vtk_port): |
97 | 1 | tkerber | assert isinstance(vtk_port, vtkAlgorithmOutput) |
98 | 1 | tkerber | |
99 | 1 | tkerber | vtkish_inner = self.filters[0] |
100 | 1 | tkerber | |
101 | 1 | tkerber | if isinstance(vtkish_inner, vtkPipeline): |
102 | 1 | tkerber | # Connect must be passed down
|
103 | 1 | tkerber | vtkish_inner.set_input_connection(vtk_port) |
104 | 1 | tkerber | else:
|
105 | 1 | tkerber | vtkish_inner.SetInputConnection(vtk_port) |
106 | 1 | tkerber | |
107 | 1 | tkerber | def connect(self, vtkish_filter): |
108 | 1 | tkerber | if vtkish_filter in self: |
109 | 1 | tkerber | raise ValueError('Pipeline loop detected.') |
110 | 1 | tkerber | |
111 | 1 | tkerber | if isinstance(vtkish_filter, vtkPipeline): |
112 | 1 | tkerber | # Connection must be passed down
|
113 | 1 | tkerber | if not self.isempty(): |
114 | 1 | tkerber | vtkish_filter.set_input_connection(self.get_output_port())
|
115 | 1 | tkerber | |
116 | 1 | tkerber | # The containing pipeline takes over
|
117 | 1 | tkerber | vtkish_filter.signal_close() |
118 | 1 | tkerber | |
119 | 1 | tkerber | elif not self.isempty(): |
120 | 1 | tkerber | assert isinstance(vtkish_filter, vtkAlgorithm) |
121 | 1 | tkerber | vtkish_filter.SetInputConnection(self.get_output_port())
|
122 | 1 | tkerber | |
123 | 1 | tkerber | def append(self, vtkish_filter): |
124 | 1 | tkerber | self.connect(vtkish_filter)
|
125 | 1 | tkerber | self.filters += (vtkish_filter,)
|
126 | 1 | tkerber | |
127 | 1 | tkerber | def extend(self, vtkish_filters): |
128 | 1 | tkerber | map(self.append, vtkish_filters) |
129 | 1 | tkerber | |
130 | 1 | tkerber | def __contains__(self, vtkish_candidate): |
131 | 1 | tkerber | if vtkish_candidate == self: |
132 | 1 | tkerber | return True |
133 | 1 | tkerber | |
134 | 1 | tkerber | if self.hasdata(): |
135 | 1 | tkerber | if isinstance(self.vtkish_data, vtkPipeline): |
136 | 1 | tkerber | if vtkish_candidate in self.vtkish_data: |
137 | 1 | tkerber | return True |
138 | 1 | tkerber | else:
|
139 | 1 | tkerber | if vtkish_candidate == self.vtkish_data: |
140 | 1 | tkerber | return True |
141 | 1 | tkerber | |
142 | 1 | tkerber | if vtkish_candidate in self.filters: |
143 | 1 | tkerber | return True |
144 | 1 | tkerber | |
145 | 1 | tkerber | for vtkish_filter in self.filters: |
146 | 1 | tkerber | if isinstance(vtkish_filter, vtkPipeline) \ |
147 | 1 | tkerber | and vtkish_candidate in vtkish_filter: |
148 | 1 | tkerber | return True |
149 | 1 | tkerber | |
150 | 1 | tkerber | return False |
151 | 1 | tkerber | |
152 | 1 | tkerber | def __getitem__(self, i): #TODO XXX this is a hack |
153 | 1 | tkerber | return self.filters[i] |
154 | 1 | tkerber | |
155 | 1 | tkerber | # -------------------------------------------------------------------
|
156 | 1 | tkerber | |
157 | 1 | tkerber | class vtkPolyDataPipeline(vtkPipeline): |
158 | 1 | tkerber | def __init__(self, vtkish_polydata=None): |
159 | 1 | tkerber | vtkPipeline.__init__(self, vtkish_polydata)
|
160 | 1 | tkerber | |
161 | 1 | tkerber | def connect(self, vtkish_filter): |
162 | 1 | tkerber | if isinstance(vtkish_filter, vtkPolyDataMapper): |
163 | 1 | tkerber | self.signal_close()
|
164 | 1 | tkerber | vtkPipeline.connect(self, vtkish_filter)
|
165 | 1 | tkerber | |
166 | 1 | tkerber | class vtkSurfaceSmootherPipeline(vtkPolyDataPipeline): |
167 | 1 | tkerber | def __init__(self, grid, vtkish_polydata=None, angle=15): |
168 | 1 | tkerber | |
169 | 1 | tkerber | vtkPolyDataPipeline.__init__(self, vtkish_polydata)
|
170 | 1 | tkerber | |
171 | 1 | tkerber | # Make sure grid argument is correct type
|
172 | 1 | tkerber | assert isinstance(grid, vtkVolumeGrid) |
173 | 1 | tkerber | self.grid = grid
|
174 | 1 | tkerber | |
175 | 1 | tkerber | # Split polys with intersection angles greater than angle
|
176 | 1 | tkerber | vtk_dnorm = vtkPolyDataNormals() |
177 | 1 | tkerber | vtk_dnorm.SetFeatureAngle(angle) |
178 | 1 | tkerber | vtk_dnorm.SplittingOn() |
179 | 1 | tkerber | vtk_dnorm.ComputeCellNormalsOff() |
180 | 1 | tkerber | vtk_dnorm.ComputePointNormalsOff() |
181 | 1 | tkerber | self.append(vtk_dnorm)
|
182 | 1 | tkerber | |
183 | 1 | tkerber | relax = self.grid.get_relaxation_factor()
|
184 | 1 | tkerber | |
185 | 1 | tkerber | if relax is not None: |
186 | 1 | tkerber | print 'relax=',relax |
187 | 1 | tkerber | #vtk_subdiv = vtkButterflySubdivisionFilter()
|
188 | 1 | tkerber | vtk_subdiv = vtkLinearSubdivisionFilter() |
189 | 1 | tkerber | self.append(vtk_subdiv)
|
190 | 1 | tkerber | |
191 | 1 | tkerber | # Smooth out some of the sharp points.
|
192 | 1 | tkerber | vtk_smooth = vtkSmoothPolyDataFilter() |
193 | 1 | tkerber | vtk_smooth.SetRelaxationFactor(relax) |
194 | 1 | tkerber | self.append(vtk_smooth)
|
195 | 1 | tkerber | |
196 | 1 | tkerber | class vtkDepthSortPipeline(vtkPolyDataPipeline): |
197 | 1 | tkerber | def __init__(self, vtk_renderer, vtkish_polydata=None): |
198 | 1 | tkerber | |
199 | 1 | tkerber | vtkPolyDataPipeline.__init__(self, vtkish_polydata)
|
200 | 1 | tkerber | |
201 | 1 | tkerber | # The depht sort object is set up to generate scalars representing
|
202 | 1 | tkerber | # the sort depth. A camera is assigned for the sorting. The camera
|
203 | 1 | tkerber | # defines the sort vector (position and focal point).
|
204 | 1 | tkerber | vtk_ds = vtkDepthSortPolyData() |
205 | 1 | tkerber | vtk_ds.SetCamera(vtk_renderer.GetActiveCamera()) |
206 | 1 | tkerber | vtk_ds.SetDirectionToBackToFront() |
207 | 1 | tkerber | #vtk_ds.SetVector(1, 1, 1)
|
208 | 1 | tkerber | #vtk_ds.SortScalarsOn()
|
209 | 1 | tkerber | #vtk_ds.Update()
|
210 | 1 | tkerber | self.append(vtk_ds)
|
211 | 1 | tkerber | |
212 | 1 | tkerber | vtk_renderer.ResetCamera() |