3
3
4
4
import numpy as np
5
5
6
-
6
+ import pylab
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}
@@ -53,11 +53,16 @@ def writeSTL(facets, file_name, ascii=False):
53
53
f .close ()
54
54
55
55
56
+ def roll2d (image , shifts ):
57
+ return np .roll (np .roll (image , shifts [0 ], axis = 0 ), shifts [1 ], axis = 1 )
58
+
59
+
56
60
def numpy2stl (A , fn , scale = 0.1 , mask_val = - np .inf , ascii = False ,
57
61
calc_normals = False ,
58
62
max_width = 235. ,
59
63
max_depth = 140. ,
60
- max_height = 150. ):
64
+ max_height = 150. ,
65
+ solid = True ):
61
66
"""
62
67
Reads a numpy array, and outputs an STL file
63
68
@@ -91,6 +96,7 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
91
96
A = scale * (A - A .min ())
92
97
93
98
facets = []
99
+ mask = np .zeros ((m , n ))
94
100
for i , k in product (range (m - 1 ), range (n - 1 )):
95
101
96
102
this_pt = np .array ([i - m / 2. , k - n / 2. , A [i , k ]])
@@ -111,16 +117,47 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
111
117
if (this_pt [- 1 ] > mask_val and top_right [- 1 ] > mask_val and
112
118
bottom_left [- 1 ] > mask_val ):
113
119
114
- facet = np .concatenate ([n1 , top_right , this_pt , bottom_left ])
120
+ facet = np .concatenate ([n1 , top_right , this_pt , bottom_right ])
121
+ mask [i , k ] = 1
122
+ mask [i , k + 1 ] = 1
123
+ mask [i + 1 , k ] = 1
115
124
facets .append (facet )
116
125
117
126
if (this_pt [- 1 ] > mask_val and bottom_right [- 1 ] > mask_val and
118
127
bottom_left [- 1 ] > mask_val ):
119
128
120
129
facet = np .concatenate ([n2 , bottom_right , this_pt , bottom_left ])
121
130
facets .append (facet )
131
+ mask [i , k ] = 1
132
+ mask [i + 1 , k + 1 ] = 1
133
+ mask [i + 1 , k ] = 1
122
134
facets = np .array (facets )
123
135
136
+ if solid :
137
+ edge_mask = np .sum ([roll2d (mask , (i , k ))
138
+ for i , k in product ([- 1 , 0 , 1 ], repeat = 2 )], axis = 0 )
139
+ edge_mask [np .where (edge_mask == 9. )] = 0.
140
+ edge_mask [np .where (edge_mask != 0. )] = 1.
141
+ edge_mask [0 ::m - 1 ,:] = 1.
142
+ edge_mask [:, 0 ::n - 1 ] = 1.
143
+ X , Y = np .where (edge_mask == 1. )
144
+ 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]
147
+ bottom = []
148
+ for i , facet in enumerate (facets ):
149
+ if (facet [3 ], facet [4 ]) in locs :
150
+ facets [i ][5 ] = minval
151
+ if (facet [6 ], facet [7 ]) in locs :
152
+ facets [i ][8 ] = minval
153
+ if (facet [9 ], facet [10 ]) in locs :
154
+ facets [i ][11 ] = minval
155
+ this_bottom = np .concatenate (
156
+ [facet [:3 ], facet [6 :8 ], [minval ], facet [3 :5 ], [minval ], facet [9 :11 ], [minval ]])
157
+ bottom .append (this_bottom )
158
+
159
+ facets = np .concatenate ([facets , bottom ])
160
+
124
161
xsize = facets [:, 3 ::3 ].ptp ()
125
162
if xsize > max_width :
126
163
facets = facets * float (max_width ) / xsize
@@ -134,3 +171,11 @@ def numpy2stl(A, fn, scale=0.1, mask_val=-np.inf, ascii=False,
134
171
facets = facets * float (max_height ) / zsize
135
172
136
173
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