[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [1780] trunk/py/scripts/addons/ mesh_looptools.py: Move from contrib to trunk.
Bart Crouch
bartius.crouch at gmail.com
Mon Apr 4 18:00:54 CEST 2011
Revision: 1780
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=1780
Author: crouch
Date: 2011-04-04 16:00:53 +0000 (Mon, 04 Apr 2011)
Log Message:
-----------
Move from contrib to trunk.
Added Paths:
-----------
trunk/py/scripts/addons/mesh_looptools.py
Added: trunk/py/scripts/addons/mesh_looptools.py
===================================================================
--- trunk/py/scripts/addons/mesh_looptools.py (rev 0)
+++ trunk/py/scripts/addons/mesh_looptools.py 2011-04-04 16:00:53 UTC (rev 1780)
@@ -0,0 +1,3712 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+bl_info = {
+ 'name': "LoopTools",
+ 'author': "Bart Crouch",
+ 'version': (3, 2, 0),
+ 'blender': (2, 5, 7),
+ 'api': 35979,
+ 'location': "View3D > Toolbar and View3D > Specials (W-key)",
+ 'warning': "",
+ 'description': "Mesh modelling toolkit. Several tools to aid modelling",
+ 'wiki_url': "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
+ "Scripts/Modeling/LoopTools",
+ 'tracker_url': "http://projects.blender.org/tracker/index.php?"\
+ "func=detail&aid=26189",
+ 'category': 'Mesh'}
+
+
+import bpy
+import mathutils
+import math
+
+
+##########################################
+####### General functions ################
+##########################################
+
+
+# used by all tools to improve speed on reruns
+looptools_cache = {}
+
+
+# force a full recalculation next time
+def cache_delete(tool):
+ if tool in looptools_cache:
+ del looptools_cache[tool]
+
+
+# check cache for stored information
+def cache_read(tool, object, mesh, input_method, boundaries):
+ # current tool not cached yet
+ if tool not in looptools_cache:
+ return(False, False, False, False, False)
+ # check if selected object didn't change
+ if object.name != looptools_cache[tool]["object"]:
+ return(False, False, False, False, False)
+ # check if input didn't change
+ if input_method != looptools_cache[tool]["input_method"]:
+ return(False, False, False, False, False)
+ if boundaries != looptools_cache[tool]["boundaries"]:
+ return(False, False, False, False, False)
+ modifiers = [mod.name for mod in object.modifiers if mod.show_viewport \
+ and mod.type == 'MIRROR']
+ if modifiers != looptools_cache[tool]["modifiers"]:
+ return(False, False, False, False, False)
+ input = [v.index for v in mesh.vertices if v.select and not v.hide]
+ if input != looptools_cache[tool]["input"]:
+ return(False, False, False, False, False)
+ # reading values
+ single_loops = looptools_cache[tool]["single_loops"]
+ loops = looptools_cache[tool]["loops"]
+ derived = looptools_cache[tool]["derived"]
+ mapping = looptools_cache[tool]["mapping"]
+
+ return(True, single_loops, loops, derived, mapping)
+
+
+# store information in the cache
+def cache_write(tool, object, mesh, input_method, boundaries, single_loops,
+loops, derived, mapping):
+ # clear cache of current tool
+ if tool in looptools_cache:
+ del looptools_cache[tool]
+ # prepare values to be saved to cache
+ input = [v.index for v in mesh.vertices if v.select and not v.hide]
+ modifiers = [mod.name for mod in object.modifiers if mod.show_viewport \
+ and mod.type == 'MIRROR']
+ # update cache
+ looptools_cache[tool] = {"input": input, "object": object.name,
+ "input_method": input_method, "boundaries": boundaries,
+ "single_loops": single_loops, "loops": loops,
+ "derived": derived, "mapping": mapping, "modifiers": modifiers}
+
+
+# calculates natural cubic splines through all given knots
+def calculate_cubic_splines(mesh_mod, tknots, knots):
+ # hack for circular loops
+ if knots[0] == knots[-1] and len(knots) > 1:
+ circular = True
+ k_new1 = []
+ for k in range(-1, -5, -1):
+ if k - 1 < -len(knots):
+ k += len(knots)
+ k_new1.append(knots[k-1])
+ k_new2 = []
+ for k in range(4):
+ if k + 1 > len(knots) - 1:
+ k -= len(knots)
+ k_new2.append(knots[k+1])
+ for k in k_new1:
+ knots.insert(0, k)
+ for k in k_new2:
+ knots.append(k)
+ t_new1 = []
+ total1 = 0
+ for t in range(-1, -5, -1):
+ if t - 1 < -len(tknots):
+ t += len(tknots)
+ total1 += tknots[t] - tknots[t-1]
+ t_new1.append(tknots[0] - total1)
+ t_new2 = []
+ total2 = 0
+ for t in range(4):
+ if t + 1 > len(tknots) - 1:
+ t -= len(tknots)
+ total2 += tknots[t+1] - tknots[t]
+ t_new2.append(tknots[-1] + total2)
+ for t in t_new1:
+ tknots.insert(0, t)
+ for t in t_new2:
+ tknots.append(t)
+ else:
+ circular = False
+ # end of hack
+
+ n = len(knots)
+ if n < 2:
+ return False
+ x = tknots[:]
+ locs = [mesh_mod.vertices[k].co[:] for k in knots]
+ result = []
+ for j in range(3):
+ a = []
+ for i in locs:
+ a.append(i[j])
+ h = []
+ for i in range(n-1):
+ if x[i+1] - x[i] == 0:
+ h.append(1e-8)
+ else:
+ h.append(x[i+1] - x[i])
+ q = [False]
+ for i in range(1, n-1):
+ q.append(3/h[i]*(a[i+1]-a[i]) - 3/h[i-1]*(a[i]-a[i-1]))
+ l = [1.0]
+ u = [0.0]
+ z = [0.0]
+ for i in range(1, n-1):
+ l.append(2*(x[i+1]-x[i-1]) - h[i-1]*u[i-1])
+ if l[i] == 0:
+ l[i] = 1e-8
+ u.append(h[i] / l[i])
+ z.append((q[i] - h[i-1] * z[i-1]) / l[i])
+ l.append(1.0)
+ z.append(0.0)
+ b = [False for i in range(n-1)]
+ c = [False for i in range(n)]
+ d = [False for i in range(n-1)]
+ c[n-1] = 0.0
+ for i in range(n-2, -1, -1):
+ c[i] = z[i] - u[i]*c[i+1]
+ b[i] = (a[i+1]-a[i])/h[i] - h[i]*(c[i+1]+2*c[i])/3
+ d[i] = (c[i+1]-c[i]) / (3*h[i])
+ for i in range(n-1):
+ result.append([a[i], b[i], c[i], d[i], x[i]])
+ splines = []
+ for i in range(len(knots)-1):
+ splines.append([result[i], result[i+n-1], result[i+(n-1)*2]])
+ if circular: # cleaning up after hack
+ knots = knots[4:-4]
+ tknots = tknots[4:-4]
+
+ return(splines)
+
+
+# calculates linear splines through all given knots
+def calculate_linear_splines(mesh_mod, tknots, knots):
+ splines = []
+ for i in range(len(knots)-1):
+ a = mesh_mod.vertices[knots[i]].co
+ b = mesh_mod.vertices[knots[i+1]].co
+ d = b-a
+ t = tknots[i]
+ u = tknots[i+1]-t
+ splines.append([a, d, t, u]) # [locStart, locDif, tStart, tDif]
+
+ return(splines)
+
+
+# calculate a best-fit plane to the given vertices
+def calculate_plane(mesh_mod, loop, method="best_fit", object=False):
+ # getting the vertex locations
+ locs = [mathutils.Vector(mesh_mod.vertices[v].co[:]) for v in loop[0]]
+
+ # calculating the center of masss
+ com = mathutils.Vector()
+ for loc in locs:
+ com += loc
+ com /= len(locs)
+ x, y, z = com
+
+ if method == 'best_fit':
+ # creating the covariance matrix
+ mat = mathutils.Matrix([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0],
+ [0.0, 0.0, 0.0]])
+ for loc in locs:
+ mat[0][0] += (loc[0]-x)**2
+ mat[0][1] += (loc[0]-x)*(loc[1]-y)
+ mat[0][2] += (loc[0]-x)*(loc[2]-z)
+ mat[1][0] += (loc[1]-y)*(loc[0]-x)
+ mat[1][1] += (loc[1]-y)**2
+ mat[1][2] += (loc[1]-y)*(loc[2]-z)
+ mat[2][0] += (loc[2]-z)*(loc[0]-x)
+ mat[2][1] += (loc[2]-z)*(loc[1]-y)
+ mat[2][2] += (loc[2]-z)**2
+
+ # calculating the normal to the plane
+ normal = False
+ try:
+ mat.invert()
+ except:
+ if sum(mat[0]) == 0.0:
+ normal = mathutils.Vector([1.0, 0.0, 0.0])
+ elif sum(mat[1]) == 0.0:
+ normal = mathutils.Vector([0.0, 1.0, 0.0])
+ elif sum(mat[2]) == 0.0:
+ normal = mathutils.Vector([0.0, 0.0, 1.0])
+ if not normal:
+ itermax = 500
+ iter = 0
+ vec = mathutils.Vector([1.0, 1.0, 1.0])
+ vec2 = (vec*mat)/(vec*mat).length
+ while vec != vec2 and iter<itermax:
+ iter += 1
+ vec = vec2
+ vec2 = (vec*mat)/(vec*mat).length
+ normal = vec2
+
+ elif method == 'normal':
+ # averaging the vertex normals
+ v_normals = [mesh_mod.vertices[v].normal for v in loop[0]]
+ normal = mathutils.Vector()
+ for v_normal in v_normals:
+ normal += v_normal
+ normal /= len(v_normals)
+ normal.normalize()
+
+ elif method == 'view':
+ # calculate view normal
+ rotation = bpy.context.space_data.region_3d.view_matrix.to_3x3().\
+ inverted()
+ normal = mathutils.Vector([0.0, 0.0, 1.0]) * rotation
+ if object:
+ normal *= object.matrix_world.inverted().to_euler().to_matrix()
+
+ return(com, normal)
+
+
+# calculate splines based on given interpolation method (controller function)
+def calculate_splines(interpolation, mesh_mod, tknots, knots):
+ if interpolation == 'cubic':
+ splines = calculate_cubic_splines(mesh_mod, tknots, knots[:])
+ else: # interpolations == 'linear'
+ splines = calculate_linear_splines(mesh_mod, tknots, knots[:])
+
+ return(splines)
+
+
+# check loops and only return valid ones
+def check_loops(loops, mapping, mesh_mod):
+ valid_loops = []
+ for loop, circular in loops:
+ # loop needs to have at least 3 vertices
+ if len(loop) < 3:
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list