commit 568b29d8ff88078479ee5a1db1b2e91dc4e9113e
Author: Leszek Koltunski <leszek@distorted.org>
Date:   Thu Jun 16 01:44:58 2016 +0100

    Major push towards simplifying DistortedObject's public API.
    All MATRIX effects are using the new API - the 'DataND' marker interfaces.

diff --git a/src/main/java/org/distorted/library/DistortedObject.java b/src/main/java/org/distorted/library/DistortedObject.java
index 1b1b681..86ffc9f 100644
--- a/src/main/java/org/distorted/library/DistortedObject.java
+++ b/src/main/java/org/distorted/library/DistortedObject.java
@@ -24,16 +24,19 @@ import android.opengl.GLES20;
 import android.opengl.GLUtils;
 
 import org.distorted.library.message.EffectListener;
-import org.distorted.library.type.Float1D;
-import org.distorted.library.type.Float2D;
-import org.distorted.library.type.Float3D;
-import org.distorted.library.type.Float4D;
-import org.distorted.library.type.Interpolator;
-import org.distorted.library.type.Interpolator1D;
-import org.distorted.library.type.Interpolator2D;
-import org.distorted.library.type.Interpolator3D;
-import org.distorted.library.type.Interpolator4D;
-import org.distorted.library.type.InterpolatorQuat;
+import org.distorted.library.type.Data1D;
+import org.distorted.library.type.Data3D;
+import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic1D;
+import org.distorted.library.type.Dynamic2D;
+import org.distorted.library.type.Dynamic3D;
+import org.distorted.library.type.Dynamic4D;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static2D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+import org.distorted.library.type.DynamicQuat;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -41,8 +44,8 @@ import org.distorted.library.type.InterpolatorQuat;
  */
 public abstract class DistortedObject 
 {
-    private static final Float2D mZero2D = new Float2D(0,0);
-    private static final Float3D mZero3D = new Float3D(0,0,0);
+    private static final Static2D mZero2D = new Static2D(0,0);
+    private static final Static3D mZero3D = new Static3D(0,0,0);
 
     private static float[] mViewMatrix   = new float[16];
    
@@ -465,329 +468,102 @@ public abstract class DistortedObject
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Matrix-based effects
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// MOVE
 /**
- * Moves the Object by a vector that changes in time as interpolated by the Interpolator.
+ * Moves the Object by a vector that changes in time as interpolated by the Dynamic.
  * 
- * @param vector 3-dimensional Interpolator which at any given time will return a Float3D
+ * @param vector 3-dimensional Data which at any given time will return a Static3D
  *               representing the current coordinates of the vector we want to move the Object with.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-  public long move(Interpolator3D vector)
+  public long move(Data3D vector)
     {   
     return mM.add(EffectNames.MOVE,vector);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Moves the Object by a vector that smoothly changes from (0,0,0) to (x,y,z).
- *  
- * @param x        The x-coordinate of the vector we want to move the Object with. 
- * @param y        The y-coordinate of the vector we want to move the Object with.
- * @param z        The z-coordinate of the vector we want to move the Object with.
- * @param duration The time, in milliseconds, it takes to complete the movement.
- * @return         ID of the effect added, or -1 if we failed to add one. 
- */
-  public long move(float x,float y,float z, int duration)
-    {   
-    Interpolator3D di = new Interpolator3D();  
-    di.setCount(0.5f);
-    di.setDuration(duration);
-    di.add(new Float3D(0.0f,0.0f,0.0f));                             
-    di.add(new Float3D(x,y,z));                        
-
-    return mM.add(EffectNames.MOVE,di);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Moves the Object by vector (x,y,z) immediately.
- *   
- * @param x The x-coordinate of the vector we want to move the Object with. 
- * @param y The y-coordinate of the vector we want to move the Object with.
- * @param z The z-coordinate of the vector we want to move the Object with.
- * @return  ID of the effect added, or -1 if we failed to add one. 
- */
-  public long move(float x,float y,float z)
-    {   
-    return mM.add(EffectNames.MOVE,mZero3D,x,y,z,0.0f);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// SCALE
-/**
- * Scales the Object by factors that change in time as returned by the Interpolator.
+ * Scales the Object by factors that change in time as returned by the Dynamic.
  * 
- * @param scale 3-dimensional Interpolator which at any given time returns a Float3D
+ * @param scale 3-dimensional Dynamic which at any given time returns a Static3D
  *              representing the current x- , y- and z- scale factors.
  * @return      ID of the effect added, or -1 if we failed to add one.
  */
-  public long scale(Interpolator3D scale)
+  public long scale(Data3D scale)
     {   
     return mM.add(EffectNames.SCALE,scale);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Scales the Object by a factor that smoothly changes from (1,1,1) at time 0 to (xscale,yscale,zscale)
- * after 'duration' milliseconds. 
- *    
- * @param xscale   After time 'duration' passes, Object's width will get multiplied by xscale; e.g. if
- *                 xscale=2, after 'duration' milliseconds the Object will become twice broader.
- * @param yscale   Factor to scale Object's height with.
- * @param zscale   Factor to scale Object's depth with.
- * @param duration Time, in milliseconds, it takes to interpolate to the full (xscale,yscale,zscale) scaling factors.
- * @return         ID of the effect added, or -1 if we failed to add one. 
- */
-  public long scale(float xscale,float yscale,float zscale, int duration)
-    {   
-    Interpolator3D di = new Interpolator3D();  
-    di.setCount(0.5f);
-    di.setDuration(duration);
-    di.add(new Float3D(1.0f,1.0f,1.0f));                             
-    di.add(new Float3D(xscale,yscale,zscale));                        
-
-    return mM.add(EffectNames.SCALE,di);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Immediately scales the Object's width by (xscale,yscale,zscale).   
- *   
- * @param xscale Object's width gets multiplied by this factor; e.g. if 
- *               xscale=2, the Object immediately becomes twice broader.
- * @param yscale factor to scale Object's height with.
- * @param zscale factor to scale Object's depth with. 
- * @return       ID of the effect added, or -1 if we failed to add one. 
- */
-  public long scale(float xscale,float yscale,float zscale)
-    {   
-    return mM.add(EffectNames.SCALE,mZero3D,xscale,yscale,zscale,0.0f);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Convenience function - scale the Object by the same factor in all 3 dimensions.   
- *   
- * @param scale all 3 Object's dimensions get multiplied by this factor; e.g. if 
- *              scale=2, the Object immediately becomes twice larger.
- * @return      ID of the effect added, or -1 if we failed to add one. 
- */
-  public long scale(float scale)
-    {   
-    return mM.add(EffectNames.SCALE,mZero3D,scale,scale,scale,0.0f);
-    }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// ROTATE
-/**
- * Rotates the Object around a (possibly moving) point, with angle and axis that change in time.
- * 
- * @param center    3-dimensional Interpolator which at any given time will return the current center
- *                  of the rotation
- * @param angleAxis 4-dimensional Interpolator which at any given time will return a Float4D
- *                  representing the current rotation in the (angle,axisX,axisY,axisY) form.
- * @return          ID of the effect added, or -1 if we failed to add one.
- */
-  public long rotate(Interpolator3D center, Interpolator4D angleAxis)
-    {   
-    return mM.add(EffectNames.ROTATE, center, angleAxis);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////  
-/**
- * Rotates the Object around a static point, with angle and axis that change in time.
- * 
- * @param center    Center of the rotation
- * @param angleAxis 4-dimensional Interpolator which at any given time will return a Float4D
- *                  representing the current rotation in the (angle,axisX,axisY,axisY) form.
- * @return          ID of the effect added, or -1 if we failed to add one.
- */
-  public long rotate(Float3D center, Interpolator4D angleAxis)
-    {   
-    return mM.add(EffectNames.ROTATE, center , angleAxis);
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////  
-/**
- * Rotates the Object around a static point, with angle that changes in time, around axis 
- * (axisX, axisY, axisZ). 
- * 
- * @param center Center of the rotation
- * @param angle  1-dimensional Interpolator which at any given time will return the current rotation
- *               angle.
- * @param axisX  Rotation vector: x-coordinate
- * @param axisY  Rotation vector: y-coordinate
- * @param axisZ  Rotation vector: z-coordinate
- * @return       ID of the effect added, or -1 if we failed to add one.
- */
-  public long rotate(Float3D center, Interpolator1D angle, float axisX, float axisY, float axisZ)
-    {   
-    return mM.add(EffectNames.ROTATE, center , angle, axisX, axisY, axisZ);
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotates the Object around a (possibly moving) point, with angle that changes in time.
- * Axis of rotation is the vector (0,0,1), i.e. a vector normal to the screen surface.
- * 
- * @param center 3-dimensional Interpolator which at any given time will return the current center
- *               of the rotation.
- * @param angle  1-dimensional Interpolator which returns the current rotation angle.
- * @return       ID of the effect added, or -1 if we failed to add one.
- */
-  public long rotate(Interpolator3D center, Interpolator1D angle)
-    {   
-    return mM.add(EffectNames.ROTATE, center, angle, 0.0f,0.0f,1.0f);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotates the Object around a constant point, with angle that changes in time.  
- * Axis of rotation is the vector (0,0,1), i.e. a vector normal to the screen surface.
- *   
- * @param center   Coordinates of the Point we are rotating around.
- * @param angle    Angle that we want to rotate the Object to. Unit: degrees
- * @param duration Time, in milliseconds, it takes to complete one rotation from 0 to 'angle' degrees.
- * @return         ID of the effect added, or -1 if we failed to add one. 
- */
-  public long rotate(Float3D center, int angle, int duration)
-    {   
-    Interpolator1D di = new Interpolator1D();  
-    di.setCount(0.5f);
-    di.setDuration(duration);
-    di.add(new Float1D(    0));
-    di.add(new Float1D(angle));                        
-
-    return mM.add(EffectNames.ROTATE, center, di, 0.0f,0.0f,1.0f);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotates the Object immediately by 'angle' degrees around point p.   
- * Axis of rotation is given by the last 3 floats.
- *   
+ * Rotates the Object by 'angle' degrees around the center.
+ * Static axis of rotation is given by the last parameter.
+ *
  * @param center Coordinates of the Point we are rotating around.
  * @param angle  Angle that we want to rotate the Object to. Unit: degrees
- * @param axisX  Axis of rotation: x-coordinate
- * @param axisY  Axis of rotation: y-coordinate
- * @param axisZ  Axis of rotation: z-coordinate
+ * @param axis   Axis of rotation
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-  public long rotate(Float3D center, float angle, float axisX, float axisY, float axisZ)
-    {   
-    return mM.add(EffectNames.ROTATE, center, angle, axisX, axisY, axisZ);
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Rotates the Object immediately by 'angle' degrees around point p.   
- *   
- * @param center Coordinates of the Point we are rotating around.
- * @param angle  The angle that we want to rotate the Object to. Unit: degrees
- * @return       ID of the effect added, or -1 if we failed to add one. 
- */
-  public long rotate(Float3D center, int angle)
+  public long rotate(Data3D center, Data1D angle, Static3D axis)
     {   
-    return mM.add(EffectNames.ROTATE, center, angle,0.0f,0.0f,1.0f);
+    return mM.add(EffectNames.ROTATE, center, angle, axis);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// QUATERNION
 /**
- * Rotates the Object immediately by quaternion (qX,qY,qZ,qW).
- *   
- * @param center Coordinates of the Point we are rotating around.
- * @param qX     Quaternion: x-coordinate
- * @param qY     Quaternion: y-coordinate
- * @param qZ     Quaternion: z-coordinate
- * @param qW     Quaternion: w-coordinate
- * @return       ID of the effect added, or -1 if we failed to add one.
+ * Rotates the Object by 'angle' degrees around the center.
+ * Static axis of rotation is given by the last parameter.
+ *
+ * @param center    Coordinates of the Point we are rotating around.
+ * @param angleaxis Combined 4-tuple representing the (angle,axisX,axisY,axisZ).
+ * @return          ID of the effect added, or -1 if we failed to add one.
  */
-  public long quaternion(Float3D center, float qX, float qY, float qZ, float qW)
-    {   
-    return mM.add(EffectNames.QUATERNION,center,qX,qY,qZ,qW);
+  public long rotate(Data3D center, Data4D angleaxis)
+    {
+    return mM.add(EffectNames.ROTATE, center, angleaxis);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Rotates the Object by a quaternion that's at the moment returned by the InterpolatorQuat.
+ * Rotates the Object by quaternion.
  *   
- * @param center Coordinates of the Point we are rotating around.
- * @param quat   Interpolator that's going to, at any given moment, return a quaternion.
- * @return       ID of the effect added, or -1 if we failed to add one.
+ * @param center     Coordinates of the Point we are rotating around.
+ * @param quaternion The quaternion describing the rotation.
+ * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long quaternion(Float3D center, InterpolatorQuat quat)
-    {   
-    return mM.add(EffectNames.QUATERNION, center, quat);
+  public long quaternion(Data3D center, Data4D quaternion)
+    {
+    return mM.add(EffectNames.QUATERNION,center,quaternion);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Rotates the Object around a moving point by a quaternion that's at the moment returned by the InterpolatorQuat.
- *   
- * @param center Interpolator that returns the current center of rotation.
- * @param quat   Interpolator that's going to, at any given moment, return a quaternion representing
- *               the current rotation.
- * @return       ID of the effect added, or -1 if we failed to add one.
- */
-  public long quaternion(Interpolator3D center, InterpolatorQuat quat)
-    {   
-    return mM.add(EffectNames.QUATERNION,center,quat);
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// SHEAR
-/**
- * Shears the Object. If the Interpolator is 1D, it will shear along the X-axis. 2D Interpolator adds
- * shearing along the Y-axis, 3D one along Z axis.
+ * Shears the Object.
  *
  * @param center  Center of shearing, i.e. the point which stays unmoved.
- * @param shear   1- 2- or 3D Interpolator which, at any given point, returns the ordered 1-, 2-
- *                or 3-tuple of shear factors.
+ * @param shear   The 3-tuple of shear factors.
  * @return        ID of the effect added, or -1 if we failed to add one.
  */
-  public long shear(Float3D center, Interpolator shear)
+  public long shear(Data3D center, Data3D shear)
     {
     return mM.add(EffectNames.SHEAR, center, shear);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Shears the Object in 3D. Order: first X shearing, then Y, then Z.
- * 
- * @param center Center of shearing, i.e. the point which stays unmoved.
- * @param shear  ordered 3-tuple (x-degree, y-degree, z-degree) of shearing (tangent of the angle with
- *               which the X,Y and Z axis get slanted) 
- * @return       ID of the effect added, or -1 if we failed to add one. 
- */
-  public long shear(Float3D center, Float3D shear)
-    {
-    Interpolator3D di = new Interpolator3D(); 
-    di.setCount(0.5f);
-    di.setDuration(0);
-    di.add(new Float3D(0.0f,0.0f,0.0f));              
-    di.add(shear);
-        
-    return mM.add(EffectNames.SHEAR, center, di );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Fragment-based effects  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // MACROBLOCK
 /**
- * Creates macroblocks at and around point defined by the Interpolator2D and the Region. 
- * Size of the macroblocks at any given time is returned by the Interpolator1D.
+ * Creates macroblocks at and around point defined by the Dynamic2D and the Region.
+ * Size of the macroblocks at any given time is returned by the Dynamic1D.
  * 
- * @param size   1-dimensional Interpolator which, at any given time, returns the size of the macroblocks.
+ * @param size   1-dimensional Dynamic which, at any given time, returns the size of the macroblocks.
  * @param region Region this Effect is limited to.
  *               Null here means 'apply the effect to the whole Object'.
- * @param center 2-dimensional Interpolator which, at any given time, returns a Float2D representing the
+ * @param center 2-dimensional Dynamic which, at any given time, returns a Static2D representing the
  *               current center of the effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long macroblock(Interpolator1D size, Float4D region, Interpolator2D center)
+  public long macroblock(Dynamic1D size, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.MACROBLOCK, size, region, center);
     }
@@ -795,24 +571,24 @@ public abstract class DistortedObject
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Creates macroblocks at and around point defined by the Point2D and the Region. 
- * Size of the macroblocks at any given time is returned by the Interpolator1D.
+ * Size of the macroblocks at any given time is returned by the Dynamic1D.
  * <p>
  * The difference between this and the previous method is that here the center of the Effect stays constant.
  *    
- * @param size   1-dimensional Interpolator which, at any given time, returns the size of the macroblocks.
+ * @param size   1-dimensional Dynamic which, at any given time, returns the size of the macroblocks.
  * @param region Region this Effect is limited to. 
  *               Null here means 'apply the effect to the whole Object'.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long macroblock(Interpolator1D size, Float4D region, Float2D center)
+  public long macroblock(Dynamic1D size, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.MACROBLOCK, size, region, center);
     }
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Creates macroblocks at and around point defined by the Interpolator2D and the Region. 
+ * Creates macroblocks at and around point defined by the Dynamic2D and the Region.
  * <p>
  * The macroblocks change in size; at time 0 there are none, and after 'duration/2' milliseconds 
  * they are of (pixels X pixels) size; after 'duration' milliseconds there are again none (i.e. their
@@ -821,19 +597,19 @@ public abstract class DistortedObject
  * @param pixels   Maximum size, in pixels, of the Macroblocks we want to see.
  * @param region   Region this Effect is limited to. 
  *                 Null here means 'apply the effect to the whole Object'.
- * @param center   2-dimensional Interpolator which, at any given time, returns a Float2D representing the
+ * @param center   2-dimensional Dynamic which, at any given time, returns a Static2D representing the
  *                 current center of the effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long macroblock(int pixels, Float4D region, Interpolator2D center, int duration, float count)
+  public long macroblock(int pixels, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D();
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                             
-    di.add(new Float1D(pixels));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(pixels));
 
     return mF.add(EffectNames.MACROBLOCK, di, region, center);
     }
@@ -853,16 +629,16 @@ public abstract class DistortedObject
  *                 Null here means 'apply the effect to the whole Object'.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long macroblock(int pixels, Float4D region, Float2D center, int duration, float count)
+  public long macroblock(int pixels, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D();
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                             
-    di.add(new Float1D(pixels));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(pixels));
 
     return mF.add(EffectNames.MACROBLOCK, di, region, center);
     }
@@ -880,16 +656,16 @@ public abstract class DistortedObject
  *    
  * @param pixels   Maximum size, in pixels, of the Macroblocks we want to see.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
   public long macroblock(int pixels, int duration, float count) 
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                            
-    di.add(new Float1D(pixels));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(pixels));
    
     return mF.add(EffectNames.MACROBLOCK, di, null, mZero2D);
     }
@@ -900,16 +676,16 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
  *        
- * @param blend  1-dimensional Interpolator that returns the level of blend a given pixel will be
+ * @param blend  1-dimensional Dynamic that returns the level of blend a given pixel will be
  *               mixed with the next parameter 'color': pixel = (1-level)*pixel + level*color
  * @param color  Color to mix. (1,0,0) is RED.
  * @param region Region this Effect is limited to. 
  *               Null here means 'apply the Effect to the whole Object'.
- * @param center 2-dimensional Interpolator which, at any given time, returns a Float2D representing
+ * @param center 2-dimensional Dynamic which, at any given time, returns a Static2D representing
  *               the current center of the effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long chroma(Interpolator1D blend, Float3D color, Float4D region, Interpolator2D center)
+  public long chroma(Dynamic1D blend, Static3D color, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.CHROMA, blend, color, region, center);
     }
@@ -920,7 +696,7 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param blend  1-dimensional Interpolator that returns the level of blend a given pixel will be
+ * @param blend  1-dimensional Dynamic that returns the level of blend a given pixel will be
  *               mixed with the next parameter 'color': pixel = (1-level)*pixel + level*color
  * @param color  Color to mix. (1,0,0) is RED.
  * @param region Region this Effect is limited to. 
@@ -928,7 +704,7 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long chroma(Interpolator1D blend, Float3D color, Float4D region, Float2D center)
+  public long chroma(Dynamic1D blend, Static3D color, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.CHROMA, blend, color, region, center);
     }
@@ -942,11 +718,11 @@ public abstract class DistortedObject
  * @param color  Color to mix. (1,0,0) is RED.
  * @param region Region this Effect is limited to.
  *               Null here means 'apply the Effect to the whole Object'.
- * @param center 2-dimensional Interpolator which, at any given time, returns a Float2D representing the
+ * @param center 2-dimensional Dynamic which, at any given time, returns a Static2D representing the
  *               current center of the effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long chroma(float blend, Float3D color, Float4D region, Interpolator2D center)
+  public long chroma(float blend, Static3D color, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.CHROMA, blend, color, region, center);
     }
@@ -965,7 +741,7 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long chroma(float blend, Float3D color, Float4D region, Float2D center)
+  public long chroma(float blend, Static3D color, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.CHROMA, blend, color, region, center);
     }
@@ -981,7 +757,7 @@ public abstract class DistortedObject
  * @param color Color to mix. (1,0,0) is RED.
  * @return      ID of the effect added, or -1 if we failed to add one. 
  */
-  public long chroma(float blend, Float3D color)
+  public long chroma(float blend, Static3D color)
     {
     return mF.add(EffectNames.CHROMA, blend, color, null, mZero2D);
     }
@@ -990,9 +766,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
  * 
- * See {@link #chroma(Interpolator1D, Float3D, Float4D, Interpolator2D)}
+ * See {@link #chroma(Dynamic1D, Static3D, Static4D, Dynamic2D)}
  */
-  public long smooth_chroma(Interpolator1D blend, Float3D color, Float4D region, Interpolator2D center)
+  public long smooth_chroma(Dynamic1D blend, Static3D color, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SMOOTH_CHROMA, blend, color, region, center);
     }
@@ -1001,9 +777,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
  * 
- * See {@link #chroma(Interpolator1D, Float3D, Float4D, Float2D)}
+ * See {@link #chroma(Dynamic1D, Static3D, Static4D, Static2D)}
  */
-  public long smooth_chroma(Interpolator1D blend, Float3D color, Float4D region, Float2D center)
+  public long smooth_chroma(Dynamic1D blend, Static3D color, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SMOOTH_CHROMA, blend, color, region, center);
     }
@@ -1012,9 +788,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
  * 
- * See {@link #chroma(float, Float3D, Float4D, Interpolator2D)}
+ * See {@link #chroma(float, Static3D, Static4D, Dynamic2D)}
  */
-  public long smooth_chroma(float blend, Float3D color, Float4D region, Interpolator2D center)
+  public long smooth_chroma(float blend, Static3D color, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SMOOTH_CHROMA, blend, color, region, center);
     }
@@ -1023,9 +799,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
  * 
- * See {@link #chroma(float, Float3D, Float4D, Float2D)}
+ * See {@link #chroma(float, Static3D, Static4D, Static2D)}
  */
-  public long smooth_chroma(float blend, Float3D color, Float4D region, Float2D center)
+  public long smooth_chroma(float blend, Static3D color, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SMOOTH_CHROMA, blend, color, region, center);
     }
@@ -1034,9 +810,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change all three of its RGB components.
  * 
- * See {@link #chroma(float, Float3D)}
+ * See {@link #chroma(float, Static3D)}
  */
-  public long smooth_chroma(float blend, Float3D color)
+  public long smooth_chroma(float blend, Static3D color)
     {
     return mF.add(EffectNames.SMOOTH_CHROMA, blend, color, null, mZero2D);
     }
@@ -1047,15 +823,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its transparency level.
  *        
- * @param alpha  1-dimensional Interpolator that returns the level of transparency we want to have at any given
+ * @param alpha  1-dimensional Dynamic that returns the level of transparency we want to have at any given
  *               moment.
  * @param region Region this Effect is limited to. 
  *               Null here means 'apply the Effect to the whole Object'.
- * @param center 2-dimensional Interpolator which, at any given time, returns a Float2D representing the
+ * @param center 2-dimensional Dynamic which, at any given time, returns a Static2D representing the
  *               current center of the effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long alpha(Interpolator1D alpha, Float4D region, Interpolator2D center)
+  public long alpha(Dynamic1D alpha, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.ALPHA, alpha, region, center);
     }
@@ -1066,14 +842,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param alpha  1-dimensional Interpolator that returns the level of transparency we want to have at any given
+ * @param alpha  1-dimensional Dynamic that returns the level of transparency we want to have at any given
  *               moment.
  * @param region Region this Effect is limited to. 
  *               Null here means 'apply the Effect to the whole Object'.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long alpha(Interpolator1D alpha, Float4D region, Float2D center)
+  public long alpha(Dynamic1D alpha, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.ALPHA, alpha, region, center);
     }
@@ -1085,19 +861,19 @@ public abstract class DistortedObject
  * @param alpha  Level of Alpha (between 0 and 1) we want to interpolate to.
  * @param region Region this Effect is limited to. 
  *               Null here means 'apply the Effect to the whole Object'.
- * @param center 2-dimensional Interpolator which, at any given time, returns a Float2D representing the
+ * @param center 2-dimensional Dynamic which, at any given time, returns a Static2D representing the
  *               current center of the effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count  Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count  Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long alpha(float alpha, Float4D region, Interpolator2D center, int duration, float count)
+  public long alpha(float alpha, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(alpha));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
    
     return mF.add(EffectNames.ALPHA, di, region, center);
     }
@@ -1113,16 +889,16 @@ public abstract class DistortedObject
  *                 Null here means 'apply the Effect to the whole Object'.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one.
  */
-  public long alpha(float alpha, Float4D region, Float2D center, int duration, float count)
+  public long alpha(float alpha, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(alpha));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
    
     return mF.add(EffectNames.ALPHA, di, region, center);
     }
@@ -1139,13 +915,13 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long alpha(float alpha, Float4D region, Float2D center)
+  public long alpha(float alpha, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(alpha));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
    
     return mF.add(EffectNames.ALPHA, di, region, center);
     }
@@ -1156,16 +932,16 @@ public abstract class DistortedObject
  * 
  * @param alpha    Level of Alpha (between 0 and 1) we want to interpolate to.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
   public long alpha(float alpha, int duration, float count) 
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                            
-    di.add(new Float1D(alpha));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
          
     return mF.add(EffectNames.ALPHA, di,null, mZero2D);
     }
@@ -1174,9 +950,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its transparency level.
  * 
- * See {@link #alpha(Interpolator1D, Float4D, Interpolator2D)}
+ * See {@link #alpha(Dynamic1D, Static4D, Dynamic2D)}
  */
-  public long smooth_alpha(Interpolator1D alpha, Float4D region, Interpolator2D center)
+  public long smooth_alpha(Dynamic1D alpha, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SMOOTH_ALPHA, alpha, region, center);
     }
@@ -1185,9 +961,9 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its transparency level.
  * 
- * See {@link #alpha(Interpolator1D, Float4D, Float2D)}
+ * See {@link #alpha(Dynamic1D, Static4D, Static2D)}
  */
-  public long smooth_alpha(Interpolator1D alpha, Float4D region, Float2D center)
+  public long smooth_alpha(Dynamic1D alpha, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SMOOTH_ALPHA, alpha, region, center);
     }
@@ -1196,15 +972,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its transparency level.
  * 
- * See {@link #alpha(float, Float4D, Interpolator2D, int, float)}
+ * See {@link #alpha(float, Static4D, Dynamic2D, int, float)}
  */
-  public long smooth_alpha(float alpha, Float4D region, Interpolator2D center, int duration, float count)
+  public long smooth_alpha(float alpha, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(alpha));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
    
     return mF.add(EffectNames.SMOOTH_ALPHA, di, region, center);
     }
@@ -1213,15 +989,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its transparency level.
  * 
- * See {@link #alpha(float, Float4D, Float2D, int, float)}
+ * See {@link #alpha(float, Static4D, Static2D, int, float)}
  */
-  public long smooth_alpha(float alpha, Float4D region, Float2D center, int duration, float count)
+  public long smooth_alpha(float alpha, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(alpha));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
    
     return mF.add(EffectNames.SMOOTH_ALPHA, di, region, center);
     }
@@ -1230,15 +1006,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its transparency level.
  * 
- * See {@link #alpha(float, Float4D, Float2D)}
+ * See {@link #alpha(float, Static4D, Static2D)}
  */
-  public long smooth_alpha(float alpha, Float4D region, Float2D center)
+  public long smooth_alpha(float alpha, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(alpha));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(alpha));
    
     return mF.add(EffectNames.SMOOTH_ALPHA, di, region, center);
     }
@@ -1249,15 +1025,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its brightness level.
  *        
- * @param brightness 1-dimensional Interpolator that returns the level of brightness we want to have
+ * @param brightness 1-dimensional Dynamic that returns the level of brightness we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D representing
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D representing
  *                   the current center of the effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long brightness(Interpolator1D brightness, Float4D region, Interpolator2D center)
+  public long brightness(Dynamic1D brightness, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.BRIGHTNESS, brightness, region, center);
     }
@@ -1268,14 +1044,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param brightness 1-dimensional Interpolator that returns the level of brightness we want to have
+ * @param brightness 1-dimensional Dynamic that returns the level of brightness we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long brightness(Interpolator1D brightness, Float4D region, Float2D center)
+  public long brightness(Dynamic1D brightness, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.BRIGHTNESS, brightness, region, center);
     }
@@ -1289,19 +1065,19 @@ public abstract class DistortedObject
  *                   anything more than 1- lighten it up. 
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   representing the current center of the effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long brightness(float brightness, Float4D region, Interpolator2D center, int duration, float count)
+  public long brightness(float brightness, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(brightness));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
    
     return mF.add(EffectNames.BRIGHTNESS, di, region, center);
     }
@@ -1319,16 +1095,16 @@ public abstract class DistortedObject
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long brightness(float brightness, Float4D region, Float2D center, int duration, float count)
+  public long brightness(float brightness, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(brightness));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
    
     return mF.add(EffectNames.BRIGHTNESS, di, region, center);
     }
@@ -1347,13 +1123,13 @@ public abstract class DistortedObject
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long brightness(float brightness, Float4D region, Float2D center)
+  public long brightness(float brightness, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(brightness));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
    
     return mF.add(EffectNames.BRIGHTNESS, di, region, center);
     }
@@ -1364,15 +1140,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its brightness level.
  *        
- * @param brightness 1-dimensional Interpolator that returns the level of brightness we want to have
+ * @param brightness 1-dimensional Dynamic that returns the level of brightness we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   representing the current center of the effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long smooth_brightness(Interpolator1D brightness, Float4D region, Interpolator2D center)
+  public long smooth_brightness(Dynamic1D brightness, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SMOOTH_BRIGHTNESS, brightness, region, center);
     }
@@ -1383,14 +1159,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param brightness 1-dimensional Interpolator that returns the level of brightness we want to have
+ * @param brightness 1-dimensional Dynamic that returns the level of brightness we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long smooth_brightness(Interpolator1D brightness, Float4D region, Float2D center)
+  public long smooth_brightness(Dynamic1D brightness, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SMOOTH_BRIGHTNESS, brightness, region, center);
     }
@@ -1404,19 +1180,19 @@ public abstract class DistortedObject
  *                   anything more than 1 - lighten it up. 
  * @param region     Region this Effect is limited to. 
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   represention the current center of the effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_brightness(float brightness, Float4D region, Interpolator2D center, int duration, float count)
+  public long smooth_brightness(float brightness, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(brightness));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
    
     return mF.add(EffectNames.SMOOTH_BRIGHTNESS, di, region, center);
     }
@@ -1434,16 +1210,16 @@ public abstract class DistortedObject
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_brightness(float brightness, Float4D region, Float2D center, int duration, float count)
+  public long smooth_brightness(float brightness, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(brightness));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
    
     return mF.add(EffectNames.SMOOTH_BRIGHTNESS, di, region, center);
     }
@@ -1462,13 +1238,13 @@ public abstract class DistortedObject
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_brightness(float brightness, Float4D region, Float2D center)
+  public long smooth_brightness(float brightness, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(brightness));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
    
     return mF.add(EffectNames.SMOOTH_BRIGHTNESS, di, region, center);
     }
@@ -1481,16 +1257,16 @@ public abstract class DistortedObject
  *                   1 - level of brightness unchanged, anything less than 1 - 'darken the image',
  *                   anything more than 1- lighten it up.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
   public long smooth_brightness(float brightness, int duration, float count) 
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                            
-    di.add(new Float1D(brightness));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(brightness));
          
     return mF.add(EffectNames.SMOOTH_BRIGHTNESS, di,null, mZero2D);
     }
@@ -1501,15 +1277,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its contrast level.
  *        
- * @param contrast 1-dimensional Interpolator that returns the level of contrast we want to have
+ * @param contrast 1-dimensional Dynamic that returns the level of contrast we want to have
  *                 at any given moment.
  * @param region   Region this Effect is limited to.
  *                 Null here means 'apply the Effect to the whole Object'.
- * @param center   2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center   2-dimensional Dynamic which, at any given time, returns a Static2D
  *                 representing the current center of the effect.
  * @return         ID of the effect added, or -1 if we failed to add one.
  */
-  public long contrast(Interpolator1D contrast, Float4D region, Interpolator2D center)
+  public long contrast(Dynamic1D contrast, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.CONTRAST, contrast, region, center);
     }
@@ -1520,14 +1296,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param contrast 1-dimensional Interpolator that returns the level of contrast we want to have
+ * @param contrast 1-dimensional Dynamic that returns the level of contrast we want to have
  *                 at any given moment.
  * @param region   Region this Effect is limited to.
  *                 Null here means 'apply the Effect to the whole Object'.
  * @param center  Center of the Effect.
  * @return        ID of the effect added, or -1 if we failed to add one.
  */
-  public long contrast(Interpolator1D contrast, Float4D region, Float2D center)
+  public long contrast(Dynamic1D contrast, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.CONTRAST, contrast, region, center);
     }
@@ -1541,19 +1317,19 @@ public abstract class DistortedObject
  *                 anything more than 1 - increase the contrast. 
  * @param region   Region this Effect is limited to.
  *                 Null here means 'apply the Effect to the whole Object'.
- * @param center   2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center   2-dimensional Dynamic which, at any given time, returns a Static2D
  *                 represention the current center of the effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long contrast(float contrast, Float4D region, Interpolator2D center, int duration, float count)
+  public long contrast(float contrast, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(contrast));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
    
     return mF.add(EffectNames.CONTRAST, di, region, center);
     }
@@ -1571,16 +1347,16 @@ public abstract class DistortedObject
  *                 Null here means 'apply the Effect to the whole Object'.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long contrast(float contrast, Float4D region, Float2D center, int duration, float count)
+  public long contrast(float contrast, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(contrast));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
    
     return mF.add(EffectNames.CONTRAST, di, region, center);
     }
@@ -1599,13 +1375,13 @@ public abstract class DistortedObject
  * @param center   Center of the Effect.
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long contrast(float contrast, Float4D region, Float2D center)
+  public long contrast(float contrast, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(contrast));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
    
     return mF.add(EffectNames.CONTRAST, di, region, center);
     }
@@ -1616,15 +1392,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its contrast level.
  *        
- * @param contrast 1-dimensional Interpolator that returns the level of contrast we want to have
+ * @param contrast 1-dimensional Dynamic that returns the level of contrast we want to have
  *                 at any given moment.
  * @param region   Region this Effect is limited to.
  *                 Null here means 'apply the Effect to the whole Object'.
- * @param center   2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center   2-dimensional Dynamic which, at any given time, returns a Static2D
  *                 representing the current center of the effect.
  * @return         ID of the effect added, or -1 if we failed to add one.
  */
-  public long smooth_contrast(Interpolator1D contrast, Float4D region, Interpolator2D center)
+  public long smooth_contrast(Dynamic1D contrast, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SMOOTH_CONTRAST, contrast, region, center);
     }
@@ -1635,14 +1411,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param contrast 1-dimensional Interpolator that returns the level of contrast we want to have
+ * @param contrast 1-dimensional Dynamic that returns the level of contrast we want to have
  *                 at any given moment.
  * @param region   Region this Effect is limited to.
  *                 Null here means 'apply the Effect to the whole Object'.
  * @param center   Center of the Effect.
  * @return         ID of the effect added, or -1 if we failed to add one.
  */
-  public long smooth_contrast(Interpolator1D contrast, Float4D region, Float2D center)
+  public long smooth_contrast(Dynamic1D contrast, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SMOOTH_CONTRAST, contrast, region, center);
     }
@@ -1656,19 +1432,19 @@ public abstract class DistortedObject
  *                 anything more than 1 - increase the contrast. 
  * @param region   Region this Effect is limited to. 
  *                 Null here means 'apply the Effect to the whole Object'.
- * @param center   2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center   2-dimensional Dynamic which, at any given time, returns a Static2D
  *                 representing the current center of the effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_contrast(float contrast, Float4D region, Interpolator2D center, int duration, float count)
+  public long smooth_contrast(float contrast, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(contrast));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
    
     return mF.add(EffectNames.SMOOTH_CONTRAST, di, region, center);
     }
@@ -1686,16 +1462,16 @@ public abstract class DistortedObject
  *                 Null here means 'apply the Effect to the whole Object'.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_contrast(float contrast, Float4D region, Float2D center, int duration, float count)
+  public long smooth_contrast(float contrast, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(contrast));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
    
     return mF.add(EffectNames.SMOOTH_CONTRAST, di, region, center);
     }
@@ -1714,13 +1490,13 @@ public abstract class DistortedObject
  * @param center   Center of the Effect.
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_contrast(float contrast, Float4D region, Float2D center)
+  public long smooth_contrast(float contrast, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(contrast));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
    
     return mF.add(EffectNames.SMOOTH_CONTRAST, di, region, center);
     }
@@ -1733,16 +1509,16 @@ public abstract class DistortedObject
  *                 1 - level of contrast unchanged, anything less than 1 - reduce contrast,
  *                 anything more than 1 - increase the contrast.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
   public long smooth_contrast(float contrast, int duration, float count) 
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                            
-    di.add(new Float1D(contrast));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(contrast));
          
     return mF.add(EffectNames.SMOOTH_CONTRAST, di,null, mZero2D);
     }
@@ -1754,15 +1530,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its saturation level.
  *        
- * @param saturation 1-dimensional Interpolator that returns the level of saturation we want to have
+ * @param saturation 1-dimensional Dynamic that returns the level of saturation we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   representing the current center of the effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long saturation(Interpolator1D saturation, Float4D region, Interpolator2D center)
+  public long saturation(Dynamic1D saturation, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SATURATION, saturation, region, center);
     }
@@ -1773,14 +1549,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param saturation 1-dimensional Interpolator that returns the level of saturation we want to have
+ * @param saturation 1-dimensional Dynamic that returns the level of saturation we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long saturation(Interpolator1D saturation, Float4D region, Float2D center)
+  public long saturation(Dynamic1D saturation, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SATURATION, saturation, region, center);
     }
@@ -1794,19 +1570,19 @@ public abstract class DistortedObject
  *                   anything more than 1 - increase the saturation. 
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   representing the current center of the effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long saturation(float saturation, Float4D region, Interpolator2D center, int duration, float count)
+  public long saturation(float saturation, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(saturation));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
    
     return mF.add(EffectNames.SATURATION, di, region, center);
     }
@@ -1824,16 +1600,16 @@ public abstract class DistortedObject
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long saturation(float saturation, Float4D region, Float2D center, int duration, float count)
+  public long saturation(float saturation, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(saturation));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
    
     return mF.add(EffectNames.SATURATION, di, region, center);
     }
@@ -1852,13 +1628,13 @@ public abstract class DistortedObject
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long saturation(float saturation, Float4D region, Float2D center)
+  public long saturation(float saturation, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(saturation));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
    
     return mF.add(EffectNames.SATURATION, di, region, center);
     }
@@ -1869,15 +1645,15 @@ public abstract class DistortedObject
 /**
  * Makes a certain sub-region of the Object smoothly change its saturation level.
  *        
- * @param saturation 1-dimensional Interpolator that returns the level of saturation we want to have
+ * @param saturation 1-dimensional Dynamic that returns the level of saturation we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   representing the current center of the effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long smooth_saturation(Interpolator1D saturation, Float4D region, Interpolator2D center)
+  public long smooth_saturation(Dynamic1D saturation, Static4D region, Dynamic2D center)
     {
     return mF.add(EffectNames.SMOOTH_SATURATION, saturation, region, center);
     }
@@ -1888,14 +1664,14 @@ public abstract class DistortedObject
  * <p>
  * Here the center of the Effect stays constant.
  *         
- * @param saturation 1-dimensional Interpolator that returns the level of saturation we want to have
+ * @param saturation 1-dimensional Dynamic that returns the level of saturation we want to have
  *                   at any given moment.
  * @param region     Region this Effect is limited to.
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one.
  */
-  public long smooth_saturation(Interpolator1D saturation, Float4D region, Float2D center)
+  public long smooth_saturation(Dynamic1D saturation, Static4D region, Static2D center)
     {
     return mF.add(EffectNames.SMOOTH_SATURATION, saturation, region, center);
     }
@@ -1909,19 +1685,19 @@ public abstract class DistortedObject
  *                   anything more than 1 -increase the saturation. 
  * @param region     Region this Effect is limited to. 
  *                   Null here means 'apply the Effect to the whole Object'.
- * @param center     2-dimensional Interpolator which, at any given time, returns a Float2D
+ * @param center     2-dimensional Dynamic which, at any given time, returns a Static2D
  *                   representing the current center of the effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_saturation(float saturation, Float4D region, Interpolator2D center, int duration, float count)
+  public long smooth_saturation(float saturation, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(saturation));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
    
     return mF.add(EffectNames.SMOOTH_SATURATION, di, region, center);
     }
@@ -1939,16 +1715,16 @@ public abstract class DistortedObject
  *                   Null here means 'apply the Effect to the whole Object'.
  * @param center     Center of the Effect.
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_saturation(float saturation, Float4D region, Float2D center, int duration, float count)
+  public long smooth_saturation(float saturation, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(saturation));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
    
     return mF.add(EffectNames.SMOOTH_SATURATION, di, region, center);
     }
@@ -1967,13 +1743,13 @@ public abstract class DistortedObject
  * @param center     Center of the Effect.
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
-  public long smooth_saturation(float saturation, Float4D region, Float2D center)
+  public long smooth_saturation(float saturation, Static4D region, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                          
-    di.add(new Float1D(saturation));                         
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
    
     return mF.add(EffectNames.SMOOTH_SATURATION, di, region, center);
     }
@@ -1986,16 +1762,16 @@ public abstract class DistortedObject
  *                   1 - level of saturation unchanged, anything less than 1 - reduce saturation,
  *                   anything more than 1 - increase the saturation. 
  * @param duration   Time, in milliseconds, it takes to do one full interpolation.
- * @param count      Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count      Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return           ID of the effect added, or -1 if we failed to add one. 
  */
   public long smooth_saturation(float saturation, int duration, float count) 
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                            
-    di.add(new Float1D(saturation));                        
+    di.add(new Static1D(1));
+    di.add(new Static1D(saturation));
          
     return mF.add(EffectNames.SMOOTH_SATURATION, di,null, mZero2D);
     }
@@ -2007,14 +1783,14 @@ public abstract class DistortedObject
 /**
  * Distort a (possibly changing in time) part of the Object by a (possibly changing in time) vector of force.
  * 
- * @param vector 2- or 3-dimensional Interpolator that returns a 2- or 3-dimensional Point which
+ * @param vector 2- or 3-dimensional Dynamic that returns a 2- or 3-dimensional Point which
  *               represents the vector the Center of the Effect is currently being dragged with.
  * @param region Region that masks the effect of the Distortion.
- * @param center 2-dimensional Interpolator that, at any given time, returns a Point2D representing
+ * @param center 2-dimensional Dynamic that, at any given time, returns a Point2D representing
  *               the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long distort(Interpolator vector, Float4D region, Interpolator2D center)
+  public long distort(Dynamic vector, Static4D region, Dynamic2D center)
     {  
     return mV.add(EffectNames.DISTORT, vector, region, center);
     }
@@ -2025,13 +1801,13 @@ public abstract class DistortedObject
  * <p>
  * Difference between this and the previous method is that here the center of the Effect stays constant.
  *   
- * @param vector 2- or 3-dimensional Interpolator that returns a 2- or 3-dimensional Point which
+ * @param vector 2- or 3-dimensional Dynamic that returns a 2- or 3-dimensional Point which
  *               represents the vector the Center of the Effect is currently being dragged with.
  * @param region Region that masks the effect of the Distortion.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long distort(Interpolator vector, Float4D region, Float2D center)
+  public long distort(Dynamic vector, Static4D region, Static2D center)
     {  
     return mV.add(EffectNames.DISTORT, vector, region, center);
     }
@@ -2040,12 +1816,12 @@ public abstract class DistortedObject
 /**
  * Distort the whole Object by a (possibly changing in time) vector of force.
  * 
- * @param vector 2- or 3-dimensional Interpolator that returns a 2- or 3-dimensional Point which
+ * @param vector 2- or 3-dimensional Dynamic that returns a 2- or 3-dimensional Point which
  *               represents the vector the Center of the Effect is currently being dragged with.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-  public long distort(Interpolator vector, Float2D center)
+  public long distort(Dynamic vector, Static2D center)
     {
     return mV.add(EffectNames.DISTORT, vector, null, center);
     }
@@ -2058,15 +1834,15 @@ public abstract class DistortedObject
  * @param region   Region that masks the effect of the Distortion.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long distort(Float3D vector, Float4D region, Float2D center, int duration, float count)
+  public long distort(Static3D vector, Static4D region, Static2D center, int duration, float count)
     {  
-    Interpolator3D di = new Interpolator3D(); 
+    Dynamic3D di = new Dynamic3D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float3D(0.0f,0.0f,0.0f));               
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);                                                  
            
     return mV.add(EffectNames.DISTORT, di, region, center);
@@ -2079,15 +1855,15 @@ public abstract class DistortedObject
  * @param vector   Maximum vector of force.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long distort(Float3D vector, Float2D center, int duration, float count)
+  public long distort(Static3D vector, Static2D center, int duration, float count)
     {
-    Interpolator3D di = new Interpolator3D(); 
+    Dynamic3D di = new Dynamic3D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float3D(0.0f,0.0f,0.0f));               
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);                                                 
            
     return mV.add(EffectNames.DISTORT, di, null, center);
@@ -2105,12 +1881,12 @@ public abstract class DistortedObject
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long distort(Float3D vector, Float2D center, int duration)
+  public long distort(Static3D vector, Static2D center, int duration)
     {
-    Interpolator3D di = new Interpolator3D();  
+    Dynamic3D di = new Dynamic3D();
     di.setCount(0.5f);
     di.setDuration(duration);
-    di.add(new Float3D(0.0f,0.0f,0.0f));              
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);                 
            
     return mV.add(EffectNames.DISTORT, di, null, center);
@@ -2126,12 +1902,12 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long distort(Float3D vector, Float2D center )
+  public long distort(Static3D vector, Static2D center )
     {
-    Interpolator3D di = new Interpolator3D(); 
+    Dynamic3D di = new Dynamic3D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float3D(0.0f,0.0f,0.0f));              
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);           
            
     return mV.add(EffectNames.DISTORT, di, null, center);
@@ -2144,13 +1920,13 @@ public abstract class DistortedObject
  * Deform the shape of the whole Object with a (possibly changing in time) vector of force applied to
  * a (possibly changing in time) point on the Object.
  *     
- * @param vector Interpolator that, at any given time, returns a Float2D representing vector of
+ * @param vector Dynamic that, at any given time, returns a Static2D representing vector of
  *               force that deforms the shape of the whole Object.
- * @param center 2-dimensional Interpolator that, at any given time, returns a Point2D representing
+ * @param center 2-dimensional Dynamic that, at any given time, returns a Point2D representing
  *               the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-  public long deform(Interpolator vector, Interpolator2D center)
+  public long deform(Dynamic vector, Dynamic2D center)
     {  
     return mV.add(EffectNames.DEFORM, vector, null, center);
     }
@@ -2160,12 +1936,12 @@ public abstract class DistortedObject
  * Deform the shape of the whole Object with a (possibly changing in time) vector of force applied to
  * a constant point on the Object.
  * 
- * @param vector Interpolator that, at any given time, returns a Float2D representing
+ * @param vector Dynamic that, at any given time, returns a Static2D representing
  *               vector of force that deforms the shape of the whole Object.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-  public long deform(Interpolator vector, Float2D center)
+  public long deform(Dynamic vector, Static2D center)
     {
     return mV.add(EffectNames.DEFORM, vector, null, center);
     }
@@ -2178,15 +1954,15 @@ public abstract class DistortedObject
  * @param vector   Vector of force.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long deform(Float3D vector, Float2D center, int duration, float count)
+  public long deform(Static3D vector, Static2D center, int duration, float count)
     {
-    Interpolator3D di = new Interpolator3D(); 
+    Dynamic3D di = new Dynamic3D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float3D(0.0f,0.0f,0.0f));               
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);                
            
     return mV.add(EffectNames.DEFORM, di, null, center);
@@ -2204,12 +1980,12 @@ public abstract class DistortedObject
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long deform(Float3D vector, Float2D center, int duration)
+  public long deform(Static3D vector, Static2D center, int duration)
     {
-    Interpolator3D di = new Interpolator3D();  
+    Dynamic3D di = new Dynamic3D();
     di.setCount(0.5f);
     di.setDuration(duration);
-    di.add(new Float3D(0.0f,0.0f,0.0f));              
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);             
            
     return mV.add(EffectNames.DEFORM, di, null, center);
@@ -2224,12 +2000,12 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long deform(Float3D vector, Float2D center )
+  public long deform(Static3D vector, Static2D center )
     {
-    Interpolator3D di = new Interpolator3D(); 
+    Dynamic3D di = new Dynamic3D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float3D(0.0f,0.0f,0.0f));              
+    di.add(new Static3D(0.0f,0.0f,0.0f));
     di.add(vector);            
            
     return mV.add(EffectNames.DEFORM, di, null, center);
@@ -2242,14 +2018,14 @@ public abstract class DistortedObject
  * Pull all points around the center of the effect towards the center (if degree>=1) or push them 
  * away from the center (degree<=1)
  *    
- * @param sink   1-dimensional Interpolator which, at any given time, returns a Point1D representing
+ * @param sink   1-dimensional Dynamic which, at any given time, returns a Point1D representing
  *               the current degree of the effect.
  * @param region Region that masks the effect of the Sink.
- * @param center 2-dimensional Interpolator that, at any given time, returns a Point2D representing
+ * @param center 2-dimensional Dynamic that, at any given time, returns a Point2D representing
  *               the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(Interpolator1D sink, Float4D region, Interpolator2D center)
+  public long sink(Dynamic1D sink, Static4D region, Dynamic2D center)
     {
     return mV.add(EffectNames.SINK, sink, region, center);
     }
@@ -2261,13 +2037,13 @@ public abstract class DistortedObject
  * <p>
  * Here the Center stays constant.
  *      
- * @param sink   1-dimensional Interpolator which, at any given time, returns a Point1D
+ * @param sink   1-dimensional Dynamic which, at any given time, returns a Point1D
  *               representing the current degree of the effect.
  * @param region Region that masks the effect of the Sink.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(Interpolator1D sink, Float4D region, Float2D center)
+  public long sink(Dynamic1D sink, Static4D region, Static2D center)
     {
     return mV.add(EffectNames.SINK, sink, region, center);
     }
@@ -2281,19 +2057,19 @@ public abstract class DistortedObject
  * 
  * @param sink     How much to push or pull. Between 0 and infinity.
  * @param region   Region that masks the effect of the Sink.
- * @param center   2-dimensional Interpolator that, at any given time, returns a Point2D representing
+ * @param center   2-dimensional Dynamic that, at any given time, returns a Point2D representing
  *                 the Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(float sink, Float4D region, Interpolator2D center, int duration, float count)
+  public long sink(float sink, Static4D region, Dynamic2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                                
-    di.add(new Float1D(sink));
+    di.add(new Static1D(1));
+    di.add(new Static1D(sink));
     
     return mV.add(EffectNames.SINK, di, region, center);
     }
@@ -2307,16 +2083,16 @@ public abstract class DistortedObject
  * @param region   Region that masks the effect of the Sink.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(float sink, Float4D region, Float2D center, int duration, float count)
+  public long sink(float sink, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                                
-    di.add(new Float1D(sink));
+    di.add(new Static1D(1));
+    di.add(new Static1D(sink));
     
     return mV.add(EffectNames.SINK, di, region, center);
     }
@@ -2329,16 +2105,16 @@ public abstract class DistortedObject
  * @param sink     How much to push or pull. Between 0 and infinity.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(float sink, Float2D center, int duration, float count)
+  public long sink(float sink, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D();  
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(1));                                
-    di.add(new Float1D(sink));
+    di.add(new Static1D(1));
+    di.add(new Static1D(sink));
          
     return mV.add(EffectNames.SINK, di, null, center);
     }
@@ -2355,13 +2131,13 @@ public abstract class DistortedObject
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(float sink, Float2D center, int duration)
+  public long sink(float sink, Static2D center, int duration)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(duration);
-    di.add(new Float1D(1));                               
-    di.add(new Float1D(sink));
+    di.add(new Static1D(1));
+    di.add(new Static1D(sink));
         
     return mV.add(EffectNames.SINK, di, null, center);
     }
@@ -2377,13 +2153,13 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long sink(float sink, Float2D center)
+  public long sink(float sink, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(1));                               
-    di.add(new Float1D(sink));
+    di.add(new Static1D(1));
+    di.add(new Static1D(sink));
         
     return mV.add(EffectNames.SINK, di, null, center);
     }
@@ -2393,16 +2169,16 @@ public abstract class DistortedObject
 // SWIRL
 /**
  * Rotate part of the Object around the Center of the Effect by a certain angle (as returned by the
- * Interpolator). 
+ * Dynamic).
  *   
- * @param swirl  1-dimensional Interpolator which, at any given time, returns a Point1D representing
+ * @param swirl  1-dimensional Dynamic which, at any given time, returns a Point1D representing
  *               the degree of Swirl.
  * @param region Region that masks the effect of the Swirl.
- * @param center 2-dimensional Interpolator that, at any given time, returns a Point2D representing
+ * @param center 2-dimensional Dynamic that, at any given time, returns a Point2D representing
  *               the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long swirl(Interpolator1D swirl, Float4D region, Interpolator2D center)
+  public long swirl(Dynamic1D swirl, Static4D region, Dynamic2D center)
     {    
     return mV.add(EffectNames.SWIRL, swirl, region, center);
     }
@@ -2410,17 +2186,17 @@ public abstract class DistortedObject
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Rotate part of the Object around the Center of the Effect by a certain angle (as returned by the
- * Interpolator).
+ * Dynamic).
  * <p>
  * Here the Center stays constant.
  *      
- * @param swirl  1-dimensional Interpolator which, at any given time, returns a Point1D representing
+ * @param swirl  1-dimensional Dynamic which, at any given time, returns a Point1D representing
  *               the degree of Swirl.
  * @param region Region that masks the effect of the Swirl.
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long swirl(Interpolator1D swirl, Float4D region, Float2D center)
+  public long swirl(Dynamic1D swirl, Static4D region, Static2D center)
     {    
     return mV.add(EffectNames.SWIRL, swirl, region, center);
     }
@@ -2431,17 +2207,17 @@ public abstract class DistortedObject
  *   
  * @param swirl    Angle of rotation. Unit: degrees.
  * @param region   Region that masks the effect of the Swirl.
- * @param center   2-dimensional Interpolator that, at any given time, returns a Point2D representing
+ * @param center   2-dimensional Dynamic that, at any given time, returns a Point2D representing
  *                 the Center of the Effect.
  * @return         ID of the effect added, or -1 if we failed to add one.
  */
-  public long swirl(int swirl, Float4D region, Interpolator2D center)
+  public long swirl(int swirl, Static4D region, Dynamic2D center)
     {
-    Interpolator1D di = new Interpolator1D();
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(0));                                
-    di.add(new Float1D(swirl));
+    di.add(new Static1D(0));
+    di.add(new Static1D(swirl));
     
     return mV.add(EffectNames.SWIRL, di, region, center);
     }
@@ -2456,16 +2232,16 @@ public abstract class DistortedObject
  * @param region   Region that masks the effect of the Swirl.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long swirl(int swirl, Float4D region, Float2D center, int duration, float count)
+  public long swirl(int swirl, Static4D region, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(0));                                
-    di.add(new Float1D(swirl));
+    di.add(new Static1D(0));
+    di.add(new Static1D(swirl));
     
     return mV.add(EffectNames.SWIRL, di, region, center);
     }
@@ -2477,16 +2253,16 @@ public abstract class DistortedObject
  * @param swirl    Angle of rotation. Unit: degrees.
  * @param center   Center of the Effect.
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
- * @param count    Controls how many interpolations we want to do. See {@link Interpolator#setCount(float)}
+ * @param count    Controls how many interpolations we want to do. See {@link Dynamic#setCount(float)}
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long swirl(int swirl, Float2D center, int duration, float count)
+  public long swirl(int swirl, Static2D center, int duration, float count)
     {
-    Interpolator1D di = new Interpolator1D();  
+    Dynamic1D di = new Dynamic1D();
     di.setCount(count);
     di.setDuration(duration);
-    di.add(new Float1D(0));                                
-    di.add(new Float1D(swirl));
+    di.add(new Static1D(0));
+    di.add(new Static1D(swirl));
          
     return mV.add(EffectNames.SWIRL, di, null, center);
     }
@@ -2502,13 +2278,13 @@ public abstract class DistortedObject
  * @param duration Time, in milliseconds, it takes to do one full interpolation.
  * @return         ID of the effect added, or -1 if we failed to add one. 
  */
-  public long swirl(int swirl, Float2D center, int duration)
+  public long swirl(int swirl, Static2D center, int duration)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(duration);
-    di.add(new Float1D(0));                               
-    di.add(new Float1D(swirl));
+    di.add(new Static1D(0));
+    di.add(new Static1D(swirl));
         
     return mV.add(EffectNames.SWIRL, di, null, center);
     }
@@ -2523,13 +2299,13 @@ public abstract class DistortedObject
  * @param center Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one. 
  */
-  public long swirl(int swirl, Float2D center)
+  public long swirl(int swirl, Static2D center)
     {
-    Interpolator1D di = new Interpolator1D(); 
+    Dynamic1D di = new Dynamic1D();
     di.setCount(0.5f);
     di.setDuration(0);
-    di.add(new Float1D(0));                               
-    di.add(new Float1D(swirl));
+    di.add(new Static1D(0));
+    di.add(new Static1D(swirl));
         
     return mV.add(EffectNames.SWIRL, di, null, center);
     }
diff --git a/src/main/java/org/distorted/library/EffectQueue.java b/src/main/java/org/distorted/library/EffectQueue.java
index 25c996e..0b4e5f3 100644
--- a/src/main/java/org/distorted/library/EffectQueue.java
+++ b/src/main/java/org/distorted/library/EffectQueue.java
@@ -21,8 +21,8 @@ package org.distorted.library;
 
 import org.distorted.library.message.EffectListener;
 import org.distorted.library.message.EffectMessage;
-import org.distorted.library.type.Interpolator;
-import org.distorted.library.type.Interpolator2D;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic2D;
 
 import java.util.Vector;
 
@@ -35,8 +35,8 @@ abstract class EffectQueue
   
   protected int[] mType;
   protected float[] mUniforms;
-  protected Interpolator[] mInterP;  // center of the effect
-  protected Interpolator[] mInterI;  // all other interpolated values
+  protected Dynamic[] mInterP;  // center of the effect
+  protected Dynamic[] mInterI;  // all other interpolated values
   protected long[] mCurrentDuration;
   protected byte[] mFreeIndexes;
   protected byte[] mIDIndex;
@@ -80,8 +80,8 @@ abstract class EffectQueue
       {
       mType            = new int[mMax[mMaxIndex]];
       mUniforms        = new float[numUniforms*mMax[mMaxIndex]];
-      mInterI          = new Interpolator[mMax[mMaxIndex]];
-      mInterP          = new Interpolator2D[mMax[mMaxIndex]];
+      mInterI          = new Dynamic[mMax[mMaxIndex]];
+      mInterP          = new Dynamic2D[mMax[mMaxIndex]];
       mCurrentDuration = new long[mMax[mMaxIndex]];
       mID              = new long[mMax[mMaxIndex]];
       mIDIndex         = new byte[mMax[mMaxIndex]];
diff --git a/src/main/java/org/distorted/library/EffectQueueFragment.java b/src/main/java/org/distorted/library/EffectQueueFragment.java
index db2130e..863b1f1 100644
--- a/src/main/java/org/distorted/library/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/EffectQueueFragment.java
@@ -22,12 +22,12 @@ package org.distorted.library;
 import android.opengl.GLES20;
 
 import org.distorted.library.message.EffectMessage;
-import org.distorted.library.type.Float2D;
-import org.distorted.library.type.Float3D;
-import org.distorted.library.type.Float4D;
-import org.distorted.library.type.Interpolator;
-import org.distorted.library.type.Interpolator1D;
-import org.distorted.library.type.Interpolator2D;
+import org.distorted.library.type.Dynamic1D;
+import org.distorted.library.type.Static2D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic2D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -169,7 +169,7 @@ class EffectQueueFragment extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
        
-  synchronized long add(EffectNames eln, Interpolator inter, Float4D region, Interpolator2D point)
+  synchronized long add(EffectNames eln, Dynamic inter, Static4D region, Dynamic2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -199,7 +199,7 @@ class EffectQueueFragment extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  synchronized long add(EffectNames eln, Interpolator inter, Float4D region, Float2D point)
+  synchronized long add(EffectNames eln, Dynamic inter, Static4D region, Static2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -231,7 +231,7 @@ class EffectQueueFragment extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
        
-  synchronized long add(EffectNames eln, Interpolator1D inter, Float3D c, Float4D region, Interpolator2D point)
+  synchronized long add(EffectNames eln, Dynamic1D inter, Static3D c, Static4D region, Dynamic2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -264,7 +264,7 @@ class EffectQueueFragment extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  synchronized long add(EffectNames eln, Interpolator1D inter, Float3D c, Float4D region, Float2D point)
+  synchronized long add(EffectNames eln, Dynamic1D inter, Static3D c, Static4D region, Static2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -299,7 +299,7 @@ class EffectQueueFragment extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
        
-  synchronized long add(EffectNames eln, float t, Float3D c, Float4D region, Interpolator2D point)
+  synchronized long add(EffectNames eln, float t, Static3D c, Static4D region, Dynamic2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -333,7 +333,7 @@ class EffectQueueFragment extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  synchronized long add(EffectNames eln, float t, Float3D c, Float4D region, Float2D point)
+  synchronized long add(EffectNames eln, float t, Static3D c, Static4D region, Static2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
diff --git a/src/main/java/org/distorted/library/EffectQueueMatrix.java b/src/main/java/org/distorted/library/EffectQueueMatrix.java
index e923342..3e4d5cf 100644
--- a/src/main/java/org/distorted/library/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/EffectQueueMatrix.java
@@ -23,10 +23,17 @@ import android.opengl.GLES20;
 import android.opengl.Matrix;
 
 import org.distorted.library.message.EffectMessage;
-import org.distorted.library.type.Float3D;
-import org.distorted.library.type.Interpolator;
-import org.distorted.library.type.Interpolator1D;
-import org.distorted.library.type.Interpolator3D;
+import org.distorted.library.type.Data1D;
+import org.distorted.library.type.Data3D;
+import org.distorted.library.type.Data4D;
+import org.distorted.library.type.Dynamic1D;
+import org.distorted.library.type.Dynamic3D;
+import org.distorted.library.type.Dynamic4D;
+import org.distorted.library.type.DynamicQuat;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Static4D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -160,7 +167,7 @@ class EffectQueueMatrix extends EffectQueue
         x = mUniforms[NUM_UNIFORMS*i  ];
         y = mUniforms[NUM_UNIFORMS*i+1];
         z = mUniforms[NUM_UNIFORMS*i+2];
-     
+
         Matrix.translateM(viewMatrix, 0, x,-y, z); 
         Matrix.rotateM( viewMatrix, 0, mUniforms[NUM_UNIFORMS*i+3], mUniforms[NUM_UNIFORMS*i+4], mUniforms[NUM_UNIFORMS*i+5], mUniforms[NUM_UNIFORMS*i+6]);  
         Matrix.translateM(viewMatrix, 0,-x, y,-z);  
@@ -244,13 +251,23 @@ class EffectQueueMatrix extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// move, scale
 
-  synchronized long add(EffectNames eln, Interpolator i)
+  synchronized long add(EffectNames eln, Data3D vector)
     {
     if( mMax[INDEX]>mNumEffects )
       {
       mInterP[mNumEffects] = null;
-      mInterI[mNumEffects] = i;
+
+           if( vector instanceof Dynamic3D) mInterI[mNumEffects] = (Dynamic3D)vector;
+      else if( vector instanceof Static3D )
+        {
+        mInterI[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static3D)vector).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+4] = ((Static3D)vector).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+5] = ((Static3D)vector).getZ();
+        }
+      else return -1;
 
       return addBase(eln);
       }
@@ -259,33 +276,34 @@ class EffectQueueMatrix extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  synchronized long add(EffectNames eln, Interpolator3D p, Interpolator i)
-    {
-    if( mMax[INDEX]>mNumEffects )
-      {
-      mInterP[mNumEffects] = p;
-      mInterI[mNumEffects] = i;
-      
-      return addBase(eln);
-      }
-      
-    return -1;
-    }
+// rotate - static axis
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  synchronized long add(EffectNames eln, Float3D p, Interpolator i)
+  synchronized long add(EffectNames eln, Data3D center, Data1D angle, Static3D axis)
     {
     if( mMax[INDEX]>mNumEffects )
       {
-      mInterP[mNumEffects] = null;
-      mInterI[mNumEffects] = i;
-      
-      mUniforms[NUM_UNIFORMS*mNumEffects  ] = p.getX();
-      mUniforms[NUM_UNIFORMS*mNumEffects+1] = p.getY();
-      mUniforms[NUM_UNIFORMS*mNumEffects+2] = p.getZ();
-            
+           if( center instanceof Dynamic3D) mInterP[mNumEffects] = (Dynamic3D)center;
+      else if( center instanceof Static3D )
+        {
+        mInterP[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)center).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)center).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)center).getZ();
+        }
+      else return -1;
+
+           if( angle instanceof Dynamic1D) mInterI[mNumEffects] = (Dynamic1D)angle;
+      else if( angle instanceof Static1D)
+        {
+        mInterI[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static1D)angle).getX();
+        }
+      else return -1;
+
+      mUniforms[NUM_UNIFORMS*mNumEffects+4] = axis.getX();
+      mUniforms[NUM_UNIFORMS*mNumEffects+5] = axis.getY();
+      mUniforms[NUM_UNIFORMS*mNumEffects+6] = axis.getZ();
+
       return addBase(eln);
       }
       
@@ -293,69 +311,70 @@ class EffectQueueMatrix extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  synchronized long add(EffectNames eln, Float3D p, Interpolator1D i, float aX, float aY, float aZ)
+// quaternion or rotate - dynamic axis
+
+  synchronized long add(EffectNames eln, Data3D center, Data4D data)
     {
     if( mMax[INDEX]>mNumEffects )
       {
-      mInterP[mNumEffects] = null;
-      mInterI[mNumEffects] = i;
-      
-      mUniforms[NUM_UNIFORMS*mNumEffects  ] = p.getX();
-      mUniforms[NUM_UNIFORMS*mNumEffects+1] = p.getY();
-      mUniforms[NUM_UNIFORMS*mNumEffects+2] = p.getZ();
-      
-      mUniforms[NUM_UNIFORMS*mNumEffects+4] = aX;
-      mUniforms[NUM_UNIFORMS*mNumEffects+5] = aY;  
-      mUniforms[NUM_UNIFORMS*mNumEffects+6] = aZ;  
-      
+           if( center instanceof Dynamic3D) mInterP[mNumEffects] = (Dynamic3D)center;
+      else if( center instanceof Static3D )
+        {
+        mInterP[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)center).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)center).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)center).getZ();
+        }
+      else return -1;
+
+           if( data instanceof Dynamic4D  ) mInterI[mNumEffects] = (Dynamic4D)data;
+      else if( data instanceof DynamicQuat) mInterI[mNumEffects] = (DynamicQuat)data;
+      else if( data instanceof Static4D   )
+        {
+        mInterI[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static4D)data).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+4] = ((Static4D)data).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+5] = ((Static4D)data).getZ();
+        mUniforms[NUM_UNIFORMS*mNumEffects+6] = ((Static4D)data).getW();
+        }
+      else return -1;
+
       return addBase(eln);
       }
-      
+
     return -1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  synchronized long add(EffectNames eln, Interpolator3D p, Interpolator1D i, float aX, float aY, float aZ)
+// shear
+
+  synchronized long add(EffectNames eln, Data3D center, Data3D shear)
     {
     if( mMax[INDEX]>mNumEffects )
       {
-      mInterP[mNumEffects] = p;
-      mInterI[mNumEffects] = i;
-      
-      mUniforms[NUM_UNIFORMS*mNumEffects+4] = aX;
-      mUniforms[NUM_UNIFORMS*mNumEffects+5] = aY;  
-      mUniforms[NUM_UNIFORMS*mNumEffects+6] = aZ;  
-      
+           if( center instanceof Dynamic3D) mInterP[mNumEffects] = (Dynamic3D)center;
+      else if( center instanceof Static3D )
+        {
+        mInterP[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)center).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)center).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)center).getZ();
+        }
+      else return -1;
+
+           if( shear instanceof Dynamic3D) mInterI[mNumEffects] = (Dynamic3D)shear;
+      else if( shear instanceof Static3D )
+        {
+        mInterI[mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static3D)shear).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+4] = ((Static3D)shear).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+5] = ((Static3D)shear).getZ();
+        }
+      else return -1;
+
       return addBase(eln);
       }
       
     return -1;
     }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  synchronized long add(EffectNames eln, Float3D p, float aA, float aX, float aY, float aZ)
-    {
-    if( mMax[INDEX]>mNumEffects )
-      {
-      mInterP[mNumEffects] = null; 
-      mInterI[mNumEffects] = null;
-      
-      mUniforms[NUM_UNIFORMS*mNumEffects  ] = p.getX();
-      mUniforms[NUM_UNIFORMS*mNumEffects+1] = p.getY();
-      mUniforms[NUM_UNIFORMS*mNumEffects+2] = p.getZ();
-      mUniforms[NUM_UNIFORMS*mNumEffects+3] = aA;  
-      mUniforms[NUM_UNIFORMS*mNumEffects+4] = aX;
-      mUniforms[NUM_UNIFORMS*mNumEffects+5] = aY;  
-      mUniforms[NUM_UNIFORMS*mNumEffects+6] = aZ;  
-      
-      return addBase(eln);   
-      }
-      
-    return -1;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
   }
diff --git a/src/main/java/org/distorted/library/EffectQueueVertex.java b/src/main/java/org/distorted/library/EffectQueueVertex.java
index 09456b4..1e95bcd 100644
--- a/src/main/java/org/distorted/library/EffectQueueVertex.java
+++ b/src/main/java/org/distorted/library/EffectQueueVertex.java
@@ -22,10 +22,10 @@ package org.distorted.library;
 import android.opengl.GLES20;
 
 import org.distorted.library.message.EffectMessage;
-import org.distorted.library.type.Float2D;
-import org.distorted.library.type.Float4D;
-import org.distorted.library.type.Interpolator;
-import org.distorted.library.type.Interpolator2D;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic2D;
+import org.distorted.library.type.Static2D;
+import org.distorted.library.type.Static4D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -154,7 +154,7 @@ class EffectQueueVertex extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  synchronized long add(EffectNames eln, Interpolator inter, Float4D region, Interpolator2D point)
+  synchronized long add(EffectNames eln, Dynamic inter, Static4D region, Dynamic2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -171,7 +171,7 @@ class EffectQueueVertex extends EffectQueue
    
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  synchronized long add(EffectNames eln, Interpolator inter, Float4D region, Float2D point)
+  synchronized long add(EffectNames eln, Dynamic inter, Static4D region, Static2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -190,7 +190,7 @@ class EffectQueueVertex extends EffectQueue
  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  synchronized long add(EffectNames eln, float v1, float v2, float v3, Float4D region, Float2D point)
+  synchronized long add(EffectNames eln, float v1, float v2, float v3, Static4D region, Static2D point)
     {
     if( mMax[INDEX]>mNumEffects )
       {
@@ -212,7 +212,7 @@ class EffectQueueVertex extends EffectQueue
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  private long addPriv(EffectNames eln, Float4D region)
+  private long addPriv(EffectNames eln, Static4D region)
     {    
     if( region!=null )
       {
diff --git a/src/main/java/org/distorted/library/message/EffectMessage.java b/src/main/java/org/distorted/library/message/EffectMessage.java
index a23698f..ff9d292 100644
--- a/src/main/java/org/distorted/library/message/EffectMessage.java
+++ b/src/main/java/org/distorted/library/message/EffectMessage.java
@@ -22,7 +22,7 @@ package org.distorted.library.message;
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 import org.distorted.library.DistortedBitmap;
-import org.distorted.library.type.Interpolator;
+import org.distorted.library.type.Dynamic;
 
 /**
 * Defines all possible events a class implementing the {@link EffectListener} interface can receive.
@@ -42,11 +42,11 @@ public enum EffectMessage
 /**
  * Interpolation of the effect has finished. 
  * <p>
- * If you set up an interpolated effect and set its Interpolator to do 3.5 interpolations of 1000 ms each
- * with calls to {@link Interpolator#setCount(float)} and {@link Interpolator#setDuration(long)},
+ * If you set up an interpolated effect and set its Dynamic to do 3.5 interpolations of 1000 ms each
+ * with calls to {@link Dynamic#setCount(float)} and {@link Dynamic#setDuration(long)},
  * then you are going to get this message exactly once after 3.5*1000 = 3500 milliseconds when the interpolation 
  * finishes. You will never get this message if you set the effect to go on indefinitely with a call to 
- * {@link Interpolator#setCount(float)}.
+ * {@link Dynamic#setCount(float)}.
  * <p>  
  * If then the end effect is equal to the effect's unity, then immediately after this message you
  * will also get a EFFECT_REMOVED message.
diff --git a/src/main/java/org/distorted/library/type/Data1D.java b/src/main/java/org/distorted/library/type/Data1D.java
new file mode 100644
index 0000000..8c974a9
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Data1D.java
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Marker Interface implemented by Static1D and Dynamic1D.
+ * <p>
+ * The point: so we can pass either Static and Dynamic to EffectQueues in a single parameter.
+ */
+public interface Data1D
+  {
+
+  }
diff --git a/src/main/java/org/distorted/library/type/Data2D.java b/src/main/java/org/distorted/library/type/Data2D.java
new file mode 100644
index 0000000..e16b88e
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Data2D.java
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Marker Interface implemented by Static2D and Dynamic2D.
+ * <p>
+ * The point: so we can pass either Static and Dynamic to EffectQueues in a single parameter.
+ */
+public interface Data2D
+  {
+
+  }
diff --git a/src/main/java/org/distorted/library/type/Data3D.java b/src/main/java/org/distorted/library/type/Data3D.java
new file mode 100644
index 0000000..79fb3c8
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Data3D.java
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Marker Interface implemented by Static3D and Dynamic3D.
+ * <p>
+ * The point: so we can pass either Static and Dynamic to EffectQueues in a single parameter.
+ */
+public interface Data3D
+  {
+
+  }
diff --git a/src/main/java/org/distorted/library/type/Data4D.java b/src/main/java/org/distorted/library/type/Data4D.java
new file mode 100644
index 0000000..c2707fd
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Data4D.java
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Marker Interface implemented by Static4D, Dynamic4D and DynamicQuat.
+ * <p>
+ * The point: so we can pass either Static and Dynamic to EffectQueues in a single parameter.
+ */
+public interface Data4D
+  {
+
+  }
diff --git a/src/main/java/org/distorted/library/type/Dynamic.java b/src/main/java/org/distorted/library/type/Dynamic.java
new file mode 100644
index 0000000..ecbab42
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Dynamic.java
@@ -0,0 +1,229 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+import java.util.Random;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/** A class to interpolate between a List of Float{1,2,3,4}Ds.
+* <p><ul>
+* <li>if there is only one Point, just jump to it.
+* <li>if there are two Points, linearly bounce between them
+* <li>if there are more, interpolate a loop (or a path!) between them.
+* </ul>
+*/
+
+// The way Interpolation between more than 2 Points is done:
+// 
+// Def: let w[i] = (w[i](x), w[i](y), w[i](z)) be the direction and speed we have to be flying at Point P[i]
+//
+// time it takes to fly though one segment v[i] --> v[i+1] : 0.0 --> 1.0
+// w[i] should be parallel to v[i+1] - v[i-1]   (cyclic notation)
+// |w[i]| proportional to | P[i]-P[i+1] |
+//
+// Given that the flight route (X(t), Y(t), Z(t)) from P(i) to P(i+1)  (0<=t<=1) has to satisfy
+// X(0) = P[i  ](x), Y(0)=P[i  ](y), Z(0)=P[i  ](z), X'(0) = w[i  ](x), Y'(0) = w[i  ](y), Z'(0) = w[i  ](z)
+// X(1) = P[i+1](x), Y(1)=P[i+1](y), Z(1)=P[i+1](z), X'(1) = w[i+1](x), Y'(1) = w[i+1](y), Z'(1) = w[i+1](z)
+//
+// we have the solution:  X(t) = at^3 + bt^2 + ct + d where
+// a =  2*P[i](x) +   w[i](x) - 2*P[i+1](x) + w[i+1](x)
+// b = -3*P[i](x) - 2*w[i](x) + 3*P[i+1](x) - w[i+1](x)
+// c = w[i](x)<br>
+// d = P[i](x)
+//
+// and similarly Y(t) and Z(t).
+
+public abstract class Dynamic
+  {
+  /**
+   * One revolution takes us from the first vector to the last and back to first through the shortest path. 
+   */
+  public static final int MODE_LOOP = 0; 
+  /**
+   * We come back from the last to the first vector through the same way we got there.
+   */
+  public static final int MODE_PATH = 1; 
+  /**
+   * We just jump back from the last point to the first.
+   */
+  public static final int MODE_JUMP = 2; 
+ 
+  protected static Random mRnd = new Random();
+  
+  protected static final int NUM_NOISE = 5; // used iff mNoise>0.0. Number of intermediary points between each pair of adjacent vectors
+                                            // where we randomize noise factors to make the way between the two vectors not so smooth.
+  protected int numPoints;
+  protected int mVecCurr;    
+  protected boolean cacheDirty; // VectorCache not up to date
+  protected int mMode;          // LOOP, PATH or JUMP
+  protected long mDuration;     // number of miliseconds it takes to do a full loop/path from first vector to the last and back to the first 
+  protected float mCount;       // number of loops/paths we will do; mCount = 1.5 means we go from the first vector to the last, back to first, and to the last again. 
+  protected float mNoise;       // how 'smooth' our path form each vector to the next is. mNoise = 0.0 (min) --> completely smooth; mNoise==1.0 (max) --> very uneven
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// hide this from Javadoc
+  
+  Dynamic()
+    {
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  public void interpolateMain(float[] buffer, int offset, long currentDuration)
+    {
+    if( mDuration<=0.0f ) 
+      {
+      interpolate(buffer,offset,mCount-(int)mCount);  
+      }
+    else
+      {
+      float x = (float)currentDuration/mDuration;
+           
+      if( x<=mCount || mCount<=0.0f )
+        {
+        interpolate(buffer,offset,x-(int)x);
+        }
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public boolean interpolateMain(float[] buffer, int offset, long currentDuration, long step)
+    {
+    if( mDuration<=0.0f ) 
+      {
+      interpolate(buffer,offset,mCount-(int)mCount);
+      return false;
+      }
+     
+    float x = (float)currentDuration/mDuration;
+           
+    if( x<=mCount || mCount<=0.0f )
+      {
+      interpolate(buffer,offset,x-(int)x);
+        
+      if( currentDuration+step > mDuration*mCount && mCount>0.0f )
+        {
+        interpolate(buffer,offset,mCount-(int)mCount);
+        return true;
+        }
+      }
+    
+    return false;
+    }
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// internal debugging only!
+  
+  public String print()
+    {
+    return "duration="+mDuration+" count="+mCount+" Noise="+mNoise+" numVectors="+numPoints+" mMode="+mMode;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  abstract void interpolate(float[] buffer, int offset, float time);
+  abstract void createNoise();
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sets the mode of the interpolation to Loop, Path or Jump.
+ * <ul>
+ * <li>Loop is when we go from the first point all the way to the last, and the back to the first through 
+ * the shortest way.
+ * <li>Path is when we come back from the last point back to the first the same way we got there.
+ * <li>Jump is when we go from first to last and then jump back to the first.
+ * </ul>
+ * 
+ * @param mode {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
+ */
+
+  public void setMode(int mode)
+    {
+    mMode = mode;  
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the number of Float{1,2,3,4}Ds this Dynamic has been fed with.
+ *   
+ * @return the number of Float{1,2,3,4}Ds we are currently interpolating through.
+ */
+  public synchronized int getNumPoints()
+    {
+    return numPoints;  
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Controls how many times we want to interpolate.
+ * <p>
+ * Count equal to 1 means 'go from the first Float{1,2,3,4}D to the last and back'. Does not have to be an
+ * integer - i.e. count=1.5 would mean 'start at the first Point, go to the last, come back to the first, 
+ * go to the last again and stop'.
+ * Count<=0 means 'go on interpolating indefinitely'.
+ * 
+ * @param count the number of times we want to interpolate between our collection of Float{1,2,3,4}Ds.
+ */
+  public void setCount(float count)
+    {
+    mCount = count;  
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sets the time it takes to do one full interpolation.
+ * 
+ * @param duration Time, in milliseconds, it takes to do one full interpolation, i.e. go from the first 
+ *                 Point to the last and back. 
+ */
+  
+  public void setDuration(long duration)
+    {
+    mDuration = duration;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sets the 'smoothness' of interpolation. 
+ * <p>
+ * When Noise=0 (the default), we interpolate between our Points through the most smooth path possible. 
+ * Increasing noise makes the Dynamic increasingly deviate from this path, pseudo-randomly speeding
+ * up and slowing down, etc.
+ * 
+ * @param noise The noise level. Permitted range: 0 <= noise <= 1.
+ */
+  
+  public void setNoise(float noise)
+    {
+    if( mNoise==0.0f && noise != 0.0f )  
+      createNoise();
+   
+    if( mNoise<0.0f ) mNoise = 0.0f;
+    if( mNoise>1.0f ) mNoise = 1.0f;
+   
+    mNoise = noise;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// end of DistortedInterpolator
+  }
diff --git a/src/main/java/org/distorted/library/type/Dynamic1D.java b/src/main/java/org/distorted/library/type/Dynamic1D.java
new file mode 100644
index 0000000..972fed6
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Dynamic1D.java
@@ -0,0 +1,499 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+import java.util.Vector;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/** 
+* A 1-dimensional implementation of the Dynamic class to interpolate between a list
+* of Float1Ds.
+*/
+
+public class Dynamic1D extends Dynamic implements Data1D
+  {
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// the coefficients of the X(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
+// (x) is the vector tangent to the path.
+// (vx) is the original vector from vv (copied here so when interpolating we can see if it is 
+// still valid and if not - rebuild the Cache
+   
+  private class VectorCache
+    {
+    float ax, bx, cx, dx;
+   
+    float x;
+    float vx;
+    }
+  
+  private class VectorNoise
+    {
+    float[] nx;
+   
+    public VectorNoise()
+      {
+      nx = new float[NUM_NOISE]; 
+      nx[0] = mRnd.nextFloat();
+      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1]+mRnd.nextFloat();
+      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
+      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
+      }
+    }
+  
+  private Vector<VectorCache> vc;
+  private VectorCache tmp1, tmp2;
+ 
+  private Vector<Static1D> vv;
+  private Static1D prev, curr, next;
+ 
+  private Vector<VectorNoise> vn;
+  private VectorNoise tmpN;
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  synchronized void createNoise()
+    {
+    if( vn==null )
+      {
+      vn = new Vector<VectorNoise>();
+      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// no array bounds checking!
+  
+  private void vec(int c)
+    {
+    int p = c>0 ? c-1: numPoints-1;
+    int n = c<numPoints-1 ? c+1: 0;
+    
+    prev = vv.elementAt(p);
+    curr = vv.elementAt(c);
+    next = vv.elementAt(n);
+
+    tmp1 = vc.elementAt(c);
+    
+    float px = curr.x - prev.x;
+    float nx = next.x - curr.x;
+     
+    float d = nx*nx;
+    
+    if( d>0 )
+      {
+      float q = (float)Math.sqrt((px*px)/d);
+      
+      if( q>1 )
+        {
+        tmp1.x = nx+px/q;
+        }
+      else
+        {
+        tmp1.x = px+nx*q;
+        }
+      }
+    else
+      {
+      tmp1.x = 0.0f;
+      }
+    }
+      
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  private void recomputeCache()
+    {  
+    if( numPoints==1 )
+      {
+      tmp1= vc.elementAt(0);
+      curr= vv.elementAt(0);
+        
+      tmp1.ax = 0.0f;
+      tmp1.bx = 0.0f;
+      tmp1.cx = curr.x;
+      tmp1.dx = 0.0f;
+      }
+    else if( numPoints==2 )
+      {
+      tmp1= vc.elementAt(0);
+      tmp2= vc.elementAt(1);
+      curr= vv.elementAt(0);
+      next= vv.elementAt(1);
+          
+      tmp1.ax = 0.0f;
+      tmp1.bx = 0.0f;
+      tmp1.cx = next.x - curr.x;
+      tmp1.dx = curr.x;
+      
+      tmp2.ax = 0.0f;
+      tmp2.bx = 0.0f;
+      tmp2.cx = curr.x - next.x;
+      tmp2.dx = next.x;
+      }
+    else
+      {
+      int i, n;  
+         
+      for(i=0; i<numPoints; i++) vec(i);
+   
+      for(i=0; i<numPoints; i++)
+        {
+        n = i<numPoints-1 ? i+1:0;  
+      
+        tmp1= vc.elementAt(i);
+        tmp2= vc.elementAt(n);
+        curr= vv.elementAt(i);
+        next= vv.elementAt(n);
+    
+        tmp1.vx = curr.x;
+        
+        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
+        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
+        tmp1.cx = tmp1.x;
+        tmp1.dx = curr.x;
+        }
+      }
+   
+    cacheDirty = false;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float noise(float time,int vecNum)
+    {
+    float lower, upper, len;  
+    float d = time*(NUM_NOISE+1);
+    int index = (int)d;
+    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
+    tmpN = vn.elementAt(vecNum);
+   
+    if( index==0 )
+      {
+      len = 1.0f/(NUM_NOISE+1);  
+      return (len + mNoise*(tmpN.nx[0]-len))*d;
+      }
+    if( index==NUM_NOISE )
+      {
+      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
+      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);   
+      return (1.0f-lower)*(d-NUM_NOISE) + lower;   
+      }
+   
+    len = ((float)index)/(NUM_NOISE+1);
+    lower = len + mNoise*(tmpN.nx[index-1]-len);   
+    len = ((float)index+1)/(NUM_NOISE+1); 
+    upper = len + mNoise*(tmpN.nx[index  ]-len);
+            
+    return (upper-lower)*(d-index) + lower; 
+    }
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Default constructor.
+ */
+  public Dynamic1D()
+    {
+    vv = new Vector<Static1D>();
+    vc = new Vector<VectorCache>();
+    vn = null;
+    numPoints = 0;
+    cacheDirty = false;
+    mMode = MODE_LOOP;
+    mDuration = 0;
+    mCount = 0.5f;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the location'th Static1D.
+ *   
+ * @param location the index of the Point we are interested in.
+ * @return The Static1D, if 0<=location&lt;getNumPoints(), or null otherwise.
+ */
+  public synchronized Static1D getPoint(int location)
+    {
+    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the location'th Point.
+ * 
+ * @param location the index of the Point we are setting.
+ * @param x New value of its first float.
+ */
+  public synchronized void setPoint(int location, float x)
+    {
+    if( location>=0 && location<numPoints )
+      {
+      curr = vv.elementAt(location);
+   
+      if( curr!=null )
+        {
+        curr.set(x);
+        cacheDirty=true;
+        }
+      }
+    }
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static1D to the end of our list of Points to interpolate through.
+ * <p>   
+ * Only a reference to the Point gets added to the List; this means that one can add a Point 
+ * here, and later on {@link Static1D#set(float)} it to some new value and the change will
+ * be seamlessly reflected in the interpolated path.  
+ * <p>
+ * A Point can be added multiple times.
+ *   
+ * @param v The Point to add.
+ */
+  public synchronized void add(Static1D v)
+    {
+    if( v!=null )
+      {
+      vv.add(v);
+     
+      if( vn!=null ) vn.add(new VectorNoise());
+       
+      switch(numPoints)
+        {
+        case 0: 
+        case 1: break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                cacheDirty = true;
+                break;
+        default:vc.add(new VectorCache());
+                cacheDirty = true;
+        }
+     
+      numPoints++;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static1D to the location'th place in our List of Points to interpolate through.
+ *   
+ * @param location Index in our List to add the new Point at.
+ * @param v The Point to add.
+ */
+  public synchronized void add(int location, Static1D v)
+    {
+    if( v!=null )
+      {
+      vv.add(location, v);
+      
+      if( vn!=null ) vn.add(new VectorNoise());
+             
+      switch(numPoints)
+        {
+        case 0:
+        case 1: break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                cacheDirty = true;
+                break;
+        default:vc.add(location,new VectorCache());
+                cacheDirty = true;
+        }
+      
+      numPoints++;
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all occurrences of Point v from the List of Points to interpolate through.  
+ * 
+ * @param v The Point to remove.
+ * @return <code>true</code> if we have removed at least one Point.
+ */
+  public synchronized boolean remove(Static1D v)
+    {
+    int n = vv.indexOf(v);
+    boolean found = false;
+   
+    while( n>=0 ) 
+      {
+      vv.remove(n);
+     
+      if( vn!=null ) vn.remove(0);
+     
+      switch(numPoints)
+        {
+        case 0:
+        case 1:
+        case 2: break;
+        case 3: vc.removeAllElements();
+                break;
+        default:vc.remove(n);
+                cacheDirty=true;
+        }
+
+      numPoints--;
+      found = true;
+      n = vv.indexOf(v);
+      }
+   
+    return found;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes a location'th Point from the List of Points we interpolate through.
+ * 
+ * @param location index of the Point we want to remove. 
+ * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
+ */
+  public synchronized boolean remove(int location)
+    {
+    if( location>=0 && location<numPoints ) 
+      {
+      vv.removeElementAt(location);
+      
+      if( vn!=null ) vn.remove(0);
+     
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                break;
+        default:vc.removeElementAt(location);
+        }
+
+      numPoints--;
+      cacheDirty = true; 
+      return true;
+      }
+
+   return false;
+   }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all Points.
+ */
+  public synchronized void removeAll()
+    {
+    numPoints = 0;
+    vv.removeAllElements();
+    vc.removeAllElements();
+    cacheDirty = false;
+   
+    if( vn!=null ) vn.removeAllElements();
+    }
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
+ * <p>
+ * Since this is a 1-dimensional Dynamic, the resulting interpolated Static1D gets written
+ * to a single location in the buffer: buffer[offset]. 
+ * 
+ * @param buffer Float buffer we will write the resulting Static1D to.
+ * @param offset Offset in the buffer where to write the result.
+ * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
+ *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
+ */
+  public synchronized void interpolate(float[] buffer, int offset, float time)
+    {
+    switch(numPoints)
+      {
+      case 0: buffer[offset] = 0.0f;
+              break;
+      case 1: curr = vv.elementAt(0);
+              buffer[offset] = curr.x;
+              break;
+      case 2: curr = vv.elementAt(0);
+              next = vv.elementAt(1);
+             
+              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
+             
+              if( vn!=null )
+                {
+                time = noise(time,0);
+                }
+             
+              buffer[offset] = (next.x-curr.x)*time + curr.x;
+              break;
+      default:float t = time;
+            
+              switch(mMode)
+                {
+                case MODE_LOOP: time = time*numPoints;
+                                break;
+                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
+                                break;
+                case MODE_JUMP: time = time*(numPoints-1);
+                                break;
+                }
+      
+              int vecCurr = (int)time;
+              time = time-vecCurr;
+      
+              if( vecCurr>=0 && vecCurr<numPoints )
+                {
+                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
+                else if( mVecCurr!= vecCurr )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                  {
+                  int vecNext;   
+                  mVecCurr = vecCurr;
+                                
+                  switch(mMode)
+                    {
+                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
+                                    break;
+                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
+                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
+                                    break;
+                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
+                                    break;
+                    default       : vecNext = 0;                
+                    }
+              
+                  next = vv.elementAt(vecNext);
+                  tmp2 = vc.elementAt(vecNext);
+              
+                  if( tmp2.vx!=next.x ) recomputeCache();
+                  }
+             
+                if( vn!=null )
+                  {
+                  time = noise(time,vecCurr);
+                  }
+            
+                tmp1 = vc.elementAt(vecCurr);
+                buffer[offset] = ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
+                break;
+                }
+        }
+     }  
+  
+  }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
diff --git a/src/main/java/org/distorted/library/type/Dynamic2D.java b/src/main/java/org/distorted/library/type/Dynamic2D.java
new file mode 100644
index 0000000..4a9a988
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Dynamic2D.java
@@ -0,0 +1,551 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+import java.util.Vector;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/** 
+* A 2-dimensional implementation of the Dynamic class to interpolate between a list
+* of Float2Ds.
+*/
+
+public class Dynamic2D extends Dynamic implements Data2D
+  {
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// the coefficients of the X(t), Y(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
+// (x,y) is the vector tangent to the path.
+// (vx,vy) is the original vector from vv (copied here so when interpolating we can see if it is 
+// still valid and if not - rebuild the Cache
+  
+  private class VectorCache
+    {
+    float ax, bx, cx, dx;
+    float ay, by, cy, dy;
+   
+    float x,y;
+    float vx,vy;
+    }
+  
+  private class VectorNoise
+    {    
+    float[] nx;
+    float[] ny;
+   
+    public VectorNoise()
+      {
+      nx = new float[NUM_NOISE]; 
+      nx[0] = mRnd.nextFloat();
+      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1]+mRnd.nextFloat();
+      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
+      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
+     
+      ny = new float[NUM_NOISE];
+      for(int i=0; i<NUM_NOISE; i++) ny[i] = mRnd.nextFloat()-0.5f;
+      }
+    }
+    
+  private Vector<VectorCache> vc;
+  private VectorCache tmp1, tmp2;
+   
+  private Vector<Static2D> vv;
+  private Static2D prev, curr, next;
+ 
+  private Vector<VectorNoise> vn;
+  private VectorNoise tmpN;
+  
+  private float mFactor;
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  synchronized void createNoise()
+    {
+    if( vn==null )
+      {
+      vn = new Vector<VectorNoise>();
+      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
+      }
+    }
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// no array bounds checking!
+  
+  private void vec(int c)
+    {
+    int p = c>0 ? c-1: numPoints-1;
+    int n = c<numPoints-1 ? c+1: 0;
+    
+    prev = vv.elementAt(p);
+    curr = vv.elementAt(c);
+    next = vv.elementAt(n);
+
+    tmp1 = vc.elementAt(c);
+    
+    float px = curr.x - prev.x;
+    float py = curr.y - prev.y;
+    float nx = next.x - curr.x;
+    float ny = next.y - curr.y;
+     
+    float d = nx*nx+ny*ny;
+    
+    if( d>0 )
+      {
+      float q = (float)Math.sqrt((px*px+py*py)/d);
+      
+      if( q>1 )
+        {
+        tmp1.x = nx+px/q;
+        tmp1.y = ny+py/q;
+        }
+      else
+        {
+        tmp1.x = px+nx*q;
+        tmp1.y = py+ny*q;
+        }
+      }
+    else
+      {
+      tmp1.x = 0.0f;
+      tmp1.y = 0.0f;
+      }
+    }
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  private void recomputeCache()
+    {  
+    if( numPoints==1 )
+      {
+      tmp1= vc.elementAt(0);
+      curr= vv.elementAt(0);
+              
+      tmp1.ax = tmp1.ay = 0.0f;
+      tmp1.bx = tmp1.by = 0.0f;
+      tmp1.cx = curr.x;
+      tmp1.cy = curr.y;
+      tmp1.dx = tmp1.dy = 0.0f;
+      }
+    else if( numPoints==2 )
+      {
+      tmp1= vc.elementAt(0);
+      tmp2= vc.elementAt(1);
+      curr= vv.elementAt(0);
+      next= vv.elementAt(1);
+          
+      tmp1.ax = tmp1.ay = 0.0f;
+      tmp1.bx = tmp1.by = 0.0f;
+      tmp1.cx = next.x - curr.x;
+      tmp1.cy = next.y - curr.y;
+      tmp1.dx = curr.x;
+      tmp1.dy = curr.y;
+      
+      tmp2.ax = tmp2.ay = 0.0f;
+      tmp2.bx = tmp2.by = 0.0f;
+      tmp2.cx = curr.x - next.x;
+      tmp2.cy = curr.y - next.y;
+      tmp2.dx = next.x;
+      tmp2.dy = next.y;
+      }
+    else
+      {
+      int i, n;  
+         
+      for(i=0; i<numPoints; i++) vec(i);
+   
+      for(i=0; i<numPoints; i++)
+        {
+        n = i<numPoints-1 ? i+1:0;  
+      
+        tmp1= vc.elementAt(i);
+        tmp2= vc.elementAt(n);
+        curr= vv.elementAt(i);
+        next= vv.elementAt(n);
+      
+        tmp1.vx = curr.x;
+        tmp1.vy = curr.y;
+        
+        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
+        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
+        tmp1.cx = tmp1.x;
+        tmp1.dx = curr.x;
+      
+        tmp1.ay =  2*curr.y +   tmp1.y - 2*next.y + tmp2.y;
+        tmp1.by = -3*curr.y - 2*tmp1.y + 3*next.y - tmp2.y;
+        tmp1.cy = tmp1.y;
+        tmp1.dy = curr.y;
+        }
+      }
+    
+    cacheDirty = false;
+    }
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float noise(float time,int vecNum)
+    {
+    float lower, upper, len;  
+    float d = time*(NUM_NOISE+1);
+    int index = (int)d;
+    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
+    tmpN = vn.elementAt(vecNum);
+   
+    float x = d-index;
+    x = x*x*(3-2*x);
+   
+    switch(index)
+      {
+      case 0        : mFactor = mNoise*tmpN.ny[0]*x;  
+                      return time + mNoise*(d*tmpN.nx[0]-time);                
+      case NUM_NOISE: mFactor= mNoise*tmpN.ny[NUM_NOISE-1]*(1-x);
+                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
+                      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);  
+                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
+      default       : float yb = tmpN.ny[index  ];
+                      float ya = tmpN.ny[index-1];
+                      mFactor  = mNoise*((yb-ya)*x+ya);
+   
+                      len = ((float)index)/(NUM_NOISE+1);
+                      lower = len + mNoise*(tmpN.nx[index-1]-len);   
+                      len = ((float)index+1)/(NUM_NOISE+1); 
+                      upper = len + mNoise*(tmpN.nx[index  ]-len);
+            
+                      return (upper-lower)*(d-index) + lower; 
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Default constructor.
+ */
+  public Dynamic2D()
+    {
+    vv = new Vector<Static2D>();
+    vc = new Vector<VectorCache>();
+    vn = null;
+    numPoints = 0;
+    cacheDirty = false;
+    mMode = MODE_LOOP;
+    mDuration = 0;
+    mCount = 0.5f;
+    mNoise = 0.0f;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the location'th Static2D.
+ *   
+ * @param location the index of the Point we are interested in.
+ * @return The Static2D, if 0<=location&lt;getNumPoints(), or null otherwise.
+ */  
+  public synchronized Static2D getPoint(int location)
+    {
+    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the location'th Point.
+ * 
+ * @param location the index of the Point we are setting.
+ * @param x New value of its first float.
+ */
+  public synchronized void setPoint(int location, float x, float y)
+    {
+    if( location>=0 && location<numPoints )
+      {
+      curr = vv.elementAt(location);
+   
+      if( curr!=null )
+        {
+        curr.set(x,y);
+        cacheDirty=true;
+        }
+      }
+    }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static2D to the end of our list of Points to interpolate through.
+ * <p>   
+ * Only a reference to the Point gets added to the List; this means that one can add a Point 
+ * here, and later on {@link Static2D#set(float,float)} it to some new value and the change
+ * will be seamlessly reflected in the interpolated path.  
+ * <p>
+ * A Point can be added multiple times.
+ *   
+ * @param v The Point to add.
+ */  
+  public synchronized void add(Static2D v)
+    {
+    if( v!=null )
+      {
+      vv.add(v);
+     
+      if( vn!=null ) vn.add(new VectorNoise());
+       
+      switch(numPoints)
+        {
+        case 0:
+        case 1: break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                break;
+        default:vc.add(new VectorCache());
+        }
+     
+      numPoints++;
+      cacheDirty = true;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static2D to the location'th place in our List of Points to interpolate through.
+ *   
+ * @param location Index in our List to add the new Point at.
+ * @param v The Point to add.
+ */  
+  public synchronized void add(int location, Static2D v)
+    {
+    if( v!=null )
+      {
+      vv.add(location, v);
+      
+      if( vn!=null ) vn.add(new VectorNoise());
+      
+      switch(numPoints)
+        {
+        case 0:
+        case 1: break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                break;
+        default:vc.add(location,new VectorCache());
+        }
+      
+      numPoints++;
+      cacheDirty = true;
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all occurrences of Point v from the List of Points to interpolate through.  
+ * 
+ * @param v The Point to remove.
+ * @return <code>true</code> if we have removed at least one Point.
+ */
+  public synchronized boolean remove(Static2D v)
+    {
+    int n = vv.indexOf(v);
+    boolean found = false;
+   
+    while( n>=0 ) 
+      {
+      vv.remove(n);
+     
+      if( vn!=null ) vn.remove(0);
+     
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                break;
+        default:vc.remove(n);
+        }
+     
+      numPoints--;
+      found = true;
+      n = vv.indexOf(v);
+      }
+   
+    if( found ) 
+      {
+      cacheDirty=true;
+      }
+   
+    return found;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes a location'th Point from the List of Points we interpolate through.
+ * 
+ * @param location index of the Point we want to remove. 
+ * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
+ */
+  public synchronized boolean remove(int location)
+    {
+    if( location>=0 && location<numPoints ) 
+      {
+      vv.removeElementAt(location);
+      
+      if( vn!=null ) vn.remove(0);
+      
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                break;
+        default:vc.removeElementAt(location);
+        }
+
+      numPoints--;
+      cacheDirty = true; 
+      return true;
+      }
+
+   return false;
+   }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all Points.
+ */
+  public synchronized void removeAll()
+    {
+    numPoints = 0;
+    vv.removeAllElements();
+    vc.removeAllElements();
+    cacheDirty = false;
+   
+    if( vn!=null ) vn.removeAllElements();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
+ * <p>
+ * Since this is a 2-dimensional Dynamic, the resulting interpolated Static2D gets written
+ * to two locations in the buffer: buffer[offset] and buffer[offset+1]. 
+ * 
+ * @param buffer Float buffer we will write the resulting Static2D to.
+ * @param offset Offset in the buffer where to write the result.
+ * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
+ *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
+ */  
+  public synchronized void interpolate(float[] buffer, int offset, float time)
+    {
+    switch(numPoints)
+      {
+      case 0: buffer[offset  ] = 0.0f;
+              buffer[offset+1] = 0.0f;
+              break;
+      case 1: curr = vv.elementAt(0);
+              buffer[offset  ] = curr.x;
+              buffer[offset+1] = curr.y;
+              break;
+      case 2: curr = vv.elementAt(0);
+              next = vv.elementAt(1);
+               
+              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
+             
+              if( vn!=null )
+                {
+                time = noise(time,0);
+              
+                float dx2 = next.x-curr.x;
+                float dy2 = next.y-curr.y;
+   
+                buffer[offset  ] = dx2*time + curr.x +dy2*mFactor;
+                buffer[offset+1] = dy2*time + curr.y -dx2*mFactor;
+                }
+              else
+                {
+                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
+                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
+                }
+              
+              break;
+      default:float t = time;
+        
+              switch(mMode)
+                {
+                case MODE_LOOP: time = time*numPoints;
+                                break;
+                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
+                                break;
+                case MODE_JUMP: time = time*(numPoints-1);
+                                break;
+                }
+            
+              int vecCurr = (int)time;
+              time = time-vecCurr;
+      
+              if( vecCurr>=0 && vecCurr<numPoints )
+                { 
+                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
+                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                  {
+                  int vecNext;   
+                  mVecCurr = vecCurr;
+                                
+                  switch(mMode)
+                    {
+                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
+                                    break;
+                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
+                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
+                                    break;
+                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
+                                    break;
+                    default       : vecNext = 0;                
+                    }
+              
+                  next = vv.elementAt(vecNext);
+                  tmp2 = vc.elementAt(vecNext);
+              
+                  if( tmp2.vx!=next.x || tmp2.vy!=next.y ) recomputeCache();
+                  }
+              
+                if( vn!=null )
+                  {
+                  time = noise(time,vecCurr);
+                  tmp1 = vc.elementAt(vecCurr);
+               
+                  float dx2 = (3*tmp1.ax*time+2*tmp1.bx)*time + tmp1.cx;
+                  float dy2 = (3*tmp1.ay*time+2*tmp1.by)*time + tmp1.cy;
+                 
+                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx +dy2*mFactor;
+                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy -dx2*mFactor;
+                  } 
+                else
+                  {
+                  tmp1 = vc.elementAt(vecCurr);
+                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
+                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy;
+                  }
+                
+                break;
+                }
+      }
+    }  
+  }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
diff --git a/src/main/java/org/distorted/library/type/Dynamic3D.java b/src/main/java/org/distorted/library/type/Dynamic3D.java
new file mode 100644
index 0000000..1c2e1e8
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Dynamic3D.java
@@ -0,0 +1,669 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+import java.util.Vector;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/** 
+* A 3-dimensional implementation of the Dynamic class to interpolate between a list
+* of Float3Ds.
+*/
+
+public class Dynamic3D extends Dynamic implements Data3D
+  {
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// the coefficients of the X(t), Y(t) and Z(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
+// (x,y,z) is the vector tangent to the path.
+// (vx,vy,vz) is the original vector from vv (copied here so when interpolating we can see if it is 
+// still valid and if not - rebuild the Cache
+  
+  private class VectorCache
+    {
+    float ax, bx, cx, dx;
+    float ay, by, cy, dy;
+    float az, bz, cz, dz;
+   
+    float x,y,z;
+    float vx,vy,vz;
+    }
+  
+  private class VectorNoise
+    {
+    float[] nx;
+    float[] ny;
+    float[] nz;
+   
+    public VectorNoise()
+      {
+      nx = new float[NUM_NOISE]; 
+      nx[0] = mRnd.nextFloat();
+      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1]+mRnd.nextFloat();
+      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
+      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
+     
+      ny = new float[NUM_NOISE];
+      for(int i=0; i<NUM_NOISE; i++) ny[i] = mRnd.nextFloat()-0.5f;
+     
+      nz = new float[NUM_NOISE];
+      for(int i=0; i<NUM_NOISE; i++) nz[i] = mRnd.nextFloat()-0.5f;  
+      }
+    }
+  
+  private Vector<VectorCache> vc;
+  private VectorCache tmp1, tmp2;
+
+  private Vector<Static3D> vv;
+  private Static3D prev, curr, next;
+  
+  private Vector<VectorNoise> vn;
+  private VectorNoise tmpN;
+  
+  private float mFactor1, mFactor2;  // used in Noise only. Those are noise factors; 1=noise of the (vec1X,vec1Y,vec1Z) vector; 2=noise of (vec2X,vec2Y,vec2Z)
+  private float vec1X,vec1Y,vec1Z;   // vector perpendicular to v(t) and in the same plane as v(t) and a(t) (for >2 points only, in case of 2 points this is calculated differently)
+  private float vec2X,vec2Y,vec2Z;   // vector perpendicular to v(t0 and to vec1.
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  synchronized void createNoise()
+    {
+    if( vn==null )
+      {  
+      vn = new Vector<VectorNoise>();
+      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
+      }
+    }
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// no array bounds checking!
+  
+  private void vec(int c)
+    {
+    int p = c>0 ? c-1: numPoints-1;
+    int n = c<numPoints-1 ? c+1: 0;
+    
+    prev = vv.elementAt(p);
+    curr = vv.elementAt(c);
+    next = vv.elementAt(n);
+
+    tmp1 = vc.elementAt(c);
+    
+    float px = curr.x - prev.x;
+    float py = curr.y - prev.y;
+    float pz = curr.z - prev.z;
+    float nx = next.x - curr.x;
+    float ny = next.y - curr.y;
+    float nz = next.z - curr.z;
+     
+    float d = nx*nx+ny*ny+nz*nz;
+    
+    if( d>0 )
+      {
+      float q = (float)Math.sqrt((px*px+py*py+pz*pz)/d);
+      
+      if( q>1 )
+        {
+        tmp1.x = nx+px/q;
+        tmp1.y = ny+py/q;
+        tmp1.z = nz+pz/q;
+        }
+      else
+        {
+        tmp1.x = px+nx*q;
+        tmp1.y = py+ny*q;
+        tmp1.z = pz+nz*q;
+        }
+      }
+    else
+      {
+      tmp1.x = 0.0f;
+      tmp1.y = 0.0f;
+      tmp1.z = 0.0f;  
+      }
+    }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  private void recomputeCache()
+    {  
+    if( numPoints==1 )
+      {
+      tmp1= vc.elementAt(0);
+      curr= vv.elementAt(0);
+        
+      tmp1.ax = tmp1.ay = tmp1.az = 0.0f;
+      tmp1.bx = tmp1.by = tmp1.bz = 0.0f;
+      tmp1.cx = curr.x;
+      tmp1.cy = curr.y;
+      tmp1.cz = curr.z;
+      tmp1.dx = tmp1.dy = tmp1.dz = 0.0f;
+      }
+    else if( numPoints==2 )
+      {
+      tmp1= vc.elementAt(0);
+      tmp2= vc.elementAt(1);
+      curr= vv.elementAt(0);
+      next= vv.elementAt(1);
+          
+      tmp1.ax = tmp1.ay = tmp1.az = 0.0f;
+      tmp1.bx = tmp1.by = tmp1.bz = 0.0f;
+      tmp1.cx = next.x - curr.x;
+      tmp1.cy = next.y - curr.y;
+      tmp1.cz = next.z - curr.z;
+      tmp1.dx = curr.x;
+      tmp1.dy = curr.y;
+      tmp1.dz = curr.z;
+      
+      tmp2.ax = tmp2.ay = tmp2.az = 0.0f;
+      tmp2.bx = tmp2.by = tmp2.bz = 0.0f;
+      tmp2.cx = curr.x - next.x;
+      tmp2.cy = curr.y - next.y;
+      tmp2.cz = curr.z - next.z;
+      tmp2.dx = next.x;
+      tmp2.dy = next.y;
+      tmp2.dz = next.z;
+      }
+    else
+      {
+      int i, n;  
+         
+      for(i=0; i<numPoints; i++) vec(i);
+   
+      for(i=0; i<numPoints; i++)
+        {
+        n = i<numPoints-1 ? i+1:0;  
+      
+        tmp1= vc.elementAt(i);
+        tmp2= vc.elementAt(n);
+        curr= vv.elementAt(i);
+        next= vv.elementAt(n);
+      
+        tmp1.vx = curr.x;
+        tmp1.vy = curr.y;
+        tmp1.vz = curr.z;
+        
+        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
+        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
+        tmp1.cx = tmp1.x;
+        tmp1.dx = curr.x;
+      
+        tmp1.ay =  2*curr.y +   tmp1.y - 2*next.y + tmp2.y;
+        tmp1.by = -3*curr.y - 2*tmp1.y + 3*next.y - tmp2.y;
+        tmp1.cy = tmp1.y;
+        tmp1.dy = curr.y;
+      
+        tmp1.az =  2*curr.z +   tmp1.z - 2*next.z + tmp2.z;
+        tmp1.bz = -3*curr.z - 2*tmp1.z + 3*next.z - tmp2.z;
+        tmp1.cz = tmp1.z;
+        tmp1.dz = curr.z;
+        }
+      }
+   
+    cacheDirty = false;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float noise(float time,int vecNum)
+    {
+    float lower, upper, len;  
+    float d = time*(NUM_NOISE+1);
+    int index = (int)d;
+    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
+    tmpN = vn.elementAt(vecNum);
+   
+    float t = d-index;
+    t = t*t*(3-2*t);
+   
+    switch(index)
+      {
+      case 0        : mFactor1 = mNoise*tmpN.ny[0]*t;
+                      mFactor2 = mNoise*tmpN.nz[0]*t;
+                      return time + mNoise*(d*tmpN.nx[0]-time);
+      case NUM_NOISE: mFactor1= mNoise*tmpN.ny[NUM_NOISE-1]*(1-t);
+                      mFactor2= mNoise*tmpN.nz[NUM_NOISE-1]*(1-t);
+                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
+                      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);  
+                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
+      default       : float ya,yb;
+                      yb = tmpN.ny[index  ];
+                      ya = tmpN.ny[index-1];
+                      mFactor1 = mNoise*((yb-ya)*t+ya);
+                      yb = tmpN.nz[index  ];
+                      ya = tmpN.nz[index-1];
+                      mFactor2 = mNoise*((yb-ya)*t+ya);
+   
+                      len = ((float)index)/(NUM_NOISE+1);
+                      lower = len + mNoise*(tmpN.nx[index-1]-len);   
+                      len = ((float)index+1)/(NUM_NOISE+1); 
+                      upper = len + mNoise*(tmpN.nx[index  ]-len);
+            
+                      return (upper-lower)*(d-index) + lower; 
+      }
+    }
+     
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// v is the speed vector (i.e. position p(t) differentiated by time)
+// a is the acceleration vector (differentiate once more)
+// now what we are doing is compute vec1{X,Y,Z} to be a vector perpendicular to v and in the same plane as both v and a.
+// vec2{X,Y,Z} would be (v)x(vec1).
+//  
+// vec1 = a-delta*v where delta = (v*a)/|v|^2   (see Gram-Schmidt)
+  
+  private void setUpVectors(float time,VectorCache vc)
+    {
+    if( vc!=null )
+      {
+      float vx = (3*vc.ax*time+2*vc.bx)*time+vc.cx;
+      float vy = (3*vc.ay*time+2*vc.by)*time+vc.cy;
+      float vz = (3*vc.az*time+2*vc.bz)*time+vc.cz;
+     
+      float ax = 6*vc.ax*time+2*vc.bx;
+      float ay = 6*vc.ay*time+2*vc.by;
+      float az = 6*vc.az*time+2*vc.bz;
+     
+      float v_sq = vx*vx+vy*vy+vz*vz;
+      float delta = (vx*ax+vy*ay+vz*az)/v_sq;
+     
+      vec1X = ax-delta*vx;
+      vec1Y = ay-delta*vy;
+      vec1Z = az-delta*vz;
+     
+      vec2X = vy*vec1Z-vz*vec1Y;
+      vec2Y = vz*vec1X-vx*vec1Z;
+      vec2Z = vx*vec1Y-vy*vec1X;
+     
+      float len1 = (float)Math.sqrt(v_sq/(vec1X*vec1X+vec1Y*vec1Y+vec1Z*vec1Z));
+      float len2 = (float)Math.sqrt(v_sq/(vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z));   
+     
+      vec1X*=len1;
+      vec1Y*=len1;
+      vec1Z*=len1;
+     
+      vec2X*=len2;
+      vec2Y*=len2;
+      vec2Z*=len2;
+      }
+    else
+      {
+      curr = vv.elementAt(0);
+      next = vv.elementAt(1); 
+     
+      float vx = (next.x-curr.x);
+      float vy = (next.y-curr.y);
+      float vz = (next.z-curr.z);
+     
+      float b = (float)Math.sqrt(vx*vx+vy*vy);
+     
+      if( b>0.0f )
+        {
+        vec1X = vx*vz/b;
+        vec1Y = vy*vz/b;
+        vec1Z = -b;
+      
+        vec2X = vy*vec1Z-vz*vec1Y;
+        vec2Y = vz*vec1X-vx*vec1Z;
+        vec2Z = vx*vec1Y-vy*vec1X;
+       
+        float len2 = (float)Math.sqrt((vx*vx+vy*vy+vz*vz)/(vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z));
+       
+        vec2X*=len2;
+        vec2Y*=len2;
+        vec2Z*=len2;
+        }
+      else
+        {
+        vec1X = vz;
+        vec1Y = 0.0f;
+        vec1Z = 0.0f;
+      
+        vec2X = 0.0f;
+        vec2Y = vz;
+        vec2Z = 0.0f;
+        }
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Default constructor.
+ */
+  public Dynamic3D()
+    {
+    vv = new Vector<Static3D>();
+    vc = new Vector<VectorCache>();
+    vn = null;
+    numPoints = 0;
+    cacheDirty = false;
+    mMode = MODE_LOOP;
+    mDuration = 0;
+    mCount = 0.5f;
+    mNoise = 0.0f;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the location'th Static3D.
+ *   
+ * @param location the index of the Point we are interested in.
+ * @return The Static3D, if 0<=location&lt;getNumPoints(), or null otherwise.
+ */  
+  public synchronized Static3D getPoint(int location)
+    {
+    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the location'th Point.
+ * 
+ * @param location the index of the Point we are setting.
+ * @param x New value of its first float.
+ */
+  public synchronized void setPoint(int location, float x, float y, float z)
+    {
+    if( location>=0 && location<numPoints )
+      {
+      curr = vv.elementAt(location);
+   
+      if( curr!=null )
+        {
+        curr.set(x,y,z);
+        cacheDirty=true;
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static3D to the end of our list of Points to interpolate through.
+ * <p>   
+ * Only a reference to the Point gets added to the List; this means that one can add a Point 
+ * here, and later on {@link Static3D#set(float,float,float)} it to some new value and the
+ * change will be seamlessly reflected in the interpolated path.  
+ * <p>
+ * A Point can be added multiple times.
+ *   
+ * @param v The Point to add.
+ */    
+  public synchronized void add(Static3D v)
+    {
+    if( v!=null )
+      {
+      vv.add(v);
+        
+      if( vn!=null ) vn.add(new VectorNoise());
+       
+      switch(numPoints)
+        {
+        case 0: break;
+        case 1: setUpVectors(0.0f,null);
+                break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                break;
+        default:vc.add(new VectorCache());
+        }
+
+      numPoints++;
+      cacheDirty = true;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static3D to the location'th place in our List of Points to interpolate through.
+ *   
+ * @param location Index in our List to add the new Point at.
+ * @param v The Point to add.
+ */  
+  public synchronized void add(int location, Static3D v)
+    {
+    if( v!=null )
+      {
+      vv.add(location, v);
+      
+      if( vn!=null ) vn.add(new VectorNoise());
+      
+      switch(numPoints)
+        {
+        case 0: break;
+        case 1: setUpVectors(0.0f,null);
+                break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                break;
+        default:vc.add(location,new VectorCache());
+        }
+
+      numPoints++;
+      cacheDirty = true;
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all occurrences of Point v from the List of Points to interpolate through.  
+ * 
+ * @param v The Point to remove.
+ * @return <code>true</code> if we have removed at least one Point.
+ */
+  public synchronized boolean remove(Static3D v)
+    {
+    int n = vv.indexOf(v);
+    boolean found = false;
+   
+    while( n>=0 ) 
+      {
+      vv.remove(n);
+     
+      if( vn!=null ) vn.remove(0);
+     
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                setUpVectors(0.0f,null);
+                break;
+        default:vc.remove(n);
+        }
+
+      numPoints--;
+      found = true;
+      n = vv.indexOf(v);
+      }
+   
+    if( found ) 
+      {
+      cacheDirty=true;
+      }
+   
+    return found;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes a location'th Point from the List of Points we interpolate through.
+ * 
+ * @param location index of the Point we want to remove. 
+ * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
+ */
+  public synchronized boolean remove(int location)
+    {
+    if( location>=0 && location<numPoints ) 
+      {
+      vv.removeElementAt(location);
+       
+      if( vn!=null ) vn.remove(0);
+      
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                setUpVectors(0.0f,null);
+                break;
+        default:vc.removeElementAt(location);
+        }
+
+      numPoints--;
+      cacheDirty = true; 
+      return true;
+      }
+
+   return false;
+   }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all Points.
+ */
+  public synchronized void removeAll()
+    {
+    numPoints = 0;
+    vv.removeAllElements();
+    vc.removeAllElements();
+    cacheDirty = false;
+   
+    if( vn!=null ) vn.removeAllElements();
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
+ * <p>
+ * Since this is a 3-dimensional Dynamic, the resulting interpolated Static3D gets written
+ * to three locations in the buffer: buffer[offset], buffer[offset+1] and buffer[offset+2]. 
+ * 
+ * @param buffer Float buffer we will write the resulting Static3D to.
+ * @param offset Offset in the buffer where to write the result.
+ * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
+ *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
+ */    
+  public synchronized void interpolate(float[] buffer, int offset, float time)
+    {  
+    switch(numPoints)
+      {
+      case 0: buffer[offset  ] = 0.0f;
+              buffer[offset+1] = 0.0f;
+              buffer[offset+2] = 0.0f;
+              break;
+      case 1: curr = vv.elementAt(0);
+              buffer[offset  ] = curr.x;
+              buffer[offset+1] = curr.y;
+              buffer[offset+2] = curr.z;
+              break;
+      case 2: curr = vv.elementAt(0);
+              next = vv.elementAt(1);
+             
+              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
+             
+              if( vn!=null )
+                {
+                time = noise(time,0);
+            
+                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (vec1X*mFactor1 + vec2X*mFactor2);
+                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (vec1Y*mFactor1 + vec2Y*mFactor2);
+                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (vec1Z*mFactor1 + vec2Z*mFactor2); 
+                }
+              else
+                {
+                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
+                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
+                buffer[offset+2] = (next.z-curr.z)*time + curr.z;
+                }
+             
+              break;
+      default:float t = time;
+        
+              switch(mMode)
+                {
+                case MODE_LOOP: time = time*numPoints;
+                                break;
+                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
+                                break;
+                case MODE_JUMP: time = time*(numPoints-1);
+                                break;
+                }
+           
+              int vecCurr = (int)time;
+              time = time-vecCurr;
+      
+              if( vecCurr>=0 && vecCurr<numPoints )
+                {
+                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
+                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                  {
+                  int vecNext;   
+                  mVecCurr = vecCurr;
+                       
+                  switch(mMode)
+                    {
+                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
+                                    break;
+                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
+                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
+                                    break;
+                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
+                                    break;
+                    default       : vecNext = 0;                
+                    }
+              
+                  next = vv.elementAt(vecNext);
+                  tmp2 = vc.elementAt(vecNext);
+              
+                  if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z ) recomputeCache();
+                  }
+            
+                tmp1 = vc.elementAt(vecCurr);
+               
+                if( vn!=null )
+                  {
+                  time = noise(time,vecCurr);
+              
+                  setUpVectors(time,tmp1);
+                 
+                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx + (vec1X*mFactor1 + vec2X*mFactor2);
+                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy + (vec1Y*mFactor1 + vec2Y*mFactor2);
+                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz + (vec1Z*mFactor1 + vec2Z*mFactor2);
+                  }
+                else
+                  {
+                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
+                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy;
+                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz;
+                  }
+               
+                break;
+                }
+       }
+     }  
+
+  }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
diff --git a/src/main/java/org/distorted/library/type/Dynamic4D.java b/src/main/java/org/distorted/library/type/Dynamic4D.java
new file mode 100644
index 0000000..d33a712
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Dynamic4D.java
@@ -0,0 +1,771 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+import java.util.Vector;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/** 
+* A 4-dimensional implementation of the Dynamic class to interpolate between a list
+* of Float4Ds.
+*/
+
+public class Dynamic4D extends Dynamic implements Data4D
+  {
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// the coefficients of the X(t), Y(t), Z(t), W(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
+// (x,y,z,w) is the vector tangent to the path.
+// (vx,vy,vz,vw) is the original vector from vv (copied here so when interpolating we can see if it is 
+// still valid and if not - rebuild the Cache
+  
+  private class VectorCache
+    {
+    float ax, bx, cx, dx;
+    float ay, by, cy, dy;
+    float az, bz, cz, dz;
+    float aw, bw, cw, dw;
+   
+    float x,y,z,w;
+    float vx,vy,vz,vw;
+    }
+  
+  private class VectorNoise
+    {
+    float[] nx;
+    float[] ny;
+    float[] nz;
+    float[] nw;
+   
+    public VectorNoise()
+      {
+      nx = new float[NUM_NOISE]; 
+      nx[0] = mRnd.nextFloat();
+      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1] + mRnd.nextFloat();
+      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
+      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
+     
+      ny = new float[NUM_NOISE];
+      for(int i=0; i<NUM_NOISE; i++) ny[i] = mRnd.nextFloat()-0.5f;
+     
+      nz = new float[NUM_NOISE];
+      for(int i=0; i<NUM_NOISE; i++) nz[i] = mRnd.nextFloat()-0.5f;
+     
+      nw = new float[NUM_NOISE];
+      for(int i=0; i<NUM_NOISE; i++) nw[i] = mRnd.nextFloat()-0.5f;  
+      }
+    }
+  
+  private Vector<VectorCache> vc;
+  private VectorCache tmp1, tmp2;
+
+  private Vector<Static4D> vv;
+  private Static4D prev, curr, next;
+  
+  private Vector<VectorNoise> vn;
+  private VectorNoise tmpN;
+  
+  private float mFactor1, mFactor2, mFactor3; // used in Noise only. Those are noise factors; 1=noise of the (vec1X,vec1Y,vec1Z,vec1W) vector; 2=noise of (vec2X,vec2Y,vec2Z,vec2W) and same for vec3.
+  private float vec1X,vec1Y,vec1Z,vec1W;      // vector perpendicular to v(t) and in the same plane as v(t) and a(t) (for >2 points only, in case of 2 points this is calculated differently)
+  private float vec2X,vec2Y,vec2Z,vec2W;      // vector perpendicular to v(t) and to vec1.
+  private float vec3X,vec3Y,vec3Z,vec3W;      // vector perpendicular to v(t) and to vec1.
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  synchronized void createNoise()
+    {
+    if( vn==null )
+      {  
+      vn = new Vector<VectorNoise>();
+      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
+      }
+    }
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// no array bounds checking!
+  
+  private void vec(int c)
+    {
+    int p = c>0 ? c-1: numPoints-1;
+    int n = c<numPoints-1 ? c+1: 0;
+    
+    prev = vv.elementAt(p);
+    curr = vv.elementAt(c);
+    next = vv.elementAt(n);
+
+    tmp1 = vc.elementAt(c);
+    
+    float px = curr.x - prev.x;
+    float py = curr.y - prev.y;
+    float pz = curr.z - prev.z;
+    float pw = curr.w - prev.w;
+    float nx = next.x - curr.x;
+    float ny = next.y - curr.y;
+    float nz = next.z - curr.z;
+    float nw = next.w - curr.w;
+     
+    float d = nx*nx+ny*ny+nz*nz+nw*nw;
+    
+    if( d>0 )
+      {
+      float q = (float)Math.sqrt((px*px+py*py+pz*pz+pw*pw)/d);
+      
+      if( q>1 )
+        {
+        tmp1.x = nx+px/q;
+        tmp1.y = ny+py/q;
+        tmp1.z = nz+pz/q;
+        tmp1.w = nw+pw/q;
+        }
+      else
+        {
+        tmp1.x = px+nx*q;
+        tmp1.y = py+ny*q;
+        tmp1.z = pz+nz*q;
+        tmp1.w = pw+nw*q;
+        }
+      }
+    else
+      {
+      tmp1.x = 0.0f;
+      tmp1.y = 0.0f;
+      tmp1.z = 0.0f;  
+      tmp1.w = 0.0f;
+      }
+    }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  private void recomputeCache()
+    {  
+    if( numPoints==1 )
+      {
+      tmp1= vc.elementAt(0);
+      curr= vv.elementAt(0);
+        
+      tmp1.ax = tmp1.ay = tmp1.az = tmp1.aw = 0.0f;
+      tmp1.bx = tmp1.by = tmp1.bz = tmp1.bw = 0.0f;
+      tmp1.cx = curr.x;
+      tmp1.cy = curr.y;
+      tmp1.cz = curr.z;
+      tmp1.cw = curr.w;
+      tmp1.dx = tmp1.dy = tmp1.dz = tmp1.dw = 0.0f;
+      }
+    else if( numPoints==2 )
+      {
+      tmp1= vc.elementAt(0);
+      tmp2= vc.elementAt(1);
+      curr= vv.elementAt(0);
+      next= vv.elementAt(1);
+      
+      tmp1.ax = tmp1.ay = tmp1.az = tmp1.aw = 0.0f;
+      tmp1.bx = tmp1.by = tmp1.bz = tmp1.bw = 0.0f;
+      tmp1.cx = next.x - curr.x;
+      tmp1.cy = next.y - curr.y;
+      tmp1.cz = next.z - curr.z;
+      tmp1.cw = next.w - curr.w;
+      tmp1.dx = curr.x;
+      tmp1.dy = curr.y;
+      tmp1.dz = curr.z;
+      tmp1.dw = curr.w;
+      
+      tmp2.ax = tmp2.ay = tmp2.az = tmp2.aw = 0.0f;
+      tmp2.bx = tmp2.by = tmp2.bz = tmp2.bw = 0.0f;
+      tmp2.cx = curr.x - next.x;
+      tmp2.cy = curr.y - next.y;
+      tmp2.cz = curr.z - next.z;
+      tmp2.cw = curr.w - next.w;
+      tmp2.dx = next.x;
+      tmp2.dy = next.y;
+      tmp2.dz = next.z;
+      tmp2.dw = next.w;
+      }
+    else
+      {
+      int i, n;  
+      
+      for(i=0; i<numPoints; i++) vec(i);
+   
+      for(i=0; i<numPoints; i++)
+        {
+        n = i<numPoints-1 ? i+1:0;  
+      
+        tmp1= vc.elementAt(i);
+        tmp2= vc.elementAt(n);
+        curr= vv.elementAt(i);
+        next= vv.elementAt(n);
+      
+        tmp1.vx = curr.x;
+        tmp1.vy = curr.y;
+        tmp1.vz = curr.z;
+        tmp1.vw = curr.w;
+        
+        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
+        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
+        tmp1.cx = tmp1.x;
+        tmp1.dx = curr.x;
+      
+        tmp1.ay =  2*curr.y +   tmp1.y - 2*next.y + tmp2.y;
+        tmp1.by = -3*curr.y - 2*tmp1.y + 3*next.y - tmp2.y;
+        tmp1.cy = tmp1.y;
+        tmp1.dy = curr.y;
+      
+        tmp1.az =  2*curr.z +   tmp1.z - 2*next.z + tmp2.z;
+        tmp1.bz = -3*curr.z - 2*tmp1.z + 3*next.z - tmp2.z;
+        tmp1.cz = tmp1.z;
+        tmp1.dz = curr.z;
+        
+        tmp1.aw =  2*curr.w +   tmp1.w - 2*next.w + tmp2.w;
+        tmp1.bw = -3*curr.w - 2*tmp1.w + 3*next.w - tmp2.w;
+        tmp1.cw = tmp1.w;
+        tmp1.dw = curr.w;
+        }
+      }
+   
+    cacheDirty = false;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float noise(float time,int vecNum)
+    {
+    float lower, upper, len;  
+    float d = time*(NUM_NOISE+1);
+    int index = (int)d;
+    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
+    tmpN = vn.elementAt(vecNum);
+   
+    float t = d-index;
+    t = t*t*(3-2*t);
+   
+    switch(index)
+      {
+      case 0        : mFactor1 = mNoise*tmpN.ny[0]*t;
+                      mFactor2 = mNoise*tmpN.nz[0]*t;
+                      mFactor3 = mNoise*tmpN.nw[0]*t;
+                      return time + mNoise*(d*tmpN.nx[0]-time);
+      case NUM_NOISE: mFactor1= mNoise*tmpN.ny[NUM_NOISE-1]*(1-t);
+                      mFactor2= mNoise*tmpN.nz[NUM_NOISE-1]*(1-t);
+                      mFactor3= mNoise*tmpN.nw[NUM_NOISE-1]*(1-t);
+                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
+                      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);  
+                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
+      default       : float ya,yb;
+                      yb = tmpN.ny[index  ];
+                      ya = tmpN.ny[index-1];
+                      mFactor1 = mNoise*((yb-ya)*t+ya);
+                      yb = tmpN.nz[index  ];
+                      ya = tmpN.nz[index-1];
+                      mFactor2 = mNoise*((yb-ya)*t+ya);
+                      yb = tmpN.nw[index  ];
+                      ya = tmpN.nw[index-1];
+                      mFactor3 = mNoise*((yb-ya)*t+ya);
+   
+                      len = ((float)index)/(NUM_NOISE+1);
+                      lower = len + mNoise*(tmpN.nx[index-1]-len);   
+                      len = ((float)index+1)/(NUM_NOISE+1); 
+                      upper = len + mNoise*(tmpN.nx[index  ]-len);
+            
+                      return (upper-lower)*(d-index) + lower; 
+      }
+    }
+     
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// v is the speed vector (i.e. position p(t) differentiated by time)
+// a is the acceleration vector (differentiate once more)
+//
+// Now we construct orthogonal basis with Gram-Schmidt:  
+// vec1 = a-delta*v where delta = (v*a)/|v|^2
+// vec2 = (0,0,1,0) - coeff1*(vx,vy,vz,vw) - coeff2*(vec1x,vec1y,vec1z,vec1w)                                     where coeff1 = vz/|v|^2, coeff2 = vec1Z/|vec1|^2
+// vec3 = (0,0,0,1) - coeff1*(vx,vy,vz,vw) - coeff2*(vec1x,vec1y,vec1z,vec1w) - coeff3*(vec2x,vec2y,vec2z,vec2w)  where coeff1 = vw/|v|^2, coeff2 = vec1W/|vec1|^2, coeff3 = vec2W/|vec2|^2
+    
+  private void setUpVectors(float time,VectorCache vc)
+    {
+    if( vc!=null )
+      {
+      float vx = (3*vc.ax*time+2*vc.bx)*time+vc.cx;
+      float vy = (3*vc.ay*time+2*vc.by)*time+vc.cy;
+      float vz = (3*vc.az*time+2*vc.bz)*time+vc.cz;
+      float vw = (3*vc.aw*time+2*vc.bw)*time+vc.cw;
+     
+      float ax = 6*vc.ax*time+2*vc.bx;
+      float ay = 6*vc.ay*time+2*vc.by;
+      float az = 6*vc.az*time+2*vc.bz;
+      float aw = 6*vc.aw*time+2*vc.bw;
+     
+      float v_sq = vx*vx+vy*vy+vz*vz+vw*vw;
+      float delta = (vx*ax+vy*ay+vz*az*vw*vw)/v_sq;
+     
+      vec1X = ax-delta*vx;
+      vec1Y = ay-delta*vy;
+      vec1Z = az-delta*vz;
+      vec1W = aw-delta*vw;
+     
+      float vec1_sq = vec1X*vec1X+vec1Y*vec1Y+vec1Z*vec1Z+vec1W*vec1W;
+     
+      // construct vec2 and vec3. Cross product does not work in 4th dimension!
+      float coeff21 = vz/v_sq;
+      float coeff22 = vec1Z/vec1_sq;
+      vec2X = 0.0f - coeff21*vx - coeff22*vec1X;
+      vec2Y = 0.0f - coeff21*vy - coeff22*vec1Y;
+      vec2Z = 1.0f - coeff21*vz - coeff22*vec1Z;
+      vec2W = 0.0f - coeff21*vw - coeff22*vec1W;
+     
+      float vec2_sq = vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z+vec2W*vec2W;
+      float coeff31 = vw/v_sq;
+      float coeff32 = vec1W/vec1_sq;
+      float coeff33 = vec2W/vec2_sq;
+      vec2X = 0.0f - coeff31*vx - coeff32*vec1X - coeff33*vec2X;
+      vec2Y = 0.0f - coeff31*vy - coeff32*vec1Y - coeff33*vec2Y;
+      vec2Z = 0.0f - coeff31*vz - coeff32*vec1Z - coeff33*vec2Z;
+      vec2W = 1.0f - coeff31*vw - coeff32*vec1W - coeff33*vec2W;
+     
+      float vec3_sq = vec3X*vec3X+vec3Y*vec3Y+vec3Z*vec3Z+vec3W*vec3W;
+     
+      float len1 = (float)Math.sqrt(v_sq/vec1_sq);   
+      float len2 = (float)Math.sqrt(v_sq/vec2_sq);   
+      float len3 = (float)Math.sqrt(v_sq/vec3_sq);
+     
+      vec1X*=len1;
+      vec1Y*=len1;
+      vec1Z*=len1;
+      vec1W*=len1;
+     
+      vec2X*=len2;
+      vec2Y*=len2;
+      vec2Z*=len2;
+      vec2W*=len2;
+     
+      vec3X*=len3;
+      vec3Y*=len3;
+      vec3Z*=len3;
+      vec3W*=len3;
+      }
+    else
+      {
+      curr = vv.elementAt(0);
+      next = vv.elementAt(1); 
+     
+      float vx = (next.x-curr.x);
+      float vy = (next.y-curr.y);
+      float vz = (next.z-curr.z);
+      float vw = (next.w-curr.w);
+     
+      float b = (float)Math.sqrt(vx*vx+vy*vy+vz*vz);
+     
+      if( b>0.0f )
+        {
+        vec1X = vx*vw/b;
+        vec1Y = vy*vw/b;
+        vec1Z = vz*vw/b;
+        vec1W = -b;
+      
+        float v_sq = vx*vx+vy*vy+vz*vz+vw*vw;
+        float vec1_sq = vec1X*vec1X+vec1Y*vec1Y+vec1Z*vec1Z+vec1W*vec1W;
+     
+        // construct vec2 and vec3. Cross product does not work in 4th dimension!
+        float coeff21 = vz/v_sq;
+        float coeff22 = vec1Z/vec1_sq;
+        vec2X = 0.0f - coeff21*vx - coeff22*vec1X;
+        vec2Y = 0.0f - coeff21*vy - coeff22*vec1Y;
+        vec2Z = 1.0f - coeff21*vz - coeff22*vec1Z;
+        vec2W = 0.0f - coeff21*vw - coeff22*vec1W;
+     
+        float vec2_sq = vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z+vec2W*vec2W;
+        float coeff31 = vw/v_sq;
+        float coeff32 = vec1W/vec1_sq;
+        float coeff33 = vec2W/vec2_sq;
+        vec2X = 0.0f - coeff31*vx - coeff32*vec1X - coeff33*vec2X;
+        vec2Y = 0.0f - coeff31*vy - coeff32*vec1Y - coeff33*vec2Y;
+        vec2Z = 0.0f - coeff31*vz - coeff32*vec1Z - coeff33*vec2Z;
+        vec2W = 1.0f - coeff31*vw - coeff32*vec1W - coeff33*vec2W;
+     
+        float vec3_sq = vec3X*vec3X+vec3Y*vec3Y+vec3Z*vec3Z+vec3W*vec3W;
+     
+        float len1 = (float)Math.sqrt(v_sq/vec1_sq);    
+        float len2 = (float)Math.sqrt(v_sq/vec2_sq);    
+        float len3 = (float)Math.sqrt(v_sq/vec3_sq);
+     
+        vec1X*=len1;
+        vec1Y*=len1;
+        vec1Z*=len1;
+        vec1W*=len1;
+     
+        vec2X*=len2;
+        vec2Y*=len2;
+        vec2Z*=len2;
+        vec2W*=len2;
+     
+        vec3X*=len3;
+        vec3Y*=len3;
+        vec3Z*=len3;
+        vec3W*=len3;
+        }
+      else
+        {
+        vec1X = vw;
+        vec1Y = 0.0f;
+        vec1Z = 0.0f;
+        vec1W = 0.0f;
+      
+        vec2X = 0.0f;
+        vec2Y = vw;
+        vec2Z = 0.0f;
+        vec2W = 0.0f;
+      
+        vec3X = 0.0f;
+        vec3Y = 0.0f;
+        vec3Z = vw;
+        vec3W = 0.0f;
+        }
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Default constructor.
+ */
+  public Dynamic4D()
+    {
+    vv = new Vector<Static4D>();
+    vc = new Vector<VectorCache>();
+    vn = null;
+    numPoints = 0;
+    cacheDirty = false;
+    mMode = MODE_LOOP;
+    mDuration = 0;
+    mCount = 0.5f;
+    mNoise = 0.0f;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the location'th Static4D.
+ *   
+ * @param location the index of the Point we are interested in.
+ * @return The Static4D, if 0<=location&lt;getNumPoints(), or null otherwise.
+ */  
+  public synchronized Static4D getPoint(int location)
+    {
+    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the location'th Point.
+ * 
+ * @param location the index of the Point we are setting.
+ * @param x New value of its first float.
+ */
+  public synchronized void setPoint(int location, float x, float y, float z, float w)
+    {
+    if( location>=0 && location<numPoints )
+      {
+      curr = vv.elementAt(location);
+   
+      if( curr!=null )
+        {
+        curr.set(x,y,z,w);
+        cacheDirty=true;
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static4D to the end of our list of Points to interpolate through.
+ * <p>   
+ * Only a reference to the Point gets added to the List; this means that one can add a Point 
+ * here, and later on {@link Static4D#set(float,float,float,float)} it to some new value and
+ * the change will be seamlessly reflected in the interpolated path.  
+ * <p>
+ * A Point can be added multiple times.
+ *   
+ * @param v The Point to add.
+ */    
+  public synchronized void add(Static4D v)
+    {
+    if( v!=null )
+      {
+      vv.add(v);
+        
+      if( vn!=null ) vn.add(new VectorNoise());
+       
+       switch(numPoints)
+         {
+         case 0: break;
+         case 1: setUpVectors(0.0f,null);
+                 break;
+         case 2: vc.add(new VectorCache());
+                 vc.add(new VectorCache());
+                 vc.add(new VectorCache());
+                 break;
+         default:vc.add(new VectorCache());
+         }
+
+       numPoints++;
+       cacheDirty = true;
+       }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static4D to the location'th place in our List of Points to interpolate through.
+ *   
+ * @param location Index in our List to add the new Point at.
+ * @param v The Static4D to add.
+ */  
+  public synchronized void add(int location, Static4D v)
+    {
+    if( v!=null )
+      {
+      vv.add(location, v);
+      
+      if( vn!=null ) vn.add(new VectorNoise());
+      
+      switch(numPoints)
+        {
+        case 0: break;
+        case 1: setUpVectors(0.0f,null);
+                break;
+        case 2: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                break;
+        default:vc.add(location,new VectorCache());
+        }
+
+      numPoints++;
+      cacheDirty = true;
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all occurrences of Point v from the List of Points to interpolate through.  
+ * 
+ * @param v The Point to remove.
+ * @return <code>true</code> if we have removed at least one Point.
+ */
+  public synchronized boolean remove(Static4D v)
+    {
+    int n = vv.indexOf(v);
+    boolean found = false;
+   
+    while( n>=0 ) 
+      {
+      vv.remove(n);
+     
+      if( vn!=null ) vn.remove(0);
+     
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                setUpVectors(0.0f,null);
+                break;
+        default:vc.remove(n);
+        }
+
+      numPoints--;
+      found = true;
+      n = vv.indexOf(v);
+      }
+   
+    if( found ) 
+      {
+      cacheDirty=true;
+      }
+   
+    return found;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes a location'th Point from the List of Points we interpolate through.
+ * 
+ * @param location index of the Point we want to remove. 
+ * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
+ */
+  public synchronized boolean remove(int location)
+    {
+    if( location>=0 && location<numPoints ) 
+      {
+      vv.removeElementAt(location);
+       
+      if( vn!=null ) vn.remove(0);
+      
+      switch(numPoints)
+        {
+        case 0:
+        case 1: 
+        case 2: break;
+        case 3: vc.removeAllElements();
+                setUpVectors(0.0f,null);
+                break;
+        default:vc.removeElementAt(location);
+        }
+
+      numPoints--;
+      cacheDirty = true; 
+      return true;
+      }
+
+    return false;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all Points.
+ */
+  public synchronized void removeAll()
+    {
+    numPoints = 0;
+    vv.removeAllElements();
+    vc.removeAllElements();
+    cacheDirty = false;
+   
+    if( vn!=null ) vn.removeAllElements();
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
+ * <p>
+ * Since this is a 4-dimensional Dynamic, the resulting interpolated Static4D gets written
+ * to four locations in the buffer: buffer[offset], buffer[offset+1], buffer[offset+2] and buffer[offset+3]. 
+ * 
+ * @param buffer Float buffer we will write the resulting Static4D to.
+ * @param offset Offset in the buffer where to write the result.
+ * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
+ *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
+ */    
+  public synchronized void interpolate(float[] buffer, int offset, float time)
+    {  
+    switch(numPoints)
+      {
+      case 0: buffer[offset  ] = 0.0f;
+              buffer[offset+1] = 0.0f;
+              buffer[offset+2] = 0.0f;
+              buffer[offset+3] = 0.0f;
+              break;
+      case 1: curr = vv.elementAt(0);
+              buffer[offset  ] = curr.x;
+              buffer[offset+1] = curr.y;
+              buffer[offset+2] = curr.z;
+              buffer[offset+3] = curr.w;
+              break;
+      case 2: curr = vv.elementAt(0);
+              next = vv.elementAt(1);
+            
+              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
+             
+              if( vn!=null )
+                {
+                time = noise(time,0);
+            
+                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (vec1X*mFactor1 + vec2X*mFactor2 + vec3X*mFactor3);
+                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (vec1Y*mFactor1 + vec2Y*mFactor2 + vec3Y*mFactor3);
+                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (vec1Z*mFactor1 + vec2Z*mFactor2 + vec3Z*mFactor3);
+                buffer[offset+3] = (next.w-curr.w)*time + curr.w + (vec1W*mFactor1 + vec2W*mFactor2 + vec3W*mFactor3); 
+                }
+              else
+                {
+                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
+                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
+                buffer[offset+2] = (next.z-curr.z)*time + curr.z;
+                buffer[offset+3] = (next.w-curr.w)*time + curr.w;
+                }
+                
+              break;
+      default:float t = time;
+        
+              switch(mMode)
+                {
+                case MODE_LOOP: time = time*numPoints;
+                                break;
+                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
+                                break;
+                case MODE_JUMP: time = time*(numPoints-1);
+                                break;
+                }
+     
+              int vecCurr = (int)time;
+              time = time-vecCurr;
+      
+              if( vecCurr>=0 && vecCurr<numPoints )
+                {
+                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
+                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                  {
+                  int vecNext;   
+                  mVecCurr = vecCurr;
+                       
+                  switch(mMode)
+                    {
+                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
+                                    break;
+                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
+                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
+                                    break;
+                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
+                                    break;
+                    default       : vecNext = 0;                
+                    }
+     
+                  next = vv.elementAt(vecNext);
+                  tmp2 = vc.elementAt(vecNext);
+              
+                  if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z || tmp2.vw!=next.w ) recomputeCache();
+                  }
+            
+                tmp1 = vc.elementAt(vecCurr);
+               
+                if( vn!=null )
+                  {
+                  time = noise(time,vecCurr);
+              
+                  setUpVectors(time,tmp1);
+                 
+                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx + (vec1X*mFactor1 + vec2X*mFactor2 + vec3X*mFactor3);
+                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy + (vec1Y*mFactor1 + vec2Y*mFactor2 + vec3Y*mFactor3);
+                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz + (vec1Z*mFactor1 + vec2Z*mFactor2 + vec3Z*mFactor3);
+                  buffer[offset+3]= ((tmp1.aw*time+tmp1.bw)*time+tmp1.cw)*time+tmp1.dw + (vec1W*mFactor1 + vec2W*mFactor2 + vec3W*mFactor3);
+                  }
+                else
+                  {
+                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
+                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy;
+                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz;
+                  buffer[offset+3]= ((tmp1.aw*time+tmp1.bw)*time+tmp1.cw)*time+tmp1.dw;
+                  }
+ 
+                break;
+                }
+      }
+    }  
+
+  }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
diff --git a/src/main/java/org/distorted/library/type/DynamicQuat.java b/src/main/java/org/distorted/library/type/DynamicQuat.java
new file mode 100644
index 0000000..2843b9f
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/DynamicQuat.java
@@ -0,0 +1,392 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+import java.util.Vector;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/** 
+* A 4-dimensional implementation of the Dynamic class to interpolate between a list
+* of Static4Ds.
+* Here, the Points are assumed to be Quaternions - thus we do the Spherical Linear Interpolation, aka
+* SLERP. Noise not supported (yet?).
+*/
+
+public class DynamicQuat extends Dynamic implements Data4D
+  {
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// omega, sinOmega, cosOmega - angle between pair of quaternions, its sinus and cosinus.
+//  
+// (vx,vy,vz,vw) is the original vector from vv (copied here so when interpolating we can see if it is 
+// still valid and if not - rebuild the Cache
+  
+  private class VectorCache
+    {
+    float omega, sinOmega,cosOmega;
+    float vx,vy,vz,vw;
+    }
+  
+  private Vector<VectorCache> vc;
+  private VectorCache tmp1, tmp2;
+
+  private Vector<Static4D> vv;
+  private Static4D curr, next;
+ 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//Abramowitz / Stegun
+
+  private static float arcCos(float x)
+    {
+    if( x<0 )
+      return 3.14159265358979f - (float)Math.sqrt(1+x)*(1.5707288f + 0.2121144f*x + 0.074261f*x*x + 0.0187293f*x*x*x);
+     
+    return (float)Math.sqrt(1-x)*(1.5707288f - 0.2121144f*x + 0.074261f*x*x - 0.0187293f*x*x*x);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Quaternion Dynamic doesn't support noise
+  
+  synchronized void createNoise()
+    {
+
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  
+  private void recomputeCache()
+    {  
+    if( numPoints>=2 )
+      {
+      int i, n;  
+     
+      for(i=0; i<numPoints; i++)
+        {
+        n = i<numPoints-1 ? i+1:0;  
+      
+        tmp1= vc.elementAt(i);
+        tmp2= vc.elementAt(n);
+        curr= vv.elementAt(i);
+        next= vv.elementAt(n);
+      
+        tmp1.vx = curr.x;
+        tmp1.vy = curr.y;
+        tmp1.vz = curr.z;
+        tmp1.vw = curr.w;
+    	
+        tmp1.cosOmega = curr.x*next.x + curr.y*next.y + curr.z*next.z + curr.w*next.w;
+      	
+        if( tmp1.cosOmega<0 && n!=0 )  // do not invert the last quaternion even if we'd have to go the long way around!
+          {
+          tmp1.cosOmega = -tmp1.cosOmega;
+          next.x = -next.x;
+          next.y = -next.y;
+          next.z = -next.z;
+          next.w = -next.w;
+          }
+      	
+        tmp1.sinOmega = (float)Math.sqrt(1-tmp1.cosOmega*tmp1.cosOmega);
+        tmp1.omega = arcCos(tmp1.cosOmega);
+        }
+      }
+   
+    cacheDirty = false;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Default constructor.
+ */
+  public DynamicQuat()
+    {
+    vv = new Vector<Static4D>();
+    vc = new Vector<VectorCache>();
+    numPoints = 0;
+    cacheDirty = false;
+    mMode = MODE_LOOP;
+    mDuration = 0;
+    mCount = 0.5f;
+    mNoise = 0.0f;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the location'th Static4D.
+ *   
+ * @param location the index of the Point we are interested in.
+ * @return The Static4D, if 0<=location&lt;getNumPoints(), or null otherwise.
+ */  
+  public synchronized Static4D getPoint(int location)
+    {
+    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the location'th Point.
+ * 
+ * @param location the index of the Point we are setting.
+ * @param x New value of its first float.
+ */
+  public synchronized void setPoint(int location, float x, float y, float z, float w)
+    {
+    if( location>=0 && location<numPoints )
+      {
+      curr = vv.elementAt(location);
+   
+      if( curr!=null )
+        {
+        curr.set(x,y,z,w);
+        cacheDirty=true;
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static4D to the end of our list of Points to interpolate through.
+ * <p>   
+ * Only a reference to the Point gets added to the List; this means that one can add a Point 
+ * here, and later on {@link Static4D#set(float,float,float,float)} it to some new value and
+ * the change will be seamlessly reflected in the interpolated path.  
+ * <p>
+ * A Point can be added multiple times.
+ *   
+ * @param v The Point to add.
+ */    
+  public synchronized void add(Static4D v)
+    {
+    if( v!=null )
+      {
+      vv.add(v);
+      
+      switch(numPoints)
+         {
+         case 0: 
+         case 1: vc.add(new VectorCache());
+                 vc.add(new VectorCache());
+        	     break;
+         default:vc.add(new VectorCache());
+         }
+
+       numPoints++;
+       cacheDirty = true;
+       }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Adds a new Static4D to the location'th place in our List of Points to interpolate through.
+ *   
+ * @param location Index in our List to add the new Point at.
+ * @param v The Static4D to add.
+ */  
+  public synchronized void add(int location, Static4D v)
+    {
+    if( v!=null )
+      {
+      vv.add(location, v);
+      
+      switch(numPoints)
+        {
+        case 0: 
+        case 1: vc.add(new VectorCache());
+                vc.add(new VectorCache());
+                break;
+        default:vc.add(location,new VectorCache());
+        }
+
+      numPoints++;
+      cacheDirty = true;
+      }
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all occurrences of Point v from the List of Points to interpolate through.  
+ * 
+ * @param v The Point to remove.
+ * @return <code>true</code> if we have removed at least one Point.
+ */
+  public synchronized boolean remove(Static4D v)
+    {
+    int n = vv.indexOf(v);
+    boolean found = false;
+   
+    while( n>=0 ) 
+      {
+      vv.remove(n);
+     
+      switch(numPoints)
+        {
+        case 0:
+        case 1: break;
+        case 2: vc.removeAllElements();
+                break;
+        default:vc.remove(n);
+        }
+
+      numPoints--;
+      found = true;
+      n = vv.indexOf(v);
+      }
+   
+    if( found ) 
+      {
+      cacheDirty=true;
+      }
+   
+    return found;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes a location'th Point from the List of Points we interpolate through.
+ * 
+ * @param location index of the Point we want to remove. 
+ * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
+ */
+  public synchronized boolean remove(int location)
+    {
+    if( location>=0 && location<numPoints ) 
+      {
+      vv.removeElementAt(location);
+      
+      switch(numPoints)
+        {
+        case 0: 
+        case 1: break;
+        case 2: vc.removeAllElements();
+                break;
+        default:vc.removeElementAt(location);
+        }
+
+      numPoints--;
+      cacheDirty = true; 
+      return true;
+      }
+
+    return false;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Removes all Points.
+ */
+  public synchronized void removeAll()
+    {
+    numPoints = 0;
+    vv.removeAllElements();
+    vc.removeAllElements();
+    cacheDirty = false;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
+ * Interpolation is done using the spherical linear algorithm, aka SLERP.
+ * <p>
+ * Since this is a 4-dimensional Dynamic, the resulting interpolated Static4D gets written
+ * to four locations in the buffer: buffer[offset], buffer[offset+1], buffer[offset+2] and buffer[offset+3]. 
+ * 
+ * @param buffer Float buffer we will write the resulting Static4D to.
+ * @param offset Offset in the buffer where to write the result.
+ * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
+ *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
+ */    
+  public synchronized void interpolate(float[] buffer, int offset, float time)
+    {  
+    switch(numPoints)
+      {
+      case 0: buffer[offset  ] = 0.0f;
+              buffer[offset+1] = 0.0f;
+              buffer[offset+2] = 0.0f;
+              buffer[offset+3] = 0.0f;
+              break;
+      case 1: curr = vv.elementAt(0);
+              buffer[offset  ] = curr.x; 
+              buffer[offset+1] = curr.y;
+              buffer[offset+2] = curr.z;
+              buffer[offset+3] = curr.w;
+              break;
+      default:float t = time;
+              float scale0, scale1;
+  
+              if( mMode==MODE_JUMP ) time = time*(numPoints-1);
+              else if( mMode==MODE_PATH || numPoints==2 ) time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
+              else time = time*numPoints;
+              
+              int vecNext, vecCurr = (int)time;
+              time = time-vecCurr;
+      
+              if( vecCurr>=0 && vecCurr<numPoints )
+                {
+                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
+                   
+                switch(mMode)
+                  {
+                  case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
+                                  break;
+                  case MODE_PATH: if( t<0.5f ) vecNext = vecCurr+1;  
+                                  else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
+                                  break;
+                  case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
+                                  break;
+                  default       : vecNext = 0;                
+                  }
+     
+                curr = vv.elementAt(vecCurr);
+                next = vv.elementAt(vecNext);
+                tmp1 = vc.elementAt(vecCurr);
+                tmp2 = vc.elementAt(vecNext);
+              
+                if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z || tmp2.vw!=next.w ) recomputeCache();
+               
+                if( tmp1.sinOmega==0 )
+                  {
+                  scale0 = 0f;
+                  scale1 = 1f;
+                  }
+                else if( tmp1.cosOmega < 0.99 ) 
+                  {
+                  scale0 = (float)Math.sin( (1f-time)*tmp1.omega ) / tmp1.sinOmega;
+                  scale1 = (float)Math.sin(     time *tmp1.omega ) / tmp1.sinOmega;
+                  }
+                else 
+                  {
+                  scale0 = 1f-time;
+                  scale1 = time;
+                  }
+
+                buffer[offset  ] = scale0*curr.x + scale1*next.x;
+                buffer[offset+1] = scale0*curr.y + scale1*next.y; 
+                buffer[offset+2] = scale0*curr.z + scale1*next.z; 
+                buffer[offset+3] = scale0*curr.w + scale1*next.w; 
+                
+                break;
+                }
+      }
+    }  
+
+  }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
diff --git a/src/main/java/org/distorted/library/type/Float1D.java b/src/main/java/org/distorted/library/type/Float1D.java
deleted file mode 100644
index 1cd6fcc..0000000
--- a/src/main/java/org/distorted/library/type/Float1D.java
+++ /dev/null
@@ -1,90 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A 1-dimensional data structure containing a single float. The float has no particular meaning; 
- * when this data structure is used in Interpolators, we can think of it as a 1-dimensional Point 
- * a few of which the Interpolator interpolates between.
- */
-
-public class Float1D 
-  {
-  float x;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the single float to ox.   
- *   
- * @param ox value of the single float.
- */
-  public Float1D(int ox)
-    {
-    x = ox;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the single float to ox.   
- *   
- * @param ox value of the single float.
- */  
-  public Float1D(float ox)
-    {
-    x = ox;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the single float.
- * 
- * @param ox new value of the single float.
- */
-  public void set(int ox)
-    {
-    x = ox;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the single float.
- * 
- * @param ox new value of the single float.
- */
-  public void set(float ox)
-    {
-    x = ox;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the float contained.
- * 
- * @return The single float.
- */
-  public float getX()
-    {
-    return x;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// end of class   
-  }
diff --git a/src/main/java/org/distorted/library/type/Float2D.java b/src/main/java/org/distorted/library/type/Float2D.java
deleted file mode 100644
index b734a94..0000000
--- a/src/main/java/org/distorted/library/type/Float2D.java
+++ /dev/null
@@ -1,98 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A 2-dimensional data structure containing two floats. The floats have no particular meaning; 
- * when this data structure is used in Interpolators, we can think of it as a 2-dimensional Point 
- * a few of which the Interpolator interpolates between.
- */
-
-public class Float2D extends Float1D
-  {
-  float y;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the two floats to (ox,oy).   
- *   
- * @param ox value of the first float.
- * @param oy value of the second float.
- */  
-  public Float2D(int ox, int oy)
-    {
-    super(ox);
-    y = oy;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the two floats to (ox,oy).   
- *   
- * @param ox value of the first float.
- * @param oy value of the second float.
- */    
-  public Float2D(float ox, float oy)
-    {
-    super(ox);
-    y = oy;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (ox,oy).
- * 
- * @param ox new value of the first float
- * @param oy new value of the second float
- */
-  public void set(int ox, int oy)
-    {
-    x = ox;
-    y = oy;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (ox,oy).
- * 
- * @param ox new value of the first float
- * @param oy new value of the seond float
- */
-  public void set(float ox, float oy)
-    {
-    x = ox;
-    y = oy;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the second float contained.
- * 
- * @return The second float.
- */
-  public float getY()
-    {
-    return y;  
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// end of class   
-  }
diff --git a/src/main/java/org/distorted/library/type/Float3D.java b/src/main/java/org/distorted/library/type/Float3D.java
deleted file mode 100644
index 11d17cd..0000000
--- a/src/main/java/org/distorted/library/type/Float3D.java
+++ /dev/null
@@ -1,104 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A 3-dimensional data structure containing three floats. The floats have no particular meaning; 
- * when this data structure is used in Interpolators, we can think of it as a 3-dimensional Point 
- * a few of which the Interpolator interpolates between.
- */
-
-public class Float3D extends Float2D 
-  {
-  float z;
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the three floats to (vx,vy,vz).   
- *   
- * @param vx value of the first float.
- * @param vy value of the second float.
- * @param vz value of the third float.
- */ 
-  public Float3D(int vx, int vy, int vz)
-    {
-    super(vx,vy);
-    z = vz;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the three floats to (vx,vy,vz).   
- *   
- * @param vx value of the first float.
- * @param vy value of the second float.
- * @param vz value of the third float.
- */ 
-  public Float3D(float vx, float vy, float vz)
-    {
-    super(vx,vy);
-    z = vz;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (vx,vy,vz).
- * 
- * @param vx new value of the first float
- * @param vy new value of the second float
- * @param vz new value of the third float
- */
-  public void set(int vx, int vy, int vz)
-    {
-    x = vx;
-    y = vy;
-    z = vz;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (vx,vy,vz).
- * 
- * @param vx new value of the first float
- * @param vy new value of the second float
- * @param vz new value of the third float
- */
-  public void set(float vx, float vy, float vz)
-    {
-    x = vx;
-    y = vy;
-    z = vz;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the third float contained.
- * 
- * @return The third float.
- */
-  public float getZ()
-    {
-    return z;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// end of class   
-  }
diff --git a/src/main/java/org/distorted/library/type/Float4D.java b/src/main/java/org/distorted/library/type/Float4D.java
deleted file mode 100644
index e093c03..0000000
--- a/src/main/java/org/distorted/library/type/Float4D.java
+++ /dev/null
@@ -1,110 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A 4-dimensional data structure containing four floats. The floats have no particular meaning; 
- * when this data structure is used in Interpolators, we can think of it as a 4-dimensional Point 
- * a few of which the Interpolator interpolates between.
- */
-
-public class Float4D extends Float3D 
-  {
-  float w;
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the four floats to (vx,vy,vz,vw).   
- *   
- * @param vx value of the first float.
- * @param vy value of the second float.
- * @param vz value of the third float.
- * @param vw value of the fourth float.
- */ 
-  public Float4D(int vx, int vy, int vz, int vw)
-    {
-    super(vx,vy,vz);
-    w = vw;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the four floats to (vx,vy,vz,vw).   
- *   
- * @param vx value of the first float.
- * @param vy value of the second float.
- * @param vz value of the third float.
- * @param vw value of the fourth float.
- */ 
-  public Float4D(float vx, float vy, float vz, float vw)
-    {
-    super(vx,vy,vz);
-    w = vw;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (vx,vy,vz,vw).
- * 
- * @param vx new value of the first float
- * @param vy new value of the second float
- * @param vz new value of the third float
- * @param vw new value of the fourth float
- */
-  public void set(int vx, int vy, int vz, int vw)
-    {
-    x = vx;
-    y = vy;
-    z = vz;
-    w = vw;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (vx,vy,vz,vw).
- * 
- * @param vx new value of the first float
- * @param vy new value of the second float
- * @param vz new value of the third float
- * @param vw new value of the fourth float
- */
-  public void set(float vx, float vy, float vz, float vw)
-    {
-    x = vx;
-    y = vy;
-    z = vz;
-    w = vw;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the fourth float contained.
- * 
- * @return The fourth float.
- */
-  public float getW()
-    {
-    return w;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// end of class   
-  }
diff --git a/src/main/java/org/distorted/library/type/Interpolator.java b/src/main/java/org/distorted/library/type/Interpolator.java
deleted file mode 100644
index cb26814..0000000
--- a/src/main/java/org/distorted/library/type/Interpolator.java
+++ /dev/null
@@ -1,229 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-import java.util.Random;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** A class to interpolate between a List of Float{1,2,3,4}Ds.
-* <p><ul>
-* <li>if there is only one Point, just jump to it.
-* <li>if there are two Points, linearly bounce between them
-* <li>if there are more, interpolate a loop (or a path!) between them.
-* </ul>
-*/
-
-// The way Interpolation between more than 2 Points is done:
-// 
-// Def: let w[i] = (w[i](x), w[i](y), w[i](z)) be the direction and speed we have to be flying at Point P[i]
-//
-// time it takes to fly though one segment v[i] --> v[i+1] : 0.0 --> 1.0
-// w[i] should be parallel to v[i+1] - v[i-1]   (cyclic notation)
-// |w[i]| proportional to | P[i]-P[i+1] |
-//
-// Given that the flight route (X(t), Y(t), Z(t)) from P(i) to P(i+1)  (0<=t<=1) has to satisfy
-// X(0) = P[i  ](x), Y(0)=P[i  ](y), Z(0)=P[i  ](z), X'(0) = w[i  ](x), Y'(0) = w[i  ](y), Z'(0) = w[i  ](z)
-// X(1) = P[i+1](x), Y(1)=P[i+1](y), Z(1)=P[i+1](z), X'(1) = w[i+1](x), Y'(1) = w[i+1](y), Z'(1) = w[i+1](z)
-//
-// we have the solution:  X(t) = at^3 + bt^2 + ct + d where
-// a =  2*P[i](x) +   w[i](x) - 2*P[i+1](x) + w[i+1](x)
-// b = -3*P[i](x) - 2*w[i](x) + 3*P[i+1](x) - w[i+1](x)
-// c = w[i](x)<br>
-// d = P[i](x)
-//
-// and similarly Y(t) and Z(t).
-
-public abstract class Interpolator 
-  {
-  /**
-   * One revolution takes us from the first vector to the last and back to first through the shortest path. 
-   */
-  public static final int MODE_LOOP = 0; 
-  /**
-   * We come back from the last to the first vector through the same way we got there.
-   */
-  public static final int MODE_PATH = 1; 
-  /**
-   * We just jump back from the last point to the first.
-   */
-  public static final int MODE_JUMP = 2; 
- 
-  protected static Random mRnd = new Random();
-  
-  protected static final int NUM_NOISE = 5; // used iff mNoise>0.0. Number of intermediary points between each pair of adjacent vectors
-                                            // where we randomize noise factors to make the way between the two vectors not so smooth.
-  protected int numPoints;
-  protected int mVecCurr;    
-  protected boolean cacheDirty; // VectorCache not up to date
-  protected int mMode;          // LOOP, PATH or JUMP
-  protected long mDuration;     // number of miliseconds it takes to do a full loop/path from first vector to the last and back to the first 
-  protected float mCount;       // number of loops/paths we will do; mCount = 1.5 means we go from the first vector to the last, back to first, and to the last again. 
-  protected float mNoise;       // how 'smooth' our path form each vector to the next is. mNoise = 0.0 (min) --> completely smooth; mNoise==1.0 (max) --> very uneven
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// hide this from Javadoc
-  
-  Interpolator()
-    {
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  public void interpolateMain(float[] buffer, int offset, long currentDuration)
-    {
-    if( mDuration<=0.0f ) 
-      {
-      interpolate(buffer,offset,mCount-(int)mCount);  
-      }
-    else
-      {
-      float x = (float)currentDuration/mDuration;
-           
-      if( x<=mCount || mCount<=0.0f )
-        {
-        interpolate(buffer,offset,x-(int)x);
-        }
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public boolean interpolateMain(float[] buffer, int offset, long currentDuration, long step)
-    {
-    if( mDuration<=0.0f ) 
-      {
-      interpolate(buffer,offset,mCount-(int)mCount);
-      return false;
-      }
-     
-    float x = (float)currentDuration/mDuration;
-           
-    if( x<=mCount || mCount<=0.0f )
-      {
-      interpolate(buffer,offset,x-(int)x);
-        
-      if( currentDuration+step > mDuration*mCount && mCount>0.0f )
-        {
-        interpolate(buffer,offset,mCount-(int)mCount);
-        return true;
-        }
-      }
-    
-    return false;
-    }
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// internal debugging only!
-  
-  public String print()
-    {
-    return "duration="+mDuration+" count="+mCount+" Noise="+mNoise+" numVectors="+numPoints+" mMode="+mMode;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  abstract void interpolate(float[] buffer, int offset, float time);
-  abstract void createNoise();
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Sets the mode of the interpolation to Loop, Path or Jump.
- * <ul>
- * <li>Loop is when we go from the first point all the way to the last, and the back to the first through 
- * the shortest way.
- * <li>Path is when we come back from the last point back to the first the same way we got there.
- * <li>Jump is when we go from first to last and then jump back to the first.
- * </ul>
- * 
- * @param mode {@link Interpolator#MODE_LOOP}, {@link Interpolator#MODE_PATH} or {@link Interpolator#MODE_JUMP}.
- */
-
-  public void setMode(int mode)
-    {
-    mMode = mode;  
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the number of Float{1,2,3,4}Ds this Interpolator has been fed with.
- *   
- * @return the number of Float{1,2,3,4}Ds we are currently interpolating through.
- */
-  public synchronized int getNumPoints()
-    {
-    return numPoints;  
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Controls how many times we want to interpolate.
- * <p>
- * Count equal to 1 means 'go from the first Float{1,2,3,4}D to the last and back'. Does not have to be an
- * integer - i.e. count=1.5 would mean 'start at the first Point, go to the last, come back to the first, 
- * go to the last again and stop'.
- * Count<=0 means 'go on interpolating indefinitely'.
- * 
- * @param count the number of times we want to interpolate between our collection of Float{1,2,3,4}Ds.
- */
-  public void setCount(float count)
-    {
-    mCount = count;  
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Sets the time it takes to do one full interpolation.
- * 
- * @param duration Time, in milliseconds, it takes to do one full interpolation, i.e. go from the first 
- *                 Point to the last and back. 
- */
-  
-  public void setDuration(long duration)
-    {
-    mDuration = duration;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Sets the 'smoothness' of interpolation. 
- * <p>
- * When Noise=0 (the default), we interpolate between our Points through the most smooth path possible. 
- * Increasing noise makes the Interpolator increasingly deviate from this path, pseudo-randomly speeding 
- * up and slowing down, etc.
- * 
- * @param noise The noise level. Permitted range: 0 <= noise <= 1.
- */
-  
-  public void setNoise(float noise)
-    {
-    if( mNoise==0.0f && noise != 0.0f )  
-      createNoise();
-   
-    if( mNoise<0.0f ) mNoise = 0.0f;
-    if( mNoise>1.0f ) mNoise = 1.0f;
-   
-    mNoise = noise;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// end of DistortedInterpolator
-  }
diff --git a/src/main/java/org/distorted/library/type/Interpolator1D.java b/src/main/java/org/distorted/library/type/Interpolator1D.java
deleted file mode 100644
index ae4ed62..0000000
--- a/src/main/java/org/distorted/library/type/Interpolator1D.java
+++ /dev/null
@@ -1,499 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-import java.util.Vector;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 1-dimensional implementation of the Interpolator class to interpolate between a list 
-* of Float1Ds.
-*/
-
-public class Interpolator1D extends Interpolator 
-  {
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// the coefficients of the X(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
-// (x) is the vector tangent to the path.
-// (vx) is the original vector from vv (copied here so when interpolating we can see if it is 
-// still valid and if not - rebuild the Cache
-   
-  private class VectorCache
-    {
-    float ax, bx, cx, dx;
-   
-    float x;
-    float vx;
-    }
-  
-  private class VectorNoise
-    {
-    float[] nx;
-   
-    public VectorNoise()
-      {
-      nx = new float[NUM_NOISE]; 
-      nx[0] = mRnd.nextFloat();
-      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1]+mRnd.nextFloat();
-      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
-      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
-      }
-    }
-  
-  private Vector<VectorCache> vc;
-  private VectorCache tmp1, tmp2;
- 
-  private Vector<Float1D> vv;
-  private Float1D prev, curr, next;
- 
-  private Vector<VectorNoise> vn;
-  private VectorNoise tmpN;
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  synchronized void createNoise()
-    {
-    if( vn==null )
-      {
-      vn = new Vector<VectorNoise>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void vec(int c)
-    {
-    int p = c>0 ? c-1: numPoints-1;
-    int n = c<numPoints-1 ? c+1: 0;
-    
-    prev = vv.elementAt(p);
-    curr = vv.elementAt(c);
-    next = vv.elementAt(n);
-
-    tmp1 = vc.elementAt(c);
-    
-    float px = curr.x - prev.x;
-    float nx = next.x - curr.x;
-     
-    float d = nx*nx;
-    
-    if( d>0 )
-      {
-      float q = (float)Math.sqrt((px*px)/d);
-      
-      if( q>1 )
-        {
-        tmp1.x = nx+px/q;
-        }
-      else
-        {
-        tmp1.x = px+nx*q;
-        }
-      }
-    else
-      {
-      tmp1.x = 0.0f;
-      }
-    }
-      
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmp1= vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      tmp1.ax = 0.0f;
-      tmp1.bx = 0.0f;
-      tmp1.cx = curr.x;
-      tmp1.dx = 0.0f;
-      }
-    else if( numPoints==2 )
-      {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-          
-      tmp1.ax = 0.0f;
-      tmp1.bx = 0.0f;
-      tmp1.cx = next.x - curr.x;
-      tmp1.dx = curr.x;
-      
-      tmp2.ax = 0.0f;
-      tmp2.bx = 0.0f;
-      tmp2.cx = curr.x - next.x;
-      tmp2.dx = next.x;
-      }
-    else
-      {
-      int i, n;  
-         
-      for(i=0; i<numPoints; i++) vec(i);
-   
-      for(i=0; i<numPoints; i++)
-        {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-    
-        tmp1.vx = curr.x;
-        
-        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
-        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
-        tmp1.cx = tmp1.x;
-        tmp1.dx = curr.x;
-        }
-      }
-   
-    cacheDirty = false;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float noise(float time,int vecNum)
-    {
-    float lower, upper, len;  
-    float d = time*(NUM_NOISE+1);
-    int index = (int)d;
-    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
-    tmpN = vn.elementAt(vecNum);
-   
-    if( index==0 )
-      {
-      len = 1.0f/(NUM_NOISE+1);  
-      return (len + mNoise*(tmpN.nx[0]-len))*d;
-      }
-    if( index==NUM_NOISE )
-      {
-      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
-      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);   
-      return (1.0f-lower)*(d-NUM_NOISE) + lower;   
-      }
-   
-    len = ((float)index)/(NUM_NOISE+1);
-    lower = len + mNoise*(tmpN.nx[index-1]-len);   
-    len = ((float)index+1)/(NUM_NOISE+1); 
-    upper = len + mNoise*(tmpN.nx[index  ]-len);
-            
-    return (upper-lower)*(d-index) + lower; 
-    }
-   
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Interpolator1D()
-    {
-    vv = new Vector<Float1D>();
-    vc = new Vector<VectorCache>();
-    vn = null;
-    numPoints = 0;
-    cacheDirty = false;
-    mMode = MODE_LOOP;
-    mDuration = 0;
-    mCount = 0.5f;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the location'th Float1D. 
- *   
- * @param location the index of the Point we are interested in.
- * @return The Float1D, if 0<=location&lt;getNumPoints(), or null otherwise. 
- */
-  public synchronized Float1D getPoint(int location)
-    {
-    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the location'th Point.
- * 
- * @param location the index of the Point we are setting.
- * @param x New value of its first float.
- */
-  public synchronized void setPoint(int location, float x)
-    {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
-        {
-        curr.set(x);
-        cacheDirty=true;
-        }
-      }
-    }
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float1D to the end of our list of Points to interpolate through.
- * <p>   
- * Only a reference to the Point gets added to the List; this means that one can add a Point 
- * here, and later on {@link Float1D#set(float)} it to some new value and the change will
- * be seamlessly reflected in the interpolated path.  
- * <p>
- * A Point can be added multiple times.
- *   
- * @param v The Point to add.
- */
-  public synchronized void add(Float1D v)
-    {
-    if( v!=null )
-      {
-      vv.add(v);
-     
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
-        {
-        case 0: 
-        case 1: break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                cacheDirty = true;
-                break;
-        default:vc.add(new VectorCache());
-                cacheDirty = true;
-        }
-     
-      numPoints++;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float1D to the location'th place in our List of Points to interpolate through.  
- *   
- * @param location Index in our List to add the new Point at.
- * @param v The Point to add.
- */
-  public synchronized void add(int location, Float1D v)
-    {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-             
-      switch(numPoints)
-        {
-        case 0:
-        case 1: break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                cacheDirty = true;
-                break;
-        default:vc.add(location,new VectorCache());
-                cacheDirty = true;
-        }
-      
-      numPoints++;
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all occurrences of Point v from the List of Points to interpolate through.  
- * 
- * @param v The Point to remove.
- * @return <code>true</code> if we have removed at least one Point.
- */
-  public synchronized boolean remove(Float1D v)
-    {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
-        {
-        case 0:
-        case 1:
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.remove(n);
-                cacheDirty=true;
-        }
-
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    return found;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes a location'th Point from the List of Points we interpolate through.
- * 
- * @param location index of the Point we want to remove. 
- * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
- */
-  public synchronized boolean remove(int location)
-    {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-      
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.removeElementAt(location);
-        }
-
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-   return false;
-   }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
-    {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
-    }
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
- * <p>
- * Since this is a 1-dimensional Interpolator, the resulting interpolated Float1D gets written
- * to a single location in the buffer: buffer[offset]. 
- * 
- * @param buffer Float buffer we will write the resulting Float1D to.
- * @param offset Offset in the buffer where to write the result.
- * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
- *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
- */
-  public synchronized void interpolate(float[] buffer, int offset, float time)
-    {
-    switch(numPoints)
-      {
-      case 0: buffer[offset] = 0.0f;
-              break;
-      case 1: curr = vv.elementAt(0);
-              buffer[offset] = curr.x;
-              break;
-      case 2: curr = vv.elementAt(0);
-              next = vv.elementAt(1);
-             
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-             
-              if( vn!=null )
-                {
-                time = noise(time,0);
-                }
-             
-              buffer[offset] = (next.x-curr.x)*time + curr.x;
-              break;
-      default:float t = time;
-            
-              switch(mMode)
-                {
-                case MODE_LOOP: time = time*numPoints;
-                                break;
-                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
-                                break;
-                case MODE_JUMP: time = time*(numPoints-1);
-                                break;
-                }
-      
-              int vecCurr = (int)time;
-              time = time-vecCurr;
-      
-              if( vecCurr>=0 && vecCurr<numPoints )
-                {
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mVecCurr!= vecCurr )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext;   
-                  mVecCurr = vecCurr;
-                                
-                  switch(mMode)
-                    {
-                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
-                                    break;
-                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
-                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
-                                    break;
-                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
-                                    break;
-                    default       : vecNext = 0;                
-                    }
-              
-                  next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
-              
-                  if( tmp2.vx!=next.x ) recomputeCache();
-                  }
-             
-                if( vn!=null )
-                  {
-                  time = noise(time,vecCurr);
-                  }
-            
-                tmp1 = vc.elementAt(vecCurr);
-                buffer[offset] = ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
-                break;
-                }
-        }
-     }  
-  
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
diff --git a/src/main/java/org/distorted/library/type/Interpolator2D.java b/src/main/java/org/distorted/library/type/Interpolator2D.java
deleted file mode 100644
index df8ddb6..0000000
--- a/src/main/java/org/distorted/library/type/Interpolator2D.java
+++ /dev/null
@@ -1,551 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-import java.util.Vector;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 2-dimensional implementation of the Interpolator class to interpolate between a list 
-* of Float2Ds.
-*/
-
-public class Interpolator2D extends Interpolator 
-  {
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// the coefficients of the X(t), Y(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
-// (x,y) is the vector tangent to the path.
-// (vx,vy) is the original vector from vv (copied here so when interpolating we can see if it is 
-// still valid and if not - rebuild the Cache
-  
-  private class VectorCache
-    {
-    float ax, bx, cx, dx;
-    float ay, by, cy, dy;
-   
-    float x,y;
-    float vx,vy;
-    }
-  
-  private class VectorNoise
-    {    
-    float[] nx;
-    float[] ny;
-   
-    public VectorNoise()
-      {
-      nx = new float[NUM_NOISE]; 
-      nx[0] = mRnd.nextFloat();
-      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1]+mRnd.nextFloat();
-      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
-      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
-     
-      ny = new float[NUM_NOISE];
-      for(int i=0; i<NUM_NOISE; i++) ny[i] = mRnd.nextFloat()-0.5f;
-      }
-    }
-    
-  private Vector<VectorCache> vc;
-  private VectorCache tmp1, tmp2;
-   
-  private Vector<Float2D> vv;
-  private Float2D prev, curr, next;
- 
-  private Vector<VectorNoise> vn;
-  private VectorNoise tmpN;
-  
-  private float mFactor;
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  synchronized void createNoise()
-    {
-    if( vn==null )
-      {
-      vn = new Vector<VectorNoise>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-      }
-    }
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void vec(int c)
-    {
-    int p = c>0 ? c-1: numPoints-1;
-    int n = c<numPoints-1 ? c+1: 0;
-    
-    prev = vv.elementAt(p);
-    curr = vv.elementAt(c);
-    next = vv.elementAt(n);
-
-    tmp1 = vc.elementAt(c);
-    
-    float px = curr.x - prev.x;
-    float py = curr.y - prev.y;
-    float nx = next.x - curr.x;
-    float ny = next.y - curr.y;
-     
-    float d = nx*nx+ny*ny;
-    
-    if( d>0 )
-      {
-      float q = (float)Math.sqrt((px*px+py*py)/d);
-      
-      if( q>1 )
-        {
-        tmp1.x = nx+px/q;
-        tmp1.y = ny+py/q;
-        }
-      else
-        {
-        tmp1.x = px+nx*q;
-        tmp1.y = py+ny*q;
-        }
-      }
-    else
-      {
-      tmp1.x = 0.0f;
-      tmp1.y = 0.0f;
-      }
-    }
-   
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmp1= vc.elementAt(0);
-      curr= vv.elementAt(0);
-              
-      tmp1.ax = tmp1.ay = 0.0f;
-      tmp1.bx = tmp1.by = 0.0f;
-      tmp1.cx = curr.x;
-      tmp1.cy = curr.y;
-      tmp1.dx = tmp1.dy = 0.0f;
-      }
-    else if( numPoints==2 )
-      {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-          
-      tmp1.ax = tmp1.ay = 0.0f;
-      tmp1.bx = tmp1.by = 0.0f;
-      tmp1.cx = next.x - curr.x;
-      tmp1.cy = next.y - curr.y;
-      tmp1.dx = curr.x;
-      tmp1.dy = curr.y;
-      
-      tmp2.ax = tmp2.ay = 0.0f;
-      tmp2.bx = tmp2.by = 0.0f;
-      tmp2.cx = curr.x - next.x;
-      tmp2.cy = curr.y - next.y;
-      tmp2.dx = next.x;
-      tmp2.dy = next.y;
-      }
-    else
-      {
-      int i, n;  
-         
-      for(i=0; i<numPoints; i++) vec(i);
-   
-      for(i=0; i<numPoints; i++)
-        {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        tmp1.vx = curr.x;
-        tmp1.vy = curr.y;
-        
-        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
-        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
-        tmp1.cx = tmp1.x;
-        tmp1.dx = curr.x;
-      
-        tmp1.ay =  2*curr.y +   tmp1.y - 2*next.y + tmp2.y;
-        tmp1.by = -3*curr.y - 2*tmp1.y + 3*next.y - tmp2.y;
-        tmp1.cy = tmp1.y;
-        tmp1.dy = curr.y;
-        }
-      }
-    
-    cacheDirty = false;
-    }
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float noise(float time,int vecNum)
-    {
-    float lower, upper, len;  
-    float d = time*(NUM_NOISE+1);
-    int index = (int)d;
-    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
-    tmpN = vn.elementAt(vecNum);
-   
-    float x = d-index;
-    x = x*x*(3-2*x);
-   
-    switch(index)
-      {
-      case 0        : mFactor = mNoise*tmpN.ny[0]*x;  
-                      return time + mNoise*(d*tmpN.nx[0]-time);                
-      case NUM_NOISE: mFactor= mNoise*tmpN.ny[NUM_NOISE-1]*(1-x);
-                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
-                      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);  
-                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
-      default       : float yb = tmpN.ny[index  ];
-                      float ya = tmpN.ny[index-1];
-                      mFactor  = mNoise*((yb-ya)*x+ya);
-   
-                      len = ((float)index)/(NUM_NOISE+1);
-                      lower = len + mNoise*(tmpN.nx[index-1]-len);   
-                      len = ((float)index+1)/(NUM_NOISE+1); 
-                      upper = len + mNoise*(tmpN.nx[index  ]-len);
-            
-                      return (upper-lower)*(d-index) + lower; 
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Interpolator2D()
-    {
-    vv = new Vector<Float2D>();
-    vc = new Vector<VectorCache>();
-    vn = null;
-    numPoints = 0;
-    cacheDirty = false;
-    mMode = MODE_LOOP;
-    mDuration = 0;
-    mCount = 0.5f;
-    mNoise = 0.0f;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the location'th Float2D. 
- *   
- * @param location the index of the Point we are interested in.
- * @return The Float2D, if 0<=location&lt;getNumPoints(), or null otherwise. 
- */  
-  public synchronized Float2D getPoint(int location)
-    {
-    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the location'th Point.
- * 
- * @param location the index of the Point we are setting.
- * @param x New value of its first float.
- */
-  public synchronized void setPoint(int location, float x, float y)
-    {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
-        {
-        curr.set(x,y);
-        cacheDirty=true;
-        }
-      }
-    }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float2D to the end of our list of Points to interpolate through.
- * <p>   
- * Only a reference to the Point gets added to the List; this means that one can add a Point 
- * here, and later on {@link Float2D#set(float,float)} it to some new value and the change 
- * will be seamlessly reflected in the interpolated path.  
- * <p>
- * A Point can be added multiple times.
- *   
- * @param v The Point to add.
- */  
-  public synchronized void add(Float2D v)
-    {
-    if( v!=null )
-      {
-      vv.add(v);
-     
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
-        {
-        case 0:
-        case 1: break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(new VectorCache());
-        }
-     
-      numPoints++;
-      cacheDirty = true;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float2D to the location'th place in our List of Points to interpolate through.  
- *   
- * @param location Index in our List to add the new Point at.
- * @param v The Point to add.
- */  
-  public synchronized void add(int location, Float2D v)
-    {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
-        {
-        case 0:
-        case 1: break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
-        }
-      
-      numPoints++;
-      cacheDirty = true;
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all occurrences of Point v from the List of Points to interpolate through.  
- * 
- * @param v The Point to remove.
- * @return <code>true</code> if we have removed at least one Point.
- */
-  public synchronized boolean remove(Float2D v)
-    {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.remove(n);
-        }
-     
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes a location'th Point from the List of Points we interpolate through.
- * 
- * @param location index of the Point we want to remove. 
- * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
- */
-  public synchronized boolean remove(int location)
-    {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-      
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.removeElementAt(location);
-        }
-
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-   return false;
-   }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
-    {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
- * <p>
- * Since this is a 2-dimensional Interpolator, the resulting interpolated Float2D gets written
- * to two locations in the buffer: buffer[offset] and buffer[offset+1]. 
- * 
- * @param buffer Float buffer we will write the resulting Float2D to.
- * @param offset Offset in the buffer where to write the result.
- * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
- *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
- */  
-  public synchronized void interpolate(float[] buffer, int offset, float time)
-    {
-    switch(numPoints)
-      {
-      case 0: buffer[offset  ] = 0.0f;
-              buffer[offset+1] = 0.0f;
-              break;
-      case 1: curr = vv.elementAt(0);
-              buffer[offset  ] = curr.x;
-              buffer[offset+1] = curr.y;
-              break;
-      case 2: curr = vv.elementAt(0);
-              next = vv.elementAt(1);
-               
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-             
-              if( vn!=null )
-                {
-                time = noise(time,0);
-              
-                float dx2 = next.x-curr.x;
-                float dy2 = next.y-curr.y;
-   
-                buffer[offset  ] = dx2*time + curr.x +dy2*mFactor;
-                buffer[offset+1] = dy2*time + curr.y -dx2*mFactor;
-                }
-              else
-                {
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
-                }
-              
-              break;
-      default:float t = time;
-        
-              switch(mMode)
-                {
-                case MODE_LOOP: time = time*numPoints;
-                                break;
-                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
-                                break;
-                case MODE_JUMP: time = time*(numPoints-1);
-                                break;
-                }
-            
-              int vecCurr = (int)time;
-              time = time-vecCurr;
-      
-              if( vecCurr>=0 && vecCurr<numPoints )
-                { 
-                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
-                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext;   
-                  mVecCurr = vecCurr;
-                                
-                  switch(mMode)
-                    {
-                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
-                                    break;
-                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
-                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
-                                    break;
-                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
-                                    break;
-                    default       : vecNext = 0;                
-                    }
-              
-                  next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
-              
-                  if( tmp2.vx!=next.x || tmp2.vy!=next.y ) recomputeCache();
-                  }
-              
-                if( vn!=null )
-                  {
-                  time = noise(time,vecCurr);
-                  tmp1 = vc.elementAt(vecCurr);
-               
-                  float dx2 = (3*tmp1.ax*time+2*tmp1.bx)*time + tmp1.cx;
-                  float dy2 = (3*tmp1.ay*time+2*tmp1.by)*time + tmp1.cy;
-                 
-                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx +dy2*mFactor;
-                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy -dx2*mFactor;
-                  } 
-                else
-                  {
-                  tmp1 = vc.elementAt(vecCurr);
-                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
-                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy;
-                  }
-                
-                break;
-                }
-      }
-    }  
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
diff --git a/src/main/java/org/distorted/library/type/Interpolator3D.java b/src/main/java/org/distorted/library/type/Interpolator3D.java
deleted file mode 100644
index 4fa1286..0000000
--- a/src/main/java/org/distorted/library/type/Interpolator3D.java
+++ /dev/null
@@ -1,669 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-import java.util.Vector;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 3-dimensional implementation of the Interpolator class to interpolate between a list 
-* of Float3Ds.
-*/
-
-public class Interpolator3D extends Interpolator 
-  {
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// the coefficients of the X(t), Y(t) and Z(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
-// (x,y,z) is the vector tangent to the path.
-// (vx,vy,vz) is the original vector from vv (copied here so when interpolating we can see if it is 
-// still valid and if not - rebuild the Cache
-  
-  private class VectorCache
-    {
-    float ax, bx, cx, dx;
-    float ay, by, cy, dy;
-    float az, bz, cz, dz;
-   
-    float x,y,z;
-    float vx,vy,vz;
-    }
-  
-  private class VectorNoise
-    {
-    float[] nx;
-    float[] ny;
-    float[] nz;
-   
-    public VectorNoise()
-      {
-      nx = new float[NUM_NOISE]; 
-      nx[0] = mRnd.nextFloat();
-      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1]+mRnd.nextFloat();
-      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
-      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
-     
-      ny = new float[NUM_NOISE];
-      for(int i=0; i<NUM_NOISE; i++) ny[i] = mRnd.nextFloat()-0.5f;
-     
-      nz = new float[NUM_NOISE];
-      for(int i=0; i<NUM_NOISE; i++) nz[i] = mRnd.nextFloat()-0.5f;  
-      }
-    }
-  
-  private Vector<VectorCache> vc;
-  private VectorCache tmp1, tmp2;
-
-  private Vector<Float3D> vv;
-  private Float3D prev, curr, next;
-  
-  private Vector<VectorNoise> vn;
-  private VectorNoise tmpN;
-  
-  private float mFactor1, mFactor2;  // used in Noise only. Those are noise factors; 1=noise of the (vec1X,vec1Y,vec1Z) vector; 2=noise of (vec2X,vec2Y,vec2Z)
-  private float vec1X,vec1Y,vec1Z;   // vector perpendicular to v(t) and in the same plane as v(t) and a(t) (for >2 points only, in case of 2 points this is calculated differently)
-  private float vec2X,vec2Y,vec2Z;   // vector perpendicular to v(t0 and to vec1.
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  synchronized void createNoise()
-    {
-    if( vn==null )
-      {  
-      vn = new Vector<VectorNoise>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-      }
-    }
-   
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void vec(int c)
-    {
-    int p = c>0 ? c-1: numPoints-1;
-    int n = c<numPoints-1 ? c+1: 0;
-    
-    prev = vv.elementAt(p);
-    curr = vv.elementAt(c);
-    next = vv.elementAt(n);
-
-    tmp1 = vc.elementAt(c);
-    
-    float px = curr.x - prev.x;
-    float py = curr.y - prev.y;
-    float pz = curr.z - prev.z;
-    float nx = next.x - curr.x;
-    float ny = next.y - curr.y;
-    float nz = next.z - curr.z;
-     
-    float d = nx*nx+ny*ny+nz*nz;
-    
-    if( d>0 )
-      {
-      float q = (float)Math.sqrt((px*px+py*py+pz*pz)/d);
-      
-      if( q>1 )
-        {
-        tmp1.x = nx+px/q;
-        tmp1.y = ny+py/q;
-        tmp1.z = nz+pz/q;
-        }
-      else
-        {
-        tmp1.x = px+nx*q;
-        tmp1.y = py+ny*q;
-        tmp1.z = pz+nz*q;
-        }
-      }
-    else
-      {
-      tmp1.x = 0.0f;
-      tmp1.y = 0.0f;
-      tmp1.z = 0.0f;  
-      }
-    }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmp1= vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      tmp1.ax = tmp1.ay = tmp1.az = 0.0f;
-      tmp1.bx = tmp1.by = tmp1.bz = 0.0f;
-      tmp1.cx = curr.x;
-      tmp1.cy = curr.y;
-      tmp1.cz = curr.z;
-      tmp1.dx = tmp1.dy = tmp1.dz = 0.0f;
-      }
-    else if( numPoints==2 )
-      {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-          
-      tmp1.ax = tmp1.ay = tmp1.az = 0.0f;
-      tmp1.bx = tmp1.by = tmp1.bz = 0.0f;
-      tmp1.cx = next.x - curr.x;
-      tmp1.cy = next.y - curr.y;
-      tmp1.cz = next.z - curr.z;
-      tmp1.dx = curr.x;
-      tmp1.dy = curr.y;
-      tmp1.dz = curr.z;
-      
-      tmp2.ax = tmp2.ay = tmp2.az = 0.0f;
-      tmp2.bx = tmp2.by = tmp2.bz = 0.0f;
-      tmp2.cx = curr.x - next.x;
-      tmp2.cy = curr.y - next.y;
-      tmp2.cz = curr.z - next.z;
-      tmp2.dx = next.x;
-      tmp2.dy = next.y;
-      tmp2.dz = next.z;
-      }
-    else
-      {
-      int i, n;  
-         
-      for(i=0; i<numPoints; i++) vec(i);
-   
-      for(i=0; i<numPoints; i++)
-        {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        tmp1.vx = curr.x;
-        tmp1.vy = curr.y;
-        tmp1.vz = curr.z;
-        
-        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
-        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
-        tmp1.cx = tmp1.x;
-        tmp1.dx = curr.x;
-      
-        tmp1.ay =  2*curr.y +   tmp1.y - 2*next.y + tmp2.y;
-        tmp1.by = -3*curr.y - 2*tmp1.y + 3*next.y - tmp2.y;
-        tmp1.cy = tmp1.y;
-        tmp1.dy = curr.y;
-      
-        tmp1.az =  2*curr.z +   tmp1.z - 2*next.z + tmp2.z;
-        tmp1.bz = -3*curr.z - 2*tmp1.z + 3*next.z - tmp2.z;
-        tmp1.cz = tmp1.z;
-        tmp1.dz = curr.z;
-        }
-      }
-   
-    cacheDirty = false;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float noise(float time,int vecNum)
-    {
-    float lower, upper, len;  
-    float d = time*(NUM_NOISE+1);
-    int index = (int)d;
-    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
-    tmpN = vn.elementAt(vecNum);
-   
-    float t = d-index;
-    t = t*t*(3-2*t);
-   
-    switch(index)
-      {
-      case 0        : mFactor1 = mNoise*tmpN.ny[0]*t;
-                      mFactor2 = mNoise*tmpN.nz[0]*t;
-                      return time + mNoise*(d*tmpN.nx[0]-time);
-      case NUM_NOISE: mFactor1= mNoise*tmpN.ny[NUM_NOISE-1]*(1-t);
-                      mFactor2= mNoise*tmpN.nz[NUM_NOISE-1]*(1-t);
-                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
-                      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);  
-                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
-      default       : float ya,yb;
-                      yb = tmpN.ny[index  ];
-                      ya = tmpN.ny[index-1];
-                      mFactor1 = mNoise*((yb-ya)*t+ya);
-                      yb = tmpN.nz[index  ];
-                      ya = tmpN.nz[index-1];
-                      mFactor2 = mNoise*((yb-ya)*t+ya);
-   
-                      len = ((float)index)/(NUM_NOISE+1);
-                      lower = len + mNoise*(tmpN.nx[index-1]-len);   
-                      len = ((float)index+1)/(NUM_NOISE+1); 
-                      upper = len + mNoise*(tmpN.nx[index  ]-len);
-            
-                      return (upper-lower)*(d-index) + lower; 
-      }
-    }
-     
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// v is the speed vector (i.e. position p(t) differentiated by time)
-// a is the acceleration vector (differentiate once more)
-// now what we are doing is compute vec1{X,Y,Z} to be a vector perpendicular to v and in the same plane as both v and a.
-// vec2{X,Y,Z} would be (v)x(vec1).
-//  
-// vec1 = a-delta*v where delta = (v*a)/|v|^2   (see Gram-Schmidt)
-  
-  private void setUpVectors(float time,VectorCache vc)
-    {
-    if( vc!=null )
-      {
-      float vx = (3*vc.ax*time+2*vc.bx)*time+vc.cx;
-      float vy = (3*vc.ay*time+2*vc.by)*time+vc.cy;
-      float vz = (3*vc.az*time+2*vc.bz)*time+vc.cz;
-     
-      float ax = 6*vc.ax*time+2*vc.bx;
-      float ay = 6*vc.ay*time+2*vc.by;
-      float az = 6*vc.az*time+2*vc.bz;
-     
-      float v_sq = vx*vx+vy*vy+vz*vz;
-      float delta = (vx*ax+vy*ay+vz*az)/v_sq;
-     
-      vec1X = ax-delta*vx;
-      vec1Y = ay-delta*vy;
-      vec1Z = az-delta*vz;
-     
-      vec2X = vy*vec1Z-vz*vec1Y;
-      vec2Y = vz*vec1X-vx*vec1Z;
-      vec2Z = vx*vec1Y-vy*vec1X;
-     
-      float len1 = (float)Math.sqrt(v_sq/(vec1X*vec1X+vec1Y*vec1Y+vec1Z*vec1Z));
-      float len2 = (float)Math.sqrt(v_sq/(vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z));   
-     
-      vec1X*=len1;
-      vec1Y*=len1;
-      vec1Z*=len1;
-     
-      vec2X*=len2;
-      vec2Y*=len2;
-      vec2Z*=len2;
-      }
-    else
-      {
-      curr = vv.elementAt(0);
-      next = vv.elementAt(1); 
-     
-      float vx = (next.x-curr.x);
-      float vy = (next.y-curr.y);
-      float vz = (next.z-curr.z);
-     
-      float b = (float)Math.sqrt(vx*vx+vy*vy);
-     
-      if( b>0.0f )
-        {
-        vec1X = vx*vz/b;
-        vec1Y = vy*vz/b;
-        vec1Z = -b;
-      
-        vec2X = vy*vec1Z-vz*vec1Y;
-        vec2Y = vz*vec1X-vx*vec1Z;
-        vec2Z = vx*vec1Y-vy*vec1X;
-       
-        float len2 = (float)Math.sqrt((vx*vx+vy*vy+vz*vz)/(vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z));
-       
-        vec2X*=len2;
-        vec2Y*=len2;
-        vec2Z*=len2;
-        }
-      else
-        {
-        vec1X = vz;
-        vec1Y = 0.0f;
-        vec1Z = 0.0f;
-      
-        vec2X = 0.0f;
-        vec2Y = vz;
-        vec2Z = 0.0f;
-        }
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Interpolator3D()
-    {
-    vv = new Vector<Float3D>();
-    vc = new Vector<VectorCache>();
-    vn = null;
-    numPoints = 0;
-    cacheDirty = false;
-    mMode = MODE_LOOP;
-    mDuration = 0;
-    mCount = 0.5f;
-    mNoise = 0.0f;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the location'th Float3D. 
- *   
- * @param location the index of the Point we are interested in.
- * @return The Float3D, if 0<=location&lt;getNumPoints(), or null otherwise. 
- */  
-  public synchronized Float3D getPoint(int location)
-    {
-    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the location'th Point.
- * 
- * @param location the index of the Point we are setting.
- * @param x New value of its first float.
- */
-  public synchronized void setPoint(int location, float x, float y, float z)
-    {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
-        {
-        curr.set(x,y,z);
-        cacheDirty=true;
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float3D to the end of our list of Points to interpolate through.
- * <p>   
- * Only a reference to the Point gets added to the List; this means that one can add a Point 
- * here, and later on {@link Float3D#set(float,float,float)} it to some new value and the 
- * change will be seamlessly reflected in the interpolated path.  
- * <p>
- * A Point can be added multiple times.
- *   
- * @param v The Point to add.
- */    
-  public synchronized void add(Float3D v)
-    {
-    if( v!=null )
-      {
-      vv.add(v);
-        
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
-        {
-        case 0: break;
-        case 1: setUpVectors(0.0f,null);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(new VectorCache());
-        }
-
-      numPoints++;
-      cacheDirty = true;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float3D to the location'th place in our List of Points to interpolate through.  
- *   
- * @param location Index in our List to add the new Point at.
- * @param v The Point to add.
- */  
-  public synchronized void add(int location, Float3D v)
-    {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
-        {
-        case 0: break;
-        case 1: setUpVectors(0.0f,null);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
-        }
-
-      numPoints++;
-      cacheDirty = true;
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all occurrences of Point v from the List of Points to interpolate through.  
- * 
- * @param v The Point to remove.
- * @return <code>true</code> if we have removed at least one Point.
- */
-  public synchronized boolean remove(Float3D v)
-    {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                setUpVectors(0.0f,null);
-                break;
-        default:vc.remove(n);
-        }
-
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes a location'th Point from the List of Points we interpolate through.
- * 
- * @param location index of the Point we want to remove. 
- * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
- */
-  public synchronized boolean remove(int location)
-    {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-       
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                setUpVectors(0.0f,null);
-                break;
-        default:vc.removeElementAt(location);
-        }
-
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-   return false;
-   }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
-    {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
- * <p>
- * Since this is a 3-dimensional Interpolator, the resulting interpolated Float3D gets written
- * to three locations in the buffer: buffer[offset], buffer[offset+1] and buffer[offset+2]. 
- * 
- * @param buffer Float buffer we will write the resulting Float3D to.
- * @param offset Offset in the buffer where to write the result.
- * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
- *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
- */    
-  public synchronized void interpolate(float[] buffer, int offset, float time)
-    {  
-    switch(numPoints)
-      {
-      case 0: buffer[offset  ] = 0.0f;
-              buffer[offset+1] = 0.0f;
-              buffer[offset+2] = 0.0f;
-              break;
-      case 1: curr = vv.elementAt(0);
-              buffer[offset  ] = curr.x;
-              buffer[offset+1] = curr.y;
-              buffer[offset+2] = curr.z;
-              break;
-      case 2: curr = vv.elementAt(0);
-              next = vv.elementAt(1);
-             
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-             
-              if( vn!=null )
-                {
-                time = noise(time,0);
-            
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (vec1X*mFactor1 + vec2X*mFactor2);
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (vec1Y*mFactor1 + vec2Y*mFactor2);
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (vec1Z*mFactor1 + vec2Z*mFactor2); 
-                }
-              else
-                {
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z;
-                }
-             
-              break;
-      default:float t = time;
-        
-              switch(mMode)
-                {
-                case MODE_LOOP: time = time*numPoints;
-                                break;
-                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
-                                break;
-                case MODE_JUMP: time = time*(numPoints-1);
-                                break;
-                }
-           
-              int vecCurr = (int)time;
-              time = time-vecCurr;
-      
-              if( vecCurr>=0 && vecCurr<numPoints )
-                {
-                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
-                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext;   
-                  mVecCurr = vecCurr;
-                       
-                  switch(mMode)
-                    {
-                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
-                                    break;
-                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
-                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
-                                    break;
-                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
-                                    break;
-                    default       : vecNext = 0;                
-                    }
-              
-                  next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
-              
-                  if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z ) recomputeCache();
-                  }
-            
-                tmp1 = vc.elementAt(vecCurr);
-               
-                if( vn!=null )
-                  {
-                  time = noise(time,vecCurr);
-              
-                  setUpVectors(time,tmp1);
-                 
-                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx + (vec1X*mFactor1 + vec2X*mFactor2);
-                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy + (vec1Y*mFactor1 + vec2Y*mFactor2);
-                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz + (vec1Z*mFactor1 + vec2Z*mFactor2);
-                  }
-                else
-                  {
-                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
-                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy;
-                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz;
-                  }
-               
-                break;
-                }
-       }
-     }  
-
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
diff --git a/src/main/java/org/distorted/library/type/Interpolator4D.java b/src/main/java/org/distorted/library/type/Interpolator4D.java
deleted file mode 100644
index 72aa1e3..0000000
--- a/src/main/java/org/distorted/library/type/Interpolator4D.java
+++ /dev/null
@@ -1,771 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-import java.util.Vector;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 4-dimensional implementation of the Interpolator class to interpolate between a list 
-* of Float4Ds.
-*/
-
-public class Interpolator4D extends Interpolator 
-  {
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// the coefficients of the X(t), Y(t), Z(t), W(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
-// (x,y,z,w) is the vector tangent to the path.
-// (vx,vy,vz,vw) is the original vector from vv (copied here so when interpolating we can see if it is 
-// still valid and if not - rebuild the Cache
-  
-  private class VectorCache
-    {
-    float ax, bx, cx, dx;
-    float ay, by, cy, dy;
-    float az, bz, cz, dz;
-    float aw, bw, cw, dw;
-   
-    float x,y,z,w;
-    float vx,vy,vz,vw;
-    }
-  
-  private class VectorNoise
-    {
-    float[] nx;
-    float[] ny;
-    float[] nz;
-    float[] nw;
-   
-    public VectorNoise()
-      {
-      nx = new float[NUM_NOISE]; 
-      nx[0] = mRnd.nextFloat();
-      for(int i=1; i<NUM_NOISE; i++) nx[i] = nx[i-1] + mRnd.nextFloat();
-      float sum = nx[NUM_NOISE-1] + mRnd.nextFloat();
-      for(int i=0; i<NUM_NOISE; i++) nx[i] /=sum;
-     
-      ny = new float[NUM_NOISE];
-      for(int i=0; i<NUM_NOISE; i++) ny[i] = mRnd.nextFloat()-0.5f;
-     
-      nz = new float[NUM_NOISE];
-      for(int i=0; i<NUM_NOISE; i++) nz[i] = mRnd.nextFloat()-0.5f;
-     
-      nw = new float[NUM_NOISE];
-      for(int i=0; i<NUM_NOISE; i++) nw[i] = mRnd.nextFloat()-0.5f;  
-      }
-    }
-  
-  private Vector<VectorCache> vc;
-  private VectorCache tmp1, tmp2;
-
-  private Vector<Float4D> vv;
-  private Float4D prev, curr, next;
-  
-  private Vector<VectorNoise> vn;
-  private VectorNoise tmpN;
-  
-  private float mFactor1, mFactor2, mFactor3; // used in Noise only. Those are noise factors; 1=noise of the (vec1X,vec1Y,vec1Z,vec1W) vector; 2=noise of (vec2X,vec2Y,vec2Z,vec2W) and same for vec3.
-  private float vec1X,vec1Y,vec1Z,vec1W;      // vector perpendicular to v(t) and in the same plane as v(t) and a(t) (for >2 points only, in case of 2 points this is calculated differently)
-  private float vec2X,vec2Y,vec2Z,vec2W;      // vector perpendicular to v(t) and to vec1.
-  private float vec3X,vec3Y,vec3Z,vec3W;      // vector perpendicular to v(t) and to vec1.
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  synchronized void createNoise()
-    {
-    if( vn==null )
-      {  
-      vn = new Vector<VectorNoise>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-      }
-    }
-   
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void vec(int c)
-    {
-    int p = c>0 ? c-1: numPoints-1;
-    int n = c<numPoints-1 ? c+1: 0;
-    
-    prev = vv.elementAt(p);
-    curr = vv.elementAt(c);
-    next = vv.elementAt(n);
-
-    tmp1 = vc.elementAt(c);
-    
-    float px = curr.x - prev.x;
-    float py = curr.y - prev.y;
-    float pz = curr.z - prev.z;
-    float pw = curr.w - prev.w;
-    float nx = next.x - curr.x;
-    float ny = next.y - curr.y;
-    float nz = next.z - curr.z;
-    float nw = next.w - curr.w;
-     
-    float d = nx*nx+ny*ny+nz*nz+nw*nw;
-    
-    if( d>0 )
-      {
-      float q = (float)Math.sqrt((px*px+py*py+pz*pz+pw*pw)/d);
-      
-      if( q>1 )
-        {
-        tmp1.x = nx+px/q;
-        tmp1.y = ny+py/q;
-        tmp1.z = nz+pz/q;
-        tmp1.w = nw+pw/q;
-        }
-      else
-        {
-        tmp1.x = px+nx*q;
-        tmp1.y = py+ny*q;
-        tmp1.z = pz+nz*q;
-        tmp1.w = pw+nw*q;
-        }
-      }
-    else
-      {
-      tmp1.x = 0.0f;
-      tmp1.y = 0.0f;
-      tmp1.z = 0.0f;  
-      tmp1.w = 0.0f;
-      }
-    }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmp1= vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      tmp1.ax = tmp1.ay = tmp1.az = tmp1.aw = 0.0f;
-      tmp1.bx = tmp1.by = tmp1.bz = tmp1.bw = 0.0f;
-      tmp1.cx = curr.x;
-      tmp1.cy = curr.y;
-      tmp1.cz = curr.z;
-      tmp1.cw = curr.w;
-      tmp1.dx = tmp1.dy = tmp1.dz = tmp1.dw = 0.0f;
-      }
-    else if( numPoints==2 )
-      {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-      
-      tmp1.ax = tmp1.ay = tmp1.az = tmp1.aw = 0.0f;
-      tmp1.bx = tmp1.by = tmp1.bz = tmp1.bw = 0.0f;
-      tmp1.cx = next.x - curr.x;
-      tmp1.cy = next.y - curr.y;
-      tmp1.cz = next.z - curr.z;
-      tmp1.cw = next.w - curr.w;
-      tmp1.dx = curr.x;
-      tmp1.dy = curr.y;
-      tmp1.dz = curr.z;
-      tmp1.dw = curr.w;
-      
-      tmp2.ax = tmp2.ay = tmp2.az = tmp2.aw = 0.0f;
-      tmp2.bx = tmp2.by = tmp2.bz = tmp2.bw = 0.0f;
-      tmp2.cx = curr.x - next.x;
-      tmp2.cy = curr.y - next.y;
-      tmp2.cz = curr.z - next.z;
-      tmp2.cw = curr.w - next.w;
-      tmp2.dx = next.x;
-      tmp2.dy = next.y;
-      tmp2.dz = next.z;
-      tmp2.dw = next.w;
-      }
-    else
-      {
-      int i, n;  
-      
-      for(i=0; i<numPoints; i++) vec(i);
-   
-      for(i=0; i<numPoints; i++)
-        {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        tmp1.vx = curr.x;
-        tmp1.vy = curr.y;
-        tmp1.vz = curr.z;
-        tmp1.vw = curr.w;
-        
-        tmp1.ax =  2*curr.x +   tmp1.x - 2*next.x + tmp2.x;
-        tmp1.bx = -3*curr.x - 2*tmp1.x + 3*next.x - tmp2.x;
-        tmp1.cx = tmp1.x;
-        tmp1.dx = curr.x;
-      
-        tmp1.ay =  2*curr.y +   tmp1.y - 2*next.y + tmp2.y;
-        tmp1.by = -3*curr.y - 2*tmp1.y + 3*next.y - tmp2.y;
-        tmp1.cy = tmp1.y;
-        tmp1.dy = curr.y;
-      
-        tmp1.az =  2*curr.z +   tmp1.z - 2*next.z + tmp2.z;
-        tmp1.bz = -3*curr.z - 2*tmp1.z + 3*next.z - tmp2.z;
-        tmp1.cz = tmp1.z;
-        tmp1.dz = curr.z;
-        
-        tmp1.aw =  2*curr.w +   tmp1.w - 2*next.w + tmp2.w;
-        tmp1.bw = -3*curr.w - 2*tmp1.w + 3*next.w - tmp2.w;
-        tmp1.cw = tmp1.w;
-        tmp1.dw = curr.w;
-        }
-      }
-   
-    cacheDirty = false;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float noise(float time,int vecNum)
-    {
-    float lower, upper, len;  
-    float d = time*(NUM_NOISE+1);
-    int index = (int)d;
-    if( index>=NUM_NOISE+1 ) index=NUM_NOISE;
-    tmpN = vn.elementAt(vecNum);
-   
-    float t = d-index;
-    t = t*t*(3-2*t);
-   
-    switch(index)
-      {
-      case 0        : mFactor1 = mNoise*tmpN.ny[0]*t;
-                      mFactor2 = mNoise*tmpN.nz[0]*t;
-                      mFactor3 = mNoise*tmpN.nw[0]*t;
-                      return time + mNoise*(d*tmpN.nx[0]-time);
-      case NUM_NOISE: mFactor1= mNoise*tmpN.ny[NUM_NOISE-1]*(1-t);
-                      mFactor2= mNoise*tmpN.nz[NUM_NOISE-1]*(1-t);
-                      mFactor3= mNoise*tmpN.nw[NUM_NOISE-1]*(1-t);
-                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
-                      lower = len + mNoise*(tmpN.nx[NUM_NOISE-1]-len);  
-                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
-      default       : float ya,yb;
-                      yb = tmpN.ny[index  ];
-                      ya = tmpN.ny[index-1];
-                      mFactor1 = mNoise*((yb-ya)*t+ya);
-                      yb = tmpN.nz[index  ];
-                      ya = tmpN.nz[index-1];
-                      mFactor2 = mNoise*((yb-ya)*t+ya);
-                      yb = tmpN.nw[index  ];
-                      ya = tmpN.nw[index-1];
-                      mFactor3 = mNoise*((yb-ya)*t+ya);
-   
-                      len = ((float)index)/(NUM_NOISE+1);
-                      lower = len + mNoise*(tmpN.nx[index-1]-len);   
-                      len = ((float)index+1)/(NUM_NOISE+1); 
-                      upper = len + mNoise*(tmpN.nx[index  ]-len);
-            
-                      return (upper-lower)*(d-index) + lower; 
-      }
-    }
-     
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// v is the speed vector (i.e. position p(t) differentiated by time)
-// a is the acceleration vector (differentiate once more)
-//
-// Now we construct orthogonal basis with Gram-Schmidt:  
-// vec1 = a-delta*v where delta = (v*a)/|v|^2
-// vec2 = (0,0,1,0) - coeff1*(vx,vy,vz,vw) - coeff2*(vec1x,vec1y,vec1z,vec1w)                                     where coeff1 = vz/|v|^2, coeff2 = vec1Z/|vec1|^2
-// vec3 = (0,0,0,1) - coeff1*(vx,vy,vz,vw) - coeff2*(vec1x,vec1y,vec1z,vec1w) - coeff3*(vec2x,vec2y,vec2z,vec2w)  where coeff1 = vw/|v|^2, coeff2 = vec1W/|vec1|^2, coeff3 = vec2W/|vec2|^2
-    
-  private void setUpVectors(float time,VectorCache vc)
-    {
-    if( vc!=null )
-      {
-      float vx = (3*vc.ax*time+2*vc.bx)*time+vc.cx;
-      float vy = (3*vc.ay*time+2*vc.by)*time+vc.cy;
-      float vz = (3*vc.az*time+2*vc.bz)*time+vc.cz;
-      float vw = (3*vc.aw*time+2*vc.bw)*time+vc.cw;
-     
-      float ax = 6*vc.ax*time+2*vc.bx;
-      float ay = 6*vc.ay*time+2*vc.by;
-      float az = 6*vc.az*time+2*vc.bz;
-      float aw = 6*vc.aw*time+2*vc.bw;
-     
-      float v_sq = vx*vx+vy*vy+vz*vz+vw*vw;
-      float delta = (vx*ax+vy*ay+vz*az*vw*vw)/v_sq;
-     
-      vec1X = ax-delta*vx;
-      vec1Y = ay-delta*vy;
-      vec1Z = az-delta*vz;
-      vec1W = aw-delta*vw;
-     
-      float vec1_sq = vec1X*vec1X+vec1Y*vec1Y+vec1Z*vec1Z+vec1W*vec1W;
-     
-      // construct vec2 and vec3. Cross product does not work in 4th dimension!
-      float coeff21 = vz/v_sq;
-      float coeff22 = vec1Z/vec1_sq;
-      vec2X = 0.0f - coeff21*vx - coeff22*vec1X;
-      vec2Y = 0.0f - coeff21*vy - coeff22*vec1Y;
-      vec2Z = 1.0f - coeff21*vz - coeff22*vec1Z;
-      vec2W = 0.0f - coeff21*vw - coeff22*vec1W;
-     
-      float vec2_sq = vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z+vec2W*vec2W;
-      float coeff31 = vw/v_sq;
-      float coeff32 = vec1W/vec1_sq;
-      float coeff33 = vec2W/vec2_sq;
-      vec2X = 0.0f - coeff31*vx - coeff32*vec1X - coeff33*vec2X;
-      vec2Y = 0.0f - coeff31*vy - coeff32*vec1Y - coeff33*vec2Y;
-      vec2Z = 0.0f - coeff31*vz - coeff32*vec1Z - coeff33*vec2Z;
-      vec2W = 1.0f - coeff31*vw - coeff32*vec1W - coeff33*vec2W;
-     
-      float vec3_sq = vec3X*vec3X+vec3Y*vec3Y+vec3Z*vec3Z+vec3W*vec3W;
-     
-      float len1 = (float)Math.sqrt(v_sq/vec1_sq);   
-      float len2 = (float)Math.sqrt(v_sq/vec2_sq);   
-      float len3 = (float)Math.sqrt(v_sq/vec3_sq);
-     
-      vec1X*=len1;
-      vec1Y*=len1;
-      vec1Z*=len1;
-      vec1W*=len1;
-     
-      vec2X*=len2;
-      vec2Y*=len2;
-      vec2Z*=len2;
-      vec2W*=len2;
-     
-      vec3X*=len3;
-      vec3Y*=len3;
-      vec3Z*=len3;
-      vec3W*=len3;
-      }
-    else
-      {
-      curr = vv.elementAt(0);
-      next = vv.elementAt(1); 
-     
-      float vx = (next.x-curr.x);
-      float vy = (next.y-curr.y);
-      float vz = (next.z-curr.z);
-      float vw = (next.w-curr.w);
-     
-      float b = (float)Math.sqrt(vx*vx+vy*vy+vz*vz);
-     
-      if( b>0.0f )
-        {
-        vec1X = vx*vw/b;
-        vec1Y = vy*vw/b;
-        vec1Z = vz*vw/b;
-        vec1W = -b;
-      
-        float v_sq = vx*vx+vy*vy+vz*vz+vw*vw;
-        float vec1_sq = vec1X*vec1X+vec1Y*vec1Y+vec1Z*vec1Z+vec1W*vec1W;
-     
-        // construct vec2 and vec3. Cross product does not work in 4th dimension!
-        float coeff21 = vz/v_sq;
-        float coeff22 = vec1Z/vec1_sq;
-        vec2X = 0.0f - coeff21*vx - coeff22*vec1X;
-        vec2Y = 0.0f - coeff21*vy - coeff22*vec1Y;
-        vec2Z = 1.0f - coeff21*vz - coeff22*vec1Z;
-        vec2W = 0.0f - coeff21*vw - coeff22*vec1W;
-     
-        float vec2_sq = vec2X*vec2X+vec2Y*vec2Y+vec2Z*vec2Z+vec2W*vec2W;
-        float coeff31 = vw/v_sq;
-        float coeff32 = vec1W/vec1_sq;
-        float coeff33 = vec2W/vec2_sq;
-        vec2X = 0.0f - coeff31*vx - coeff32*vec1X - coeff33*vec2X;
-        vec2Y = 0.0f - coeff31*vy - coeff32*vec1Y - coeff33*vec2Y;
-        vec2Z = 0.0f - coeff31*vz - coeff32*vec1Z - coeff33*vec2Z;
-        vec2W = 1.0f - coeff31*vw - coeff32*vec1W - coeff33*vec2W;
-     
-        float vec3_sq = vec3X*vec3X+vec3Y*vec3Y+vec3Z*vec3Z+vec3W*vec3W;
-     
-        float len1 = (float)Math.sqrt(v_sq/vec1_sq);    
-        float len2 = (float)Math.sqrt(v_sq/vec2_sq);    
-        float len3 = (float)Math.sqrt(v_sq/vec3_sq);
-     
-        vec1X*=len1;
-        vec1Y*=len1;
-        vec1Z*=len1;
-        vec1W*=len1;
-     
-        vec2X*=len2;
-        vec2Y*=len2;
-        vec2Z*=len2;
-        vec2W*=len2;
-     
-        vec3X*=len3;
-        vec3Y*=len3;
-        vec3Z*=len3;
-        vec3W*=len3;
-        }
-      else
-        {
-        vec1X = vw;
-        vec1Y = 0.0f;
-        vec1Z = 0.0f;
-        vec1W = 0.0f;
-      
-        vec2X = 0.0f;
-        vec2Y = vw;
-        vec2Z = 0.0f;
-        vec2W = 0.0f;
-      
-        vec3X = 0.0f;
-        vec3Y = 0.0f;
-        vec3Z = vw;
-        vec3W = 0.0f;
-        }
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Interpolator4D()
-    {
-    vv = new Vector<Float4D>();
-    vc = new Vector<VectorCache>();
-    vn = null;
-    numPoints = 0;
-    cacheDirty = false;
-    mMode = MODE_LOOP;
-    mDuration = 0;
-    mCount = 0.5f;
-    mNoise = 0.0f;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the location'th Float4D. 
- *   
- * @param location the index of the Point we are interested in.
- * @return The Float4D, if 0<=location&lt;getNumPoints(), or null otherwise. 
- */  
-  public synchronized Float4D getPoint(int location)
-    {
-    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the location'th Point.
- * 
- * @param location the index of the Point we are setting.
- * @param x New value of its first float.
- */
-  public synchronized void setPoint(int location, float x, float y, float z, float w)
-    {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
-        {
-        curr.set(x,y,z,w);
-        cacheDirty=true;
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float4D to the end of our list of Points to interpolate through.
- * <p>   
- * Only a reference to the Point gets added to the List; this means that one can add a Point 
- * here, and later on {@link Float4D#set(float,float,float,float)} it to some new value and 
- * the change will be seamlessly reflected in the interpolated path.  
- * <p>
- * A Point can be added multiple times.
- *   
- * @param v The Point to add.
- */    
-  public synchronized void add(Float4D v)
-    {
-    if( v!=null )
-      {
-      vv.add(v);
-        
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-       switch(numPoints)
-         {
-         case 0: break;
-         case 1: setUpVectors(0.0f,null);
-                 break;
-         case 2: vc.add(new VectorCache());
-                 vc.add(new VectorCache());
-                 vc.add(new VectorCache());
-                 break;
-         default:vc.add(new VectorCache());
-         }
-
-       numPoints++;
-       cacheDirty = true;
-       }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float4D to the location'th place in our List of Points to interpolate through.  
- *   
- * @param location Index in our List to add the new Point at.
- * @param v The Float4D to add.
- */  
-  public synchronized void add(int location, Float4D v)
-    {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
-        {
-        case 0: break;
-        case 1: setUpVectors(0.0f,null);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
-        }
-
-      numPoints++;
-      cacheDirty = true;
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all occurrences of Point v from the List of Points to interpolate through.  
- * 
- * @param v The Point to remove.
- * @return <code>true</code> if we have removed at least one Point.
- */
-  public synchronized boolean remove(Float4D v)
-    {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                setUpVectors(0.0f,null);
-                break;
-        default:vc.remove(n);
-        }
-
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes a location'th Point from the List of Points we interpolate through.
- * 
- * @param location index of the Point we want to remove. 
- * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
- */
-  public synchronized boolean remove(int location)
-    {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-       
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
-        {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                setUpVectors(0.0f,null);
-                break;
-        default:vc.removeElementAt(location);
-        }
-
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-    return false;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
-    {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
- * <p>
- * Since this is a 4-dimensional Interpolator, the resulting interpolated Float4D gets written
- * to four locations in the buffer: buffer[offset], buffer[offset+1], buffer[offset+2] and buffer[offset+3]. 
- * 
- * @param buffer Float buffer we will write the resulting Float4D to.
- * @param offset Offset in the buffer where to write the result.
- * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
- *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
- */    
-  public synchronized void interpolate(float[] buffer, int offset, float time)
-    {  
-    switch(numPoints)
-      {
-      case 0: buffer[offset  ] = 0.0f;
-              buffer[offset+1] = 0.0f;
-              buffer[offset+2] = 0.0f;
-              buffer[offset+3] = 0.0f;
-              break;
-      case 1: curr = vv.elementAt(0);
-              buffer[offset  ] = curr.x;
-              buffer[offset+1] = curr.y;
-              buffer[offset+2] = curr.z;
-              buffer[offset+3] = curr.w;
-              break;
-      case 2: curr = vv.elementAt(0);
-              next = vv.elementAt(1);
-            
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-             
-              if( vn!=null )
-                {
-                time = noise(time,0);
-            
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (vec1X*mFactor1 + vec2X*mFactor2 + vec3X*mFactor3);
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (vec1Y*mFactor1 + vec2Y*mFactor2 + vec3Y*mFactor3);
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (vec1Z*mFactor1 + vec2Z*mFactor2 + vec3Z*mFactor3);
-                buffer[offset+3] = (next.w-curr.w)*time + curr.w + (vec1W*mFactor1 + vec2W*mFactor2 + vec3W*mFactor3); 
-                }
-              else
-                {
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z;
-                buffer[offset+3] = (next.w-curr.w)*time + curr.w;
-                }
-                
-              break;
-      default:float t = time;
-        
-              switch(mMode)
-                {
-                case MODE_LOOP: time = time*numPoints;
-                                break;
-                case MODE_PATH: time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
-                                break;
-                case MODE_JUMP: time = time*(numPoints-1);
-                                break;
-                }
-     
-              int vecCurr = (int)time;
-              time = time-vecCurr;
-      
-              if( vecCurr>=0 && vecCurr<numPoints )
-                {
-                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
-                else if( mVecCurr!= vecCurr )         // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext;   
-                  mVecCurr = vecCurr;
-                       
-                  switch(mMode)
-                    {
-                    case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
-                                    break;
-                    case MODE_PATH: if( t<0.5f ) vecNext = vecCurr==numPoints-1 ? numPoints-2: vecCurr+1;  
-                                    else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
-                                    break;
-                    case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
-                                    break;
-                    default       : vecNext = 0;                
-                    }
-     
-                  next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
-              
-                  if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z || tmp2.vw!=next.w ) recomputeCache();
-                  }
-            
-                tmp1 = vc.elementAt(vecCurr);
-               
-                if( vn!=null )
-                  {
-                  time = noise(time,vecCurr);
-              
-                  setUpVectors(time,tmp1);
-                 
-                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx + (vec1X*mFactor1 + vec2X*mFactor2 + vec3X*mFactor3);
-                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy + (vec1Y*mFactor1 + vec2Y*mFactor2 + vec3Y*mFactor3);
-                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz + (vec1Z*mFactor1 + vec2Z*mFactor2 + vec3Z*mFactor3);
-                  buffer[offset+3]= ((tmp1.aw*time+tmp1.bw)*time+tmp1.cw)*time+tmp1.dw + (vec1W*mFactor1 + vec2W*mFactor2 + vec3W*mFactor3);
-                  }
-                else
-                  {
-                  buffer[offset  ]= ((tmp1.ax*time+tmp1.bx)*time+tmp1.cx)*time+tmp1.dx;
-                  buffer[offset+1]= ((tmp1.ay*time+tmp1.by)*time+tmp1.cy)*time+tmp1.dy;
-                  buffer[offset+2]= ((tmp1.az*time+tmp1.bz)*time+tmp1.cz)*time+tmp1.dz;
-                  buffer[offset+3]= ((tmp1.aw*time+tmp1.bw)*time+tmp1.cw)*time+tmp1.dw;
-                  }
- 
-                break;
-                }
-      }
-    }  
-
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
diff --git a/src/main/java/org/distorted/library/type/InterpolatorQuat.java b/src/main/java/org/distorted/library/type/InterpolatorQuat.java
deleted file mode 100644
index 9334e09..0000000
--- a/src/main/java/org/distorted/library/type/InterpolatorQuat.java
+++ /dev/null
@@ -1,392 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.library.type;
-
-import java.util.Vector;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 4-dimensional implementation of the Interpolator class to interpolate between a list 
-* of Float4Ds.
-* Here, the Points are assumed to be Quaternions - thus we do the Spherical Linear Interpolation, aka
-* SLERP. Noise not supported (yet?).
-*/
-
-public class InterpolatorQuat extends Interpolator 
-  {
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// omega, sinOmega, cosOmega - angle between pair of quaternions, its sinus and cosinus.
-//  
-// (vx,vy,vz,vw) is the original vector from vv (copied here so when interpolating we can see if it is 
-// still valid and if not - rebuild the Cache
-  
-  private class VectorCache
-    {
-    float omega, sinOmega,cosOmega;
-    float vx,vy,vz,vw;
-    }
-  
-  private Vector<VectorCache> vc;
-  private VectorCache tmp1, tmp2;
-
-  private Vector<Float4D> vv;
-  private Float4D curr, next;
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//Abramowitz / Stegun
-
-  private static float arcCos(float x)
-    {
-    if( x<0 )
-      return 3.14159265358979f - (float)Math.sqrt(1+x)*(1.5707288f + 0.2121144f*x + 0.074261f*x*x + 0.0187293f*x*x*x);
-     
-    return (float)Math.sqrt(1-x)*(1.5707288f - 0.2121144f*x + 0.074261f*x*x - 0.0187293f*x*x*x);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Quaternion Interpolator doesn't support noise
-  
-  synchronized void createNoise()
-    {
-
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints>=2 )
-      {
-      int i, n;  
-     
-      for(i=0; i<numPoints; i++)
-        {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        tmp1.vx = curr.x;
-        tmp1.vy = curr.y;
-        tmp1.vz = curr.z;
-        tmp1.vw = curr.w;
-    	
-        tmp1.cosOmega = curr.x*next.x + curr.y*next.y + curr.z*next.z + curr.w*next.w;
-      	
-        if( tmp1.cosOmega<0 && n!=0 )  // do not invert the last quaternion even if we'd have to go the long way around!
-          {
-          tmp1.cosOmega = -tmp1.cosOmega;
-          next.x = -next.x;
-          next.y = -next.y;
-          next.z = -next.z;
-          next.w = -next.w;
-          }
-      	
-        tmp1.sinOmega = (float)Math.sqrt(1-tmp1.cosOmega*tmp1.cosOmega);
-        tmp1.omega = arcCos(tmp1.cosOmega);
-        }
-      }
-   
-    cacheDirty = false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public InterpolatorQuat()
-    {
-    vv = new Vector<Float4D>();
-    vc = new Vector<VectorCache>();
-    numPoints = 0;
-    cacheDirty = false;
-    mMode = MODE_LOOP;
-    mDuration = 0;
-    mCount = 0.5f;
-    mNoise = 0.0f;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the location'th Float4D. 
- *   
- * @param location the index of the Point we are interested in.
- * @return The Float4D, if 0<=location&lt;getNumPoints(), or null otherwise. 
- */  
-  public synchronized Float4D getPoint(int location)
-    {
-    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the location'th Point.
- * 
- * @param location the index of the Point we are setting.
- * @param x New value of its first float.
- */
-  public synchronized void setPoint(int location, float x, float y, float z, float w)
-    {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
-        {
-        curr.set(x,y,z,w);
-        cacheDirty=true;
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float4D to the end of our list of Points to interpolate through.
- * <p>   
- * Only a reference to the Point gets added to the List; this means that one can add a Point 
- * here, and later on {@link Float4D#set(float,float,float,float)} it to some new value and 
- * the change will be seamlessly reflected in the interpolated path.  
- * <p>
- * A Point can be added multiple times.
- *   
- * @param v The Point to add.
- */    
-  public synchronized void add(Float4D v)
-    {
-    if( v!=null )
-      {
-      vv.add(v);
-      
-      switch(numPoints)
-         {
-         case 0: 
-         case 1: vc.add(new VectorCache());
-                 vc.add(new VectorCache());
-        	     break;
-         default:vc.add(new VectorCache());
-         }
-
-       numPoints++;
-       cacheDirty = true;
-       }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Float4D to the location'th place in our List of Points to interpolate through.  
- *   
- * @param location Index in our List to add the new Point at.
- * @param v The Float4D to add.
- */  
-  public synchronized void add(int location, Float4D v)
-    {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      switch(numPoints)
-        {
-        case 0: 
-        case 1: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
-        }
-
-      numPoints++;
-      cacheDirty = true;
-      }
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all occurrences of Point v from the List of Points to interpolate through.  
- * 
- * @param v The Point to remove.
- * @return <code>true</code> if we have removed at least one Point.
- */
-  public synchronized boolean remove(Float4D v)
-    {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      switch(numPoints)
-        {
-        case 0:
-        case 1: break;
-        case 2: vc.removeAllElements();
-                break;
-        default:vc.remove(n);
-        }
-
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes a location'th Point from the List of Points we interpolate through.
- * 
- * @param location index of the Point we want to remove. 
- * @return <code>true</code> if location is valid, i.e. if 0<=location&lt;getNumPoints().
- */
-  public synchronized boolean remove(int location)
-    {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-      
-      switch(numPoints)
-        {
-        case 0: 
-        case 1: break;
-        case 2: vc.removeAllElements();
-                break;
-        default:vc.removeElementAt(location);
-        }
-
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-    return false;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
-    {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-    }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
- * Interpolation is done using the spherical linear algorithm, aka SLERP.
- * <p>
- * Since this is a 4-dimensional Interpolator, the resulting interpolated Float4D gets written
- * to four locations in the buffer: buffer[offset], buffer[offset+1], buffer[offset+2] and buffer[offset+3]. 
- * 
- * @param buffer Float buffer we will write the resulting Float4D to.
- * @param offset Offset in the buffer where to write the result.
- * @param time Time of interpolation. Time=0.0 would return the first Point, Time=0.5 - the last,
- *             time=1.0 - the first again, and time 0.1 would be 1/5 of the way between the first and the last Points.
- */    
-  public synchronized void interpolate(float[] buffer, int offset, float time)
-    {  
-    switch(numPoints)
-      {
-      case 0: buffer[offset  ] = 0.0f;
-              buffer[offset+1] = 0.0f;
-              buffer[offset+2] = 0.0f;
-              buffer[offset+3] = 0.0f;
-              break;
-      case 1: curr = vv.elementAt(0);
-              buffer[offset  ] = curr.x; 
-              buffer[offset+1] = curr.y;
-              buffer[offset+2] = curr.z;
-              buffer[offset+3] = curr.w;
-              break;
-      default:float t = time;
-              float scale0, scale1;
-  
-              if( mMode==MODE_JUMP ) time = time*(numPoints-1);
-              else if( mMode==MODE_PATH || numPoints==2 ) time = (time<=0.5f) ? 2*time*(numPoints-1) : 2*(1-time)*(numPoints-1);
-              else time = time*numPoints;
-              
-              int vecNext, vecCurr = (int)time;
-              time = time-vecCurr;
-      
-              if( vecCurr>=0 && vecCurr<numPoints )
-                {
-                if( cacheDirty ) recomputeCache();    // recompute cache if we have added or remove vectors since last computation
-                   
-                switch(mMode)
-                  {
-                  case MODE_LOOP: vecNext = vecCurr==numPoints-1 ? 0:vecCurr+1; 
-                                  break;
-                  case MODE_PATH: if( t<0.5f ) vecNext = vecCurr+1;  
-                                  else         vecNext = vecCurr==0 ? 1 : vecCurr-1;  
-                                  break;
-                  case MODE_JUMP: vecNext = vecCurr==numPoints-1 ? 1:vecCurr+1;
-                                  break;
-                  default       : vecNext = 0;                
-                  }
-     
-                curr = vv.elementAt(vecCurr);
-                next = vv.elementAt(vecNext);
-                tmp1 = vc.elementAt(vecCurr);
-                tmp2 = vc.elementAt(vecNext);
-              
-                if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z || tmp2.vw!=next.w ) recomputeCache();
-               
-                if( tmp1.sinOmega==0 )
-                  {
-                  scale0 = 0f;
-                  scale1 = 1f;
-                  }
-                else if( tmp1.cosOmega < 0.99 ) 
-                  {
-                  scale0 = (float)Math.sin( (1f-time)*tmp1.omega ) / tmp1.sinOmega;
-                  scale1 = (float)Math.sin(     time *tmp1.omega ) / tmp1.sinOmega;
-                  }
-                else 
-                  {
-                  scale0 = 1f-time;
-                  scale1 = time;
-                  }
-
-                buffer[offset  ] = scale0*curr.x + scale1*next.x;
-                buffer[offset+1] = scale0*curr.y + scale1*next.y; 
-                buffer[offset+2] = scale0*curr.z + scale1*next.z; 
-                buffer[offset+3] = scale0*curr.w + scale1*next.w; 
-                
-                break;
-                }
-      }
-    }  
-
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
diff --git a/src/main/java/org/distorted/library/type/Static1D.java b/src/main/java/org/distorted/library/type/Static1D.java
new file mode 100644
index 0000000..9121d5a
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Static1D.java
@@ -0,0 +1,90 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A 1-dimensional data structure containing a single float. The float has no particular meaning; 
+ * when this data structure is used in Interpolators, we can think of it as a 1-dimensional Point 
+ * a few of which the Dynamic interpolates between.
+ */
+
+public class Static1D implements Data1D
+  {
+  float x;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the single float to ox.   
+ *   
+ * @param ox value of the single float.
+ */
+  public Static1D(int ox)
+    {
+    x = ox;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the single float to ox.   
+ *   
+ * @param ox value of the single float.
+ */  
+  public Static1D(float ox)
+    {
+    x = ox;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the value of the single float.
+ * 
+ * @param ox new value of the single float.
+ */
+  public void set(int ox)
+    {
+    x = ox;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resets the value of the single float.
+ * 
+ * @param ox new value of the single float.
+ */
+  public void set(float ox)
+    {
+    x = ox;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Return the value of the float contained.
+ * 
+ * @return The single float.
+ */
+  public float getX()
+    {
+    return x;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// end of class   
+  }
diff --git a/src/main/java/org/distorted/library/type/Static2D.java b/src/main/java/org/distorted/library/type/Static2D.java
new file mode 100644
index 0000000..7cefddb
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Static2D.java
@@ -0,0 +1,98 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A 2-dimensional data structure containing two floats. The floats have no particular meaning; 
+ * when this data structure is used in Interpolators, we can think of it as a 2-dimensional Point 
+ * a few of which the Dynamic interpolates between.
+ */
+
+public class Static2D extends Static1D implements Data2D
+  {
+  float y;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the two floats to (ox,oy).   
+ *   
+ * @param ox value of the first float.
+ * @param oy value of the second float.
+ */  
+  public Static2D(int ox, int oy)
+    {
+    super(ox);
+    y = oy;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the two floats to (ox,oy).   
+ *   
+ * @param ox value of the first float.
+ * @param oy value of the second float.
+ */    
+  public Static2D(float ox, float oy)
+    {
+    super(ox);
+    y = oy;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Reset the value of the floats to (ox,oy).
+ * 
+ * @param ox new value of the first float
+ * @param oy new value of the second float
+ */
+  public void set(int ox, int oy)
+    {
+    x = ox;
+    y = oy;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Reset the value of the floats to (ox,oy).
+ * 
+ * @param ox new value of the first float
+ * @param oy new value of the seond float
+ */
+  public void set(float ox, float oy)
+    {
+    x = ox;
+    y = oy;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Return the value of the second float contained.
+ * 
+ * @return The second float.
+ */
+  public float getY()
+    {
+    return y;  
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// end of class   
+  }
diff --git a/src/main/java/org/distorted/library/type/Static3D.java b/src/main/java/org/distorted/library/type/Static3D.java
new file mode 100644
index 0000000..57a4fd7
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Static3D.java
@@ -0,0 +1,104 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A 3-dimensional data structure containing three floats. The floats have no particular meaning; 
+ * when this data structure is used in Interpolators, we can think of it as a 3-dimensional Point 
+ * a few of which the Dynamic interpolates between.
+ */
+
+public class Static3D extends Static2D  implements Data3D
+  {
+  float z;
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the three floats to (vx,vy,vz).   
+ *   
+ * @param vx value of the first float.
+ * @param vy value of the second float.
+ * @param vz value of the third float.
+ */ 
+  public Static3D(int vx, int vy, int vz)
+    {
+    super(vx,vy);
+    z = vz;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the three floats to (vx,vy,vz).   
+ *   
+ * @param vx value of the first float.
+ * @param vy value of the second float.
+ * @param vz value of the third float.
+ */ 
+  public Static3D(float vx, float vy, float vz)
+    {
+    super(vx,vy);
+    z = vz;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Reset the value of the floats to (vx,vy,vz).
+ * 
+ * @param vx new value of the first float
+ * @param vy new value of the second float
+ * @param vz new value of the third float
+ */
+  public void set(int vx, int vy, int vz)
+    {
+    x = vx;
+    y = vy;
+    z = vz;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Reset the value of the floats to (vx,vy,vz).
+ * 
+ * @param vx new value of the first float
+ * @param vy new value of the second float
+ * @param vz new value of the third float
+ */
+  public void set(float vx, float vy, float vz)
+    {
+    x = vx;
+    y = vy;
+    z = vz;
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Return the value of the third float contained.
+ * 
+ * @return The third float.
+ */
+  public float getZ()
+    {
+    return z;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// end of class   
+  }
diff --git a/src/main/java/org/distorted/library/type/Static4D.java b/src/main/java/org/distorted/library/type/Static4D.java
new file mode 100644
index 0000000..6c92182
--- /dev/null
+++ b/src/main/java/org/distorted/library/type/Static4D.java
@@ -0,0 +1,110 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.type;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A 4-dimensional data structure containing four floats. The floats have no particular meaning; 
+ * when this data structure is used in Dynamics, we can think of it as a 4-dimensional Point
+ * a few of which the Dynamic interpolates between.
+ */
+
+public class Static4D extends Static3D implements Data4D
+  {
+  float w;
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the four floats to (vx,vy,vz,vw).   
+ *   
+ * @param vx value of the first float.
+ * @param vy value of the second float.
+ * @param vz value of the third float.
+ * @param vw value of the fourth float.
+ */ 
+  public Static4D(int vx, int vy, int vz, int vw)
+    {
+    super(vx,vy,vz);
+    w = vw;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor that initialises the value of the four floats to (vx,vy,vz,vw).   
+ *   
+ * @param vx value of the first float.
+ * @param vy value of the second float.
+ * @param vz value of the third float.
+ * @param vw value of the fourth float.
+ */ 
+  public Static4D(float vx, float vy, float vz, float vw)
+    {
+    super(vx,vy,vz);
+    w = vw;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Reset the value of the floats to (vx,vy,vz,vw).
+ * 
+ * @param vx new value of the first float
+ * @param vy new value of the second float
+ * @param vz new value of the third float
+ * @param vw new value of the fourth float
+ */
+  public void set(int vx, int vy, int vz, int vw)
+    {
+    x = vx;
+    y = vy;
+    z = vz;
+    w = vw;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Reset the value of the floats to (vx,vy,vz,vw).
+ * 
+ * @param vx new value of the first float
+ * @param vy new value of the second float
+ * @param vz new value of the third float
+ * @param vw new value of the fourth float
+ */
+  public void set(float vx, float vy, float vz, float vw)
+    {
+    x = vx;
+    y = vy;
+    z = vz;
+    w = vw;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Return the value of the fourth float contained.
+ * 
+ * @return The fourth float.
+ */
+  public float getW()
+    {
+    return w;  
+    }
+  
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// end of class   
+  }
