133 lines
4.8 KiB
Text
133 lines
4.8 KiB
Text
# This file contains the spline motion code contributed by Aenakume, at
|
|
# http://lemmasoft.renai.us/forums/viewtopic.php?f=8&t=3977
|
|
|
|
init -1500 python:
|
|
class _SplineInterpolator(object):
|
|
|
|
ANCHORS = {
|
|
'top' : 0.0,
|
|
'center' : 0.5,
|
|
'bottom' : 1.0,
|
|
'left' : 0.0,
|
|
'right' : 1.0,
|
|
}
|
|
|
|
def __init__(self, points, anchors=(0.5, 0.5)):
|
|
|
|
assert len(points) >= 2, "Need at least a start and end point."
|
|
|
|
def setup_coordinate_(c):
|
|
if len(c) == 2:
|
|
c += anchors
|
|
return [ self.ANCHORS.get(i, i) for i in c ]
|
|
|
|
self.points = []
|
|
|
|
for p in points:
|
|
length = len(p)
|
|
|
|
if isinstance(p[-1], float):
|
|
length = len(p) - 1
|
|
point = [ p[-1] ]
|
|
else:
|
|
length = len(p)
|
|
point = [ -1 ]
|
|
|
|
self.points.append(point + [ setup_coordinate_(p[i]) for i in range(length) ])
|
|
|
|
# Make sure start and end times are set, if not already set
|
|
if self.points[0][0] == -1:
|
|
self.points[0][0] = 0.0
|
|
if self.points[-1][0] == -1:
|
|
self.points[-1][0] = 1.0
|
|
|
|
# Now we gotta calculate the step times that need calculating
|
|
for start in range(1, len(self.points) - 1):
|
|
if self.points[start][0] != -1:
|
|
continue
|
|
|
|
end = start + 1
|
|
|
|
while end < (len(self.points) - 1) and self.points[end][0] == -1:
|
|
end += 1
|
|
|
|
step = (self.points[end][0] - self.points[start - 1][0]) / float(end - start + 1)
|
|
|
|
for i in range(start, end):
|
|
self.points[i][0] = self.points[i - 1][0] + step
|
|
|
|
# And finally, sort the list of points by increasing time
|
|
self.points.sort(key=lambda a : a[0])
|
|
|
|
self.initialized = None
|
|
|
|
def init_values(self, sizes):
|
|
def to_abs_(value, size):
|
|
if isinstance(value, float):
|
|
return value * size
|
|
else:
|
|
return value
|
|
|
|
def coord_(c):
|
|
|
|
if len(c) == 2:
|
|
c = c + (0, 0)
|
|
|
|
return ( to_abs_(c[0], sizes[0]) - to_abs_(c[2], sizes[2]),
|
|
to_abs_(c[1], sizes[1]) - to_abs_(c[3], sizes[3]) )
|
|
|
|
for p in self.points:
|
|
for i in range(1, len(p)):
|
|
p[i] = coord_(p[i])
|
|
|
|
self.initialized = sizes
|
|
|
|
def __call__(self, t, sizes):
|
|
# Initialize if necessary
|
|
if not self.initialized == sizes:
|
|
self.init_values(sizes)
|
|
|
|
# Now we must determine which segment we are in
|
|
for segment in range(len(self.points)):
|
|
if self.points[segment][0] > t:
|
|
break
|
|
|
|
# If this is the zeroth segment, just start at the start point
|
|
if segment == 0:
|
|
result = self.points[0][1]
|
|
# If this is past the last segment, just leave it at the end point
|
|
elif segment == len(self.points) - 1 and t > self.points[-1][0]:
|
|
result = self.points[-1][1]
|
|
else:
|
|
# Scale t
|
|
t = (t - self.points[segment - 1][0]) / (self.points[segment][0] - self.points[segment - 1][0])
|
|
|
|
# Get start and end points
|
|
start = self.points[segment - 1][1]
|
|
end = self.points[segment][1]
|
|
|
|
# Now what kind of interpolation is it?
|
|
if len(self.points[segment]) == 2: # Straight line
|
|
t_p = 1.0 - t
|
|
|
|
result = [ t_p * start[i] + t * end[i] for i in 0,1 ]
|
|
|
|
elif len(self.points[segment]) == 3: # Quadratic Bezier
|
|
t_pp = (1.0 - t)**2
|
|
t_p = 2 * t * (1.0 - t)
|
|
t2 = t**2
|
|
|
|
result = [ t_pp * start[i] + t_p * self.points[segment][2][i] + t2 * end[i] for i in 0,1 ]
|
|
|
|
elif len(self.points[segment]) == 4: # Cubic Bezier
|
|
t_ppp = (1.0 - t)**3
|
|
t_pp = 3 * t * (1.0 - t)**2
|
|
t_p = 3 * t**2 * (1.0 - t)
|
|
t3 = t**3
|
|
|
|
result = [ t_ppp * start[i] + t_pp * self.points[segment][2][i] + t_p * self.points[segment][3][i] + t3 * end[i] for i in 0,1 ]
|
|
|
|
return ( absolute(result[0]), absolute(result[1]), 0, 0 )
|
|
|
|
def SplineMotion(points, time, child=None, anchors=(0.5, 0.5), repeat=False, bounce=False, anim_timebase=False, style='default', time_warp=None, **properties):
|
|
return Motion(_SplineInterpolator(points, anchors), time, child, repeat=repeat, bounce=bounce, anim_timebase=anim_timebase, style=style, time_warp=time_warp, add_sizes=True, **properties)
|