commit be7c919012ab9db6f661a7650273af23cd9a01dd
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Sep 17 15:51:50 2021 +0200

    Abstract out some methods from the Movement classes. only two remain now: rowFromOffset and enabledAxis.

diff --git a/src/main/java/org/distorted/objects/Movement12.java b/src/main/java/org/distorted/objects/Movement12.java
new file mode 100644
index 00000000..0ceec30e
--- /dev/null
+++ b/src/main/java/org/distorted/objects/Movement12.java
@@ -0,0 +1,157 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 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.objects;
+
+import static org.distorted.objects.TwistyMinx.C2;
+import static org.distorted.objects.TwistyMinx.COS54;
+import static org.distorted.objects.TwistyMinx.LEN;
+import static org.distorted.objects.TwistyMinx.SIN54;
+import static org.distorted.objects.TwistyObject.SQ5;
+
+import org.distorted.library.type.Static3D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+abstract class Movement12 extends Movement
+{
+  static final float DIST3D = (float)Math.sqrt(0.625f+0.275f*SQ5);
+  static final float DIST2D = (SIN54/COS54)/2;
+
+  static final Static3D[] FACE_AXIS = new Static3D[]
+         {
+           new Static3D(    C2/LEN, SIN54/LEN,    0      ),
+           new Static3D(    C2/LEN,-SIN54/LEN,    0      ),
+           new Static3D(   -C2/LEN, SIN54/LEN,    0      ),
+           new Static3D(   -C2/LEN,-SIN54/LEN,    0      ),
+           new Static3D( 0        ,    C2/LEN, SIN54/LEN ),
+           new Static3D( 0        ,    C2/LEN,-SIN54/LEN ),
+           new Static3D( 0        ,   -C2/LEN, SIN54/LEN ),
+           new Static3D( 0        ,   -C2/LEN,-SIN54/LEN ),
+           new Static3D( SIN54/LEN,    0     ,    C2/LEN ),
+           new Static3D( SIN54/LEN,    0     ,   -C2/LEN ),
+           new Static3D(-SIN54/LEN,    0     ,    C2/LEN ),
+           new Static3D(-SIN54/LEN,    0     ,   -C2/LEN )
+         };
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Movement12(Static3D[] rotAxis)
+    {
+    super(rotAxis, FACE_AXIS, DIST3D, DIST2D);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float returnRotationFactor(int numLayers, int row)
+    {
+    return 1.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// return angle (in radians) that the line connecting the center C of the pentagonal face and the
+// first vertex of the pentagon makes with a vertical line coming upwards from the center C.
+
+  private float returnAngle(int face)
+    {
+    switch(face)
+      {
+      case  0:
+      case  2:
+      case  6:
+      case  7: return 0.0f;
+      case  1:
+      case  3:
+      case  4:
+      case  5: return (float)(36*Math.PI/180);
+      case  9:
+      case 10: return (float)(54*Math.PI/180);
+      case  8:
+      case 11: return (float)(18*Math.PI/180);
+      }
+
+    return 0.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// The pair (distance,angle) defines a point P in R^2 in polar coordinate system. Let V be the vector
+// from the center of the coordinate system to P.
+// Let P' be the point defined by polar (distance,angle+PI/2). Let Lh be the half-line starting at
+// P' and going in the direction of V.
+// Return true iff point 'point' lies on the left of Lh, i.e. when we rotate (using the center of
+// the coordinate system as the center of rotation) 'point' and Lh in such a way that Lh points
+// directly upwards, is 'point' on the left or the right of it?
+
+  private boolean isOnTheLeft(float[] point, float distance, float angle)
+    {
+    float sin = (float)Math.sin(angle);
+    float cos = (float)Math.cos(angle);
+
+    float vx = point[0] + sin*distance;
+    float vy = point[1] - cos*distance;
+
+    return vx*sin < vy*cos;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Return 1,2,3,4,5 - the vertex of the pentagon to which point 'point' is the closest, if the
+// 'point' is inside the pentagon - or 0 otherwise.
+// The 'first' vertex is the one we meet the first when we rotate clockwise starting from 12:00.
+// This vertex makes angle 'returnAngle()' with the line coming out upwards from the center of the
+// pentagon.
+// Distance from the center to a vertex of the pentagon = 1/(6*COS54)
+
+  int returnPartOfThePentagon(float[] point, int face)
+    {
+    float angle = returnAngle(face);
+    float A = (float)(Math.PI/5);
+
+    for(int i=0; i<5; i++)
+      {
+      if( isOnTheLeft(point, DIST2D, (9-2*i)*A-angle) ) return 0;
+      }
+
+    if( isOnTheLeft(point, 0, 2.5f*A-angle) )
+      {
+      if( isOnTheLeft(point, 0, 3.5f*A-angle) )
+        {
+        return isOnTheLeft(point, 0, 5.5f*A-angle) ? 4 : 5;
+        }
+      else return 1;
+      }
+    else
+      {
+      if( isOnTheLeft(point, 0, 4.5f*A-angle) )
+        {
+        return 3;
+        }
+      else
+        {
+        return isOnTheLeft(point, 0, 6.5f*A-angle) ? 2 : 1;
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean isInsideFace(int face, float[] p)
+    {
+    return returnPartOfThePentagon(p,face) > 0;
+    }
+}
diff --git a/src/main/java/org/distorted/objects/Movement4.java b/src/main/java/org/distorted/objects/Movement4.java
new file mode 100644
index 00000000..23fdbc0a
--- /dev/null
+++ b/src/main/java/org/distorted/objects/Movement4.java
@@ -0,0 +1,61 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 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.objects;
+
+import org.distorted.library.type.Static3D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+abstract class Movement4 extends Movement
+{
+  static final float DIST3D = SQ6/12;
+  static final float DIST2D = SQ3/6;
+
+  static final Static3D[] FACE_AXIS = new Static3D[]
+         {
+           new Static3D(     0,+SQ3/3,+SQ6/3),
+           new Static3D(     0,+SQ3/3,-SQ6/3),
+           new Static3D(-SQ6/3,-SQ3/3,     0),
+           new Static3D(+SQ6/3,-SQ3/3,     0),
+         };
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Movement4(Static3D[] rotAxis)
+    {
+    super(rotAxis, FACE_AXIS, DIST3D, DIST2D);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float returnRotationFactor(int numLayers, int row)
+    {
+    return ((float)numLayers)/(numLayers-row);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean isInsideFace(int face, float[] p)
+    {
+    float y = (face > 1 ? p[1] : -p[1]);
+    float x = p[0];
+    return (y >= -DIST2D) && (y <= DIST2D*(2-6*x)) && (y <= DIST2D*(2+6*x));
+    }
+}
diff --git a/src/main/java/org/distorted/objects/Movement6.java b/src/main/java/org/distorted/objects/Movement6.java
new file mode 100644
index 00000000..2b06ebf4
--- /dev/null
+++ b/src/main/java/org/distorted/objects/Movement6.java
@@ -0,0 +1,58 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 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.objects;
+
+import org.distorted.library.type.Static3D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+abstract class Movement6 extends Movement
+{
+  static final float DIST3D = 0.5f;
+  static final float DIST2D = 0.5f;
+
+  static final Static3D[] FACE_AXIS = new Static3D[]
+         {
+           new Static3D(1,0,0), new Static3D(-1,0,0),
+           new Static3D(0,1,0), new Static3D(0,-1,0),
+           new Static3D(0,0,1), new Static3D(0,0,-1)
+         };
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Movement6(Static3D[] rotAxis)
+    {
+    super(rotAxis, FACE_AXIS, DIST3D, DIST2D);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float returnRotationFactor(int numLayers, int row)
+    {
+    return 1.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean isInsideFace(int face, float[] p)
+    {
+    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
+    }
+}
diff --git a/src/main/java/org/distorted/objects/Movement8.java b/src/main/java/org/distorted/objects/Movement8.java
new file mode 100644
index 00000000..c4327133
--- /dev/null
+++ b/src/main/java/org/distorted/objects/Movement8.java
@@ -0,0 +1,61 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 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.objects;
+
+import org.distorted.library.type.Static3D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+abstract class Movement8 extends Movement
+{
+  static final float DIST3D = SQ6/6;
+  static final float DIST2D = SQ3/6;
+
+  static final Static3D[] FACE_AXIS = new Static3D[]
+         {
+           new Static3D(+SQ6/3,+SQ3/3,     0), new Static3D(-SQ6/3,-SQ3/3,     0),
+           new Static3D(-SQ6/3,+SQ3/3,     0), new Static3D(+SQ6/3,-SQ3/3,     0),
+           new Static3D(     0,+SQ3/3,+SQ6/3), new Static3D(     0,-SQ3/3,-SQ6/3),
+           new Static3D(     0,+SQ3/3,-SQ6/3), new Static3D(     0,-SQ3/3,+SQ6/3)
+         };
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Movement8(Static3D[] rotAxis)
+    {
+    super(rotAxis, FACE_AXIS, DIST3D, DIST2D);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float returnRotationFactor(int numLayers, int row)
+    {
+    return 1.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean isInsideFace(int face, float[] p)
+    {
+    float y = (face%2 == 0 ? p[1] : -p[1]);
+    float x = p[0];
+    return (y >= -DIST2D) && (y <= DIST2D*(2-6*x)) && (y <= DIST2D*(2+6*x));
+    }
+}
diff --git a/src/main/java/org/distorted/objects/MovementCube.java b/src/main/java/org/distorted/objects/MovementCube.java
index 628ec6f0..849dccc6 100644
--- a/src/main/java/org/distorted/objects/MovementCube.java
+++ b/src/main/java/org/distorted/objects/MovementCube.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementCube extends Movement
+class MovementCube extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementCube()
     {
-    super(TwistyCube.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyCube.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,20 +35,6 @@ class MovementCube extends Movement
     return (int)(numLayers*offset);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementDiamond.java b/src/main/java/org/distorted/objects/MovementDiamond.java
index ed78e0d2..107b0f1a 100644
--- a/src/main/java/org/distorted/objects/MovementDiamond.java
+++ b/src/main/java/org/distorted/objects/MovementDiamond.java
@@ -19,28 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementDiamond extends Movement
+class MovementDiamond extends Movement8
 {
-  static final float DIST3D = SQ6/6;
-  static final float DIST2D = SQ3/6;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(+SQ6/3,+SQ3/3,     0), new Static3D(-SQ6/3,-SQ3/3,     0),
-           new Static3D(-SQ6/3,+SQ3/3,     0), new Static3D(+SQ6/3,-SQ3/3,     0),
-           new Static3D(     0,+SQ3/3,+SQ6/3), new Static3D(     0,-SQ3/3,-SQ6/3),
-           new Static3D(     0,+SQ3/3,-SQ6/3), new Static3D(     0,-SQ3/3,+SQ6/3)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementDiamond()
     {
-    super(TwistyDiamond.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyDiamond.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -55,23 +40,6 @@ class MovementDiamond extends Movement
     return (int)(2*numLayers*off);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    float y = (face%2 == 0 ? p[1] : -p[1]);
-    float x = p[0];
-
-    return (y >= -DIST2D) && (y <= DIST2D*(2-6*x)) && (y <= DIST2D*(2+6*x));
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementDino.java b/src/main/java/org/distorted/objects/MovementDino.java
index ac46e8c9..603f3c90 100644
--- a/src/main/java/org/distorted/objects/MovementDino.java
+++ b/src/main/java/org/distorted/objects/MovementDino.java
@@ -19,27 +19,14 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementDino extends Movement
+class MovementDino extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MovementDino()
     {
-    super(TwistyDino.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyDino.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,13 +36,6 @@ class MovementDino extends Movement
     return offset<DIST2D ? 0:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // _____________
 // |  \  0  /  |
@@ -74,13 +54,6 @@ class MovementDino extends Movement
     else      return p1 ? 1:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementHelicopter.java b/src/main/java/org/distorted/objects/MovementHelicopter.java
index 1ae6fdcb..7775d6f5 100644
--- a/src/main/java/org/distorted/objects/MovementHelicopter.java
+++ b/src/main/java/org/distorted/objects/MovementHelicopter.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementHelicopter extends Movement
+class MovementHelicopter extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementHelicopter()
     {
-    super(TwistyHelicopter.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyHelicopter.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,13 +35,6 @@ class MovementHelicopter extends Movement
     return offset<DIST2D ? 0:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // _____________
 // |     |     |
@@ -74,13 +53,6 @@ class MovementHelicopter extends Movement
     else      return p1 ? 3:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementIvy.java b/src/main/java/org/distorted/objects/MovementIvy.java
index dd72cc40..05659bb6 100644
--- a/src/main/java/org/distorted/objects/MovementIvy.java
+++ b/src/main/java/org/distorted/objects/MovementIvy.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementIvy extends Movement
+class MovementIvy extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementIvy()
     {
-    super(TwistyIvy.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyIvy.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,13 +35,6 @@ class MovementIvy extends Movement
     return offset<DIST2D ? 0:1;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // faces 0,1,2,3  --> /
 // faces 4,5      --> \
@@ -66,13 +45,6 @@ class MovementIvy extends Movement
     else                     return touchPoint[1] >= touchPoint[0];
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // 0 +++
 // 1 ++-
diff --git a/src/main/java/org/distorted/objects/MovementJing.java b/src/main/java/org/distorted/objects/MovementJing.java
index 68a1d396..b5ae5a03 100644
--- a/src/main/java/org/distorted/objects/MovementJing.java
+++ b/src/main/java/org/distorted/objects/MovementJing.java
@@ -19,30 +19,15 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 import static org.distorted.objects.TwistyJing.F;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementJing extends Movement
+class MovementJing extends Movement4
 {
-  static final float DIST3D = SQ6/12;
-  static final float DIST2D = SQ3/6;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(     0,+SQ3/3,+SQ6/3),
-           new Static3D(     0,+SQ3/3,-SQ6/3),
-           new Static3D(-SQ6/3,-SQ3/3,     0),
-           new Static3D(+SQ6/3,-SQ3/3,     0),
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementJing()
     {
-    super(TwistyJing.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyJing.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -52,22 +37,6 @@ class MovementJing extends Movement
     return offset < (SQ3/4)*F ? 0:1;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    float y = (face > 1 ? p[1] : -p[1]);
-    float x = p[0];
-    return (y >= -DIST2D) && (y <= 2*DIST2D-SQ3*x) && (y <= 2*DIST2D+SQ3*x);
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementMinx.java b/src/main/java/org/distorted/objects/MovementMinx.java
index 3456cd51..a85bd5da 100644
--- a/src/main/java/org/distorted/objects/MovementMinx.java
+++ b/src/main/java/org/distorted/objects/MovementMinx.java
@@ -19,41 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-import static org.distorted.objects.TwistyMinx.C2;
-import static org.distorted.objects.TwistyMinx.LEN;
-import static org.distorted.objects.TwistyMinx.SIN54;
-import static org.distorted.objects.TwistyMinx.COS54;
-import static org.distorted.objects.TwistyObject.SQ5;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementMinx extends Movement
+class MovementMinx extends Movement12
 {
-  static final float DIST3D = (float)Math.sqrt(0.625f+0.275f*SQ5);
-  static final float DIST2D = (SIN54/COS54)/2;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(    C2/LEN, SIN54/LEN,    0      ),
-           new Static3D(    C2/LEN,-SIN54/LEN,    0      ),
-           new Static3D(   -C2/LEN, SIN54/LEN,    0      ),
-           new Static3D(   -C2/LEN,-SIN54/LEN,    0      ),
-           new Static3D( 0        ,    C2/LEN, SIN54/LEN ),
-           new Static3D( 0        ,    C2/LEN,-SIN54/LEN ),
-           new Static3D( 0        ,   -C2/LEN, SIN54/LEN ),
-           new Static3D( 0        ,   -C2/LEN,-SIN54/LEN ),
-           new Static3D( SIN54/LEN,    0     ,    C2/LEN ),
-           new Static3D( SIN54/LEN,    0     ,   -C2/LEN ),
-           new Static3D(-SIN54/LEN,    0     ,    C2/LEN ),
-           new Static3D(-SIN54/LEN,    0     ,   -C2/LEN )
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementMinx()
     {
-    super(TwistyMinx.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyMinx.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,104 +49,6 @@ class MovementMinx extends Movement
     return 0;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// return angle (in radians) that the line connecting the center C of the pentagonal face and the
-// first vertex of the pentagon makes with a vertical line coming upwards from the center C.
-
-  private float returnAngle(int face)
-    {
-    switch(face)
-      {
-      case  0:
-      case  2:
-      case  6:
-      case  7: return 0.0f;
-      case  1:
-      case  3:
-      case  4:
-      case  5: return (float)(36*Math.PI/180);
-      case  9:
-      case 10: return (float)(54*Math.PI/180);
-      case  8:
-      case 11: return (float)(18*Math.PI/180);
-      }
-
-    return 0.0f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// The pair (distance,angle) defines a point P in R^2 in polar coordinate system. Let V be the vector
-// from the center of the coordinate system to P.
-// Let P' be the point defined by polar (distance,angle+PI/2). Let Lh be the half-line starting at
-// P' and going in the direction of V.
-// Return true iff point 'point' lies on the left of Lh, i.e. when we rotate (using the center of
-// the coordinate system as the center of rotation) 'point' and Lh in such a way that Lh points
-// directly upwards, is 'point' on the left or the right of it?
-
-  private boolean isOnTheLeft(float[] point, float distance, float angle)
-    {
-    float sin = (float)Math.sin(angle);
-    float cos = (float)Math.cos(angle);
-
-    float vx = point[0] + sin*distance;
-    float vy = point[1] - cos*distance;
-
-    return vx*sin < vy*cos;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Return 1,2,3,4,5 - the vertex of the pentagon to which point 'point' is the closest, if the
-// 'point' is inside the pentagon - or 0 otherwise.
-// The 'first' vertex is the one we meet the first when we rotate clockwise starting from 12:00.
-// This vertex makes angle 'returnAngle()' with the line coming out upwards from the center of the
-// pentagon.
-// Distance from the center to a vertex of the pentagon = 1/(6*COS54)
-
-  private int returnPartOfThePentagon(float[] point, int face)
-    {
-    float angle = returnAngle(face);
-    float A = (float)(Math.PI/5);
-
-    for(int i=0; i<5; i++)
-      {
-      if( isOnTheLeft(point, DIST2D, (9-2*i)*A-angle) ) return 0;
-      }
-
-    if( isOnTheLeft(point, 0, 2.5f*A-angle) )
-      {
-      if( isOnTheLeft(point, 0, 3.5f*A-angle) )
-        {
-        return isOnTheLeft(point, 0, 5.5f*A-angle) ? 4 : 5;
-        }
-      else return 1;
-      }
-    else
-      {
-      if( isOnTheLeft(point, 0, 4.5f*A-angle) )
-        {
-        return 3;
-        }
-      else
-        {
-        return isOnTheLeft(point, 0, 6.5f*A-angle) ? 2 : 1;
-        }
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return returnPartOfThePentagon(p,face) > 0;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementPyraminx.java b/src/main/java/org/distorted/objects/MovementPyraminx.java
index 0818ab62..306a8ee2 100644
--- a/src/main/java/org/distorted/objects/MovementPyraminx.java
+++ b/src/main/java/org/distorted/objects/MovementPyraminx.java
@@ -19,28 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementPyraminx extends Movement
+class MovementPyraminx extends Movement4
 {
-  static final float DIST3D = SQ6/12;
-  static final float DIST2D = SQ3/6;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(     0,+SQ3/3,+SQ6/3),
-           new Static3D(     0,+SQ3/3,-SQ6/3),
-           new Static3D(-SQ6/3,-SQ3/3,     0),
-           new Static3D(+SQ6/3,-SQ3/3,     0),
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementPyraminx()
     {
-    super(TwistyPyraminx.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyPyraminx.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -50,22 +35,6 @@ class MovementPyraminx extends Movement
     return (int)(numLayers*offset/(SQ6/3));
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return ((float)numLayers)/(numLayers-row);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    float y = (face > 1 ? p[1] : -p[1]);
-    float x = p[0];
-    return (y >= -DIST2D) && (y <= 2*DIST2D-SQ3*x) && (y <= 2*DIST2D+SQ3*x);
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementRedi.java b/src/main/java/org/distorted/objects/MovementRedi.java
index a5592087..e95e7d03 100644
--- a/src/main/java/org/distorted/objects/MovementRedi.java
+++ b/src/main/java/org/distorted/objects/MovementRedi.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementRedi extends Movement
+class MovementRedi extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementRedi()
     {
-    super(TwistyRedi.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyRedi.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,13 +35,6 @@ class MovementRedi extends Movement
     return offset<DIST2D ? 0:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // _____________
 // |  \  0  /  |
@@ -74,13 +53,6 @@ class MovementRedi extends Movement
     else      return p1 ? 1:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementRex.java b/src/main/java/org/distorted/objects/MovementRex.java
index daf82aad..69a2b073 100644
--- a/src/main/java/org/distorted/objects/MovementRex.java
+++ b/src/main/java/org/distorted/objects/MovementRex.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementRex extends Movement
+class MovementRex extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementRex()
     {
-    super(TwistyRex.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistyRex.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,13 +35,6 @@ class MovementRex extends Movement
     return offset<DIST2D ? 0:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // _____________
 // |  \  0  /  |
@@ -74,13 +53,6 @@ class MovementRex extends Movement
     else      return p1 ? 1:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementSkewb.java b/src/main/java/org/distorted/objects/MovementSkewb.java
index 977c42c6..4cc72ac7 100644
--- a/src/main/java/org/distorted/objects/MovementSkewb.java
+++ b/src/main/java/org/distorted/objects/MovementSkewb.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementSkewb extends Movement
+class MovementSkewb extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementSkewb()
     {
-    super(TwistySkewb.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistySkewb.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,13 +35,6 @@ class MovementSkewb extends Movement
     return offset<DIST2D ? 0:numLayers-1;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float returnRotationFactor(int numLayers, int row)
-    {
-    return 1.0f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // _____________
 // |  \  0  /  |
@@ -74,13 +53,6 @@ class MovementSkewb extends Movement
     else      return p1 ? 1:2;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean isInsideFace(int face, float[] p)
-    {
-    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
diff --git a/src/main/java/org/distorted/objects/MovementSquare.java b/src/main/java/org/distorted/objects/MovementSquare.java
index a74cd86f..a3f4f144 100644
--- a/src/main/java/org/distorted/objects/MovementSquare.java
+++ b/src/main/java/org/distorted/objects/MovementSquare.java
@@ -19,27 +19,13 @@
 
 package org.distorted.objects;
 
-import org.distorted.library.type.Static3D;
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class MovementSquare extends Movement
+class MovementSquare extends Movement6
 {
-  static final float DIST3D = 0.5f;
-  static final float DIST2D = 0.5f;
-
-  static final Static3D[] FACE_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0), new Static3D(-1,0,0),
-           new Static3D(0,1,0), new Static3D(0,-1,0),
-           new Static3D(0,0,1), new Static3D(0,0,-1)
-         };
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   MovementSquare()
     {
-    super(TwistySquare.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    super(TwistySquare.ROT_AXIS);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
