Statistiques
| Révision :

root / ase / visualize / vtk / data.py @ 3

Historique | Voir | Annoter | Télécharger (7,12 ko)

1 1 tkerber
2 1 tkerber
import numpy as np
3 1 tkerber
from numpy.ctypeslib import ctypes
4 1 tkerber
5 1 tkerber
from vtk import vtkDataArray, vtkFloatArray, vtkDoubleArray
6 1 tkerber
7 1 tkerber
if ctypes is None:
8 1 tkerber
    class CTypesEmulator:
9 1 tkerber
        def __init__(self):
10 1 tkerber
            self._SimpleCData = np.number
11 1 tkerber
            self.c_float = np.float32
12 1 tkerber
            self.c_double = np.float64
13 1 tkerber
    try:
14 1 tkerber
        import ctypes
15 1 tkerber
    except ImportError:
16 1 tkerber
        ctypes = CTypesEmulator()
17 1 tkerber
18 1 tkerber
# -------------------------------------------------------------------
19 1 tkerber
20 1 tkerber
class vtkNumPyBuffer:
21 1 tkerber
    def __init__(self, data):
22 1 tkerber
        self.strbuf = data.tostring()
23 1 tkerber
        self.nitems = len(data.flat)
24 1 tkerber
25 1 tkerber
    def __len__(self):
26 1 tkerber
        return self.nitems
27 1 tkerber
28 1 tkerber
    def get_pointer(self):
29 1 tkerber
        # Any C/C++ method that requires a void * can be passed a Python
30 1 tkerber
        # string. No check is done to ensure that the string is the correct
31 1 tkerber
        # size, and the string's reference count is not incremented. Extreme
32 1 tkerber
        # caution should be applied when using this feature.
33 1 tkerber
        return self.strbuf
34 1 tkerber
35 1 tkerber
    def notify(self, obj, event):
36 1 tkerber
        if event == 'DeleteEvent':
37 1 tkerber
            del self.strbuf
38 1 tkerber
        else:
39 1 tkerber
            raise RuntimeError('Event not recognized.')
40 1 tkerber
41 1 tkerber
class vtkDataArrayFromNumPyBuffer:
42 1 tkerber
    def __init__(self, vtk_class, ctype, data=None):
43 1 tkerber
44 1 tkerber
        assert issubclass(ctype, ctypes._SimpleCData)
45 1 tkerber
        self.ctype = ctype
46 1 tkerber
47 1 tkerber
        self.vtk_da = vtk_class()
48 1 tkerber
        assert isinstance(self.vtk_da, vtkDataArray)
49 1 tkerber
        assert self.vtk_da.GetDataTypeSize() == np.nbytes[np.dtype(self.ctype)]
50 1 tkerber
51 1 tkerber
        if data is not None:
52 1 tkerber
            self.read_numpy_array(data)
53 1 tkerber
54 1 tkerber
    def read_numpy_array(self, data):
55 1 tkerber
56 1 tkerber
        if not isinstance(data, np.ndarray):
57 1 tkerber
            data = np.array(data, dtype=self.ctype)
58 1 tkerber
59 1 tkerber
        if data.dtype != self.ctype: # NB: "is not" gets it wrong
60 1 tkerber
            data = data.astype(self.ctype)
61 1 tkerber
62 1 tkerber
        self.vtk_da.SetNumberOfComponents(data.shape[-1])
63 1 tkerber
64 1 tkerber
        # Passing the void* buffer to the C interface does not increase
65 1 tkerber
        # its reference count, hence the buffer is deleted by Python when
66 1 tkerber
        # the reference count of the string from tostring reaches zero.
67 1 tkerber
        # Also, the boolean True tells VTK to save (not delete) the buffer
68 1 tkerber
        # when the VTK data array is deleted - we want Python to do this.
69 1 tkerber
        npybuf = vtkNumPyBuffer(data)
70 1 tkerber
        self.vtk_da.SetVoidArray(npybuf.get_pointer(), len(npybuf), True)
71 1 tkerber
        self.vtk_da.AddObserver('DeleteEvent', npybuf.notify)
72 1 tkerber
73 1 tkerber
    def get_output(self):
74 1 tkerber
        return self.vtk_da
75 1 tkerber
76 1 tkerber
    def copy(self):
77 1 tkerber
        vtk_da_copy = self.vtk_da.NewInstance()
78 1 tkerber
        vtk_da_copy.SetNumberOfComponents(self.vtk_da.GetNumberOfComponents())
79 1 tkerber
        vtk_da_copy.SetNumberOfTuples(self.vtk_da.GetNumberOfTuples())
80 1 tkerber
81 1 tkerber
        assert vtk_da_copy.GetSize() == self.vtk_da.GetSize()
82 1 tkerber
83 1 tkerber
        vtk_da_copy.DeepCopy(self.vtk_da)
84 1 tkerber
85 1 tkerber
        return vtk_da_copy
86 1 tkerber
87 1 tkerber
# -------------------------------------------------------------------
88 1 tkerber
89 1 tkerber
class vtkDataArrayFromNumPyArray(vtkDataArrayFromNumPyBuffer):
90 1 tkerber
    """Class for reading vtkDataArray from 1D or 2D NumPy array.
91 1 tkerber

92 1 tkerber
    This class can be used to generate a vtkDataArray from a NumPy array.
93 1 tkerber
    The NumPy array should be of the form <entries> x <number of components>
94 1 tkerber
    where 'number of components' indicates the number of components in
95 1 tkerber
    each entry in the vtkDataArray. Note that this form is also expected
96 1 tkerber
    even in the case of only a single component.
97 1 tkerber
    """
98 1 tkerber
    def __init__(self, vtk_class, ctype, data=None, buffered=True):
99 1 tkerber
100 1 tkerber
        self.buffered = buffered
101 1 tkerber
102 1 tkerber
        vtkDataArrayFromNumPyBuffer.__init__(self, vtk_class, ctype, data)
103 1 tkerber
104 1 tkerber
    def read_numpy_array(self, data):
105 1 tkerber
        """Read vtkDataArray from NumPy array"""
106 1 tkerber
107 1 tkerber
        if not isinstance(data, np.ndarray):
108 1 tkerber
            data = np.array(data, dtype=self.ctype)
109 1 tkerber
110 1 tkerber
        if data.dtype != self.ctype: # NB: "is not" gets it wrong
111 1 tkerber
            data = data.astype(self.ctype)
112 1 tkerber
113 1 tkerber
        if data.ndim == 1:
114 1 tkerber
            data = data[:, np.newaxis]
115 1 tkerber
        elif data.ndim != 2:
116 1 tkerber
            raise ValueError('Data must be a 1D or 2D NumPy array.')
117 1 tkerber
118 1 tkerber
        if self.buffered:
119 1 tkerber
            vtkDataArrayFromNumPyBuffer.read_numpy_array(self, data)
120 1 tkerber
        else:
121 1 tkerber
            self.vtk_da.SetNumberOfComponents(data.shape[-1])
122 1 tkerber
            self.vtk_da.SetNumberOfTuples(data.shape[0])
123 1 tkerber
124 1 tkerber
            for i, d_c in enumerate(data):
125 1 tkerber
                for c, d in enumerate(d_c):
126 1 tkerber
                    self.vtk_da.SetComponent(i, c, d)
127 1 tkerber
128 1 tkerber
class vtkFloatArrayFromNumPyArray(vtkDataArrayFromNumPyArray):
129 1 tkerber
    def __init__(self, data):
130 1 tkerber
        vtkDataArrayFromNumPyArray.__init__(self, vtkFloatArray,
131 1 tkerber
                                            ctypes.c_float, data)
132 1 tkerber
133 1 tkerber
class vtkDoubleArrayFromNumPyArray(vtkDataArrayFromNumPyArray):
134 1 tkerber
    def __init__(self, data):
135 1 tkerber
        vtkDataArrayFromNumPyArray.__init__(self, vtkDoubleArray,
136 1 tkerber
                                            ctypes.c_double, data)
137 1 tkerber
138 1 tkerber
# -------------------------------------------------------------------
139 1 tkerber
140 1 tkerber
class vtkDataArrayFromNumPyMultiArray(vtkDataArrayFromNumPyBuffer):
141 1 tkerber
    """Class for reading vtkDataArray from a multi-dimensional NumPy array.
142 1 tkerber

143 1 tkerber
    This class can be used to generate a vtkDataArray from a NumPy array.
144 1 tkerber
    The NumPy array should be of the form <gridsize> x <number of components>
145 1 tkerber
    where 'number of components' indicates the number of components in
146 1 tkerber
    each gridpoint in the vtkDataArray. Note that this form is also expected
147 1 tkerber
    even in the case of only a single component.
148 1 tkerber
    """
149 1 tkerber
    def __init__(self, vtk_class, ctype, data=None, buffered=True):
150 1 tkerber
151 1 tkerber
        self.buffered = buffered
152 1 tkerber
153 1 tkerber
        vtkDataArrayFromNumPyBuffer.__init__(self, vtk_class, ctype, data)
154 1 tkerber
155 1 tkerber
    def read_numpy_array(self, data):
156 1 tkerber
        """Read vtkDataArray from NumPy array"""
157 1 tkerber
158 1 tkerber
        if not isinstance(data, np.ndarray):
159 1 tkerber
            data = np.array(data, dtype=self.ctype)
160 1 tkerber
161 1 tkerber
        if data.dtype != self.ctype: # NB: "is not" gets it wrong
162 1 tkerber
            data = data.astype(self.ctype)
163 1 tkerber
164 1 tkerber
        if data.ndim <=2:
165 1 tkerber
            raise Warning('This is inefficient for 1D and 2D NumPy arrays. ' +
166 1 tkerber
                          'Use a vtkDataArrayFromNumPyArray subclass instead.')
167 1 tkerber
168 1 tkerber
        if self.buffered:
169 1 tkerber
            # This is less than ideal, but will not copy data (uses views).
170 1 tkerber
            # To get the correct ordering, the grid dimensions have to be
171 1 tkerber
            # transposed without moving the last dimension (the components).
172 1 tkerber
            n = data.ndim-1
173 1 tkerber
            for c in range(n//2):
174 1 tkerber
                data = data.swapaxes(c,n-1-c)
175 1 tkerber
176 1 tkerber
            vtkDataArrayFromNumPyBuffer.read_numpy_array(self, data)
177 1 tkerber
        else:
178 1 tkerber
            self.vtk_da.SetNumberOfComponents(data.shape[-1])
179 1 tkerber
            self.vtk_da.SetNumberOfTuples(np.prod(data.shape[:-1]))
180 1 tkerber
181 1 tkerber
            for c, d_T in enumerate(data.T):
182 1 tkerber
                for i, d in enumerate(d_T.flat):
183 1 tkerber
                    self.vtk_da.SetComponent(i, c, d)
184 1 tkerber
185 1 tkerber
class vtkFloatArrayFromNumPyMultiArray(vtkDataArrayFromNumPyMultiArray):
186 1 tkerber
    def __init__(self, data):
187 1 tkerber
        vtkDataArrayFromNumPyMultiArray.__init__(self, vtkFloatArray,
188 1 tkerber
                                                 ctypes.c_float, data)
189 1 tkerber
190 1 tkerber
class vtkDoubleArrayFromNumPyMultiArray(vtkDataArrayFromNumPyMultiArray):
191 1 tkerber
    def __init__(self, data):
192 1 tkerber
        vtkDataArrayFromNumPyMultiArray.__init__(self, vtkDoubleArray,
193 1 tkerber
                                                 ctypes.c_double, data)