commit 9aabc9eb2384ddb390f585b756faff9ce3188e8f
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Jun 1 12:02:38 2021 +0200

    Dynamics: introduce two speed modes - smooth and segment_constant.
    Prepare the third mode - globally_constant.

diff --git a/src/main/java/org/distorted/library/type/Dynamic.java b/src/main/java/org/distorted/library/type/Dynamic.java
index 2138494..0cf4977 100644
--- a/src/main/java/org/distorted/library/type/Dynamic.java
+++ b/src/main/java/org/distorted/library/type/Dynamic.java
@@ -55,6 +55,22 @@ import java.util.Vector;
 
 public abstract class Dynamic
   {
+  /**
+   * Keep the speed of interpolation always changing. Time to cover one segment (distance between
+   * two consecutive points) always the same. Smoothly interpolate the speed between two segments.
+   */
+  public static final int SPEED_MODE_SMOOTH            = 0;
+  /**
+   * Make each segment have constant speed. Time to cover each segment is still the same, thus the
+   * speed will jump when passing through a point and then keep constant.
+   */
+  public static final int SPEED_MODE_SEGMENT_CONSTANT  = 1;
+  /**
+   * Have the speed be always, globally the same across all segments. Time to cover one segment will
+   * thus generally no longer be the same.
+   */
+  public static final int SPEED_MODE_GLOBALLY_CONSTANT = 2;
+
   /**
    * One revolution takes us from the first point to the last and back to first through the shortest path.
    */
@@ -92,6 +108,7 @@ public abstract class Dynamic
   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 double mLastPos;
   protected int mAccessType;
+  protected int mSpeedMode;
 
   protected class VectorNoise
     {
@@ -123,8 +140,8 @@ public abstract class Dynamic
   protected float[][] baseV;
 
   ///////////////////////////////////////////////////////////////////////////////////////////////////
-  // the coefficients of the X(t), Y(t) and Z(t) polynomials: X(t) = ax*T^3 + bx*T^2 + cx*t + dx  etc.
-  // (tangent) is the vector tangent to the path.
+  // the coefficients of the X(t), Y(t) and Z(t) polynomials: X(t) = a[0]*T^3 + b[0]*T^2 + c[0]*t + d[0]  etc.
+  // (velocity) is the velocity vector.
   // (cached) 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
 
@@ -134,8 +151,9 @@ public abstract class Dynamic
     float[] b;
     float[] c;
     float[] d;
-    float[] tangent;
+    float[] velocity;
     float[] cached;
+    float[] path_ratio;
 
     VectorCache()
       {
@@ -143,15 +161,22 @@ public abstract class Dynamic
       b = new float[mDimension];
       c = new float[mDimension];
       d = new float[mDimension];
-      tangent = new float[mDimension];
-      cached = new float[mDimension];
+
+      velocity   = new float[mDimension];
+      cached     = new float[mDimension];
+      path_ratio = new float[NUM_RATIO];
       }
     }
 
   protected Vector<VectorCache> vc;
-  protected VectorCache tmp1, tmp2;
+  protected VectorCache tmpCache1, tmpCache2;
   protected float mConvexity;
 
+  private static final int NUM_RATIO = 10; // we attempt to 'smooth out' the speed in each segment -
+                                           // remember this many 'points' inside the Cache for each segment.
+
+  protected static final float[] mTmpRatio = new float[NUM_RATIO];
+
   private float[] buf;
   private float[] old;
   private static final Random mRnd = new Random();
@@ -184,6 +209,7 @@ public abstract class Dynamic
     mSegment   = -1;
     mLastPos   = -1;
     mAccessType= ACCESS_TYPE_RANDOM;
+    mSpeedMode = SPEED_MODE_SMOOTH;
     mConvexity = 1.0f;
     mStartTime = -1;
     mCorrectedTime = 0;
@@ -208,6 +234,85 @@ public abstract class Dynamic
     mPausedTime = System.currentTimeMillis();
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float valueAtPoint(float t, VectorCache cache)
+    {
+    float tmp,sum = 0.0f;
+
+    for(int d=0; d<mDimension; d++)
+      {
+      tmp = (3*cache.a[d]*t + 2*cache.b[d])*t + cache.c[d];
+      sum += tmp*tmp;
+      }
+
+    return (float)Math.sqrt(sum);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  protected float smoothSpeed(float time, VectorCache cache)
+    {
+    float fndex = time*NUM_RATIO;
+    int index = (int)fndex;
+    float prev = index==0 ? 0.0f : cache.path_ratio[index-1];
+    float next = cache.path_ratio[index];
+
+    return prev + (next-prev)*(fndex-index);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// First, compute the approx length of the segment from time=0 to time=(i+1)/NUM_TIME and store this
+// in cache.path_ratio[i]. Then the last path_ratio is the length from 0 to 1, i.e. the total length
+// of the segment.
+// We do this by computing the integral from 0 to 1 of sqrt( (dx/dt)^2 + (dy/dt)^2 ) (i.e. the length
+// of the segment) using the approx 'trapezoids' integration method.
+//
+// Then, for every i, divide path_ratio[i] by the total length to get the percentage of total path
+// length covered at time i. At this time, path_ratio[3] = 0.45 means 'at time 3/NUM_RATIO, we cover
+// 0.45 = 45% of the total length of the segment.
+//
+// Finally, invert this function (for quicker lookups in smoothSpeed) so that after this step,
+// path_ratio[3] = 0.45 means 'at 45% of the time, we cover 3/NUM_RATIO distance'.
+
+  protected void smoothOutSegment(VectorCache cache)
+    {
+    float vPrev, sum = 0.0f;
+    float vNext = valueAtPoint(0.0f,cache);
+
+    for(int i=0; i<NUM_RATIO; i++)
+      {
+      vPrev = vNext;
+      vNext = valueAtPoint( (float)(i+1)/NUM_RATIO,cache);
+      sum += (vPrev+vNext);
+      cache.path_ratio[i] = sum;
+      }
+
+    float total = cache.path_ratio[NUM_RATIO-1];
+
+    for(int i=0; i<NUM_RATIO; i++) cache.path_ratio[i] /= total;
+
+    int writeIndex = 0;
+    float prev=0.0f, next, ratio= 1.0f/NUM_RATIO;
+
+    for(int readIndex=0; readIndex<NUM_RATIO; readIndex++)
+      {
+      next = cache.path_ratio[readIndex];
+
+      while( prev<ratio && ratio<=next )
+        {
+        float a = (next-ratio)/(next-prev);
+        mTmpRatio[writeIndex] = (readIndex+1-a)/NUM_RATIO;
+        writeIndex++;
+        ratio = (writeIndex+1.0f)/NUM_RATIO;
+        }
+
+      prev = next;
+      }
+
+    System.arraycopy(mTmpRatio, 0, cache.path_ratio, 0, NUM_RATIO);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   protected float noise(float time,int vecNum)
@@ -340,28 +445,6 @@ public abstract class Dynamic
 
     if( cosA<0.0f )
       {
-/*
-      /// DEBUGGING ////
-      String s = index+" (";
-      float t;
-
-      for(int j=0; j<mDimension; j++)
-        {
-        t = ((int)(100*baseV[index][j]))/(100.0f);
-        s+=(" "+t);
-        }
-      s += ") (";
-
-      for(int j=0; j<mDimension; j++)
-        {
-        t = ((int)(100*old[j]))/(100.0f);
-        s+=(" "+t);
-        }
-      s+= ")";
-
-      android.util.Log.e("dynamic", "kat: " + s);
-      /// END DEBUGGING ///
-*/
       for(int j=0; j<mDimension; j++)
         baseV[index][j] = -baseV[index][j];
       }
@@ -658,6 +741,39 @@ public abstract class Dynamic
     mLastPos = -1;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * @return See {@link Dynamic#setSpeedMode(int)}
+ */
+  public float getSpeedMode()
+    {
+    return mSpeedMode;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Sets the way we compute the interpolation speed.
+ *
+ * @param mode {@link Dynamic#SPEED_MODE_SMOOTH} or {@link Dynamic#SPEED_MODE_SEGMENT_CONSTANT} or
+ *             {@link Dynamic#SPEED_MODE_GLOBALLY_CONSTANT}
+ */
+  public void setSpeedMode(int mode)
+    {
+    if( mSpeedMode!=mode )
+      {
+      if( mSpeedMode==SPEED_MODE_SMOOTH )
+        {
+        for(int i=0; i<numPoints; i++)
+          {
+          tmpCache1 = vc.elementAt(i);
+          smoothOutSegment(tmpCache1);
+          }
+        }
+
+      mSpeedMode = mode;
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Return the Dimension, ie number of floats in a single Point this Dynamic interpolates through.
diff --git a/src/main/java/org/distorted/library/type/Dynamic1D.java b/src/main/java/org/distorted/library/type/Dynamic1D.java
index bfb9859..1e2e2e1 100644
--- a/src/main/java/org/distorted/library/type/Dynamic1D.java
+++ b/src/main/java/org/distorted/library/type/Dynamic1D.java
@@ -44,7 +44,7 @@ public class Dynamic1D extends Dynamic implements Data1D
     curr = vv.elementAt(c);
     next = vv.elementAt(n);
 
-    tmp1 = vc.elementAt(c);
+    tmpCache1 = vc.elementAt(c);
     
     float px = curr.x - prev.x;
     float nx = next.x - curr.x;
@@ -57,16 +57,16 @@ public class Dynamic1D extends Dynamic implements Data1D
       
       if( q>1 )
         {
-        tmp1.tangent[0] = nx+px/q;
+        tmpCache1.velocity[0] = nx+px/q;
         }
       else
         {
-        tmp1.tangent[0] = px+nx*q;
+        tmpCache1.velocity[0] = px+nx*q;
         }
       }
     else
       {
-      tmp1.tangent[0] = 0.0f;
+      tmpCache1.velocity[0] = 0.0f;
       }
     }
       
@@ -76,30 +76,30 @@ public class Dynamic1D extends Dynamic implements Data1D
     {  
     if( numPoints==1 )
       {
-      tmp1= vc.elementAt(0);
+      tmpCache1 = vc.elementAt(0);
       curr= vv.elementAt(0);
         
-      tmp1.a[0] = 0.0f;
-      tmp1.b[0] = 0.0f;
-      tmp1.c[0] = curr.x;
-      tmp1.d[0] = 0.0f;
+      tmpCache1.a[0] = 0.0f;
+      tmpCache1.b[0] = 0.0f;
+      tmpCache1.c[0] = curr.x;
+      tmpCache1.d[0] = 0.0f;
       }
     else if( numPoints==2 )
       {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
+      tmpCache1 = vc.elementAt(0);
+      tmpCache2 = vc.elementAt(1);
       curr= vv.elementAt(0);
       next= vv.elementAt(1);
           
-      tmp1.a[0] = 0.0f;
-      tmp1.b[0] = 0.0f;
-      tmp1.c[0] = next.x - curr.x;
-      tmp1.d[0] = curr.x;
+      tmpCache1.a[0] = 0.0f;
+      tmpCache1.b[0] = 0.0f;
+      tmpCache1.c[0] = next.x - curr.x;
+      tmpCache1.d[0] = curr.x;
       
-      tmp2.a[0] = 0.0f;
-      tmp2.b[0] = 0.0f;
-      tmp2.c[0] = curr.x - next.x;
-      tmp2.d[0] = next.x;
+      tmpCache2.a[0] = 0.0f;
+      tmpCache2.b[0] = 0.0f;
+      tmpCache2.c[0] = curr.x - next.x;
+      tmpCache2.d[0] = next.x;
       }
     else
       {
@@ -111,17 +111,19 @@ public class Dynamic1D extends Dynamic implements Data1D
         {
         n = i<numPoints-1 ? i+1:0;  
       
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
+        tmpCache1 = vc.elementAt(i);
+        tmpCache2 = vc.elementAt(n);
         curr= vv.elementAt(i);
         next= vv.elementAt(n);
     
-        tmp1.cached[0] = curr.x;
+        tmpCache1.cached[0] = curr.x;
         
-        tmp1.a[0] = mConvexity*( 2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0]);
-        tmp1.b[0] = mConvexity*(-3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0]);
-        tmp1.c[0] = mConvexity*(tmp1.tangent[0]) + (1.0f-mConvexity)*(next.x-curr.x);
-        tmp1.d[0] = curr.x;
+        tmpCache1.a[0] = mConvexity*( 2*curr.x +   tmpCache1.velocity[0] - 2*next.x + tmpCache2.velocity[0]);
+        tmpCache1.b[0] = mConvexity*(-3*curr.x - 2* tmpCache1.velocity[0] + 3*next.x - tmpCache2.velocity[0]);
+        tmpCache1.c[0] = mConvexity*(tmpCache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x);
+        tmpCache1.d[0] = curr.x;
+
+        if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) smoothOutSegment(tmpCache1);
         }
       }
    
@@ -442,25 +444,24 @@ public class Dynamic1D extends Dynamic implements Data1D
                   {
                   int vecNext = getNext(vecCurr,t);
                   next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
+                  tmpCache2 = vc.elementAt(vecNext);
               
-                  if( tmp2.cached[0]!=next.x ) recomputeCache();
+                  if( tmpCache2.cached[0]!=next.x ) recomputeCache();
                   }
 
                 if( mSegment!= segment && vn!=null ) vn.elementAt(vecCurr).computeNoise();
 
                 mSegment = segment;
-
                 time = time-vecCurr;
-
-                tmp1 = vc.elementAt(vecCurr);
+                tmpCache1 = vc.elementAt(vecCurr);
+                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
 
                 if( vn!=null )
                   {
                   time = noise(time,vecCurr);
                   }
             
-                buffer[offset] = ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
+                buffer[offset] = ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
                 break;
                 }
         }
diff --git a/src/main/java/org/distorted/library/type/Dynamic2D.java b/src/main/java/org/distorted/library/type/Dynamic2D.java
index 914d815..6c97d79 100644
--- a/src/main/java/org/distorted/library/type/Dynamic2D.java
+++ b/src/main/java/org/distorted/library/type/Dynamic2D.java
@@ -44,7 +44,7 @@ public class Dynamic2D extends Dynamic implements Data2D
     curr = vv.elementAt(c);
     next = vv.elementAt(n);
 
-    tmp1 = vc.elementAt(c);
+    tmpCache1 = vc.elementAt(c);
     
     float px = curr.x - prev.x;
     float py = curr.y - prev.y;
@@ -59,19 +59,19 @@ public class Dynamic2D extends Dynamic implements Data2D
       
       if( q>1 )
         {
-        tmp1.tangent[0] = nx+px/q;
-        tmp1.tangent[1] = ny+py/q;
+        tmpCache1.velocity[0] = nx+px/q;
+        tmpCache1.velocity[1] = ny+py/q;
         }
       else
         {
-        tmp1.tangent[0] = px+nx*q;
-        tmp1.tangent[1] = py+ny*q;
+        tmpCache1.velocity[0] = px+nx*q;
+        tmpCache1.velocity[1] = py+ny*q;
         }
       }
     else
       {
-      tmp1.tangent[0] = 0.0f;
-      tmp1.tangent[1] = 0.0f;
+      tmpCache1.velocity[0] = 0.0f;
+      tmpCache1.velocity[1] = 0.0f;
       }
     }
    
@@ -81,35 +81,35 @@ public class Dynamic2D extends Dynamic implements Data2D
     {  
     if( numPoints==1 )
       {
-      tmp1= vc.elementAt(0);
+      tmpCache1 = vc.elementAt(0);
       curr= vv.elementAt(0);
               
-      tmp1.a[0] = tmp1.a[1] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = 0.0f;
-      tmp1.c[0] = curr.x;
-      tmp1.c[1] = curr.y;
-      tmp1.d[0] = tmp1.d[1] = 0.0f;
+      tmpCache1.a[0] = tmpCache1.a[1] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = 0.0f;
+      tmpCache1.c[0] = curr.x;
+      tmpCache1.c[1] = curr.y;
+      tmpCache1.d[0] = tmpCache1.d[1] = 0.0f;
       }
     else if( numPoints==2 )
       {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
+      tmpCache1 = vc.elementAt(0);
+      tmpCache2 = vc.elementAt(1);
       curr= vv.elementAt(0);
       next= vv.elementAt(1);
           
-      tmp1.a[0] = tmp1.a[1] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = 0.0f;
-      tmp1.c[0] = next.x - curr.x;
-      tmp1.c[1] = next.y - curr.y;
-      tmp1.d[0] = curr.x;
-      tmp1.d[1] = curr.y;
+      tmpCache1.a[0] = tmpCache1.a[1] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = 0.0f;
+      tmpCache1.c[0] = next.x - curr.x;
+      tmpCache1.c[1] = next.y - curr.y;
+      tmpCache1.d[0] = curr.x;
+      tmpCache1.d[1] = curr.y;
       
-      tmp2.a[0] = tmp2.a[1] = 0.0f;
-      tmp2.b[0] = tmp2.b[1] = 0.0f;
-      tmp2.c[0] = curr.x - next.x;
-      tmp2.c[1] = curr.y - next.y;
-      tmp2.d[0] = next.x;
-      tmp2.d[1] = next.y;
+      tmpCache2.a[0] = tmpCache2.a[1] = 0.0f;
+      tmpCache2.b[0] = tmpCache2.b[1] = 0.0f;
+      tmpCache2.c[0] = curr.x - next.x;
+      tmpCache2.c[1] = curr.y - next.y;
+      tmpCache2.d[0] = next.x;
+      tmpCache2.d[1] = next.y;
       }
     else
       {
@@ -121,23 +121,25 @@ public class Dynamic2D extends Dynamic implements Data2D
         {
         n = i<numPoints-1 ? i+1:0;  
       
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
+        tmpCache1 = vc.elementAt(i);
+        tmpCache2 = vc.elementAt(n);
         curr= vv.elementAt(i);
         next= vv.elementAt(n);
       
-        tmp1.cached[0] = curr.x;
-        tmp1.cached[1] = curr.y;
-
-        tmp1.a[0] = mConvexity*( 2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0]);
-        tmp1.b[0] = mConvexity*(-3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0]);
-        tmp1.c[0] = mConvexity*(tmp1.tangent[0]) + (1.0f-mConvexity)*(next.x-curr.x);
-        tmp1.d[0] = curr.x;
-
-        tmp1.a[1] = mConvexity*( 2*curr.y +   tmp1.tangent[1] - 2*next.y + tmp2.tangent[1]);
-        tmp1.b[1] = mConvexity*(-3*curr.y - 2*tmp1.tangent[1] + 3*next.y - tmp2.tangent[1]);
-        tmp1.c[1] = mConvexity*(tmp1.tangent[1]) + (1.0f-mConvexity)*(next.y-curr.y);
-        tmp1.d[1] = curr.y;
+        tmpCache1.cached[0] = curr.x;
+        tmpCache1.cached[1] = curr.y;
+
+        tmpCache1.a[0] = mConvexity*( 2*curr.x +   tmpCache1.velocity[0] - 2*next.x + tmpCache2.velocity[0]);
+        tmpCache1.b[0] = mConvexity*(-3*curr.x - 2* tmpCache1.velocity[0] + 3*next.x - tmpCache2.velocity[0]);
+        tmpCache1.c[0] = mConvexity*(tmpCache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x);
+        tmpCache1.d[0] = curr.x;
+
+        tmpCache1.a[1] = mConvexity*( 2*curr.y +   tmpCache1.velocity[1] - 2*next.y + tmpCache2.velocity[1]);
+        tmpCache1.b[1] = mConvexity*(-3*curr.y - 2* tmpCache1.velocity[1] + 3*next.y - tmpCache2.velocity[1]);
+        tmpCache1.c[1] = mConvexity*(tmpCache1.velocity[1]) + (1.0f-mConvexity)*(next.y-curr.y);
+        tmpCache1.d[1] = curr.y;
+
+        if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) smoothOutSegment(tmpCache1);
         }
       }
     
@@ -475,32 +477,32 @@ public class Dynamic2D extends Dynamic implements Data2D
                   {
                   int vecNext = getNext(vecCurr,t);
                   next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
+                  tmpCache2 = vc.elementAt(vecNext);
 
-                  if( tmp2.cached[0]!=next.x || tmp2.cached[1]!=next.y ) recomputeCache();
+                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y ) recomputeCache();
                   }
 
                 if( mSegment!= segment && vn!=null ) vn.elementAt(vecCurr).computeNoise();
 
                 mSegment = segment;
-
                 time = time-vecCurr;
-                tmp1 = vc.elementAt(vecCurr);
+                tmpCache1 = vc.elementAt(vecCurr);
+                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
 
                 if( vn!=null )
                   {
                   time = noise(time,vecCurr);
 
-                  baseV[1][0] = (3*tmp1.a[0]*time+2*tmp1.b[0])*time + tmp1.c[0];
-                  baseV[1][1] = (3*tmp1.a[1]*time+2*tmp1.b[1])*time + tmp1.c[1];
+                  baseV[1][0] = (3* tmpCache1.a[0]*time+2* tmpCache1.b[0])*time + tmpCache1.c[0];
+                  baseV[1][1] = (3* tmpCache1.a[1]*time+2* tmpCache1.b[1])*time + tmpCache1.c[1];
                  
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0] +baseV[1][1]*mFactor[0];
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1] -baseV[1][0]*mFactor[0];
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0] +baseV[1][1]*mFactor[0];
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1] -baseV[1][0]*mFactor[0];
                   } 
                 else
                   {
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1];
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1];
                   }
                 
                 break;
diff --git a/src/main/java/org/distorted/library/type/Dynamic3D.java b/src/main/java/org/distorted/library/type/Dynamic3D.java
index a01c2c7..4322d4f 100644
--- a/src/main/java/org/distorted/library/type/Dynamic3D.java
+++ b/src/main/java/org/distorted/library/type/Dynamic3D.java
@@ -44,7 +44,7 @@ public class Dynamic3D extends Dynamic implements Data3D
     curr = vv.elementAt(c);
     next = vv.elementAt(n);
 
-    tmp1 = vc.elementAt(c);
+    tmpCache1 = vc.elementAt(c);
     
     float px = curr.x - prev.x;
     float py = curr.y - prev.y;
@@ -61,22 +61,22 @@ public class Dynamic3D extends Dynamic implements Data3D
       
       if( q>1 )
         {
-        tmp1.tangent[0] = nx+px/q;
-        tmp1.tangent[1] = ny+py/q;
-        tmp1.tangent[2] = nz+pz/q;
+        tmpCache1.velocity[0] = nx+px/q;
+        tmpCache1.velocity[1] = ny+py/q;
+        tmpCache1.velocity[2] = nz+pz/q;
         }
       else
         {
-        tmp1.tangent[0] = px+nx*q;
-        tmp1.tangent[1] = py+ny*q;
-        tmp1.tangent[2] = pz+nz*q;
+        tmpCache1.velocity[0] = px+nx*q;
+        tmpCache1.velocity[1] = py+ny*q;
+        tmpCache1.velocity[2] = pz+nz*q;
         }
       }
     else
       {
-      tmp1.tangent[0] = 0.0f;
-      tmp1.tangent[1] = 0.0f;
-      tmp1.tangent[2] = 0.0f;
+      tmpCache1.velocity[0] = 0.0f;
+      tmpCache1.velocity[1] = 0.0f;
+      tmpCache1.velocity[2] = 0.0f;
       }
     }
     
@@ -86,40 +86,40 @@ public class Dynamic3D extends Dynamic implements Data3D
     {  
     if( numPoints==1 )
       {
-      tmp1= vc.elementAt(0);
+      tmpCache1 = vc.elementAt(0);
       curr= vv.elementAt(0);
         
-      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = 0.0f;
-      tmp1.c[0] = curr.x;
-      tmp1.c[1] = curr.y;
-      tmp1.c[2] = curr.z;
-      tmp1.d[0] = tmp1.d[1] = tmp1.d[2] = 0.0f;
+      tmpCache1.a[0] = tmpCache1.a[1] = tmpCache1.a[2] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = tmpCache1.b[2] = 0.0f;
+      tmpCache1.c[0] = curr.x;
+      tmpCache1.c[1] = curr.y;
+      tmpCache1.c[2] = curr.z;
+      tmpCache1.d[0] = tmpCache1.d[1] = tmpCache1.d[2] = 0.0f;
       }
     else if( numPoints==2 )
       {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
+      tmpCache1 = vc.elementAt(0);
+      tmpCache2 = vc.elementAt(1);
       curr= vv.elementAt(0);
       next= vv.elementAt(1);
           
-      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = 0.0f;
-      tmp1.c[0] = next.x - curr.x;
-      tmp1.c[1] = next.y - curr.y;
-      tmp1.c[2] = next.z - curr.z;
-      tmp1.d[0] = curr.x;
-      tmp1.d[1] = curr.y;
-      tmp1.d[2] = curr.z;
+      tmpCache1.a[0] = tmpCache1.a[1] = tmpCache1.a[2] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = tmpCache1.b[2] = 0.0f;
+      tmpCache1.c[0] = next.x - curr.x;
+      tmpCache1.c[1] = next.y - curr.y;
+      tmpCache1.c[2] = next.z - curr.z;
+      tmpCache1.d[0] = curr.x;
+      tmpCache1.d[1] = curr.y;
+      tmpCache1.d[2] = curr.z;
       
-      tmp2.a[0] = tmp2.a[1] = tmp2.a[2] = 0.0f;
-      tmp2.b[0] = tmp2.b[1] = tmp2.b[2] = 0.0f;
-      tmp2.c[0] = curr.x - next.x;
-      tmp2.c[1] = curr.y - next.y;
-      tmp2.c[2] = curr.z - next.z;
-      tmp2.d[0] = next.x;
-      tmp2.d[1] = next.y;
-      tmp2.d[2] = next.z;
+      tmpCache2.a[0] = tmpCache2.a[1] = tmpCache2.a[2] = 0.0f;
+      tmpCache2.b[0] = tmpCache2.b[1] = tmpCache2.b[2] = 0.0f;
+      tmpCache2.c[0] = curr.x - next.x;
+      tmpCache2.c[1] = curr.y - next.y;
+      tmpCache2.c[2] = curr.z - next.z;
+      tmpCache2.d[0] = next.x;
+      tmpCache2.d[1] = next.y;
+      tmpCache2.d[2] = next.z;
       }
     else
       {
@@ -131,29 +131,31 @@ public class Dynamic3D extends Dynamic implements Data3D
         {
         n = i<numPoints-1 ? i+1:0;  
       
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
+        tmpCache1 = vc.elementAt(i);
+        tmpCache2 = vc.elementAt(n);
         curr= vv.elementAt(i);
         next= vv.elementAt(n);
       
-        tmp1.cached[0] = curr.x;
-        tmp1.cached[1] = curr.y;
-        tmp1.cached[2] = curr.z;
+        tmpCache1.cached[0] = curr.x;
+        tmpCache1.cached[1] = curr.y;
+        tmpCache1.cached[2] = curr.z;
         
-        tmp1.a[0] = mConvexity*( 2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0]);
-        tmp1.b[0] = mConvexity*(-3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0]);
-        tmp1.c[0] = mConvexity*(tmp1.tangent[0]) + (1.0f-mConvexity)*(next.x-curr.x);
-        tmp1.d[0] = curr.x;
+        tmpCache1.a[0] = mConvexity*( 2*curr.x +   tmpCache1.velocity[0] - 2*next.x + tmpCache2.velocity[0]);
+        tmpCache1.b[0] = mConvexity*(-3*curr.x - 2* tmpCache1.velocity[0] + 3*next.x - tmpCache2.velocity[0]);
+        tmpCache1.c[0] = mConvexity*(tmpCache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x);
+        tmpCache1.d[0] = curr.x;
       
-        tmp1.a[1] = mConvexity*( 2*curr.y +   tmp1.tangent[1] - 2*next.y + tmp2.tangent[1]);
-        tmp1.b[1] = mConvexity*(-3*curr.y - 2*tmp1.tangent[1] + 3*next.y - tmp2.tangent[1]);
-        tmp1.c[1] = mConvexity*(tmp1.tangent[1]) + (1.0f-mConvexity)*(next.y-curr.y);
-        tmp1.d[1] = curr.y;
+        tmpCache1.a[1] = mConvexity*( 2*curr.y +   tmpCache1.velocity[1] - 2*next.y + tmpCache2.velocity[1]);
+        tmpCache1.b[1] = mConvexity*(-3*curr.y - 2* tmpCache1.velocity[1] + 3*next.y - tmpCache2.velocity[1]);
+        tmpCache1.c[1] = mConvexity*(tmpCache1.velocity[1]) + (1.0f-mConvexity)*(next.y-curr.y);
+        tmpCache1.d[1] = curr.y;
       
-        tmp1.a[2] = mConvexity*( 2*curr.z +   tmp1.tangent[2] - 2*next.z + tmp2.tangent[2]);
-        tmp1.b[2] = mConvexity*(-3*curr.z - 2*tmp1.tangent[2] + 3*next.z - tmp2.tangent[2]);
-        tmp1.c[2] = mConvexity*(tmp1.tangent[2]) + (1.0f-mConvexity)*(next.z-curr.z);
-        tmp1.d[2] = curr.z;
+        tmpCache1.a[2] = mConvexity*( 2*curr.z +   tmpCache1.velocity[2] - 2*next.z + tmpCache2.velocity[2]);
+        tmpCache1.b[2] = mConvexity*(-3*curr.z - 2* tmpCache1.velocity[2] + 3*next.z - tmpCache2.velocity[2]);
+        tmpCache1.c[2] = mConvexity*(tmpCache1.velocity[2]) + (1.0f-mConvexity)*(next.z-curr.z);
+        tmpCache1.d[2] = curr.z;
+
+        if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) smoothOutSegment(tmpCache1);
         }
       }
    
@@ -499,34 +501,33 @@ public class Dynamic3D extends Dynamic implements Data3D
                   {
                   int vecNext = getNext(vecCurr,t);
                   next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
+                  tmpCache2 = vc.elementAt(vecNext);
 
-                  if( tmp2.cached[0]!=next.x || tmp2.cached[1]!=next.y || tmp2.cached[2]!=next.z ) recomputeCache();
+                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y || tmpCache2.cached[2]!=next.z ) recomputeCache();
                   }
 
                 if( mSegment!= segment && vn!=null ) vn.elementAt(vecCurr).computeNoise();
 
                 mSegment = segment;
-
                 time = time-vecCurr;
-            
-                tmp1 = vc.elementAt(vecCurr);
+                tmpCache1 = vc.elementAt(vecCurr);
+                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
 
                 if( vn!=null )
                   {
                   time = noise(time,vecCurr);
               
-                  computeOrthonormalBaseMore(time,tmp1);
+                  computeOrthonormalBaseMore(time, tmpCache1);
                  
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1]);
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1]);
-                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1]);
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1]);
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1]);
+                  buffer[offset+2]= ((tmpCache1.a[2]*time+ tmpCache1.b[2])*time+ tmpCache1.c[2])*time+ tmpCache1.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1]);
                   }
                 else
                   {
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1];
-                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2];
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1];
+                  buffer[offset+2]= ((tmpCache1.a[2]*time+ tmpCache1.b[2])*time+ tmpCache1.c[2])*time+ tmpCache1.d[2];
                   }
                
                 break;
diff --git a/src/main/java/org/distorted/library/type/Dynamic4D.java b/src/main/java/org/distorted/library/type/Dynamic4D.java
index dd4d6a4..53f448c 100644
--- a/src/main/java/org/distorted/library/type/Dynamic4D.java
+++ b/src/main/java/org/distorted/library/type/Dynamic4D.java
@@ -44,7 +44,7 @@ public class Dynamic4D extends Dynamic implements Data4D
     curr = vv.elementAt(c);
     next = vv.elementAt(n);
 
-    tmp1 = vc.elementAt(c);
+    tmpCache1 = vc.elementAt(c);
     
     float px = curr.x - prev.x;
     float py = curr.y - prev.y;
@@ -63,25 +63,25 @@ public class Dynamic4D extends Dynamic implements Data4D
       
       if( q>1 )
         {
-        tmp1.tangent[0] = nx+px/q;
-        tmp1.tangent[1] = ny+py/q;
-        tmp1.tangent[2] = nz+pz/q;
-        tmp1.tangent[3] = nw+pw/q;
+        tmpCache1.velocity[0] = nx+px/q;
+        tmpCache1.velocity[1] = ny+py/q;
+        tmpCache1.velocity[2] = nz+pz/q;
+        tmpCache1.velocity[3] = nw+pw/q;
         }
       else
         {
-        tmp1.tangent[0] = px+nx*q;
-        tmp1.tangent[1] = py+ny*q;
-        tmp1.tangent[2] = pz+nz*q;
-        tmp1.tangent[3] = pw+nw*q;
+        tmpCache1.velocity[0] = px+nx*q;
+        tmpCache1.velocity[1] = py+ny*q;
+        tmpCache1.velocity[2] = pz+nz*q;
+        tmpCache1.velocity[3] = pw+nw*q;
         }
       }
     else
       {
-      tmp1.tangent[0] = 0.0f;
-      tmp1.tangent[1] = 0.0f;
-      tmp1.tangent[2] = 0.0f;
-      tmp1.tangent[3] = 0.0f;
+      tmpCache1.velocity[0] = 0.0f;
+      tmpCache1.velocity[1] = 0.0f;
+      tmpCache1.velocity[2] = 0.0f;
+      tmpCache1.velocity[3] = 0.0f;
       }
     }
     
@@ -91,45 +91,45 @@ public class Dynamic4D extends Dynamic implements Data4D
     {  
     if( numPoints==1 )
       {
-      tmp1= vc.elementAt(0);
+      tmpCache1 = vc.elementAt(0);
       curr= vv.elementAt(0);
         
-      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = tmp1.a[3] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = tmp1.b[3] = 0.0f;
-      tmp1.c[0] = curr.x;
-      tmp1.c[1] = curr.y;
-      tmp1.c[2] = curr.z;
-      tmp1.c[3] = curr.w;
-      tmp1.d[0] = tmp1.d[1] = tmp1.d[3] = tmp1.d[3] = 0.0f;
+      tmpCache1.a[0] = tmpCache1.a[1] = tmpCache1.a[2] = tmpCache1.a[3] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = tmpCache1.b[2] = tmpCache1.b[3] = 0.0f;
+      tmpCache1.c[0] = curr.x;
+      tmpCache1.c[1] = curr.y;
+      tmpCache1.c[2] = curr.z;
+      tmpCache1.c[3] = curr.w;
+      tmpCache1.d[0] = tmpCache1.d[1] = tmpCache1.d[3] = tmpCache1.d[3] = 0.0f;
       }
     else if( numPoints==2 )
       {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
+      tmpCache1 = vc.elementAt(0);
+      tmpCache2 = vc.elementAt(1);
       curr= vv.elementAt(0);
       next= vv.elementAt(1);
       
-      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = tmp1.a[3] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = tmp1.b[3] = 0.0f;
-      tmp1.c[0] = next.x - curr.x;
-      tmp1.c[1] = next.y - curr.y;
-      tmp1.c[2] = next.z - curr.z;
-      tmp1.c[3] = next.w - curr.w;
-      tmp1.d[0] = curr.x;
-      tmp1.d[1] = curr.y;
-      tmp1.d[2] = curr.z;
-      tmp1.d[3] = curr.w;
+      tmpCache1.a[0] = tmpCache1.a[1] = tmpCache1.a[2] = tmpCache1.a[3] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = tmpCache1.b[2] = tmpCache1.b[3] = 0.0f;
+      tmpCache1.c[0] = next.x - curr.x;
+      tmpCache1.c[1] = next.y - curr.y;
+      tmpCache1.c[2] = next.z - curr.z;
+      tmpCache1.c[3] = next.w - curr.w;
+      tmpCache1.d[0] = curr.x;
+      tmpCache1.d[1] = curr.y;
+      tmpCache1.d[2] = curr.z;
+      tmpCache1.d[3] = curr.w;
       
-      tmp2.a[0] = tmp2.a[1] = tmp2.a[2] = tmp2.a[3] = 0.0f;
-      tmp2.b[0] = tmp2.b[1] = tmp2.b[2] = tmp2.b[3] = 0.0f;
-      tmp2.c[0] = curr.x - next.x;
-      tmp2.c[1] = curr.y - next.y;
-      tmp2.c[2] = curr.z - next.z;
-      tmp2.c[3] = curr.w - next.w;
-      tmp2.d[0] = next.x;
-      tmp2.d[1] = next.y;
-      tmp2.d[2] = next.z;
-      tmp2.d[3] = next.w;
+      tmpCache2.a[0] = tmpCache2.a[1] = tmpCache2.a[2] = tmpCache2.a[3] = 0.0f;
+      tmpCache2.b[0] = tmpCache2.b[1] = tmpCache2.b[2] = tmpCache2.b[3] = 0.0f;
+      tmpCache2.c[0] = curr.x - next.x;
+      tmpCache2.c[1] = curr.y - next.y;
+      tmpCache2.c[2] = curr.z - next.z;
+      tmpCache2.c[3] = curr.w - next.w;
+      tmpCache2.d[0] = next.x;
+      tmpCache2.d[1] = next.y;
+      tmpCache2.d[2] = next.z;
+      tmpCache2.d[3] = next.w;
       }
     else
       {
@@ -141,35 +141,37 @@ public class Dynamic4D extends Dynamic implements Data4D
         {
         n = i<numPoints-1 ? i+1:0;  
       
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
+        tmpCache1 = vc.elementAt(i);
+        tmpCache2 = vc.elementAt(n);
         curr= vv.elementAt(i);
         next= vv.elementAt(n);
       
-        tmp1.cached[0] = curr.x;
-        tmp1.cached[1] = curr.y;
-        tmp1.cached[2] = curr.z;
-        tmp1.cached[3] = curr.w;
+        tmpCache1.cached[0] = curr.x;
+        tmpCache1.cached[1] = curr.y;
+        tmpCache1.cached[2] = curr.z;
+        tmpCache1.cached[3] = curr.w;
         
-        tmp1.a[0] = mConvexity*( 2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0]);
-        tmp1.b[0] = mConvexity*(-3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0]);
-        tmp1.c[0] = mConvexity*(tmp1.tangent[0]) + (1.0f-mConvexity)*(next.x-curr.x);
-        tmp1.d[0] = curr.x;
+        tmpCache1.a[0] = mConvexity*( 2*curr.x +   tmpCache1.velocity[0] - 2*next.x + tmpCache2.velocity[0]);
+        tmpCache1.b[0] = mConvexity*(-3*curr.x - 2* tmpCache1.velocity[0] + 3*next.x - tmpCache2.velocity[0]);
+        tmpCache1.c[0] = mConvexity*(tmpCache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x);
+        tmpCache1.d[0] = curr.x;
       
-        tmp1.a[1] = mConvexity*( 2*curr.y +   tmp1.tangent[1] - 2*next.y + tmp2.tangent[1]);
-        tmp1.b[1] = mConvexity*(-3*curr.y - 2*tmp1.tangent[1] + 3*next.y - tmp2.tangent[1]);
-        tmp1.c[1] = mConvexity*(tmp1.tangent[1]) + (1.0f-mConvexity)*(next.y-curr.y);
-        tmp1.d[1] = curr.y;
+        tmpCache1.a[1] = mConvexity*( 2*curr.y +   tmpCache1.velocity[1] - 2*next.y + tmpCache2.velocity[1]);
+        tmpCache1.b[1] = mConvexity*(-3*curr.y - 2* tmpCache1.velocity[1] + 3*next.y - tmpCache2.velocity[1]);
+        tmpCache1.c[1] = mConvexity*(tmpCache1.velocity[1]) + (1.0f-mConvexity)*(next.y-curr.y);
+        tmpCache1.d[1] = curr.y;
       
-        tmp1.a[2] = mConvexity*( 2*curr.z +   tmp1.tangent[2] - 2*next.z + tmp2.tangent[2]);
-        tmp1.b[2] = mConvexity*(-3*curr.z - 2*tmp1.tangent[2] + 3*next.z - tmp2.tangent[2]);
-        tmp1.c[2] = mConvexity*(tmp1.tangent[2]) + (1.0f-mConvexity)*(next.z-curr.z);
-        tmp1.d[2] = curr.z;
+        tmpCache1.a[2] = mConvexity*( 2*curr.z +   tmpCache1.velocity[2] - 2*next.z + tmpCache2.velocity[2]);
+        tmpCache1.b[2] = mConvexity*(-3*curr.z - 2* tmpCache1.velocity[2] + 3*next.z - tmpCache2.velocity[2]);
+        tmpCache1.c[2] = mConvexity*(tmpCache1.velocity[2]) + (1.0f-mConvexity)*(next.z-curr.z);
+        tmpCache1.d[2] = curr.z;
         
-        tmp1.a[3] = mConvexity*( 2*curr.w +   tmp1.tangent[3] - 2*next.w + tmp2.tangent[3]);
-        tmp1.b[3] = mConvexity*(-3*curr.w - 2*tmp1.tangent[3] + 3*next.w - tmp2.tangent[3]);
-        tmp1.c[3] = mConvexity*(tmp1.tangent[3]) + (1.0f-mConvexity)*(next.w-curr.w);
-        tmp1.d[3] = curr.w;
+        tmpCache1.a[3] = mConvexity*( 2*curr.w +   tmpCache1.velocity[3] - 2*next.w + tmpCache2.velocity[3]);
+        tmpCache1.b[3] = mConvexity*(-3*curr.w - 2* tmpCache1.velocity[3] + 3*next.w - tmpCache2.velocity[3]);
+        tmpCache1.c[3] = mConvexity*(tmpCache1.velocity[3]) + (1.0f-mConvexity)*(next.w-curr.w);
+        tmpCache1.d[3] = curr.w;
+
+        if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) smoothOutSegment(tmpCache1);
         }
       }
    
@@ -522,36 +524,35 @@ public class Dynamic4D extends Dynamic implements Data4D
                   {
                   int vecNext = getNext(vecCurr,t);
                   next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
+                  tmpCache2 = vc.elementAt(vecNext);
 
-                  if( tmp2.cached[0]!=next.x || tmp2.cached[1]!=next.y || tmp2.cached[2]!=next.z || tmp2.cached[3]!=next.w ) recomputeCache();
+                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y || tmpCache2.cached[2]!=next.z || tmpCache2.cached[3]!=next.w ) recomputeCache();
                   }
 
                 if( mSegment!= segment && vn!=null ) vn.elementAt(vecCurr).computeNoise();
 
                 mSegment = segment;
-
                 time = time-vecCurr;
-            
-                tmp1 = vc.elementAt(vecCurr);
-               
+                tmpCache1 = vc.elementAt(vecCurr);
+                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
+
                 if( vn!=null )
                   {
                   time = noise(time,vecCurr);
               
-                  computeOrthonormalBaseMore(time,tmp1);
+                  computeOrthonormalBaseMore(time, tmpCache1);
 
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2]);
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2]);
-                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2]);
-                  buffer[offset+3]= ((tmp1.a[3]*time+tmp1.b[3])*time+tmp1.c[3])*time+tmp1.d[3] + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2]);
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2]);
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2]);
+                  buffer[offset+2]= ((tmpCache1.a[2]*time+ tmpCache1.b[2])*time+ tmpCache1.c[2])*time+ tmpCache1.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2]);
+                  buffer[offset+3]= ((tmpCache1.a[3]*time+ tmpCache1.b[3])*time+ tmpCache1.c[3])*time+ tmpCache1.d[3] + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2]);
                   }
                 else
                   {
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1];
-                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2];
-                  buffer[offset+3]= ((tmp1.a[3]*time+tmp1.b[3])*time+tmp1.c[3])*time+tmp1.d[3];
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1];
+                  buffer[offset+2]= ((tmpCache1.a[2]*time+ tmpCache1.b[2])*time+ tmpCache1.c[2])*time+ tmpCache1.d[2];
+                  buffer[offset+3]= ((tmpCache1.a[3]*time+ tmpCache1.b[3])*time+ tmpCache1.c[3])*time+ tmpCache1.d[3];
                   }
 
                 break;
diff --git a/src/main/java/org/distorted/library/type/Dynamic5D.java b/src/main/java/org/distorted/library/type/Dynamic5D.java
index 8f28d10..373505e 100644
--- a/src/main/java/org/distorted/library/type/Dynamic5D.java
+++ b/src/main/java/org/distorted/library/type/Dynamic5D.java
@@ -44,7 +44,7 @@ public class Dynamic5D extends Dynamic implements Data5D
     curr = vv.elementAt(c);
     next = vv.elementAt(n);
 
-    tmp1 = vc.elementAt(c);
+    tmpCache1 = vc.elementAt(c);
     
     float px = curr.x - prev.x;
     float py = curr.y - prev.y;
@@ -65,28 +65,28 @@ public class Dynamic5D extends Dynamic implements Data5D
       
       if( q>1 )
         {
-        tmp1.tangent[0] = nx+px/q;
-        tmp1.tangent[1] = ny+py/q;
-        tmp1.tangent[2] = nz+pz/q;
-        tmp1.tangent[3] = nw+pw/q;
-        tmp1.tangent[4] = nv+pv/q;
+        tmpCache1.velocity[0] = nx+px/q;
+        tmpCache1.velocity[1] = ny+py/q;
+        tmpCache1.velocity[2] = nz+pz/q;
+        tmpCache1.velocity[3] = nw+pw/q;
+        tmpCache1.velocity[4] = nv+pv/q;
         }
       else
         {
-        tmp1.tangent[0] = px+nx*q;
-        tmp1.tangent[1] = py+ny*q;
-        tmp1.tangent[2] = pz+nz*q;
-        tmp1.tangent[3] = pw+nw*q;
-        tmp1.tangent[4] = pv+nv*q;
+        tmpCache1.velocity[0] = px+nx*q;
+        tmpCache1.velocity[1] = py+ny*q;
+        tmpCache1.velocity[2] = pz+nz*q;
+        tmpCache1.velocity[3] = pw+nw*q;
+        tmpCache1.velocity[4] = pv+nv*q;
         }
       }
     else
       {
-      tmp1.tangent[0] = 0.0f;
-      tmp1.tangent[1] = 0.0f;
-      tmp1.tangent[2] = 0.0f;
-      tmp1.tangent[3] = 0.0f;
-      tmp1.tangent[4] = 0.0f;
+      tmpCache1.velocity[0] = 0.0f;
+      tmpCache1.velocity[1] = 0.0f;
+      tmpCache1.velocity[2] = 0.0f;
+      tmpCache1.velocity[3] = 0.0f;
+      tmpCache1.velocity[4] = 0.0f;
       }
     }
     
@@ -96,50 +96,50 @@ public class Dynamic5D extends Dynamic implements Data5D
     {  
     if( numPoints==1 )
       {
-      tmp1= vc.elementAt(0);
+      tmpCache1 = vc.elementAt(0);
       curr= vv.elementAt(0);
         
-      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = tmp1.a[3] = tmp1.a[4] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = tmp1.b[3] = tmp1.b[4] = 0.0f;
-      tmp1.c[0] = curr.x;
-      tmp1.c[1] = curr.y;
-      tmp1.c[2] = curr.z;
-      tmp1.c[3] = curr.w;
-      tmp1.c[4] = curr.v;
-      tmp1.d[0] = tmp1.d[1] = tmp1.d[2] = tmp1.d[3] = tmp1.d[4] = 0.0f;
+      tmpCache1.a[0] = tmpCache1.a[1] = tmpCache1.a[2] = tmpCache1.a[3] = tmpCache1.a[4] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = tmpCache1.b[2] = tmpCache1.b[3] = tmpCache1.b[4] = 0.0f;
+      tmpCache1.c[0] = curr.x;
+      tmpCache1.c[1] = curr.y;
+      tmpCache1.c[2] = curr.z;
+      tmpCache1.c[3] = curr.w;
+      tmpCache1.c[4] = curr.v;
+      tmpCache1.d[0] = tmpCache1.d[1] = tmpCache1.d[2] = tmpCache1.d[3] = tmpCache1.d[4] = 0.0f;
       }
     else if( numPoints==2 )
       {
-      tmp1= vc.elementAt(0);
-      tmp2= vc.elementAt(1);
+      tmpCache1 = vc.elementAt(0);
+      tmpCache2 = vc.elementAt(1);
       curr= vv.elementAt(0);
       next= vv.elementAt(1);
       
-      tmp1.a[0] = tmp1.a[1] = tmp1.a[2] = tmp1.a[3] = tmp1.a[4] = 0.0f;
-      tmp1.b[0] = tmp1.b[1] = tmp1.b[2] = tmp1.b[3] = tmp1.b[4] = 0.0f;
-      tmp1.c[0] = next.x - curr.x;
-      tmp1.c[1] = next.y - curr.y;
-      tmp1.c[2] = next.z - curr.z;
-      tmp1.c[3] = next.w - curr.w;
-      tmp1.c[4] = next.v - curr.v;
-      tmp1.d[0] = curr.x;
-      tmp1.d[1] = curr.y;
-      tmp1.d[2] = curr.z;
-      tmp1.d[3] = curr.w;
-      tmp1.d[4] = curr.v;
+      tmpCache1.a[0] = tmpCache1.a[1] = tmpCache1.a[2] = tmpCache1.a[3] = tmpCache1.a[4] = 0.0f;
+      tmpCache1.b[0] = tmpCache1.b[1] = tmpCache1.b[2] = tmpCache1.b[3] = tmpCache1.b[4] = 0.0f;
+      tmpCache1.c[0] = next.x - curr.x;
+      tmpCache1.c[1] = next.y - curr.y;
+      tmpCache1.c[2] = next.z - curr.z;
+      tmpCache1.c[3] = next.w - curr.w;
+      tmpCache1.c[4] = next.v - curr.v;
+      tmpCache1.d[0] = curr.x;
+      tmpCache1.d[1] = curr.y;
+      tmpCache1.d[2] = curr.z;
+      tmpCache1.d[3] = curr.w;
+      tmpCache1.d[4] = curr.v;
       
-      tmp2.a[0] = tmp2.a[1] = tmp2.a[2] = tmp2.a[3] = tmp2.a[4] = 0.0f;
-      tmp2.b[0] = tmp2.b[1] = tmp2.b[2] = tmp2.b[3] = tmp2.b[4] = 0.0f;
-      tmp2.c[0] = curr.x - next.x;
-      tmp2.c[1] = curr.y - next.y;
-      tmp2.c[2] = curr.z - next.z;
-      tmp2.c[3] = curr.w - next.w;
-      tmp2.c[4] = curr.v - next.v;
-      tmp2.d[0] = next.x;
-      tmp2.d[1] = next.y;
-      tmp2.d[2] = next.z;
-      tmp2.d[3] = next.w;
-      tmp2.d[4] = next.v;
+      tmpCache2.a[0] = tmpCache2.a[1] = tmpCache2.a[2] = tmpCache2.a[3] = tmpCache2.a[4] = 0.0f;
+      tmpCache2.b[0] = tmpCache2.b[1] = tmpCache2.b[2] = tmpCache2.b[3] = tmpCache2.b[4] = 0.0f;
+      tmpCache2.c[0] = curr.x - next.x;
+      tmpCache2.c[1] = curr.y - next.y;
+      tmpCache2.c[2] = curr.z - next.z;
+      tmpCache2.c[3] = curr.w - next.w;
+      tmpCache2.c[4] = curr.v - next.v;
+      tmpCache2.d[0] = next.x;
+      tmpCache2.d[1] = next.y;
+      tmpCache2.d[2] = next.z;
+      tmpCache2.d[3] = next.w;
+      tmpCache2.d[4] = next.v;
       }
     else
       {
@@ -151,41 +151,43 @@ public class Dynamic5D extends Dynamic implements Data5D
         {
         n = i<numPoints-1 ? i+1:0;  
       
-        tmp1= vc.elementAt(i);
-        tmp2= vc.elementAt(n);
+        tmpCache1 = vc.elementAt(i);
+        tmpCache2 = vc.elementAt(n);
         curr= vv.elementAt(i);
         next= vv.elementAt(n);
       
-        tmp1.cached[0] = curr.x;
-        tmp1.cached[1] = curr.y;
-        tmp1.cached[2] = curr.z;
-        tmp1.cached[3] = curr.w;
-        tmp1.cached[4] = curr.v;
+        tmpCache1.cached[0] = curr.x;
+        tmpCache1.cached[1] = curr.y;
+        tmpCache1.cached[2] = curr.z;
+        tmpCache1.cached[3] = curr.w;
+        tmpCache1.cached[4] = curr.v;
         
-        tmp1.a[0] = mConvexity*( 2*curr.x +   tmp1.tangent[0] - 2*next.x + tmp2.tangent[0]);
-        tmp1.b[0] = mConvexity*(-3*curr.x - 2*tmp1.tangent[0] + 3*next.x - tmp2.tangent[0]);
-        tmp1.c[0] = mConvexity*(tmp1.tangent[0]) + (1.0f-mConvexity)*(next.x-curr.x);
-        tmp1.d[0] = curr.x;
+        tmpCache1.a[0] = mConvexity*( 2*curr.x +   tmpCache1.velocity[0] - 2*next.x + tmpCache2.velocity[0]);
+        tmpCache1.b[0] = mConvexity*(-3*curr.x - 2* tmpCache1.velocity[0] + 3*next.x - tmpCache2.velocity[0]);
+        tmpCache1.c[0] = mConvexity*(tmpCache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x);
+        tmpCache1.d[0] = curr.x;
       
-        tmp1.a[1] = mConvexity*( 2*curr.y +   tmp1.tangent[1] - 2*next.y + tmp2.tangent[1]);
-        tmp1.b[1] = mConvexity*(-3*curr.y - 2*tmp1.tangent[1] + 3*next.y - tmp2.tangent[1]);
-        tmp1.c[1] = mConvexity*(tmp1.tangent[1]) + (1.0f-mConvexity)*(next.y-curr.y);
-        tmp1.d[1] = curr.y;
+        tmpCache1.a[1] = mConvexity*( 2*curr.y +   tmpCache1.velocity[1] - 2*next.y + tmpCache2.velocity[1]);
+        tmpCache1.b[1] = mConvexity*(-3*curr.y - 2* tmpCache1.velocity[1] + 3*next.y - tmpCache2.velocity[1]);
+        tmpCache1.c[1] = mConvexity*(tmpCache1.velocity[1]) + (1.0f-mConvexity)*(next.y-curr.y);
+        tmpCache1.d[1] = curr.y;
       
-        tmp1.a[2] = mConvexity*( 2*curr.z +   tmp1.tangent[2] - 2*next.z + tmp2.tangent[2]);
-        tmp1.b[2] = mConvexity*(-3*curr.z - 2*tmp1.tangent[2] + 3*next.z - tmp2.tangent[2]);
-        tmp1.c[2] = mConvexity*(tmp1.tangent[2]) + (1.0f-mConvexity)*(next.z-curr.z);
-        tmp1.d[2] = curr.z;
+        tmpCache1.a[2] = mConvexity*( 2*curr.z +   tmpCache1.velocity[2] - 2*next.z + tmpCache2.velocity[2]);
+        tmpCache1.b[2] = mConvexity*(-3*curr.z - 2* tmpCache1.velocity[2] + 3*next.z - tmpCache2.velocity[2]);
+        tmpCache1.c[2] = mConvexity*(tmpCache1.velocity[2]) + (1.0f-mConvexity)*(next.z-curr.z);
+        tmpCache1.d[2] = curr.z;
         
-        tmp1.a[3] = mConvexity*( 2*curr.w +   tmp1.tangent[3] - 2*next.w + tmp2.tangent[3]);
-        tmp1.b[3] = mConvexity*(-3*curr.w - 2*tmp1.tangent[3] + 3*next.w - tmp2.tangent[3]);
-        tmp1.c[3] = mConvexity*(tmp1.tangent[3]) + (1.0f-mConvexity)*(next.w-curr.w);
-        tmp1.d[3] = curr.w;
+        tmpCache1.a[3] = mConvexity*( 2*curr.w +   tmpCache1.velocity[3] - 2*next.w + tmpCache2.velocity[3]);
+        tmpCache1.b[3] = mConvexity*(-3*curr.w - 2* tmpCache1.velocity[3] + 3*next.w - tmpCache2.velocity[3]);
+        tmpCache1.c[3] = mConvexity*(tmpCache1.velocity[3]) + (1.0f-mConvexity)*(next.w-curr.w);
+        tmpCache1.d[3] = curr.w;
         
-        tmp1.a[4] = mConvexity*( 2*curr.v +   tmp1.tangent[4] - 2*next.v + tmp2.tangent[4]);
-        tmp1.b[4] = mConvexity*(-3*curr.v - 2*tmp1.tangent[4] + 3*next.v - tmp2.tangent[4]);
-        tmp1.c[4] = mConvexity*(tmp1.tangent[4]) + (1.0f-mConvexity)*(next.v-curr.v);
-        tmp1.d[4] = curr.v;
+        tmpCache1.a[4] = mConvexity*( 2*curr.v +   tmpCache1.velocity[4] - 2*next.v + tmpCache2.velocity[4]);
+        tmpCache1.b[4] = mConvexity*(-3*curr.v - 2* tmpCache1.velocity[4] + 3*next.v - tmpCache2.velocity[4]);
+        tmpCache1.c[4] = mConvexity*(tmpCache1.velocity[4]) + (1.0f-mConvexity)*(next.v-curr.v);
+        tmpCache1.d[4] = curr.v;
+
+        if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) smoothOutSegment(tmpCache1);
         }
       }
    
@@ -545,38 +547,37 @@ public class Dynamic5D extends Dynamic implements Data5D
                   {
                   int vecNext= getNext(vecCurr,t);
                   next = vv.elementAt(vecNext);
-                  tmp2 = vc.elementAt(vecNext);
+                  tmpCache2 = vc.elementAt(vecNext);
 
-                  if( tmp2.cached[0]!=next.x || tmp2.cached[1]!=next.y || tmp2.cached[2]!=next.z || tmp2.cached[3]!=next.w || tmp2.cached[4]!=next.v ) recomputeCache();
+                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y || tmpCache2.cached[2]!=next.z || tmpCache2.cached[3]!=next.w || tmpCache2.cached[4]!=next.v ) recomputeCache();
                   }
 
                 if( mSegment!= segment && vn!=null ) vn.elementAt(vecCurr).computeNoise();
 
                 mSegment = segment;
-
                 time = time-vecCurr;
-            
-                tmp1 = vc.elementAt(vecCurr);
-               
+                tmpCache1 = vc.elementAt(vecCurr);
+                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
+
                 if( vn!=null )
                   {
                   time = noise(time,vecCurr);
               
-                  computeOrthonormalBaseMore(time,tmp1);
+                  computeOrthonormalBaseMore(time, tmpCache1);
 
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2] + baseV[4][0]*mFactor[3]);
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2] + baseV[4][1]*mFactor[3]);
-                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2] + baseV[4][2]*mFactor[3]);
-                  buffer[offset+3]= ((tmp1.a[3]*time+tmp1.b[3])*time+tmp1.c[3])*time+tmp1.d[3] + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2] + baseV[4][3]*mFactor[3]);
-                  buffer[offset+4]= ((tmp1.a[4]*time+tmp1.b[4])*time+tmp1.c[4])*time+tmp1.d[4] + (baseV[1][4]*mFactor[0] + baseV[2][4]*mFactor[1] + baseV[3][4]*mFactor[2] + baseV[4][4]*mFactor[3]);
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2] + baseV[4][0]*mFactor[3]);
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2] + baseV[4][1]*mFactor[3]);
+                  buffer[offset+2]= ((tmpCache1.a[2]*time+ tmpCache1.b[2])*time+ tmpCache1.c[2])*time+ tmpCache1.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2] + baseV[4][2]*mFactor[3]);
+                  buffer[offset+3]= ((tmpCache1.a[3]*time+ tmpCache1.b[3])*time+ tmpCache1.c[3])*time+ tmpCache1.d[3] + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2] + baseV[4][3]*mFactor[3]);
+                  buffer[offset+4]= ((tmpCache1.a[4]*time+ tmpCache1.b[4])*time+ tmpCache1.c[4])*time+ tmpCache1.d[4] + (baseV[1][4]*mFactor[0] + baseV[2][4]*mFactor[1] + baseV[3][4]*mFactor[2] + baseV[4][4]*mFactor[3]);
                   }
                 else
                   {
-                  buffer[offset  ]= ((tmp1.a[0]*time+tmp1.b[0])*time+tmp1.c[0])*time+tmp1.d[0];
-                  buffer[offset+1]= ((tmp1.a[1]*time+tmp1.b[1])*time+tmp1.c[1])*time+tmp1.d[1];
-                  buffer[offset+2]= ((tmp1.a[2]*time+tmp1.b[2])*time+tmp1.c[2])*time+tmp1.d[2];
-                  buffer[offset+3]= ((tmp1.a[3]*time+tmp1.b[3])*time+tmp1.c[3])*time+tmp1.d[3];
-                  buffer[offset+4]= ((tmp1.a[4]*time+tmp1.b[4])*time+tmp1.c[4])*time+tmp1.d[4];
+                  buffer[offset  ]= ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
+                  buffer[offset+1]= ((tmpCache1.a[1]*time+ tmpCache1.b[1])*time+ tmpCache1.c[1])*time+ tmpCache1.d[1];
+                  buffer[offset+2]= ((tmpCache1.a[2]*time+ tmpCache1.b[2])*time+ tmpCache1.c[2])*time+ tmpCache1.d[2];
+                  buffer[offset+3]= ((tmpCache1.a[3]*time+ tmpCache1.b[3])*time+ tmpCache1.c[3])*time+ tmpCache1.d[3];
+                  buffer[offset+4]= ((tmpCache1.a[4]*time+ tmpCache1.b[4])*time+ tmpCache1.c[4])*time+ tmpCache1.d[4];
                   }
  
                 break;
diff --git a/src/main/java/org/distorted/library/type/DynamicQuat.java b/src/main/java/org/distorted/library/type/DynamicQuat.java
index 6056f7b..b50991a 100644
--- a/src/main/java/org/distorted/library/type/DynamicQuat.java
+++ b/src/main/java/org/distorted/library/type/DynamicQuat.java
@@ -50,10 +50,10 @@ public class DynamicQuat extends Dynamic implements Data4D
     float vx,vy,vz,vw;
     }
   
-  private Vector<VectorCacheQuat> vc;
+  private final Vector<VectorCacheQuat> vc;
   private VectorCacheQuat tmp1, tmp2;
 
-  private Vector<Static4D> vv;
+  private final Vector<Static4D> vv;
   private Static4D curr, next;
  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
