forked from orbingol/NURBS-Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path_voxelize.py
170 lines (136 loc) · 5.13 KB
/
_voxelize.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
"""
.. module:: _voxelize
:platform: Unix, Windows
:synopsis: Helper functions for voxelization module
.. moduleauthor:: Onur Rauf Bingol <orbingol@gmail.com>
"""
from functools import partial
from . import linalg
from ._utilities import pool_context
from .exceptions import GeomdlException
# Initialize an empty __all__ for controlling imports
__all__ = []
def find_inouts_st(voxel_grid, datapts, **kwargs):
""" Single-threaded ins and outs finding (default)
:param voxel_grid: voxel grid
:param datapts: data points
:return: in-outs
"""
tol = kwargs.get('tol', 10e-8)
filled = [0 for _ in range(len(voxel_grid))]
for idx, bb in enumerate(voxel_grid):
pts_inside = is_point_inside_voxel(bb, datapts, tol=tol)
if pts_inside:
filled[idx] = 1
return filled
def find_inouts_mp(voxel_grid, datapts, **kwargs):
""" Multi-threaded ins and outs finding (using multiprocessing)
:param voxel_grid: voxel grid
:param datapts: data points
:return: in-outs
"""
tol = kwargs.get('tol', 10e-8)
num_procs = kwargs.get('num_procs', 4)
with pool_context(processes=num_procs) as pool:
filled = pool.map(partial(is_point_inside_voxel, ptsarr=datapts, tol=tol), voxel_grid)
return filled
def generate_voxel_grid(bbox, szval, use_cubes=False):
""" Generates the voxel grid with the desired size.
:param bbox: bounding box
:type bbox: list, tuple
:param szval: size in x-, y-, z-directions
:type szval: list, tuple
:param use_cubes: use cube voxels instead of cuboid ones
:type use_cubes: bool
:return: voxel grid
:rtype: list
"""
# Input validation
if szval[0] <= 1 or szval[1] <= 1 or szval[2] <= 1:
raise GeomdlException("Size values must be bigger than 1", data=dict(sizevals=szval))
# Find step size for each direction
steps = [float(bbox[1][idx] - bbox[0][idx]) / float(szval[idx] - 1) for idx in range(0, 3)]
# It is possible to use cubes instead of cuboids
if use_cubes:
min_val = min(*steps)
steps = [min_val for _ in range(0, 3)]
# Find range in each direction
ranges = [list(linalg.frange(bbox[0][idx], bbox[1][idx], steps[idx])) for idx in range(0, 3)]
voxel_grid = []
for u in ranges[0]:
for v in ranges[1]:
for w in ranges[2]:
bbmin = [u, v, w]
bbmax = [k + l for k, l in zip(bbmin, steps)]
voxel_grid.append([bbmin, bbmax])
return voxel_grid
def is_point_inside_voxel(bbox, ptsarr, **kwargs):
""" Finds if any point is contained inside the voxel boundaries (inouts array).
Ref: https://math.stackexchange.com/a/1552579
:param bbox: bounding box of the voxel
:type bbox: list, tuple
:param ptsarr: points to be checked
:type ptsarr: list, tuple
:return: list of ins and outs
:rtype: list
"""
# Get keyword arguments
tol = kwargs.get('tol', 10e-8) # padding value
# Make bounding box vertices more readable
bbmin = [b - tol for b in bbox[0]]
bbmax = [b + tol for b in bbox[1]]
# Find basis vectors
i = [bbmax[0] - bbmin[0], 0, 0]
j = [0, bbmax[1] - bbmin[1], 0]
k = [0, 0, bbmax[2] - bbmin[2]]
# Find dot products
idi = linalg.vector_dot(i, i)
jdj = linalg.vector_dot(j, j)
kdk = linalg.vector_dot(k, k)
for pt in ptsarr:
v = [p - b for p, b in zip(pt, bbmin)]
# Bigger than and equal to will include the border and,
# since we have a padding on the boundary box, we only
# need to include the lower boundary below
vdi = linalg.vector_dot(v, i)
vdj = linalg.vector_dot(v, j)
vdk = linalg.vector_dot(v, k)
if idi > vdi >= 0.0 and jdj > vdj >= 0.0 and kdk > vdk >= 0.0:
return 1
return 0
def get_points_inside_voxel(bbox, ptsarr, **kwargs):
""" Finds the list of points contained inside the voxel boundaries.
Ref: https://math.stackexchange.com/a/1552579
:param bbox: bounding box of the voxel
:type bbox: list, tuple
:param ptsarr: points to be checked
:type ptsarr: list, tuple
:return: list of points inside the voxel
:rtype: list
"""
# Get keyword arguments
tol = kwargs.get('tol', 10e-8)
# Make bounding box vertices more readable
bbmin = [b - tol for b in bbox[0]]
bbmax = [b + tol for b in bbox[1]]
# Initialize an empty list
points_inside = []
# Find basis vectors
i = [bbmax[0] - bbmin[0], 0, 0]
j = [0, bbmax[1] - bbmin[1], 0]
k = [0, 0, bbmax[2] - bbmin[2]]
# Find dot products
idi = linalg.vector_dot(i, i)
jdj = linalg.vector_dot(j, j)
kdk = linalg.vector_dot(k, k)
for pt in ptsarr:
v = [p - b for p, b in zip(pt, bbmin)]
# Bigger than and equal to will include the border and,
# since we have a padding on the boundary box, we only
# need to include the lower boundary below
vdi = linalg.vector_dot(v, i)
vdj = linalg.vector_dot(v, j)
vdk = linalg.vector_dot(v, k)
if idi > vdi >= 0.0 and jdj > vdj >= 0.0 and kdk > vdk >= 0.0:
points_inside.append(pt)
return points_inside