commit e52efe179934da095b5026001f9c322fc7a4e740
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon May 20 01:31:57 2019 +0100

    Improve the Dynamic app.

diff --git a/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java b/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java
index 56c5fcf..4531ddb 100644
--- a/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java
+++ b/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java
@@ -46,6 +46,7 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
     private int mDim, mMode;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     protected void onCreate(Bundle savedState)
       {
@@ -87,6 +88,7 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
       ArrayAdapter<String> adapterMode = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, modes );
       adapterMode.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
       modeSpinner.setAdapter(adapterMode);
+      modeSpinner.setSelection(0);
 
       if( savedState==null )
         {
@@ -103,27 +105,34 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     protected void onResume() 
       {
       super.onResume();
       
-      GLSurfaceView view = findViewById(R.id.dynamicSurfaceView);
-      view.onResume();
+      GLSurfaceView v1 = findViewById(R.id.dynamicSurfaceView);
+      v1.onResume();
+      DynamicSpeedSurfaceView v2 = findViewById(R.id.dynamicSpeedSurfaceView);
+      v2.onResume();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     protected void onPause() 
       {
-      GLSurfaceView view = findViewById(R.id.dynamicSurfaceView);
-      view.onPause();
+      GLSurfaceView v1 = findViewById(R.id.dynamicSurfaceView);
+      v1.onPause();
+      DynamicSpeedSurfaceView v2 = findViewById(R.id.dynamicSpeedSurfaceView);
+      v2.onPause();
 
       DistortedLibrary.onPause();
       super.onPause();
       }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     public void onStop()
       {
@@ -131,6 +140,7 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     public void onDestroy()
       {  
@@ -138,6 +148,22 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
       super.onDestroy();
       }     
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void setNumRedPoints(int numPoints)
+      {
+      DynamicSpeedSurfaceView view = findViewById(R.id.dynamicSpeedSurfaceView);
+      view.setNumRedPoints(numPoints);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void addPoint(float x, float y)
+      {
+      DynamicSpeedSurfaceView view = findViewById(R.id.dynamicSpeedSurfaceView);
+      view.addPoint(x,y);
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void setDim(int dim)
@@ -151,8 +177,11 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
 
     public void setMode(int mode)
       {
-      DynamicSurfaceView view = findViewById(R.id.dynamicSurfaceView);
-      view.setMode(mode);
+      DynamicSurfaceView v1 = findViewById(R.id.dynamicSurfaceView);
+      v1.setMode(mode);
+      DynamicSpeedSurfaceView v2 = findViewById(R.id.dynamicSpeedSurfaceView);
+      v2.setMode(mode);
+
       mMode = mode;
       }
 
@@ -160,17 +189,21 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
 
     public void Start(View v)
       {
-      DynamicSurfaceView view = findViewById(R.id.dynamicSurfaceView);
-      view.startDynamic();
+      DynamicSpeedSurfaceView v2 = findViewById(R.id.dynamicSpeedSurfaceView);
+      v2.clearPoints();
+      DynamicSurfaceView v1 = findViewById(R.id.dynamicSurfaceView);
+      v1.startDynamic();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void Reset(View v)
       {
-      DynamicSurfaceView view = findViewById(R.id.dynamicSurfaceView);
-      view.resetPoints();
-      view.stopDynamic();
+      DynamicSurfaceView v1 = findViewById(R.id.dynamicSurfaceView);
+      v1.resetPoints();
+      v1.stopDynamic();
+      DynamicSpeedSurfaceView v2 = findViewById(R.id.dynamicSpeedSurfaceView);
+      v2.clearPoints();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/examples/dynamic/DynamicSpeedSurfaceView.java b/src/main/java/org/distorted/examples/dynamic/DynamicSpeedSurfaceView.java
new file mode 100644
index 0000000..ec25bcb
--- /dev/null
+++ b/src/main/java/org/distorted/examples/dynamic/DynamicSpeedSurfaceView.java
@@ -0,0 +1,322 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.dynamic;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import org.distorted.library.type.Dynamic;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class DynamicSpeedSurfaceView extends SurfaceView implements SurfaceHolder.Callback
+{
+    private static final int FRAME_INTERVAL = 70;
+    private static final int NUM_POINTS     = DynamicSurfaceView.NUM_POINTS;
+
+    private static boolean refreshScreen = true;
+    private GraphicsThread mThread;
+    private int mWidth, mHeight, mMargin;
+    private int mMode, mNumRedPoints, mPointSize;
+    private float mFontHeight;
+    private Paint mPaint;
+    private float[] mPoints = new float[2*NUM_POINTS];
+    private int mPosition;
+    private float mMultiplier;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+    private class GraphicsThread extends Thread
+      {
+      private final SurfaceHolder mSurfaceHolder;
+      private final DynamicSpeedSurfaceView mPicker;
+      private boolean mRun = false;
+
+      ///////////////////////////////////////////////////////////////////////////////////////
+
+      GraphicsThread(SurfaceHolder surfaceHolder, DynamicSpeedSurfaceView p)
+        {
+        mSurfaceHolder = surfaceHolder;
+        mPicker = p;
+        }
+
+      ///////////////////////////////////////////////////////////////////////////////////////
+
+      void setRunning(boolean run)
+        {
+        mRun = run;
+        }
+
+      ///////////////////////////////////////////////////////////////////////////////////////
+
+      public void run()
+        {
+        Canvas c;
+        long time;
+
+        while (mRun)
+          {
+          c = null;
+          time = 0;
+
+          if( refreshScreen )
+            {
+            refreshScreen=false;
+            time = System.currentTimeMillis();
+
+            try
+              {
+              c = mSurfaceHolder.lockCanvas(null);
+              synchronized (mSurfaceHolder) { mPicker.render(c); }
+              }
+            finally
+              {
+              if (c != null)  mSurfaceHolder.unlockCanvasAndPost(c);
+              }
+
+            time = System.currentTimeMillis() -time;
+            }
+
+          if( time<FRAME_INTERVAL )
+            {
+            try { Thread.sleep(FRAME_INTERVAL-time); }
+            catch(InterruptedException ex) {}
+            }
+          }
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public DynamicSpeedSurfaceView(Context context, AttributeSet attrs)
+      {
+      super(context,attrs);
+
+      mNumRedPoints = 0;
+      mPosition     = 0;
+
+      mPaint = new Paint();
+      mPaint.setAntiAlias(true);
+      mPaint.setFakeBoldText(true);
+      mPaint.setStyle(Paint.Style.FILL);
+
+      clearPoints();
+
+      getHolder().addCallback(this);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void stopThread()
+      {
+      if( mThread!=null )
+        {
+        boolean retry = true;
+        mThread.setRunning(false);
+
+        while (retry)
+          {
+          try
+            {
+            mThread.join();
+            retry = false;
+            }
+          catch (InterruptedException e) { android.util.Log.e( "DynamicSpeed", "Joining thread interrupted!"); }
+          }
+
+        mThread=null;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void render(Canvas c)
+      {
+      if( c!=null )
+        {
+        mPaint.setColor(0xff007d00);
+        c.drawRect(0, 0, mWidth, mHeight, mPaint);
+        mPaint.setColor(0xff000000);
+        c.drawText( "Speed", mWidth/2, mMargin, mPaint);
+        drawAxis(c);
+        drawSpeedGraph(c);
+        drawRedPoints(c);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void drawAxis(Canvas c)
+      {
+      mPaint.setColor(0xff000000);
+
+      c.drawLine( mMargin, mHeight-mMargin, mWidth-mMargin, mHeight-mMargin, mPaint);
+      c.drawLine( mMargin, mHeight-mMargin,        mMargin,         mMargin, mPaint);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void drawRedPoints(Canvas c)
+      {
+      if( mNumRedPoints==1 )
+        {
+        drawRedPoint(c,"0", mMargin, mHeight-mMargin);
+        }
+      else if( mNumRedPoints>1 )
+        {
+        int len = mMode== Dynamic.MODE_LOOP ? mNumRedPoints+1 : mNumRedPoints;
+        String label;
+        float x;
+
+        for(int curr=0; curr<len; curr++)
+          {
+          label = curr==mNumRedPoints ? "0" : curr+"";
+          x = mMargin + curr*((float)(mWidth-2*mMargin))/(len-1);
+          drawRedPoint(c,label, x, mHeight-mMargin);
+          }
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void drawRedPoint(Canvas c, String label, float width, float height)
+      {
+      mPaint.setColor(0xffff0000);
+      c.drawCircle( width, height, mPointSize, mPaint);
+      mPaint.setColor(0xffffffff);
+      c.drawText(label, width,height-mFontHeight, mPaint);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void drawSpeedGraph(Canvas c)
+      {
+      mPaint.setColor(0xffffffff);
+      float y, highiest=0.0f;
+
+      for(int i=0; i<NUM_POINTS; i++)
+        {
+        y = mPoints[2*i+1];
+        c.drawCircle( mMargin+mPoints[2*i]*(mWidth-2*mMargin), mHeight-mMargin-mMultiplier*y , mPointSize*0.3f, mPaint );
+
+        if( y>highiest ) highiest = y;
+        }
+
+      mMultiplier = (mHeight-2*mMargin)/highiest;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void setMode(int mode)
+      {
+      mMode = mode;
+      refreshScreen = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void clearPoints()
+      {
+      for(int i=0; i<2*NUM_POINTS; i++)
+         {
+         mPoints[i] = -10.0f;
+         }
+      refreshScreen = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void addPoint(float x, float y)
+      {
+      mPoints[2*mPosition  ] =x;
+      mPoints[2*mPosition+1] =y;
+
+      if ( ++mPosition >= NUM_POINTS ) mPosition=0;
+
+      refreshScreen = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void setNumRedPoints(int numRedPoints)
+      {
+      mNumRedPoints = numRedPoints;
+      refreshScreen = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void onPause()
+      {
+      if( mThread!=null ) mThread.setRunning(false);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void onResume()
+      {
+      if( mThread!=null ) mThread.setRunning(true);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
+      {
+      mWidth = width;
+      mHeight= height;
+      mMargin= height/10;
+
+      mPointSize = (mWidth+mHeight)/80;
+      mPaint.setTextSize((mWidth+mHeight)/60);
+      mPaint.setTextAlign(Paint.Align.CENTER);
+
+      final Rect textBounds = new Rect();
+      String text = "1";
+      mPaint.getTextBounds(text, 0, text.length(), textBounds);
+      mFontHeight = textBounds.exactCenterY();
+
+      refreshScreen = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder)
+      {
+      mThread = new GraphicsThread(getHolder(), this);
+      mThread.setRunning(true);
+      mThread.start();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder)
+      {
+      stopThread();
+      }
+}
+
diff --git a/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java b/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java
index 2830d53..cc4b378 100644
--- a/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java
+++ b/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java
@@ -38,7 +38,9 @@ import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static2D;
 import org.distorted.library.type.Static3D;
 
-///////////////////////////////////////////////////////////////////
+import java.lang.ref.WeakReference;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class DynamicSurfaceView extends GLSurfaceView
     {
@@ -47,9 +49,11 @@ public class DynamicSurfaceView extends GLSurfaceView
     public static final int DIM_3DXY = 2; 
     public static final int DIM_3DXZ = 3; 
 
-    private static final int NUM_POINTS = 250;
+    static final int NUM_POINTS = 250;
     private static final Object lock = new Object();
 
+    private WeakReference<DynamicActivity> mAct;
+
     private static int halfScreenHeight=0;
     private static int halfScreenWidth =0;
 
@@ -81,12 +85,15 @@ public class DynamicSurfaceView extends GLSurfaceView
     private float[] mPoints = new float[3*NUM_POINTS];
     private boolean mRunning;
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
     
     public DynamicSurfaceView(Context context, AttributeSet attrs)
       {
       super(context, attrs);
-      
+
+      DynamicActivity act = (DynamicActivity)context;
+      mAct = new WeakReference<>(act);
+
       mPaint = new Paint();
       mPaint.setStyle(Style.FILL);
       mPaint.setAntiAlias(true);
@@ -104,6 +111,8 @@ public class DynamicSurfaceView extends GLSurfaceView
 
       mRunning = false;
 
+      clearPoints();
+
       di1D = new Dynamic1D(mDuration,mCount);
       p1N  = new Static1D(mNoise0);
       di2D = new Dynamic2D(mDuration,mCount);
@@ -148,21 +157,21 @@ public class DynamicSurfaceView extends GLSurfaceView
       clearPoints();
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public static void setHalfWidth(int hw)
       {
       halfScreenWidth = hw;
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public static void setHalfHeight(int hh)
       {
       halfScreenHeight = hh;
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void setMode(int mode)
       {
@@ -171,7 +180,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di3D.setMode(mode);
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void setDuration(int duration)
       {
@@ -182,7 +191,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di3D.setDuration(duration);
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void setCount(float count)
       {
@@ -193,7 +202,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di3D.setCount(count);
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void setNoise(float noise0, float noise1, float noise2)
       {
@@ -210,7 +219,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di3D.setNoise(p3N);
       }
     
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void setDimension(int dim)
       {
@@ -225,7 +234,7 @@ public class DynamicSurfaceView extends GLSurfaceView
         }
       }
     
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
     
     public void drawCurve(Canvas c, long time)
       {
@@ -262,17 +271,17 @@ public class DynamicSurfaceView extends GLSurfaceView
       mLastTime = time;
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void clearPoints()
       {
       for(int i=0; i<3*NUM_POINTS; i++)
          {
-         mPoints[i] = -10.0f;
+         mPoints[i] = -100000.0f;
          }
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void resetPoints()
       {
@@ -287,10 +296,12 @@ public class DynamicSurfaceView extends GLSurfaceView
           case DIM_3DXY:
           case DIM_3DXZ: di3D.removeAll(); break;
           }
+
+        mAct.get().setNumRedPoints(0);
         }
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void startDynamic()
       {
@@ -304,14 +315,14 @@ public class DynamicSurfaceView extends GLSurfaceView
       di3D.resetToBeginning();
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void stopDynamic()
       {
       mRunning = false;
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawHorizontalAxis(Canvas c, String label)
       {
@@ -322,7 +333,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       }
 
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawVerticalAxis(Canvas c, String label)
       {
@@ -332,7 +343,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       c.drawText(label, halfScreenWidth + mSizeT,                mSizeT , mPaint);
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawPath(Canvas c, Dynamic dyn, int index, long time)
       {
@@ -353,6 +364,8 @@ public class DynamicSurfaceView extends GLSurfaceView
             {
             stopDynamic();
             }
+
+          addNewSpeedPoint(time);
           }
 
         for(int i=0; i<NUM_POINTS; i++)
@@ -366,7 +379,7 @@ public class DynamicSurfaceView extends GLSurfaceView
         }
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawRedPoints1D(Canvas c)
       {
@@ -379,7 +392,7 @@ public class DynamicSurfaceView extends GLSurfaceView
         }
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawRedPoints2D(Canvas c)
       {
@@ -392,7 +405,7 @@ public class DynamicSurfaceView extends GLSurfaceView
         }
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawRedPoints3D(Canvas c)
       {
@@ -405,7 +418,7 @@ public class DynamicSurfaceView extends GLSurfaceView
         }
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawRedPoint(Canvas c, String label, float width, float height)
       {
@@ -415,7 +428,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       c.drawText(label, width,height-mFontHeight, mPaint);
       }
 
-///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void addNewPoint(int x, int y)
       {
@@ -442,6 +455,7 @@ public class DynamicSurfaceView extends GLSurfaceView
                        synchronized(lock)
                          {
                          di1D.add(new Static1D(x));
+                         mAct.get().setNumRedPoints(len+1);
                          }
                        }
                      break;
@@ -464,6 +478,7 @@ public class DynamicSurfaceView extends GLSurfaceView
                        synchronized(lock)
                          {
                          di2D.add(new Static2D(x,y));
+                         mAct.get().setNumRedPoints(len+1);
                          }
                        }
                      break;
@@ -497,22 +512,38 @@ public class DynamicSurfaceView extends GLSurfaceView
                      { 
                      synchronized(lock)
                        {
-                       if( currentDim==DIM_3DXY )
-                         {
-                         di3D.add(new Static3D(x,y, halfScreenHeight));
-                         }
-                       if( currentDim==DIM_3DXZ )
-                         {
-                         di3D.add(new Static3D(x, halfScreenHeight,y));
-                         }
+                       if( currentDim==DIM_3DXY ) di3D.add(new Static3D(x,y, halfScreenHeight));
+                       if( currentDim==DIM_3DXZ ) di3D.add(new Static3D(x, halfScreenHeight,y));
+                       mAct.get().setNumRedPoints(len+1);
                        }
                      }
                    break; 
         }
       }
     
-///////////////////////////////////////////////////////////////////
-    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void addNewSpeedPoint(long time)
+      {
+      int prev = mPosition-1;
+      if( prev<0 ) prev = NUM_POINTS-1;
+
+      float xdiff = mPoints[3*prev  ]-mPoints[3*mPosition  ];
+      float ydiff = mPoints[3*prev+1]-mPoints[3*mPosition+1];
+      float zdiff = mPoints[3*prev+2]-mPoints[3*mPosition+2];
+
+      float dist = (float)Math.sqrt( xdiff*xdiff + ydiff*ydiff + zdiff*zdiff );
+      float speed= mDiffTime<=0 ? 0: dist / mDiffTime;
+      float timepoint = ((float)(time-mStartTime))/mDuration;
+
+      if( dist<1000.0f )   // otherwise this is a very first call; do not send it!
+        {
+        mAct.get().addPoint( timepoint - (int)timepoint, speed );
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
     @Override
     public boolean onTouchEvent(MotionEvent event)
       {
@@ -551,6 +582,4 @@ public class DynamicSurfaceView extends GLSurfaceView
             
       return true;
       }
- 
-///////////////////////////////////////////////////////////////////
   }
diff --git a/src/main/res/layout/dynamicslayout.xml b/src/main/res/layout/dynamicslayout.xml
index b769448..401945a 100644
--- a/src/main/res/layout/dynamicslayout.xml
+++ b/src/main/res/layout/dynamicslayout.xml
@@ -140,7 +140,13 @@
         android:id="@+id/dynamicSurfaceView"
         android:layout_width="fill_parent"
         android:layout_height="0dp"
-        android:layout_weight="1" />
+        android:layout_weight="0.8" />
+
+    <org.distorted.examples.dynamic.DynamicSpeedSurfaceView
+        android:id="@+id/dynamicSpeedSurfaceView"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="0.2" />
 
     <LinearLayout
         android:orientation="horizontal"
