15
15
Optionaly you can skin between the original and new faces to make a watertight solid object
18
# --------------------------------------------------------------------------
19
# Solidify Selection 1.0 by Campbell Barton (AKA Ideasman42)
20
# --------------------------------------------------------------------------
21
# ***** BEGIN GPL LICENSE BLOCK *****
23
# This program is free software; you can redistribute it and/or
24
# modify it under the terms of the GNU General Public License
25
# as published by the Free Software Foundation; either version 2
26
# of the License, or (at your option) any later version.
28
# This program is distributed in the hope that it will be useful,
29
# but WITHOUT ANY WARRANTY; without even the implied warranty of
30
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
# GNU General Public License for more details.
33
# You should have received a copy of the GNU General Public License
34
# along with this program; if not, write to the Free Software Foundation,
35
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37
# ***** END GPL LICENCE BLOCK *****
38
# --------------------------------------------------------------------------
19
40
from Blender import *
23
45
# reload(BPyMessages)
47
from BPyMathutils import angleToLength
25
49
# python 2.3 has no reversed() iterator. this will only work on lists and tuples
73
97
Ang= Mathutils.AngleBetweenVecs
77
# returns a length from an angle
79
# there is a hoz line at Y1 going to inf on both X ends, never moves (LINEA)
80
# down at Y0 is a unit length line point up at (angle) from X0,Y0 (LINEB)
81
# This function returns the length of LINEB at the point it would intersect LINEA
82
# - Use this for working out how long to make the vector - differencing it from surrounding faces,
84
from math import pi, sin, cos, sqrt
86
def lengthFromAngle(angle):
87
''' # Alredy accounted for
91
angle = 2*pi*angle/360
92
x,y = cos(angle), sin(angle)
94
# 0 d is hoz to the right.
99
return sqrt((x*x)+(y*y))
103
scn = Scene.GetCurrent()
104
ob = scn.objects.active
106
if not ob or ob.type != 'Mesh':
107
BPyMessages.Error_NoMeshActive()
110
me = ob.getData(mesh=1)
112
BPyMessages.Error_NoMeshMultiresEdit()
115
# Create the variables.
116
PREF_THICK = Draw.Create(-0.1)
117
PREF_SKIN_SIDES= Draw.Create(1)
118
PREF_REM_ORIG= Draw.Create(0)
121
('Thick:', PREF_THICK, -10, 10, 'Skin thickness in mesh space.'),\
122
('Skin Sides', PREF_SKIN_SIDES, 'Skin between the original and new faces.'),\
123
('Remove Original', PREF_REM_ORIG, 'Remove the selected faces after skinning.'),\
126
if not Draw.PupBlock('Solid Skin Selection', pup_block):
129
PREF_THICK= PREF_THICK.val
130
PREF_SKIN_SIDES= PREF_SKIN_SIDES.val
131
PREF_REM_ORIG= PREF_REM_ORIG.val
135
is_editmode = Window.EditMode()
136
if is_editmode: Window.EditMode(0)
100
def solidify(me, PREF_THICK, PREF_SKIN_SIDES=True, PREF_REM_ORIG=False, PREF_COLLAPSE_SIDES=False):
138
102
# Main code function
139
me = ob.getData(mesh=1)
140
103
me_faces = me.faces
141
104
faces_sel= [f for f in me_faces if f.sel]
144
106
BPyMesh.meshCalcNormals(me)
145
107
normals= [v.no for v in me.verts]
146
108
vertFaces= [[] for i in xrange(len(me.verts))]
238
200
edges[edgekey] = f, f_v, i, ROT_QUAD_INDEX[i+1]
239
201
del ROT_QUAD_INDEX, ROT_TRI_INDEX
203
# So we can remove doubles with edges only.
204
if PREF_COLLAPSE_SIDES:
242
207
# Edges are done. extrude the single user edges.
243
208
for edge_face_data in edges.itervalues():
244
209
if edge_face_data: # != None
245
210
f, f_v, i1, i2 = edge_face_data
246
211
v1i,v2i= f_v[i1].index, f_v[i2].index
247
# Now make a new Face
248
# skin_side_faces.append( (v1i, v2i, vert_mapping[v2i], vert_mapping[v1i]) )
249
skin_side_faces.append( (v2i, v1i, vert_mapping[v1i], vert_mapping[v2i]) )
250
skin_side_faces_orig.append((f, len(me_faces) + len(skin_side_faces_orig), i1, i2))
252
me_faces.extend(skin_side_faces)
256
# Now assign properties.
259
for i, origfData in enumerate(skin_side_faces_orig):
260
orig_f, new_f_idx, i1, i2 = origfData
261
new_f= me_faces[new_f_idx]
263
new_f.mat= orig_f.mat
264
new_f.smooth= orig_f.smooth
266
new_f.mode= orig_f.mode
267
new_f.flag= orig_f.flag
213
if PREF_COLLAPSE_SIDES:
216
cv2 = me.verts[vert_mapping[v1i]]
219
cv4 = me.verts[vert_mapping[v2i]]
221
cv1.co = cv2.co = (cv1.co+cv2.co)/2
222
cv3.co = cv4.co = (cv3.co+cv4.co)/2
224
cv1.sel=cv2.sel=cv3.sel=cv4.sel=True
229
# Now make a new Face
230
# skin_side_faces.append( (v1i, v2i, vert_mapping[v2i], vert_mapping[v1i]) )
231
skin_side_faces.append( (v2i, v1i, vert_mapping[v1i], vert_mapping[v2i]) )
232
skin_side_faces_orig.append((f, len(me_faces) + len(skin_side_faces_orig), i1, i2))
234
if PREF_COLLAPSE_SIDES:
235
me.remDoubles(0.0001)
237
me_faces.extend(skin_side_faces)
238
# Now assign properties.
241
for i, origfData in enumerate(skin_side_faces_orig):
242
orig_f, new_f_idx, i1, i2 = origfData
243
new_f= me_faces[new_f_idx]
245
new_f.mat= orig_f.mat
246
new_f.smooth= orig_f.smooth
248
new_f.mode= orig_f.mode
249
new_f.flag= orig_f.flag
251
new_f.image= orig_f.image
255
new_f.uv= (uv1, uv2, uv2, uv1)
260
new_f.col= (col1, col2, col2, col1)
263
for i, origfData in enumerate(skin_side_faces_orig):
264
orig_f, new_f_idx, i2, i1 = origfData
265
new_f= me_faces[new_f_idx]
267
new_f.mat= orig_f.mat
268
new_f.smooth= orig_f.smooth
270
for uvlayer in me.getUVLayerNames():
271
me.activeUVLayer = uvlayer
272
for i, origfData in enumerate(skin_side_faces_orig):
273
orig_f, new_f_idx, i2, i1 = origfData
274
new_f= me_faces[new_f_idx]
276
new_f.mode= orig_f.mode
277
new_f.flag= orig_f.flag
269
278
new_f.image= orig_f.image
273
new_f.uv= (uv1, uv2, uv2, uv1)
278
new_f.col= (col1, col2, col2, col1)
281
for i, origfData in enumerate(skin_side_faces_orig):
282
orig_f, new_f_idx, i2, i1 = origfData
283
new_f= me_faces[new_f_idx]
285
new_f.mat= orig_f.mat
286
new_f.smooth= orig_f.smooth
288
for uvlayer in me.getUVLayerNames():
289
me.activeUVLayer = uvlayer
290
for i, origfData in enumerate(skin_side_faces_orig):
291
orig_f, new_f_idx, i2, i1 = origfData
292
new_f= me_faces[new_f_idx]
294
new_f.mode= orig_f.mode
295
new_f.flag= orig_f.flag
296
new_f.image= orig_f.image
300
new_f.uv= (uv1, uv2, uv2, uv1)
302
for collayer in me.getColorLayerNames():
303
me.activeColorLayer = collayer
304
for i, origfData in enumerate(skin_side_faces_orig):
305
orig_f, new_f_idx, i2, i1 = origfData
306
new_f= me_faces[new_f_idx]
310
new_f.col= (col1, col2, col2, col1)
282
new_f.uv= (uv1, uv2, uv2, uv1)
284
for collayer in me.getColorLayerNames():
285
me.activeColorLayer = collayer
286
for i, origfData in enumerate(skin_side_faces_orig):
287
orig_f, new_f_idx, i2, i1 = origfData
288
new_f= me_faces[new_f_idx]
292
new_f.col= (col1, col2, col2, col1)
313
295
if PREF_REM_ORIG:
314
296
me_faces.delete(0, faces_sel)
302
scn = bpy.data.scenes.active
303
ob = scn.objects.active
305
if not ob or ob.type != 'Mesh':
306
BPyMessages.Error_NoMeshActive()
309
me = ob.getData(mesh=1)
311
BPyMessages.Error_NoMeshMultiresEdit()
314
# Create the variables.
315
PREF_THICK = Draw.Create(-0.1)
316
PREF_SKIN_SIDES= Draw.Create(1)
317
PREF_COLLAPSE_SIDES= Draw.Create(0)
318
PREF_REM_ORIG= Draw.Create(0)
321
('Thick:', PREF_THICK, -10, 10, 'Skin thickness in mesh space.'),\
322
('Skin Sides', PREF_SKIN_SIDES, 'Skin between the original and new faces.'),\
323
('Collapse Sides', PREF_COLLAPSE_SIDES, 'Skin between the original and new faces.'),\
324
('Remove Original', PREF_REM_ORIG, 'Remove the selected faces after skinning.'),\
327
if not Draw.PupBlock('Solid Skin Selection', pup_block):
330
is_editmode = Window.EditMode()
331
if is_editmode: Window.EditMode(0)
335
me = ob.getData(mesh=1)
336
solidify(me, PREF_THICK.val, PREF_SKIN_SIDES.val, PREF_REM_ORIG.val, PREF_COLLAPSE_SIDES.val)
317
339
Window.WaitCursor(0)