commit 14a4712f30416d0bf663f38eab1282c1890dd4bd
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Mar 12 13:57:31 2020 +0000

    Progress with object Movement. Assigning new Rotations works now, independently of object type.

diff --git a/src/main/java/org/distorted/magic/RubikSurfaceView.java b/src/main/java/org/distorted/magic/RubikSurfaceView.java
index dc25de02..1d8ebcfc 100644
--- a/src/main/java/org/distorted/magic/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/magic/RubikSurfaceView.java
@@ -40,8 +40,8 @@ public class RubikSurfaceView extends GLSurfaceView
     // Moving the finger from the middle of the vertical screen to the right edge will rotate a
     // given face by SWIPING_SENSITIVITY/2 degrees.
     private final static int SWIPING_SENSITIVITY  = 240;
-    // Moving the finger by 1/12 the distance of min(scrWidth,scrHeight) will start a Rotation.
-    private final static int ROTATION_SENSITIVITY =  12;
+    // Moving the finger by 1/15 the distance of min(scrWidth,scrHeight) will start a Rotation.
+    private final static int ROTATION_SENSITIVITY =  15;
     // Every 1/12 the distance of min(scrWidth,scrHeight) the direction of cube rotation will reset.
     private final static int DIRECTION_SENSITIVITY=  12;
 
diff --git a/src/main/java/org/distorted/object/RubikCubeMovement.java b/src/main/java/org/distorted/object/RubikCubeMovement.java
index 590617c2..01d2bed7 100644
--- a/src/main/java/org/distorted/object/RubikCubeMovement.java
+++ b/src/main/java/org/distorted/object/RubikCubeMovement.java
@@ -25,14 +25,7 @@ class RubikCubeMovement extends RubikObjectMovement
 {
   RubikCubeMovement()
     {
-    super(RubikCube.AXIS,2,0.5f);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private boolean isVertical(float x, float y)
-    {
-    return (y>x) ? (y>=-x) : (y< -x);
+    super(RubikCube.AXIS, 2, 0.5f, 0.5f);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -54,14 +47,6 @@ class RubikCubeMovement extends RubikObjectMovement
     return ( p[0]<=0.5f && p[0]>=-0.5f && p[1]<=0.5f && p[1]>=-0.5f );
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float fillUpRotationVectAndOffset(float[] v, float[] touch, int[] possible)
-    {
-    mRotationVect = isVertical(v[possible[0]],v[possible[1]]) ? possible[0] : possible[1];
-    return touch[mRotationVect]+0.5f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   float returnAngle(float[] v, int[] possible)
diff --git a/src/main/java/org/distorted/object/RubikObjectMovement.java b/src/main/java/org/distorted/object/RubikObjectMovement.java
index 1af4f4d8..4c510ca6 100644
--- a/src/main/java/org/distorted/object/RubikObjectMovement.java
+++ b/src/main/java/org/distorted/object/RubikObjectMovement.java
@@ -29,36 +29,118 @@ public abstract class RubikObjectMovement
   {
   int mRotationVect, mLastTouchedAxis;
 
-  private float[] mPoint, mCamera, mDiff, mTouch, m2Dpoint;
+  private float[] mPoint, mCamera, mDiff, mTouch;
+  private float[] mPoint2D, mMove2D;
+  private float[][][] mCastAxis;
   private int mLastTouchedLR;
   private int mNumAxis, mNumFacesPerAxis;
   private int[] mPossible;
-  private float mDistanceCenterFace;
+  private float mDistanceCenterFace3D, mDistanceCenterFace2D;
   private Static3D[] mAxis;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   abstract boolean isInsideFace(float[] point);
-  abstract float fillUpRotationVectAndOffset(float[] vect, float[] touch, int[] possible);
   abstract float returnAngle(float[] vect, int[] possible);
   abstract void fillPossibleRotations(int axis, int[] output);
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  RubikObjectMovement(Static3D[] axis, int numFacesPerAxis, float distance)
+  RubikObjectMovement(Static3D[] axis, int numFacesPerAxis, float distance3D, float distance2D)
     {
     mPoint = new float[3];
     mCamera= new float[3];
     mDiff  = new float[3];
     mTouch = new float[3];
 
-    m2Dpoint = new float[2];
+    mPoint2D = new float[2];
+    mMove2D  = new float[2];
 
     mAxis = axis;
     mNumAxis = mAxis.length;
     mNumFacesPerAxis = numFacesPerAxis;
-    mDistanceCenterFace = distance;
+    mDistanceCenterFace3D = distance3D; // distance from the center of the object to each of its faces
+    mDistanceCenterFace2D = distance2D; // distance from the center of a face to its edge
     mPossible = new int[mNumAxis-1];
+
+    // mCastAxis[1][2]{0,1} are the 2D coords of the 2nd axis cast onto the face defined by the
+    // 1st pair (axis,lr)
+    mCastAxis = new float[mNumAxis*mNumFacesPerAxis][mNumAxis][2];
+
+    for( int casted=0; casted<mNumAxis; casted++)
+      {
+      Static3D a = mAxis[casted];
+      mPoint[0]= a.get0();
+      mPoint[1]= a.get1();
+      mPoint[2]= a.get2();
+
+      for( int surface=0; surface<mNumAxis; surface++)
+        for(int lr=0; lr<mNumFacesPerAxis; lr++)
+          {
+          int index = surface*mNumFacesPerAxis + lr;
+
+          if( casted!=surface )
+            {
+            convertTo2Dcoords( mPoint, mAxis[surface], lr, mPoint2D);
+            mCastAxis[index][casted][0] = mPoint2D[0];
+            mCastAxis[index][casted][1] = mPoint2D[1];
+            normalize2D(mCastAxis[index][casted]);
+            }
+          else
+            {
+            mCastAxis[index][casted][0] = 0;
+            mCastAxis[index][casted][1] = 0;
+            }
+          }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void normalize2D(float[] vect)
+    {
+    float len = (float)Math.sqrt(vect[0]*vect[0] + vect[1]*vect[1]);
+    vect[0] /= len;
+    vect[1] /= len;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// find the casted axis with which our move2D vector forms an angle closest to 90 deg.
+
+  private int computeRotationVect(int axis, int lr, float[] move2D)
+    {
+    float cosAngle, minCosAngle = Float.MAX_VALUE;
+    int minIndex=-1;
+    int index = axis*mNumFacesPerAxis + lr;
+    float m0 = move2D[0];
+    float m1 = move2D[1];
+    float len = (float)Math.sqrt(m0*m0 + m1*m1);
+    m0 /= len;
+    m1 /= len;
+
+    for(int i=0; i<mNumAxis; i++)
+      {
+      if( axis != i )
+        {
+        cosAngle = m0*mCastAxis[index][i][0] +  m1*mCastAxis[index][i][1];
+        if( cosAngle<0 ) cosAngle = -cosAngle;
+
+        if( cosAngle<minCosAngle )
+          {
+          minCosAngle=cosAngle;
+          minIndex = i;
+          }
+        }
+      }
+
+    return minIndex;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float computeOffset(float[] point, float[] axis)
+    {
+    return point[0]*axis[0] + point[1]*axis[1] + mDistanceCenterFace2D;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -66,7 +148,7 @@ public abstract class RubikObjectMovement
   private boolean faceIsVisible(Static3D axis, int lr)
     {
     float castCameraOnAxis = mCamera[0]*axis.get0() + mCamera[1]*axis.get1() + mCamera[2]*axis.get2();
-    return (2*lr-1)*castCameraOnAxis > mDistanceCenterFace;
+    return (2*lr-1)*castCameraOnAxis > mDistanceCenterFace3D;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -93,7 +175,7 @@ public abstract class RubikObjectMovement
     if( denom != 0.0f )
       {
       float axisCam = a0*mCamera[0] + a1*mCamera[1] + a2*mCamera[2];
-      float distance = (2*lr-1)*mDistanceCenterFace;
+      float distance = (2*lr-1)*mDistanceCenterFace3D;
       float alpha = (distance-axisCam)/denom;
 
       output[0] = mCamera[0] + d0*alpha;
@@ -162,10 +244,10 @@ public abstract class RubikObjectMovement
     {
     switch(axis)
       {
-      case 0: return "yellow ";
-      case 1: return "green ";
-      case 2: return "blue ";
-      case 3: return "red ";
+      case 0: return "yellow (bottom) ";
+      case 1: return "green (back) ";
+      case 2: return "blue (right) ";
+      case 3: return "red (left) ";
       }
 
     return null;
@@ -192,11 +274,11 @@ public abstract class RubikObjectMovement
         if( faceIsVisible(mAxis[mLastTouchedAxis], mLastTouchedLR) )
           {
           castTouchPointOntoFace(mAxis[mLastTouchedAxis], mLastTouchedLR, mTouch);
-          convertTo2Dcoords(mTouch, mAxis[mLastTouchedAxis], mLastTouchedLR, m2Dpoint);
+          convertTo2Dcoords(mTouch, mAxis[mLastTouchedAxis], mLastTouchedLR, mPoint2D);
 
-          if( isInsideFace(m2Dpoint) )
+          if( isInsideFace(mPoint2D) )
             {
-            android.util.Log.e("move", "face "+getFaceColor(mLastTouchedAxis)+" ("+m2Dpoint[0]+","+m2Dpoint[1]+")");
+            android.util.Log.e("move", "face "+getFaceColor(mLastTouchedAxis)+" ("+mPoint2D[0]+","+mPoint2D[1]+")");
 
             fillPossibleRotations(mLastTouchedAxis, mPossible);
             return true;
@@ -216,13 +298,18 @@ public abstract class RubikObjectMovement
     mPoint[1] = rotatedTouchPoint.get1()/RubikObject.OBJECT_SCREEN_RATIO;
     mPoint[2] = rotatedTouchPoint.get2()/RubikObject.OBJECT_SCREEN_RATIO;
 
-    castTouchPointOntoFace(mAxis[mLastTouchedAxis], mLastTouchedLR, mDiff);
+    castTouchPointOntoFace(mAxis[mLastTouchedAxis], mLastTouchedLR, mTouch);
+    convertTo2Dcoords(mTouch, mAxis[mLastTouchedAxis], mLastTouchedLR, mMove2D);
+
+    mMove2D[0] -= mPoint2D[0];
+    mMove2D[1] -= mPoint2D[1];
+
+    mRotationVect= computeRotationVect(mLastTouchedAxis, mLastTouchedLR, mMove2D);
+    int index = mLastTouchedAxis*mNumFacesPerAxis+mLastTouchedLR;
+    float offset = computeOffset(mPoint2D, mCastAxis[index][mRotationVect]);
 
-    mDiff[0] -= mTouch[0];
-    mDiff[1] -= mTouch[1];
-    mDiff[2] -= mTouch[2];
+android.util.Log.d("move", "new rot: face "+getFaceColor(mLastTouchedAxis)+" vect: "+mRotationVect+" offset: "+offset);
 
-    float offset = fillUpRotationVectAndOffset(mDiff, mTouch, mPossible);
     return new Static2D(mRotationVect,offset);
     }
 
diff --git a/src/main/java/org/distorted/object/RubikPyraminxMovement.java b/src/main/java/org/distorted/object/RubikPyraminxMovement.java
index b10cc0d3..df8287be 100644
--- a/src/main/java/org/distorted/object/RubikPyraminxMovement.java
+++ b/src/main/java/org/distorted/object/RubikPyraminxMovement.java
@@ -30,7 +30,7 @@ class RubikPyraminxMovement extends RubikObjectMovement
 
   RubikPyraminxMovement()
     {
-    super(RubikPyraminx.AXIS,1,SQ2*SQ3/12);
+    super(RubikPyraminx.AXIS, 1, SQ2*SQ3/12, SQ3/6);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -61,17 +61,6 @@ class RubikPyraminxMovement extends RubikObjectMovement
     return a1 && a2 && a3;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
-
-  float fillUpRotationVectAndOffset(float[] v, float[] touch, int[] possible)
-    {
-    //mRotationVect = isVertical(v[possible[0]],v[possible[1]]) ? possible[0] : possible[1];
-    //return mTouch[mRotationVect]+0.5f;
-
-    return 0;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // TODO
 
