diff --git a/cuburn/code/interp.py b/cuburn/code/interp.py index a2267b5..47e453c 100644 --- a/cuburn/code/interp.py +++ b/cuburn/code/interp.py @@ -204,6 +204,8 @@ class GenomePacker(object): times, knots = np.empty((2, len(self.genome), width), 'f4') times.fill(1e9) + # TODO: do a nicer job of finding the value of scale + scale = gnm.get('time', {}).get('duration', 1) for idx, path in enumerate(self.genome): attr = gnm for name in path: @@ -211,7 +213,7 @@ class GenomePacker(object): attr = resolve_spec(specs.anim, path).default break attr = attr[name] - attr = SplineEval.normalize(attr) + attr = SplineEval.normalize(attr, scale) times[idx,:len(attr[0])] = attr[0] knots[idx,:len(attr[1])] = attr[1] return times, knots diff --git a/cuburn/genome/blend.py b/cuburn/genome/blend.py index 079f97c..09eabff 100644 --- a/cuburn/genome/blend.py +++ b/cuburn/genome/blend.py @@ -98,7 +98,7 @@ def blend(src, dst, edit={}): opts.update(d.get('blend', {})) opts = Wrapper(opts, specs.blend) - blended = merge_nodes(specs.node, src, dst, edit, opts.nloops) + blended = merge_nodes(specs.node, src, dst, edit, opts.duration) name_map = sort_xforms(src['xforms'], dst['xforms'], opts.xform_sort, explicit=zip(*opts.xform_map)) @@ -111,11 +111,12 @@ def blend(src, dst, edit={}): blended['xforms'][bxf_key] = blend_xform( src['xforms'].get(sxf_key), dst['xforms'].get(dxf_key), - xf_edits, opts.nloops) + xf_edits, opts.duration) if 'final_xform' in src or 'final_xform' in dst: blended['final_xform'] = blend_xform(src.get('final_xform'), - dst.get('final_xform'), edit.get('final_xform'), 0, True) + dst.get('final_xform'), edit.get('final_xform'), + opts.duration, True) # TODO: write 'info' section # TODO: palflip @@ -144,7 +145,7 @@ def split_node_val(spl, val): return val, 0 return val -def tospline(spl, src, dst, edit, loops): +def tospline(spl, src, dst, edit, duration): sp, sv = split_node_val(spl, src) # position, velocity dp, dv = split_node_val(spl, dst) @@ -163,8 +164,11 @@ def tospline(spl, src, dst, edit, loops): # Periodic extension: compute an appropriate number of loops based on # the angular velocities at the endpoints, and extend the destination # position by the appropriate number of periods. - avg_vel = round(float(sv + dv) * loops / spl.period) - dp = dp % spl.period + avg_vel * spl.period + sign = lambda x: 1. if x >= 0 else -1. + + movement = duration * (sv + dv) / (2.0 * spl.period) + angdiff = ((dp - sp) / spl.period) % (sign(movement)) + dp = sp + (round(movement - angdiff) + angdiff) * spl.period # Endpoint override: allow adjusting the number of loops as calculated # above by locking to the nearest value with the same mod (i.e. the @@ -183,14 +187,14 @@ def trace(k): print k, return k -def merge_nodes(sp, src, dst, edit, loops): +def merge_nodes(sp, src, dst, edit, duration): if isinstance(sp, dict): src, dst, edit = [x or {} for x in src, dst, edit] return dict([(k, merge_nodes(sp[k], src.get(k), - dst.get(k), edit.get(k), loops)) + dst.get(k), edit.get(k), duration)) for k in set(src.keys() + dst.keys() + edit.keys()) if k in sp]) elif isinstance(sp, spectypes.Spline): - return tospline(sp, src, dst, edit, loops) + return tospline(sp, src, dst, edit, duration) elif isinstance(sp, spectypes.List): if isinstance(sp.type, spectypes.Palette): if src is not None: src = [[0] + src] @@ -199,12 +203,12 @@ def merge_nodes(sp, src, dst, edit, loops): else: return edit if edit is not None else dst if dst is not None else src -def blend_xform(sxf, dxf, edits, loops, isfinal=False): +def blend_xform(sxf, dxf, edits, duration, isfinal=False): if sxf is None: sxf = padding_xform(dxf, isfinal) if dxf is None: dxf = padding_xform(sxf, isfinal) - return merge_nodes(specs.xform, sxf, dxf, edits, loops) + return merge_nodes(specs.xform, sxf, dxf, edits, duration) # If xin contains any of these, use the inverse identity hole_variations = ('spherical ngon julian juliascope polar ' diff --git a/cuburn/genome/specs.py b/cuburn/genome/specs.py index d9332d3..17354fb 100644 --- a/cuburn/genome/specs.py +++ b/cuburn/genome/specs.py @@ -70,8 +70,10 @@ time = ( }) blend = ( - { 'nloops': scalar(2) - , 'duration': scalar(2) + { 'duration': scalar(2, d='The base duration of the animation. This value ' + 'affects the periodic extension of angular parameters (values are ' + 'extended to minimize deviation from average velocity), and also ' + 'sets the default value for `time.duration` in an animation.') , 'xform_sort': enum('weightflip weight natural color') , 'xform_map': list_(list_(String('xfid'), d='A pair of src, dst IDs')) })