commit 7c8012eea4dbd8de5374b2191da02d495d6f7f18
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Tue Nov 15 11:22:32 2016 +0000

    Matrix3D: implement quaternion effect

diff --git a/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java b/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java
index 91b6776..63de511 100644
--- a/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java
+++ b/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java
@@ -83,16 +83,16 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
       {
       case ROTATE           : mId = object.rotate    (mDyn4, mCenterDyn); break;
       case QUATERNION       : mId = object.quaternion(mDyn4, mCenterDyn); break;
-      case MOVE             : mId = object.move      (mDyn3)             ; break;
-      case SCALE            : mId = object.scale     (mDyn3)             ; break;
+      case MOVE             : mId = object.move      (mDyn3)            ; break;
+      case SCALE            : mId = object.scale     (mDyn3)            ; break;
       case SHEAR            : mId = object.shear     (mDyn3, mCenterDyn); break;
 
-      case DISTORT: mId = object.distort(mDyn3, mCenterDyn, mRegionDyn); break;
-      case DEFORM : mId = object.deform (mDyn3, mCenterDyn            ); break;
-      case SINK   : mId = object.sink   (mDyn1, mCenterDyn, mRegionDyn); break;
-      case PINCH  : mId = object.pinch  (mDyn2, mCenterDyn, mRegionDyn); break;
-      case SWIRL  : mId = object.swirl  (mDyn1, mCenterDyn, mRegionDyn); break;
-      case WAVE   : mId = object.wave   (mDyn5, mCenterDyn, mRegionDyn); break;
+      case DISTORT          : mId = object.distort   (mDyn3, mCenterDyn, mRegionDyn); break;
+      case DEFORM           : mId = object.deform    (mDyn3, mCenterDyn            ); break;
+      case SINK             : mId = object.sink      (mDyn1, mCenterDyn, mRegionDyn); break;
+      case PINCH            : mId = object.pinch     (mDyn2, mCenterDyn, mRegionDyn); break;
+      case SWIRL            : mId = object.swirl     (mDyn1, mCenterDyn, mRegionDyn); break;
+      case WAVE             : mId = object.wave      (mDyn5, mCenterDyn, mRegionDyn); break;
 
       case ALPHA            : mId = object.alpha     (mDyn1,        mRegionDyn, false); break;
       case SMOOTH_ALPHA     : mId = object.alpha     (mDyn1,        mRegionDyn, true ); break;
@@ -122,7 +122,14 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
                               float rz = (mInter[3]-50)/ 50.0f;
                               mSta4.set(an,rx,ry,rz);
                               break;
-      case QUATERNION       :
+      case QUATERNION       : float qx = (mInter[0]-50)/ 50.0f;
+                              float qy = (mInter[1]-50)/ 50.0f;
+                              float qz = (mInter[2]-50)/ 50.0f;
+                              float qa = (mInter[3]-50)*3.1415f/50;
+                              float cosA = (float)Math.cos(qa/2);
+                              float len = (float)Math.sqrt(qx*qx+qy*qy+qz*qz);
+                              float sinAnorm = (float)Math.sin(qa/2)/len;
+                              mSta4.set(sinAnorm*qx,sinAnorm*qy,sinAnorm*qz, cosA);
                               break;
       case MOVE             : float sw = mAct.get().getScreenWidth()/50.0f;
                               float sh = mAct.get().getScreenWidth()/50.0f;
@@ -141,6 +148,7 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
                               float zsh = (mInter[2]-50)/25.0f;
                               mSta3.set(xsh,ysh,zsh);
                               break;
+
       case DISTORT          :
       case DEFORM           : float ld = mAct.get().getWidth()/50.0f;
                               float xd = (mInter[0]-50)*ld;
@@ -197,7 +205,7 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
       case 1: mInter[0] = 50;
       }
 
-    if( mName==EffectNames.ROTATE ) mInter[1]= 100;
+    if( mName==EffectNames.ROTATE || mName==EffectNames.QUATERNION ) mInter[1]= 100;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -357,7 +365,7 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
                mSta3 = new Static3D(0,0,0);
                mDyn3.add(mSta3);
                break;
-      case 4 : if( mName == EffectNames.QUATERNION || mName == EffectNames.ROTATE )
+      case 4 : if( mName == EffectNames.ROTATE || mName == EffectNames.QUATERNION )
                  {
                  mDyn4 = new Dynamic4D();
                  mSta4 = new Static4D(0,0,0,0);
diff --git a/src/main/java/org/distorted/examples/matrix3d/Matrix3DEffect.java b/src/main/java/org/distorted/examples/matrix3d/Matrix3DEffect.java
index 6953eff..9a23d68 100644
--- a/src/main/java/org/distorted/examples/matrix3d/Matrix3DEffect.java
+++ b/src/main/java/org/distorted/examples/matrix3d/Matrix3DEffect.java
@@ -83,15 +83,16 @@ class Matrix3DEffect implements SeekBar.OnSeekBarChangeListener
       {
       case ROTATE           : mId = object.rotate    (mDyn4, mCenterDyn); break;
       case QUATERNION       : mId = object.quaternion(mDyn4, mCenterDyn); break;
-      case MOVE             : mId = object.move      (mDyn3)             ; break;
-      case SCALE            : mId = object.scale     (mDyn3)             ; break;
+      case MOVE             : mId = object.move      (mDyn3)            ; break;
+      case SCALE            : mId = object.scale     (mDyn3)            ; break;
       case SHEAR            : mId = object.shear     (mDyn3, mCenterDyn); break;
 
-      case DISTORT: mId = object.distort(mDyn3, mCenterDyn, mRegionDyn); break;
-      case DEFORM : mId = object.deform (mDyn3, mCenterDyn            ); break;
-      case SINK   : mId = object.sink   (mDyn1, mCenterDyn, mRegionDyn); break;
-      case SWIRL  : mId = object.swirl  (mDyn1, mCenterDyn, mRegionDyn); break;
-      case WAVE   : mId = object.wave   (mDyn5, mCenterDyn, mRegionDyn); break;
+      case DISTORT          : mId = object.distort   (mDyn3, mCenterDyn, mRegionDyn); break;
+      case DEFORM           : mId = object.deform    (mDyn3, mCenterDyn            ); break;
+      case SINK             : mId = object.sink      (mDyn1, mCenterDyn, mRegionDyn); break;
+      case PINCH            : mId = object.pinch     (mDyn2, mCenterDyn, mRegionDyn); break;
+      case SWIRL            : mId = object.swirl     (mDyn1, mCenterDyn, mRegionDyn); break;
+      case WAVE             : mId = object.wave      (mDyn5, mCenterDyn, mRegionDyn); break;
 
       case ALPHA            : mId = object.alpha     (mDyn1,        mRegionDyn, false); break;
       case SMOOTH_ALPHA     : mId = object.alpha     (mDyn1,        mRegionDyn, true ); break;
@@ -121,7 +122,14 @@ class Matrix3DEffect implements SeekBar.OnSeekBarChangeListener
                               float rz = (mInter[3]-50)/ 50.0f;
                               mSta4.set(an,rx,ry,rz);
                               break;
-      case QUATERNION       :
+      case QUATERNION       : float qx = (mInter[0]-50)/ 50.0f;
+                              float qy = (mInter[1]-50)/ 50.0f;
+                              float qz = (mInter[2]-50)/ 50.0f;
+                              float qa = (mInter[3]-50)*3.1415f/50;
+                              float cosA = (float)Math.cos(qa/2);
+                              float len = (float)Math.sqrt(qx*qx+qy*qy+qz*qz);
+                              float sinAnorm = (float)Math.sin(qa/2)/len;
+                              mSta4.set(sinAnorm*qx,sinAnorm*qy,sinAnorm*qz, cosA);
                               break;
       case MOVE             : float sw = mAct.get().getScreenWidth()/50.0f;
                               float sh = mAct.get().getScreenWidth()/50.0f;
@@ -140,6 +148,7 @@ class Matrix3DEffect implements SeekBar.OnSeekBarChangeListener
                               float zsh = (mInter[2]-50)/25.0f;
                               mSta3.set(xsh,ysh,zsh);
                               break;
+
       case DISTORT          :
       case DEFORM           : float ld = mAct.get().getWidth()/50.0f;
                               float xd = (mInter[0]-50)*ld;
@@ -157,10 +166,16 @@ class Matrix3DEffect implements SeekBar.OnSeekBarChangeListener
                               break;
       case SWIRL            : mSta1.set( 3.6f*(mInter[0]-50) );
                               break;
+      case SINK             : mSta1.set(mInter[0] > 50 ? 50.0f/(100.01f-mInter[0]) : mInter[0] / 50.0f);
+                              break;
+      case PINCH            : float dp = mInter[0] > 50 ? 50.0f/(100.01f-mInter[0]) : mInter[0] / 50.0f;
+                              float ap = (mInter[1]-50)*180 / 50;
+                              mSta2.set(dp,ap);
+                              break;
+
       case ALPHA            :
       case SMOOTH_ALPHA     : mSta1.set(mInter[0]/100.0f);
                               break;
-      case SINK             :
       case SATURATION       :
       case SMOOTH_SATURATION:
       case CONTRAST         :
@@ -190,7 +205,7 @@ class Matrix3DEffect implements SeekBar.OnSeekBarChangeListener
       case 1: mInter[0] = 50;
       }
 
-    if( mName==EffectNames.ROTATE ) mInter[1]= 100;
+    if( mName==EffectNames.ROTATE || mName==EffectNames.QUATERNION ) mInter[1]= 100;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -350,7 +365,7 @@ class Matrix3DEffect implements SeekBar.OnSeekBarChangeListener
                mSta3 = new Static3D(0,0,0);
                mDyn3.add(mSta3);
                break;
-      case 4 : if( mName == EffectNames.QUATERNION || mName == EffectNames.ROTATE )
+      case 4 : if( mName == EffectNames.ROTATE || mName == EffectNames.QUATERNION )
                  {
                  mDyn4 = new Dynamic4D();
                  mSta4 = new Static4D(0,0,0,0);
