commit ead913424e217f421eee95f63e21e7812aa551cc
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Mar 31 00:49:29 2021 +0200

    Progress with any size Kilominx.

diff --git a/src/main/java/org/distorted/objects/TwistyKilominx.java b/src/main/java/org/distorted/objects/TwistyKilominx.java
index f324ff17..3bbfd88f 100644
--- a/src/main/java/org/distorted/objects/TwistyKilominx.java
+++ b/src/main/java/org/distorted/objects/TwistyKilominx.java
@@ -31,6 +31,10 @@ import org.distorted.library.mesh.MeshSquare;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 import org.distorted.main.R;
+import org.distorted.main.RubikSurfaceView;
+
+import static org.distorted.objects.FactoryCubit.COS18;
+import static org.distorted.objects.FactoryCubit.COS54;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -50,21 +54,21 @@ public class TwistyKilominx extends TwistyMinx
 
   private int numCubitsPerCorner(int numLayers)
     {
-    return 3*((numLayers-3)/2)*((numLayers-5)/2) + (numLayers>=5 ? 1 : 0);
+    return 3*((numLayers-3)/2)*((numLayers-5)/2) + (numLayers<5 ? 0:1);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private int numCubitsPerEdge(int numLayers)
     {
-    return numLayers<5 ? 0 : numLayers-4;
+    return numLayers<5 ? 0 : 2*(numLayers-4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   int getNumStickerTypes(int numLayers)
     {
-    return numLayers == 3 ? 1 : numLayers/2 + 1;
+    return numLayers<5 ? 1 : numLayers/2 + 1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -75,19 +79,175 @@ public class TwistyKilominx extends TwistyMinx
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
   float[] getCuts(int numLayers)
     {
-    return new float[] { -0.5f , 0.5f };
+    float[] cuts = new float[numLayers-1];
+    float D = numLayers*MovementMinx.DIST3D;
+    float E = 2*C1;           // 2*cos(36 deg)
+    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
+                              // its height is then D*2*DIST3D, it has one 'lower' part of height X, one
+                              // 'middle' part of height Y and one upper part of height X again.
+                              // It's edge length = numLayers/3.0f.
+    int num = (numLayers-1)/2;
+    float G = X*0.5f/num;     // height of one Layer
+
+    for(int i=0; i<num; i++)
+      {
+      cuts[        i] = -D + (i+0.5f)*G;
+      cuts[2*num-1-i] = -cuts[i];
+      }
+
+    return cuts;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
+// Appropriate one: QUATS[QUAT_INDICES[corner]].
+
+  private void computeBasicCornerVectors(int corner)
+    {
+    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
+
+    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
+    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
+    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float[] computeCorner(int numCubitsPerCorner, int numLayers, int corner, int part)
+    {
+    float D = numLayers/3.0f;
+    float[] corn = CORNERS[corner];
+
+    if( part==0 )
+      {
+      return new float[] { corn[0]*D, corn[1]*D, corn[2]*D };
+      }
+    else
+      {
+      float E = D/(0.5f*(numLayers-1));   // ?? maybe 0.5*
+      int N = (numCubitsPerCorner-1)/3;
+      int block = (part-1) % N;
+      int index = (part-1) / N;
+      Static4D pri = mCurrCornerV[index];
+      Static4D sec = mCurrCornerV[(index+2)%3];
+
+      int layers= (numLayers-5)/2;
+      int multP = (block % layers) + 1;
+      int multS = (block / layers);
+
+      return new float[] {
+                          corn[0]*D + (pri.get0()*multP + sec.get0()*multS)*E,
+                          corn[1]*D + (pri.get1()*multP + sec.get1()*multS)*E,
+                          corn[2]*D + (pri.get2()*multP + sec.get2()*multS)*E
+                         };
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float[] computeCenter(int numLayers, int center, int part)
+    {
+    int corner = mCenterMap[center][part];
+    float[] cent = mCenterCoords[center];
+    float[] corn = CORNERS[corner];
+    float D = numLayers/3.0f;
+    float F = 1.0f - (2.0f*numLayers-6.0f)/(numLayers-1)*COS54*COS54;
+
+    return new float[]
+      {
+        D * ( cent[0] + (corn[0]-cent[0])*F),
+        D * ( cent[1] + (corn[1]-cent[1])*F),
+        D * ( cent[2] + (corn[2]-cent[2])*F)
+      };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
+    {
+    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
+    return (part+1)/2;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float[] computeEdge(int numLayers, int edge, int part)
+    {
+    float D = numLayers/3.0f;
+
+    float[] c1 = CORNERS[ mEdgeMap[edge][0] ];
+    float[] c2 = CORNERS[ mEdgeMap[edge][1] ];
+    float x = D * (c1[0]+c2[0]) / 2;
+    float y = D * (c1[1]+c2[1]) / 2;
+    float z = D * (c1[2]+c2[2]) / 2;
+
+    part /= 2;
+
+    if( part==0 )
+      {
+      return new float[] { x, y, z };
+      }
+    else
+      {
+      int mult = (part+1)/2;
+      int dir  = (part+1)%2;
+      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
+
+      float vX = D*center[0] - x;
+      float vY = D*center[1] - y;
+      float vZ = D*center[2] - z;
+
+      float A = mult*D*COS18/(numLayers-1);
+      A /= (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
+
+      return new float[] { x+A*vX, y+A*vY, z+A*vZ };
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
   float[][] getCubitPositions(int numLayers)
     {
-    return CORNERS;
+    if( numLayers<5 ) return CORNERS;
+
+    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
+    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
+    int numCubitsPerCenter = 5;
+    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS*numCubitsPerCenter;
+    int index=0;
+
+    final float[][] CENTERS = new float[numCubits][];
+
+    for(int corner=0; corner<NUM_CORNERS; corner++)
+      {
+      computeBasicCornerVectors(corner);
+
+      for(int part=0; part<numCubitsPerCorner; part++, index++)
+        {
+        CENTERS[index] = computeCorner(numCubitsPerCorner,numLayers,corner,part);
+        }
+      }
+
+    for(int edge=0; edge<NUM_EDGES; edge++)
+      {
+      for(int part=0; part<numCubitsPerEdge; part++, index++)
+        {
+        CENTERS[index] = computeEdge(numLayers, edge, part );
+        }
+      }
+
+    for(int center=0; center<NUM_CENTERS; center++, index++)
+      {
+      for(int part=0; part<numCubitsPerCenter; part++, index++)
+        {
+        CENTERS[index] = computeCenter(numLayers,center, part);
+        }
+      }
+
+    return CENTERS;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistyMegaminx.java b/src/main/java/org/distorted/objects/TwistyMegaminx.java
index d320d905..77630836 100644
--- a/src/main/java/org/distorted/objects/TwistyMegaminx.java
+++ b/src/main/java/org/distorted/objects/TwistyMegaminx.java
@@ -44,67 +44,6 @@ public class TwistyMegaminx extends TwistyMinx
 {
   static final float MEGA_D = 0.04f;
 
-  private static final int NUM_CORNERS = 20;
-  private static final int NUM_CENTERS = 12;
-  private static final int NUM_EDGES   = 30;
-
-  // the five vertices that form a given face. Order: the same as colors
-  // of the faces in TwistyMinx.
-  private static final int[][] mCenterMap =
-         {
-           { 0, 12,  4, 14,  2},
-           { 0,  2, 18,  6, 16},
-           { 6, 18, 11, 19,  7},
-           { 3, 15,  9, 11, 19},
-           { 4,  5, 15,  9, 14},
-           { 1, 13,  5, 15,  3},
-           { 1,  3, 19,  7, 17},
-           {10, 16,  6,  7, 17},
-           { 0, 12,  8, 10, 16},
-           { 8, 13,  5,  4, 12},
-           { 1, 13,  8, 10, 17},
-           { 2, 14,  9, 11, 18},
-         };
-
-  // the quadruple ( vertex1, vertex2, face1, face2 ) defining an edge.
-  // In fact the 2 vertices already define it, the faces only provide easy
-  // way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
-  // the 'left' or right of vector vertex1 --> vertex2, according to Quat.
-  private static final int[][] mEdgeMap =
-         {
-           {  0, 12,  0,  8},
-           { 12,  4,  0,  9},
-           {  4, 14,  0,  4},
-           { 14,  2,  0, 11},
-           {  2,  0,  0,  1},
-           { 14,  9,  4, 11},
-           {  9, 11,  3, 11},
-           { 11, 18,  2, 11},
-           { 18,  2,  1, 11},
-           { 18,  6,  1,  2},
-           {  6, 16,  1,  7},
-           { 16,  0,  8,  1},
-           { 16, 10,  7,  8},
-           { 10,  8, 10,  8},
-           {  8, 12,  9,  8},
-           {  8, 13,  9, 10},
-           { 13,  5,  9,  5},
-           {  5,  4,  9,  4},
-           {  5, 15,  5,  4},
-           { 15,  9,  3,  4},
-           { 11, 19,  2,  3},
-           { 19,  7,  2,  6},
-           {  7,  6,  2,  7},
-           {  7, 17,  7,  6},
-           { 17, 10,  7, 10},
-           { 17,  1, 10,  6},
-           {  1,  3,  5,  6},
-           {  3, 19,  3,  6},
-           {  1, 13, 10,  5},
-           {  3, 15,  3,  5},
-         };
-
-
   private static final int[] QUAT_EDGE_INDICES =
       {
         56, 40, 43, 59,  0, 55, 10, 17, 25, 49,
@@ -117,53 +56,9 @@ public class TwistyMegaminx extends TwistyMinx
         16, 18, 22,  1, 20, 13, 14, 15,  0, 12,  2,  3
       };
 
-  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
-
-  static
-    {
-    for(int center=0; center<NUM_CENTERS; center++)
-      {
-      int[] map = mCenterMap[center];
-
-      float x = CORNERS[map[0]][0] +
-                CORNERS[map[1]][0] +
-                CORNERS[map[2]][0] +
-                CORNERS[map[3]][0] +
-                CORNERS[map[4]][0] ;
-
-      float y = CORNERS[map[0]][1] +
-                CORNERS[map[1]][1] +
-                CORNERS[map[2]][1] +
-                CORNERS[map[3]][1] +
-                CORNERS[map[4]][1] ;
-
-      float z = CORNERS[map[0]][2] +
-                CORNERS[map[1]][2] +
-                CORNERS[map[2]][2] +
-                CORNERS[map[3]][2] +
-                CORNERS[map[4]][2] ;
-
-      mCenterCoords[center][0] = x/5;
-      mCenterCoords[center][1] = y/5;
-      mCenterCoords[center][2] = z/5;
-      }
-    }
-
   private static MeshBase[] mCenterMeshes, mCornerMeshes;
   private static MeshBase[][] mEdgeMeshes;
 
-  private static final Static4D[] mBasicCornerV, mCurrCornerV;
-
-  static
-    {
-    mBasicCornerV = new Static4D[3];
-    mCurrCornerV  = new Static4D[3];
-
-    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
-    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
-    mBasicCornerV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   TwistyMegaminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
@@ -259,15 +154,16 @@ public class TwistyMegaminx extends TwistyMinx
       }
     else
       {
-      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
+      float E = 2.0f*D*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
       int N = (numCubitsPerCorner-1)/3;
       int block = (part-1) % N;
       int index = (part-1) / N;
       Static4D pri = mCurrCornerV[index];
       Static4D sec = mCurrCornerV[(index+2)%3];
 
-      int multP = (block % ((numLayers-3)/2)) + 1;
-      int multS = (block / ((numLayers-3)/2));
+      int layers= (numLayers-5)/2;
+      int multP = (block % layers) + 1;
+      int multS = (block / layers);
 
       return new float[] {
                           corn[0]*D + (pri.get0()*multP + sec.get0()*multS)*E,
@@ -289,13 +185,13 @@ public class TwistyMegaminx extends TwistyMinx
 
   private float[] computeEdge(int numLayers, int edge, int part)
     {
-    float corr = numLayers/3.0f;
+    float D = numLayers/3.0f;
 
     float[] c1 = CORNERS[ mEdgeMap[edge][0] ];
     float[] c2 = CORNERS[ mEdgeMap[edge][1] ];
-    float x = corr * (c1[0]+c2[0]) / 2;
-    float y = corr * (c1[1]+c2[1]) / 2;
-    float z = corr * (c1[2]+c2[2]) / 2;
+    float x = D * (c1[0]+c2[0]) / 2;
+    float y = D * (c1[1]+c2[1]) / 2;
+    float z = D * (c1[2]+c2[2]) / 2;
 
     if( part==0 )
       {
@@ -307,12 +203,12 @@ public class TwistyMegaminx extends TwistyMinx
       int dir  = (part+1)%2;
       float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
 
-      float vX = corr*center[0] - x;
-      float vY = corr*center[1] - y;
-      float vZ = corr*center[2] - z;
+      float vX = D*center[0] - x;
+      float vY = D*center[1] - y;
+      float vZ = D*center[2] - z;
 
-      float len = (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
-      float A = mult*corr*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f)/len;
+      float A = mult*D*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
+      A /= (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
 
       return new float[] { x+A*vX, y+A*vY, z+A*vZ };
       }
diff --git a/src/main/java/org/distorted/objects/TwistyMinx.java b/src/main/java/org/distorted/objects/TwistyMinx.java
index c480c9ef..de8c68b6 100644
--- a/src/main/java/org/distorted/objects/TwistyMinx.java
+++ b/src/main/java/org/distorted/objects/TwistyMinx.java
@@ -35,6 +35,10 @@ abstract class TwistyMinx extends TwistyObject
 {
   private static final int FACES_PER_CUBIT =6;
 
+  static final int NUM_CORNERS = 20;
+  static final int NUM_CENTERS = 12;
+  static final int NUM_EDGES   = 30;
+
   static final float C0 = (SQ5-1)/4;                       // cos(72 deg)
   static final float C1 = (SQ5+1)/4;                       // cos(36 deg)
   static final float C2 = (SQ5+3)/4;
@@ -206,6 +210,107 @@ abstract class TwistyMinx extends TwistyObject
           {false,  true,  true,  true,  true, false}
       };
 
+  // the quadruple ( vertex1, vertex2, face1, face2 ) defining an edge.
+  // In fact the 2 vertices already define it, the faces only provide easy
+  // way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
+  // the 'left' or right of vector vertex1 --> vertex2, according to Quat.
+  static final int[][] mEdgeMap =
+         {
+           {  0, 12,  0,  8},
+           { 12,  4,  0,  9},
+           {  4, 14,  0,  4},
+           { 14,  2,  0, 11},
+           {  2,  0,  0,  1},
+           { 14,  9,  4, 11},
+           {  9, 11,  3, 11},
+           { 11, 18,  2, 11},
+           { 18,  2,  1, 11},
+           { 18,  6,  1,  2},
+           {  6, 16,  1,  7},
+           { 16,  0,  8,  1},
+           { 16, 10,  7,  8},
+           { 10,  8, 10,  8},
+           {  8, 12,  9,  8},
+           {  8, 13,  9, 10},
+           { 13,  5,  9,  5},
+           {  5,  4,  9,  4},
+           {  5, 15,  5,  4},
+           { 15,  9,  3,  4},
+           { 11, 19,  2,  3},
+           { 19,  7,  2,  6},
+           {  7,  6,  2,  7},
+           {  7, 17,  7,  6},
+           { 17, 10,  7, 10},
+           { 17,  1, 10,  6},
+           {  1,  3,  5,  6},
+           {  3, 19,  3,  6},
+           {  1, 13, 10,  5},
+           {  3, 15,  3,  5},
+         };
+
+  // the five vertices that form a given face. Order: the same as colors
+  // of the faces in TwistyMinx.
+  static final int[][] mCenterMap =
+         {
+           { 0, 12,  4, 14,  2},
+           { 0,  2, 18,  6, 16},
+           { 6, 18, 11, 19,  7},
+           { 3, 15,  9, 11, 19},
+           { 4,  5, 15,  9, 14},
+           { 1, 13,  5, 15,  3},
+           { 1,  3, 19,  7, 17},
+           {10, 16,  6,  7, 17},
+           { 0, 12,  8, 10, 16},
+           { 8, 13,  5,  4, 12},
+           { 1, 13,  8, 10, 17},
+           { 2, 14,  9, 11, 18},
+         };
+
+  static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
+
+  static
+    {
+    for(int center=0; center<NUM_CENTERS; center++)
+      {
+      int[] map = mCenterMap[center];
+
+      float x = CORNERS[map[0]][0] +
+                CORNERS[map[1]][0] +
+                CORNERS[map[2]][0] +
+                CORNERS[map[3]][0] +
+                CORNERS[map[4]][0] ;
+
+      float y = CORNERS[map[0]][1] +
+                CORNERS[map[1]][1] +
+                CORNERS[map[2]][1] +
+                CORNERS[map[3]][1] +
+                CORNERS[map[4]][1] ;
+
+      float z = CORNERS[map[0]][2] +
+                CORNERS[map[1]][2] +
+                CORNERS[map[2]][2] +
+                CORNERS[map[3]][2] +
+                CORNERS[map[4]][2] ;
+
+      mCenterCoords[center][0] = x/5;
+      mCenterCoords[center][1] = y/5;
+      mCenterCoords[center][2] = z/5;
+      }
+    }
+
+  static final Static4D[] mBasicCornerV, mCurrCornerV;
+
+  static
+    {
+    mBasicCornerV = new Static4D[3];
+    mCurrCornerV  = new Static4D[3];
+
+    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
+    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
+    mBasicCornerV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
+    }
+
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   TwistyMinx(int numLayers, int realSize, Static4D quat, DistortedTexture texture, MeshSquare mesh,
