1 # SPDX-FileCopyrightText: 2005 `Mike Kost <contact@povray.tashcorp.net>`
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 ################################################################################
9 # -----------------------------------------------------------------------------
12 # __init__(x=1, y=1, z=1) : default constructor
13 # clone(indf3) : make this df3 look like indf3
16 # sizeX(): returns X dimension
17 # sizeY(): returns Y dimension
18 # sizeZ(): returns Z dimension
23 # max(): returns highest voxel value in df3
24 # min(): returns lowest voxel value in df3
28 # Import/Export functions
32 # -----------------------------------------------------------------------------
39 # -+-+-+- Start df3 Class -+-+-+-
47 __struct4byte__
= '>I'
48 __struct2byte__
= '>H'
49 __struct2byte3__
= '>HHH'
50 __struct1byte__
= '>B'
55 def __init__(self
, x
=1, y
=1, z
=1):
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
]
80 tmp
.append(self
.sizeY())
81 tmp
.append(self
.sizeZ())
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:
92 if y
> self
.sizeX() or y
< 0:
94 if z
> self
.sizeX() or z
< 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:
105 if y
> self
.sizeX() or y
< 0:
107 if z
> self
.sizeX() or z
< 0:
110 self
.voxel
[self
.__voxa
__(x
, y
, z
)] = val
112 # --- Scalar Functions
115 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
116 self
.voxel
[i
] = self
.voxel
[i
] * val
121 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
122 self
.voxel
[i
] = self
.voxel
[i
] + val
129 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
130 if self
.voxel
[i
] > tmp
:
138 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
139 if self
.voxel
[i
] < tmp
:
144 # --- Vector Functions
146 def compare(self
, indf3
):
147 if self
.__samesize
__(indf3
) == 0:
150 if self
.voxel
== indf3
.voxel
:
155 def multV(self
, indf3
):
156 if self
.__samesize
__(indf3
) == 0:
157 print("Cannot multiply voxels - not same size")
160 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
161 self
.voxel
[i
] = self
.voxel
[i
] * indf3
.voxel
[i
]
165 def addV(self
, indf3
):
166 if self
.__samesize
__(indf3
) == 0:
167 print("Cannot add voxels - not same size")
170 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
171 self
.voxel
[i
] = self
.voxel
[i
] + indf3
.voxel
[i
]
175 def convolveV(self
, filt
):
180 print("Incompatible filter - must be odd number of X")
183 print("Incompatible filter - must be odd number of Y")
186 print("Incompatible filter - must be odd number of Z")
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
)
201 for i
in range(flen
):
202 tmp
+= rip
[i
] * filt
.voxel
[i
]
203 newV
[self
.__voxa
__(x
, y
, z
)] = tmp
209 # --- Import/Export Functions
211 def exportDF3(self
, file, depth
=8, rescale
=1):
218 except BaseException
as e
:
220 print('An exception occurred: {}'.format(e
))
221 print("Could not open " + file + " for write")
224 f
.write(struct
.pack(self
.__struct
2byte
3__, 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
.__struct
4byte
__, tmp
[i
]))
231 elif depth
> 8: # 16-bit
232 for i
in range(x
* y
* z
):
233 f
.write(struct
.pack(self
.__struct
2byte
__, tmp
[i
]))
235 for i
in range(x
* y
* z
):
236 f
.write(struct
.pack(self
.__struct
1byte
__, tmp
[i
]))
238 def importDF3(self
, file, scale
=1):
241 size
= os
.stat(file)[stat
.ST_SIZE
]
243 except BaseException
as e
:
245 print('An exception occurred: {}'.format(e
))
246 print("Could not open " + file + " for read")
249 (x
, y
, z
) = struct
.unpack(self
.__struct
2byte
3__, f
.read(6))
251 self
.voxel
= self
.__create
__(x
, y
, z
)
257 if size
== x
* y
* z
:
259 elif size
== 2 * x
* y
* z
:
261 elif size
== 4 * x
* y
* z
:
264 for i
in range(x
* y
* z
):
266 self
.voxel
[i
] = float(struct
.unpack(self
.__struct
4byte
__, f
.read(4))[0])
268 self
.voxel
[i
] = float(struct
.unpack(self
.__struct
2byte
__, f
.read(2))[0])
270 self
.voxel
[i
] = float(struct
.unpack(self
.__struct
1byte
__, f
.read(1))[0])
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
):
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
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
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
302 tmpV
[(z
* sizeZ
+ y
) * sizeY
+ x
] = self
.get(minX
+ x
, minY
+ y
, minZ
+ z
)
306 def __samesize__(self
, indf3
):
307 if self
.sizeX() != indf3
.sizeX():
309 if self
.sizeY() != indf3
.sizeY():
311 if self
.sizeZ() != indf3
.sizeZ():
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):
320 tmp
= self
.__arraytype
__
325 if tmp
in ('f', 'd'):
326 voxel
= array
.array(tmp
, [0.0 for i
in range(x
* y
* z
)])
328 voxel
= array
.array(tmp
, [0 for i
in range(x
* y
* z
)])
330 voxel
= array
.array(tmp
)
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
.__array
1byte
__)
337 elif scale
< pow(2, 16): # 16-bit
338 tmp
= self
.__create
__(self
.sizeX(), self
.sizeY(), self
.sizeZ(), self
.__array
2byte
__)
340 tmp
= self
.__create
__(self
.sizeX(), self
.sizeY(), self
.sizeZ(), self
.__array
4byte
__)
346 for i
in range(self
.sizeX() * self
.sizeY() * self
.sizeZ()):
348 tmp
[i
] = max(0, int(round(scale
* self
.voxel
[i
] / maxVal
)))
350 tmp
[i
] = max(0, min(scale
, int(round(self
.voxel
[i
]))))
355 # -=-=-=- End df3 Class -=-=-=-
356 # --------DEFAULT EXAMPLES
357 # if __name__ == '__main__':
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 # -----------------------------------------------------------------------------
373 # temp2 = df3().importDF3('temp.df3')
374 # temp2.mult(1/temp2.max())
377 # print(temp2.size())
379 # if (temp.compare(temp2) == 0): print("DF3's Do Not Match")
381 # -----------------------------------------------------------------------------
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 # -----------------------------------------------------------------------------