Newer
Older
# SPDX-License-Identifier: GPL-2.0-or-later
# Contributed to Germano Cavalcante (mano-wii), Florian Meyer (testscreenings),
# Brendon Murphy (meta-androcto),
# Maintainer: Vladimir Spivak (cwolf3d)
# Originally an addon by Bart Crouch
"author": "Bart Crouch, Vladimir Spivak (cwolf3d)",
Vladimir Spivak(cwolf3d)
committed
"version": (4, 7, 7),
"location": "View3D > Sidebar > Edit Tab / Edit Mode Context Menu",
"warning": "",
"description": "Mesh modelling toolkit. Several tools to aid modelling",
"doc_url": "{BLENDER_MANUAL_URL}/addons/mesh/looptools.html",
"category": "Mesh",
}
import bmesh
import bpy
import collections
import mathutils
import math
from bpy.types import (
Operator,
Menu,
Panel,
PropertyGroup,
AddonPreferences,
)
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
PointerProperty,
StringProperty,
)
# ########################################
# ##### General functions ################
# ########################################
# used by all tools to improve speed on reruns Unlink
looptools_cache = {}
def get_strokes(self, context):
looptools = context.window_manager.looptools
if looptools.gstretch_use_guide == "Annotation":
try:
strokes = bpy.data.grease_pencils[0].layers.active.active_frame.strokes
return True
except:
self.report({'WARNING'}, "active Annotation strokes not found")
return False
if looptools.gstretch_use_guide == "GPencil" and not looptools.gstretch_guide == None:
try:
strokes = looptools.gstretch_guide.data.layers.active.active_frame.strokes
return True
except:
self.report({'WARNING'}, "active GPencil strokes not found")
return False
else:
return False
beta-tester
committed
# 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, bm, 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 bm.verts 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"]
CoDEmanX
committed
return(True, single_loops, loops, derived, mapping)
# store information in the cache
def cache_write(tool, object, bm, 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 bm.verts if v.select and not v.hide]
modifiers = [mod.name for mod in object.modifiers if mod.show_viewport
and mod.type == 'MIRROR']
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(bm_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_new2 = []
for k in range(4):
if k + 1 > len(knots) - 1:
k -= len(knots)
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
CoDEmanX
committed
n = len(knots)
if n < 2:
return False
x = tknots[:]
locs = [bm_mod.verts[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:
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)
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
Loading
Loading full blame...