4
Name: 'Similar to Active'
7
Tooltip: 'Select faces that match a given attribute of the active face'
10
__author__ = "Campbell Barton"
11
__url__ = ["blender", "elysiun"]
15
This script selects faces matching a given attribute of the currently
20
Enter "UV Face Select" mode and make the desired face active. Then run this
21
script and choose the selection rule: by same (or similar for some itens):
33
Another menu will ask if the script should add, subtract, overwrite or
34
overwrite inverse of current current selection. For some choices like vcolors,
35
area, etc., a pop-up will ask for a maximum threshold value.
38
Again, to select / deselect faces, enter "UV Face Select" mode. This is not
39
the same as selecting faces in edit mode (new feature in Blender 2.35).
42
# $Id: sel_same.py,v 1.5 2005/03/19 06:24:54 ianwill Exp $
44
#===============================================#
45
# Sel Same script 1.0 by Campbell Barton #
46
# email me ideasman@linuxmail.org #
47
#===============================================#
50
# --------------------------------------------------------------------------
51
# Sel Same Face 1.0 By Campbell Barton (AKA Ideasman)
52
# --------------------------------------------------------------------------
53
# ***** BEGIN GPL LICENSE BLOCK *****
55
# This program is free software; you can redistribute it and/or
56
# modify it under the terms of the GNU General Public License
57
# as published by the Free Software Foundation; either version 2
58
# of the License, or (at your option) any later version.
60
# This program is distributed in the hope that it will be useful,
61
# but WITHOUT ANY WARRANTY; without even the implied warranty of
62
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63
# GNU General Public License for more details.
65
# You should have received a copy of the GNU General Public License
66
# along with this program; if not, write to the Free Software Foundation,
67
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
69
# ***** END GPL LICENCE BLOCK *****
70
# --------------------------------------------------------------------------
75
from Blender.Mathutils import DotVecs, Vector
79
#====================================#
81
#====================================#
83
Draw.PupMenu('ERROR: '+str)
85
selection = Object.GetSelected()
86
if len(selection) == 0:
87
error('No object selected')
89
object = Object.GetSelected()[0]
90
if object.getType() != 'Mesh':
91
error('Active object must be a mesh')
93
mesh = object.getData()
95
# We have a mesh so find AF.
96
af = mesh.getActiveFace()
97
if af: af = mesh.faces[af]
100
error('No active face')
102
else: # Okay everything seems sane
104
#=====================================
105
# Popup menu to select the functions #
106
#====================================#
107
method = Draw.PupMenu(\
108
'Selection Attribute%t|\
120
#================================================#
121
# Do we add, seb or set to the existing face sel #
122
#================================================#
123
faceOp = Draw.PupMenu(\
124
'Active Face Match%t|\
126
Subtract From Selection |\
127
Overwrite Selection|\
128
Overwrite Selection Inverse|')
133
if faceOp == 1 or faceOp == 3:
134
f.flag |= NMesh.FaceFlags['SELECT'] # will set selection
135
elif faceOp == 2 or faceOp ==4:
136
f.flag &=~NMesh.FaceFlags['SELECT'] # will unselect, note the '~' to invert bitflags
140
f.flag &=~NMesh.FaceFlags['SELECT'] # will unselect, note the '~' to invert bitflags
142
f.flag |= NMesh.FaceFlags['SELECT'] # will set selection
149
def compare(f1, f2, limit):
150
if f1 + limit > f2 and f1 - limit < f2:
154
def compare2(v1, v2, limit):
155
if v1[0] + limit > v2[0] and v1[0] - limit < v2[0]:
156
if v1[1] + limit > v2[1] and v1[1] - limit < v2[1]:
160
def compare3(v1, v2, limit):
161
if v1[0] + limit > v2[0] and v1[0] - limit < v2[0]:
162
if v1[1] + limit > v2[1] and v1[1] - limit < v2[1]:
163
if v1[2] + limit > v2[2] and v1[2] - limit < v2[2]:
167
def colCompare(v1, v2, limit):
173
# Now a test that uses the limit.
174
limit = int(limit * 255)
175
if v1.r + limit >= v2.r and v1.r - limit <= v2.r:
176
if v1.g + limit >= v2.g and v1.g - limit <= v2.g:
177
if v1.b + limit >= v2.b and v1.b - limit <= v2.b:
181
# Makes sure face 2 has all the colours of face 1
182
def faceColCompare(f1, f2, limit):
184
while avcolIdx < len(f1.col):
188
while vcolIdx < len(f2.col):
189
if colCompare(f1.col[avcolIdx], f2.col[vcolIdx], limit):
193
if match == 0: # premature exit if a motch not found
198
# Makes sure face 2 has matching UVs within the limit.
199
def faceUvCompare(f1, f2, limit):
203
if compare2(auv, uv, limit):
206
if match == 0: # premature exit if a motch not found
212
return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length
214
def triArea2D(v1, v2, v3):
219
return 0.25 * sqrt(p*(p-2*e1)*(p-2*e2)*(p-2*e3))
220
#====================#
221
# End Math Functions #
222
#====================#
225
#=============================#
226
# Blender functions/shortcuts #
227
#=============================#
229
return Draw.PupFloatInput(text, 0.1, 0.0, 1.0, 0.1, 3)
233
return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co) + triArea2D(f.v[0].co, f.v[2].co, f.v[3].co)
235
return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co)
237
def getEdgeLengths(f):
239
return (measure(f.v[0].co, f.v[1].co), measure(f.v[1].co, f.v[2].co), measure(f.v[2].co, f.v[3].co) , measure(f.v[3].co, f.v[0].co) )
241
return (measure(f.v[0].co, f.v[1].co), measure(f.v[1].co, f.v[2].co), measure(f.v[2].co, f.v[0].co) )
252
return Vector([x, y, z])
254
#========================================#
255
# Should we bother computing this faces #
256
#========================================#
257
def fShouldCompare(f):
258
# Only calculate for faces that will be affected.
259
if len(f.v) < 3: # cant be an edge
261
elif faceOp == 1 and f.flag == 1:
263
elif faceOp == 0 and f.flag == 0:
265
elif f.flag == 64: # Ignore hidden
269
#=======================================#
270
# Sel same funcs as called by the menus #
271
#=======================================#
274
if fShouldCompare(f):
275
if af.mat == f.mat: setFSel(f)
278
def get_same_image():
279
if mesh.hasFaceUV() == 0:
280
error('mesh has no uv image')
283
if fShouldCompare(f):
284
if af.image == f.image: setFSel(f)
289
if fShouldCompare(f):
290
if af.mode == f.mode: setFSel(f)
293
def get_same_vcol(limit):
295
if fShouldCompare(f):
296
if faceColCompare(f, af, limit) and faceColCompare(af, f, limit) :
301
def get_same_uvco(limit):
303
if fShouldCompare(f):
304
if faceUvCompare(af, f, limit): setFSel(f)
307
def get_same_area(limit):
308
afArea = faceArea(af)
309
limit = limit * afArea # Make the lomot proportinal to the
311
if fShouldCompare(f):
312
if compare(afArea, faceArea(f), limit): setFSel(f)
315
def get_same_prop(limit):
316
# Here we get the perimeter and use it for a proportional limit modifier.
317
afEdgeLens = getEdgeLengths(af)
322
limit = limit * perim
324
if fShouldCompare(f):
325
for ae in afEdgeLens:
327
for e in getEdgeLengths(f):
328
if compare(ae, e, limit):
337
def get_same_normal(limit):
340
if fShouldCompare(f):
341
if compare3(af.no, f.no, limit): setFSel(f)
344
def get_same_coplaner(limit):
345
nlimit = limit * 2 # * 1 # limit for normal test
346
climit = limit * 3 # limit for coplaner test.
347
afCent = faceCent(af)
349
if fShouldCompare(f):
351
if compare3(af.no, f.no, nlimit):
353
if abs(DotVecs(Vector([af.no[0], af.no[1], af.no[2]]), afCent ) - DotVecs(Vector([af.no[0], af.no[1], af.no[2]]), fCent )) <= climit:
360
#=====================#
361
# End Sel same funcs #
362
#=====================#
363
limit = 1 # some of these dont use the limit so it needs to be set, to somthing.
364
# act on the menu item selected
365
if method == 1: # Material
367
elif method == 2: # UV Image
369
elif method == 3: # mode
371
elif method == 4: # vertex colours
372
limit = getLimit('vert col limit: ')
375
elif method == 5: # UV-coords
376
limit = getLimit('uv-coord limit: ')
379
elif method == 6: # area
380
limit = getLimit('area limit: ')
383
elif method == 7: # proportions
384
limit = getLimit('proportion limit: ')
387
elif method == 8: # normal
388
limit = getLimit('normal limit: ')
390
get_same_normal(limit)
391
elif method == 9: # coplaner
392
limit = getLimit('coplanar limit: ')
394
get_same_coplaner(limit)
396
# If limit is not set then dont bother