Design requirements for movie path planner

 

Usage: moviePlanner <optionFile>

 

optionFile format

 

ÔoptionFileÕ is an ASCII text file containing the following key/value combinations.

 

frameCount frameCount

            This is the number of frames the final movie will contain.

 

Preview previewFile

            This is the initial preview file, generally this will be the initial dataset timestep

 

DatasetBase baseDatasetPathAndFormat

This is the path and file format (in ÔprintfÕ form) of the real source data.  It need not be present on the system running the moviePlanner, and is used in the output frame specifications.  The format must include one integer substitution, which will be populated with the relevant computed timestep number.

 

DatasetInitialTimestep initialDatasetTimestepNumber

            This is the initial timestep sequence number for the real source data.

 

DatasetTimestepCount datasetTimestepCount

            This is the total number of timesteps in the real source data

 

DatasetTimestepIncrement datasetTimestepIncrement

This is the amount by which the timestep sequence number is increased from one timestep to the next.  This is usually Ô1Õ, but for situations where a sparse dataset is used, it may be more than one (i.e., if only every 4th timestep exists, this may be Ô4Õ).

 

OutputBase outputPathAndFormat

This is the path and file format (in ÔprintfÕ form) of the desired output file set.  The format must include a single integer substitution, which will be used to produce multiple frame camera specifications.

 

OutputInitialFrame initialOutputFrameNumber

This is the initial frame number for the output frame sequence.  This may be non-zero in the case of a multi-part movie.

 

DatasetKeyframe movieFrame datasetTimestep

This is an association between a particular movie frame and a corresponding dataset timestep.  There are only two required associations, one with frame Ô0Õ and one with frame Ôn-1Õ (where ÔnÕ is the total number of frames in the output movie).  If additional keyframes are assigned, they are used to produce a non-linear simulation progression (for instance, to emphasize the later parts of a simulation series where ÔinterestingÕ things happen).  There may be any number of these specified.

 

Basic Theory of Operation

 

The operation of the movie path planner will progress along a basic sequence of steps, which may be broken down into initialization, interaction, and output.  Initialization consists of reading in the optionsFile, parsing it, and producing the path layout environment.  Interaction consists of user interaction during which a set of camera keyframes is established.  Output consists of interpolating along a spline defined by the set of defined camera keyframes and producing a set of output camera specifications, one for each frame in the desired movie.  Each of these components is broken down in more detail below.

 

I)              Initialization

                                                     i.     Read the ÔoptionsFileÕ and parse it into appropriate variables

                                                      ii.     Establish a timeline for the movie

1.     The basis of the timeline is a simple progression of frames of exactly the requested movie length

2.     Augment the basis by interpolating the set of timestep keyframes such that at each movie frame the appropriate timestep is known

                                                        iii.     Load the initial preview dataset and display it

II)            Interaction

                                                     i.     Allow for the user to place a camera key position and viewpoint in 3-space.  This position/viewpoint combination (hereafter called a Ôcamera keyÕ) is associated with a particular location in the timeline, making it an animation keyframe.

                                                      ii.     Allow the user to modify the timestep associated with a particular camera key (to move it in the timeline).

                                                        iii.     Allow the user to remove any camera key Ð recalculate spline based on remaining camera keys

                                                        iv.     Allow the user to load additional preview data sets at any point.  An additional preview is associated with the time step at which it was loaded, and becomes the new ÔactiveÕ preview at all points after that timestep

                                                      v.     Allow the user to change the timestep associated with a particular preview dataset

                                                        vi.     Allow the user to remove a preview dataset

                                                         vii.     Allow the user to ÔscanÕ along timeline, watching some representation of the camera move from one camera key to another along the computed spline.  This ÔscanÕ should also cause the preview data set to change at the appropriate point.

III)          Output

                                                     i.     Compute the final spline based on all camera keys.

                                                      ii.     Apply the camera values to the pre-computed data timestep information to produce output camera specifications

                                                        iii.     Write output files according to requested base format and numbering.

 

Class Descriptions

 

The movie path planner shall consist of at least the following classes, with the following public interfaces.  In general, classes should each have their own python module, though several very closely related classes may exist in a common module (as noted below)

 

1)    Utilities Module

a.     Interpolation Class (virtual base class Ð multiple implementations)

                                                     i.     Singleton Ð not instantiated

                                                      ii.     [newValues] interpolateValues([oldValues],[oldBasis],[newBasis])

1.     Produces an array [newValues] using some form of interpolation (which form depends on the particular implementation).

2.     For each value in array [oldValues] there must be a matching value in array [oldBasis].  Interpolation is then performed between the values in [oldValues] (using whole integers only) based on the relative variation between [oldBasis] and [newBasis].

3.     [oldBasis] may contain gaps, as may [newBasis]

4.     The size of the space represented by [newBasis] MUST BE greater than or equal to the space represented by [oldBasis] (i.e. max[newBasis]-min[newBasis] >= max[oldBasis]-min[oldBasis])

b.     SplineInterpolation

                                                     i.     Implemenation of Interpolation Class producing a best-fit spline along the input set of values and using that spline to interpolate output values.

c.     LinearInterpolation

                                                     i.     Implementation of Interpolation Class producing a linear interpolation between the various points of the input set to map the output values.

d.     ConfigParser Class

                                                     i.     Singleton Ð not instantiated

                                                      ii.     {keyvalueDict} parseFile(filename)

1.     Produces (and returns) a dictionary of key/value pairs as parsed from the config file named by ÔfilenameÕ.

2.     ÔfilenameÕ must be ASCII text, can consist of lines that are of the following set:

a.     Blank lines are ignored

b.     Lines beginning with Ô#Õ are comments, and ignored

c.     Lines of the form Ô<keyword> <value>Õ where the keyword contains no whitespace, but the remainder of the line (whitespace included, beyond the initial delimiter) is considered the value

3.     Keywords are case-insensitive and all returned keywords in the dictionary are in lower case

4.     Multiple instances of the same keyword in a config file result in a list of values associated with that keyword in the dictionary.

                                                        iii.     ((missingKeys),{keyvalueDict}) parseValidateFile(filename,(requiredKeyList))

1.     Produces (and returns) two objects

a.     A tuple (or list) of the required keys that are not present in the config file

b.     A dictionary of key/value pairs as parsed from the config file named by ÔfilenameÕ

2.     The ÔrequiredKeyListÕ argument is a tuple (or list) containing the various key names (case-insensitive) that must be defined in the config file.  The returned ÔmissingKeysÕ is either an empty list, or a subset of ÔrequiredKeyListÕ representing those keys that are missing.

3.     Keywords are case-insensitive and all returned keywords in the dictionary are in lower case

4.     Multiple instances of the same keyword in a config file result in a list of values associated with that keyword in the dictionary.

2)    Camera Module

a.     Camera class

                                                     i.     For now, this is a placeholder class.  It just needs to exist in the design.  In the future, it will contain camera-specific parameters, such as:

1.     Color map

2.     Alpha map

3.     Frame size

4.     Other rendering options and characteristics

b.     Camera Key class

                                                     i.     This class provides the binding between a particular set of variable camera parameters (initially position, look-at and up vector) and a specific frame.

                                                      ii.     (frame) GetFrame()

1.     Return the ÔframeÕ associated with this Camera Key

                                                        iii.     () SetFrame(frame)

1.     Set the frame associated with this Camera Key

                                                        iv.     {cameraParm} GetCameraParm()

1.     Return a dictionary containing the camera parameters associated with this Camera Key.  This dictionary contains a minimum of:

a.     Camera position (a list of three values, key ÔpositionÕ)

b.     Camera look-at point (a list of three values, key ÔlookatÕ)

c.     Camera up vector (a list of three values, key ÔupÕ)

                                                      v.     () SetCameraParm({cameraParm})

1.     Set the dictionary containing the camera parameters associated with this Camera Key.  The dictionary must contain a minimum of:

a.     Camera position (a list of three values, key ÔpositionÕ)

b.     Camera look-at point (a  list of three values, key ÔlookatÕ)

c.     Camera up vector (a list of three values, key ÔupÕ)

3)    Preview Model class (and Module)

a.     This class represents a preview.  It associates a particular preview data set with a frame number.

b.     (frame) GetFrame()

                                                     i.     Return the frame number associated with this preview

c.     () SetFrame(frame)

                                                     i.     Sets the frame number associated with this preview

d.     {preview} GetPreview()

                                                     i.     Get the preview dictionary associated with this preview.  The preview dictionary *MUST* contain a key ÔfilenameÕ with the associated filename.  It will also contain user-defined data for storing the actual preview model once loaded, and any other information necessary for caching or more complex operations.

e.     () SetPreview({preview})

                                                     i.     Set the preview dictionary associated with this preview.  The preview dictionary *MUST* contain a key ÔfilenameÕ with the associated filename.  It will also contain user-defined data for storing the actual preview model once loaded, and any other information necessary for caching or more complex operations.

4)    SpecGenerator class (and Module)

a.     Singleton Ð not instantiated

b.     () WriteOutput(filename,timeline,camera)

                                                     i.     Write a set of camera spec files based on information in the Timeline class ÔtimelineÕ and the Camera class ÔcameraÕ.  Uses output configuration parameters specified in the config file ÔfilenameÕ.

1.     Parses ÔfilenameÕ using ConfigParser

2.     Performs a timeline.RecomputeFrames() to verify up-to-date frame state

3.     Iterates over frame set producing camera spec files

c.     NOTE: This design allows sub-classing to produce different spec file formats without changing the overall code.  This will become important as the application evolves.

5)    Timeline class (and Module)

a.      () loadConfig(filename)

                                                     i.     ÔfilenameÕ is the name of the config file

                                                      ii.     Uses ÔConfigParserÕ class to parse config file

                                                        iii.     Loads various values into internal state

                                                        iv.     Performs initial computation of timeline

1.     Forms a list of dictionaries representing ÔnÕ frames (number of frames in final movie, as requested in config file)

2.     Each dictionary contains the following

a.     Data set timestep (key ÔtimestepÕ)

b.     Active preview (key ÔpreviewÕ)

c.     Camera position (key ÔcameraÕ)

                                                                                                           i.     dictionary containing

1.     position (list of three values key ÔpositionÕ)

2.     look-at (list of three values key ÔlookatÕ)

3.     up-vector (list of three values key ÔupÕ)

                                                      v.     Initializes any non-configuration-based internal state

                                                        vi.     Initializes list of tuples for storing camera key -> frame mappings.

                                                         vii.     Initializes list of tuples for storing preview -> frame mappings

b.     {frameState} GetFrameData(frame)

                                                     i.     Index into frame list using ÔframeÕ and return the dictionary associated with it (as defined in (i)(4)(b)(iii) above).

                                                      ii.     Return ÔNoneÕ if frame is out of range

c.     (numFrames) GetNumFrames()

                                                     i.     Return the total number of frames

d.     (numCamKeys) GetNumCameraKeys()

                                                     i.     Return the total number of camera keys

e.     (cameraKey) GetCameraKey(camKeyNum)

                                                     i.     Return the cameraKey entry indexed by camKeyNum

                                                      ii.     Return ÔNoneÕ if camKeyNum is out of range

f.      () RemoveCameraKey(camKeyNum,recompute=true)

                                                     i.     Remove the camera key indexed by camKeyNum from the camera key list.

                                                      ii.     Re-compute camera positions for all frames using interpolation over new set of camera keys.

1.     If ÔrecomputeÕ is ÔfalseÕ, then do not do re-computation.  Useful for multiple operations, to avoid unnecessary duplicate re-computation.

                                                        iii.     Do nothing if camKeyNum is out of range

g.     () AddCameraKey(camKey,recompute=true)

                                                     i.     Add the camera key ÔcamKeyÕ to the camera key list

                                                      ii.     NOTE: the camera key list *MUST* be kept sorted (by frame #)

                                                        iii.     Re-compute camera positions for all frames using interpolation over new set of camera keys.

1.     If ÔrecomputeÕ is ÔfalseÕ, then do not do re-computation.  Useful for multiple operations, to avoid unnecessary duplicate recomputation

h.      (numPreviews) GetNumPreviews()

                                                     i.     Return the total number of preview entries

i.      (preview) GetPreview(previewNum)

                                                     i.     Return the preview entry indexed by previewNum

                                                      ii.     Return ÔNoneÕ if previewNum is out of range

j.      () RemovePreview(previewNum,recompute=true)

                                                     i.     Remove the preview indexed by previewNum from the preview list.

                                                      ii.     Re-compute active preview for all frames using simple repeat-until-change logic over preview list.

1.     If ÔrecomputeÕ is ÔfalseÕ, then do not do re-computation.  Useful for multiple operations, to avoid unnecessary duplicate re-computation.

                                                        iii.     Do nothing if previewNum is out of range

k.     () AddPreview(preview,recompute=true)

                                                     i.     Add the preview ÔpreviewÕ to the preview list

                                                      ii.     NOTE: the preview list *MUST* be kept sorted (by frame #)

                                                        iii.     Re-compute active preview for all frames using simple repeat-until-change logic over preview list.

1.     If ÔrecomputeÕ is ÔfalseÕ, then do not do re-computation.  Useful for multiple operations, to avoid unnecessary duplicate recomputation

l.      () RecomputeFrames()

                                                     i.     Force re-computation of all frame state (re-interpolates camera position based on current camera key list, performs repeat-until-change logic over preview list for active preview)

 

Design Guidelines

 

The following guidelines should be considered throughout the design and implementation of the application.

 

1)    Extensive use of Object Oriented Programming paradigms is preferred

a.     As python has deep support for objects and classes, including rich support for inheritance, object oriented techniques should be used in all stages of development

2)    Many simple objects preferred over few, complex objects

a.     This is a specialization of (1) above

b.     Any object requiring extensive, complex modules to implement can likely be re-factored as a set of simpler inter-related sub-classes.  This re-factoring should be favored whenever possible.

3)    API separation between GUI classes and functional implementation

a.     The GUI classes should interrogate and manipulate core functionality, but should not contain core functionality

b.     The core classes providing the base functionality of the program (such as the ÔTimelineÕ class above) should have clear API interfaces that are the *exclusive* means of communication between the core classes and the GUI classes.

c.     A replacement GUI should be implementable with very little (zero, ideally) knowledge of the implementation of the core functionality.

4)    All public API classes and functions should be documented

a.     In python, all functions are technically ÔpublicÕ.  There exists, however, a logical distinction between API functions and private implementation functions, even if the language does not enforce the distinction.

b.     All public ÔAPIÕ functions *must* be documented.  Private implementation functions should be documented, and must be marked as private implementation functions.  Documentation of private functions should be prioritized by the likelihood a particular function will be re-implemented or directly invoked by outside developers.

5)    One class per module

a.     In general, one class per module is a good rule in Python, helping keep the namespaces consistent.  Two exceptions exist.

b.     Exception 1: In rare cases, a set of utility functions and/or classes may be required.  In order to qualify, they must be outside the primary scope of program functionality, and must be Ôblack boxÕ utilities (i.e., the interpolation methods above, which are useful outside of the movie planner, are not part of movie planning, and are utilized as Ôblack boxÕ helpers).  Such utilities may be grouped into a single module (or small set of modules).

c.     Exception 2: In rare cases, several classes may be tightly coupled both as to use and implementation (i.e., the classes listed in the ÔCameraÕ module above).  These classes may be grouped into a single module.