commit 553a95018556d29e760acadfe05b7821ed0a1753
Author: leszek <leszek@koltunski.pl>
Date:   Tue Apr 22 13:12:09 2025 +0200

    transition the 'type' package

diff --git a/src/main/java/org/distorted/library/type/Data1D.kt b/src/main/java/org/distorted/library/type/Data1D.kt
index b590475..a59c701 100644
--- a/src/main/java/org/distorted/library/type/Data1D.kt
+++ b/src/main/java/org/distorted/library/type/Data1D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,15 +18,15 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+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
-  {
-  boolean get(float[] buffer, int offset, long time, long step);
-  }
+interface Data1D
+{
+    fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
+}
diff --git a/src/main/java/org/distorted/library/type/Data2D.kt b/src/main/java/org/distorted/library/type/Data2D.kt
index eab6d38..c261be3 100644
--- a/src/main/java/org/distorted/library/type/Data2D.kt
+++ b/src/main/java/org/distorted/library/type/Data2D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,15 +18,15 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+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
-  {
-  boolean get(float[] buffer, int offset, long time, long step);
-  }
+interface Data2D
+{
+    fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
+}
diff --git a/src/main/java/org/distorted/library/type/Data3D.kt b/src/main/java/org/distorted/library/type/Data3D.kt
index aaf1178..3a7a80b 100644
--- a/src/main/java/org/distorted/library/type/Data3D.kt
+++ b/src/main/java/org/distorted/library/type/Data3D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,15 +18,15 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+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
-  {
-  boolean get(float[] buffer, int offset, long time, long step);
-  }
+interface Data3D
+{
+    fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
+}
diff --git a/src/main/java/org/distorted/library/type/Data4D.kt b/src/main/java/org/distorted/library/type/Data4D.kt
index 7539508..81f8c02 100644
--- a/src/main/java/org/distorted/library/type/Data4D.kt
+++ b/src/main/java/org/distorted/library/type/Data4D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,15 +18,15 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+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
-  {
-  boolean get(float[] buffer, int offset, long time, long step);
-  }
+interface Data4D
+{
+    fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
+}
diff --git a/src/main/java/org/distorted/library/type/Data5D.kt b/src/main/java/org/distorted/library/type/Data5D.kt
index 2905e17..4c1b78a 100644
--- a/src/main/java/org/distorted/library/type/Data5D.kt
+++ b/src/main/java/org/distorted/library/type/Data5D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,15 +18,15 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Marker Interface implemented by Static5D and Dynamic5D.
- * <p>
+ *
  * The point: so we can pass either Static and Dynamic to EffectQueues in a single parameter.
  */
-public interface Data5D
-  {
-  boolean get(float[] buffer, int offset, long time, long step);
-  }
+interface Data5D
+{
+    fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
+}
diff --git a/src/main/java/org/distorted/library/type/Dynamic.kt b/src/main/java/org/distorted/library/type/Dynamic.kt
index 124cdb7..54eb59b 100644
--- a/src/main/java/org/distorted/library/type/Dynamic.kt
+++ b/src/main/java/org/distorted/library/type/Dynamic.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,22 +18,21 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
-
-import org.distorted.library.main.DistortedLibrary;
+package org.distorted.library.type
 
-import java.util.Random;
-import java.util.Vector;
+import org.distorted.library.main.DistortedLibrary
+import java.util.Random
+import java.util.Vector
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /** A class to interpolate between a list of Statics.
-* <p><ul>
-* <li>if there is only one Point, just return it.
-* <li>if there are two Points, linearly bounce between them
-* <li>if there are more, interpolate a path between them. Exact way we interpolate depends on the MODE.
-* </ul>
+*
+*  if there is only one Point, just return it.
+*  if there are two Points, linearly bounce between them
+*  if there are more, interpolate a path between them. Exact way we interpolate depends on the MODE.
+*
 */
-
 // The way Interpolation between more than 2 Points is done:
 // 
 // Def: let V[i] = (V[i](x), V[i](y), V[i](z)) be the direction and speed (i.e. velocity) we have to
@@ -56,833 +55,736 @@ import java.util.Vector;
 //
 // and similarly Y(t) and Z(t).
 
-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;  // TODO: not supported yet
-
-  /**
-   * One revolution takes us from the first point to the last and back to first through the shortest path.
-   */
-  public static final int MODE_LOOP = 0; 
-  /**
-   * One revolution takes us from the first point to the last and back to first through the same path.
-   */
-  public static final int MODE_PATH = 1; 
-  /**
-   * One revolution takes us from the first point to the last and jumps straight back to the first point.
-   */
-  public static final int MODE_JUMP = 2; 
-
-  /**
-   * The default mode of access. When in this mode, we are able to call interpolate() with points in time
-   * in any random order. This means one single Dynamic can be used in many effects simultaneously.
-   * On the other hand, when in this mode, it is not possible to smoothly interpolate when mDuration suddenly
-   * changes.
-   */
-  public static final int ACCESS_TYPE_RANDOM     = 0;
-  /**
-   * Set the mode to ACCESS_SEQUENTIAL if you need to change mDuration and you would rather have the Dynamic
-   * keep on smoothly interpolating.
-   * On the other hand, in this mode, a Dynamic can only be accessed in sequential manner, which means one
-   * Dynamic can only be used in one effect at a time.
-   */
-  public static final int ACCESS_TYPE_SEQUENTIAL = 1;
-
-  protected int mDimension;
-  protected int numPoints;
-  protected int mSegment;       // between which pair of points are we currently? (in case of PATH this is a bit complicated!)
-  protected boolean cacheDirty; // VectorCache not up to date
-  protected int mMode;          // LOOP, PATH or JUMP
-  protected long mDuration;     // number of milliseconds 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 double mLastPos;
-  protected int mAccessType;
-  protected int mSpeedMode;
-  protected float mTmpTime;
-  protected int mTmpVec, mTmpSeg;
-
-  protected class VectorNoise
-    {
-    float[][] n;
-
-    VectorNoise()
-      {
-      n = new float[mDimension][NUM_NOISE];
-      }
+abstract class Dynamic
+{
+    companion object
+    {
+        /**
+         * 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.
+         */
+        const val SPEED_MODE_SMOOTH: Int = 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.
+         */
+        const val SPEED_MODE_SEGMENT_CONSTANT: Int = 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.
+         */
+        const val SPEED_MODE_GLOBALLY_CONSTANT: Int = 2 // TODO: not supported yet
+
+        /**
+         * One revolution takes us from the first point to the last and back to first through the shortest path.
+         */
+        const val MODE_LOOP: Int = 0
+
+        /**
+         * One revolution takes us from the first point to the last and back to first through the same path.
+         */
+        const val MODE_PATH: Int = 1
+
+        /**
+         * One revolution takes us from the first point to the last and jumps straight back to the first point.
+         */
+        const val MODE_JUMP: Int = 2
+
+        /**
+         * The default mode of access. When in this mode, we are able to call interpolate() with points in time
+         * in any random order. This means one single Dynamic can be used in many effects simultaneously.
+         * On the other hand, when in this mode, it is not possible to smoothly interpolate when mDuration suddenly
+         * changes.
+         */
+        const val ACCESS_TYPE_RANDOM: Int = 0
+
+        /**
+         * Set the mode to ACCESS_SEQUENTIAL if you need to change mDuration and you would rather have the Dynamic
+         * keep on smoothly interpolating.
+         * On the other hand, in this mode, a Dynamic can only be accessed in sequential manner, which means one
+         * Dynamic can only be used in one effect at a time.
+         */
+        const val ACCESS_TYPE_SEQUENTIAL: Int = 1
+
+        private const val NUM_RATIO = 10 // we attempt to 'smooth out' the speed in each segment -
+
+        // remember this many 'points' inside the Cache for each segment.
+        protected val mTmpRatio: FloatArray = FloatArray(NUM_RATIO)
+
+        private val mRnd = Random()
+        private const val NUM_NOISE = 5 // used iff mNoise>0.0. Number of intermediary points between each pair of adjacent vectors
+        private var mPausedTime: Long = 0
+
+        @JvmStatic fun onPause() { mPausedTime = System.currentTimeMillis() }
+    }
+
+    var dimension: Int = 0
+        protected set
+
+    @get:Synchronized
+    var numPoints: Int = 0
+        protected set
+    protected var mSegment: Int       = 0 // between which pair of points are we currently? (in case of PATH this is a bit complicated!)
+    protected var cacheDirty: Boolean = false // VectorCache not up to date
+    protected var mMode: Int          = 0 // LOOP, PATH or JUMP
+    var duration: Long                = 0 // number of milliseconds it takes to do a full loop/path from first vector to the last and back to the first
+    var count: Float                  = 0f // 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 var mLastPos: Double    = 0.0
+    protected var mAccessType: Int    = 0
+    protected var mSpeedMode: Int     = 0
+    protected var mTmpTime: Float     = 0f
+    protected var mTmpVec: Int        = 0
+    protected var mTmpSeg: Int        = 0
+
+    var convexity: Float
+        get() = mConvexity
+        set(convexity)
+        {
+            if (mConvexity!=convexity)
+            {
+                mConvexity = convexity
+                cacheDirty = true
+            }
+        }
 
-    void computeNoise()
-      {
-      n[0][0] = mRnd.nextFloat();
-      for(int i=1; i<NUM_NOISE; i++) n[0][i] = n[0][i-1]+mRnd.nextFloat();
+    val speedMode: Float
+        get() = mSpeedMode.toFloat()
 
-      float sum = n[0][NUM_NOISE-1] + mRnd.nextFloat();
+    protected inner class VectorNoise
+    internal constructor()
+    {
+        var n: Array<FloatArray> = Array(dimension) { FloatArray(NUM_NOISE) }
 
-      for(int i=0; i<NUM_NOISE; i++)
+        fun computeNoise()
         {
-        n[0][i] /=sum;
-        for(int j=1; j<mDimension; j++) n[j][i] = mRnd.nextFloat()-0.5f;
+            n[0][0] = mRnd.nextFloat()
+            for (i in 1..<NUM_NOISE) n[0][i] = n[0][i-1] + mRnd.nextFloat()
+
+            val sum = n[0][NUM_NOISE-1] + mRnd.nextFloat()
+
+            for (i in 0..<NUM_NOISE)
+            {
+                n[0][i] /= sum
+                for (j in 1..<dimension) n[j][i] = mRnd.nextFloat()-0.5f
+            }
         }
-      }
     }
 
-  protected Vector<VectorNoise> vn;
-  protected float[] mFactor;
-  protected float[] mNoise;
-  protected float[][] baseV;
+    protected var vn: Vector<VectorNoise>? = null
+    protected lateinit var mFactor: FloatArray
+    protected lateinit var mNoise: FloatArray
+    protected lateinit var baseV: Array<FloatArray>
 
-  ///////////////////////////////////////////////////////////////////////////////////////////////////
-  // 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
-
-  protected class VectorCache
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // 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
+    protected inner class VectorCache
+    internal constructor()
     {
-    float[] a;
-    float[] b;
-    float[] c;
-    float[] d;
-    float[] velocity;
-    float[] cached;
-    float[] path_ratio;
-
-    VectorCache()
-      {
-      a = new float[mDimension];
-      b = new float[mDimension];
-      c = new float[mDimension];
-      d = new float[mDimension];
-
-      velocity   = new float[mDimension];
-      cached     = new float[mDimension];
-      path_ratio = new float[NUM_RATIO];
-      }
+        var a: FloatArray = FloatArray(dimension)
+        var b: FloatArray = FloatArray(dimension)
+        var c: FloatArray = FloatArray(dimension)
+        var d: FloatArray = FloatArray(dimension)
+        var velocity: FloatArray = FloatArray(dimension)
+        var cached: FloatArray = FloatArray(dimension)
+        var path_ratio: FloatArray = FloatArray(NUM_RATIO)
     }
 
-  protected Vector<VectorCache> vc;
-  protected VectorCache tmpCache1, tmpCache2;
-  protected float mConvexity;
+    protected var vc: Vector<VectorCache>? = null
+    protected var mConvexity: Float = 0f
 
-  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.
+    private lateinit var buf: FloatArray
+    private lateinit var old: FloatArray
 
-  protected static final float[] mTmpRatio = new float[NUM_RATIO];
+    // where we randomize noise factors to make the way between the two vectors not so smooth.
+    private var mStartTime: Long = 0
+    private var mCorrectedTime: Long = 0
 
-  private float[] buf;
-  private float[] old;
-  private static final Random mRnd = new Random();
-  private 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.
-  private long mStartTime;
-  private long mCorrectedTime;
-  private static long mPausedTime;
+    protected constructor()
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// hide this from Javadoc
-  
-  protected Dynamic()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    protected constructor(duration: Int, count: Float, dimension: Int)
     {
+        vc = Vector()
+        vn = null
+        numPoints = 0
+        cacheDirty = false
+        mMode = MODE_LOOP
+        this.duration = duration.toLong()
+        this.count = count
+        this.dimension = dimension
+        mSegment = -1
+        mLastPos = -1.0
+        mAccessType = ACCESS_TYPE_RANDOM
+        mSpeedMode = SPEED_MODE_SMOOTH
+        mConvexity = 1.0f
+        mStartTime = -1
+        mCorrectedTime = 0
 
+        baseV = Array(this.dimension) { FloatArray(this.dimension) }
+        buf = FloatArray(this.dimension)
+        old = FloatArray(this.dimension)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  protected Dynamic(int duration, float count, int dimension)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    fun initDynamic()
     {
-    vc         = new Vector<>();
-    vn         = null;
-    numPoints  = 0;
-    cacheDirty = false;
-    mMode      = MODE_LOOP;
-    mDuration  = duration;
-    mCount     = count;
-    mDimension = dimension;
-    mSegment   = -1;
-    mLastPos   = -1;
-    mAccessType= ACCESS_TYPE_RANDOM;
-    mSpeedMode = SPEED_MODE_SMOOTH;
-    mConvexity = 1.0f;
-    mStartTime = -1;
-    mCorrectedTime = 0;
-
-    baseV      = new float[mDimension][mDimension];
-    buf        = new float[mDimension];
-    old        = new float[mDimension];
+        mStartTime = -1
+        mCorrectedTime = 0
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void initDynamic()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    protected fun computeSegmentAndTime(time: Float)
     {
-    mStartTime = -1;
-    mCorrectedTime = 0;
+        when (mMode)
+        {
+            MODE_LOOP ->
+                {
+                    mTmpTime= time*numPoints
+                    mTmpSeg = mTmpTime.toInt()
+                    mTmpVec = mTmpSeg
+                }
+
+            MODE_PATH ->
+                {
+                    mTmpSeg = (2*time*(numPoints-1)).toInt()
+
+                    if (time <= 0.5f)  // this has to be <= (otherwise when effect ends at t=0.5, then time=1.0
+                    {                  // and end position is slightly not equal to the end point => might not get autodeleted!
+                        mTmpTime = 2*time*(numPoints-1)
+                        mTmpVec = mTmpSeg
+                    }
+                    else
+                    {
+                        mTmpTime = 2 * (1 - time) * (numPoints - 1)
+                        mTmpVec = 2 * numPoints - 3 - mTmpSeg
+                    }
+                }
+
+            MODE_JUMP ->
+                {
+                    mTmpTime = time*(numPoints-1)
+                    mTmpSeg = mTmpTime.toInt()
+                    mTmpVec = mTmpSeg
+                }
+
+            else ->
+                {
+                    mTmpVec = 0
+                    mTmpSeg = 0
+                }
+        }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static void onPause()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun valueAtPoint(t: Float, cache: VectorCache): Float
     {
-    mPausedTime = System.currentTimeMillis();
-    }
+        var tmp: Float
+        var sum = 0.0f
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+        for (d in 0..<dimension)
+        {
+            tmp = (3*cache.a[d]*t + 2*cache.b[d])*t + cache.c[d]
+            sum += tmp*tmp
+        }
 
-  protected void computeSegmentAndTime(float time)
-    {
-    switch(mMode)
-      {
-      case MODE_LOOP: mTmpTime= time*numPoints;
-                      mTmpSeg = (int)mTmpTime;
-                      mTmpVec = mTmpSeg;
-                      break;
-      case MODE_PATH: mTmpSeg = (int)(2*time*(numPoints-1));
-
-                      if( time<=0.5f )  // this has to be <= (otherwise when effect ends at t=0.5, then time=1.0
-                        {               // and end position is slightly not equal to the end point => might not get autodeleted!
-                        mTmpTime = 2*time*(numPoints-1);
-                        mTmpVec = mTmpSeg;
-                        }
-                      else
-                        {
-                        mTmpTime = 2*(1-time)*(numPoints-1);
-                        mTmpVec  = 2*numPoints-3-mTmpSeg;
-                        }
-                      break;
-      case MODE_JUMP: mTmpTime= time*(numPoints-1);
-                      mTmpSeg = (int)mTmpTime;
-                      mTmpVec = mTmpSeg;
-                      break;
-      default       : mTmpVec = 0;
-                      mTmpSeg = 0;
-      }
+        return sqrt(sum.toDouble()).toFloat()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private float valueAtPoint(float t, VectorCache cache)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    protected fun smoothSpeed(time: Float, cache: VectorCache): Float
     {
-    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;
-      }
+        val fndex = time*NUM_RATIO
+        val index = fndex.toInt()
+        val prev  = if (index==0) 0.0f else cache.path_ratio[index-1]
+        val next  = cache.path_ratio[index]
 
-    return (float)Math.sqrt(sum);
+        return prev + (next-prev) * (fndex-index)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  protected float smoothSpeed(float time, VectorCache cache)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // 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 fun smoothOutSegment(cache: VectorCache)
     {
-    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];
+        var vPrev: Float
+        var sum = 0.0f
+        var vNext = valueAtPoint(0.0f,cache)
 
-    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 (i in 0..<NUM_RATIO)
+        {
+            vPrev = vNext
+            vNext = valueAtPoint( (i+1).toFloat()/NUM_RATIO, cache )
+            sum += (vPrev+vNext)
+            cache.path_ratio[i] = sum
+        }
 
-    for(int i=0; i<NUM_RATIO; i++) cache.path_ratio[i] /= total;
+        val total = cache.path_ratio[NUM_RATIO-1]
 
-    int writeIndex = 0;
-    float prev=0.0f, next, ratio= 1.0f/NUM_RATIO;
+        for (i in 0..<NUM_RATIO) cache.path_ratio[i] /= total
 
-    for(int readIndex=0; readIndex<NUM_RATIO; readIndex++)
-      {
-      next = cache.path_ratio[readIndex];
+        var writeIndex = 0
+        var prev = 0.0f
+        var next: Float
+        var ratio = 1.0f/NUM_RATIO
 
-      while( prev<ratio && ratio<=next )
+        for (readIndex in 0..<NUM_RATIO)
         {
-        float a = (next-ratio)/(next-prev);
-        mTmpRatio[writeIndex] = (readIndex+1-a)/NUM_RATIO;
-        writeIndex++;
-        ratio = (writeIndex+1.0f)/NUM_RATIO;
-        }
+            next = cache.path_ratio[readIndex]
 
-      prev = next;
-      }
+            while (prev<ratio && ratio<=next)
+            {
+                val a = (next-ratio) / (next-prev)
+                mTmpRatio[writeIndex] = (readIndex+1-a) / NUM_RATIO
+                writeIndex++
+                ratio = (writeIndex+1.0f) / NUM_RATIO
+            }
 
-    System.arraycopy(mTmpRatio, 0, cache.path_ratio, 0, NUM_RATIO);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+            prev = next
+        }
 
-  protected 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;
-    VectorNoise tmpN = vn.elementAt(vecNum);
-
-    float t = d-index;
-    t = t*t*(3-2*t);
-
-    switch(index)
-      {
-      case 0        : for(int i=0;i<mDimension-1;i++) mFactor[i] = mNoise[i+1]*tmpN.n[i+1][0]*t;
-                      return time + mNoise[0]*(d*tmpN.n[0][0]-time);
-      case NUM_NOISE: for(int i=0;i<mDimension-1;i++) mFactor[i] = mNoise[i+1]*tmpN.n[i+1][NUM_NOISE-1]*(1-t);
-                      len = ((float)NUM_NOISE)/(NUM_NOISE+1);
-                      lower = len + mNoise[0]*(tmpN.n[0][NUM_NOISE-1]-len);
-                      return (1.0f-lower)*(d-NUM_NOISE) + lower;
-      default       : float ya,yb;
-
-                      for(int i=0;i<mDimension-1;i++)
-                        {
-                        yb = tmpN.n[i+1][index  ];
-                        ya = tmpN.n[i+1][index-1];
-                        mFactor[i] = mNoise[i+1]*((yb-ya)*t+ya);
-                        }
-
-                      len = ((float)index)/(NUM_NOISE+1);
-                      lower = len + mNoise[0]*(tmpN.n[0][index-1]-len);
-                      len = ((float)index+1)/(NUM_NOISE+1);
-                      upper = len + mNoise[0]*(tmpN.n[0][index  ]-len);
-
-                      return (upper-lower)*(d-index) + lower;
-      }
+        System.arraycopy(mTmpRatio, 0, cache.path_ratio, 0, NUM_RATIO)
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// debugging only
-
-  private void printBase(String str)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    protected fun noise(time: Float, vecNum: Int): Float
     {
-    String s;
-    float t;
+        val lower: Float
+        val upper: Float
+        var len: Float
+        val d = time*(NUM_NOISE+1)
+        var index = d.toInt()
+        if (index >= NUM_NOISE+1) index = NUM_NOISE
+        val tmpN = vn!!.elementAt(vecNum)
 
-    for(int i=0; i<mDimension; i++)
-      {
-      s = "";
+        var t = d-index
+        t = t*t*(3-2*t)
 
-      for(int j=0; j<mDimension; j++)
+        when (index)
         {
-        t = ((int)(1000*baseV[i][j]))/(1000.0f);
-        s+=(" "+t);
+            0 ->
+                {
+                    var i = 0
+                    while (i < dimension-1)
+                    {
+                        mFactor[i] = mNoise[i+1] * tmpN.n[i+1][0] * t
+                        i++
+                    }
+                    return time + mNoise[0] * (d*tmpN.n[0][0]-time)
+                }
+
+            NUM_NOISE ->
+                {
+                    var i = 0
+                    while (i < dimension - 1)
+                    {
+                        mFactor[i] = mNoise[i+1] * tmpN.n[i+1][NUM_NOISE-1] * (1-t)
+                        i++
+                    }
+
+                    len = (NUM_NOISE.toFloat()) / (NUM_NOISE+1)
+                    lower = len + mNoise[0] * (tmpN.n[0][NUM_NOISE-1] - len)
+                    return (1.0f-lower) * (d-NUM_NOISE) + lower
+                }
+
+            else ->
+                {
+                    var ya: Float
+                    var yb: Float
+                    var i = 0
+
+                    while (i < dimension-1)
+                    {
+                        yb = tmpN.n[i+1][index]
+                        ya = tmpN.n[i+1][index-1]
+                        mFactor[i] = mNoise[i+1] * ((yb-ya) * t+ya)
+                        i++
+                    }
+
+                    len   = (index.toFloat()) / (NUM_NOISE+1)
+                    lower = len + mNoise[0] * (tmpN.n[0][index-1] - len)
+                    len   = (index.toFloat()+1) / (NUM_NOISE+1)
+                    upper = len + mNoise[0] * (tmpN.n[0][index] - len)
+
+                return (upper-lower)*(d-index) + lower
+                }
         }
-      DistortedLibrary.logMessage("Dynamic: "+str+" base "+i+" : " + s);
-      }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// debugging only
-
-  @SuppressWarnings("unused")
-  private void checkBase()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // debugging only
+    private fun printBase(str: String)
     {
-    float tmp, cosA;
-    float[] len= new float[mDimension];
-    boolean error=false;
-
-    for(int i=0; i<mDimension; i++)
-      {
-      len[i] = 0.0f;
-
-      for(int k=0; k<mDimension; k++)
-        {
-        len[i] += baseV[i][k]*baseV[i][k];
-        }
+        var s: String
+        var t: Float
 
-      if( len[i] == 0.0f || len[0]/len[i] < 0.95f || len[0]/len[i]>1.05f )
+        for (i in 0..<dimension)
         {
-        DistortedLibrary.logMessage("Dynamic: length of vector "+i+" : "+Math.sqrt(len[i]));
-        error = true;
+            s = ""
+
+            for (j in 0..<dimension)
+            {
+                t = ((1000*baseV[i][j]).toInt()) / (1000.0f)
+                s += (" $t")
+            }
+            DistortedLibrary.logMessage("Dynamic: $str base $i : $s")
         }
-      }
-
-    for(int i=0; i<mDimension; i++)
-      for(int j=i+1; j<mDimension; j++)
-        {
-        tmp = 0.0f;
-
-        for(int k=0; k<mDimension; k++)
-          {
-          tmp += baseV[i][k]*baseV[j][k];
-          }
-
-        cosA = ( (len[i]==0.0f || len[j]==0.0f) ? 0.0f : tmp/(float)Math.sqrt(len[i]*len[j]));
-
-        if( cosA > 0.05f || cosA < -0.05f )
-          {
-          DistortedLibrary.logMessage("Dynamic: cos angle between vectors "+i+" and "+j+" : "+cosA);
-          error = true;
-          }
-        }
-
-    if( error ) printBase("");
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getNext(int curr, float time)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // debugging only
+    @Suppress("unused")
+    private fun checkBase()
     {
-    switch(mMode)
-      {
-      case MODE_LOOP: return curr==numPoints-1 ? 0:curr+1;
-      case MODE_PATH: return time<0.5f ? (curr+1) : (curr==0 ? 1 : curr-1);
-      case MODE_JUMP: return curr==numPoints-1 ? 1:curr+1;
-      default       : return 0;
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+        var tmp: Float
+        var cosA: Float
+        val len = FloatArray(dimension)
+        var error = false
 
-  private void checkAngle(int index)
-    {
-    float cosA = 0.0f;
+        for (i in 0..<dimension)
+        {
+            len[i] = 0.0f
+            for (k in 0..<dimension) len[i] += baseV[i][k]*baseV[i][k]
+
+            if (len[i]==0.0f || len[0]/len[i] < 0.95f || len[0]/len[i] > 1.05f)
+            {
+                DistortedLibrary.logMessage("Dynamic: length of vector $i : " + sqrt(len[i].toDouble()) )
+                error = true
+            }
+        }
 
-    for(int k=0;k<mDimension; k++)
-      cosA += baseV[index][k]*old[k];
+        for (i in 0..<dimension)
+            for (j in i+1..<dimension)
+            {
+                tmp = 0.0f
+                for (k in 0..<dimension) tmp += baseV[i][k]*baseV[j][k]
 
-    if( cosA<0.0f )
-      {
-      for(int j=0; j<mDimension; j++)
-        baseV[index][j] = -baseV[index][j];
-      }
-    }
+                cosA = (if (len[i]==0.0f || len[j]==0.0f) 0.0f else tmp / sqrt((len[i]*len[j]).toDouble()).toFloat())
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// helper function in case we are interpolating through exactly 2 points
+                if (cosA>0.05f || cosA<-0.05f)
+                {
+                    DistortedLibrary.logMessage("Dynamic: cos angle between vectors $i and $j : $cosA")
+                    error = true
+                }
+            }
 
-  protected void computeOrthonormalBase2(Static curr, Static next)
-    {
-    switch(mDimension)
-      {
-      case 1: Static1D curr1 = (Static1D)curr;
-              Static1D next1 = (Static1D)next;
-              baseV[0][0] = (next1.x-curr1.x);
-              break;
-      case 2: Static2D curr2 = (Static2D)curr;
-              Static2D next2 = (Static2D)next;
-              baseV[0][0] = (next2.x-curr2.x);
-              baseV[0][1] = (next2.y-curr2.y);
-              break;
-      case 3: Static3D curr3 = (Static3D)curr;
-              Static3D next3 = (Static3D)next;
-              baseV[0][0] = (next3.x-curr3.x);
-              baseV[0][1] = (next3.y-curr3.y);
-              baseV[0][2] = (next3.z-curr3.z);
-              break;
-      case 4: Static4D curr4 = (Static4D)curr;
-              Static4D next4 = (Static4D)next;
-              baseV[0][0] = (next4.x-curr4.x);
-              baseV[0][1] = (next4.y-curr4.y);
-              baseV[0][2] = (next4.z-curr4.z);
-              baseV[0][3] = (next4.w-curr4.w);
-              break;
-      case 5: Static5D curr5 = (Static5D)curr;
-              Static5D next5 = (Static5D)next;
-              baseV[0][0] = (next5.x-curr5.x);
-              baseV[0][1] = (next5.y-curr5.y);
-              baseV[0][2] = (next5.z-curr5.z);
-              baseV[0][3] = (next5.w-curr5.w);
-              baseV[0][4] = (next5.v-curr5.v);
-              break;
-      default: throw new RuntimeException("Unsupported dimension");
-      }
-
-    if( baseV[0][0] == 0.0f )
-      {
-      baseV[1][0] = 1.0f;
-      baseV[1][1] = 0.0f;
-      }
-    else
-      {
-      baseV[1][0] = 0.0f;
-      baseV[1][1] = 1.0f;
-      }
-
-    for(int i=2; i<mDimension; i++)
-      {
-      baseV[1][i] = 0.0f;
-      }
-
-    computeOrthonormalBase();
+        if (error) printBase("")
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// helper function in case we are interpolating through more than 2 points
-
-  protected void computeOrthonormalBaseMore(float time,VectorCache vc)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    fun getNext(curr: Int, time: Float): Int
     {
-    for(int i=0; i<mDimension; i++)
-      {
-      baseV[0][i] = (3*vc.a[i]*time+2*vc.b[i])*time+vc.c[i];   // first derivative, i.e. velocity vector
-      old[i]      = baseV[1][i];
-      baseV[1][i] =  6*vc.a[i]*time+2*vc.b[i];                 // second derivative,i.e. acceleration vector
-      }
-
-    computeOrthonormalBase();
+        return when (mMode)
+        {
+            MODE_LOOP -> if (curr == numPoints-1) 0        else curr+1
+            MODE_PATH -> if (time < 0.5f        ) (curr+1) else (if (curr==0) 1 else curr-1)
+            MODE_JUMP -> if (curr == numPoints-1) 1        else curr+1
+            else      -> 0
+        }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// When this function gets called, baseV[0] and baseV[1] should have been filled with two mDimension-al
-// vectors. This function then fills the rest of the baseV array with a mDimension-al Orthonormal base.
-// (mDimension-2 vectors, pairwise orthogonal to each other and to the original 2). The function always
-// leaves base[0] alone but generally speaking must adjust base[1] to make it orthogonal to base[0]!
-// The whole baseV is then used to compute Noise.
-//
-// When computing noise of a point travelling along a N-dimensional path, there are three cases:
-// a) we may be interpolating through 1 point, i.e. standing in place - nothing to do in this case
-// b) we may be interpolating through 2 points, i.e. travelling along a straight line between them -
-//    then pass the velocity vector in baseV[0] and anything linearly independent in base[1].
-//    The output will then be discontinuous in dimensions>2 (sad corollary from the Hairy Ball Theorem)
-//    but we don't care - we are travelling along a straight line, so velocity (aka baseV[0]!) does
-//    not change.
-// c) we may be interpolating through more than 2 points. Then interpolation formulas ensure the path
-//    will never be a straight line, even locally -> we can pass in baseV[0] and baseV[1] the velocity
-//    and the acceleration (first and second derivatives of the path) which are then guaranteed to be
-//    linearly independent. Then we can ensure this is continuous in dimensions <=4. This leaves
-//    dimension 5 (ATM WAVE is 5-dimensional) discontinuous -> WAVE will suffer from chaotic noise.
-//
-// Bear in mind here the 'normal' in 'orthonormal' means 'length equal to the length of the original
-// velocity vector' (rather than the standard 1)
-
-  protected void computeOrthonormalBase()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun checkAngle(index: Int)
     {
-    int last_non_zero=-1;
-    float tmp;
-
-    for(int i=0; i<mDimension; i++)
-      if( baseV[0][i] != 0.0f )
-        last_non_zero=i;
-
-    if( last_non_zero==-1 )                                               ///
-      {                                                                   //  velocity is the 0 vector -> two
-      for(int i=0; i<mDimension-1; i++)                                   //  consecutive points we are interpolating
-        for(int j=0; j<mDimension; j++)                                   //  through are identical -> no noise,
-          baseV[i+1][j]= 0.0f;                                            //  set the base to 0 vectors.
-      }                                                                   ///
-    else
-      {
-      for(int i=1; i<mDimension; i++)                                     /// One iteration computes baseV[i][*]
-        {                                                                 //  (aka b[i]), the i-th orthonormal vector.
-        buf[i-1]=0.0f;                                                    //
-                                                                          //  We can use (modified!) Gram-Schmidt.
-        for(int k=0; k<mDimension; k++)                                   //
-          {                                                               //
-          if( i>=2 )                                                      //  b[0] = b[0]
-            {                                                             //  b[1] = b[1] - (<b[1],b[0]>/<b[0],b[0]>)*b[0]
-            old[k] = baseV[i][k];                                         //  b[2] = b[2] - (<b[2],b[0]>/<b[0],b[0]>)*b[0] - (<b[2],b[1]>/<b[1],b[1]>)*b[1]
-            baseV[i][k]= (k==i-(last_non_zero>=i?1:0)) ? 1.0f : 0.0f;     //  b[3] = b[3] - (<b[3],b[0]>/<b[0],b[0]>)*b[0] - (<b[3],b[1]>/<b[1],b[1]>)*b[1] - (<b[3],b[2]>/<b[2],b[2]>)*b[2]
-            }                                                             //  (...)
-                                                                          //  then b[i] = b[i] / |b[i]|  ( Here really b[i] = b[i] / (|b[0]|/|b[i]|)
-          tmp = baseV[i-1][k];                                            //
-          buf[i-1] += tmp*tmp;                                            //
-          }                                                               //
-                                                                          //
-        for(int j=0; j<i; j++)                                            //
-          {                                                               //
-          tmp = 0.0f;                                                     //
-          for(int k=0;k<mDimension; k++) tmp += baseV[i][k]*baseV[j][k];  //
-          tmp /= buf[j];                                                  //
-          for(int k=0;k<mDimension; k++) baseV[i][k] -= tmp*baseV[j][k];  //
-          }                                                               //
-                                                                          //
-        checkAngle(i);                                                    //
-        }                                                                 /// end compute baseV[i][*]
-
-      buf[mDimension-1]=0.0f;                                             /// Normalize
-      for(int k=0; k<mDimension; k++)                                     //
-        {                                                                 //
-        tmp = baseV[mDimension-1][k];                                     //
-        buf[mDimension-1] += tmp*tmp;                                     //
-        }                                                                 //
-                                                                          //
-      for(int i=1; i<mDimension; i++)                                     //
-        {                                                                 //
-        tmp = (float)Math.sqrt(buf[0]/buf[i]);                            //
-        for(int k=0;k<mDimension; k++) baseV[i][k] *= tmp;                //
-        }                                                                 /// End Normalize
-      }
-    }
+        var cosA = 0.0f
+        for (k in 0..<dimension) cosA += baseV[index][k]*old[k]
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  abstract void interpolate(float[] buffer, int offset, float time);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// 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 straight 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;  
+        if (cosA < 0.0f)
+            for (j in 0..<dimension) baseV[index][j] = -baseV[index][j]
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the number of Points this Dynamic has been fed with.
- *   
- * @return the number of Points we are currently interpolating through.
- */
-  public synchronized int getNumPoints()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // helper function in case we are interpolating through exactly 2 points
+    protected fun computeOrthonormalBase2(curr: Static, next: Static)
     {
-    return numPoints;  
-    }
+        when (dimension)
+        {
+            1 ->
+                {
+                    val curr1 = curr as Static1D
+                    val next1 = next as Static1D
+                    baseV[0][0] = (next1.x - curr1.x)
+                }
+
+            2 ->
+                {
+                    val curr2 = curr as Static2D
+                    val next2 = next as Static2D
+                    baseV[0][0] = (next2.x - curr2.x)
+                    baseV[0][1] = (next2.y - curr2.y)
+                }
+
+            3 ->
+                {
+                    val curr3 = curr as Static3D
+                    val next3 = next as Static3D
+                    baseV[0][0] = (next3.x - curr3.x)
+                    baseV[0][1] = (next3.y - curr3.y)
+                    baseV[0][2] = (next3.z - curr3.z)
+                }
+
+            4 ->
+                {
+                    val curr4 = curr as Static4D
+                    val next4 = next as Static4D
+                    baseV[0][0] = (next4.x - curr4.x)
+                    baseV[0][1] = (next4.y - curr4.y)
+                    baseV[0][2] = (next4.z - curr4.z)
+                    baseV[0][3] = (next4.w - curr4.w)
+                }
+
+            5 ->
+                {
+                    val curr5 = curr as Static5D
+                    val next5 = next as Static5D
+                    baseV[0][0] = (next5.x - curr5.x)
+                    baseV[0][1] = (next5.y - curr5.y)
+                    baseV[0][2] = (next5.z - curr5.z)
+                    baseV[0][3] = (next5.w - curr5.w)
+                    baseV[0][4] = (next5.v - curr5.v)
+                }
+
+            else -> throw RuntimeException("Unsupported dimension")
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Sets how many revolutions we want to do.
- * <p>
- * Does not have to be an integer. What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- * Count<=0 means 'go on interpolating indefinitely'.
- * 
- * @param count the number of times we want to interpolate between our collection of Points.
- */
-  public void setCount(float count)
-    {
-    mCount = count;  
-    }
+        if (baseV[0][0] == 0.0f)
+        {
+            baseV[1][0] = 1.0f
+            baseV[1][1] = 0.0f
+        }
+        else
+        {
+            baseV[1][0] = 0.0f
+            baseV[1][1] = 1.0f
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the number of revolutions this Dynamic will make.
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @return the number revolutions this Dynamic will make.
- */
-  public float getCount()
-    {
-    return mCount;
-    }
+        for (i in 2..<dimension) baseV[1][i] = 0.0f
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Start running from the beginning again.
- *
- * If a Dynamic has been used already, and we want to use it again and start interpolating from the
- * first Point, first we need to reset it using this method.
- */
-  public void resetToBeginning()
-    {
-    mStartTime = -1;
+        computeOrthonormalBase()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * @param duration Number of milliseconds one revolution will take.
- *                 What constitutes 'one revolution' depends on the MODE:
- *                 {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- */
-  public void setDuration(long duration)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // helper function in case we are interpolating through more than 2 points
+    protected fun computeOrthonormalBaseMore(time: Float, vc: VectorCache)
     {
-    mDuration = duration;
-    }
+        for (i in 0..<dimension)
+        {
+            baseV[0][i] = (3*vc.a[i]*time + 2*vc.b[i])*time + vc.c[i] // first derivative, i.e. velocity vector
+            old[i] = baseV[1][i]
+            baseV[1][i] = 6*vc.a[i]*time + 2*vc.b[i] // second derivative,i.e. acceleration vector
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * @return Number of milliseconds one revolution will take.
- */
-  public long getDuration()
-    {
-    return mDuration;
+        computeOrthonormalBase()
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // When this function gets called, baseV[0] and baseV[1] should have been filled with two mDimension-al
+    // vectors. This function then fills the rest of the baseV array with a mDimension-al Orthonormal base.
+    // (mDimension-2 vectors, pairwise orthogonal to each other and to the original 2). The function always
+    // leaves base[0] alone but generally speaking must adjust base[1] to make it orthogonal to base[0]!
+    // The whole baseV is then used to compute Noise.
+    //
+    // When computing noise of a point travelling along a N-dimensional path, there are three cases:
+    // a) we may be interpolating through 1 point, i.e. standing in place - nothing to do in this case
+    // b) we may be interpolating through 2 points, i.e. travelling along a straight line between them -
+    //    then pass the velocity vector in baseV[0] and anything linearly independent in base[1].
+    //    The output will then be discontinuous in dimensions>2 (sad corollary from the Hairy Ball Theorem)
+    //    but we don't care - we are travelling along a straight line, so velocity (aka baseV[0]!) does
+    //    not change.
+    // c) we may be interpolating through more than 2 points. Then interpolation formulas ensure the path
+    //    will never be a straight line, even locally -> we can pass in baseV[0] and baseV[1] the velocity
+    //    and the acceleration (first and second derivatives of the path) which are then guaranteed to be
+    //    linearly independent. Then we can ensure this is continuous in dimensions <=4. This leaves
+    //    dimension 5 (ATM WAVE is 5-dimensional) discontinuous -> WAVE will suffer from chaotic noise.
+    //
+    // Bear in mind here the 'normal' in 'orthonormal' means 'length equal to the length of the original
+    // velocity vector' (rather than the standard 1)
+    protected fun computeOrthonormalBase()
+    {
+        var lastnonzero = -1
+        var tmp: Float
+
+        for (i in 0..<dimension)
+            if (baseV[0][i] != 0.0f) lastnonzero = i
+
+        if (lastnonzero == -1)
+        {                                   //  velocity is the 0 vector -> two
+            for (i in 0..<dimension-1)    //  consecutive points we are interpolating
+                for (j in 0..<dimension)  //  through are identical -> no noise,
+                    baseV[i+1][j] = 0.0f    //  set the base to 0 vectors.
+        }
+        else
+        {
+            for (i in 1..<dimension)                                                             // One iteration computes baseV[i][*]
+            {                                                                                      //  (aka b[i]), the i-th orthonormal vector.
+                buf[i-1] = 0.0f                                                                    //
+                                                                                                   //  We can use (modified!) Gram-Schmidt.
+                for (k in 0..<dimension)                                                         //
+                {                                                                                  //
+                    if (i>=2)                                                                      //  b[0] = b[0]
+                    {                                                                              //  b[1] = b[1] - (<b[1],b[0]>/<b[0],b[0]>)*b[0]
+                        old[k] = baseV[i][k]                                                       //  b[2] = b[2] - (<b[2],b[0]>/<b[0],b[0]>)*b[0] - (<b[2],b[1]>/<b[1],b[1]>)*b[1]
+                        baseV[i][k] = if (k== i - (if (lastnonzero >= i) 1 else 0)) 1.0f else 0.0f //  b[3] = b[3] - (<b[3],b[0]>/<b[0],b[0]>)*b[0] - (<b[3],b[1]>/<b[1],b[1]>)*b[1] - (<b[3],b[2]>/<b[2],b[2]>)*b[2]
+                    }                                                                              //  (...)
+                                                                                                   //  then b[i] = b[i] / |b[i]|  ( Here really b[i] = b[i] / (|b[0]|/|b[i]|)
+                    tmp = baseV[i-1][k]                                                            //
+                    buf[i-1] += tmp*tmp                                                            //
+                }                                                                                  //
+                                                                                                   //
+                for (j in 0..<i)                                                                 //
+                {                                                                                  //
+                    tmp = 0.0f                                                                     //
+                    for (k in 0..<dimension) tmp += baseV[i][k]*baseV[j][k]                      //
+                    tmp /= buf[j]                                                                  //
+                    for (k in 0..<dimension) baseV[i][k] -= tmp*baseV[j][k]                      //
+                }                                                                                  //
+                                                                                                   //
+                checkAngle(i)                                                                      //
+            }                                                                                      //
+                                                                                                   // end compute baseV[i][*]
+            buf[dimension-1] = 0.0f
+                                                                                                   // Normalize
+            for (k in 0..<dimension)                                                             //
+            {                                                                                      //
+                tmp = baseV[dimension-1][k]                                                        //
+                buf[dimension-1] += tmp*tmp                                                        //
+            }                                                                                      //
+                                                                                                   //
+            for (i in 1..<dimension)                                                             //
+            {                                                                                      //
+                tmp = sqrt((buf[0] / buf[i]).toDouble()).toFloat()                                 //
+                for (k in 0..<dimension) baseV[i][k] *= tmp                                      //
+            }                                                                                      // End Normalize
+        }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * @param convexity If set to the default (1.0f) then interpolation between 4 points
- *                  (1,0) (0,1) (-1,0) (0,-1) will be the natural circle centered at (0,0) with radius 1.
- *                  The less it is, the less convex the circle becomes, ultimately when convexity=0.0f
- *                  then the interpolation shape will be straight lines connecting the four points.
- *                  Further setting this to negative values will make the shape concave.
- *                  Valid values: all floats. (although probably only something around (0,2) actually
- *                  makes sense)
- */
-  public void setConvexity(float convexity)
-    {
-    if( mConvexity!=convexity )
-      {
-      mConvexity = convexity;
-      cacheDirty = true;
-      }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    abstract fun interpolate(buffer: FloatArray, offset: Int, tm: Float)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the mode of the interpolation to Loop, Path or Jump.
+    *
+    *  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.
+    *  Path is when we come back from the last point back to the first the same way we got there.
+    *  Jump is when we go from first to last and then jump straight back to the first.
+    *
+    * @param mode [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    */
+    fun setMode(mode: Int) { mMode = mode }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Start running from the beginning again.
+    *
+    * If a Dynamic has been used already, and we want to use it again and start interpolating from the
+    * first Point, first we need to reset it using this method.
+    */
+    fun resetToBeginning() { mStartTime = -1 }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the access type this Dynamic will be working in.
+    *
+    * @param type [Dynamic.ACCESS_TYPE_RANDOM] or [Dynamic.ACCESS_TYPE_SEQUENTIAL].
+    */
+    fun setAccessType(type: Int)
+    {
+        mAccessType = type
+        mLastPos = -1.0
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the way we compute the interpolation speed.
+    *
+    * @param mode [Dynamic.SPEED_MODE_SMOOTH] or [Dynamic.SPEED_MODE_SEGMENT_CONSTANT] or
+    * [Dynamic.SPEED_MODE_GLOBALLY_CONSTANT]
+    */
+    fun setSpeedMode(mode: Int)
+    {
+        if (mSpeedMode!=mode)
+        {
+            if (mSpeedMode==SPEED_MODE_SMOOTH)
+                for (i in 0..<numPoints) smoothOutSegment(vc!!.elementAt(i))
+            mSpeedMode = mode
+        }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * @return See {@link Dynamic#setConvexity(float)}
- */
-  public float getConvexity()
-    {
-    return mConvexity;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
+    *
+    * This version differs from the previous in that it returns a boolean value which indicates whether
+    * the interpolation is finished.
+    *
+    * @param buffer Float buffer we will write the results to.
+    * @param offset Offset in the buffer where to write the result.
+    * @param tm Time of interpolation. Time=0.0 is the beginning of the first revolution, time=1.0 - the end
+    * of the first revolution, time=2.5 - the middle of the third revolution.
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    * @param st Time difference between now and the last time we called this function. Needed to figure
+    * out if the previous time we were called the effect wasn't finished yet, but now it is.
+    * @return true if the interpolation reached its end.
+    */
+    fun get(buffer: FloatArray, offset: Int, tm: Long, st: Long): Boolean
+    {
+        var time = tm
+        var step = st
+        val pos: Double
+
+        if (duration <= 0.0f)
+        {
+            interpolate(buffer, offset, count-count.toInt())
+            return false
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Sets the access type this Dynamic will be working in.
- *
- * @param type {@link Dynamic#ACCESS_TYPE_RANDOM} or {@link Dynamic#ACCESS_TYPE_SEQUENTIAL}.
- */
-  public void setAccessType(int type)
-    {
-    mAccessType = type;
-    mLastPos = -1;
-    }
+        if (mStartTime == -1L)
+        {
+            mStartTime = time
+            mLastPos   = -1.0
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * @return See {@link Dynamic#setSpeedMode(int)}
- */
-  public float getSpeedMode()
-    {
-    return mSpeedMode;
-    }
+        val diff = time-mPausedTime
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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 )
+        if (mStartTime<mPausedTime && mCorrectedTime<mPausedTime && diff>=0 && diff<=step)
         {
-        for(int i=0; i<numPoints; i++)
-          {
-          tmpCache1 = vc.elementAt(i);
-          smoothOutSegment(tmpCache1);
-          }
+            mCorrectedTime = mPausedTime
+            mStartTime += diff
+            step -= diff
         }
 
-      mSpeedMode = mode;
-      }
-    }
+        time -= mStartTime
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the Dimension, ie number of floats in a single Point this Dynamic interpolates through.
- *
- * @return number of floats in a single Point (ie its dimension) contained in the Dynamic.
- */
-  public int getDimension()
-    {
-    return mDimension;
-    }
+        if (time+step > duration*count && count>0.0f)
+        {
+            interpolate(buffer, offset, count-count.toInt())
+            return true
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Writes the results of interpolation between the Points at time 'time' to the passed float buffer.
- * <p>
- * This version differs from the previous in that it returns a boolean value which indicates whether
- * the interpolation is finished.
- *
- * @param buffer Float buffer we will write the results to.
- * @param offset Offset in the buffer where to write the result.
- * @param time   Time of interpolation. Time=0.0 is the beginning of the first revolution, time=1.0 - the end
- *               of the first revolution, time=2.5 - the middle of the third revolution.
- *               What constitutes 'one revolution' depends on the MODE:
- *               {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- * @param step   Time difference between now and the last time we called this function. Needed to figure
- *               out if the previous time we were called the effect wasn't finished yet, but now it is.
- * @return true if the interpolation reached its end.
- */
-  public boolean get(float[] buffer, int offset, long time, long step)
-    {
-    if( mDuration<=0.0f )
-      {
-      interpolate(buffer,offset,mCount-(int)mCount);
-      return false;
-      }
-
-    if( mStartTime==-1 )
-      {
-      mStartTime = time;
-      mLastPos   = -1;
-      }
-
-    long diff = time-mPausedTime;
-
-    if( mStartTime<mPausedTime && mCorrectedTime<mPausedTime && diff>=0 && diff<=step )
-      {
-      mCorrectedTime = mPausedTime;
-      mStartTime += diff;
-      step -= diff;
-      }
-
-    time -= mStartTime;
-
-    if( time+step > mDuration*mCount && mCount>0.0f )
-      {
-      interpolate(buffer,offset,mCount-(int)mCount);
-      return true;
-      }
-
-    double pos;
-
-    if( mAccessType ==ACCESS_TYPE_SEQUENTIAL )
-      {
-      pos = mLastPos<0 ? (double)time/mDuration : (double)step/mDuration + mLastPos;
-      mLastPos = pos;
-      }
-    else
-      {
-      pos = (double)time/mDuration;
-      }
-
-    interpolate(buffer,offset, (float)(pos-(int)pos) );
-    return false;
+        if (mAccessType == ACCESS_TYPE_SEQUENTIAL)
+        {
+            pos = if (mLastPos < 0) time.toDouble()/duration else step.toDouble()/duration + mLastPos
+            mLastPos = pos
+        }
+        else
+        {
+            pos = time.toDouble() / duration
+        }
+
+        interpolate(buffer, offset, (pos-pos.toInt()).toFloat())
+        return false
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/type/Dynamic1D.kt b/src/main/java/org/distorted/library/type/Dynamic1D.kt
index 7f7a7e7..5d2ef67 100644
--- a/src/main/java/org/distorted/library/type/Dynamic1D.kt
+++ b/src/main/java/org/distorted/library/type/Dynamic1D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,428 +18,407 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
-import java.util.Vector;
+import java.util.Vector
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 1-dimensional implementation of the Dynamic class to interpolate between a list
+/** A 1-dimensional implementation of the Dynamic class to interpolate between a list
 * of Static1Ds.
 */
+class Dynamic1D : Dynamic, Data1D
+{
+    private val vv: Vector<Static1D>
 
-public class Dynamic1D extends Dynamic implements Data1D
-  {
-  private final Vector<Static1D> vv;
-  private Static1D prev, curr, next;
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // no array bounds checking!
+    private fun computeVelocity(c: Int)
+    {
+        val p = if (c >           0) c-1 else numPoints-1
+        val n = if (c < numPoints-1) c+1 else 0
+        val prev = vv.elementAt(p)
+        val curr = vv.elementAt(c)
+        val next = vv.elementAt(n)
+        val cache= vc!!.elementAt(c)
+        val px = curr.x - prev.x
+        val nx = next.x - curr.x
+
+        val d = nx*nx
+
+        if (d>0)
+        {
+            val q = sqrt( ((px*px)/d).toDouble() ).toFloat()
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void computeVelocity(int c)
+            if (q>1) cache.velocity[0] = nx + px/q
+            else     cache.velocity[0] = px + nx*q
+
+        }
+        else cache.velocity[0] = 0.0f
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun recomputeCache()
     {
-    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);
-
-    tmpCache1 = 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 )
+        if (numPoints==1)
         {
-        tmpCache1.velocity[0] = nx+px/q;
+            val cache = vc!!.elementAt(0)
+            val curr = vv.elementAt(0)
+
+            cache.a[0] = 0.0f
+            cache.b[0] = 0.0f
+            cache.c[0] = curr.x
+            cache.d[0] = 0.0f
         }
-      else
+        else if (numPoints==2)
         {
-        tmpCache1.velocity[0] = px+nx*q;
+            val cache1 = vc!!.elementAt(0)
+            val cache2 = vc!!.elementAt(1)
+            val curr = vv.elementAt(0)
+            val next = vv.elementAt(1)
+
+            cache1.a[0] = 0.0f
+            cache1.b[0] = 0.0f
+            cache1.c[0] = next.x - curr.x
+            cache1.d[0] = curr.x
+
+            cache2.a[0] = 0.0f
+            cache2.b[0] = 0.0f
+            cache2.c[0] = curr.x - next.x
+            cache2.d[0] = next.x
         }
-      }
-    else
-      {
-      tmpCache1.velocity[0] = 0.0f;
-      }
-    }
-      
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      tmpCache1.a[0] = 0.0f;
-      tmpCache1.b[0] = 0.0f;
-      tmpCache1.c[0] = curr.x;
-      tmpCache1.d[0] = 0.0f;
-      }
-    else if( numPoints==2 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      tmpCache2 = vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-          
-      tmpCache1.a[0] = 0.0f;
-      tmpCache1.b[0] = 0.0f;
-      tmpCache1.c[0] = next.x - curr.x;
-      tmpCache1.d[0] = curr.x;
-      
-      tmpCache2.a[0] = 0.0f;
-      tmpCache2.b[0] = 0.0f;
-      tmpCache2.c[0] = curr.x - next.x;
-      tmpCache2.d[0] = next.x;
-      }
-    else
-      {
-      int i, n;  
-         
-      for(i=0; i<numPoints; i++) computeVelocity(i);
-   
-      for(i=0; i<numPoints; i++)
+        else
         {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmpCache1 = vc.elementAt(i);
-        tmpCache2 = vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-    
-        tmpCache1.cached[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);
+            var n: Int
+            var i = 0
+
+            while (i<numPoints)
+            {
+                computeVelocity(i)
+                i++
+            }
+
+            i = 0
+            while (i < numPoints)
+            {
+                n = if (i < numPoints-1) i+1 else 0
+
+                val cache1 = vc!!.elementAt(i)
+                val cache2 = vc!!.elementAt(n)
+                val curr = vv.elementAt(i)
+                val next = vv.elementAt(n)
+
+                cache1.cached[0] = curr.x
+
+                cache1.a[0] = mConvexity * ( 2*curr.x +   cache1.velocity[0] - 2*next.x + cache2.velocity[0])
+                cache1.b[0] = mConvexity * (-3*curr.x - 2*cache1.velocity[0] + 3*next.x - cache2.velocity[0])
+                cache1.c[0] = mConvexity * (cache1.velocity[0]) + (1.0f-mConvexity) * (next.x-curr.x)
+                cache1.d[0] = curr.x
+
+                if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) smoothOutSegment(cache1)
+                i++
+            }
         }
-      }
-   
-    cacheDirty = false;
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Dynamic1D()
-    {
-    super(0,0.5f,1);
-    vv = new Vector<>();
+        cacheDirty = false
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor setting the speed of interpolation and the number of revolutions.
- *
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @param duration number of milliseconds it takes to do one revolution.
- * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
- */
-  public Dynamic1D(int duration, float count)
-    {
-    super(duration,count,1);
-    vv = new Vector<>();
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    constructor() : super(0,0.5f,1) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Constructor setting the speed of interpolation and the number of revolutions.
+    *
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    *
+    * @param duration number of milliseconds it takes to do one revolution.
+    * @param count number of revolutions we will do. Count<=0 means 'infinite'.
+    */
+    constructor(duration: Int, count: Float) : super(duration,count,1) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Returns the Static1D at index.
+    *
+    * @param index the index of the Point we are interested in .
+    * @return The Static1D, if 0<=location&lt;getNumPoints(), or null otherwise.
+    */
+    @Synchronized
+    fun getPoint(index: Int): Static1D? { return if (index in 0..<numPoints) vv.elementAt(index) else null
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Resets the Point.
+    *
+    * @param index the index of the Point we are setting.
+    * @param x New value of its first float.
+    */
+    @Synchronized
+    fun setPoint(index: Int, x: Float)
     {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
+        if (index in 0..<numPoints)
         {
-        curr.set(x);
-        cacheDirty=true;
+            val curr = vv.elementAt(index)
+
+            if (curr!=null)
+            {
+                curr.set0(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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static1D to the end of our list of Points to interpolate through.
+    *
+    * Only a reference to the Point gets added to the List; this means that one can add a Point
+    * here, and later on [Static1D.set] it to some new value and the change will
+    * be seamlessly reflected in the interpolated path.
+    *
+    * A Point can be added multiple times.
+    *
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(v: Static1D?)
     {
-    if( v!=null )
-      {
-      vv.add(v);
-     
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
+        if (v!=null)
         {
-        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;
+            vv.add(v)
+
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0, 1 -> {}
+                2    ->
+                    {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        cacheDirty = true
+                    }
+
+                else ->
+                    {
+                        vc!!.add(VectorCache())
+                        cacheDirty = true
+                    }
+            }
+
+            numPoints++
         }
-     
-      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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static1D to the index'th place in our List of Points to interpolate through.
+    *
+    * @param index Index in our List to add the new Point at.
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(index: Int, v: Static1D?)
     {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-             
-      switch(numPoints)
+        if (v!=null)
         {
-        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;
+            vv.add(index,v)
+
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0, 1 -> {}
+                2 ->
+                    {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        cacheDirty = true
+                    }
+
+                else ->
+                    {
+                        vc!!.add(index,VectorCache())
+                        cacheDirty = true
+                    }
+            }
+
+            numPoints++
         }
-      
-      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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all occurrences of Point v from the List of Points to interpolate through.
+    *
+    * @param v The Point to remove.
+    * @return `true` if we have removed at least one Point.
+    */
+    @Synchronized
+    fun remove(v: Static1D): Boolean
     {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
+        var n = vv.indexOf(v)
+        var found = false
+
+        while (n>=0)
         {
-        case 0:
-        case 1:
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.remove(n);
-                cacheDirty=true;
+            vv.removeAt(n)
+
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3       -> vc!!.removeAllElements()
+                else    ->
+                    {
+                        vc!!.removeAt(n)
+                        cacheDirty = true
+                    }
+            }
+
+            numPoints--
+            found = true
+            n = vv.indexOf(v)
         }
 
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    return found;
+        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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes a index'th Point from the List of Points we interpolate through.
+    *
+    * @param index index of the Point we want to remove.
+    * @return `true` if location is valid, i.e. if 0<=location&lt;getNumPoints().
+    */
+    @Synchronized
+    fun remove(index: Int): Boolean
     {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-      
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
+        if (index in 0..<numPoints)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.removeElementAt(location);
+            vv.removeElementAt(index)
+
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3       -> vc!!.removeAllElements()
+                else    -> vc!!.removeElementAt(index)
+            }
+
+            numPoints--
+            cacheDirty = true
+            return true
         }
 
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
+        return false
+    }
 
-   return false;
-   }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all Points.
+    */
+    @Synchronized
+    fun removeAll()
     {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
+        numPoints = 0
+        vv.removeAllElements()
+        vc!!.removeAllElements()
+        cacheDirty = false
+        if (vn!=null) vn!!.removeAllElements()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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 synchronized void setNoise(Static1D noise)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the 'smoothness' of interpolation.
+    *
+    * 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.
+    */
+    @Synchronized
+    fun setNoise(noise: Static1D)
     {
-    if( vn==null )
-      {
-      vn = new Vector<>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-
-      if( mDimension>=2 )
+        if (vn==null)
         {
-        mFactor = new float[mDimension-1];
+            vn = Vector()
+            for (i in 0..<numPoints) vn!!.add(VectorNoise())
+            if (dimension>=2) mFactor = FloatArray(dimension-1)
+            mNoise = FloatArray(dimension)
         }
 
-      mNoise = new float[mDimension];
-      }
-
-    if( noise.x<0.0f ) noise.x = 0.0f;
-    if( noise.x>1.0f ) noise.x = 1.0f;
+        if (noise.x<0.0f) noise.x = 0.0f
+        if (noise.x>1.0f) noise.x = 1.0f
 
-    mNoise[0] = noise.x;
+        mNoise[0] = noise.x
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  synchronized void interpolate(float[] buffer, int offset, float time)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    @Synchronized
+    override fun interpolate(buffer: FloatArray, offset: Int, tm: Float)
     {
-    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);
-
-              int segment= (int)(2*time);
+        var time = tm
 
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
+        when (numPoints)
+        {
+            0 -> buffer[offset] = 0.0f
+            1 ->
+                {
+                    val curr = vv.elementAt(0)
+                    buffer[offset] = curr.x
+                }
 
-              if( vn!=null )
+            2 ->
                 {
-                if( segment != mSegment )
-                  {
-                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
-                  mSegment = segment;
-                  }
+                    val curr = vv.elementAt(0)
+                    val next = vv.elementAt(1)
 
-                time = noise(time,0);
+                    val segment = (2*time).toInt()
+
+                    if (mMode == MODE_LOOP || mMode == MODE_PATH) time = (if (time>0.5f) 2-2*time else 2*time)
+
+                    if (vn!=null)
+                    {
+                        if (segment!=mSegment)
+                        {
+                            if (mMode != MODE_JUMP || mSegment==1) vn!!.elementAt(0).computeNoise()
+                            mSegment = segment
+                        }
+
+                        time = noise(time, 0)
+                    }
+
+                    buffer[offset] = (next.x-curr.x)*time + curr.x
                 }
-             
-              buffer[offset] = (next.x-curr.x)*time + curr.x;
-              break;
-      default:computeSegmentAndTime(time);
 
-              if( mTmpVec>=0 && mTmpVec<numPoints )
+            else ->
                 {
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext = getNext(mTmpVec,time);
-                  next = vv.elementAt(vecNext);
-                  tmpCache2 = vc.elementAt(vecNext);
-
-                  if( tmpCache2.cached[0]!=next.x ) recomputeCache();
-                  }
-
-                if( mSegment!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
-
-                mSegment = mTmpSeg;
-                time = mTmpTime-mTmpVec;
-                tmpCache1 = vc.elementAt(mTmpVec);
-                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
-
-                if( vn!=null )
-                  {
-                  time = noise(time,mTmpVec);
-                  }
-            
-                buffer[offset] = ((tmpCache1.a[0]*time+ tmpCache1.b[0])*time+ tmpCache1.c[0])*time+ tmpCache1.d[0];
-                break;
+                    computeSegmentAndTime(time)
+
+                    if (mTmpVec>=0 && mTmpVec<numPoints)
+                    {
+                        if (cacheDirty) recomputeCache() // recompute cache if we have added or remove vectors since last computation
+                        else if (mSegment!=mTmpSeg)      // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                        {
+                            val vecNext = getNext(mTmpVec, time)
+                            val next = vv.elementAt(vecNext)
+                            val cache = vc!!.elementAt(vecNext)
+
+                            if (cache.cached[0]!=next.x) recomputeCache()
+                        }
+
+                        if (mSegment != mTmpSeg && vn != null) vn!!.elementAt(mTmpVec).computeNoise()
+
+                        mSegment = mTmpSeg
+                        time = mTmpTime - mTmpVec
+                        val cache = vc!!.elementAt(mTmpVec)
+                        if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) time = smoothSpeed(time,cache)
+                        if (vn!=null) time = noise(time,mTmpVec)
+                        buffer[offset] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0]
+                    }
                 }
         }
-     }  
-  
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/type/Dynamic2D.kt b/src/main/java/org/distorted/library/type/Dynamic2D.kt
index 8590611..78ae4e2 100644
--- a/src/main/java/org/distorted/library/type/Dynamic2D.kt
+++ b/src/main/java/org/distorted/library/type/Dynamic2D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,470 +18,463 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
-import java.util.Vector;
+import java.util.Vector
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 2-dimensional implementation of the Dynamic class to interpolate between a list
-* of Static2Ds.
+/** A 2-dimensional implementation of the Dynamic class to interpolate between a list of Static2Ds.
 */
+class Dynamic2D : Dynamic, Data2D
+{
+    private val vv: Vector<Static2D>
 
-public class Dynamic2D extends Dynamic implements Data2D
-  {
-  private final Vector<Static2D> vv;
-  private Static2D prev, curr, next;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void computeVelocity(int c)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // no array bounds checking!
+    private fun computeVelocity(c: Int)
     {
-    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);
-
-    tmpCache1 = 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 )
+        val p = if (c >           0) c-1 else numPoints-1
+        val n = if (c < numPoints-1) c+1 else 0
+
+        val prev = vv.elementAt(p)
+        val curr = vv.elementAt(c)
+        val next = vv.elementAt(n)
+        val cache= vc!!.elementAt(c)
+
+        val px = curr.x - prev.x
+        val py = curr.y - prev.y
+        val nx = next.x - curr.x
+        val ny = next.y - curr.y
+
+        val d = nx*nx + ny*ny
+
+        if (d>0)
         {
-        tmpCache1.velocity[0] = nx+px/q;
-        tmpCache1.velocity[1] = ny+py/q;
+            val q = sqrt( ((px*px+py*py)/d).toDouble() ).toFloat()
+
+            if (q>1)
+            {
+                cache.velocity[0] = nx + px/q
+                cache.velocity[1] = ny + py/q
+            }
+            else
+            {
+                cache.velocity[0] = px + nx*q
+                cache.velocity[1] = py + ny*q
+            }
         }
-      else
+        else
         {
-        tmpCache1.velocity[0] = px+nx*q;
-        tmpCache1.velocity[1] = py+ny*q;
+            cache.velocity[0] = 0.0f
+            cache.velocity[1] = 0.0f
         }
-      }
-    else
-      {
-      tmpCache1.velocity[0] = 0.0f;
-      tmpCache1.velocity[1] = 0.0f;
-      }
     }
-   
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      curr= vv.elementAt(0);
-              
-      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 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      tmpCache2 = vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-          
-      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;
-      
-      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
-      {
-      int i, n;  
-         
-      for(i=0; i<numPoints; i++) computeVelocity(i);
-   
-      for(i=0; i<numPoints; i++)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun recomputeCache()
+    {
+        if (numPoints==1)
         {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmpCache1 = vc.elementAt(i);
-        tmpCache2 = vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        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);
+            val cache = vc!!.elementAt(0)
+            val curr = vv.elementAt(0)
+
+            cache.a[1] = 0.0f
+            cache.a[0] = cache.a[1]
+            cache.b[1] = 0.0f
+            cache.b[0] = cache.b[1]
+            cache.c[0] = curr.x
+            cache.c[1] = curr.y
+            cache.d[1] = 0.0f
+            cache.d[0] = cache.d[1]
+        }
+        else if (numPoints==2)
+        {
+            val cache1 = vc!!.elementAt(0)
+            val cache2 = vc!!.elementAt(1)
+            val curr = vv.elementAt(0)
+            val next = vv.elementAt(1)
+
+            cache1.a[1] = 0.0f
+            cache1.a[0] = cache1.a[1]
+            cache1.b[1] = 0.0f
+            cache1.b[0] = cache1.b[1]
+            cache1.c[0] = next.x - curr.x
+            cache1.c[1] = next.y - curr.y
+            cache1.d[0] = curr.x
+            cache1.d[1] = curr.y
+
+            cache2.a[1] = 0.0f
+            cache2.a[0] = cache2.a[1]
+            cache2.b[1] = 0.0f
+            cache2.b[0] = cache2.b[1]
+            cache2.c[0] = curr.x - next.x
+            cache2.c[1] = curr.y - next.y
+            cache2.d[0] = next.x
+            cache2.d[1] = next.y
+        }
+        else
+        {
+            var n: Int
+            var i = 0
+
+            while (i<numPoints)
+            {
+                computeVelocity(i)
+                i++
+            }
+
+            i = 0
+            while (i < numPoints)
+            {
+                n = if (i < numPoints-1) i+1 else 0
+
+                val cache1 = vc!!.elementAt(i)
+                val cache2 = vc!!.elementAt(n)
+                val curr = vv.elementAt(i)
+                val next = vv.elementAt(n)
+
+                cache1.cached[0] = curr.x
+                cache1.cached[1] = curr.y
+
+                cache1.a[0] = mConvexity * ( 2*curr.x +   cache1.velocity[0] - 2*next.x + cache2.velocity[0])
+                cache1.b[0] = mConvexity * (-3*curr.x - 2*cache1.velocity[0] + 3*next.x - cache2.velocity[0])
+                cache1.c[0] = mConvexity * cache1.velocity[0] + (1.0f-mConvexity) * (next.x-curr.x)
+                cache1.d[0] = curr.x
+
+                cache1.a[1] = mConvexity * ( 2*curr.y +   cache1.velocity[1] - 2*next.y + cache2.velocity[1])
+                cache1.b[1] = mConvexity * (-3*curr.y - 2*cache1.velocity[1] + 3*next.y - cache2.velocity[1])
+                cache1.c[1] = mConvexity * cache1.velocity[1] + (1.0f-mConvexity) * (next.y-curr.y)
+                cache1.d[1] = curr.y
+
+                if (mSpeedMode == SPEED_MODE_SEGMENT_CONSTANT) smoothOutSegment(cache1)
+                i++
+            }
         }
-      }
-    
-    cacheDirty = false;
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Dynamic2D()
-    {
-    super(0,0.5f,2);
-    vv = new Vector<>();
+        cacheDirty = false
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor setting the speed of interpolation and the number of revolutions.
- *
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @param duration number of milliseconds it takes to do one revolution.
- * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
- */
-  public Dynamic2D(int duration, float count)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    constructor() : super(0, 0.5f, 2) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Constructor setting the speed of interpolation and the number of revolutions.
+    *
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    *
+    * @param duration number of milliseconds it takes to do one revolution.
+    * @param count number of revolutions we will do. Count<=0 means 'infinite'.
+    */
+    constructor(duration: Int, count: Float) : super(duration, count, 2) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Returns the index'th Static2D.
+    *
+    * @param index the index of the Point we are interested in .
+    * @return The Static2D, if 0<=index&lt;getNumPoints(), or null otherwise.
+    */
+    @Synchronized
+    fun getPoint(index: Int): Static2D?
     {
-    super(duration,count,2);
-    vv = new Vector<>();
+        return if (index in 0..<numPoints) vv.elementAt(index) else null
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Resets the index'th Point.
+    *
+    * @param index the index of the Point we are setting.
+    * @param x New value of its first float.
+    * @param y New value of its second float.
+    */
+    @Synchronized
+    fun setPoint(index: Int, x: Float, y: Float)
     {
-    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 )
+        if (index in 0..<numPoints)
         {
-        curr.set(x,y);
-        cacheDirty=true;
+            val curr = vv.elementAt(index)
+
+            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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static2D to the end of our list of Points to interpolate through.
+    *
+    * Only a reference to the Point gets added to the List; this means that one can add a Point
+    * here, and later on [Static2D.set] it to some new value and the change
+    * will be seamlessly reflected in the interpolated path.
+    *
+    * A Point can be added multiple times.
+    *
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(v: Static2D?)
     {
-    if( v!=null )
-      {
-      vv.add(v);
-     
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
+        if (v!=null)
         {
-        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());
+            vv.add(v)
+
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0, 1 -> {}
+                2 ->
+                    {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                    }
+
+                else -> vc!!.add(VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-     
-      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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static2D to the index'th place in our List of Points to interpolate through.
+    *
+    * @param index Index in our List to add the new Point at.
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(index: Int, v: Static2D?)
     {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
+        if (v != null)
         {
-        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());
+            vv.add(index,v)
+
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0, 1 -> {}
+                2 ->
+                    {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                    }
+
+                else -> vc!!.add(index,VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-      
-      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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all occurrences of Point v from the List of Points to interpolate through.
+    *
+    * @param v The Point to remove.
+    * @return `true` if we have removed at least one Point.
+    */
+    @Synchronized
+    fun remove(v: Static2D): Boolean
     {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
+        var n = vv.indexOf(v)
+        var found = false
+
+        while (n>=0)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.remove(n);
+            vv.removeAt(n)
+
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3       -> vc!!.removeAllElements()
+                else    -> vc!!.removeAt(n)
+            }
+
+            numPoints--
+            found = true
+            n = vv.indexOf(v)
         }
-     
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
+
+        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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes a INDEX'th Point from the List of Points we interpolate through.
+    *
+    * @param index index of the Point we want to remove.
+    * @ return `true` if location is valid, i.e. if 0<=location&lt;getNumPoints().
+    */
+    @Synchronized
+    fun remove(index: Int): Boolean
     {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-      
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
+        if (index in 0..<numPoints)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                break;
-        default:vc.removeElementAt(location);
+            vv.removeElementAt(index)
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3       -> vc!!.removeAllElements()
+                else    -> vc!!.removeElementAt(index)
+            }
+
+            numPoints--
+            cacheDirty = true
+            return true
         }
 
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
+        return false
+    }
 
-   return false;
-   }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all Points.
+    */
+    @Synchronized
+    fun removeAll()
     {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
+        numPoints = 0
+        vv.removeAllElements()
+        vc!!.removeAllElements()
+        cacheDirty = false
+
+        if (vn!=null) vn!!.removeAllElements()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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 synchronized void setNoise(Static2D noise)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the 'smoothness' of interpolation.
+    *
+    * 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.
+    */
+    @Synchronized
+    fun setNoise(noise: Static2D)
     {
-    if( vn==null )
-      {
-      vn = new Vector<>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-
-      if( mDimension>=2 )
+        if (vn==null)
         {
-        mFactor = new float[mDimension-1];
+            vn = Vector()
+            for (i in 0..<numPoints) vn!!.add(VectorNoise())
+            if (dimension >= 2) mFactor = FloatArray(dimension-1)
+            mNoise = FloatArray(dimension)
         }
 
-      mNoise = new float[mDimension];
-      }
-
-    if( noise.x<0.0f ) noise.x = 0.0f;
-    if( noise.x>1.0f ) noise.x = 1.0f;
-    if( noise.y<0.0f ) noise.y = 0.0f;
-    if( noise.y>1.0f ) noise.y = 1.0f;
+        if (noise.x < 0.0f) noise.x = 0.0f
+        if (noise.x > 1.0f) noise.x = 1.0f
+        if (noise.y < 0.0f) noise.y = 0.0f
+        if (noise.y > 1.0f) noise.y = 1.0f
 
-    mNoise[0] = noise.x;
-    mNoise[1] = noise.y;
+        mNoise[0] = noise.x
+        mNoise[1] = noise.y
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  synchronized void interpolate(float[] buffer, int offset, float time)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    @Synchronized
+    override fun interpolate(buffer: FloatArray, offset: Int, tm: Float)
     {
-    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);
-
-              int segment= (int)(2*time);
-
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-
-              if( vn!=null )
+        var time = tm
+
+        when (numPoints)
+        {
+            0 ->
                 {
-                if( segment != mSegment )
-                  {
-                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
-                  mSegment = segment;
-                  }
-
-                time = noise(time,0);
-              
-                baseV[1][0] = next.x-curr.x;
-                baseV[1][1] = next.y-curr.y;
-   
-                buffer[offset  ] = baseV[1][0]*time + curr.x +baseV[1][1]*mFactor[0];
-                buffer[offset+1] = baseV[1][1]*time + curr.y -baseV[1][0]*mFactor[0];
+                    buffer[offset  ] = 0.0f
+                    buffer[offset+1] = 0.0f
                 }
-              else
+
+            1 ->
                 {
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x;
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y;
+                    val curr = vv.elementAt(0)
+                    buffer[offset  ] = curr.x
+                    buffer[offset+1] = curr.y
                 }
-              
-              break;
-      default:computeSegmentAndTime(time);
 
-              if( mTmpVec>=0 && mTmpVec<numPoints )
+            2 ->
                 {
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext = getNext(mTmpVec,time);
-                  next = vv.elementAt(vecNext);
-                  tmpCache2 = vc.elementAt(vecNext);
-
-                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y ) recomputeCache();
-                  }
-
-                if( mSegment!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
-
-                mSegment = mTmpSeg;
-                time = mTmpTime-mTmpVec;
-                tmpCache1 = vc.elementAt(mTmpVec);
-                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
-
-                if( vn!=null )
-                  {
-                  time = noise(time,mTmpVec);
-
-                  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  ]= ((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  ]= ((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;
+                    val curr = vv.elementAt(0)
+                    val next = vv.elementAt(1)
+                    val segment = (2*time).toInt()
+
+                    if (mMode==MODE_LOOP || mMode==MODE_PATH) time = (if (time>0.5f) 2-2*time else 2*time)
+
+                    if (vn != null)
+                    {
+                        if (segment!=mSegment)
+                        {
+                            if (mMode!=MODE_JUMP || mSegment==1) vn!!.elementAt(0).computeNoise()
+                            mSegment = segment
+                        }
+
+                        time = noise(time,0)
+
+                        baseV[1][0] = next.x - curr.x
+                        baseV[1][1] = next.y - curr.y
+
+                        buffer[offset  ] = baseV[1][0]*time + curr.x + baseV[1][1]*mFactor[0]
+                        buffer[offset+1] = baseV[1][1]*time + curr.y - baseV[1][0]*mFactor[0]
+                    }
+                    else
+                    {
+                        buffer[offset  ] = (next.x-curr.x)*time + curr.x
+                        buffer[offset+1] = (next.y-curr.y)*time + curr.y
+                    }
                 }
-      }
-    }  
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
+
+            else ->
+                {
+                    computeSegmentAndTime(time)
+
+                    if (mTmpVec>=0 && mTmpVec<numPoints)
+                    {
+                        if (cacheDirty) recomputeCache() // recompute cache if we have added or remove vectors since last computation
+                        else if (mSegment!=mTmpSeg)      // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                        {
+                            val vecNext = getNext(mTmpVec,time)
+                            val next    = vv.elementAt(vecNext)
+                            val cache   = vc!!.elementAt(vecNext)
+
+                            if (cache.cached[0]!=next.x || cache.cached[1]!=next.y) recomputeCache()
+                        }
+
+                    if (mSegment!=mTmpSeg && vn!=null) vn!!.elementAt(mTmpVec).computeNoise()
+
+                    mSegment = mTmpSeg
+                    time = mTmpTime - mTmpVec
+                    val cache = vc!!.elementAt(mTmpVec)
+                    if (mSpeedMode == SPEED_MODE_SEGMENT_CONSTANT) time = smoothSpeed(time,cache)
+
+                    if (vn != null)
+                    {
+                        time = noise(time,mTmpVec)
+
+                        baseV[1][0] = (3*cache.a[0]*time + 2*cache.b[0])*time + cache.c[0]
+                        baseV[1][1] = (3*cache.a[1]*time + 2*cache.b[1])*time + cache.c[1]
+
+                        buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0] + baseV[1][1]*mFactor[0]
+                        buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1] - baseV[1][0]*mFactor[0]
+                    }
+                    else
+                    {
+                        buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0]
+                        buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1]
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/distorted/library/type/Dynamic3D.kt b/src/main/java/org/distorted/library/type/Dynamic3D.kt
index ffd0256..a103d64 100644
--- a/src/main/java/org/distorted/library/type/Dynamic3D.kt
+++ b/src/main/java/org/distorted/library/type/Dynamic3D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,496 +18,491 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
-import java.util.Vector;
+import java.util.Vector
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 3-dimensional implementation of the Dynamic class to interpolate between a list
-* of Static3Ds.
+/** A 3-dimensional implementation of the Dynamic class to interpolate between a list of Static3Ds.
 */
+class Dynamic3D : Dynamic, Data3D
+{
+    private val vv: Vector<Static3D>
 
-public class Dynamic3D extends Dynamic implements Data3D
-  {
-  private final Vector<Static3D> vv;
-  private Static3D prev, curr, next;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void computeVelocity(int c)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // no array bounds checking!
+    private fun computeVelocity(c: Int)
     {
-    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);
-
-    tmpCache1 = 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 )
+        val p = if (c >           0) c-1 else numPoints-1
+        val n = if (c < numPoints-1) c+1 else 0
+
+        val prev = vv.elementAt(p)
+        val curr = vv.elementAt(c)
+        val next = vv.elementAt(n)
+        val cache= vc!!.elementAt(c)
+
+        val px = curr.x - prev.x
+        val py = curr.y - prev.y
+        val pz = curr.z - prev.z
+        val nx = next.x - curr.x
+        val ny = next.y - curr.y
+        val nz = next.z - curr.z
+
+        val d = nx*nx + ny*ny + nz*nz
+
+        if (d > 0)
         {
-        tmpCache1.velocity[0] = nx+px/q;
-        tmpCache1.velocity[1] = ny+py/q;
-        tmpCache1.velocity[2] = nz+pz/q;
+            val q = sqrt( ((px*px+py*py+pz*pz)/d).toDouble() ).toFloat()
+
+            if (q > 1)
+            {
+                cache.velocity[0] = nx + px/q
+                cache.velocity[1] = ny + py/q
+                cache.velocity[2] = nz + pz/q
+            }
+            else
+            {
+                cache.velocity[0] = px + nx*q
+                cache.velocity[1] = py + ny*q
+                cache.velocity[2] = pz + nz*q
+            }
         }
-      else
+        else
         {
-        tmpCache1.velocity[0] = px+nx*q;
-        tmpCache1.velocity[1] = py+ny*q;
-        tmpCache1.velocity[2] = pz+nz*q;
+            cache.velocity[0] = 0.0f
+            cache.velocity[1] = 0.0f
+            cache.velocity[2] = 0.0f
         }
-      }
-    else
-      {
-      tmpCache1.velocity[0] = 0.0f;
-      tmpCache1.velocity[1] = 0.0f;
-      tmpCache1.velocity[2] = 0.0f;
-      }
     }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      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 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      tmpCache2 = vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-          
-      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;
-      
-      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
-      {
-      int i, n;  
-         
-      for(i=0; i<numPoints; i++) computeVelocity(i);
-   
-      for(i=0; i<numPoints; i++)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun recomputeCache()
+    {
+        if (numPoints==1)
         {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmpCache1 = vc.elementAt(i);
-        tmpCache2 = vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        tmpCache1.cached[0] = curr.x;
-        tmpCache1.cached[1] = curr.y;
-        tmpCache1.cached[2] = curr.z;
-        
-        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;
-      
-        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);
+            val cache = vc!!.elementAt(0)
+            val curr = vv.elementAt(0)
+
+            cache.a[2] = 0.0f
+            cache.a[1] = cache.a[2]
+            cache.a[0] = cache.a[1]
+            cache.b[2] = 0.0f
+            cache.b[1] = cache.b[2]
+            cache.b[0] = cache.b[1]
+            cache.c[0] = curr.x
+            cache.c[1] = curr.y
+            cache.c[2] = curr.z
+            cache.d[2] = 0.0f
+            cache.d[1] = cache.d[2]
+            cache.d[0] = cache.d[1]
+        }
+        else if (numPoints==2)
+        {
+            val cache1 = vc!!.elementAt(0)
+            val cache2 = vc!!.elementAt(1)
+            val curr = vv.elementAt(0)
+            val next = vv.elementAt(1)
+
+            cache1.a[2] = 0.0f
+            cache1.a[1] = cache1.a[2]
+            cache1.a[0] = cache1.a[1]
+            cache1.b[2] = 0.0f
+            cache1.b[1] = cache1.b[2]
+            cache1.b[0] = cache1.b[1]
+            cache1.c[0] = next.x - curr.x
+            cache1.c[1] = next.y - curr.y
+            cache1.c[2] = next.z - curr.z
+            cache1.d[0] = curr.x
+            cache1.d[1] = curr.y
+            cache1.d[2] = curr.z
+
+            cache2.a[2] = 0.0f
+            cache2.a[1] = cache2.a[2]
+            cache2.a[0] = cache2.a[1]
+            cache2.b[2] = 0.0f
+            cache2.b[1] = cache2.b[2]
+            cache2.b[0] = cache2.b[1]
+            cache2.c[0] = curr.x - next.x
+            cache2.c[1] = curr.y - next.y
+            cache2.c[2] = curr.z - next.z
+            cache2.d[0] = next.x
+            cache2.d[1] = next.y
+            cache2.d[2] = next.z
+        }
+        else
+        {
+            var n: Int
+            var i = 0
+
+            while (i < numPoints)
+            {
+                computeVelocity(i)
+                i++
+            }
+
+            i = 0
+            while (i < numPoints)
+            {
+                n = if (i < numPoints-1) i+1 else 0
+
+                val cache1 = vc!!.elementAt(i)
+                val cache2 = vc!!.elementAt(n)
+                val curr = vv.elementAt(i)
+                val next = vv.elementAt(n)
+
+                cache1.cached[0] = curr.x
+                cache1.cached[1] = curr.y
+                cache1.cached[2] = curr.z
+
+                cache1.a[0] = mConvexity * ( 2*curr.x +   cache1.velocity[0] - 2*next.x + cache2.velocity[0])
+                cache1.b[0] = mConvexity * (-3*curr.x - 2*cache1.velocity[0] + 3*next.x - cache2.velocity[0])
+                cache1.c[0] = mConvexity * (cache1.velocity[0]) + (1.0f-mConvexity) * (next.x-curr.x)
+                cache1.d[0] = curr.x
+
+                cache1.a[1] = mConvexity * ( 2*curr.y +   cache1.velocity[1] - 2*next.y + cache2.velocity[1])
+                cache1.b[1] = mConvexity * (-3*curr.y - 2*cache1.velocity[1] + 3*next.y - cache2.velocity[1])
+                cache1.c[1] = mConvexity * (cache1.velocity[1]) + (1.0f-mConvexity) * (next.y-curr.y)
+                cache1.d[1] = curr.y
+
+                cache1.a[2] = mConvexity * ( 2*curr.z +   cache1.velocity[2] - 2*next.z + cache2.velocity[2])
+                cache1.b[2] = mConvexity * (-3*curr.z - 2*cache1.velocity[2] + 3*next.z - cache2.velocity[2])
+                cache1.c[2] = mConvexity * (cache1.velocity[2]) + (1.0f-mConvexity) * (next.z-curr.z)
+                cache1.d[2] = curr.z
+
+                if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) smoothOutSegment(cache1)
+                i++
+            }
         }
-      }
-   
-    cacheDirty = false;
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Dynamic3D()
-    {
-    super(0,0.5f,3);
-    vv = new Vector<>();
+        cacheDirty = false
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor setting the speed of interpolation and the number of revolutions.
- *
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @param duration number of milliseconds it takes to do one revolution.
- * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
- */
-  public Dynamic3D(int duration, float count)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    constructor() : super(0, 0.5f, 3) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Constructor setting the speed of interpolation and the number of revolutions.
+    *
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    *
+    * @param duration number of milliseconds it takes to do one revolution.
+    * @param count number of revolutions we will do. Count<=0 means 'infinite'.
+    */
+    constructor(duration: Int, count: Float) : super(duration, count, 3) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Returns the index'th Static3D.
+    *
+    * @param index the index of the Point we are interested in .
+    * @return The Static3D, if 0<=location&lt;getNumPoints(), or null otherwise.
+    */
+    @Synchronized
+    fun getPoint(index: Int): Static3D?
     {
-    super(duration,count,3);
-    vv = new Vector<>();
+        return if (index in 0..<numPoints) vv.elementAt(index) else null
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Resets the index'th Point.
+    *
+    * @param index the index of the Point we are setting.
+    * @param x New value of its first float.
+    */
+    @Synchronized
+    fun setPoint(index: Int, x: Float, y: Float, z: Float)
     {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
+        if (index in 0..<numPoints)
         {
-        curr.set(x,y,z);
-        cacheDirty=true;
+            val curr = vv.elementAt(index)
+
+            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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static3D to the end of our list of Points to interpolate through.
+    *
+    * Only a reference to the Point gets added to the List; this means that one can add a Point
+    * here, and later on [Static3D.set] it to some new value and the
+    * change will be seamlessly reflected in the interpolated path.
+    *
+    * A Point can be added multiple times.
+    *
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(v: Static3D?)
     {
-    if( v!=null )
-      {
-      vv.add(v);
-        
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
+        if (v != null)
         {
-        case 0: break;
-        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(new VectorCache());
+            vv.add(v)
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0 -> {}
+                1 -> computeOrthonormalBase2(vv.elementAt(0), v)
+                2 -> {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                     }
+
+                else -> vc!!.add(VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-
-      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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static3D to the index'th place in our List of Points to interpolate through.
+    *
+    * @param index Index in our List to add the new Point at.
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(index: Int, v: Static3D?)
     {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
+        if (v != null)
         {
-        case 0: break;
-        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
-        }
+            vv.add(index,v)
 
-      numPoints++;
-      cacheDirty = true;
-      }
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0 -> {}
+                1 -> computeOrthonormalBase2(vv.elementAt(0), v)
+                2 -> {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                     }
+
+                else -> vc!!.add(index, 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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all occurrences of Point v from the List of Points to interpolate through.
+    *
+    * @param v The Point to remove.
+    * @ return `true` if we have removed at least one Point.
+    */
+    @Synchronized
+    fun remove(v: Static3D): Boolean
     {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
+        var n = vv.indexOf(v)
+        var found = false
+
+        while (n >= 0)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
-                break;
-        default:vc.remove(n);
+            vv.removeAt(n)
+            if (vn != null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3 -> {
+                        vc!!.removeAllElements()
+                        computeOrthonormalBase2(vv.elementAt(0), vv.elementAt(1))
+                     }
+
+                else -> vc!!.removeAt(n)
+            }
+
+            numPoints--
+            found = true
+            n = vv.indexOf(v)
         }
 
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
+        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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes a index'th Point from the List of Points we interpolate through.
+    *
+    * @param index index of the Point we want to remove.
+    * @return `true` if location is valid, i.e. if 0<=location&lt;getNumPoints().
+    */
+    @Synchronized
+    fun remove(index: Int): Boolean
     {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-       
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
+        if (index in 0..<numPoints)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
-                break;
-        default:vc.removeElementAt(location);
+            vv.removeElementAt(index)
+
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3 -> {
+                        vc!!.removeAllElements()
+                        computeOrthonormalBase2(vv.elementAt(0), vv.elementAt(1))
+                     }
+
+                else -> vc!!.removeElementAt(index)
+            }
+
+            numPoints--
+            cacheDirty = true
+            return true
         }
 
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
+        return false
+    }
 
-   return false;
-   }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all Points.
+    */
+    @Synchronized
+    fun removeAll()
     {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
+        numPoints = 0
+        vv.removeAllElements()
+        vc!!.removeAllElements()
+        cacheDirty = false
+        if (vn!=null) vn!!.removeAllElements()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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 synchronized void setNoise(Static3D noise)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the 'smoothness' of interpolation.
+    *
+    * 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.
+    */
+    @Synchronized
+    fun setNoise(noise: Static3D)
     {
-    if( vn==null )
-      {
-      vn = new Vector<>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-
-      if( mDimension>=2 )
+        if (vn == null)
         {
-        mFactor = new float[mDimension-1];
+            vn = Vector()
+            for (i in 0..<numPoints) vn!!.add(VectorNoise())
+            if (dimension>=2) mFactor = FloatArray(dimension-1)
+            mNoise = FloatArray(dimension)
         }
 
-      mNoise = new float[mDimension];
-      }
-
-    if( noise.x<0.0f ) noise.x = 0.0f;
-    if( noise.x>1.0f ) noise.x = 1.0f;
-    if( noise.y<0.0f ) noise.y = 0.0f;
-    if( noise.y>1.0f ) noise.y = 1.0f;
-    if( noise.z<0.0f ) noise.z = 0.0f;
-    if( noise.z>1.0f ) noise.z = 1.0f;
+        if (noise.x < 0.0f) noise.x = 0.0f
+        if (noise.x > 1.0f) noise.x = 1.0f
+        if (noise.y < 0.0f) noise.y = 0.0f
+        if (noise.y > 1.0f) noise.y = 1.0f
+        if (noise.z < 0.0f) noise.z = 0.0f
+        if (noise.z > 1.0f) noise.z = 1.0f
 
-    mNoise[0] = noise.x;
-    mNoise[1] = noise.y;
-    mNoise[2] = noise.z;
+        mNoise[0] = noise.x
+        mNoise[1] = noise.y
+        mNoise[2] = noise.z
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    @Synchronized
+    override fun interpolate(buffer: FloatArray, offset: Int, tm: Float)
+    {
+        var time = tm
 
-  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);
-
-              int segment= (int)(2*time);
-
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-
-              if( vn!=null )
-                {
-                if( segment != mSegment )
-                  {
-                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
-                  mSegment = segment;
-                  }
-
-                time = noise(time,0);
-            
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1]);
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1]);
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1]);
-                }
-              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;
+        when (numPoints)
+        {
+            0 -> {
+                    buffer[offset  ] = 0.0f
+                    buffer[offset+1] = 0.0f
+                    buffer[offset+2] = 0.0f
+                 }
+
+            1 -> {
+                    val curr = vv.elementAt(0)
+                    buffer[offset  ] = curr.x
+                    buffer[offset+1] = curr.y
+                    buffer[offset+2] = curr.z
+                 }
+
+            2 -> {
+                    val curr = vv.elementAt(0)
+                    val next = vv.elementAt(1)
+                    val segment = (2*time).toInt()
+
+                    if (mMode==MODE_LOOP || mMode==MODE_PATH) time = (if (time>0.5f) 2-2*time else 2*time)
+
+                    if (vn != null)
+                    {
+                        if (segment != mSegment)
+                        {
+                            if (mMode!=MODE_JUMP || mSegment==1) vn!!.elementAt(0).computeNoise()
+                            mSegment = segment
+                        }
+
+                        time = noise(time,0)
+
+                        buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1])
+                        buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1])
+                        buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1])
+                    }
+                    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:computeSegmentAndTime(time);
 
-              if( mTmpVec>=0 && mTmpVec<numPoints )
+            else ->
                 {
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext = getNext(mTmpVec,time);
-                  next = vv.elementAt(vecNext);
-                  tmpCache2 = vc.elementAt(vecNext);
-
-                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y || tmpCache2.cached[2]!=next.z ) recomputeCache();
-                  }
-
-                if( mSegment!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
-
-                mSegment = mTmpSeg;
-                time = mTmpTime-mTmpVec;
-                tmpCache1 = vc.elementAt(mTmpVec);
-                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
-
-                if( vn!=null )
-                  {
-                  time = noise(time,mTmpVec);
-              
-                  computeOrthonormalBaseMore(time, tmpCache1);
-                 
-                  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  ]= ((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;
+                    computeSegmentAndTime(time)
+
+                    if (mTmpVec>=0 && mTmpVec<numPoints)
+                    {
+                        if (cacheDirty) recomputeCache() // recompute cache if we have added or remove vectors since last computation
+                        else if (mSegment!=mTmpSeg)  // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                        {
+                            val vecNext = getNext(mTmpVec,time)
+                            val next = vv.elementAt(vecNext)
+                            val cache = vc!!.elementAt(vecNext)
+                            if (cache.cached[0]!=next.x || cache.cached[1]!=next.y || cache.cached[2]!=next.z) recomputeCache()
+                        }
+
+                        if (mSegment!=mTmpSeg && vn!=null) vn!!.elementAt(mTmpVec).computeNoise()
+
+                        mSegment = mTmpSeg
+                        time = mTmpTime - mTmpVec
+                        val cache = vc!!.elementAt(mTmpVec)
+                        if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) time = smoothSpeed(time,cache)
+
+                        if (vn != null)
+                        {
+                            time = noise(time, mTmpVec)
+                            computeOrthonormalBaseMore(time,cache)
+
+                            buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1])
+                            buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1])
+                            buffer[offset+2] = ((cache.a[2]*time + cache.b[2])*time + cache.c[2])*time + cache.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1])
+                        }
+                        else
+                        {
+                            buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0]
+                            buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1]
+                            buffer[offset+2] = ((cache.a[2]*time + cache.b[2])*time + cache.c[2])*time + cache.d[2]
+                        }
                 }
-       }
-     }  
-
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/type/Dynamic4D.kt b/src/main/java/org/distorted/library/type/Dynamic4D.kt
index 4716d34..6b10470 100644
--- a/src/main/java/org/distorted/library/type/Dynamic4D.kt
+++ b/src/main/java/org/distorted/library/type/Dynamic4D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,521 +18,518 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
-import java.util.Vector;
+import java.util.Vector
+import kotlin.math.sqrt
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 4-dimensional implementation of the Dynamic class to interpolate between a list
-* of Static4Ds.
+//////////////////////////////////////////////////////////////////////////////////////////////////
+/** A 4-dimensional implementation of the Dynamic class to interpolate between a list of Static4Ds.
 */
+class Dynamic4D : Dynamic, Data4D
+{
+    private val vv: Vector<Static4D>
 
-public class Dynamic4D extends Dynamic implements Data4D
-  {
-  private final Vector<Static4D> vv;
-  private Static4D prev, curr, next;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void computeVelocity(int c)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // no array bounds checking!
+    private fun computeVelocity(c: Int)
     {
-    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);
-
-    tmpCache1 = 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 )
+        val p = if (c >           0) c-1 else numPoints-1
+        val n = if (c < numPoints-1) c+1 else 0
+
+        val prev = vv.elementAt(p)
+        val curr = vv.elementAt(c)
+        val next = vv.elementAt(n)
+        val cache= vc!!.elementAt(c)
+
+        val px = curr.x - prev.x
+        val py = curr.y - prev.y
+        val pz = curr.z - prev.z
+        val pw = curr.w - prev.w
+        val nx = next.x - curr.x
+        val ny = next.y - curr.y
+        val nz = next.z - curr.z
+        val nw = next.w - curr.w
+
+        val d = nx*nx + ny*ny + nz*nz + nw*nw
+
+        if (d > 0)
         {
-        tmpCache1.velocity[0] = nx+px/q;
-        tmpCache1.velocity[1] = ny+py/q;
-        tmpCache1.velocity[2] = nz+pz/q;
-        tmpCache1.velocity[3] = nw+pw/q;
+            val q = sqrt( ((px*px+py*py+pz*pz+pw*pw)/d).toDouble() ).toFloat()
+
+            if (q > 1)
+            {
+                cache.velocity[0] = nx + px/q
+                cache.velocity[1] = ny + py/q
+                cache.velocity[2] = nz + pz/q
+                cache.velocity[3] = nw + pw/q
+            }
+            else
+            {
+                cache.velocity[0] = px + nx*q
+                cache.velocity[1] = py + ny*q
+                cache.velocity[2] = pz + nz*q
+                cache.velocity[3] = pw + nw*q
+            }
         }
-      else
+        else
         {
-        tmpCache1.velocity[0] = px+nx*q;
-        tmpCache1.velocity[1] = py+ny*q;
-        tmpCache1.velocity[2] = pz+nz*q;
-        tmpCache1.velocity[3] = pw+nw*q;
+            cache.velocity[0] = 0.0f
+            cache.velocity[1] = 0.0f
+            cache.velocity[2] = 0.0f
+            cache.velocity[3] = 0.0f
         }
-      }
-    else
-      {
-      tmpCache1.velocity[0] = 0.0f;
-      tmpCache1.velocity[1] = 0.0f;
-      tmpCache1.velocity[2] = 0.0f;
-      tmpCache1.velocity[3] = 0.0f;
-      }
     }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      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 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      tmpCache2 = vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-      
-      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;
-      
-      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
-      {
-      int i, n;  
-      
-      for(i=0; i<numPoints; i++) computeVelocity(i);
-   
-      for(i=0; i<numPoints; i++)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun recomputeCache()
+    {
+        if (numPoints == 1)
         {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmpCache1 = vc.elementAt(i);
-        tmpCache2 = vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        tmpCache1.cached[0] = curr.x;
-        tmpCache1.cached[1] = curr.y;
-        tmpCache1.cached[2] = curr.z;
-        tmpCache1.cached[3] = curr.w;
-        
-        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;
-      
-        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;
-        
-        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);
+            val cache = vc!!.elementAt(0)
+            val curr = vv.elementAt(0)
+
+            cache.a[3] = 0.0f
+            cache.a[2] = cache.a[3]
+            cache.a[1] = cache.a[2]
+            cache.a[0] = cache.a[1]
+            cache.b[3] = 0.0f
+            cache.b[2] = cache.b[3]
+            cache.b[1] = cache.b[2]
+            cache.b[0] = cache.b[1]
+            cache.c[0] = curr.x
+            cache.c[1] = curr.y
+            cache.c[2] = curr.z
+            cache.c[3] = curr.w
+            cache.d[3] = 0.0f
+            cache.d[3] = cache.d[3]
+            cache.d[1] = cache.d[3]
+            cache.d[0] = cache.d[1]
+        }
+        else if (numPoints == 2)
+        {
+            val cache1 = vc!!.elementAt(0)
+            val cache2 = vc!!.elementAt(1)
+            val curr = vv.elementAt(0)
+            val next = vv.elementAt(1)
+
+            cache1.a[3] = 0.0f
+            cache1.a[2] = cache1.a[3]
+            cache1.a[1] = cache1.a[2]
+            cache1.a[0] = cache1.a[1]
+            cache1.b[3] = 0.0f
+            cache1.b[2] = cache1.b[3]
+            cache1.b[1] = cache1.b[2]
+            cache1.b[0] = cache1.b[1]
+            cache1.c[0] = next.x - curr.x
+            cache1.c[1] = next.y - curr.y
+            cache1.c[2] = next.z - curr.z
+            cache1.c[3] = next.w - curr.w
+            cache1.d[0] = curr.x
+            cache1.d[1] = curr.y
+            cache1.d[2] = curr.z
+            cache1.d[3] = curr.w
+
+            cache2.a[3] = 0.0f
+            cache2.a[2] = cache2.a[3]
+            cache2.a[1] = cache2.a[2]
+            cache2.a[0] = cache2.a[1]
+            cache2.b[3] = 0.0f
+            cache2.b[2] = cache2.b[3]
+            cache2.b[1] = cache2.b[2]
+            cache2.b[0] = cache2.b[1]
+            cache2.c[0] = curr.x - next.x
+            cache2.c[1] = curr.y - next.y
+            cache2.c[2] = curr.z - next.z
+            cache2.c[3] = curr.w - next.w
+            cache2.d[0] = next.x
+            cache2.d[1] = next.y
+            cache2.d[2] = next.z
+            cache2.d[3] = next.w
+        }
+        else
+        {
+            var n: Int
+            var i = 0
+
+            while (i < numPoints)
+            {
+                computeVelocity(i)
+                i++
+            }
+
+            i = 0
+            while (i < numPoints)
+            {
+                n = if (i < numPoints-1) i+1 else 0
+
+                val cache1 = vc!!.elementAt(i)
+                val cache2 = vc!!.elementAt(n)
+                val curr = vv.elementAt(i)
+                val next = vv.elementAt(n)
+
+                cache1.cached[0] = curr.x
+                cache1.cached[1] = curr.y
+                cache1.cached[2] = curr.z
+                cache1.cached[3] = curr.w
+
+                cache1.a[0] = mConvexity * ( 2*curr.x +   cache1.velocity[0] - 2*next.x + cache2.velocity[0])
+                cache1.b[0] = mConvexity * (-3*curr.x - 2*cache1.velocity[0] + 3*next.x - cache2.velocity[0])
+                cache1.c[0] = mConvexity * (cache1.velocity[0]) + (1.0f-mConvexity)*(next.x-curr.x)
+                cache1.d[0] = curr.x
+
+                cache1.a[1] = mConvexity * ( 2*curr.y +   cache1.velocity[1] - 2*next.y + cache2.velocity[1])
+                cache1.b[1] = mConvexity * (-3*curr.y - 2*cache1.velocity[1] + 3*next.y - cache2.velocity[1])
+                cache1.c[1] = mConvexity * (cache1.velocity[1]) + (1.0f-mConvexity)*(next.y-curr.y)
+                cache1.d[1] = curr.y
+
+                cache1.a[2] = mConvexity * ( 2*curr.z +   cache1.velocity[2] - 2*next.z + cache2.velocity[2])
+                cache1.b[2] = mConvexity * (-3*curr.z - 2*cache1.velocity[2] + 3*next.z - cache2.velocity[2])
+                cache1.c[2] = mConvexity * (cache1.velocity[2]) + (1.0f-mConvexity)*(next.z-curr.z)
+                cache1.d[2] = curr.z
+
+                cache1.a[3] = mConvexity * ( 2*curr.w +   cache1.velocity[3] - 2*next.w + cache2.velocity[3])
+                cache1.b[3] = mConvexity * (-3*curr.w - 2*cache1.velocity[3] + 3*next.w - cache2.velocity[3])
+                cache1.c[3] = mConvexity * (cache1.velocity[3]) + (1.0f-mConvexity)*(next.w-curr.w)
+                cache1.d[3] = curr.w
+
+                if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) smoothOutSegment(cache1)
+                i++
+            }
         }
-      }
-   
-    cacheDirty = false;
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Dynamic4D()
-    {
-    super(0,0.5f,4);
-    vv = new Vector<>();
+        cacheDirty = false
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor setting the speed of interpolation and the number of revolutions.
- *
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @param duration number of milliseconds it takes to do one revolution.
- * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
- */
-  public Dynamic4D(int duration, float count)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    constructor() : super(0, 0.5f, 4) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Constructor setting the speed of interpolation and the number of revolutions.
+    *
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    *
+    * @param duration number of milliseconds it takes to do one revolution.
+    * @param count number of revolutions we will do. Count<=0 means 'infinite'.
+    */
+    constructor(duration: Int, count: Float) : super(duration,count,4) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Returns the index'th Static4D.
+    *
+    * @param index the index of the Point we are interested in .
+    * @ return The Static4D, if 0<=location&lt;getNumPoints(), or null otherwise.
+    */
+    @Synchronized
+    fun getPoint(index: Int): Static4D?
     {
-    super(duration,count,4);
-    vv = new Vector<>();
+        return if (index in 0..<numPoints) vv.elementAt(index) else null
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Resets the index'th Point.
+    *
+    * @param index the index of the Point we are setting.
+    * @param x New value of its first float.
+    */
+    @Synchronized
+    fun setPoint(index: Int, x: Float, y: Float, z: Float, w: Float)
     {
-    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 )
+        if (index in 0..<numPoints)
         {
-        curr.set(x,y,z,w);
-        cacheDirty=true;
+            val curr = vv.elementAt(index)
+
+            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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static4D to the end of our list of Points to interpolate through.
+    *
+    * Only a reference to the Point gets added to the List; this means that one can add a Point
+    * here, and later on [Static4D.set] it to some new value and
+    * the change will be seamlessly reflected in the interpolated path.
+    *
+    * A Point can be added multiple times.
+    *
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(v: Static4D?)
     {
-    if( v!=null )
-      {
-      vv.add(v);
-        
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
+        if (v!=null)
         {
-        case 0: break;
-        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(new VectorCache());
+            vv.add(v)
+
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0 -> {}
+                1 -> computeOrthonormalBase2(vv.elementAt(0), v)
+                2 -> {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                     }
+                else -> vc!!.add(VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-
-      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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static4D to the index'th place in our List of Points to interpolate through.
+    *
+    * @param index Index in our List to add the new Point at.
+    * @param v The Static4D to add.
+    */
+    @Synchronized
+    fun add(index: Int, v: Static4D?)
     {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
+        if (v != null)
         {
-        case 0: break;
-        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
+            vv.add(index,v)
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0 -> {}
+                1 -> computeOrthonormalBase2(vv.elementAt(0), v)
+                2 -> {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                     }
+                else -> vc!!.add(index,VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-
-      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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all occurrences of Point v from the List of Points to interpolate through.
+    *
+    * @param v The Point to remove.
+    * @return `true` if we have removed at least one Point.
+    */
+    @Synchronized
+    fun remove(v: Static4D): Boolean
     {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
+        var n = vv.indexOf(v)
+        var found = false
+
+        while (n >= 0)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
-                break;
-        default:vc.remove(n);
+            vv.removeAt(n)
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3 -> {
+                        vc!!.removeAllElements()
+                        computeOrthonormalBase2(vv.elementAt(0), vv.elementAt(1))
+                     }
+                else -> vc!!.removeAt(n)
+            }
+
+            numPoints--
+            found = true
+            n = vv.indexOf(v)
         }
 
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
+        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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes a index'th Point from the List of Points we interpolate through.
+    *
+    * @param index index of the Point we want to remove.
+    * @ return `true` if location is valid, i.e. if 0<=location&lt;getNumPoints().
+    */
+    @Synchronized
+    fun remove(index: Int): Boolean
     {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-       
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
+        if (index in 0..<numPoints)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
-                break;
-        default:vc.removeElementAt(location);
+            vv.removeElementAt(index)
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3 -> {
+                        vc!!.removeAllElements()
+                        computeOrthonormalBase2(vv.elementAt(0), vv.elementAt(1))
+                     }
+
+                else -> vc!!.removeElementAt(index)
+            }
+
+            numPoints--
+            cacheDirty = true
+            return true
         }
 
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-    return false;
+        return false
     }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all Points.
+    */
+    @Synchronized
+    fun removeAll()
     {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
+        numPoints = 0
+        vv.removeAllElements()
+        vc!!.removeAllElements()
+        cacheDirty = false
+        if (vn != null) vn!!.removeAllElements()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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 synchronized void setNoise(Static4D noise)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the 'smoothness' of interpolation.
+    *
+    * 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.
+    */
+    @Synchronized
+    fun setNoise(noise: Static4D)
     {
-    if( vn==null )
-      {
-      vn = new Vector<>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-
-      if( mDimension>=2 )
+        if (vn==null)
         {
-        mFactor = new float[mDimension-1];
+            vn = Vector()
+            for (i in 0..<numPoints) vn!!.add(VectorNoise())
+            if (dimension >= 2) mFactor = FloatArray(dimension-1)
+            mNoise = FloatArray(dimension)
         }
 
-      mNoise = new float[mDimension];
-      }
-
-    if( noise.x<0.0f ) noise.x = 0.0f;
-    if( noise.x>1.0f ) noise.x = 1.0f;
-    if( noise.y<0.0f ) noise.y = 0.0f;
-    if( noise.y>1.0f ) noise.y = 1.0f;
-    if( noise.z<0.0f ) noise.z = 0.0f;
-    if( noise.z>1.0f ) noise.z = 1.0f;
-    if( noise.w<0.0f ) noise.w = 0.0f;
-    if( noise.w>1.0f ) noise.w = 1.0f;
-
-    mNoise[0] = noise.x;
-    mNoise[1] = noise.y;
-    mNoise[2] = noise.z;
-    mNoise[3] = noise.w;
+        if (noise.x < 0.0f) noise.x = 0.0f
+        if (noise.x > 1.0f) noise.x = 1.0f
+        if (noise.y < 0.0f) noise.y = 0.0f
+        if (noise.y > 1.0f) noise.y = 1.0f
+        if (noise.z < 0.0f) noise.z = 0.0f
+        if (noise.z > 1.0f) noise.z = 1.0f
+        if (noise.w < 0.0f) noise.w = 0.0f
+        if (noise.w > 1.0f) noise.w = 1.0f
+
+        mNoise[0] = noise.x
+        mNoise[1] = noise.y
+        mNoise[2] = noise.z
+        mNoise[3] = noise.w
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    @Synchronized
+    override fun interpolate(buffer: FloatArray, offset: Int, tm: Float)
+    {
+        var time = tm
 
-  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);
-
-              int segment= (int)(2*time);
-
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-
-              if( vn!=null )
-                {
-                if( segment != mSegment )
-                  {
-                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
-                  mSegment = segment;
-                  }
-
-                time = noise(time,0);
-
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2]);
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2]);
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2]);
-                buffer[offset+3] = (next.w-curr.w)*time + curr.w + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2]);
-                }
-              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;
+        when (numPoints)
+        {
+            0 -> {
+                    buffer[offset  ] = 0.0f
+                    buffer[offset+1] = 0.0f
+                    buffer[offset+2] = 0.0f
+                    buffer[offset+3] = 0.0f
+                 }
+
+            1 -> {
+                    val curr = vv.elementAt(0)
+                    buffer[offset  ] = curr.x
+                    buffer[offset+1] = curr.y
+                    buffer[offset+2] = curr.z
+                    buffer[offset+3] = curr.w
+                 }
+
+            2 -> {
+                    val curr = vv.elementAt(0)
+                    val next = vv.elementAt(1)
+                    val segment = (2*time).toInt()
+
+                    if (mMode==MODE_LOOP || mMode==MODE_PATH) time = (if (time>0.5f) 2-2*time else 2*time)
+
+                    if (vn != null)
+                    {
+                        if (segment!=mSegment)
+                        {
+                            if (mMode!=MODE_JUMP || mSegment==1) vn!!.elementAt(0).computeNoise()
+                            mSegment = segment
+                        }
+
+                        time = noise(time,0)
+
+                        buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2])
+                        buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2])
+                        buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2])
+                        buffer[offset+3] = (next.w-curr.w)*time + curr.w + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2])
+                    }
+                    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:computeSegmentAndTime(time);
 
-              if( mTmpVec>=0 && mTmpVec<numPoints )
+            else ->
                 {
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext = getNext(mTmpVec,time);
-                  next = vv.elementAt(vecNext);
-                  tmpCache2 = vc.elementAt(vecNext);
-
-                  if( tmpCache2.cached[0]!=next.x || tmpCache2.cached[1]!=next.y || tmpCache2.cached[2]!=next.z || tmpCache2.cached[3]!=next.w ) recomputeCache();
-                  }
-
-                if( mSegment!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
-
-                mSegment = mTmpSeg;
-                time = mTmpTime-mTmpVec;
-                tmpCache1 = vc.elementAt(mTmpVec);
-                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
-
-                if( vn!=null )
-                  {
-                  time = noise(time,mTmpVec);
-              
-                  computeOrthonormalBaseMore(time, tmpCache1);
-
-                  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  ]= ((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;
+                    computeSegmentAndTime(time)
+
+                    if (mTmpVec in 0..<numPoints)
+                    {
+                        if (cacheDirty) recomputeCache() // recompute cache if we have added or remove vectors since last computation
+                        else if (mSegment != mTmpSeg)  // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                        {
+                            val vecNext = getNext(mTmpVec,time)
+                            val next = vv.elementAt(vecNext)
+                            val cache = vc!!.elementAt(vecNext)
+                            if (cache.cached[0]!=next.x || cache.cached[1]!=next.y || cache.cached[2]!=next.z || cache.cached[3]!=next.w) recomputeCache()
+                        }
+
+                        if (mSegment!=mTmpSeg && vn!=null) vn!!.elementAt(mTmpVec).computeNoise()
+
+                        mSegment = mTmpSeg
+                        time = mTmpTime - mTmpVec
+                        val cache = vc!!.elementAt(mTmpVec)
+                        if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) time = smoothSpeed(time,cache)
+
+                        if (vn != null)
+                        {
+                            time = noise(time,mTmpVec)
+                            computeOrthonormalBaseMore(time,cache)
+                            buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0] + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2])
+                            buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1] + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2])
+                            buffer[offset+2] = ((cache.a[2]*time + cache.b[2])*time + cache.c[2])*time + cache.d[2] + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2])
+                            buffer[offset+3] = ((cache.a[3]*time + cache.b[3])*time + cache.c[3])*time + cache.d[3] + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2])
+                        }
+                        else
+                        {
+                            buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0]
+                            buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1]
+                            buffer[offset+2] = ((cache.a[2]*time + cache.b[2])*time + cache.c[2])*time + cache.d[2]
+                            buffer[offset+3] = ((cache.a[3]*time + cache.b[3])*time + cache.c[3])*time + cache.d[3]
+                        }
+                    }
                 }
-      }
-    }  
-
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
+        }
+    }
+} /**//////////////////////////////////////////////////////////////////////////////////////////////// */ //
diff --git a/src/main/java/org/distorted/library/type/Dynamic5D.kt b/src/main/java/org/distorted/library/type/Dynamic5D.kt
index 3e8a109..69f4ee2 100644
--- a/src/main/java/org/distorted/library/type/Dynamic5D.kt
+++ b/src/main/java/org/distorted/library/type/Dynamic5D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,546 +18,550 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
-import java.util.Vector;
+import java.util.Vector
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 5-dimensional implementation of the Dynamic class to interpolate between a list
-* of Static5Ds.
+/** A 5-dimensional implementation of the Dynamic class to interpolate between a list of Static5Ds.
 */
+class Dynamic5D : Dynamic, Data5D
+{
+    private val vv: Vector<Static5D>
 
-public class Dynamic5D extends Dynamic implements Data5D
-  {
-  private final Vector<Static5D> vv;
-  private Static5D prev, curr, next;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// no array bounds checking!
-  
-  private void computeVelocity(int c)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // no array bounds checking!
+    private fun computeVelocity(c: Int)
     {
-    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);
-
-    tmpCache1 = 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 pv = curr.v - prev.v;
-    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 nv = next.v - curr.v;
-     
-    float d = nx*nx+ny*ny+nz*nz+nw*nw+nv*nv;
-    
-    if( d>0 )
-      {
-      float q = (float)Math.sqrt((px*px+py*py+pz*pz+pw*pw+pv*pv)/d);
-      
-      if( q>1 )
+        val p = if (c >           0) c-1 else numPoints-1
+        val n = if (c < numPoints-1) c+1 else 0
+
+        val prev = vv.elementAt(p)
+        val curr = vv.elementAt(c)
+        val next = vv.elementAt(n)
+        val cache= vc!!.elementAt(c)
+
+        val px = curr.x - prev.x
+        val py = curr.y - prev.y
+        val pz = curr.z - prev.z
+        val pw = curr.w - prev.w
+        val pv = curr.v - prev.v
+        val nx = next.x - curr.x
+        val ny = next.y - curr.y
+        val nz = next.z - curr.z
+        val nw = next.w - curr.w
+        val nv = next.v - curr.v
+
+        val d = nx*nx + ny*ny + nz*nz + nw*nw + nv*nv
+
+        if (d > 0)
         {
-        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;
+            val q = sqrt( ((px*px+py*py+pz*pz+pw*pw+pv*pv)/d).toDouble() ).toFloat()
+
+            if (q > 1)
+            {
+                cache.velocity[0] = nx + px/q
+                cache.velocity[1] = ny + py/q
+                cache.velocity[2] = nz + pz/q
+                cache.velocity[3] = nw + pw/q
+                cache.velocity[4] = nv + pv/q
+            }
+            else
+            {
+                cache.velocity[0] = px + nx*q
+                cache.velocity[1] = py + ny*q
+                cache.velocity[2] = pz + nz*q
+                cache.velocity[3] = pw + nw*q
+                cache.velocity[4] = pv + nv*q
+            }
         }
-      else
+        else
         {
-        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;
+            cache.velocity[0] = 0.0f
+            cache.velocity[1] = 0.0f
+            cache.velocity[2] = 0.0f
+            cache.velocity[3] = 0.0f
+            cache.velocity[4] = 0.0f
         }
-      }
-    else
-      {
-      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;
-      }
     }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  private void recomputeCache()
-    {  
-    if( numPoints==1 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      curr= vv.elementAt(0);
-        
-      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 )
-      {
-      tmpCache1 = vc.elementAt(0);
-      tmpCache2 = vc.elementAt(1);
-      curr= vv.elementAt(0);
-      next= vv.elementAt(1);
-      
-      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;
-      
-      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
-      {
-      int i, n;  
-      
-      for(i=0; i<numPoints; i++) computeVelocity(i);
-   
-      for(i=0; i<numPoints; i++)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun recomputeCache()
+    {
+        if (numPoints==1)
         {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        tmpCache1 = vc.elementAt(i);
-        tmpCache2 = vc.elementAt(n);
-        curr= vv.elementAt(i);
-        next= vv.elementAt(n);
-      
-        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;
-        
-        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;
-      
-        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;
-        
-        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;
-        
-        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);
+            val cache = vc!!.elementAt(0)
+            val curr = vv.elementAt(0)
+
+            cache.a[4] = 0.0f
+            cache.a[3] = cache.a[4]
+            cache.a[2] = cache.a[3]
+            cache.a[1] = cache.a[2]
+            cache.a[0] = cache.a[1]
+            cache.b[4] = 0.0f
+            cache.b[3] = cache.b[4]
+            cache.b[2] = cache.b[3]
+            cache.b[1] = cache.b[2]
+            cache.b[0] = cache.b[1]
+            cache.c[0] = curr.x
+            cache.c[1] = curr.y
+            cache.c[2] = curr.z
+            cache.c[3] = curr.w
+            cache.c[4] = curr.v
+            cache.d[4] = 0.0f
+            cache.d[3] = cache.d[4]
+            cache.d[2] = cache.d[3]
+            cache.d[1] = cache.d[2]
+            cache.d[0] = cache.d[1]
+        }
+        else if (numPoints==2)
+        {
+            val cache1 = vc!!.elementAt(0)
+            val cache2 = vc!!.elementAt(1)
+            val curr = vv.elementAt(0)
+            val next = vv.elementAt(1)
+
+            cache1.a[4] = 0.0f
+            cache1.a[3] = cache1.a[4]
+            cache1.a[2] = cache1.a[3]
+            cache1.a[1] = cache1.a[2]
+            cache1.a[0] = cache1.a[1]
+            cache1.b[4] = 0.0f
+            cache1.b[3] = cache1.b[4]
+            cache1.b[2] = cache1.b[3]
+            cache1.b[1] = cache1.b[2]
+            cache1.b[0] = cache1.b[1]
+            cache1.c[0] = next.x - curr.x
+            cache1.c[1] = next.y - curr.y
+            cache1.c[2] = next.z - curr.z
+            cache1.c[3] = next.w - curr.w
+            cache1.c[4] = next.v - curr.v
+            cache1.d[0] = curr.x
+            cache1.d[1] = curr.y
+            cache1.d[2] = curr.z
+            cache1.d[3] = curr.w
+            cache1.d[4] = curr.v
+
+            cache2.a[4] = 0.0f
+            cache2.a[3] = cache2.a[4]
+            cache2.a[2] = cache2.a[3]
+            cache2.a[1] = cache2.a[2]
+            cache2.a[0] = cache2.a[1]
+            cache2.b[4] = 0.0f
+            cache2.b[3] = cache2.b[4]
+            cache2.b[2] = cache2.b[3]
+            cache2.b[1] = cache2.b[2]
+            cache2.b[0] = cache2.b[1]
+            cache2.c[0] = curr.x - next.x
+            cache2.c[1] = curr.y - next.y
+            cache2.c[2] = curr.z - next.z
+            cache2.c[3] = curr.w - next.w
+            cache2.c[4] = curr.v - next.v
+            cache2.d[0] = next.x
+            cache2.d[1] = next.y
+            cache2.d[2] = next.z
+            cache2.d[3] = next.w
+            cache2.d[4] = next.v
+        }
+        else
+        {
+            var n: Int
+            var i = 0
+
+            while (i < numPoints)
+            {
+                computeVelocity(i)
+                i++
+            }
+
+            i = 0
+            while (i < numPoints)
+            {
+                n = if (i < numPoints-1) i+1 else 0
+
+                val cache1 = vc!!.elementAt(i)
+                val cache2 = vc!!.elementAt(n)
+                val curr = vv.elementAt(i)
+                val next = vv.elementAt(n)
+
+                cache1.cached[0] = curr.x
+                cache1.cached[1] = curr.y
+                cache1.cached[2] = curr.z
+                cache1.cached[3] = curr.w
+                cache1.cached[4] = curr.v
+
+                cache1.a[0] = mConvexity * ( 2*curr.x +   cache1.velocity[0] - 2*next.x + cache2.velocity[0])
+                cache1.b[0] = mConvexity * (-3*curr.x - 2*cache1.velocity[0] + 3*next.x - cache2.velocity[0])
+                cache1.c[0] = mConvexity * (cache1.velocity[0]) + (1.0f-mConvexity) * (next.x-curr.x)
+                cache1.d[0] = curr.x
+
+                cache1.a[1] = mConvexity * ( 2*curr.y +   cache1.velocity[1] - 2*next.y + cache2.velocity[1])
+                cache1.b[1] = mConvexity * (-3*curr.y - 2*cache1.velocity[1] + 3*next.y - cache2.velocity[1])
+                cache1.c[1] = mConvexity * (cache1.velocity[1]) + (1.0f-mConvexity) * (next.y-curr.y)
+                cache1.d[1] = curr.y
+
+                cache1.a[2] = mConvexity * ( 2*curr.z +   cache1.velocity[2] - 2*next.z + cache2.velocity[2])
+                cache1.b[2] = mConvexity * (-3*curr.z - 2*cache1.velocity[2] + 3*next.z - cache2.velocity[2])
+                cache1.c[2] = mConvexity * (cache1.velocity[2]) + (1.0f-mConvexity) * (next.z-curr.z)
+                cache1.d[2] = curr.z
+
+                cache1.a[3] = mConvexity * ( 2*curr.w +   cache1.velocity[3] - 2*next.w + cache2.velocity[3])
+                cache1.b[3] = mConvexity * (-3*curr.w - 2*cache1.velocity[3] + 3*next.w - cache2.velocity[3])
+                cache1.c[3] = mConvexity * (cache1.velocity[3]) + (1.0f-mConvexity) * (next.w-curr.w)
+                cache1.d[3] = curr.w
+
+                cache1.a[4] = mConvexity * ( 2*curr.v +   cache1.velocity[4] - 2*next.v + cache2.velocity[4])
+                cache1.b[4] = mConvexity * (-3*curr.v - 2*cache1.velocity[4] + 3*next.v - cache2.velocity[4])
+                cache1.c[4] = mConvexity * (cache1.velocity[4]) + (1.0f-mConvexity) * (next.v-curr.v)
+                cache1.d[4] = curr.v
+
+                if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) smoothOutSegment(cache1)
+                i++
+            }
         }
-      }
-   
-    cacheDirty = false;
-    }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public Dynamic5D()
-    {
-    super(0,0.5f,5);
-    vv = new Vector<>();
+        cacheDirty = false
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor setting the speed of interpolation and the number of revolutions.
- *
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @param duration number of milliseconds it takes to do one revolution.
- * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
- */
-  public Dynamic5D(int duration, float count)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    constructor() : super(0, 0.5f, 5) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Constructor setting the speed of interpolation and the number of revolutions.
+    *
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    *
+    * @param duration number of milliseconds it takes to do one revolution.
+    * @param count number of revolutions we will do. Count<=0 means 'infinite'.
+    */
+    constructor(duration: Int, count: Float) : super(duration, count, 5) { vv = Vector() }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Returns the index'th Static5D.
+    *
+    * @param index the index of the Point we are interested in .
+    * @ return The Static5D, if 0<=location&lt;getNumPoints(), or null otherwise.
+    */
+    @Synchronized
+    fun getPoint(index: Int): Static5D?
     {
-    super(duration,count,5);
-    vv = new Vector<>();
+        return if (index in 0..<numPoints) vv.elementAt(index) else null
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Returns the location'th Static5D.
- *   
- * @param location the index of the Point we are interested in.
- * @return The Static5D, if 0<=location&lt;getNumPoints(), or null otherwise.
- */  
-  public synchronized Static5D getPoint(int location)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Resets the index'th Point.
+    *
+    * @param index the index of the Point we are setting.
+    * @param x New value of its first float.
+    */
+    @Synchronized
+    fun setPoint(index: Int, x: Float, y: Float, z: Float, w: Float, v: Float)
     {
-    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, float v)
-    {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
+        if (index in 0..<numPoints)
         {
-        curr.set(x,y,z,w,v);
-        cacheDirty=true;
+            val curr = vv.elementAt(index)
+
+            if (curr!=null)
+            {
+                curr.set(x,y,z,w,v)
+                cacheDirty = true
+            }
         }
-      }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Static5D 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 Static5D#set(float,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(Static5D v)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static5D to the end of our list of Points to interpolate through.
+    *
+    * Only a reference to the Point gets added to the List; this means that one can add a Point
+    * here, and later on [Static5D.set] it to some new value and
+    * the change will be seamlessly reflected in the interpolated path.
+    *
+    * A Point can be added multiple times.
+    *
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(v: Static5D?)
     {
-    if( v!=null )
-      {
-      vv.add(v);
-        
-      if( vn!=null ) vn.add(new VectorNoise());
-       
-      switch(numPoints)
+        if (v != null)
         {
-        case 0: break;
-        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(new VectorCache());
+            vv.add(v)
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0 -> {}
+                1 -> computeOrthonormalBase2(vv.elementAt(0), v)
+                2 -> {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                     }
+                else -> vc!!.add(VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-
-      numPoints++;
-      cacheDirty = true;
-      }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Adds a new Static5D 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 Static5D to add.
- */  
-  public synchronized void add(int location, Static5D v)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static5D to the index'th place in our List of Points to interpolate through.
+    *
+    * @param index Index in our List to add the new Point at.
+    * @param v The Static5D to add.
+    */
+    @Synchronized
+    fun add(index: Int, v: Static5D?)
     {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      if( vn!=null ) vn.add(new VectorNoise());
-      
-      switch(numPoints)
+        if (v!=null)
         {
-        case 0: break;
-        case 1: computeOrthonormalBase2(vv.elementAt(0),v);
-                break;
-        case 2: vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                vc.add(new VectorCache());
-                break;
-        default:vc.add(location,new VectorCache());
+            vv.add(index,v)
+            if (vn!=null) vn!!.add(VectorNoise())
+
+            when (numPoints)
+            {
+                0 -> {}
+                1 -> computeOrthonormalBase2(vv.elementAt(0), v)
+                2 -> {
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                        vc!!.add(VectorCache())
+                     }
+                else -> vc!!.add(index, VectorCache())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-
-      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(Static5D v)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all occurrences of Point v from the List of Points to interpolate through.
+    *
+    * @param v The Point to remove.
+    * @return `true` if we have removed at least one Point.
+    */
+    @Synchronized
+    fun remove(v: Static5D): Boolean
     {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      if( vn!=null ) vn.remove(0);
-     
-      switch(numPoints)
+        var n = vv.indexOf(v)
+        var found = false
+
+        while (n>=0)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
-                break;
-        default:vc.remove(n);
+            vv.removeAt(n)
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3 -> {
+                        vc!!.removeAllElements()
+                        computeOrthonormalBase2(vv.elementAt(0), vv.elementAt(1))
+                     }
+                else -> vc!!.removeAt(n)
+            }
+
+            numPoints--
+            found = true
+            n = vv.indexOf(v)
         }
 
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
+        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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes a index'th Point from the List of Points we interpolate through.
+    *
+    * @param index index of the Point we want to remove.
+    * @ return `true` if location is valid, i.e. if 0<=location&lt;getNumPoints().
+    */
+    @Synchronized
+    fun remove(index: Int): Boolean
     {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-       
-      if( vn!=null ) vn.remove(0);
-      
-      switch(numPoints)
+        if (index in 0..<numPoints)
         {
-        case 0:
-        case 1: 
-        case 2: break;
-        case 3: vc.removeAllElements();
-                computeOrthonormalBase2(vv.elementAt(0),vv.elementAt(1));
-                break;
-        default:vc.removeElementAt(location);
+            vv.removeElementAt(index)
+            if (vn!=null) vn!!.removeAt(0)
+
+            when (numPoints)
+            {
+                0, 1, 2 -> {}
+                3 -> {
+                        vc!!.removeAllElements()
+                        computeOrthonormalBase2(vv.elementAt(0), vv.elementAt(1))
+                    }
+                else -> vc!!.removeElementAt(index)
+            }
+
+            numPoints--
+            cacheDirty = true
+            return true
         }
 
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-    return false;
+        return false
     }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all Points.
+    */
+    @Synchronized
+    fun removeAll()
     {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
-   
-    if( vn!=null ) vn.removeAllElements();
+        numPoints = 0
+        vv.removeAllElements()
+        vc!!.removeAllElements()
+        cacheDirty = false
+        if (vn != null) vn!!.removeAllElements()
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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 synchronized void setNoise(Static5D noise)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Sets the 'smoothness' of interpolation.
+    *
+    * 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.
+    */
+    @Synchronized
+    fun setNoise(noise: Static5D)
     {
-    if( vn==null )
-      {
-      vn = new Vector<>();
-      for(int i=0; i<numPoints; i++) vn.add(new VectorNoise());
-
-      if( mDimension>=2 )
+        if (vn == null)
         {
-        mFactor = new float[mDimension-1];
+            vn = Vector()
+            for (i in 0..<numPoints) vn!!.add(VectorNoise())
+            if (dimension>=2) mFactor = FloatArray(dimension-1)
+            mNoise = FloatArray(dimension)
         }
 
-      mNoise = new float[mDimension];
-      }
-
-    if( noise.x<0.0f ) noise.x = 0.0f;
-    if( noise.x>1.0f ) noise.x = 1.0f;
-    if( noise.y<0.0f ) noise.y = 0.0f;
-    if( noise.y>1.0f ) noise.y = 1.0f;
-    if( noise.z<0.0f ) noise.z = 0.0f;
-    if( noise.z>1.0f ) noise.z = 1.0f;
-    if( noise.w<0.0f ) noise.w = 0.0f;
-    if( noise.w>1.0f ) noise.w = 1.0f;
-    if( noise.v<0.0f ) noise.v = 0.0f;
-    if( noise.v>1.0f ) noise.v = 1.0f;
-
-    mNoise[0] = noise.x;
-    mNoise[1] = noise.y;
-    mNoise[2] = noise.z;
-    mNoise[3] = noise.w;
-    mNoise[4] = noise.v;
+        if (noise.x < 0.0f) noise.x = 0.0f
+        if (noise.x > 1.0f) noise.x = 1.0f
+        if (noise.y < 0.0f) noise.y = 0.0f
+        if (noise.y > 1.0f) noise.y = 1.0f
+        if (noise.z < 0.0f) noise.z = 0.0f
+        if (noise.z > 1.0f) noise.z = 1.0f
+        if (noise.w < 0.0f) noise.w = 0.0f
+        if (noise.w > 1.0f) noise.w = 1.0f
+        if (noise.v < 0.0f) noise.v = 0.0f
+        if (noise.v > 1.0f) noise.v = 1.0f
+
+        mNoise[0] = noise.x
+        mNoise[1] = noise.y
+        mNoise[2] = noise.z
+        mNoise[3] = noise.w
+        mNoise[4] = noise.v
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    @Synchronized
+    override fun interpolate(buffer: FloatArray, offset: Int, tm: Float)
+    {
+        var time = tm
 
-  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;
-              buffer[offset+4] = 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;
-              buffer[offset+4] = curr.v;
-              break;
-      case 2: curr = vv.elementAt(0);
-              next = vv.elementAt(1);
-
-              int segment= (int)(2*time);
-
-              if( mMode==MODE_LOOP || mMode==MODE_PATH ) time = (time>0.5f ? 2-2*time : 2*time);
-
-              if( vn!=null )
-                {
-                if( segment != mSegment )
-                  {
-                  if(mMode!=MODE_JUMP || mSegment==1) vn.elementAt(0).computeNoise();
-                  mSegment = segment;
-                  }
-
-                time = noise(time,0);
-
-                buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2] + baseV[4][0]*mFactor[3]);
-                buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2] + baseV[4][1]*mFactor[3]);
-                buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2] + baseV[4][2]*mFactor[3]);
-                buffer[offset+3] = (next.w-curr.w)*time + curr.w + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2] + baseV[4][3]*mFactor[3]);
-                buffer[offset+4] = (next.v-curr.v)*time + curr.v + (baseV[1][4]*mFactor[0] + baseV[2][4]*mFactor[1] + baseV[3][4]*mFactor[2] + baseV[4][4]*mFactor[3]);
-                }
-              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;
-                buffer[offset+4] = (next.v-curr.v)*time + curr.v;
+        when (numPoints)
+        {
+            0 -> {
+                    buffer[offset  ] = 0.0f
+                    buffer[offset+1] = 0.0f
+                    buffer[offset+2] = 0.0f
+                    buffer[offset+3] = 0.0f
+                    buffer[offset+4] = 0.0f
+                 }
+
+            1 -> {
+                    val curr = vv.elementAt(0)
+                    buffer[offset  ] = curr.x
+                    buffer[offset+1] = curr.y
+                    buffer[offset+2] = curr.z
+                    buffer[offset+3] = curr.w
+                    buffer[offset+4] = curr.v
+                 }
+
+            2 -> {
+                    val curr = vv.elementAt(0)
+                    val next = vv.elementAt(1)
+                    val segment = (2*time).toInt()
+
+                    if (mMode==MODE_LOOP || mMode==MODE_PATH) time = (if (time>0.5f) 2-2*time else 2*time)
+
+                    if (vn != null)
+                    {
+                        if (segment != mSegment)
+                        {
+                            if (mMode!=MODE_JUMP || mSegment==1) vn!!.elementAt(0).computeNoise()
+                            mSegment = segment
+                        }
+
+                        time = noise(time,0)
+
+                        buffer[offset  ] = (next.x-curr.x)*time + curr.x + (baseV[1][0]*mFactor[0] + baseV[2][0]*mFactor[1] + baseV[3][0]*mFactor[2] + baseV[4][0]*mFactor[3])
+                        buffer[offset+1] = (next.y-curr.y)*time + curr.y + (baseV[1][1]*mFactor[0] + baseV[2][1]*mFactor[1] + baseV[3][1]*mFactor[2] + baseV[4][1]*mFactor[3])
+                        buffer[offset+2] = (next.z-curr.z)*time + curr.z + (baseV[1][2]*mFactor[0] + baseV[2][2]*mFactor[1] + baseV[3][2]*mFactor[2] + baseV[4][2]*mFactor[3])
+                        buffer[offset+3] = (next.w-curr.w)*time + curr.w + (baseV[1][3]*mFactor[0] + baseV[2][3]*mFactor[1] + baseV[3][3]*mFactor[2] + baseV[4][3]*mFactor[3])
+                        buffer[offset+4] = (next.v-curr.v)*time + curr.v + (baseV[1][4]*mFactor[0] + baseV[2][4]*mFactor[1] + baseV[3][4]*mFactor[2] + baseV[4][4]*mFactor[3])
+                    }
+                    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
+                        buffer[offset+4] = (next.v-curr.v)*time + curr.v
+                    }
                 }
-                
-              break;
-      default:computeSegmentAndTime(time);
 
-              if( mTmpVec>=0 && mTmpVec<numPoints )
+            else ->
                 {
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mSegment!= mTmpSeg )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  int vecNext = getNext(mTmpVec,time);
-                  next = vv.elementAt(vecNext);
-                  tmpCache2 = vc.elementAt(vecNext);
-
-                  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!= mTmpSeg && vn!=null ) vn.elementAt(mTmpVec).computeNoise();
-
-                mSegment = mTmpSeg;
-                time = mTmpTime-mTmpVec;
-                tmpCache1 = vc.elementAt(mTmpVec);
-                if( mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT ) time = smoothSpeed(time, tmpCache1);
-
-                if( vn!=null )
-                  {
-                  time = noise(time,mTmpVec);
-              
-                  computeOrthonormalBaseMore(time, tmpCache1);
-
-                  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  ]= ((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;
+                    computeSegmentAndTime(time)
+
+                    if (mTmpVec in 0..<numPoints)
+                    {
+                        if (cacheDirty) recomputeCache() // recompute cache if we have added or remove vectors since last computation
+                        else if (mSegment != mTmpSeg)  // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                        {
+                            val vecNext = getNext(mTmpVec,time)
+                            val next = vv.elementAt(vecNext)
+                            val cache = vc!!.elementAt(vecNext)
+
+                            if (cache.cached[0]!=next.x || cache.cached[1]!=next.y || cache.cached[2]!=next.z || cache.cached[3]!=next.w || cache.cached[4]!=next.v) recomputeCache()
+                        }
+
+                        if (mSegment!=mTmpSeg && vn!=null) vn!!.elementAt(mTmpVec).computeNoise()
+
+                        mSegment = mTmpSeg
+                        time = mTmpTime - mTmpVec
+                        val cache = vc!!.elementAt(mTmpVec)
+                        if (mSpeedMode==SPEED_MODE_SEGMENT_CONSTANT) time = smoothSpeed(time,cache)
+
+                        if (vn != null)
+                        {
+                            time = noise(time,mTmpVec)
+                            computeOrthonormalBaseMore(time,cache)
+
+                        buffer[offset  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.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] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.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] = ((cache.a[2]*time + cache.b[2])*time + cache.c[2])*time + cache.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] = ((cache.a[3]*time + cache.b[3])*time + cache.c[3])*time + cache.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] = ((cache.a[4]*time + cache.b[4])*time + cache.c[4])*time + cache.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  ] = ((cache.a[0]*time + cache.b[0])*time + cache.c[0])*time + cache.d[0]
+                        buffer[offset+1] = ((cache.a[1]*time + cache.b[1])*time + cache.c[1])*time + cache.d[1]
+                        buffer[offset+2] = ((cache.a[2]*time + cache.b[2])*time + cache.c[2])*time + cache.d[2]
+                        buffer[offset+3] = ((cache.a[3]*time + cache.b[3])*time + cache.c[3])*time + cache.d[3]
+                        buffer[offset+4] = ((cache.a[4]*time + cache.b[4])*time + cache.c[4])*time + cache.d[4]
+                        }
+                    }
                 }
-      }
-    }  
-
-  }
-///////////////////////////////////////////////////////////////////////////////////////////////////
-//
+        }
+    }
+} /**//////////////////////////////////////////////////////////////////////////////////////////////// */ //
diff --git a/src/main/java/org/distorted/library/type/DynamicQuat.kt b/src/main/java/org/distorted/library/type/DynamicQuat.kt
index 145585c..dc76eba 100644
--- a/src/main/java/org/distorted/library/type/DynamicQuat.kt
+++ b/src/main/java/org/distorted/library/type/DynamicQuat.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,14 +18,14 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
-import java.util.Vector;
+import java.util.Vector
+import kotlin.math.sin
+import kotlin.math.sqrt
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/** 
-* A 4-dimensional implementation of the Dynamic class to interpolate between a list
-* of Static4Ds.
+/** 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?).
 *
@@ -34,381 +34,383 @@ import java.util.Vector;
 *
 * Rotation Quaternion is assumed to be in the form ( axisX*sinT, axisY*sinT, axisZ*sinT, cosT ).
 */
-
-public class DynamicQuat extends Dynamic implements Data4D
-  {
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Here we implement our own Cache as we need something slightly different.
-// 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 VectorCacheQuat
+class DynamicQuat : Dynamic, Data4D 
+{
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Here we implement our own Cache as we need something slightly different.
+    // 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 inner class VectorCacheQuat 
     {
-    float omega, sinOmega,cosOmega;
-    float vx,vy,vz,vw;
+        var omega: Float = 0f
+        var sinOmega: Float = 0f
+        var cosOmega: Float = 0f
+        var vx: Float = 0f
+        var vy: Float = 0f
+        var vz: Float = 0f
+        var vw: Float = 0f
     }
-  
-  private final Vector<VectorCacheQuat> vc;
-  private VectorCacheQuat tmp1, tmp2;
 
-  private final Vector<Static4D> vv;
-  private Static4D curr, next;
- 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Abramowitz / Stegun
+    private var cc: Vector<VectorCacheQuat> = Vector<VectorCacheQuat>()
+    private val vv = Vector<Static4D>()
 
-  private static float arcCos(float x)
+    companion object 
     {
-    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);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void recomputeCache()
-    {  
-    if( numPoints>=2 )
-      {
-      int i, n;  
-      Static4D cu,ne;
-      VectorCacheQuat vq;
-
-      for(i=0; i<numPoints; i++)
+        // Abramowitz / Stegun
+        private fun arcCos(x: Float): Float 
         {
-        n = i<numPoints-1 ? i+1:0;  
-      
-        vq= vc.elementAt(i);
-        cu= vv.elementAt(i);
-        ne= vv.elementAt(n);
-      
-        vq.vx = cu.x;
-        vq.vy = cu.y;
-        vq.vz = cu.z;
-        vq.vw = cu.w;
-    	
-        vq.cosOmega = cu.x*ne.x + cu.y*ne.y + cu.z*ne.z + cu.w*ne.w;
-        vq.sinOmega = (float)Math.sqrt(1-vq.cosOmega*vq.cosOmega);
-        vq.omega    = arcCos(vq.cosOmega);
+            if (x<0) return 3.1415927f - sqrt((1+x).toDouble()).toFloat() * (1.5707288f + 0.2121144f*x + 0.074261f*x*x + 0.0187293f*x*x*x)
+            return sqrt((1-x).toDouble()).toFloat() * (1.5707288f - 0.2121144f*x + 0.074261f*x*x - 0.0187293f*x*x*x)
         }
-      }
-   
-    cacheDirty = false;
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Default constructor.
- */
-  public DynamicQuat()
+    
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private fun recomputeCache() 
     {
-    this(0,0.5f);
-    }
+        if (numPoints >= 2) 
+        {
+            var n: Int
+            var cu: Static4D
+            var ne: Static4D
+            var vq: VectorCacheQuat
+
+            var i = 0
+            while (i < numPoints) 
+            {
+                n = if (i < numPoints-1) i+1 else 0
+
+                vq = cc.elementAt(i)
+                cu = vv.elementAt(i)
+                ne = vv.elementAt(n)
+
+                vq.vx = cu.x
+                vq.vy = cu.y
+                vq.vz = cu.z
+                vq.vw = cu.w
+
+                vq.cosOmega = cu.x*ne.x + cu.y*ne.y + cu.z*ne.z + cu.w*ne.w
+                vq.sinOmega = sqrt( (1-vq.cosOmega*vq.cosOmega).toDouble() ).toFloat()
+                vq.omega = arcCos(vq.cosOmega)
+                i++
+            }
+        }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor setting the speed of interpolation and the number of revolutions.
- *
- * What constitutes 'one revolution' depends on the MODE:
- * {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- *
- * @param duration number of milliseconds it takes to do one revolution.
- * @param count    number of revolutions we will do. Count<=0 means 'infinite'.
- */
-  public DynamicQuat(int duration, float count)
+        cacheDirty = false
+    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // PUBLIC API
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    constructor() : super(0, 0.5f, 4)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Constructor setting the speed of interpolation and the number of revolutions.
+    *
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    *
+    * @param duration number of milliseconds it takes to do one revolution.
+    * @param count number of revolutions we will do. Count<=0 means 'infinite'.
+    */
+    constructor(duration: Int, count: Float) : super(duration,count,4)
     {
-    vv         = new Vector<>();
-    vc         = new Vector<>();
-    numPoints  = 0;
-    cacheDirty = false;
-    mMode      = MODE_LOOP;
-    mDuration  = duration;
-    mCount     = count;
-    mLastPos   =-1;
-    mAccessType= ACCESS_TYPE_RANDOM;
-    mDimension = 4;
-    mSegment   =-1;
-
-    initDynamic();
+        numPoints = 0
+        cacheDirty = false
+        mMode = MODE_LOOP
+        this.duration = duration.toLong()
+        this.count = count
+        mLastPos = -1.0
+        mAccessType = ACCESS_TYPE_RANDOM
+        this.dimension = 4
+        mSegment = -1
+
+        initDynamic() 
     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Returns the index'th Static4D.
+    *
+    * @param index the index of the Point we are interested in.
+    * @ return The Static4D, if 0<=location&lt;getNumPoints(), or null otherwise.
+    */
+    @Synchronized
+    fun getPoint(index: Int): Static4D? 
     {
-    return (location>=0 && location<numPoints) ? vv.elementAt(location) : null;  
+        return if (index in 0..<numPoints) vv.elementAt(index) else null
     }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the location'th Point.
- * <p>
- * Rotation Quaternion is assumed to be in the form ( axisX*sinT, axisY*sinT, axisZ*sinT, cosT ).
- *
- * @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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Resets the index'th Point.
+    *
+    * Rotation Quaternion is assumed to be in the form ( axisX*sinT, axisY*sinT, axisZ*sinT, cosT ).
+    *
+    * @param index the index of the Point we are setting.
+    * @param x New value of its first float.
+    */
+    @Synchronized
+    fun setPoint(index: Int, x: Float, y: Float, z: Float, w: Float) 
     {
-    if( location>=0 && location<numPoints )
-      {
-      curr = vv.elementAt(location);
-   
-      if( curr!=null )
+        if (index in 0..<numPoints) 
         {
-        curr.set(x,y,z,w);
-        cacheDirty=true;
+            val curr = vv.elementAt(index)
+
+            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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static4D to the end of our list of Points to interpolate through.
+    *
+    * Only a reference to the Point gets added to the List; this means that one can add a Point
+    * here, and later on [Static4D.set] it to some new value and
+    * the change will be seamlessly reflected in the interpolated path.
+    *
+    * A Point can be added multiple times.
+    *
+    * @param v The Point to add.
+    */
+    @Synchronized
+    fun add(v: Static4D?) 
     {
-    if( v!=null )
-      {
-      vv.add(v);
-      
-      switch(numPoints)
-         {
-         case 0: 
-         case 1: vc.add(new VectorCacheQuat());
-                 vc.add(new VectorCacheQuat());
-        	     break;
-         default:vc.add(new VectorCacheQuat());
-         }
-
-       numPoints++;
-       cacheDirty = true;
-       }
+        if (v != null) 
+        {
+            vv.add(v)
+
+            when (numPoints) 
+            {
+                0, 1 -> 
+                    {
+                        cc.add(VectorCacheQuat())
+                        cc.add(VectorCacheQuat())
+                    }
+                else -> cc.add(VectorCacheQuat())
+            }
+
+            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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Adds a new Static4D to the index'th place in our List of Points to interpolate through.
+    *
+    * @param index Index in our List to add the new Point at.
+    * @param v The Static4D to add.
+    */
+    @Synchronized
+    fun add(index: Int, v: Static4D?) 
     {
-    if( v!=null )
-      {
-      vv.add(location, v);
-      
-      switch(numPoints)
+        if (v != null) 
         {
-        case 0: 
-        case 1: vc.add(new VectorCacheQuat());
-                vc.add(new VectorCacheQuat());
-                break;
-        default:vc.add(location,new VectorCacheQuat());
+            vv.add(index,v)
+
+            when (numPoints) 
+            {
+                0, 1 -> 
+                    {
+                        cc.add(VectorCacheQuat())
+                        cc.add(VectorCacheQuat())
+                    }
+                else -> cc.add(index,VectorCacheQuat())
+            }
+
+            numPoints++
+            cacheDirty = true
         }
-
-      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)
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all occurrences of Point v from the List of Points to interpolate through.
+    *
+    * @param v The Point to remove.
+    * @return `true` if we have removed at least one Point.
+    */
+    @Synchronized
+    fun remove(v: Static4D): Boolean 
     {
-    int n = vv.indexOf(v);
-    boolean found = false;
-   
-    while( n>=0 ) 
-      {
-      vv.remove(n);
-     
-      switch(numPoints)
+        var n = vv.indexOf(v)
+        var found = false
+
+        while (n >= 0) 
         {
-        case 0:
-        case 1: break;
-        case 2: vc.removeAllElements();
-                break;
-        default:vc.remove(n);
+            vv.removeAt(n)
+
+            when (numPoints) 
+            {
+                0, 1 -> {}
+                2    -> cc.removeAllElements()
+                else -> cc.removeAt(n)
+            }
+
+            numPoints--
+            found = true
+            n = vv.indexOf(v)
         }
 
-      numPoints--;
-      found = true;
-      n = vv.indexOf(v);
-      }
-   
-    if( found ) 
-      {
-      cacheDirty=true;
-      }
-   
-    return found;
+        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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes a index'th Point from the List of Points we interpolate through.
+    *
+    * @param index index of the Point we want to remove.
+    * @ return `true` if location is valid, i.e. if 0<=location&lt;getNumPoints().
+    */
+    @Synchronized
+    fun remove(index: Int): Boolean 
     {
-    if( location>=0 && location<numPoints ) 
-      {
-      vv.removeElementAt(location);
-      
-      switch(numPoints)
+        if (index in 0..<numPoints) 
         {
-        case 0: 
-        case 1: break;
-        case 2: vc.removeAllElements();
-                break;
-        default:vc.removeElementAt(location);
+            vv.removeElementAt(index)
+
+            when (numPoints) 
+            {
+                0, 1 -> {}
+                2    -> cc.removeAllElements()
+                else -> cc.removeElementAt(index)
+            }
+
+            numPoints--
+            cacheDirty = true
+            return true
         }
 
-      numPoints--;
-      cacheDirty = true; 
-      return true;
-      }
-
-    return false;
+        return false
     }
-  
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Removes all Points.
- */
-  public synchronized void removeAll()
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Removes all Points.
+    */
+    @Synchronized
+    fun removeAll() 
     {
-    numPoints = 0;
-    vv.removeAllElements();
-    vc.removeAllElements();
-    cacheDirty = false;
+        numPoints = 0
+        vv.removeAllElements()
+        cc.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 is the beginning of the first revolution, time=1.0 - the end
- *               of the first revolution, time=2.5 - the middle of the third revolution.
- *               What constitutes 'one revolution' depends on the MODE:
- *               {@link Dynamic#MODE_LOOP}, {@link Dynamic#MODE_PATH} or {@link Dynamic#MODE_JUMP}.
- **/
-  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;
-              int vecCurr, segment;
-              float scale0, scale1;
-
-              switch(mMode)
-                {
-                case MODE_LOOP: time = time*numPoints;
-                                segment = (int)time;
-                                vecCurr = segment;
-                                break;
-                case MODE_PATH: if( t>0.5f ) t = 1.0f-t;
-                                time = 2*t*(numPoints-1);
-                                segment = (int)(2*t*(numPoints-1));
-                                vecCurr = segment;
-                                break;
-                case MODE_JUMP: time = time*(numPoints-1);
-                                segment = (int)time;
-                                vecCurr = segment;
-                                break;
-                default       : vecCurr = 0;
-                                segment = 0;
-                }
 
-              if( vecCurr>=0 && vecCurr<numPoints )
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** 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.
+    *
+    * 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 tm Time of interpolation. Time=0.0 is the beginning of the first revolution, time=1.0 - the end
+    * of the first revolution, time=2.5 - the middle of the third revolution.
+    * What constitutes 'one revolution' depends on the MODE:
+    * [Dynamic.MODE_LOOP], [Dynamic.MODE_PATH] or [Dynamic.MODE_JUMP].
+    */
+    @Synchronized
+    override fun interpolate(buffer: FloatArray, offset: Int, tm: Float) 
+    {
+        var time = tm
+        
+        when (numPoints) 
+        {
+            0 -> {
+                    buffer[offset  ] = 0.0f
+                    buffer[offset+1] = 0.0f
+                    buffer[offset+2] = 0.0f
+                    buffer[offset+3] = 0.0f
+                 }
+
+            1 -> {
+                    val curr = vv.elementAt(0)
+                    buffer[offset  ] = curr.x
+                    buffer[offset+1] = curr.y
+                    buffer[offset+2] = curr.z
+                    buffer[offset+3] = curr.w
+                 }
+
+            else -> 
                 {
-                int vecNext = getNext(vecCurr,t);
-
-                curr = vv.elementAt(vecCurr);
-                tmp1 = vc.elementAt(vecCurr);
-                next = vv.elementAt(vecNext);
-
-                if( cacheDirty ) recomputeCache();  // recompute cache if we have added or remove vectors since last computation
-                else if( mSegment!= segment )       // ...or if we have just passed a vector and the vector we are currently flying to has changed
-                  {
-                  tmp2 = vc.elementAt(vecNext);
-
-                  if( tmp2.vx!=next.x || tmp2.vy!=next.y || tmp2.vz!=next.z || tmp2.vw!=next.w ) recomputeCache();
-                  }
-
-                mSegment = segment;
-
-                time = time-vecCurr;
-
-                if( tmp1.sinOmega==0 )
-                  {
-                  scale0 = 1f;
-                  scale1 = 0f;
-                  }
-                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;
+                    var t = time
+                    val vecCurr: Int
+                    val segment: Int
+                    val scale0: Float
+                    val scale1: Float
+
+                    when (mMode) 
+                    {
+                        MODE_LOOP -> 
+                            {
+                                time *= numPoints
+                                segment = time.toInt()
+                                vecCurr = segment
+                            }
+
+                        MODE_PATH -> 
+                            {
+                                if (t>0.5f) t = 1.0f-t
+                                time = 2*t*(numPoints-1)
+                                segment = (2*t*(numPoints-1)).toInt()
+                                vecCurr = segment
+                            }
+
+                        MODE_JUMP -> 
+                            {
+                                time *= (numPoints-1)
+                                segment = time.toInt()
+                                vecCurr = segment
+                            }
+
+                        else -> 
+                            {
+                                vecCurr = 0
+                                segment = 0
+                            }
+                    }
+
+                    if (vecCurr in 0..<numPoints) 
+                    {
+                        val vecNext = getNext(vecCurr, t)
+                        val curr = vv.elementAt(vecCurr)
+                        val currC= cc.elementAt(vecCurr)
+                        val next = vv.elementAt(vecNext)
+
+                        if (cacheDirty) recomputeCache() // recompute cache if we have added or remove vectors since last computation
+                        else if (mSegment != segment)  // ...or if we have just passed a vector and the vector we are currently flying to has changed
+                        {
+                            val nextC = cc.elementAt(vecNext)
+                            if (nextC.vx!=next.x || nextC.vy!=next.y || nextC.vz!=next.z || nextC.vw!=next.w) recomputeCache()
+                        }
+
+                        mSegment = segment
+                        time -= vecCurr
+
+                        if (currC.sinOmega==0f) 
+                        {
+                            scale0 = 1f
+                            scale1 = 0f
+                        } 
+                        else if (currC.cosOmega < 0.99) 
+                        {
+                            scale0 = sin(((1f-time) * currC.omega).toDouble()).toFloat() / currC.sinOmega
+                            scale1 = sin((time * currC.omega).toDouble()).toFloat() / currC.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
+                    }
                 }
-      }
-    }  
-
-  }
+        }
+    }
+}
diff --git a/src/main/java/org/distorted/library/type/Static.kt b/src/main/java/org/distorted/library/type/Static.kt
index 47618b9..bdcbe79 100644
--- a/src/main/java/org/distorted/library/type/Static.kt
+++ b/src/main/java/org/distorted/library/type/Static.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,7 +18,7 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -26,24 +26,5 @@ package org.distorted.library.type;
  * particular meaning; when this data structure is used in Dynamics, we can think of it as a
  * N-dimensional Point a few of which the Dynamic interpolates between.
  */
-
-public abstract class Static
-  {
-  private final int mDimension;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  Static(int dim)
-    {
-    mDimension = dim;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the Dimension, ie number of floats in this Static.
- */
-  public int getDimension()
-    {
-    return mDimension;
-    }
-  }
\ No newline at end of file
+abstract class Static
+internal constructor(val dimension: Int) 
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/type/Static1D.kt b/src/main/java/org/distorted/library/type/Static1D.kt
index 0da4380..4ce160f 100644
--- a/src/main/java/org/distorted/library/type/Static1D.kt
+++ b/src/main/java/org/distorted/library/type/Static1D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,96 +18,64 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * A 1-dimensional data structure containing a single float. The float has no particular meaning; 
+ * A 1-dimensional data structure containing a single float. The float has no particular meaning;
  * when this data structure is used in Dynamics, we can think of it as a 1-dimensional Point
  * a few of which the Dynamic interpolates between.
  */
+class Static1D : Static, Data1D
+{
+    var x: Float
 
-public class Static1D extends Static implements Data1D
-  {
-  float x;
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox value of the single float.
+    */
+    constructor(ox: Float) : super(1) { x = ox }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the single float to ox.   
- *   
- * @param ox value of the single float.
- */  
-  public Static1D(float ox)
-    {
-    super(1);
-    x = ox;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy constructor.
+    */
+    constructor(sta: Static1D) : super(1) { x = sta.x }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy constructor.
- */
-  public Static1D(Static1D sta)
-    {
-    super(1);
-    x = sta.x;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the single float.
- * 
- * @param ox new value of the single float.
- */
-  public void set(float ox)
-    {
-    x = ox;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the single float.
+    */
+    fun set(ox: Float) { x = ox }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy a Static1D.
- */
-  public void set(Static1D s)
-    {
-    x = s.x;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy a Static1D.
+    */
+    fun set(s: Static1D) { x = s.x }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the first float.
- *
- * @param ox new value of the first float.
- */
-  public void set0(float ox)
-    {
-    x = ox;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the first float.
+    */
+    fun set0(ox: Float) { x = ox }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the float contained.
- * 
- * @return The single float.
- */
-  public float get0()
-    {
-    return x;  
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @return The single float.
+    */
+    fun get0(): Float { return x }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 'Interpolation' between the single Point (i.e. always this very value) returned to the buffer.
- *
- * @param buffer Float buffer we will write the results to.
- * @param offset Offset in the buffer where to write the result.
- * @param time not used
- * @param step not used
- * @return <code>false</code>
- */
-  public boolean get(float[] buffer, int offset, long time, long step)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** 'Interpolation' between the single Point (i.e. always this very value ) returned to the buffer.
+    *
+    * @param buffer Float buffer we will write the results to.
+    * @param offset Offset in the buffer where to write the result.
+    * @param time not used
+    * @param step not used
+    * @return `false`
+    */
+    override fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
     {
-    buffer[offset] = x;
-    return false;
+        buffer[offset] = x
+        return false
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/type/Static2D.kt b/src/main/java/org/distorted/library/type/Static2D.kt
index 2d827ac..485d656 100644
--- a/src/main/java/org/distorted/library/type/Static2D.kt
+++ b/src/main/java/org/distorted/library/type/Static2D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,125 +18,96 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * A 2-dimensional data structure containing two floats. The floats have no particular meaning; 
+ * A 2-dimensional data structure containing two floats. The floats have no particular meaning;
  * when this data structure is used in Dynamics, we can think of it as a 2-dimensional Point
  * a few of which the Dynamic interpolates between.
  */
+class Static2D : Static, Data2D
+{
+    var x: Float
+    var y: Float
 
-public class Static2D extends Static implements Data2D
-  {
-  float x,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(float ox, float oy)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox value of the first float.
+    * @param oy value of the second float.
+    */
+    constructor(ox: Float, oy: Float) : super(2)
     {
-    super(2);
-    x = ox;
-    y = oy;
+        x = ox
+        y = oy
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy constructor.
- */
-  public Static2D(Static2D sta)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy constructor.
+    */
+    constructor(sta: Static2D) : super(2)
     {
-    super(2);
-    x = sta.x;
-    y = sta.y;
+        x = sta.x
+        y = sta.y
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the first float
+    * @param oy new value of the seond float
+    */
+    fun set(ox: Float, oy: Float)
     {
-    x = ox;
-    y = oy;
+        x = ox
+        y = oy
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy a Static2D.
- */
-  public void set(Static2D s)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy a Static2D.
+     */
+    fun set(s: Static2D)
     {
-    x = s.x;
-    y = s.y;
+        x = s.x
+        y = s.y
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the first float.
- *
- * @param ox new value of the first float.
- */
-  public void set0(float ox)
-    {
-    x = ox;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the first float.
+    */
+    fun set0(ox: Float) { x = ox }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the second float.
- *
- * @param oy new value of the second float.
- */
-  public void set1(float oy)
-    {
-    y = oy;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oy new value of the second float.
+    */
+    fun set1(oy: Float) { y = oy }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the first float contained.
- *
- * @return The first float.
- */
-  public float get0()
-    {
-    return x;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @return The first float.
+    */
+    fun get0(): Float { return x }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the second float contained.
- * 
- * @return The second float.
- */
-  public float get1()
-    {
-    return y;  
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @return The second float.
+    */
+    fun get1(): Float { return y }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 'Interpolation' between the single Point (i.e. always this very value) returned to the buffer.
- *
- * @param buffer Float buffer we will write the results to.
- * @param offset Offset in the buffer where to write the result.
- * @param time not used
- * @param step not used
- * @return <code>false</code>
- */
-  public boolean get(float[] buffer, int offset, long time, long step)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** 'Interpolation' between the single Point (i.e. always this very value ) returned to the buffer.
+    *
+    * @param buffer Float buffer we will write the results to.
+    * @param offset Offset in the buffer where to write the result.
+    * @param time not used
+    * @param step not used
+    * @return `false`
+    */
+    override fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
     {
-    buffer[offset  ] = x;
-    buffer[offset+1] = y;
-    return false;
+        buffer[offset  ] = x
+        buffer[offset+1] = y
+        return false
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/type/Static3D.kt b/src/main/java/org/distorted/library/type/Static3D.kt
index c7dc291..b5dcd71 100644
--- a/src/main/java/org/distorted/library/type/Static3D.kt
+++ b/src/main/java/org/distorted/library/type/Static3D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,154 +18,116 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * A 3-dimensional data structure containing three floats. The floats have no particular meaning; 
+ * A 3-dimensional data structure containing three floats. The floats have no particular meaning;
  * when this data structure is used in Dynamics, we can think of it as a 3-dimensional Point
  * a few of which the Dynamic interpolates between.
  */
+class Static3D : Static, Data3D
+{
+    var x: Float
+    var y: Float
+    var z: Float
 
-public class Static3D extends Static implements Data3D
-  {
-  float x,y,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(float vx, float vy, float vz)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param vx value of the first float.
+    * @param vy value of the second float.
+    * @param vz value of the third float.
+    */
+    constructor(vx: Float, vy: Float, vz: Float) : super(3)
     {
-    super(3);
-    x = vx;
-    y = vy;
-    z = vz;
+        x = vx
+        y = vy
+        z = vz
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy constructor.
- */
-  public Static3D(Static3D sta)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy constructor.
+    */
+    constructor(sta: Static3D) : super(3)
     {
-    super(3);
-    x = sta.x;
-    y = sta.y;
-    z = sta.z;
+        x = sta.x
+        y = sta.y
+        z = sta.z
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param vx new value of the first float
+    * @param vy new value of the second float
+    * @param vz new value of the third float
+    */
+    fun set(vx: Float, vy: Float, vz: Float)
     {
-    x = vx;
-    y = vy;
-    z = vz;
+        x = vx
+        y = vy
+        z = vz
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy a Static3D.
- */
-  public void set(Static3D s)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy a Static3D.
+    */
+    fun set(s: Static3D)
     {
-    x = s.x;
-    y = s.y;
-    z = s.z;
+        x = s.x
+        y = s.y
+        z = s.z
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the first float.
- *
- * @param ox new value of the first float.
- */
-  public void set0(float ox)
-    {
-    x = ox;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the first float.
+    */
+    fun set0(ox: Float) { x = ox }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the second float.
- *
- * @param oy new value of the second float.
- */
-  public void set1(float oy)
-    {
-    y = oy;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oy new value of the second float.
+    */
+    fun set1(oy: Float) { y = oy }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the third float.
- *
- * @param oz new value of the third float.
- */
-  public void set2(float oz)
-    {
-    z = oz;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oz new value of the third float.
+    */
+    fun set2(oz: Float) { z = oz }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the first float contained.
- *
- * @return The first float.
- */
-  public float get0()
-    {
-    return x;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The first float.
+    */
+    fun get0(): Float { return x }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the second float contained.
- *
- * @return The second float.
- */
-  public float get1()
-    {
-    return y;
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The second float.
+    */
+    fun get1(): Float { return y }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the third float contained.
- * 
- * @return The third float.
- */
-  public float get2()
-    {
-    return z;  
-    }
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The third float.
+    */
+    fun get2(): Float { return z }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 'Interpolation' between the single Point (i.e. always this very value) returned to the buffer.
- *
- * @param buffer Float buffer we will write the results to.
- * @param offset Offset in the buffer where to write the result.
- * @param time not used
- * @param step not used
- * @return <code>false</code>
- */
-  public boolean get(float[] buffer, int offset, long time, long step)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** 'Interpolation' between the single Point (i.e. always this very value ) returned to the buffer.
+    *
+    * @param buffer Float buffer we will write the results to.
+    * @param offset Offset in the buffer where to write the result.
+    * @param time not used
+    * @param step not used
+    * @return `false`
+    */
+    override fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
     {
-    buffer[offset  ] = x;
-    buffer[offset+1] = y;
-    buffer[offset+2] = z;
-    return false;
+        buffer[offset  ] = x
+        buffer[offset+1] = y
+        buffer[offset+2] = z
+        return false
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/type/Static4D.kt b/src/main/java/org/distorted/library/type/Static4D.kt
index 3ffbedb..93508a0 100644
--- a/src/main/java/org/distorted/library/type/Static4D.kt
+++ b/src/main/java/org/distorted/library/type/Static4D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,183 +18,136 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * A 4-dimensional data structure containing four floats. The floats have no particular meaning; 
+ * 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 Static implements Data4D
-  {
-  float x,y,z,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(float vx, float vy, float vz, float vw)
+class Static4D : Static, Data4D
+{
+    var x: Float
+    var y: Float
+    var z: Float
+    var w: Float
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @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.
+    */
+    constructor(vx: Float, vy: Float, vz: Float, vw: Float) : super(4)
     {
-    super(4);
-    x = vx;
-    y = vy;
-    z = vz;
-    w = vw;
+        x = vx
+        y = vy
+        z = vz
+        w = vw
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy constructor.
- */
-  public Static4D(Static4D sta)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy constructor.
+    */
+    constructor(sta: Static4D) : super(4)
     {
-    super(4);
-    x = sta.x;
-    y = sta.y;
-    z = sta.z;
-    w = sta.w;
+        x = sta.x
+        y = sta.y
+        z = sta.z
+        w = sta.w
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 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)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @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
+    */
+    fun set(vx: Float, vy: Float, vz: Float, vw: Float)
     {
-    x = vx;
-    y = vy;
-    z = vz;
-    w = vw;
+        x = vx
+        y = vy
+        z = vz
+        w = vw
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy a Static4D.
- */
-  public void set(Static4D s)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy a Static4D.
+    */
+    fun set(s: Static4D)
     {
-    x = s.x;
-    y = s.y;
-    z = s.z;
-    w = s.w;
+        x = s.x
+        y = s.y
+        z = s.z
+        w = s.w
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the first float.
- *
- * @param ox new value of the first float.
- */
-  public void set0(float ox)
-    {
-    x = ox;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the second float.
- *
- * @param oy new value of the second float.
- */
-  public void set1(float oy)
-    {
-    y = oy;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the third float.
- *
- * @param oz new value of the third float.
- */
-  public void set2(float oz)
-    {
-    z = oz;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the fourth float.
- *
- * @param ow new value of the fourth float.
- */
-  public void set3(float ow)
-    {
-    w = ow;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the first float contained.
- *
- * @return The first float.
- */
-  public float get0()
-    {
-    return x;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the second float contained.
- *
- * @return The second float.
- */
-  public float get1()
-    {
-    return y;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the third float contained.
- *
- * @return The third float.
- */
-  public float get2()
-    {
-    return z;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the fourth float contained.
- *
- * @return The fourth float.
- */
-  public float get3()
-    {
-    return w;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 'Interpolation' between the single Point (i.e. always this very value) returned to the buffer.
- *
- * @param buffer Float buffer we will write the results to.
- * @param offset Offset in the buffer where to write the result.
- * @param time not used
- * @param step not used
- * @return <code>false</code>
- */
-  public boolean get(float[] buffer, int offset, long time, long step)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the first float.
+    */
+    fun set0(ox: Float) { x = ox }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oy new value of the second float.
+    */
+    fun set1(oy: Float) { y = oy }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oz new value of the third float.
+    */
+    fun set2(oz: Float) { z = oz }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ow new value of the fourth float.
+    */
+    fun set3(ow: Float) { w = ow }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The first float.
+    */
+    fun get0(): Float { return x }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The second float.
+    */
+    fun get1(): Float { return y }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The third float.
+    */
+    fun get2(): Float { return z }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The fourth float.
+    */
+    fun get3(): Float { return w }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** 'Interpolation' between the single Point (i.e. always this very value ) returned to the buffer.
+    *
+    * @param buffer Float buffer we will write the results to.
+    * @param offset Offset in the buffer where to write the result.
+    * @param time not used
+    * @param step not used
+    * @return `false`
+    */
+    override fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
     {
-    buffer[offset  ] = x;
-    buffer[offset+1] = y;
-    buffer[offset+2] = z;
-    buffer[offset+3] = w;
-    return false;
+        buffer[offset  ] = x
+        buffer[offset+1] = y
+        buffer[offset+2] = z
+        buffer[offset+3] = w
+        return false
     }
-  }
+}
diff --git a/src/main/java/org/distorted/library/type/Static5D.kt b/src/main/java/org/distorted/library/type/Static5D.kt
index 8d6d247..64ba513 100644
--- a/src/main/java/org/distorted/library/type/Static5D.kt
+++ b/src/main/java/org/distorted/library/type/Static5D.kt
@@ -1,4 +1,4 @@
-////////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 // Copyright 2016 Leszek Koltunski  leszek@koltunski.pl                                          //
 //                                                                                               //
 // This file is part of Distorted.                                                               //
@@ -18,212 +18,156 @@
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-package org.distorted.library.type;
+package org.distorted.library.type
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * A 5-dimensional data structure containing five floats. The floats have no particular meaning; 
+ * A 5-dimensional data structure containing five floats. The floats have no particular meaning;
  * when this data structure is used in Dynamics, we can think of it as a 5-dimensional Point
  * a few of which the Dynamic interpolates between.
  */
-
-public class Static5D extends Static implements Data5D
-  {
-  float x,y,z,w,v;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Constructor that initialises the value of the five floats to (vx,vy,vz,vw,vv).   
- *   
- * @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.
- * @param vv value of the fifth float.
- */ 
-  public Static5D(float vx, float vy, float vz, float vw, float vv)
-    {
-    super(5);
-    x = vx;
-    y = vy;
-    z = vz;
-    w = vw;
-    v = vv;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy constructor.
- */
-  public Static5D(Static5D sta)
+class Static5D : Static, Data5D
+{
+    var x: Float
+    var y: Float
+    var z: Float
+    var w: Float
+    var v: Float
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @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.
+    * @param vv value of the fifth float.
+    */
+    constructor(vx: Float, vy: Float, vz: Float, vw: Float, vv: Float) : super(5)
     {
-    super(5);
-    x = sta.x;
-    y = sta.y;
-    z = sta.z;
-    w = sta.w;
-    v = sta.v;
+        x = vx
+        y = vy
+        z = vz
+        w = vw
+        v = vv
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Reset the value of the floats to (vx,vy,vz,vw,vv).
- * 
- * @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
- * @param vv new value of the fifth float
- */
-  public void set(float vx, float vy, float vz, float vw, float vv)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy constructor.
+    */
+    constructor(sta: Static5D) : super(5)
     {
-    x = vx;
-    y = vy;
-    z = vz;
-    w = vw;
-    v = vv;
+        x = sta.x
+        y = sta.y
+        z = sta.z
+        w = sta.w
+        v = sta.v
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Copy a Static5D.
- */
-  public void set(Static5D s)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @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
+    * @param vv new value of the fifth float
+    */
+    fun set(vx: Float, vy: Float, vz: Float, vw: Float, vv: Float)
     {
-    x = s.x;
-    y = s.y;
-    z = s.z;
-    w = s.w;
-    v = s.v;
+        x = vx
+        y = vy
+        z = vz
+        w = vw
+        v = vv
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the first float.
- *
- * @param ox new value of the first float.
- */
-  public void set0(float ox)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** Copy a Static5D.
+    */
+    fun set(s: Static5D)
     {
-    x = ox;
+        x = s.x
+        y = s.y
+        z = s.z
+        w = s.w
+        v = s.v
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the second float.
- *
- * @param oy new value of the second float.
- */
-  public void set1(float oy)
-    {
-    y = oy;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the third float.
- *
- * @param oz new value of the third float.
- */
-  public void set2(float oz)
-    {
-    z = oz;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the fourth float.
- *
- * @param ow new value of the fourth float.
- */
-  public void set3(float ow)
-    {
-    w = ow;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Resets the value of the fifth float.
- *
- * @param ov new value of the fifth float.
- */
-  public void set4(float ov)
-    {
-    v = ov;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the first float contained.
- *
- * @return The first float.
- */
-  public float get0()
-    {
-    return x;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the second float contained.
- *
- * @return The second float.
- */
-  public float get1()
-    {
-    return y;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the third float contained.
- *
- * @return The third float.
- */
-  public float get2()
-    {
-    return z;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the fourth float contained.
- *
- * @return The fourth float.
- */
-  public float get3()
-    {
-    return w;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Return the value of the fifth float contained.
- * 
- * @return The fifth float.
- */
-  public float get4()
-    {
-    return v;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * 'Interpolation' between the single Point (i.e. always this very value) returned to the buffer.
- *
- * @param buffer Float buffer we will write the results to.
- * @param offset Offset in the buffer where to write the result.
- * @param time not used
- * @param step not used
- * @return <code>false</code>
- */
-  public boolean get(float[] buffer, int offset, long time, long step)
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ox new value of the first float.
+    */
+    fun set0(ox: Float) { x = ox }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oy new value of the second float.
+    */
+    fun set1(oy: Float) { y = oy }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param oz new value of the third float.
+    */
+    fun set2(oz: Float) { z = oz }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ow new value of the fourth float.
+    */
+    fun set3(ow: Float) { w = ow }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @param ov new value of the fifth float.
+    */
+    fun set4(ov: Float) { v = ov }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The first float.
+    */
+    fun get0(): Float { return x }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The second float.
+    */
+    fun get1(): Float { return y }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The third float.
+    */
+    fun get2(): Float { return z }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The fourth float.
+    */
+    fun get3(): Float { return w }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+    * @ return The fifth float.
+    */
+    fun get4(): Float { return v }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /** 'Interpolation' between the single Point (i.e. always this very value ) returned to the buffer.
+    *
+    * @param buffer Float buffer we will write the results to.
+    * @param offset Offset in the buffer where to write the result.
+    * @param time not used
+    * @param step not used
+    * @return `false`
+    */
+    override fun get(buffer: FloatArray, offset: Int, time: Long, step: Long): Boolean
     {
-    buffer[offset  ] = x;
-    buffer[offset+1] = y;
-    buffer[offset+2] = z;
-    buffer[offset+3] = w;
-    buffer[offset+4] = v;
-    return false;
+        buffer[offset  ] = x
+        buffer[offset+1] = y
+        buffer[offset+2] = z
+        buffer[offset+3] = w
+        buffer[offset+4] = v
+        return false
     }
-  }
+}
