Project

General

Profile

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

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

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.SIN18;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

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

    
45
  private static final int NUM_CORNERS = 20;
46
  private static final int NUM_CENTERS = 12;
47
  private static final int NUM_EDGES   = 30;
48

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

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

    
105

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

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

    
118
  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
119

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

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

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

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

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

    
150
  private static MeshBase[] mCenterMeshes, mCornerMeshes;
151
  private static MeshBase[][] mEdgeMeshes;
152

    
153
  private static final Static4D[] mBasicCornerV, mCurrCornerV;
154

    
155
  static
156
    {
157
    mBasicCornerV = new Static4D[3];
158
    mCurrCornerV  = new Static4D[3];
159

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

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

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

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

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

    
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

    
182
  private int numCubitsPerEdge(int numLayers)
183
    {
184
    return numLayers-2;
185
    }
186

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

    
189
  int getNumStickerTypes(int numLayers)
190
    {
191
    return (numLayers+3)/2;
192
    }
193

    
194
///////////////////////////////////////////////////////////////////////////////////////////////////
195

    
196
  float[] getCuts(int numLayers)
197
    {
198
    float[] cuts = new float[numLayers-1];
199
    float D = (numLayers/3.0f)*MovementMinx.DIST3D;
200
    float E = 2*C1;           // 2*cos(36 deg)
201
    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
202
                              // its height is then 2*DIST3D, it has one 'lower' part of height X, one
203
                              // 'middle' part of height Y and one upper part of height X again.
204
                              // It's edge length = numLayers/3.0f.
205
    int num = (numLayers-1)/2;
206
    float G = X*(0.5f-MEGA_D)/num; // height of one Layer
207

    
208
    for(int i=0; i<num; i++)
209
      {
210
      cuts[        i] = -MovementMinx.DIST3D + (i+0.5f)*G;
211
      cuts[2*num-1-i] = -cuts[i];
212
      }
213

    
214
    return cuts;
215
    }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
  private void computeCenter(Static3D pos, int center, int numLayers)
220
    {
221
    float[] coords = mCenterCoords[center];
222
    float A = numLayers/3.0f;
223

    
224
    pos.set( A*coords[0], A*coords[1], A*coords[2] );
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
229
// Appropriate one: QUATS[QUAT_INDICES[corner]].
230

    
231
  private void computeBasicCornerVectors(int corner)
232
    {
233
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
234

    
235
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
236
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
237
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  private void computeCorner(Static3D pos, int numCubitsPerCorner, int numLayers, int corner, int part)
243
    {
244
    float D = numLayers/3.0f;
245
    Static3D corn = CORNERS[corner];
246

    
247
    if( part==0 )
248
      {
249
      pos.set( corn.get0()*D, corn.get1()*D, corn.get2()*D );
250
      }
251
    else
252
      {
253
      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
254
      int N = (numCubitsPerCorner-1)/3;
255
      int block = (part-1) % N;
256
      int index = (part-1) / N;
257
      Static4D pri = mCurrCornerV[index];
258
      Static4D sec = mCurrCornerV[(index+2)%3];
259

    
260
      int multP = (block % ((numLayers-3)/2)) + 1;
261
      int multS = (block / ((numLayers-3)/2));
262

    
263
      pos.set( corn.get0()*D + (pri.get0()*multP + sec.get0()*multS)*E,
264
               corn.get1()*D + (pri.get1()*multP + sec.get1()*multS)*E,
265
               corn.get2()*D + (pri.get2()*multP + sec.get2()*multS)*E );
266
      }
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

    
271
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
272
    {
273
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
274
    return (part+1)/2;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
280
    {
281
    float corr = numLayers/3.0f;
282

    
283
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
284
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
285
    float x = corr*(c1.get0() + c2.get0())/2;
286
    float y = corr*(c1.get1() + c2.get1())/2;
287
    float z = corr*(c1.get2() + c2.get2())/2;
288

    
289
    if( part==0 )
290
      {
291
      pos.set(x,y,z);
292
      }
293
    else
294
      {
295
      int mult = (part+1)/2;
296
      int dir  = (part+1)%2;
297
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
298

    
299
      float vX = corr*center[0] - x;
300
      float vY = corr*center[1] - y;
301
      float vZ = corr*center[2] - z;
302

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

    
306
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
307
      }
308
    }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311

    
312
  Static3D[] getCubitPositions(int numLayers)
313
    {
314
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
315
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
316
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
317
    int index=0;
318

    
319
    final Static3D[] CENTERS = new Static3D[numCubits];
320

    
321
    for(int corner=0; corner<NUM_CORNERS; corner++)
322
      {
323
      computeBasicCornerVectors(corner);
324

    
325
      for(int part=0; part<numCubitsPerCorner; part++, index++)
326
        {
327
        CENTERS[index] = new Static3D(0,0,0);
328
        computeCorner(CENTERS[index],numCubitsPerCorner,numLayers,corner,part);
329
        }
330
      }
331

    
332
    for(int edge=0; edge<NUM_EDGES; edge++)
333
      {
334
      for(int part=0; part<numCubitsPerEdge; part++, index++)
335
        {
336
        CENTERS[index] = new Static3D(0,0,0);
337
        computeEdge(CENTERS[index], numLayers, edge, part );
338
        }
339
      }
340

    
341
    for(int center=0; center<NUM_CENTERS; center++, index++)
342
      {
343
      CENTERS[index] = new Static3D(0,0,0);
344
      computeCenter(CENTERS[index], center, numLayers);
345
      }
346

    
347
    return CENTERS;
348
    }
349

    
350
///////////////////////////////////////////////////////////////////////////////////////////////////
351

    
352
  private int getQuat(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
353
    {
354
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
355
      {
356
      int corner = cubit/numCubitsPerCorner;
357
      return QUAT_CORNER_INDICES[corner];
358
      }
359

    
360
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
361
      {
362
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
363
      return QUAT_EDGE_INDICES[edge];
364
      }
365

    
366
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
367
    return QUAT_CENTER_INDICES[center];
368
    }
369

    
370
///////////////////////////////////////////////////////////////////////////////////////////////////
371

    
372
  MeshBase createCubitMesh(int cubit, int numLayers)
373
    {
374
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
375
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
376
    int index = (numLayers-3)/2;
377
    int[] sizes = ObjectList.MEGA.getSizes();
378
    int variants = sizes.length;
379
    MeshBase mesh;
380

    
381
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
382
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
383
    if( mCenterMeshes==null ) mCenterMeshes = new MeshBase[variants];
384

    
385
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
386
      {
387
      if( mCornerMeshes[index]==null )
388
        {
389
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
390
        }
391
      mesh = mCornerMeshes[index].copy(true);
392
      }
393
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
394
      {
395
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
396

    
397
      if( mEdgeMeshes[index][type]==null )
398
        {
399
        float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
400
        float width = (numLayers/3.0f)*2*MEGA_D + 2*type*height*SIN18/COS18;
401

    
402
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(width,height);
403
        }
404

    
405
      mesh = mEdgeMeshes[index][type].copy(true);
406
      }
407
    else
408
      {
409
      if( mCenterMeshes[index]==null )
410
        {
411
        float width = 2 * (numLayers/3.0f) * (MEGA_D+(0.5f-MEGA_D)*SIN18);
412
        mCenterMeshes[index] = FactoryCubit.getInstance().createMegaminxCenterMesh(width);
413
        }
414

    
415
      mesh = mCenterMeshes[index].copy(true);
416
      }
417

    
418
    Static4D q = QUATS[getQuat(cubit,numCubitsPerCorner,numCubitsPerEdge)];
419
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
420
    mesh.apply(quat,0xffffffff,0);
421

    
422
    return mesh;
423
    }
424

    
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426

    
427
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
428
    {
429
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES;
430

    
431
    int part  = cubit % numCubitsPerCorner;
432
    int corner= cubit / numCubitsPerCorner;
433

    
434
    if( part==0 )
435
      {
436
      return mCornerFaceMap[corner][cubitface];
437
      }
438
    else
439
      {
440
      int N = (numCubitsPerCorner-1)/3;
441
      int block = (part-1) % N;
442
      int index = (part-1) / N;
443

    
444
      if( block< (numLayers-3)/2 )
445
        {
446
        switch(index)
447
          {
448
          case 0: return cubitface==1 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
449
          case 1: return cubitface==0 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
450
          case 2: return cubitface==2 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
451
          }
452
        }
453
      else
454
        {
455
        switch(index)
456
          {
457
          case 0: return cubitface==0 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
458
          case 1: return cubitface==2 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
459
          case 2: return cubitface==1 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
460
          }
461
        }
462
      }
463

    
464
    return NUM_TEXTURES;
465
    }
466

    
467
///////////////////////////////////////////////////////////////////////////////////////////////////
468

    
469
  int getEdgeColor(int edge, int cubitface, int numCubitsPerEdge)
470
    {
471
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES;
472

    
473
    int part    = edge % numCubitsPerEdge;
474
    int variant = edge / numCubitsPerEdge;
475

    
476
    return (part==0 || cubitface==((part+1)%2)) ? mEdgeMap[variant][cubitface+2] + (part+1)*NUM_FACES : NUM_TEXTURES;
477
    }
478

    
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480

    
481
  int getCenterColor(int center, int cubitface, int numLayers)
482
    {
483
    return cubitface>0 ? NUM_TEXTURES : center + NUM_FACES*(numLayers+1)/2;
484
    }
485

    
486
///////////////////////////////////////////////////////////////////////////////////////////////////
487

    
488
  int getFaceColor(int cubit, int cubitface, int numLayers)
489
    {
490
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
491
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
492

    
493
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
494
      {
495
      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
496
      }
497
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
498
      {
499
      int edge = cubit - NUM_CORNERS*numCubitsPerCorner;
500
      return getEdgeColor(edge,cubitface,numCubitsPerEdge);
501
      }
502
    else
503
      {
504
      int center = cubit-NUM_CORNERS*numCubitsPerCorner-NUM_EDGES*numCubitsPerEdge;
505
      return getCenterColor( center, cubitface, numLayers);
506
      }
507
    }
508

    
509
///////////////////////////////////////////////////////////////////////////////////////////////////
510
// TODO
511

    
512
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
513
    {
514
    paint.setColor(FACE_COLORS[face%NUM_FACES]);
515
    paint.setStyle(Paint.Style.FILL);
516
    canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
517
    }
518

    
519
///////////////////////////////////////////////////////////////////////////////////////////////////
520
// PUBLIC API
521

    
522
  public boolean isSolved()
523
    {
524
    int index = CUBITS[0].mQuatIndex;
525

    
526
    for(int i=1; i<NUM_CUBITS; i++)
527
      {
528
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
529
      }
530

    
531
    return true;
532
    }
533

    
534
///////////////////////////////////////////////////////////////////////////////////////////////////
535
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
536
// then if it were rotated by quaternion 'quat'.
537
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
538
// middle squares get interchanged. No visible difference!
539
//
540
// So: this is true iff the cubit
541
// a) is a corner or edge and the quaternions are the same
542
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
543

    
544
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
545
    {
546
    if ( cubit.mQuatIndex == quatIndex ) return true;
547

    
548
    int belongsToHowManyFaces = 0;
549
    int lastLayer = getNumLayers()-1;
550
    float row;
551
    final float MAX_ERROR = 0.01f;
552

    
553
    for(int i=0; i<NUM_AXIS; i++)
554
      {
555
      row = cubit.mRotationRow[i];
556
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
557
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
558
      }
559

    
560
    switch(belongsToHowManyFaces)
561
      {
562
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
563
      case 1 :                // cubit that lies inside one of the faces
564
               Static3D orig = cubit.getOrigPosition();
565
               Static4D quat1 = QUATS[quatIndex];
566
               Static4D quat2 = QUATS[cubit.mQuatIndex];
567

    
568
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
569
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
570
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
571

    
572
               float row1, row2;
573
               float x1 = rotated1.get0();
574
               float y1 = rotated1.get1();
575
               float z1 = rotated1.get2();
576
               float x2 = rotated2.get0();
577
               float y2 = rotated2.get1();
578
               float z2 = rotated2.get2();
579

    
580
               for(int i=0; i<NUM_AXIS; i++)
581
                 {
582
                 row1 = computeRow(x1,y1,z1,i);
583
                 row2 = computeRow(x2,y2,z2,i);
584

    
585
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
586
                 }
587
               return false;
588

    
589
      default: return false;  // edge or corner
590
      }
591
    }
592

    
593
///////////////////////////////////////////////////////////////////////////////////////////////////
594

    
595
  public int getObjectName(int numLayers)
596
    {
597
    if( numLayers==3 ) return R.string.minx3;
598
    if( numLayers==5 ) return R.string.minx4;
599

    
600
    return 0;
601
    }
602

    
603
///////////////////////////////////////////////////////////////////////////////////////////////////
604

    
605
  public int getInventor(int numLayers)
606
    {
607
    if( numLayers==3 ) return R.string.minx3_inventor;
608
    if( numLayers==5 ) return R.string.minx4_inventor;
609

    
610
    return 0;
611
    }
612

    
613
///////////////////////////////////////////////////////////////////////////////////////////////////
614

    
615
  public int getComplexity(int numLayers)
616
    {
617
    if( numLayers==3 ) return 4;
618

    
619
    return 5;
620
    }
621
}
(24-24/30)