~ubuntu-branches/ubuntu/gutsy/blender/gutsy-security

« back to all changes in this revision

Viewing changes to release/scripts/sel_same.py

  • Committer: Bazaar Package Importer
  • Author(s): Florian Ernst
  • Date: 2005-11-06 12:40:03 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20051106124003-3pgs7tcg5rox96xg
Tags: 2.37a-1.1
* Non-maintainer upload.
* Split out parts of 01_SConstruct_debian.dpatch again: root_build_dir
  really needs to get adjusted before the clean target runs - closes: #333958,
  see #288882 for reference

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!BPY
 
2
 
 
3
"""
 
4
Name: 'Similar to Active'
 
5
Blender: 234
 
6
Group: 'FaceSelect'
 
7
Tooltip: 'Select faces that match a given attribute of the active face'
 
8
"""
 
9
 
 
10
__author__ = "Campbell Barton"
 
11
__url__ = ["blender", "elysiun"]
 
12
__version__ = "1.0"
 
13
 
 
14
__bpydoc__ = """\
 
15
This script selects faces matching a given attribute of the currently
 
16
active face.
 
17
 
 
18
Usage:
 
19
 
 
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):
 
22
 
 
23
- material;<br>
 
24
- texture image;<br>
 
25
- mode;<br>
 
26
- vertex colors;<br>
 
27
- uv coordinates;<br>
 
28
- area;<br>
 
29
- proportions;<br>
 
30
- normal vector;<br>
 
31
- coplanar.
 
32
 
 
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.
 
36
 
 
37
Notes:<br>
 
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).
 
40
"""
 
41
 
 
42
# $Id: sel_same.py,v 1.5 2005/03/19 06:24:54 ianwill Exp $
 
43
#
 
44
#===============================================#
 
45
# Sel Same script 1.0 by Campbell Barton        #
 
46
# email me ideasman@linuxmail.org               #
 
47
#===============================================#
 
48
 
 
49
 
 
50
# -------------------------------------------------------------------------- 
 
51
# Sel Same Face 1.0 By Campbell Barton (AKA Ideasman)
 
52
# -------------------------------------------------------------------------- 
 
53
# ***** BEGIN GPL LICENSE BLOCK ***** 
 
54
 
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. 
 
59
 
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. 
 
64
 
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. 
 
68
 
69
# ***** END GPL LICENCE BLOCK ***** 
 
70
# -------------------------------------------------------------------------- 
 
71
 
 
72
 
 
73
 
 
74
from Blender import *
 
75
from Blender.Mathutils import DotVecs, Vector
 
76
from math import sqrt
 
77
 
 
78
 
 
79
#====================================#
 
80
# Sanity checks                      #
 
81
#====================================#
 
82
def error(str):
 
83
        Draw.PupMenu('ERROR: '+str)
 
84
af = None 
 
85
selection = Object.GetSelected()
 
86
if len(selection) == 0:
 
87
  error('No object selected')
 
88
else:
 
89
  object = Object.GetSelected()[0]
 
90
  if object.getType() != 'Mesh':
 
91
    error('Active object must be a mesh')
 
92
  else:
 
93
    mesh = object.getData()
 
94
    
 
95
    # We have a mesh so find AF.
 
96
    af = mesh.getActiveFace()
 
97
    if af: af = mesh.faces[af]
 
98
 
 
99
if af == None:
 
100
  error('No active face')
 
101
 
 
102
else: # Okay everything seems sane
 
103
  
 
104
  #=====================================
 
105
  # Popup menu to select the functions #
 
106
  #====================================#
 
107
  method = Draw.PupMenu(\
 
108
  'Selection Attribute%t|\
 
109
  Material|\
 
110
  UV Image|\
 
111
  Face Mode|\
 
112
  Vertex Colours|\
 
113
  UV Coordinates|\
 
114
  Area|\
 
115
  Edge Proportions|\
 
116
  Normal Vector|\
 
117
  Coplanar|')
 
118
  
 
119
  if method != -1:
 
120
    #================================================#
 
121
    # Do we add, seb or set to the existing face sel #
 
122
    #================================================#
 
123
    faceOp = Draw.PupMenu(\
 
124
    'Active Face Match%t|\
 
125
    Add to Selection|\
 
126
    Subtract From Selection |\
 
127
    Overwrite Selection|\
 
128
    Overwrite Selection Inverse|')
 
129
    
 
130
    if faceOp != -1:
 
131
      
 
132
      def setFSel(f):
 
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
 
137
      
 
138
      def setFUnSel(f):
 
139
        if faceOp == 3:
 
140
          f.flag &=~NMesh.FaceFlags['SELECT'] # will unselect, note the '~' to invert bitflags
 
141
        elif faceOp == 4:
 
142
          f.flag |= NMesh.FaceFlags['SELECT'] # will set selection
 
143
      
 
144
      
 
145
      
 
146
      #================#
 
147
      # Math functions #
 
148
      #================#
 
149
      def compare(f1, f2, limit):
 
150
        if f1 + limit > f2 and f1 - limit < f2:
 
151
          return 1
 
152
        return 0
 
153
      
 
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]:
 
157
              return 1
 
158
        return 0
 
159
      
 
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]:
 
164
                return 1
 
165
        return 0
 
166
      
 
167
      def colCompare(v1, v2, limit):
 
168
        # Simple test first
 
169
        if v1.r == v2.r:
 
170
          if v1.g == v2.g:
 
171
            if v1.b == v2.b:
 
172
              return 1  
 
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:
 
178
              return 1
 
179
        return 0
 
180
      
 
181
      # Makes sure face 2 has all the colours of face 1
 
182
      def faceColCompare(f1, f2, limit):
 
183
        avcolIdx = 0
 
184
        while avcolIdx < len(f1.col):
 
185
          match = 0
 
186
          
 
187
          vcolIdx = 0
 
188
          while vcolIdx < len(f2.col):
 
189
            if colCompare(f1.col[avcolIdx], f2.col[vcolIdx], limit):
 
190
              match = 1
 
191
              break
 
192
            vcolIdx += 1
 
193
          if match == 0: # premature exit if a motch not found
 
194
            return 0
 
195
          avcolIdx += 1
 
196
        return 1
 
197
      
 
198
      # Makes sure face 2 has matching UVs within the limit.
 
199
      def faceUvCompare(f1, f2, limit):
 
200
        for auv in f1.uv:
 
201
          match = 0
 
202
          for uv in f2.uv:
 
203
            if compare2(auv, uv, limit):
 
204
              match = 1
 
205
              break
 
206
          if match == 0: # premature exit if a motch not found
 
207
            return 0
 
208
        return 1
 
209
      
 
210
      
 
211
      def measure(v1, v2):
 
212
        return Mathutils.Vector([v1[0]-v2[0], v1[1] - v2[1], v1[2] - v2[2]]).length
 
213
      
 
214
      def triArea2D(v1, v2, v3):
 
215
        e1 = measure(v1, v2)  
 
216
        e2 = measure(v2, v3)  
 
217
        e3 = measure(v3, v1)  
 
218
        p = e1+e2+e3
 
219
        return 0.25 * sqrt(p*(p-2*e1)*(p-2*e2)*(p-2*e3))
 
220
      #====================#
 
221
      # End Math Functions #
 
222
      #====================#
 
223
      
 
224
      
 
225
      #=============================#
 
226
      # Blender functions/shortcuts #
 
227
      #=============================#
 
228
      def getLimit(text):
 
229
        return Draw.PupFloatInput(text, 0.1, 0.0, 1.0, 0.1, 3)
 
230
      
 
231
      def faceArea(f):
 
232
        if len(f.v) == 4:
 
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)
 
234
        elif len(f.v) == 3:
 
235
          return triArea2D(f.v[0].co, f.v[1].co, f.v[2].co)
 
236
        
 
237
      def getEdgeLengths(f):
 
238
        if len(f.v) == 4:
 
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) )
 
240
        elif len(f.v) == 3:
 
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) )
 
242
      
 
243
      def faceCent(f):
 
244
        x = y = z = 0
 
245
        for v in f.v:
 
246
          x += v.co[0]
 
247
          y += v.co[1]
 
248
          z += v.co[2]
 
249
        x = x/len(f.v)
 
250
        y = y/len(f.v)
 
251
        z = z/len(f.v)
 
252
        return Vector([x, y, z])
 
253
      
 
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
 
260
          return 0
 
261
        elif faceOp == 1 and f.flag == 1:
 
262
          return 0
 
263
        elif faceOp == 0 and f.flag == 0:
 
264
          return 0
 
265
        elif f.flag == 64: # Ignore hidden
 
266
          return 0
 
267
        return 1
 
268
        
 
269
      #=======================================#
 
270
      # Sel same funcs as called by the menus #
 
271
      #=======================================#
 
272
      def get_same_mat():
 
273
        for f in mesh.faces:
 
274
          if fShouldCompare(f):
 
275
            if af.mat == f.mat: setFSel(f)
 
276
            else:               setFUnSel(f)
 
277
      
 
278
      def get_same_image():
 
279
        if mesh.hasFaceUV() == 0:
 
280
          error('mesh has no uv image')
 
281
        else:
 
282
          for f in mesh.faces:
 
283
            if fShouldCompare(f):
 
284
              if af.image == f.image: setFSel(f)
 
285
              else:                   setFUnSel(f)
 
286
      
 
287
      def get_same_mode():
 
288
        for f in mesh.faces:
 
289
          if fShouldCompare(f):
 
290
            if af.mode == f.mode: setFSel(f)
 
291
            else:                 setFUnSel(f)
 
292
      
 
293
      def get_same_vcol(limit):
 
294
        for f in mesh.faces:
 
295
          if fShouldCompare(f):
 
296
            if faceColCompare(f, af, limit) and faceColCompare(af, f, limit) :
 
297
              setFSel(f)
 
298
            else:
 
299
              setFUnSel(f)
 
300
      
 
301
      def get_same_uvco(limit):
 
302
        for f in mesh.faces:
 
303
          if fShouldCompare(f):
 
304
            if faceUvCompare(af, f, limit): setFSel(f)
 
305
            else:                           setFUnSel(f)
 
306
      
 
307
      def get_same_area(limit):
 
308
        afArea = faceArea(af)
 
309
        limit = limit * afArea # Make the lomot proportinal to the 
 
310
        for f in mesh.faces:
 
311
          if fShouldCompare(f):
 
312
            if compare(afArea, faceArea(f), limit): setFSel(f)
 
313
            else:                                   setFUnSel(f)
 
314
      
 
315
      def get_same_prop(limit):
 
316
        # Here we get the perimeter and use it for a proportional limit modifier.
 
317
        afEdgeLens = getEdgeLengths(af)
 
318
        perim = 0
 
319
        for e in afEdgeLens:
 
320
          perim += e
 
321
      
 
322
        limit = limit * perim
 
323
        for f in mesh.faces:
 
324
          if fShouldCompare(f):
 
325
            for ae in afEdgeLens:
 
326
              match = 0
 
327
              for e in getEdgeLengths(f):
 
328
                if compare(ae, e, limit):
 
329
                  match = 1
 
330
                  break
 
331
              if not match:
 
332
                break
 
333
           
 
334
            if match: setFSel(f)
 
335
            else:     setFUnSel(f)
 
336
      
 
337
      def get_same_normal(limit):    
 
338
        limit = limit * 2
 
339
        for f in mesh.faces:
 
340
          if fShouldCompare(f):
 
341
            if compare3(af.no, f.no, limit): setFSel(f)
 
342
            else:                            setFUnSel(f)
 
343
      
 
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)
 
348
        for f in mesh.faces:
 
349
          if fShouldCompare(f):
 
350
            match = 0
 
351
            if compare3(af.no, f.no, nlimit):
 
352
              fCent = faceCent(f)
 
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:
 
354
                match = 1
 
355
            if match:
 
356
              setFSel(f)
 
357
            else:
 
358
              setFUnSel(f)
 
359
      
 
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
 
366
        get_same_mat()
 
367
      elif method == 2: # UV Image
 
368
        get_same_image()
 
369
      elif method == 3: # mode
 
370
        get_same_mode()
 
371
      elif method == 4: # vertex colours
 
372
        limit = getLimit('vert col limit: ')
 
373
        if limit != None:
 
374
          get_same_vcol(limit)
 
375
      elif method == 5: # UV-coords
 
376
        limit = getLimit('uv-coord limit: ')
 
377
        if limit != None:
 
378
          get_same_uvco(limit)
 
379
      elif method == 6: # area
 
380
        limit = getLimit('area limit: ')
 
381
        if limit != None:
 
382
          get_same_area(limit)
 
383
      elif method == 7: # proportions
 
384
        limit = getLimit('proportion limit: ')
 
385
        if limit != None:
 
386
          get_same_prop(limit)
 
387
      elif method == 8: # normal
 
388
        limit = getLimit('normal limit: ')
 
389
        if limit != None:
 
390
          get_same_normal(limit)
 
391
      elif method == 9: # coplaner
 
392
        limit = getLimit('coplanar limit: ')
 
393
        if limit != None:
 
394
          get_same_coplaner(limit)
 
395
      
 
396
      # If limit is not set then dont bother
 
397
      if limit != None:
 
398
        mesh.update(0)