Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyMegaminx.java @ 722b2512

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
import static org.distorted.objects.FactoryCubit.COS18;
37
import static org.distorted.objects.FactoryCubit.COS54;
38
import static org.distorted.objects.FactoryCubit.SIN18;
39
import static org.distorted.objects.FactoryCubit.SIN54;
40

    
41
///////////////////////////////////////////////////////////////////////////////////////////////////
42

    
43
public class TwistyMegaminx extends TwistyMinx
44
{
45
  static final float MEGA_D = 0.04f;
46

    
47
  private static final int NUM_CORNERS = 20;
48
  private static final int NUM_CENTERS = 12;
49
  private static final int NUM_EDGES   = 30;
50

    
51
  // the five vertices that form a given face. Order: the same as colors
52
  // of the faces in TwistyMinx.
53
  private static final int[][] mCenterMap =
54
         {
55
           { 0, 12,  4, 14,  2},
56
           { 0,  2, 18,  6, 16},
57
           { 6, 18, 11, 19,  7},
58
           { 3, 15,  9, 11, 19},
59
           { 4,  5, 15,  9, 14},
60
           { 1, 13,  5, 15,  3},
61
           { 1,  3, 19,  7, 17},
62
           {10, 16,  6,  7, 17},
63
           { 0, 12,  8, 10, 16},
64
           { 8, 13,  5,  4, 12},
65
           { 1, 13,  8, 10, 17},
66
           { 2, 14,  9, 11, 18},
67
         };
68

    
69
  // the quadruple ( vertex1, vertex2, face1, face2 ) defining an edge.
70
  // In fact the 2 vertices already define it, the faces only provide easy
71
  // way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
72
  // the 'left' or right of vector vertex1 --> vertex2, according to Quat.
73
  private static final int[][] mEdgeMap =
74
         {
75
           {  0, 12,  0,  8},
76
           { 12,  4,  0,  9},
77
           {  4, 14,  0,  4},
78
           { 14,  2,  0, 11},
79
           {  2,  0,  0,  1},
80
           { 14,  9,  4, 11},
81
           {  9, 11,  3, 11},
82
           { 11, 18,  2, 11},
83
           { 18,  2,  1, 11},
84
           { 18,  6,  1,  2},
85
           {  6, 16,  1,  7},
86
           { 16,  0,  8,  1},
87
           { 16, 10,  7,  8},
88
           { 10,  8, 10,  8},
89
           {  8, 12,  9,  8},
90
           {  8, 13,  9, 10},
91
           { 13,  5,  9,  5},
92
           {  5,  4,  9,  4},
93
           {  5, 15,  5,  4},
94
           { 15,  9,  3,  4},
95
           { 11, 19,  2,  3},
96
           { 19,  7,  2,  6},
97
           {  7,  6,  2,  7},
98
           {  7, 17,  7,  6},
99
           { 17, 10,  7, 10},
100
           { 17,  1, 10,  6},
101
           {  1,  3,  5,  6},
102
           {  3, 19,  3,  6},
103
           {  1, 13, 10,  5},
104
           {  3, 15,  3,  5},
105
         };
106

    
107

    
108
  private static final int[] QUAT_EDGE_INDICES =
109
      {
110
        56, 40, 43, 59,  0, 55, 10, 17, 25, 49,
111
        48, 57, 18,  7, 53, 32, 20, 11, 31, 38,
112
        37, 30,  8, 28, 36, 44,  1, 46, 12, 14
113
      };
114

    
115
  private static final int[] QUAT_CENTER_INDICES =
116
      {
117
        16, 18, 22,  1, 20, 13, 14, 15,  0, 12,  2,  3
118
      };
119

    
120
  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
121

    
122
  static
123
    {
124
    for(int center=0; center<NUM_CENTERS; center++)
125
      {
126
      int[] map = mCenterMap[center];
127

    
128
      float x = CORNERS[map[0]].get0() +
129
                CORNERS[map[1]].get0() +
130
                CORNERS[map[2]].get0() +
131
                CORNERS[map[3]].get0() +
132
                CORNERS[map[4]].get0() ;
133

    
134
      float y = CORNERS[map[0]].get1() +
135
                CORNERS[map[1]].get1() +
136
                CORNERS[map[2]].get1() +
137
                CORNERS[map[3]].get1() +
138
                CORNERS[map[4]].get1() ;
139

    
140
      float z = CORNERS[map[0]].get2() +
141
                CORNERS[map[1]].get2() +
142
                CORNERS[map[2]].get2() +
143
                CORNERS[map[3]].get2() +
144
                CORNERS[map[4]].get2() ;
145

    
146
      mCenterCoords[center][0] = x/5;
147
      mCenterCoords[center][1] = y/5;
148
      mCenterCoords[center][2] = z/5;
149
      }
150
    }
151

    
152
  private static MeshBase[] mCenterMeshes, mCornerMeshes;
153
  private static MeshBase[][] mEdgeMeshes;
154

    
155
  private static final Static4D[] mBasicCornerV, mCurrCornerV;
156

    
157
  static
158
    {
159
    mBasicCornerV = new Static4D[3];
160
    mCurrCornerV  = new Static4D[3];
161

    
162
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
163
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
164
    mBasicCornerV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
165
    }
166

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

    
169
  TwistyMegaminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
170
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
171
    {
172
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.MEGA, res, scrWidth);
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  private int numCubitsPerCorner(int numLayers)
178
    {
179
    return 3*((numLayers-1)/2)*((numLayers-3)/2) + 1;
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  private int numCubitsPerEdge(int numLayers)
185
    {
186
    return numLayers-2;
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  float getScreenRatio()
192
    {
193
    return 1.07f;
194
    }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197

    
198
  int getNumStickerTypes(int numLayers)
199
    {
200
    return (numLayers+3)/2;
201
    }
202

    
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204

    
205
  float[] getCuts(int numLayers)
206
    {
207
    float[] cuts = new float[numLayers-1];
208
    float D = numLayers*MovementMinx.DIST3D;
209
    float E = 2*C1;           // 2*cos(36 deg)
210
    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
211
                              // its height is then D*2*DIST3D, it has one 'lower' part of height X, one
212
                              // 'middle' part of height Y and one upper part of height X again.
213
                              // It's edge length = numLayers/3.0f.
214
    int num = (numLayers-1)/2;
215
    float G = X*(0.5f-MEGA_D)/num; // height of one Layer
216

    
217
    for(int i=0; i<num; i++)
218
      {
219
      cuts[        i] = -D + (i+0.5f)*G;
220
      cuts[2*num-1-i] = -cuts[i];
221
      }
222

    
223
    return cuts;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private void computeCenter(Static3D pos, int center, int numLayers)
229
    {
230
    float[] coords = mCenterCoords[center];
231
    float A = numLayers/3.0f;
232

    
233
    pos.set( A*coords[0], A*coords[1], A*coords[2] );
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
238
// Appropriate one: QUATS[QUAT_INDICES[corner]].
239

    
240
  private void computeBasicCornerVectors(int corner)
241
    {
242
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
243

    
244
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
245
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
246
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

    
251
  private void computeCorner(Static3D pos, int numCubitsPerCorner, int numLayers, int corner, int part)
252
    {
253
    float D = numLayers/3.0f;
254
    Static3D corn = CORNERS[corner];
255

    
256
    if( part==0 )
257
      {
258
      pos.set( corn.get0()*D, corn.get1()*D, corn.get2()*D );
259
      }
260
    else
261
      {
262
      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
263
      int N = (numCubitsPerCorner-1)/3;
264
      int block = (part-1) % N;
265
      int index = (part-1) / N;
266
      Static4D pri = mCurrCornerV[index];
267
      Static4D sec = mCurrCornerV[(index+2)%3];
268

    
269
      int multP = (block % ((numLayers-3)/2)) + 1;
270
      int multS = (block / ((numLayers-3)/2));
271

    
272
      pos.set( corn.get0()*D + (pri.get0()*multP + sec.get0()*multS)*E,
273
               corn.get1()*D + (pri.get1()*multP + sec.get1()*multS)*E,
274
               corn.get2()*D + (pri.get2()*multP + sec.get2()*multS)*E );
275
      }
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
281
    {
282
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
283
    return (part+1)/2;
284
    }
285

    
286
///////////////////////////////////////////////////////////////////////////////////////////////////
287

    
288
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
289
    {
290
    float corr = numLayers/3.0f;
291

    
292
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
293
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
294
    float x = corr*(c1.get0() + c2.get0())/2;
295
    float y = corr*(c1.get1() + c2.get1())/2;
296
    float z = corr*(c1.get2() + c2.get2())/2;
297

    
298
    if( part==0 )
299
      {
300
      pos.set(x,y,z);
301
      }
302
    else
303
      {
304
      int mult = (part+1)/2;
305
      int dir  = (part+1)%2;
306
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
307

    
308
      float vX = corr*center[0] - x;
309
      float vY = corr*center[1] - y;
310
      float vZ = corr*center[2] - z;
311

    
312
      float len = (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
313
      float A = mult*corr*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f)/len;
314

    
315
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
316
      }
317
    }
318

    
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320

    
321
  Static3D[] getCubitPositions(int numLayers)
322
    {
323
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
324
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
325
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
326
    int index=0;
327

    
328
    final Static3D[] CENTERS = new Static3D[numCubits];
329

    
330
    for(int corner=0; corner<NUM_CORNERS; corner++)
331
      {
332
      computeBasicCornerVectors(corner);
333

    
334
      for(int part=0; part<numCubitsPerCorner; part++, index++)
335
        {
336
        CENTERS[index] = new Static3D(0,0,0);
337
        computeCorner(CENTERS[index],numCubitsPerCorner,numLayers,corner,part);
338
        }
339
      }
340

    
341
    for(int edge=0; edge<NUM_EDGES; edge++)
342
      {
343
      for(int part=0; part<numCubitsPerEdge; part++, index++)
344
        {
345
        CENTERS[index] = new Static3D(0,0,0);
346
        computeEdge(CENTERS[index], numLayers, edge, part );
347
        }
348
      }
349

    
350
    for(int center=0; center<NUM_CENTERS; center++, index++)
351
      {
352
      CENTERS[index] = new Static3D(0,0,0);
353
      computeCenter(CENTERS[index], center, numLayers);
354
      }
355

    
356
    return CENTERS;
357
    }
358

    
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360

    
361
  private int getQuat(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
362
    {
363
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
364
      {
365
      int corner = cubit/numCubitsPerCorner;
366
      return QUAT_CORNER_INDICES[corner];
367
      }
368

    
369
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
370
      {
371
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
372
      return QUAT_EDGE_INDICES[edge];
373
      }
374

    
375
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
376
    return QUAT_CENTER_INDICES[center];
377
    }
378

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380

    
381
  MeshBase createCubitMesh(int cubit, int numLayers)
382
    {
383
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
384
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
385
    int index = (numLayers-3)/2;
386
    int[] sizes = ObjectList.MEGA.getSizes();
387
    int variants = sizes.length;
388
    MeshBase mesh;
389

    
390
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
391
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
392
    if( mCenterMeshes==null ) mCenterMeshes = new MeshBase[variants];
393

    
394
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
395
      {
396
      if( mCornerMeshes[index]==null )
397
        {
398
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
399
        }
400
      mesh = mCornerMeshes[index].copy(true);
401
      }
402
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
403
      {
404
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
405

    
406
      if( mEdgeMeshes[index][type]==null )
407
        {
408
        float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
409
        float width = (numLayers/3.0f)*2*MEGA_D + 2*type*height*SIN18/COS18;
410

    
411
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(numLayers,width,height);
412
        }
413

    
414
      mesh = mEdgeMeshes[index][type].copy(true);
415
      }
416
    else
417
      {
418
      if( mCenterMeshes[index]==null )
419
        {
420
        float width = 2 * (numLayers/3.0f) * (MEGA_D+(0.5f-MEGA_D)*SIN18);
421
        mCenterMeshes[index] = FactoryCubit.getInstance().createMegaminxCenterMesh(numLayers,width);
422
        }
423

    
424
      mesh = mCenterMeshes[index].copy(true);
425
      }
426

    
427
    Static4D q = QUATS[getQuat(cubit,numCubitsPerCorner,numCubitsPerEdge)];
428
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
429
    mesh.apply(quat,0xffffffff,0);
430

    
431
    return mesh;
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

    
436
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
437
    {
438
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES;
439

    
440
    int part  = cubit % numCubitsPerCorner;
441
    int corner= cubit / numCubitsPerCorner;
442

    
443
    if( part==0 )
444
      {
445
      return mCornerFaceMap[corner][cubitface];
446
      }
447
    else
448
      {
449
      int N = (numCubitsPerCorner-1)/3;
450
      int block = (part-1) % N;
451
      int index = (part-1) / N;
452

    
453
      if( block< (numLayers-3)/2 )
454
        {
455
        switch(index)
456
          {
457
          case 0: return cubitface==1 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
458
          case 1: return cubitface==0 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
459
          case 2: return cubitface==2 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
460
          }
461
        }
462
      else
463
        {
464
        switch(index)
465
          {
466
          case 0: return cubitface==0 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
467
          case 1: return cubitface==2 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
468
          case 2: return cubitface==1 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
469
          }
470
        }
471
      }
472

    
473
    return NUM_TEXTURES;
474
    }
475

    
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477

    
478
  int getEdgeColor(int edge, int cubitface, int numCubitsPerEdge)
479
    {
480
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES;
481

    
482
    int part    = edge % numCubitsPerEdge;
483
    int variant = edge / numCubitsPerEdge;
484

    
485
    return (part==0 || cubitface==((part+1)%2)) ? mEdgeMap[variant][cubitface+2] + ((part+3)/2)*NUM_FACES : NUM_TEXTURES;
486
    }
487

    
488
///////////////////////////////////////////////////////////////////////////////////////////////////
489

    
490
  int getCenterColor(int center, int cubitface, int numLayers)
491
    {
492
    return cubitface>0 ? NUM_TEXTURES : center + NUM_FACES*(numLayers+1)/2;
493
    }
494

    
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496

    
497
  int getFaceColor(int cubit, int cubitface, int numLayers)
498
    {
499
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
500
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
501

    
502
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
503
      {
504
      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
505
      }
506
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
507
      {
508
      int edge = cubit - NUM_CORNERS*numCubitsPerCorner;
509
      return getEdgeColor(edge,cubitface,numCubitsPerEdge);
510
      }
511
    else
512
      {
513
      int center = cubit-NUM_CORNERS*numCubitsPerCorner-NUM_EDGES*numCubitsPerEdge;
514
      return getCenterColor( center, cubitface, numLayers);
515
      }
516
    }
517

    
518
///////////////////////////////////////////////////////////////////////////////////////////////////
519

    
520
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
521
    {
522
    int COLORS = FACE_COLORS.length;
523
    float R,S;
524
    float[] vertices;
525

    
526
    int variant = face/COLORS;
527

    
528
    if( variant==0 )
529
      {
530
      float Y = COS54/(2*SIN54);
531
      R = 0.070f;
532
      S = 0.08f;
533
      vertices = new float[] { -0.5f, 0.0f, 0.0f, -Y, 0.5f, 0.0f, 0.0f, Y };
534
      }
535
    else
536
      {
537
      int numLayers = getNumLayers();
538
      float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
539
      float W = height*SIN18/COS18;
540
      float width = (numLayers/3.0f)*2*MEGA_D + 2*(variant-1)*W;
541

    
542
      if( variant < (numLayers+1)/2 )
543
        {
544
        float X1 = 0.5f*height;
545
        float Y1 = 0.5f*width;
546
        float Y2 = 0.5f*width + W;
547

    
548
        R = 0.05f;
549
        S = 0.07f;
550
        vertices = new float[] { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
551
        }
552
      else
553
        {
554
        float Z  = 0.5f;
555
        float X1 = Z*COS54;
556
        float Y1 = Z*SIN54;
557
        float X2 = Z*COS18;
558
        float Y2 = Z*SIN18;
559

    
560
        R = 0.10f;
561
        S = 0.08f;
562
        vertices = new float[] { -X1,+Y1, -X2,-Y2, 0.0f,-Z, +X2,-Y2, +X1,+Y1 };
563
        }
564
      }
565

    
566
    FactorySticker factory = FactorySticker.getInstance();
567
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face%COLORS], R);
568
    }
569

    
570
///////////////////////////////////////////////////////////////////////////////////////////////////
571
// PUBLIC API
572

    
573
  public boolean isSolved()
574
    {
575
    int index = CUBITS[0].mQuatIndex;
576

    
577
    for(int i=1; i<NUM_CUBITS; i++)
578
      {
579
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
580
      }
581

    
582
    return true;
583
    }
584

    
585
///////////////////////////////////////////////////////////////////////////////////////////////////
586

    
587
  public int getObjectName(int numLayers)
588
    {
589
    if( numLayers==3 ) return R.string.minx3;
590
    if( numLayers==5 ) return R.string.minx4;
591

    
592
    return 0;
593
    }
594

    
595
///////////////////////////////////////////////////////////////////////////////////////////////////
596

    
597
  public int getInventor(int numLayers)
598
    {
599
    if( numLayers==3 ) return R.string.minx3_inventor;
600
    if( numLayers==5 ) return R.string.minx4_inventor;
601

    
602
    return 0;
603
    }
604

    
605
///////////////////////////////////////////////////////////////////////////////////////////////////
606

    
607
  public int getComplexity(int numLayers)
608
    {
609
    if( numLayers==3 ) return 4;
610

    
611
    return 5;
612
    }
613
}
(29-29/35)