Source code for firefly.data_reader.tween

from __future__ import print_function

import numpy as np

import os 

from .json_utils import write_to_json

[docs]class TweenParams(object): """A class to store tween parameters and make an output file"""
[docs] def __init__( self, coords=None, duration=5, loop=True, filename=None): """Create a new tween parameter object, allowing the user to press :code:`t` from within the webapp to move between keyframe camera locations smoothly and automatically. :param coords: keyframe camera coordinates, list of positions that camera will move between. 3 acceptable input formats: * [x,y,z] single keyframe * [[x1,y1,z1],[x2,y2,z2],...] multiple keyframes * [x1,y1,z1,x2,y2,z2,...] multiple flattened keyframes, defaults to [] :type coords: list of float :param duration: duration to approach keyframe in seconds. 3 acceptable input formats: * d single duration (will be repeated) * [d] single duration in list (will be repeated) * [d1,d2,...] multiple durations (corresponding to number of keyframes or raises an error), defaults to 5 :type duration: float/list of float :param loop: flag to loop after reaching the last keyframe, defaults to True :type loop: bool, optional :param filename: name of tween file :code:`.json` file, defaults to ``'TweenParams.json'`` :type filename: str, optional """ ## initialize containers self.coordss = np.array([]).reshape(0,3) try: iter(duration) except: duration = np.repeat(duration,np.size(coords)//3) self.durations = np.array([]) ## store loop flag self.loop = bool(loop) ## add keyframes if any were passed if coords is not None: self.addKeyframe(coords,duration) ## bind filename so js knows where to look self.filename = 'TweenParams.json' if filename is None else filename
[docs] def addKeyframe( self, coords, duration): """ Adds a new keyframe to an existing TweenParams object. :param coords: keyframe camera coordinates, list of positions that camera will move between 3 acceptable input formats: * [x,y,z] single keyframe * [[x1,y1,z1],[x2,y2,z2],...] multiple keyframes * [x1,y1,z1,x2,y2,z2,...] multiple flattened keyframes :type coords: list of float :param duration: duration to approach keyframe, 3 acceptable input formats: * d single duration (will be repeated) * [d] single duration in list (will be repeated) * [d1,d2,...] multiple durations (corresponding to number of keyframes or raises an error) :type duration: float/list of float :raises np.AxisError: if len of coords is not divisible by 3 :raises np.AxisError: if len of durations does not match len of coords """ try: ## cast to numpy array and reorder coords at the same time for ## convenient input coords = np.array(coords).reshape(-1,3) except: raise np.AxisError("coords should either be a 2d Nx3 numpy array or"+ "a 3N list/array.") ## convert duration to a 1d numpy array, however it was passed duration = np.array(duration).reshape(-1) if duration.shape == 1: duration = np.repeat(duration,coords.shape[0]) ## ensure there is a duration per keyframe transition ## TODO: shouldn't durations be 1 less than coordss? if duration.shape[0]!=coords.shape[0]: raise np.AxisError( "Mismatching coords and duration shape (%d,%d)"%( coords.shape[0], duration.shape[0])) self.coordss = np.append(self.coordss,coords,axis=0) self.durations = np.append(self.durations,duration)
[docs] def outputToDict(self): """Converts stored data into a single python dictionary. :return: tween_params_dict :rtype: dict """ xs,ys,zs = self.coordss.T keyframe_dicts = [ {'x':xs[i],'y':ys[i],'z':zs[i]} for i in range(xs.shape[0])] rotation_dicts = [ {'x':0,'y':0,'z':0} for i in range(xs.shape[0])] tween_params_dict = { 'position':keyframe_dicts, 'rotation':rotation_dicts, 'duration':self.durations, 'loop':self.loop, 'loaded':True } return tween_params_dict
[docs] def outputToJSON( self, datadir, file_prefix='', loud=1, write_to_disk=True, not_reader=True): """ Saves the current tween parameters to a JSON file. :param datadir: the sub-directory that will contain your JSON files, relative to your :code:`$HOME directory`. , defaults to :code:`$HOME/<file_prefix>` :type datadir: str, optional :param file_prefix: Prefix for any :code:`.json` files created, :code:`.json` files will be of the format: :code:`<file_prefix><self.filename>.json`, defaults to '' :type file_prefix: str, optional :param loud: flag to print status information to the console, defaults to True :type loud: bool, optional :param write_to_disk: flag that controls whether data is saved to disk (:code:`True`) or only converted to a string and returned (:code:`False`), defaults to True :type write_to_disk: bool, optional :param not_reader: flag for whether to print the Reader :code:`filenames.json` warning, defaults to True :type write_to_disk: bool, optional :return: filename, JSON(tween_params_dict) (either a filename if written to disk or a JSON strs) :rtype: str, str """ tween_params_dict = self.outputToDict() ## file_prefix+ filename = os.path.join(datadir,self.filename) if loud and not_reader: print("You will need to add this tween params filename to"+ " filenames.json if this was not called by a Reader instance.") return filename,write_to_json( tween_params_dict, filename if write_to_disk else None) ## None-> returns a string
def tweenOrbiter(radius=1,duration=10): """Helper function to create tween parameters for a camera orbit around the center. :param radius: radius of the orbit, defaults to 1 :type radius: int, optional :param duration: duration in seconds to complete a full orbit, defaults to 10 :type duration: int, optional :return: a TweenParams object that can be attached to a reader. :rtype: :class:`firefly.data_reader.TweenParams` """ thetas = np.arange(0,360,1) xs = np.sin(thetas/180*np.pi)*radius zs = np.cos(thetas/180*np.pi)*radius coords = np.zeros((thetas.size,3)) coords[:,1] = xs coords[:,-1] = zs return TweenParams(coords,duration=duration)