Project

General

Profile

Download (20.4 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / objects / TwistyMegaminx.java @ d38f1397

1 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19
20
package org.distorted.objects;
21
22
import android.content.res.Resources;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25
26
import org.distorted.library.effect.MatrixEffectQuaternion;
27
import org.distorted.library.main.DistortedEffects;
28
import org.distorted.library.main.DistortedTexture;
29
import org.distorted.library.mesh.MeshBase;
30
import org.distorted.library.mesh.MeshSquare;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33
import org.distorted.main.R;
34
import org.distorted.main.RubikSurfaceView;
35
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37
38
public class TwistyMegaminx extends TwistyMinx
39
{
40
  static final float MEGA_D = 0.05f;
41
42
  private static final int NUM_CORNERS = 20;
43
  private static final int NUM_CENTERS = 12;
44
  private static final int NUM_EDGES   = 30;
45
46 d38f1397 Leszek Koltunski
  // the five vertices that form a given face. Order: the same as colors
47
  // of the faces in TwistyMinx.
48
  private static final int[][] mCenterMap =
49 a64e07d0 Leszek Koltunski
         {
50
           { 0, 12,  4, 14,  2},
51
           { 0,  2, 18,  6, 16},
52
           { 6, 18, 11, 19,  7},
53
           { 3, 15,  9, 11, 19},
54 d38f1397 Leszek Koltunski
           { 4,  5, 15,  9, 14},
55
           { 1, 13,  5, 15,  3},
56 a64e07d0 Leszek Koltunski
           { 1,  3, 19,  7, 17},
57 d38f1397 Leszek Koltunski
           {10, 16,  6,  7, 17},
58
           { 0, 12,  8, 10, 16},
59
           { 8, 13,  5,  4, 12},
60
           { 1, 13,  8, 10, 17},
61
           { 2, 14,  9, 11, 18},
62 a64e07d0 Leszek Koltunski
         };
63
64 d38f1397 Leszek Koltunski
  // the quadruple ( vertex1, vertex2, face1, face2 ) defining an edge.
65
  // In fact the 2 vertices already define it, the faces only provide easy
66
  // way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
67
  // the 'left' or right of vector vertex1 --> vertex2, according to Quat.
68
  private static final int[][] mEdgeMap =
69
         {
70
           {  0, 12,  0,  8},
71
           { 12,  4,  0,  9},
72
           {  4, 14,  0,  4},
73
           { 14,  2,  0, 11},
74
           {  2,  0,  0,  1},
75
           { 14,  9,  4, 11},
76
           {  9, 11,  3, 11},
77
           { 11, 18,  2, 11},
78
           { 18,  2,  1, 11},
79
           { 18,  6,  2,  1},
80
           {  6, 16,  7,  1},
81
           { 16,  0,  8,  1},
82
           { 16, 10,  8,  7},
83
           { 10,  8,  8, 10},
84
           {  8, 12,  8,  9},
85
           {  8, 13,  9, 10},
86
           { 13,  5,  9,  5},
87
           {  5,  4,  9,  4},
88
           {  5, 15,  4,  5},
89
           { 15,  9,  4,  3},
90
           { 11, 19,  2,  3},
91
           { 19,  7,  2,  6},
92
           {  7,  6,  2,  7},
93
           {  7, 17,  7,  6},
94
           { 17, 10,  7, 10},
95
           { 17,  1,  6, 10},
96
           {  1,  3,  6,  4},
97
           {  3, 19,  6,  3},
98
           {  1, 13, 10,  5},
99
           {  3, 15,  5,  3},
100
         };
101 a64e07d0 Leszek Koltunski
102 d38f1397 Leszek Koltunski
  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
103 a64e07d0 Leszek Koltunski
104
  static
105
    {
106 d38f1397 Leszek Koltunski
    for(int center=0; center<NUM_CENTERS; center++)
107
      {
108
      int[] map = mCenterMap[center];
109
110
      float x = CORNERS[map[0]].get0() +
111
                CORNERS[map[1]].get0() +
112
                CORNERS[map[2]].get0() +
113
                CORNERS[map[3]].get0() +
114
                CORNERS[map[4]].get0() ;
115
116
      float y = CORNERS[map[0]].get1() +
117
                CORNERS[map[1]].get1() +
118
                CORNERS[map[2]].get1() +
119
                CORNERS[map[3]].get1() +
120
                CORNERS[map[4]].get1() ;
121
122
      float z = CORNERS[map[0]].get2() +
123
                CORNERS[map[1]].get2() +
124
                CORNERS[map[2]].get2() +
125
                CORNERS[map[3]].get2() +
126
                CORNERS[map[4]].get2() ;
127
128
      mCenterCoords[center][0] = x/5;
129
      mCenterCoords[center][1] = y/5;
130
      mCenterCoords[center][2] = z/5;
131
      }
132
    }
133
134
  private static MeshBase[] mCenterMeshes, mCornerMeshes;
135
  private static MeshBase[][] mEdgeMeshes;
136
137
  private static final Static4D[] mBasicCornerV, mCurrCornerV;
138 a64e07d0 Leszek Koltunski
139 d38f1397 Leszek Koltunski
  static
140
    {
141
    mBasicCornerV = new Static4D[3];
142
    mCurrCornerV  = new Static4D[3];
143
144
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
145
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
146
    mBasicCornerV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
147 a64e07d0 Leszek Koltunski
    };
148
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150
151
  TwistyMegaminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
152
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
153
    {
154
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.MEGA, res, scrWidth);
155
    }
156
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158
159
  private int numCubitsPerCorner(int numLayers)
160
    {
161
    return 3*((numLayers-1)/2)*((numLayers-3)/2) + 1;
162
    }
163
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165
166
  private int numCubitsPerEdge(int numLayers)
167
    {
168
    return numLayers-2;
169
    }
170
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172
173
  int getNumStickerTypes(int numLayers)
174
    {
175 d38f1397 Leszek Koltunski
    return numLayers-1; //numLayers;
176 a64e07d0 Leszek Koltunski
    }
177
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179
180
  float[] getCuts(int numLayers)
181
    {
182
    float[] cuts = new float[numLayers-1];
183
    float D = (numLayers/3.0f)*MovementMinx.DIST3D;
184
    float E = 2*C1;           // 2*cos(36 deg)
185
    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
186
                              // its height is then 2*DIST3D, it has one 'lower' part of height X, one
187
                              // 'middle' part of height Y and one upper part of height X again.
188
                              // It's edge length = numLayers/3.0f.
189
    int num = (numLayers-1)/2;
190
    float G = X*(0.5f-MEGA_D)/num; // height of one Layer
191
192
    for(int i=0; i<num; i++)
193
      {
194
      cuts[        i] = -MovementMinx.DIST3D + (i+0.5f)*G;
195
      cuts[2*num-1-i] = -cuts[i];
196
      }
197
198
    return cuts;
199
    }
200
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202
203
  private void computeCenter(Static3D[] array, int center)
204
    {
205 d38f1397 Leszek Koltunski
    float[] coords = mCenterCoords[center];
206
    array[center].set( coords[0], coords[1], coords[2]);
207 a64e07d0 Leszek Koltunski
    }
208
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210 d38f1397 Leszek Koltunski
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
211 a64e07d0 Leszek Koltunski
// Appropriate one: QUATS[QUAT_INDICES[corner]].
212
213 d38f1397 Leszek Koltunski
  private void computeBasicCornerVectors(int corner)
214 a64e07d0 Leszek Koltunski
    {
215 d38f1397 Leszek Koltunski
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
216 a64e07d0 Leszek Koltunski
217 d38f1397 Leszek Koltunski
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
218
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
219
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
220 a64e07d0 Leszek Koltunski
    }
221
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223
224
  private void computeCorner(Static3D pos, int numCubitsPerCorner, int numLayers, int corner, int part)
225
    {
226
    float D = numLayers/3.0f;
227
    Static3D corn = CORNERS[corner];
228
229
    if( part==0 )
230
      {
231
      pos.set( corn.get0()*D, corn.get1()*D, corn.get2()*D );
232
      }
233
    else
234
      {
235 28b54fe3 Leszek Koltunski
      float E = 2.0f*(numLayers/6.0f - MEGA_D)/(0.5f*(numLayers-1));
236 a64e07d0 Leszek Koltunski
      int N = (numCubitsPerCorner-1)/3;
237 6e7146df Leszek Koltunski
      int block = (part-1) % N;
238
      int index = (part-1) / N;
239 d38f1397 Leszek Koltunski
      Static4D pri = mCurrCornerV[index];
240
      Static4D sec = mCurrCornerV[(index+2)%3];
241 a64e07d0 Leszek Koltunski
242 6e7146df Leszek Koltunski
      int multP = (block % ((numLayers-3)/2)) + 1;
243
      int multS = (block / ((numLayers-3)/2));
244 a64e07d0 Leszek Koltunski
245
      pos.set( corn.get0()*D + (pri.get0()*multP + sec.get0()*multS)*E,
246
               corn.get1()*D + (pri.get1()*multP + sec.get1()*multS)*E,
247
               corn.get2()*D + (pri.get2()*multP + sec.get2()*multS)*E );
248
      }
249
    }
250
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252
253 d38f1397 Leszek Koltunski
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
254 a64e07d0 Leszek Koltunski
    {
255 d38f1397 Leszek Koltunski
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
256
    return (part+1)/2;
257
    }
258 a64e07d0 Leszek Koltunski
259 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
260
261
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
262
    {
263
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
264
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
265
    float x = (c1.get0() + c2.get0())/2;
266
    float y = (c1.get1() + c2.get1())/2;
267
    float z = (c1.get2() + c2.get2())/2;
268
269
    if( part==0 )
270
      {
271
      pos.set(x,y,z);
272
      }
273
    else
274
      {
275
      int mult = (part+1)/2;
276
      int dir  = (part+1)%2;
277
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
278
279
      float vX = center[0]-x;
280
      float vY = center[1]-y;
281
      float vZ = center[2]-z;
282
283
      float A = mult*(0.5f-MEGA_D)/((1+SQ5/5)*(numLayers-1));
284
285
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
286
      }
287 a64e07d0 Leszek Koltunski
    }
288
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290
291
  Static3D[] getCubitPositions(int numLayers)
292
    {
293
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
294 d38f1397 Leszek Koltunski
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
295
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge;// + NUM_CENTERS;
296 a64e07d0 Leszek Koltunski
    int index=0;
297
298
    final Static3D[] CENTERS = new Static3D[numCubits];
299
300
    for(int corner=0; corner<NUM_CORNERS; corner++)
301
      {
302 d38f1397 Leszek Koltunski
      computeBasicCornerVectors(corner);
303 a64e07d0 Leszek Koltunski
304
      for(int part=0; part<numCubitsPerCorner; part++, index++)
305
        {
306
        CENTERS[index] = new Static3D(0,0,0);
307
        computeCorner(CENTERS[index],numCubitsPerCorner,numLayers,corner,part);
308
        }
309
      }
310 d38f1397 Leszek Koltunski
311 a64e07d0 Leszek Koltunski
    for(int edge=0; edge<NUM_EDGES; edge++)
312
      {
313
      for(int part=0; part<numCubitsPerEdge; part++, index++)
314
        {
315 d38f1397 Leszek Koltunski
        CENTERS[index] = new Static3D(0,0,0);
316
        computeEdge(CENTERS[index], numLayers, edge, part );
317 a64e07d0 Leszek Koltunski
        }
318
      }
319 d38f1397 Leszek Koltunski
/*
320 a64e07d0 Leszek Koltunski
    for(int center=0; center<NUM_CENTERS; center++, index++)
321
      {
322
      computeCenter(CENTERS,index);
323
      }
324
*/
325
    return CENTERS;
326
    }
327
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329
330
  private int getQuat(int cubit, int numLayers)
331
    {
332
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
333
334
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
335
      {
336
      int corner = cubit/numCubitsPerCorner;
337 d38f1397 Leszek Koltunski
      return QUAT_CORNER_INDICES[corner];
338 a64e07d0 Leszek Koltunski
      }
339
340
    int numCubitsPerEdge = numCubitsPerEdge(numLayers);
341
342 d38f1397 Leszek Koltunski
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
343
      {
344
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
345
      return QUAT_EDGE_INDICES[edge];
346
      }
347
348
/*
349
    else
350
      {
351
      // TODO: centers
352
      }
353 a64e07d0 Leszek Koltunski
*/
354 d38f1397 Leszek Koltunski
355 a64e07d0 Leszek Koltunski
    return 0;
356
    }
357
358
///////////////////////////////////////////////////////////////////////////////////////////////////
359
360
  MeshBase createCubitMesh(int cubit, int numLayers)
361
    {
362
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
363
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
364 28b54fe3 Leszek Koltunski
    int index = (numLayers-3)/2;
365 d38f1397 Leszek Koltunski
    int variants = ObjectList.MEGA.getNumVariants();
366 a64e07d0 Leszek Koltunski
    MeshBase mesh;
367
368 d38f1397 Leszek Koltunski
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
369
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][index+1];
370 28b54fe3 Leszek Koltunski
371 d38f1397 Leszek Koltunski
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
372 a64e07d0 Leszek Koltunski
      {
373 d38f1397 Leszek Koltunski
      if( mCornerMeshes[index]==null )
374
        {
375
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
376
        }
377 28b54fe3 Leszek Koltunski
      mesh = mCornerMeshes[index].copy(true);
378 a64e07d0 Leszek Koltunski
      }
379 d38f1397 Leszek Koltunski
    else //if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
380 a64e07d0 Leszek Koltunski
      {
381 d38f1397 Leszek Koltunski
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
382
383
      if( mEdgeMeshes[index][type]==null )
384
        {
385
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(index,type);
386
        }
387
388
      mesh = mEdgeMeshes[index][type].copy(true);
389 a64e07d0 Leszek Koltunski
      }
390 d38f1397 Leszek Koltunski
/*
391 a64e07d0 Leszek Koltunski
    else
392
      {
393 d38f1397 Leszek Koltunski
      // TODO: centers
394 a64e07d0 Leszek Koltunski
      }
395
*/
396
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[getQuat(cubit,numLayers)], new Static3D(0,0,0) );
397
    mesh.apply(quat,0xffffffff,0);
398
399
    return mesh;
400
    }
401
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403
404 d38f1397 Leszek Koltunski
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
405 a64e07d0 Leszek Koltunski
    {
406 6e7146df Leszek Koltunski
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES*NUM_FACES;
407
408
    int part  = cubit % numCubitsPerCorner;
409 a64e07d0 Leszek Koltunski
    int corner= cubit / numCubitsPerCorner;
410
411 6e7146df Leszek Koltunski
    if( part==0 )
412 a64e07d0 Leszek Koltunski
      {
413 6e7146df Leszek Koltunski
      return mCornerFaceMap[corner][cubitface];
414 a64e07d0 Leszek Koltunski
      }
415
    else
416
      {
417
      int N = (numCubitsPerCorner-1)/3;
418 6e7146df Leszek Koltunski
      int block = (part-1) % N;
419
      int index = (part-1) / N;
420 a64e07d0 Leszek Koltunski
421 6e7146df Leszek Koltunski
      if( block< (numLayers-1)/2 )
422 a64e07d0 Leszek Koltunski
        {
423 6e7146df Leszek Koltunski
        switch(index)
424
          {
425
          case 0: return cubitface==1 ? NUM_TEXTURES*NUM_FACES : mCornerFaceMap[corner][cubitface];
426
          case 1: return cubitface==0 ? NUM_TEXTURES*NUM_FACES : mCornerFaceMap[corner][cubitface];
427
          case 2: return cubitface==2 ? NUM_TEXTURES*NUM_FACES : mCornerFaceMap[corner][cubitface];
428
          }
429 a64e07d0 Leszek Koltunski
        }
430
      else
431
        {
432 6e7146df Leszek Koltunski
        switch(index)
433
          {
434
          case 0: return cubitface==0 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES*NUM_FACES;
435
          case 1: return cubitface==2 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES*NUM_FACES;
436
          case 2: return cubitface==1 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES*NUM_FACES;
437
          }
438 a64e07d0 Leszek Koltunski
        }
439
      }
440 6e7146df Leszek Koltunski
441
    return NUM_TEXTURES*NUM_FACES;
442 a64e07d0 Leszek Koltunski
    }
443
444 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
445
446
  int getEdgeColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner, int numCubitsPerEdge)
447
    {
448
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES*NUM_FACES;
449
450
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
451
    int edge = (cubit - NUM_CORNERS*numCubitsPerCorner) / numCubitsPerEdge;
452
453
    if( part==0 )
454
      {
455
      return mEdgeMap[edge][cubitface+2];
456
      }
457
458
    return cubitface==((part+1)%2) ? mEdgeMap[edge][cubitface+2] : NUM_TEXTURES*NUM_FACES;
459
    }
460
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462
// TODO
463
464
  int getCenterColor(int cubit, int cubitface, int numLayers)
465
    {
466
    return 0;
467
    }
468
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470
471
  int getFaceColor(int cubit, int cubitface, int numLayers)
472
    {
473
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
474
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
475
476
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
477
      {
478
      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
479
      }
480
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
481
      {
482
      return getEdgeColor(cubit,cubitface,numLayers,numCubitsPerCorner,numCubitsPerEdge);
483
      }
484
    else
485
      {
486
      return getCenterColor(cubit,cubitface,numLayers);
487
      }
488
    }
489
490 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
491
// TODO
492
493
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
494
    {
495 d38f1397 Leszek Koltunski
    paint.setColor(FACE_COLORS[face%NUM_FACES]);
496 a64e07d0 Leszek Koltunski
    paint.setStyle(Paint.Style.FILL);
497
    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
498
    }
499
500
///////////////////////////////////////////////////////////////////////////////////////////////////
501
// PUBLIC API
502
503
  public boolean isSolved()
504
    {
505
    int index = CUBITS[0].mQuatIndex;
506
507
    for(int i=1; i<NUM_CUBITS; i++)
508
      {
509
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
510
      }
511
512
    return true;
513
    }
514
515
///////////////////////////////////////////////////////////////////////////////////////////////////
516
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
517
// then if it were rotated by quaternion 'quat'.
518
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
519
// middle squares get interchanged. No visible difference!
520
//
521
// So: this is true iff the cubit
522
// a) is a corner or edge and the quaternions are the same
523
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
524
525
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
526
    {
527
    if ( cubit.mQuatIndex == quatIndex ) return true;
528
529
    int belongsToHowManyFaces = 0;
530
    int lastLayer = getNumLayers()-1;
531
    float row;
532
    final float MAX_ERROR = 0.01f;
533
534
    for(int i=0; i<NUM_AXIS; i++)
535
      {
536
      row = cubit.mRotationRow[i];
537
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
538
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
539
      }
540
541
    switch(belongsToHowManyFaces)
542
      {
543
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
544
      case 1 :                // cubit that lies inside one of the faces
545
               Static3D orig = cubit.getOrigPosition();
546
               Static4D quat1 = QUATS[quatIndex];
547
               Static4D quat2 = QUATS[cubit.mQuatIndex];
548
549
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
550
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
551
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
552
553
               float row1, row2;
554
               float x1 = rotated1.get0();
555
               float y1 = rotated1.get1();
556
               float z1 = rotated1.get2();
557
               float x2 = rotated2.get0();
558
               float y2 = rotated2.get1();
559
               float z2 = rotated2.get2();
560
561
               for(int i=0; i<NUM_AXIS; i++)
562
                 {
563
                 row1 = computeRow(x1,y1,z1,i);
564
                 row2 = computeRow(x2,y2,z2,i);
565
566
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
567
                 }
568
               return false;
569
570
      default: return false;  // edge or corner
571
      }
572
    }
573
574
///////////////////////////////////////////////////////////////////////////////////////////////////
575
576
  public int getObjectName(int numLayers)
577
    {
578
    if( numLayers==3 ) return R.string.minx3;
579
    if( numLayers==5 ) return R.string.minx4;
580
581
    return 0;
582
    }
583
584
///////////////////////////////////////////////////////////////////////////////////////////////////
585
586
  public int getInventor(int numLayers)
587
    {
588
    if( numLayers==3 ) return R.string.minx3_inventor;
589
    if( numLayers==5 ) return R.string.minx4_inventor;
590
591
    return 0;
592
    }
593
594
///////////////////////////////////////////////////////////////////////////////////////////////////
595
596
  public int getComplexity(int numLayers)
597
    {
598
    if( numLayers==3 ) return 4;
599
600
    return 5;
601
    }
602
}