3
3
4
4
import numpy as np
5
5
6
- import pylab
6
+
7
7
ASCII_FACET = """ facet normal {face[0]:e} {face[1]:e} {face[2]:e}
8
8
outer loop
9
9
vertex {face[3]:e} {face[4]:e} {face[5]:e}
@@ -62,7 +62,8 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
62
62
max_width = 235. ,
63
63
max_depth = 140. ,
64
64
max_height = 150. ,
65
- solid = True ):
65
+ solid = True ,
66
+ min_thickness_percent = 0.1 ):
66
67
"""
67
68
Reads a numpy array, and outputs an STL file
68
69
@@ -86,7 +87,14 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
86
87
object (in mm). Match this to
87
88
the dimensions of a 3D printer
88
89
platform
89
-
90
+ solid (bool): sets whether to create a solid geometry (with sides and
91
+ a bottom) or not.
92
+ min_thickness_percent (float) : when creating the solid bottom face, this
93
+ multiplier sets the minimum thickness in
94
+ the final geometry (shallowest interior
95
+ point to bottom face), as a percentage of
96
+ the thickness of the model computed up to
97
+ that point.
90
98
Returns: (None)
91
99
"""
92
100
m , n = A .shape
@@ -98,6 +106,7 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
98
106
facets = []
99
107
mask = np .zeros ((m , n ))
100
108
for i , k in product (range (m - 1 ), range (n - 1 )):
109
+ print ("Creating top mesh..." )
101
110
102
111
this_pt = np .array ([i - m / 2. , k - n / 2. , A [i , k ]])
103
112
top_right = np .array ([i - m / 2. , k + 1 - n / 2. , A [i , k + 1 ]])
@@ -134,17 +143,23 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
134
143
facets = np .array (facets )
135
144
136
145
if solid :
146
+ print ("Computed edges..." )
137
147
edge_mask = np .sum ([roll2d (mask , (i , k ))
138
148
for i , k in product ([- 1 , 0 , 1 ], repeat = 2 )], axis = 0 )
139
149
edge_mask [np .where (edge_mask == 9. )] = 0.
140
150
edge_mask [np .where (edge_mask != 0. )] = 1.
141
- edge_mask [0 ::m - 1 ,:] = 1.
151
+ edge_mask [0 ::m - 1 , :] = 1.
142
152
edge_mask [:, 0 ::n - 1 ] = 1.
143
153
X , Y = np .where (edge_mask == 1. )
144
154
locs = zip (X - m / 2. , Y - n / 2. )
145
- minval = facets [:, 5 ::3 ].min () - 0.1 * facets [:, 5 ::3 ].ptp ()
146
- #[0, 0, 0, 1, 1, z, 1, 1, z, 1, 1, z]
155
+
156
+ zvals = facets [:, 5 ::3 ]
157
+ zmin , zthickness = zvals .min (), zvals .ptp ()
158
+
159
+ minval = zmin - min_thickness_percent * zthickness
160
+
147
161
bottom = []
162
+ print ("Extending edges, creating bottom..." )
148
163
for i , facet in enumerate (facets ):
149
164
if (facet [3 ], facet [4 ]) in locs :
150
165
facets [i ][5 ] = minval
@@ -153,7 +168,8 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
153
168
if (facet [9 ], facet [10 ]) in locs :
154
169
facets [i ][11 ] = minval
155
170
this_bottom = np .concatenate (
156
- [facet [:3 ], facet [6 :8 ], [minval ], facet [3 :5 ], [minval ], facet [9 :11 ], [minval ]])
171
+ [facet [:3 ], facet [6 :8 ], [minval ], facet [3 :5 ], [minval ],
172
+ facet [9 :11 ], [minval ]])
157
173
bottom .append (this_bottom )
158
174
159
175
facets = np .concatenate ([facets , bottom ])
@@ -171,11 +187,3 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
171
187
facets = facets * float (max_height ) / zsize
172
188
173
189
writeSTL (facets , fn , ascii = ascii )
174
-
175
-
176
- if __name__ == "__main__" :
177
- from scipy .ndimage import gaussian_filter
178
- A = 256 * pylab .imread ("openmdao.png" )
179
- A = A [:,:, 0 ] + 1. * A [:,:, 3 ] # Compose some elements from RGBA to give depth
180
- A = gaussian_filter (A , 2 ) # smoothing
181
- numpy2stl (A , "OpenMDAO-logo.stl" , scale = 0.05 , mask_val = 1. )
0 commit comments