commit 0d15e9346b7683eae1c9eb8d7bd6aeb46ba173b6
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Jan 4 14:11:49 2022 +0100

    Compute the Quat Group in Java.

diff --git a/src/main/java/org/distorted/objectlib/helpers/QuatGroupGenerator.java b/src/main/java/org/distorted/objectlib/helpers/QuatGroupGenerator.java
new file mode 100644
index 00000000..29e487b5
--- /dev/null
+++ b/src/main/java/org/distorted/objectlib/helpers/QuatGroupGenerator.java
@@ -0,0 +1,254 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube 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.                                                           //
+//                                                                                               //
+// Magic Cube 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 Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.objectlib.helpers;
+
+import org.distorted.library.main.QuatHelper;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class QuatGroupGenerator
+  {
+  private static final int MAX_GROUP_SIZE = 256;
+  private static final double PI = Math.PI;
+  private static final Static4D[] mTable= new Static4D[MAX_GROUP_SIZE];
+
+  private static int mInserted;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// sin(A/2)*x, sin(A/2)*y, sin(A/2)*z, cos(A/2)
+
+  private static void createQuat(Static3D axis, double angle, Static4D output)
+    {
+    float cosAngle = (float)Math.cos(angle/2);
+    float sinAngle = (float)Math.sin(angle/2);
+
+    output.set0( sinAngle*axis.get0() );
+    output.set1( sinAngle*axis.get1() );
+    output.set2( sinAngle*axis.get2() );
+    output.set3( cosAngle );
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// double cover, so q == -q
+
+  private static boolean quatTheSame(Static4D q1, Static4D q2)
+    {
+    final float MAX_ERROR = 0.01f;
+
+    float q10 = q1.get0();
+    float q11 = q1.get1();
+    float q12 = q1.get2();
+    float q13 = q1.get3();
+
+    float q20 = q2.get0();
+    float q21 = q2.get1();
+    float q22 = q2.get2();
+    float q23 = q2.get3();
+
+    float d0 = q10-q20;
+    float d1 = q11-q21;
+    float d2 = q12-q22;
+    float d3 = q13-q23;
+
+    if( d0<MAX_ERROR && d0>-MAX_ERROR &&
+        d1<MAX_ERROR && d1>-MAX_ERROR &&
+        d2<MAX_ERROR && d2>-MAX_ERROR &&
+        d3<MAX_ERROR && d3>-MAX_ERROR  ) return true;
+
+    d0 = q10+q20;
+    d1 = q11+q21;
+    d2 = q12+q22;
+    d3 = q13+q23;
+
+    if( d0<MAX_ERROR && d0>-MAX_ERROR &&
+        d1<MAX_ERROR && d1>-MAX_ERROR &&
+        d2<MAX_ERROR && d2>-MAX_ERROR &&
+        d3<MAX_ERROR && d3>-MAX_ERROR  ) return true;
+
+    return false;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static int getIndexInTable(Static4D quat, Static4D[] table)
+    {
+    for(int i=0; i<mInserted; i++)
+      {
+      if( quatTheSame(quat,table[i]) ) return i;
+      }
+
+    return -1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static boolean insertQuat(Static4D quat, Static4D[] table)
+    {
+    if( getIndexInTable(quat,table)<0 )
+      {
+      if( mInserted<MAX_GROUP_SIZE )
+        {
+        table[mInserted] = new Static4D(quat);
+        mInserted++;
+        return true;
+        }
+      return false;
+      }
+
+    return true;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static Static4D[] computeGroup(Static3D[] rotAxis, int[] basicAngles)
+    {
+    Static4D quat = new Static4D(0,0,0,1);
+    int num,numAxis = rotAxis.length;
+    mInserted = 0;
+
+    insertQuat(quat,mTable);
+
+    for( int ax=0; ax<numAxis; ax++)
+      for(int angle=1; angle<basicAngles[ax]; angle++)
+        {
+        createQuat(rotAxis[ax], 2*PI*angle/basicAngles[ax], quat);
+        insertQuat(quat,mTable);
+        }
+
+    do
+      {
+      num = mInserted;
+
+      for(int i=0; i<num; i++)
+        for(int j=0; j<num; j++)
+          {
+          quat = QuatHelper.quatMultiply(mTable[i], mTable[j]);
+
+          if( !insertQuat(quat,mTable) )
+            {
+            i=num;j=num;
+            android.util.Log.e("QuatGroupGenerator", "OVERFLOW");
+            }
+          }
+      }
+    while( num < mInserted );
+
+    Static4D[] table = new Static4D[mInserted];
+
+    for(int i=0; i<mInserted; i++)
+      {
+      table[i] = new Static4D(mTable[i]);
+      }
+
+    return table;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void showQuats(Static4D[] table)
+    {
+    final float MAX_ERR = 0.00001f;
+    String dbg = "---------------------------------\n";
+
+    for (Static4D quat : table)
+      {
+      float x = quat.get0();
+      float y = quat.get1();
+      float z = quat.get2();
+      float w = quat.get3();
+
+      if( x<MAX_ERR && x>-MAX_ERR ) x = 0.0f;
+      if( y<MAX_ERR && y>-MAX_ERR ) y = 0.0f;
+      if( z<MAX_ERR && z>-MAX_ERR ) z = 0.0f;
+      if( w<MAX_ERR && w>-MAX_ERR ) w = 0.0f;
+
+      if( x<0.5f+MAX_ERR && x>0.5f-MAX_ERR ) x = 0.5f;
+      if( y<0.5f+MAX_ERR && y>0.5f-MAX_ERR ) y = 0.5f;
+      if( z<0.5f+MAX_ERR && z>0.5f-MAX_ERR ) z = 0.5f;
+      if( w<0.5f+MAX_ERR && w>0.5f-MAX_ERR ) w = 0.5f;
+
+      if( x<-0.5f+MAX_ERR && x>-0.5f-MAX_ERR ) x = -0.5f;
+      if( y<-0.5f+MAX_ERR && y>-0.5f-MAX_ERR ) y = -0.5f;
+      if( z<-0.5f+MAX_ERR && z>-0.5f-MAX_ERR ) z = -0.5f;
+      if( w<-0.5f+MAX_ERR && w>-0.5f-MAX_ERR ) w = -0.5f;
+
+      if( x<1.0f+MAX_ERR && x>1.0f-MAX_ERR ) x = 1.0f;
+      if( y<1.0f+MAX_ERR && y>1.0f-MAX_ERR ) y = 1.0f;
+      if( z<1.0f+MAX_ERR && z>1.0f-MAX_ERR ) z = 1.0f;
+      if( w<1.0f+MAX_ERR && w>1.0f-MAX_ERR ) w = 1.0f;
+
+      if( x<-1.0f+MAX_ERR && x>-1.0f-MAX_ERR ) x = -1.0f;
+      if( y<-1.0f+MAX_ERR && y>-1.0f-MAX_ERR ) y = -1.0f;
+      if( z<-1.0f+MAX_ERR && z>-1.0f-MAX_ERR ) z = -1.0f;
+      if( w<-1.0f+MAX_ERR && w>-1.0f-MAX_ERR ) w = -1.0f;
+
+      dbg += ( "("+x+" "+y+" "+z+" "+w+")\n");
+      }
+
+    android.util.Log.e("D", dbg);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void showRotations(Static4D[] table)
+    {
+    final float MAX_ERR = 0.00001f;
+    String dbg = "---------------------------------\n";
+
+    for (Static4D quat : table)
+      {
+      float cos = quat.get3();
+      float sin = (float)Math.sqrt(1-cos*cos);
+      float x = sin==0 ? 0 : quat.get0()/sin;
+      float y = sin==0 ? 0 : quat.get1()/sin;
+      float z = sin==0 ? 0 : quat.get2()/sin;
+      float halfAngle = (float)Math.acos(cos);
+      int ang = (int) ( (360*halfAngle/Math.PI) + 0.5f);
+
+      if( x<MAX_ERR && x>-MAX_ERR ) x = 0.0f;
+      if( y<MAX_ERR && y>-MAX_ERR ) y = 0.0f;
+      if( z<MAX_ERR && z>-MAX_ERR ) z = 0.0f;
+
+      if( x<0.5f+MAX_ERR && x>0.5f-MAX_ERR ) x = 0.5f;
+      if( y<0.5f+MAX_ERR && y>0.5f-MAX_ERR ) y = 0.5f;
+      if( z<0.5f+MAX_ERR && z>0.5f-MAX_ERR ) z = 0.5f;
+
+      if( x<-0.5f+MAX_ERR && x>-0.5f-MAX_ERR ) x = -0.5f;
+      if( y<-0.5f+MAX_ERR && y>-0.5f-MAX_ERR ) y = -0.5f;
+      if( z<-0.5f+MAX_ERR && z>-0.5f-MAX_ERR ) z = -0.5f;
+
+      if( x<1.0f+MAX_ERR && x>1.0f-MAX_ERR ) x = 1.0f;
+      if( y<1.0f+MAX_ERR && y>1.0f-MAX_ERR ) y = 1.0f;
+      if( z<1.0f+MAX_ERR && z>1.0f-MAX_ERR ) z = 1.0f;
+
+      if( x<-1.0f+MAX_ERR && x>-1.0f-MAX_ERR ) x = -1.0f;
+      if( y<-1.0f+MAX_ERR && y>-1.0f-MAX_ERR ) y = -1.0f;
+      if( z<-1.0f+MAX_ERR && z>-1.0f-MAX_ERR ) z = -1.0f;
+
+      dbg += ( "("+x+" "+y+" "+z+") "+ang+"\n");
+      }
+
+    android.util.Log.e("D", dbg);
+    }
+  }
\ No newline at end of file
diff --git a/src/main/res/raw/compute_quats.c b/src/main/res/raw/compute_quats.c
deleted file mode 100644
index 0dfcf860..00000000
--- a/src/main/res/raw/compute_quats.c
+++ /dev/null
@@ -1,250 +0,0 @@
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-
-#define TRAJBER
-
-#define SQ2 1.41421356237f
-#define SQ3 1.73205080757f
-#define SQ5 2.23606797750f
-#define PI  3.14159265358f
-#define NUM_QUATS  200
-
-#ifdef PYRA 
-int basic[] = { 3,3,3,3 };
-
-float axis[][3] = { { SQ2*SQ3/3,   SQ3/3,          0 } ,
-                    {-SQ2*SQ3/3,   SQ3/3,          0 } ,
-                    {         0,  -SQ3/3, -SQ2*SQ3/3 } ,
-                    {         0,  -SQ3/3,  SQ2*SQ3/3 } };
-#endif
-
-#ifdef CUBE
-int basic[] = { 4,4,4 };
-
-float axis[][3] = { { 1,0,0 } , 
-                    { 0,1,0 } , 
-                    { 0,0,1 } };
-#endif
-
-#ifdef DINO
-int basic[] = { 3,3,3,3 };
-
-float axis[][3] = { {+SQ3/3,+SQ3/3,+SQ3/3} , 
-                    {+SQ3/3,+SQ3/3,-SQ3/3} , 
-                    {+SQ3/3,-SQ3/3,+SQ3/3} , 
-                    {+SQ3/3,-SQ3/3,-SQ3/3} };
-#endif
-
-#ifdef DIAM
-int basic[] = { 3,3,3,3 };
-
-float axis[][3] = { {+SQ3*SQ2/3,+SQ3/3,         0} ,
-                    {-SQ3*SQ2/3,+SQ3/3,         0} ,
-                    {         0,+SQ3/3,+SQ3*SQ2/3} ,
-                    {         0,+SQ3/3,-SQ3*SQ2/3} };
-#endif
-
-#ifdef HELI
-int basic[] = { 2,2,2,2,2,2 };
-
-float axis[][3] = { {     0, +SQ2/2, -SQ2/2} ,
-                    {     0, -SQ2/2, -SQ2/2} ,
-                    {+SQ2/2,      0, -SQ2/2} ,
-                    {-SQ2/2,      0, -SQ2/2} ,
-                    {+SQ2/2, -SQ2/2,      0} ,
-                    {-SQ2/2, -SQ2/2,      0} };
-
-#endif
-
-#ifdef ULTI
-int basic[] = { 3,3,3,3 };
-
-float axis[][3] = { { 5*SQ5/16 + 11.0f/16,              0.0f   ,    SQ5/8  + 1.0f/4 } ,
-                    {   SQ5/8  +  1.0f/4 ,  5*SQ5/16 + 11.0f/16,             0.0f   } ,
-                    {-3*SQ5/16 -  7.0f/16,  3*SQ5/16 +  7.0f/16,  3*SQ5/16 + 7.0f/16} ,
-                    {             0.0f   ,    SQ5/4  +  1.0f/2 , -5*SQ5/8  -11.0f/8 } };
-
-#endif
-
-#ifdef SQUARE
-#define COS15 (0.25f*SQ2*(SQ3+1))
-#define SIN15 (0.25f*SQ2*(SQ3-1))
-
-int basic[] = { 12, 2 };
-
-float axis[][3] = { {     0, 1,     0 } ,
-                    { COS15, 0, SIN15 } };
-#endif
-
-#ifdef TRAJBER
-
-int basic[] = { 4,4,4 };
-
-float axis[][3] = { { SQ2/2, 0, SQ2/2 },
-                    { SQ2/2, 0,-SQ2/2 },
-                    {     0, 1,     0 } };
-                     
-#endif
-
-int inserted=0;
-
-///////////////////////////////////////////////////////////////////
-// q1*q2
-
-void multiply_quats( float* q1, float* q2, float* output)
-  {
-  output[0] = q2[3]*q1[0] - q2[2]*q1[1] + q2[1]*q1[2] + q2[0]*q1[3];
-  output[1] = q2[3]*q1[1] + q2[2]*q1[0] + q2[1]*q1[3] - q2[0]*q1[2];
-  output[2] = q2[3]*q1[2] + q2[2]*q1[3] - q2[1]*q1[0] + q2[0]*q1[1];
-  output[3] = q2[3]*q1[3] - q2[2]*q1[2] - q2[1]*q1[1] - q2[0]*q1[0];
-  }
-
-///////////////////////////////////////////////////////////////////
-// sin(A/2)*x, sin(A/2)*y, sin(A/2)*z, cos(A/2)
-
-void create_quat(float* axis, float angle, float* output)
-  {
-  float cosAngle = cos(angle/2);
-  float sinAngle = sin(angle/2);
-
-  output[0] = sinAngle*axis[0];
-  output[1] = sinAngle*axis[1];
-  output[2] = sinAngle*axis[2];
-  output[3] = cosAngle;
-  }
-
-///////////////////////////////////////////////////////////////////
-// double cover, so q == -q
-
-int is_the_same(float* q1, float* q2)
-  {
-  const float MAX = 0.01f;
-
-  float d0 = q1[0]-q2[0];
-  float d1 = q1[1]-q2[1];
-  float d2 = q1[2]-q2[2];
-  float d3 = q1[3]-q2[3];
-
-  if( d0<MAX && d0>-MAX &&
-      d1<MAX && d1>-MAX &&
-      d2<MAX && d2>-MAX &&
-      d3<MAX && d3>-MAX  ) return 1;
-
-  d0 = q1[0]+q2[0];
-  d1 = q1[1]+q2[1];
-  d2 = q1[2]+q2[2];
-  d3 = q1[3]+q2[3];
-
-  if( d0<MAX && d0>-MAX &&
-      d1<MAX && d1>-MAX &&
-      d2<MAX && d2>-MAX &&
-      d3<MAX && d3>-MAX  ) return 1;
-
-  return 0;
-  }
-
-///////////////////////////////////////////////////////////////////
-
-int getIndexInTable(float* quat, float* table)
-  {
-  for(int i=0; i<inserted; i++)
-    {
-    if( is_the_same(quat,table+4*i)==1 ) return i;
-    }
-
-  return -1;
-  }
-
-///////////////////////////////////////////////////////////////////
-
-void insert(float* quat, float* table)
-  {
-  if( getIndexInTable(quat,table)<0 )
-    {
-    if( inserted<NUM_QUATS )
-      {
-      table[4*inserted+0] = quat[0];
-      table[4*inserted+1] = quat[1];
-      table[4*inserted+2] = quat[2];
-      table[4*inserted+3] = quat[3];
-
-      inserted++;
-      }
-    else printf("Error: inserted=%d\n", inserted);
-    }
-  }
-
-///////////////////////////////////////////////////////////////////
-
-void normalize(int index)
-  {
-  float* a = axis[index];
-
-  float len = (float)(sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]));
-
-  a[0] /= len;  
-  a[1] /= len;  
-  a[2] /= len;  
-  }
-
-///////////////////////////////////////////////////////////////////
-
-int main(int argc, char** argv)
-  {
-  float tmp[4];
-  float table[4*NUM_QUATS];
-  int num,NUM_AXIS = sizeof(axis) / sizeof(axis[0]);
-
-  tmp[0] = 0.0f; tmp[1] = 0.0f; tmp[2] = 0.0f; tmp[3] = 1.0f;
-  insert(tmp,table);
-
-  for(int ax=0; ax<NUM_AXIS; ax++)
-    {
-    normalize(ax);
-    }
-
-  for( int ax=0; ax<NUM_AXIS; ax++)
-    for(int angle=1; angle<basic[ax]; angle++)
-      {
-      create_quat(axis[ax], 2*PI*angle/basic[ax], tmp);
-      insert(tmp,table); 
-      }
-
-  do
-    {
-    num = inserted;
-
-    for(int i=0; i<num; i++)
-      for(int j=0; j<num; j++)
-        {
-        multiply_quats( table+4*i, table+4*j, tmp);
-        insert(tmp,table);
-        }
-    }
-  while( num < inserted );
-
-  printf("\n");
-
-  for(int i=0; i<inserted; i++)
-    {
-    printf( "%2d %7.4f %7.4f %7.4f %7.4f\n", i, table[4*i], table[4*i+1], table[4*i+2], table[4*i+3] );
-    }
-
-  printf("\n");
-
-  for(int i=0; i<inserted; i++)
-    {
-    printf("{");
-
-    for(int j=0; j<inserted; j++)
-      {
-      multiply_quats( table+4*i, table+4*j, tmp);
-      num = getIndexInTable(tmp,table);
-      printf("%3d," , num);
-      }
-    printf("},\n");
-    }
- 
-return 0;
-}
