glTF: Bump version after we enter 4.1 alpha
[blender-addons.git] / render_povray / voxel_lib.py
blobfd19a42060e31a92cf8dbb7fb1f8fb5c9335be5d
1 # SPDX-FileCopyrightText: 2005 `Mike Kost <contact@povray.tashcorp.net>`
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 ################################################################################
7 # df3.py
9 # -----------------------------------------------------------------------------
11 # Creation functions
12 # __init__(x=1, y=1, z=1) : default constructor
13 # clone(indf3) : make this df3 look like indf3
15 # Info functions
16 # sizeX(): returns X dimension
17 # sizeY(): returns Y dimension
18 # sizeZ(): returns Z dimension
20 # Scalar functions
21 # mult():
22 # add():
23 # max(): returns highest voxel value in df3
24 # min(): returns lowest voxel value in df3
26 # Vector functions
28 # Import/Export functions
29 # exportDF3():
30 # importDF3():
32 # -----------------------------------------------------------------------------
34 import struct
35 import os
36 import stat
37 import array
39 # -+-+-+- Start df3 Class -+-+-+-
42 class df3:
43 __version__ = '0.2'
45 __arraytype__ = 'f'
47 __struct4byte__ = '>I'
48 __struct2byte__ = '>H'
49 __struct2byte3__ = '>HHH'
50 __struct1byte__ = '>B'
51 __array4byte__ = 'I'
52 __array2byte__ = 'H'
53 __array1byte__ = 'B'
55 def __init__(self, x=1, y=1, z=1):
56 self.maxX = x
57 self.maxY = y
58 self.maxZ = z
59 self.voxel = self.__create__(x, y, z)
61 def clone(self, indf3):
62 self.voxel = array.array(self.__arraytype__)
63 for i in range(indf3.sizeX() * indf3.sizeY() * indf3.sizeZ()):
64 self.voxel[i] = indf3.voxel[i]
65 return self
67 # --- Info Functions
69 def sizeX(self):
70 return self.maxX
72 def sizeY(self):
73 return self.maxY
75 def sizeZ(self):
76 return self.maxZ
78 def size(self):
79 tmp = [self.sizeX()]
80 tmp.append(self.sizeY())
81 tmp.append(self.sizeZ())
82 return tmp
84 # --- Voxel Access Functions
86 def get(self, x, y, z):
87 return self.voxel[self.__voxa__(x, y, z)]
89 def getB(self, x, y, z):
90 if x > self.sizeX() or x < 0:
91 return 0
92 if y > self.sizeX() or y < 0:
93 return 0
94 if z > self.sizeX() or z < 0:
95 return 0
97 return self.voxel[self.__voxa__(x, y, z)]
99 def set(self, x, y, z, val):
100 self.voxel[self.__voxa__(x, y, z)] = val
102 def setB(self, x, y, z, val):
103 if x > self.sizeX() or x < 0:
104 return
105 if y > self.sizeX() or y < 0:
106 return
107 if z > self.sizeX() or z < 0:
108 return
110 self.voxel[self.__voxa__(x, y, z)] = val
112 # --- Scalar Functions
114 def mult(self, val):
115 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
116 self.voxel[i] = self.voxel[i] * val
118 return self
120 def add(self, val):
121 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
122 self.voxel[i] = self.voxel[i] + val
124 return self
126 def max(self):
127 tmp = self.voxel[0]
129 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
130 if self.voxel[i] > tmp:
131 tmp = self.voxel[i]
133 return tmp
135 def min(self):
136 tmp = self.voxel[0]
138 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
139 if self.voxel[i] < tmp:
140 tmp = self.voxel[i]
142 return tmp
144 # --- Vector Functions
146 def compare(self, indf3):
147 if self.__samesize__(indf3) == 0:
148 return 0
150 if self.voxel == indf3.voxel:
151 return 1
153 return 0
155 def multV(self, indf3):
156 if self.__samesize__(indf3) == 0:
157 print("Cannot multiply voxels - not same size")
158 return
160 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
161 self.voxel[i] = self.voxel[i] * indf3.voxel[i]
163 return self
165 def addV(self, indf3):
166 if self.__samesize__(indf3) == 0:
167 print("Cannot add voxels - not same size")
168 return
170 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
171 self.voxel[i] = self.voxel[i] + indf3.voxel[i]
173 return self
175 def convolveV(self, filt):
176 fx = filt.sizeX()
177 fy = filt.sizeY()
178 fz = filt.sizeZ()
179 if fx % 2 != 1:
180 print("Incompatible filter - must be odd number of X")
181 return self
182 if fy % 2 != 1:
183 print("Incompatible filter - must be odd number of Y")
184 return self
185 if fz % 2 != 1:
186 print("Incompatible filter - must be odd number of Z")
187 return self
189 fdx = (fx - 1) / 2
190 fdy = (fy - 1) / 2
191 fdz = (fz - 1) / 2
192 flen = fx * fy * fz
194 newV = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ())
196 for x in range(self.sizeX()):
197 for y in range(self.sizeY()):
198 for z in range(self.sizeZ()):
199 rip = self.__rip__(x - fdx, x + fdx, y - fdy, y + fdy, z - fdz, z + fdz)
200 tmp = 0.0
201 for i in range(flen):
202 tmp += rip[i] * filt.voxel[i]
203 newV[self.__voxa__(x, y, z)] = tmp
205 self.voxel = newV
207 return self
209 # --- Import/Export Functions
211 def exportDF3(self, file, depth=8, rescale=1):
212 x = self.sizeX()
213 y = self.sizeY()
214 z = self.sizeZ()
216 try:
217 f = open(file, 'wb')
218 except BaseException as e:
219 print(e.__doc__)
220 print('An exception occurred: {}'.format(e))
221 print("Could not open " + file + " for write")
222 return
224 f.write(struct.pack(self.__struct2byte3__, x, y, z))
226 tmp = self.__toInteger__(pow(2, depth) - 1, rescale)
228 if depth > 16: # 32-bit
229 for i in range(x * y * z):
230 f.write(struct.pack(self.__struct4byte__, tmp[i]))
231 elif depth > 8: # 16-bit
232 for i in range(x * y * z):
233 f.write(struct.pack(self.__struct2byte__, tmp[i]))
234 else:
235 for i in range(x * y * z):
236 f.write(struct.pack(self.__struct1byte__, tmp[i]))
238 def importDF3(self, file, scale=1):
239 try:
240 f = open(file, 'rb')
241 size = os.stat(file)[stat.ST_SIZE]
243 except BaseException as e:
244 print(e.__doc__)
245 print('An exception occurred: {}'.format(e))
246 print("Could not open " + file + " for read")
247 return []
249 (x, y, z) = struct.unpack(self.__struct2byte3__, f.read(6))
251 self.voxel = self.__create__(x, y, z)
252 self.maxX = x
253 self.maxY = y
254 self.maxZ = z
256 size = size - 6
257 if size == x * y * z:
258 format = 8
259 elif size == 2 * x * y * z:
260 format = 16
261 elif size == 4 * x * y * z:
262 format = 32
264 for i in range(x * y * z):
265 if format == 32:
266 self.voxel[i] = float(struct.unpack(self.__struct4byte__, f.read(4))[0])
267 elif format == 16:
268 self.voxel[i] = float(struct.unpack(self.__struct2byte__, f.read(2))[0])
269 elif format == 8:
270 self.voxel[i] = float(struct.unpack(self.__struct1byte__, f.read(1))[0])
272 return self
274 # --- Local classes not intended for user use
276 def __rip__(self, minX, maxX, minY, maxY, minZ, maxZ):
277 sizeX = maxX - minX + 1
278 sizeY = maxY - minY + 1
279 sizeZ = maxZ - minZ + 1
281 tmpV = self.__create__(sizeX, sizeY, sizeZ)
283 for x in range(sizeX):
284 for y in range(sizeY):
285 for z in range(sizeZ):
286 # Check X
287 if (minX + x) < 0:
288 tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
289 elif (minX + x) > self.sizeX() - 1:
290 tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
291 # Check Y
292 elif (minY + y) < 0:
293 tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
294 elif (minY + y) > self.sizeY() - 1:
295 tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
296 # Check Z
297 elif (minZ + z) < 0:
298 tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
299 elif (minZ + z) > self.sizeZ() - 1:
300 tmpV[(z * sizeZ + y) * sizeY + x] = 0.0
301 else:
302 tmpV[(z * sizeZ + y) * sizeY + x] = self.get(minX + x, minY + y, minZ + z)
304 return tmpV
306 def __samesize__(self, indf3):
307 if self.sizeX() != indf3.sizeX():
308 return 0
309 if self.sizeY() != indf3.sizeY():
310 return 0
311 if self.sizeZ() != indf3.sizeZ():
312 return 0
313 return 1
315 def __voxa__(self, x, y, z):
316 return (z * self.sizeY() + y) * self.sizeX() + x
318 def __create__(self, x, y, z, atype='0', init=1):
319 if atype == '0':
320 tmp = self.__arraytype__
321 else:
322 tmp = atype
324 if init == 1:
325 if tmp in ('f', 'd'):
326 voxel = array.array(tmp, [0.0 for i in range(x * y * z)])
327 else:
328 voxel = array.array(tmp, [0 for i in range(x * y * z)])
329 else:
330 voxel = array.array(tmp)
332 return voxel
334 def __toInteger__(self, scale, rescale=1):
335 if scale < pow(2, 8): # 8-bit
336 tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array1byte__)
337 elif scale < pow(2, 16): # 16-bit
338 tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array2byte__)
339 else: # 32-bit
340 tmp = self.__create__(self.sizeX(), self.sizeY(), self.sizeZ(), self.__array4byte__)
342 maxVal = self.max()
344 print(scale)
346 for i in range(self.sizeX() * self.sizeY() * self.sizeZ()):
347 if rescale == 1:
348 tmp[i] = max(0, int(round(scale * self.voxel[i] / maxVal)))
349 else:
350 tmp[i] = max(0, min(scale, int(round(self.voxel[i]))))
352 return tmp
355 # -=-=-=- End df3 Class -=-=-=-
356 # --------DEFAULT EXAMPLES
357 # if __name__ == '__main__':
358 # localX = 80
359 # localY = 90
360 # localZ = 100
361 # -- Generate an output
362 # temp = df3(localX, localY, localZ)
364 # for i in range(localX):
365 # for j in range(localY):
366 # for k in range(localZ):
367 # if (i >= (localX/2)):
368 # temp.set(i, j, k, 1.0)
370 # temp.exportDF3('temp.df3', 16)
371 # -----------------------------------------------------------------------------
372 # -- Import
373 # temp2 = df3().importDF3('temp.df3')
374 # temp2.mult(1/temp2.max())
376 # -- Compare
377 # print(temp2.size())
379 # if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
381 # -----------------------------------------------------------------------------
382 # ChangeLog
383 # ---------
384 # 08/09/05: 0.20 released
385 # + Change internal representation to floating point
386 # + Rewrite import/export for speed
387 # + Convert from 3-d list structure to Array class for data storage
388 # + Add element access, scalar, and vector functions
389 # 07/13/05: 0.10 released
390 # -----------------------------------------------------------------------------