commit 31cd725613d0cffc6af6dfcd8ec02f6910c466ee
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Apr 14 22:09:59 2021 +0200

    Convert the second and third object, the Pyraminx and the Diamond, to the new Cubit-creating engine.

diff --git a/src/main/java/org/distorted/helpers/FactoryCubit.java b/src/main/java/org/distorted/helpers/FactoryCubit.java
index 5656b50c..bf46d529 100644
--- a/src/main/java/org/distorted/helpers/FactoryCubit.java
+++ b/src/main/java/org/distorted/helpers/FactoryCubit.java
@@ -89,7 +89,8 @@ public class FactoryCubit
     boolean flip;
     }
 
-  private static final ArrayList<FaceTransform> mFaceTransform = new ArrayList<>();
+  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
+  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
   private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -297,60 +298,6 @@ public class FactoryCubit
     return new MeshJoined(meshes);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesOcta()
-    {
-    MeshBase[] meshes = new MeshPolygon[8];
-
-    float E = 0.75f;
-    float F = 0.5f;
-    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
-    float[] bands = computeBands(0.05f,35,F,0.8f,6);
-
-    meshes[0] = new MeshPolygon(vertices, bands, 2,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[0].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-    meshes[4] = meshes[0].copy(true);
-    meshes[4].setEffectAssociation(0,16,0);
-    meshes[5] = meshes[0].copy(true);
-    meshes[5].setEffectAssociation(0,32,0);
-    meshes[6] = meshes[0].copy(true);
-    meshes[6].setEffectAssociation(0,64,0);
-    meshes[7] = meshes[0].copy(true);
-    meshes[7].setEffectAssociation(0,128,0);
-
-    return new MeshJoined(meshes);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createFacesTetra()
-    {
-    MeshBase[] meshes = new MeshBase[4];
-
-    float E = 0.75f;
-    float F = 0.5f;
-    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
-    float[] bands = computeBands(0.05f,35,F,0.8f,6);
-
-    meshes[0] = new MeshPolygon(vertices, bands, 2,2);
-    meshes[0].setEffectAssociation(0,1,0);
-    meshes[1] = meshes[0].copy(true);
-    meshes[1].setEffectAssociation(0,2,0);
-    meshes[2] = meshes[0].copy(true);
-    meshes[2].setEffectAssociation(0,4,0);
-    meshes[3] = meshes[0].copy(true);
-    meshes[3].setEffectAssociation(0,8,0);
-
-    return new MeshJoined(meshes);
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MeshBase createFacesDino()
@@ -971,73 +918,6 @@ public class FactoryCubit
     return effect;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsOcta()
-    {
-    Static1D alpha = new Static1D((float)(-(180/Math.PI)*Math.asin(SQ3/3)));
-    Static1D angle1= new Static1D( 90);
-    Static1D angle2= new Static1D(180);
-    Static1D angle3= new Static1D(270);
-    Static3D move1 = new Static3D(0,SQ2/2-SQ3/3,0);
-    Static3D axisX = new Static3D(1,0,0);
-    Static3D axisY = new Static3D(0,1,0);
-    Static3D cent0 = new Static3D(0,0,0);
-    Static3D cent1 = new Static3D(0,SQ2/2,0);
-    Static3D flipY = new Static3D( 1,-1, 1);
-    Static3D scale = new Static3D( 1, 2*SQ3/3, 1);
-
-    VertexEffect[] effect = new VertexEffect[7];
-
-    effect[0] = new VertexEffectScale(scale);
-    effect[1] = new VertexEffectMove(move1);
-    effect[2] = new VertexEffectRotate(alpha , axisX, cent1);
-    effect[3] = new VertexEffectRotate(angle1, axisY, cent0);
-    effect[4] = new VertexEffectRotate(angle2, axisY, cent0);
-    effect[5] = new VertexEffectRotate(angle3, axisY, cent0);
-    effect[6] = new VertexEffectScale(flipY);
-
-    effect[3].setMeshAssociation ( 34,-1); // apply to meshes 1 & 5
-    effect[4].setMeshAssociation ( 68,-1); // apply to meshes 2 & 6
-    effect[5].setMeshAssociation (136,-1); // apply to meshes 3 & 7
-    effect[6].setMeshAssociation (240,-1); // apply to meshes 4,5,6,7
-
-    return effect;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  VertexEffect[] createVertexEffectsTetra()
-    {
-    Static3D flipZ = new Static3D( 1, 1,-1);
-    Static1D alpha = new Static1D((float)(-(180/Math.PI)*Math.asin(SQ3/3)));
-    Static1D angle1= new Static1D( 90);
-    Static1D angle2= new Static1D(180);
-    Static3D move1 = new Static3D(0,SQ2/4-SQ3/6,0);
-    Static3D axisX = new Static3D(1,0,0);
-    Static3D axisY = new Static3D(0,1,0);
-    Static3D axisZ = new Static3D(0,0,1);
-    Static3D cent0 = new Static3D(0,0,0);
-    Static3D cent1 = new Static3D(0,SQ2/4,0);
-    Static3D scale = new Static3D( 1, 2*SQ3/3, 1);
-
-    VertexEffect[] effect = new VertexEffect[7];
-
-    effect[0] = new VertexEffectScale(scale);
-    effect[1] = new VertexEffectRotate(angle2, axisZ, cent0);
-    effect[2] = new VertexEffectMove(move1);
-    effect[3] = new VertexEffectRotate(alpha , axisX, cent1);
-    effect[4] = new VertexEffectScale(flipZ);
-    effect[5] = new VertexEffectRotate(angle1, axisY, cent0);
-    effect[6] = new VertexEffectRotate(angle2, axisZ, cent0);
-
-    effect[4].setMeshAssociation(10,-1); // meshes 1 & 3
-    effect[5].setMeshAssociation(12,-1); // meshes 2 & 3
-    effect[6].setMeshAssociation(12,-1); // meshes 2 & 3
-
-    return effect;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   VertexEffect[] createVertexEffectsDino()
@@ -1708,56 +1588,6 @@ public class FactoryCubit
     return mesh;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// SKEWB DIAMOND / PYRAMINX
-
-  public MeshBase createOctaMesh()
-    {
-    MeshBase mesh = createFacesOcta();
-    VertexEffect[] effects = createVertexEffectsOcta();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D roundingCenter = new Static3D(0,0,0);
-    Static3D[] vertices = new Static3D[6];
-    vertices[0] = new Static3D(    0, SQ2/2,    0 );
-    vertices[1] = new Static3D( 0.5f,     0, 0.5f );
-    vertices[2] = new Static3D(-0.5f,     0, 0.5f );
-    vertices[3] = new Static3D(    0,-SQ2/2,    0 );
-    vertices[4] = new Static3D(-0.5f,     0,-0.5f );
-    vertices[5] = new Static3D( 0.5f,     0,-0.5f );
-
-    roundCorners(mesh,roundingCenter,vertices,0.06f,0.20f);
-
-    mesh.mergeEffComponents();
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public MeshBase createTetraMesh()
-    {
-    MeshBase mesh = createFacesTetra();
-    VertexEffect[] effects = createVertexEffectsTetra();
-    for( VertexEffect effect : effects ) mesh.apply(effect);
-
-    Static3D roundingCenter = new Static3D(0,0,0);
-    Static3D[] verticesRound = new Static3D[4];
-    verticesRound[0] = new Static3D(-0.5f,+SQ2/4,   0 );
-    verticesRound[1] = new Static3D(+0.5f,+SQ2/4,   0 );
-    verticesRound[2] = new Static3D(    0,-SQ2/4,+0.5f);
-    verticesRound[3] = new Static3D(    0,-SQ2/4,-0.5f);
-    roundCorners(mesh,roundingCenter,verticesRound,0.08f,0.15f);
-
-    mesh.mergeEffComponents();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-    mesh.addEmptyTexComponent();
-
-    return mesh;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // DINO
 
@@ -2277,31 +2107,33 @@ public class FactoryCubit
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void constructNew(FaceTransform info, final double[][] vert3D)
+  private FaceTransform constructNewTransform(final double[][] vert3D)
     {
+    FaceTransform ft = new FaceTransform();
+
     // compute center of gravity
-    info.vx = 0.0f;
-    info.vy = 0.0f;
-    info.vz = 0.0f;
+    ft.vx = 0.0f;
+    ft.vy = 0.0f;
+    ft.vz = 0.0f;
     int len = vert3D.length;
 
     for (double[] vert : vert3D)
       {
-      info.vx += vert[0];
-      info.vy += vert[1];
-      info.vz += vert[2];
+      ft.vx += vert[0];
+      ft.vy += vert[1];
+      ft.vz += vert[2];
       }
 
-    info.vx /= len;
-    info.vy /= len;
-    info.vz /= len;
+    ft.vx /= len;
+    ft.vy /= len;
+    ft.vz /= len;
 
     // move all vertices so that their center of gravity is at (0,0,0)
     for (int i=0; i<len; i++)
       {
-      vert3D[i][0] -= info.vx;
-      vert3D[i][1] -= info.vy;
-      vert3D[i][2] -= info.vz;
+      vert3D[i][0] -= ft.vx;
+      vert3D[i][1] -= ft.vy;
+      vert3D[i][2] -= ft.vz;
       }
 
     // find 3 non-colinear vertices
@@ -2367,13 +2199,15 @@ public class FactoryCubit
       }
 
     // fit the whole thing in a square and remember the scale & 2D vertices
-    fitInSquare(info, vert3D);
+    fitInSquare(ft, vert3D);
 
     // remember the rotation
-    info.qx =-mQuat1[0];
-    info.qy =-mQuat1[1];
-    info.qz =-mQuat1[2];
-    info.qw = mQuat1[3];
+    ft.qx =-mQuat1[0];
+    ft.qy =-mQuat1[1];
+    ft.qz =-mQuat1[2];
+    ft.qw = mQuat1[3];
+
+    return ft;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2421,6 +2255,7 @@ public class FactoryCubit
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// valid for 0<angle<2*PI
 
   private double computeSinHalf(double cos)
     {
@@ -2428,6 +2263,7 @@ public class FactoryCubit
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// valid for 0<angle<2*PI
 
   private double computeCosHalf(double sin, double cos)
     {
@@ -2681,6 +2517,14 @@ android.util.Log.e("D", "vertex: "+v+" CENTER: "+center.get0()+" "+center.get1()
     for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void printTransform(FaceTransform f)
+    {
+    android.util.Log.e("D", "q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
+                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC
 
@@ -2713,16 +2557,22 @@ android.util.Log.e("D", "vertex: "+v+" CENTER: "+center.get0()+" "+center.get1()
 
   public void printFaceTransform()
     {
-    android.util.Log.d("D", "---- FACE TRANSFORM ---");
+    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
 
-    int faces = mFaceTransform.size();
+    int oldfaces = mOldFaceTransf.size();
 
-    for(int f=0; f<faces; f++)
+    for(int f=0; f<oldfaces; f++)
       {
-      FaceTransform info = mFaceTransform.get(f);
+      printTransform(mOldFaceTransf.get(f));
+      }
+
+    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
+
+    int newfaces = mNewFaceTransf.size();
 
-      android.util.Log.e("D", "q=("+info.qx+", "+info.qy+", "+info.qz+", "+info.qw+") v=("
-                       +info.vx+", "+info.vy+", "+info.vz+") scale="+info.scale+" sticker="+info.sticker);
+    for(int f=0; f<newfaces; f++)
+      {
+      printTransform(mNewFaceTransf.get(f));
       }
     }
 
@@ -2731,32 +2581,46 @@ android.util.Log.e("D", "vertex: "+v+" CENTER: "+center.get0()+" "+center.get1()
   public void clear()
     {
     mStickerCoords.clear();
-    mFaceTransform.clear();
+    mNewFaceTransf.clear();
+    mOldFaceTransf.clear();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void createNewFaceTransform( final double[][] vertices, final int[][] indexes)
     {
-    mFaceTransform.clear();
+    FaceTransform ft;
+    int numNew = mNewFaceTransf.size();
+
+    for(int i=0; i<numNew; i++)
+      {
+      ft = mNewFaceTransf.remove(0);
+      mOldFaceTransf.add(ft);
+      }
 
     int numFaces = indexes.length;
-    FaceTransform oldInfo;
+    int numOld = mOldFaceTransf.size();
 
-    for(int face=0; face<numFaces; face++)
+    for (int face=0; face<numFaces; face++)
       {
-      FaceTransform newInfo = new FaceTransform();
-      int[] index = indexes[face];
-      double[][] vert = constructVert(vertices,index);
-      constructNew(newInfo,vert);
+      boolean collapsed = false;
+
+      double[][] vert = constructVert(vertices, indexes[face]);
+      FaceTransform newT = constructNewTransform(vert);
+
+      for (int old=0; !collapsed && old<numOld; old++)
+        {
+        ft = mOldFaceTransf.get(old);
+        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
+        }
 
-      for(int previous=0; previous<face; previous++)
+      for (int pre=0; !collapsed && pre<face; pre++)
         {
-        oldInfo = mFaceTransform.get(previous);
-        if( successfullyCollapsedStickers(newInfo,oldInfo) ) break;
+        ft = mNewFaceTransf.get(pre);
+        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
         }
 
-      mFaceTransform.add(newInfo);
+      mNewFaceTransf.add(newT);
       }
     }
 
@@ -2775,7 +2639,7 @@ android.util.Log.e("D", "vertex: "+v+" CENTER: "+center.get0()+" "+center.get1()
 
     for(int face=0; face<numFaces; face++)
       {
-      fInfo = mFaceTransform.get(face);
+      fInfo = mNewFaceTransf.get(face);
       sInfo = mStickerCoords.get(fInfo.sticker);
 
       double[] verts = sInfo.vertices;
@@ -2795,7 +2659,7 @@ android.util.Log.e("D", "vertex: "+v+" CENTER: "+center.get0()+" "+center.get1()
     for(int face=0; face<numFaces; face++)
       {
       int assoc = (1<<face);
-      fInfo = mFaceTransform.get(face);
+      fInfo = mNewFaceTransf.get(face);
 
       float vx = (float)fInfo.vx;
       float vy = (float)fInfo.vy;
diff --git a/src/main/java/org/distorted/objects/TwistyDiamond.java b/src/main/java/org/distorted/objects/TwistyDiamond.java
index 416216eb..04fcdb9e 100644
--- a/src/main/java/org/distorted/objects/TwistyDiamond.java
+++ b/src/main/java/org/distorted/objects/TwistyDiamond.java
@@ -94,7 +94,7 @@ public class TwistyDiamond extends TwistyObject
 
   private static final int[] mTetraToFaceMap = new int[] {1,2,3,0,5,6,7,4};
 
-  private final double[][] VERTICES_TETRA = new double[][]
+  private static final double[][] VERTICES_TETRA = new double[][]
           {
              {-0.5, SQ2/4, 0.0},
              { 0.5, SQ2/4, 0.0},
@@ -102,7 +102,7 @@ public class TwistyDiamond extends TwistyObject
              { 0.0,-SQ2/4,-0.5}
           };
 
-  private final int[][] VERT_INDEXES_TETRA = new int[][]
+  private static final int[][] VERT_INDEXES_TETRA = new int[][]
           {
              {2,1,0},   // counterclockwise!
              {2,3,1},
@@ -110,7 +110,7 @@ public class TwistyDiamond extends TwistyObject
              {3,0,1}
           };
 
-  private final double[][] VERTICES_OCTA = new double[][]
+  private static final double[][] VERTICES_OCTA = new double[][]
           {
              { 0.5,   0.0, 0.5},
              { 0.5,   0.0,-0.5},
@@ -120,7 +120,7 @@ public class TwistyDiamond extends TwistyObject
              { 0.0,-SQ2/2, 0.0}
           };
 
-  private final int[][] VERT_INDEXES_OCTA = new int[][]
+  private static final int[][] VERT_INDEXES_OCTA = new int[][]
           {
              {3,0,4},   // counterclockwise!
              {0,1,4},
@@ -132,7 +132,12 @@ public class TwistyDiamond extends TwistyObject
              {5,3,2}
           };
 
-  private static MeshBase mOctaMesh, mTetraMesh;
+  private static final float[][] STICKERS = new float[][]
+          {
+             { -0.4330127f, -0.25f, 0.4330127f, -0.25f, 0.0f, 0.5f }
+          };
+
+  private static MeshBase[] mMeshes;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -146,15 +151,8 @@ public class TwistyDiamond extends TwistyObject
 
   double[][] getVertices(int cubitType)
     {
-    if( cubitType==0 )  // Tetrahedron
-      {
-      return VERTICES_TETRA;
-      }
-    if( cubitType==1 )  // Octahedron
-      {
-      return VERTICES_OCTA;
-      }
-
+    if( cubitType==0 ) return VERTICES_OCTA;
+    if( cubitType==1 ) return VERTICES_TETRA;
     return null;
     }
 
@@ -162,15 +160,8 @@ public class TwistyDiamond extends TwistyObject
 
   int[][] getVertIndexes(int cubitType)
     {
-    if( cubitType==0 )  // Tetrahedron
-      {
-      return VERT_INDEXES_TETRA;
-      }
-    if( cubitType==1 )  // Octahedron
-      {
-      return VERT_INDEXES_OCTA;
-      }
-
+    if( cubitType==0 ) return VERT_INDEXES_OCTA;
+    if( cubitType==1 ) return VERT_INDEXES_TETRA;
     return null;
     }
 
@@ -213,7 +204,7 @@ public class TwistyDiamond extends TwistyObject
 
   int getNumStickerTypes(int numLayers)
     {
-    return 1;
+    return STICKERS.length;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -263,7 +254,7 @@ public class TwistyDiamond extends TwistyObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private int createOctahedrons(float[][] centers, int index, int layers, float height)
+  private int createOctaPositions(float[][] centers, int index, int layers, float height)
     {
     float x = DIST*(layers-1);
     float z = DIST*(layers+1);
@@ -305,7 +296,7 @@ public class TwistyDiamond extends TwistyObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private int createTetrahedrons(float[][] centers, int index, int layers, float height)
+  private int createTetraPositions(float[][] centers, int index, int layers, float height)
     {
     float x = DIST*(layers-1);
     float z = DIST*layers;
@@ -365,21 +356,21 @@ public class TwistyDiamond extends TwistyObject
 
     float[][] CENTERS = new float[numO+numT][3];
 
-    index = createOctahedrons(CENTERS,index,layers,height);
+    index = createOctaPositions(CENTERS,index,layers,height);
 
     for(int i=layers-1; i>0; i--)
       {
       height += SQ2*DIST;
-      index = createOctahedrons(CENTERS,index,i,+height);
-      index = createOctahedrons(CENTERS,index,i,-height);
+      index = createOctaPositions(CENTERS,index,i,+height);
+      index = createOctaPositions(CENTERS,index,i,-height);
       }
 
     height = DIST*SQ2/2;
 
     for(int i=layers; i>1; i--)
       {
-      index = createTetrahedrons(CENTERS,index,i,+height);
-      index = createTetrahedrons(CENTERS,index,i,-height);
+      index = createTetraPositions(CENTERS,index,i,+height);
+      index = createTetraPositions(CENTERS,index,i,-height);
       height += SQ2*DIST;
       }
 
@@ -424,18 +415,53 @@ public class TwistyDiamond extends TwistyObject
 
   MeshBase createCubitMesh(int cubit, int numLayers)
     {
+    if( mMeshes==null )
+      {
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.clear();
+      mMeshes = new MeshBase[2];
+      }
+
     MeshBase mesh;
     int numO = getNumOctahedrons(numLayers);
 
     if( cubit<numO )
       {
-      if( mOctaMesh==null ) mOctaMesh = FactoryCubit.getInstance().createOctaMesh();
-      mesh = mOctaMesh.copy(true);
+      if( mMeshes[0]==null )
+        {
+        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
+        int[] bandIndexes   = new int[] { 0,0,0,0,0,0,0,0 };
+        float[][] corners   = new float[][] { {0.04f,0.20f} };
+        int[] cornerIndexes = new int[] { 0,0,0,0,0,0 };
+
+        FactoryCubit factory = FactoryCubit.getInstance();
+
+        factory.createNewFaceTransform(VERTICES_OCTA,VERT_INDEXES_OCTA);
+        mMeshes[0] = factory.createRoundedSolid(VERTICES_OCTA, VERT_INDEXES_OCTA,
+                                                bands, bandIndexes,
+                                                corners, cornerIndexes,
+                                                getNumCubitFaces() );
+        }
+      mesh = mMeshes[0].copy(true);
       }
     else
       {
-      if( mTetraMesh==null ) mTetraMesh = FactoryCubit.getInstance().createTetraMesh();
-      mesh = mTetraMesh.copy(true);
+      if( mMeshes[1]==null )
+        {
+        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
+        int[] bandIndexes   = new int[] { 0,0,0,0 };
+        float[][] corners   = new float[][] { {0.08f,0.15f} };
+        int[] cornerIndexes = new int[] { 0,0,0,0 };
+
+        FactoryCubit factory = FactoryCubit.getInstance();
+
+        factory.createNewFaceTransform(VERTICES_TETRA,VERT_INDEXES_TETRA);
+        mMeshes[1] = factory.createRoundedSolid(VERTICES_TETRA, VERT_INDEXES_TETRA,
+                                                bands, bandIndexes,
+                                                corners, cornerIndexes,
+                                                getNumCubitFaces() );
+        }
+      mesh = mMeshes[1].copy(true);
       }
 
     Static4D sQ = getQuat(cubit,numLayers,numO);
@@ -480,14 +506,11 @@ public class TwistyDiamond extends TwistyObject
 
   void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
     {
-    float E = 0.75f;
-    float F = 0.50f;
     float R = 0.06f;
     float S = 0.07f;
-    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
 
     FactorySticker factory = FactorySticker.getInstance();
-    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
+    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistyObject.java b/src/main/java/org/distorted/objects/TwistyObject.java
index 1d353ae6..e05881ee 100644
--- a/src/main/java/org/distorted/objects/TwistyObject.java
+++ b/src/main/java/org/distorted/objects/TwistyObject.java
@@ -518,11 +518,10 @@ public abstract class TwistyObject extends DistortedNode
       {
       double[][] vertices = getVertices(cubit);
       int[][] vertIndices = getVertIndexes(cubit);
-
       factory.createNewFaceTransform(vertices,vertIndices);
-      factory.printFaceTransform();
       }
 
+    factory.printFaceTransform();
     factory.printStickerCoords();
     }
 
diff --git a/src/main/java/org/distorted/objects/TwistyPyraminx.java b/src/main/java/org/distorted/objects/TwistyPyraminx.java
index 67e846f1..0cb27b81 100644
--- a/src/main/java/org/distorted/objects/TwistyPyraminx.java
+++ b/src/main/java/org/distorted/objects/TwistyPyraminx.java
@@ -70,7 +70,7 @@ public class TwistyPyraminx extends TwistyObject
            new Static4D(-SQ2/2,   0.0f,  SQ2/2,  0.0f)
          };
 
-  private final double[][] VERTICES_TETRA = new double[][]
+  private static final double[][] VERTICES_TETRA = new double[][]
           {
              {-0.5, SQ2/4, 0.0},
              { 0.5, SQ2/4, 0.0},
@@ -78,15 +78,15 @@ public class TwistyPyraminx extends TwistyObject
              { 0.0,-SQ2/4,-0.5}
           };
 
-  private final int[][] VERT_INDEXES_TETRA = new int[][]
+  private static final int[][] VERT_INDEXES_TETRA = new int[][]
           {
              {2,1,0},   // counterclockwise!
-             {2,3,1},
+             {3,0,1},
              {3,2,0},
-             {3,0,1}
+             {2,3,1}
           };
 
-  private final double[][] VERTICES_OCTA = new double[][]
+  private static final double[][] VERTICES_OCTA = new double[][]
           {
              { 0.5,   0.0, 0.5},
              { 0.5,   0.0,-0.5},
@@ -96,7 +96,7 @@ public class TwistyPyraminx extends TwistyObject
              { 0.0,-SQ2/2, 0.0}
           };
 
-  private final int[][] VERT_INDEXES_OCTA = new int[][]
+  private static final int[][] VERT_INDEXES_OCTA = new int[][]
           {
              {3,0,4},   // counterclockwise!
              {0,1,4},
@@ -108,7 +108,12 @@ public class TwistyPyraminx extends TwistyObject
              {5,3,2}
           };
 
-  private static MeshBase mOctaMesh, mTetraMesh;
+  private static final float[][] STICKERS = new float[][]
+          {
+             { -0.4330127f, -0.25f, 0.4330127f, -0.25f, 0.0f, 0.5f }
+          };
+
+  private static MeshBase[] mMeshes;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -122,15 +127,8 @@ public class TwistyPyraminx extends TwistyObject
 
   double[][] getVertices(int cubitType)
     {
-    if( cubitType==0 )  // Tetrahedron
-      {
-      return VERTICES_TETRA;
-      }
-    if( cubitType==1 )  // Octahedron
-      {
-      return VERTICES_OCTA;
-      }
-
+    if( cubitType==0 ) return VERTICES_OCTA;
+    if( cubitType==1 ) return VERTICES_TETRA;
     return null;
     }
 
@@ -138,15 +136,8 @@ public class TwistyPyraminx extends TwistyObject
 
   int[][] getVertIndexes(int cubitType)
     {
-    if( cubitType==0 )  // Tetrahedron
-      {
-      return VERT_INDEXES_TETRA;
-      }
-    if( cubitType==1 )  // Octahedron
-      {
-      return VERT_INDEXES_OCTA;
-      }
-
+    if( cubitType==0 ) return VERT_INDEXES_OCTA;
+    if( cubitType==1 ) return VERT_INDEXES_TETRA;
     return null;
     }
 
@@ -227,7 +218,7 @@ public class TwistyPyraminx extends TwistyObject
 
   int getNumStickerTypes(int numLayers)
     {
-    return 1;
+    return STICKERS.length;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -265,6 +256,13 @@ public class TwistyPyraminx extends TwistyObject
     return false;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getNumOctahedrons(int numLayers)
+    {
+    return (numLayers-1)*numLayers*(numLayers+1)/6;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private int faceColor(int cubit, int axis)
@@ -297,30 +295,69 @@ public class TwistyPyraminx extends TwistyObject
 
   MeshBase createCubitMesh(int cubit, int numLayers)
     {
-    if( cubit< (numLayers-1)*numLayers*(numLayers+1)/6 )
+    if( mMeshes==null )
       {
-      if( mOctaMesh==null ) mOctaMesh = FactoryCubit.getInstance().createOctaMesh();
-      return mOctaMesh.copy(true);
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.clear();
+      mMeshes = new MeshBase[2];
+      }
+
+    MeshBase mesh;
+    int numO = getNumOctahedrons(numLayers);
+
+    if( cubit<numO )
+      {
+      if( mMeshes[0]==null )
+        {
+        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
+        int[] bandIndexes   = new int[] { 0,0,0,0,0,0,0,0 };
+        float[][] corners   = new float[][] { {0.04f,0.20f} };
+        int[] cornerIndexes = new int[] { 0,0,0,0,0,0 };
+
+        FactoryCubit factory = FactoryCubit.getInstance();
+
+        factory.createNewFaceTransform(VERTICES_OCTA,VERT_INDEXES_OCTA);
+        mMeshes[0] = factory.createRoundedSolid(VERTICES_OCTA, VERT_INDEXES_OCTA,
+                                                bands, bandIndexes,
+                                                corners, cornerIndexes,
+                                                getNumCubitFaces() );
+        }
+      mesh = mMeshes[0].copy(true);
       }
     else
       {
-      if( mTetraMesh==null ) mTetraMesh = FactoryCubit.getInstance().createTetraMesh();
-      return mTetraMesh.copy(true);
+      if( mMeshes[1]==null )
+        {
+        float[][] bands     = new float[][] { {0.05f,35,0.5f,0.8f,6,2,2} };
+        int[] bandIndexes   = new int[] { 0,0,0,0 };
+        float[][] corners   = new float[][] { {0.06f,0.15f} };
+        int[] cornerIndexes = new int[] { 0,0,0,0 };
+
+        FactoryCubit factory = FactoryCubit.getInstance();
+
+        factory.createNewFaceTransform(VERTICES_TETRA,VERT_INDEXES_TETRA);
+        mMeshes[1] = factory.createRoundedSolid(VERTICES_TETRA, VERT_INDEXES_TETRA,
+                                                bands, bandIndexes,
+                                                corners, cornerIndexes,
+                                                getNumCubitFaces() );
+
+        factory.printStickerCoords();
+        }
+      mesh = mMeshes[1].copy(true);
       }
+
+    return mesh;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
     {
-    float E = 0.75f;
-    float F = 0.50f;
     float R = 0.06f;
     float S = 0.08f;
-    float[] vertices = { -F,-E/3, +F,-E/3, 0.0f,2*E/3};
 
     FactorySticker factory = FactorySticker.getInstance();
-    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face], R);
+    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
