commit f20265a7cfbad73af3325263802bb20734de75ee
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Dec 18 21:33:09 2019 +0000

    Dynamics App: fix moving Quat Points
    Library: remove negating the Quat Points in the DynamicQuat in order to always go the shortest route.

diff --git a/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java b/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java
index 421e55d..171140c 100644
--- a/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java
+++ b/src/main/java/org/distorted/examples/dynamic/DynamicActivity.java
@@ -77,7 +77,7 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
 
       Spinner dimensionSpinner  = findViewById(R.id.dynamicSpinnerDimension);
       dimensionSpinner.setOnItemSelectedListener(this);
-      String[] dimensions = { "Dimension 1" , "Dimension 2" , "Dimension 3 (XY)" , "Dimension 3 (XZ)" , "Dimension 4 (XY)" , "Dimension 4 (ZW)" };
+      String[] dimensions = { "Dimension 1" , "Dimension 2" , "Dimension 3 (XY)" , "Dimension 3 (XZ)" , "Dimension 4 (XY)" , "Dimension 4 (ZW)" , "Quaternion XY" , "Quaternion ZW" };
 
       ArrayAdapter<String> adapterDim = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, dimensions );
       adapterDim.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -232,6 +232,8 @@ public class DynamicActivity extends Activity implements OnSeekBarChangeListener
           case 3: setDim(DynamicSurfaceView.DIM_3DXZ); break;
           case 4: setDim(DynamicSurfaceView.DIM_4DXY); break;
           case 5: setDim(DynamicSurfaceView.DIM_4DZW); break;
+          case 6: setDim(DynamicSurfaceView.DIM_Q_XY); break;
+          case 7: setDim(DynamicSurfaceView.DIM_Q_ZW); break;
           }
         }
       else if( spinnerID == R.id.dynamicSpinnerMode )
diff --git a/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java b/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java
index fb028ca..58e884a 100644
--- a/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java
+++ b/src/main/java/org/distorted/examples/dynamic/DynamicSurfaceView.java
@@ -35,6 +35,7 @@ import org.distorted.library.type.Dynamic1D;
 import org.distorted.library.type.Dynamic2D;
 import org.distorted.library.type.Dynamic3D;
 import org.distorted.library.type.Dynamic4D;
+import org.distorted.library.type.DynamicQuat;
 import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static2D;
 import org.distorted.library.type.Static3D;
@@ -52,8 +53,11 @@ public class DynamicSurfaceView extends GLSurfaceView
     public static final int DIM_3DXZ = 3; 
     public static final int DIM_4DXY = 4;
     public static final int DIM_4DZW = 5;
+    public static final int DIM_Q_XY = 6;
+    public static final int DIM_Q_ZW = 7;
 
     private static final int MAX_DIM = 4;
+    private static final float QUAT_QUOT = 0.9f;
 
     static final int NUM_POINTS = 250;
     private static final Object lock = new Object();
@@ -63,10 +67,11 @@ public class DynamicSurfaceView extends GLSurfaceView
     private static int halfScreenHeight=0;
     private static int halfScreenWidth =0;
 
-    private Dynamic1D di1D;
-    private Dynamic2D di2D;
-    private Dynamic3D di3D;
-    private Dynamic4D di4D;
+    private Dynamic1D   di1D;
+    private Dynamic2D   di2D;
+    private Dynamic3D   di3D;
+    private Dynamic4D   di4D;
+    private DynamicQuat diQu;
     
     private Paint mPaint;
     private int mMoving;
@@ -85,11 +90,13 @@ public class DynamicSurfaceView extends GLSurfaceView
     private Static2D p2D;
     private Static3D p3D;
     private Static4D p4D;
+    private Static4D pQD;
 
     private Static1D p1N;
     private Static2D p2N;
     private Static3D p3N;
     private Static4D p4N;
+    private Static4D pQN;
 
     private float[] mPoints = new float[MAX_DIM*NUM_POINTS];
     private boolean mRunning;
@@ -128,11 +135,14 @@ public class DynamicSurfaceView extends GLSurfaceView
       p3N  = new Static3D(mNoise[0],mNoise[1],mNoise[2]);
       di4D = new Dynamic4D(mDuration,mCount);
       p4N  = new Static4D(mNoise[0],mNoise[1],mNoise[2],mNoise[3]);
+      diQu = new DynamicQuat(mDuration,mCount);
+      pQN  = new Static4D(mNoise[0],mNoise[1],mNoise[2],mNoise[3]);
 
       di1D.setAccessType(Dynamic.ACCESS_TYPE_SEQUENTIAL);
       di2D.setAccessType(Dynamic.ACCESS_TYPE_SEQUENTIAL);
       di3D.setAccessType(Dynamic.ACCESS_TYPE_SEQUENTIAL);
       di4D.setAccessType(Dynamic.ACCESS_TYPE_SEQUENTIAL);
+      diQu.setAccessType(Dynamic.ACCESS_TYPE_SEQUENTIAL);
 
       if(!isInEditMode())
         {
@@ -189,6 +199,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di2D.setMode(mode);
       di3D.setMode(mode);
       di4D.setMode(mode);
+      diQu.setMode(mode);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -201,6 +212,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di2D.setDuration(duration);
       di3D.setDuration(duration);
       di4D.setDuration(duration);
+      diQu.setDuration(duration);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -213,6 +225,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di2D.setCount(count);
       di3D.setCount(count);
       di4D.setCount(count);
+      diQu.setCount(count);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -223,9 +236,11 @@ public class DynamicSurfaceView extends GLSurfaceView
       di2D.setConvexity(convexity);
       di3D.setConvexity(convexity);
       di4D.setConvexity(convexity);
+      diQu.setConvexity(convexity);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// DynamicQuat does not support noise
 
     public void setNoise(float noise0, float noise1, float noise2, float noise3)
       {
@@ -252,7 +267,8 @@ public class DynamicSurfaceView extends GLSurfaceView
       if( currentDim != dim )
         {
         if( !(currentDim==DIM_3DXY && dim==DIM_3DXZ) && !(currentDim==DIM_3DXZ && dim==DIM_3DXY) &&
-            !(currentDim==DIM_4DXY && dim==DIM_4DZW) && !(currentDim==DIM_4DZW && dim==DIM_4DXY)  )
+            !(currentDim==DIM_4DXY && dim==DIM_4DZW) && !(currentDim==DIM_4DZW && dim==DIM_4DXY) &&
+            !(currentDim==DIM_Q_XY && dim==DIM_Q_ZW) && !(currentDim==DIM_Q_ZW && dim==DIM_Q_XY)  )
           {
           resetPoints();
           }
@@ -307,6 +323,16 @@ public class DynamicSurfaceView extends GLSurfaceView
                          drawPath(c,di4D,2,3,time);
                          drawRedPoints4D(c);
                          break;
+          case DIM_Q_XY: drawHorizontalAxis(c,"x");
+                         drawVerticalAxis  (c,"y");
+                         drawPath(c,diQu,0,1,time);
+                         drawRedPointsQu(c);
+                         break;
+          case DIM_Q_ZW: drawHorizontalAxis(c,"z");
+                         drawVerticalAxis  (c,"w");
+                         drawPath(c,diQu,2,3,time);
+                         drawRedPointsQu(c);
+                         break;
           }
         }
 
@@ -339,6 +365,8 @@ public class DynamicSurfaceView extends GLSurfaceView
           case DIM_3DXZ: di3D.removeAll(); break;
           case DIM_4DXY:
           case DIM_4DZW: di4D.removeAll(); break;
+          case DIM_Q_XY:
+          case DIM_Q_ZW: diQu.removeAll(); break;
           }
 
         DynamicActivity act = mAct.get();
@@ -360,6 +388,7 @@ public class DynamicSurfaceView extends GLSurfaceView
       di2D.resetToBeginning();
       di3D.resetToBeginning();
       di4D.resetToBeginning();
+      diQu.resetToBeginning();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -415,13 +444,31 @@ public class DynamicSurfaceView extends GLSurfaceView
           addNewSpeedPoint(time);
           }
 
-        for(int i=0; i<NUM_POINTS; i++)
+        if( currentDim!=DIM_Q_XY && currentDim!=DIM_Q_ZW )
+          {
+          for(int i=0; i<NUM_POINTS; i++)
+            {
+            int color = i<=mPosition ? 0xff - (mPosition           -i)*0xff/(NUM_POINTS-1)
+                                     : 0xff - (mPosition+NUM_POINTS-i)*0xff/(NUM_POINTS-1);
+
+            mPaint.setColor( 0xffffff + ((color&0xff)<<24) );
+            c.drawCircle(mPoints[MAX_DIM*i+indexH], mPoints[MAX_DIM*i+indexW] , mSize1, mPaint );
+            }
+          }
+        else
           {
-          int color = i<=mPosition ? 0xff - (mPosition           -i)*0xff/(NUM_POINTS-1)
-                                   : 0xff - (mPosition+NUM_POINTS-i)*0xff/(NUM_POINTS-1);
+          float x,y,min = QUAT_QUOT* (halfScreenWidth<halfScreenHeight ? halfScreenWidth:halfScreenHeight );
 
-          mPaint.setColor( 0xffffff + ((color&0xff)<<24) );
-          c.drawCircle(mPoints[MAX_DIM*i+indexH], mPoints[MAX_DIM*i+indexW] , mSize1, mPaint );
+          for(int i=0; i<NUM_POINTS; i++)
+            {
+            int color = i<=mPosition ? 0xff - (mPosition           -i)*0xff/(NUM_POINTS-1)
+                                     : 0xff - (mPosition+NUM_POINTS-i)*0xff/(NUM_POINTS-1);
+
+            mPaint.setColor( 0xffffff + ((color&0xff)<<24) );
+            x = mPoints[MAX_DIM*i+indexH]*min + halfScreenWidth;
+            y = mPoints[MAX_DIM*i+indexW]*min + halfScreenHeight;
+            c.drawCircle( x, y, mSize1, mPaint );
+            }
           }
         }
       }
@@ -480,6 +527,32 @@ public class DynamicSurfaceView extends GLSurfaceView
         }
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void drawRedPointsQu(Canvas c)
+      {
+      int len = diQu.getNumPoints();
+      float x,y, min = QUAT_QUOT* (halfScreenWidth<halfScreenHeight ? halfScreenWidth:halfScreenHeight );
+
+      for(int curr=0; curr<len; curr++)
+        {
+        pQD = diQu.getPoint(curr);
+
+        if( currentDim==DIM_Q_XY )
+          {
+          x = pQD.get1()*min + halfScreenWidth;
+          y = pQD.get2()*min + halfScreenHeight;
+          }
+        else
+          {
+          x = pQD.get3()*min + halfScreenWidth;
+          y = pQD.get4()*min + halfScreenHeight;
+          }
+
+        drawRedPoint(c,curr+"", x,y);
+        }
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void drawRedPoint(Canvas c, String label, float width, float height)
@@ -492,7 +565,7 @@ public class DynamicSurfaceView extends GLSurfaceView
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void addNewPoint(int x, int y)
+    private void addNewPoint(float x, float y)
       {
       float gx,gy,gz,gw;
       int len;
@@ -622,9 +695,70 @@ public class DynamicSurfaceView extends GLSurfaceView
                           }
                         }
                       break;
+        case DIM_Q_XY:
+        case DIM_Q_ZW:len = diQu.getNumPoints();
+                      float min = QUAT_QUOT* (halfScreenWidth<halfScreenHeight ? halfScreenWidth:halfScreenHeight );
+
+                      for(int g=0; g<len; g++)
+                        {
+                        pQD = diQu.getPoint(g);
+
+                        if( currentDim==DIM_Q_XY )
+                          {
+                          gx = pQD.get1()*min + halfScreenWidth;
+                          gy = pQD.get2()*min + halfScreenHeight;
+
+                          if( (x-gx)*(x-gx) + (y-gy)*(y-gy) < minDist )
+                            {
+                            mMoving = g;
+                            break;
+                            }
+                          }
+                        if( currentDim==DIM_Q_ZW )
+                          {
+                          gz = pQD.get3()*min + halfScreenWidth;
+                          gw = pQD.get4()*min + halfScreenHeight;
+
+                          if( (x-gz)*(x-gz) + (y-gw)*(y-gw) < minDist )
+                            {
+                            mMoving = g;
+                            break;
+                            }
+                          }
+                        }
+
+                      if( mMoving <0 )
+                        {
+                        float z,w;
+                        x = (x - halfScreenWidth ) / min;
+                        y = (y - halfScreenHeight) / min;
+                        float len1 = x*x + y*y;
+
+                        if( len1>= 1.0f )
+                          {
+                          float A = (float)Math.sqrt(len1);
+                          x = x/A;
+                          y = y/A;
+                          z = 0.0f;
+                          w = 0.0f;
+                          }
+                        else
+                          {
+                          z = (float)Math.sqrt(1-len1);
+                          w = 0.0f;
+                          }
+
+                        synchronized(lock)
+                          {
+                          if( currentDim==DIM_Q_XY ) diQu.add(new Static4D(x,y,z,w));
+                          if( currentDim==DIM_Q_ZW ) diQu.add(new Static4D(z,w,x,y));
+                          mAct.get().setNumRedPoints(len+1);
+                          }
+                        }
+                      break;
         }
       }
-    
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private void addNewSpeedPoint(long time)
@@ -653,20 +787,20 @@ public class DynamicSurfaceView extends GLSurfaceView
     public boolean onTouchEvent(MotionEvent event)
       {
       int action = event.getAction();
-      int xDown, yDown;
+      float xDown, yDown;
 
       switch(action)
         {
-        case MotionEvent.ACTION_DOWN: xDown = (int)event.getX();
-                                      yDown = (int)event.getY();
-                                      
+        case MotionEvent.ACTION_DOWN: xDown = event.getX();
+                                      yDown = event.getY();
+
                                       addNewPoint(xDown,yDown);
-                                    
+
                                       break;
         case MotionEvent.ACTION_MOVE: if( mMoving >=0 )
                                         {
-                                        xDown = (int)event.getX();
-                                        yDown = (int)event.getY();
+                                        xDown = event.getX();
+                                        yDown = event.getY();
                                         
                                         switch(currentDim)
                                           {
@@ -682,6 +816,88 @@ public class DynamicSurfaceView extends GLSurfaceView
                                                          break;
                                           case DIM_4DZW: di4D.setPoint(mMoving, (int)di4D.getPoint(mMoving).get1(), (int)di4D.getPoint(mMoving).get2(), xDown, yDown);
                                                          break;
+                                          case DIM_Q_XY: float min1 = QUAT_QUOT* (halfScreenWidth<halfScreenHeight ? halfScreenWidth:halfScreenHeight );
+                                                         float x1 = (xDown - halfScreenWidth ) / min1;
+                                                         float y1 = (yDown - halfScreenHeight) / min1;
+                                                         float z1 = diQu.getPoint(mMoving).get3();
+                                                         float w1 = diQu.getPoint(mMoving).get4();
+                                                         float len1 = x1*x1 + y1*y1;
+
+                                                         if( len1 <= 1.0f )
+                                                           {
+                                                           float len2 = z1*z1 + w1*w1;
+
+                                                           if( len2 == 0 )
+                                                             {
+                                                             if( len1 == 0 )
+                                                               {
+                                                               w1 = 1.0f;
+                                                               }
+                                                             else
+                                                               {
+                                                               float B = (float)Math.sqrt(len1);
+                                                               x1 = x1/B;
+                                                               y1 = y1/B;
+                                                               }
+                                                             }
+                                                           else
+                                                             {
+                                                             float A = (float)Math.sqrt((1.0f - len1)/len2);
+                                                             z1 = A*z1;
+                                                             w1 = A*w1;
+                                                             }
+                                                           }
+                                                         else
+                                                           {
+                                                           float B = (float)Math.sqrt(len1);
+                                                           x1 = x1/B;
+                                                           y1 = y1/B;
+                                                           z1 = 0.0f;
+                                                           w1 = 0.0f;
+                                                           }
+                                                         diQu.setPoint(mMoving, x1,y1,z1,w1);
+                                                         break;
+                                          case DIM_Q_ZW: float min2 = QUAT_QUOT* (halfScreenWidth<halfScreenHeight ? halfScreenWidth:halfScreenHeight );
+                                                         float x2 = diQu.getPoint(mMoving).get1();
+                                                         float y2 = diQu.getPoint(mMoving).get2();
+                                                         float z2 = (xDown - halfScreenWidth ) / min2;
+                                                         float w2 = (yDown - halfScreenHeight) / min2;
+                                                         float len3 = z2*z2 + w2*w2;
+
+                                                         if( len3 <= 1.0f )
+                                                           {
+                                                           float len4 = x2*x2 + y2*y2;
+
+                                                           if( len4 == 0 )
+                                                             {
+                                                             if( len3 == 0 )
+                                                               {
+                                                               w2 = 1.0f;
+                                                               }
+                                                             else
+                                                               {
+                                                               float B = (float)Math.sqrt(len3);
+                                                               z2 = z2/B;
+                                                               w2 = w2/B;
+                                                               }
+                                                             }
+                                                           else
+                                                             {
+                                                             float A = (float)Math.sqrt((1.0f - len3)/len4);
+                                                             x2 = A*x2;
+                                                             y2 = A*y2;
+                                                             }
+                                                           }
+                                                         else
+                                                           {
+                                                           float B = (float)Math.sqrt(len3);
+                                                           x2 = 0.0f;
+                                                           y2 = 0.0f;
+                                                           z2 = z2/B;
+                                                           w2 = w2/B;
+                                                           }
+                                                         diQu.setPoint(mMoving, x2,y2,z2,w2);
+                                                         break;
                                           }
                                         }                           
                                       break;
