Project

General

Profile

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

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

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 3d8237cc Leszek Koltunski
import static org.distorted.objects.FactoryCubit.COS18;
37
import static org.distorted.objects.FactoryCubit.SIN18;
38
39 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
40
41
public class TwistyMegaminx extends TwistyMinx
42
{
43 e4bf4d02 Leszek Koltunski
  static final float MEGA_D = 0.04f;
44 a64e07d0 Leszek Koltunski
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 d38f1397 Leszek Koltunski
  // 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 a64e07d0 Leszek Koltunski
         {
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 d38f1397 Leszek Koltunski
           { 4,  5, 15,  9, 14},
58
           { 1, 13,  5, 15,  3},
59 a64e07d0 Leszek Koltunski
           { 1,  3, 19,  7, 17},
60 d38f1397 Leszek Koltunski
           {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 a64e07d0 Leszek Koltunski
         };
66
67 d38f1397 Leszek Koltunski
  // 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 3d8237cc Leszek Koltunski
           { 18,  6,  1,  2},
83
           {  6, 16,  1,  7},
84 d38f1397 Leszek Koltunski
           { 16,  0,  8,  1},
85 3d8237cc Leszek Koltunski
           { 16, 10,  7,  8},
86
           { 10,  8, 10,  8},
87
           {  8, 12,  9,  8},
88 d38f1397 Leszek Koltunski
           {  8, 13,  9, 10},
89
           { 13,  5,  9,  5},
90
           {  5,  4,  9,  4},
91 3d8237cc Leszek Koltunski
           {  5, 15,  5,  4},
92
           { 15,  9,  3,  4},
93 d38f1397 Leszek Koltunski
           { 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 3d8237cc Leszek Koltunski
           { 17,  1, 10,  6},
99
           {  1,  3,  5,  6},
100
           {  3, 19,  3,  6},
101 d38f1397 Leszek Koltunski
           {  1, 13, 10,  5},
102 3d8237cc Leszek Koltunski
           {  3, 15,  3,  5},
103 d38f1397 Leszek Koltunski
         };
104 a64e07d0 Leszek Koltunski
105 e4bf4d02 Leszek Koltunski
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 d38f1397 Leszek Koltunski
  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
119 a64e07d0 Leszek Koltunski
120
  static
121
    {
122 d38f1397 Leszek Koltunski
    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 a64e07d0 Leszek Koltunski
155 d38f1397 Leszek Koltunski
  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 a64e07d0 Leszek Koltunski
    };
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 e4bf4d02 Leszek Koltunski
    return (numLayers+3)/2;
192 a64e07d0 Leszek Koltunski
    }
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 e4bf4d02 Leszek Koltunski
  private void computeCenter(Static3D pos, int center, int numLayers)
220 a64e07d0 Leszek Koltunski
    {
221 d38f1397 Leszek Koltunski
    float[] coords = mCenterCoords[center];
222 e4bf4d02 Leszek Koltunski
    float A = numLayers/3.0f;
223
224
    pos.set( A*coords[0], A*coords[1], A*coords[2] );
225 a64e07d0 Leszek Koltunski
    }
226
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228 d38f1397 Leszek Koltunski
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
229 a64e07d0 Leszek Koltunski
// Appropriate one: QUATS[QUAT_INDICES[corner]].
230
231 d38f1397 Leszek Koltunski
  private void computeBasicCornerVectors(int corner)
232 a64e07d0 Leszek Koltunski
    {
233 d38f1397 Leszek Koltunski
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
234 a64e07d0 Leszek Koltunski
235 d38f1397 Leszek Koltunski
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
236
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
237
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
238 a64e07d0 Leszek Koltunski
    }
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 3d8237cc Leszek Koltunski
      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
254 a64e07d0 Leszek Koltunski
      int N = (numCubitsPerCorner-1)/3;
255 6e7146df Leszek Koltunski
      int block = (part-1) % N;
256
      int index = (part-1) / N;
257 d38f1397 Leszek Koltunski
      Static4D pri = mCurrCornerV[index];
258
      Static4D sec = mCurrCornerV[(index+2)%3];
259 a64e07d0 Leszek Koltunski
260 6e7146df Leszek Koltunski
      int multP = (block % ((numLayers-3)/2)) + 1;
261
      int multS = (block / ((numLayers-3)/2));
262 a64e07d0 Leszek Koltunski
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 d38f1397 Leszek Koltunski
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
272 a64e07d0 Leszek Koltunski
    {
273 d38f1397 Leszek Koltunski
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
274
    return (part+1)/2;
275
    }
276 a64e07d0 Leszek Koltunski
277 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
278
279
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
280
    {
281 3d8237cc Leszek Koltunski
    float corr = numLayers/3.0f;
282
283 d38f1397 Leszek Koltunski
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
284
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
285 3d8237cc Leszek Koltunski
    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 d38f1397 Leszek Koltunski
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 3d8237cc Leszek Koltunski
      float vX = corr*center[0] - x;
300
      float vY = corr*center[1] - y;
301
      float vZ = corr*center[2] - z;
302 d38f1397 Leszek Koltunski
303 3d8237cc Leszek Koltunski
      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 d38f1397 Leszek Koltunski
306
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
307
      }
308 a64e07d0 Leszek Koltunski
    }
309
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311
312
  Static3D[] getCubitPositions(int numLayers)
313
    {
314
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
315 d38f1397 Leszek Koltunski
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
316 e4bf4d02 Leszek Koltunski
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
317 a64e07d0 Leszek Koltunski
    int index=0;
318
319
    final Static3D[] CENTERS = new Static3D[numCubits];
320
321
    for(int corner=0; corner<NUM_CORNERS; corner++)
322
      {
323 d38f1397 Leszek Koltunski
      computeBasicCornerVectors(corner);
324 a64e07d0 Leszek Koltunski
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 d38f1397 Leszek Koltunski
332 a64e07d0 Leszek Koltunski
    for(int edge=0; edge<NUM_EDGES; edge++)
333
      {
334
      for(int part=0; part<numCubitsPerEdge; part++, index++)
335
        {
336 d38f1397 Leszek Koltunski
        CENTERS[index] = new Static3D(0,0,0);
337
        computeEdge(CENTERS[index], numLayers, edge, part );
338 a64e07d0 Leszek Koltunski
        }
339
      }
340 e4bf4d02 Leszek Koltunski
341 a64e07d0 Leszek Koltunski
    for(int center=0; center<NUM_CENTERS; center++, index++)
342
      {
343 e4bf4d02 Leszek Koltunski
      CENTERS[index] = new Static3D(0,0,0);
344
      computeCenter(CENTERS[index], center, numLayers);
345 a64e07d0 Leszek Koltunski
      }
346 e4bf4d02 Leszek Koltunski
347 a64e07d0 Leszek Koltunski
    return CENTERS;
348
    }
349
350
///////////////////////////////////////////////////////////////////////////////////////////////////
351
352 e4bf4d02 Leszek Koltunski
  private int getQuat(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
353 a64e07d0 Leszek Koltunski
    {
354
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
355
      {
356
      int corner = cubit/numCubitsPerCorner;
357 d38f1397 Leszek Koltunski
      return QUAT_CORNER_INDICES[corner];
358 a64e07d0 Leszek Koltunski
      }
359
360 d38f1397 Leszek Koltunski
    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 e4bf4d02 Leszek Koltunski
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
367
    return QUAT_CENTER_INDICES[center];
368 a64e07d0 Leszek Koltunski
    }
369
370
///////////////////////////////////////////////////////////////////////////////////////////////////
371
372
  MeshBase createCubitMesh(int cubit, int numLayers)
373
    {
374
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
375
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
376 28b54fe3 Leszek Koltunski
    int index = (numLayers-3)/2;
377 db608887 Leszek Koltunski
    int[] sizes = ObjectList.MEGA.getSizes();
378
    int variants = sizes.length;
379 a64e07d0 Leszek Koltunski
    MeshBase mesh;
380
381 d38f1397 Leszek Koltunski
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
382 db608887 Leszek Koltunski
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
383 e4bf4d02 Leszek Koltunski
    if( mCenterMeshes==null ) mCenterMeshes = new MeshBase[variants];
384 28b54fe3 Leszek Koltunski
385 d38f1397 Leszek Koltunski
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
386 a64e07d0 Leszek Koltunski
      {
387 d38f1397 Leszek Koltunski
      if( mCornerMeshes[index]==null )
388
        {
389
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
390
        }
391 28b54fe3 Leszek Koltunski
      mesh = mCornerMeshes[index].copy(true);
392 a64e07d0 Leszek Koltunski
      }
393 e4bf4d02 Leszek Koltunski
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
394 a64e07d0 Leszek Koltunski
      {
395 d38f1397 Leszek Koltunski
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
396
397
      if( mEdgeMeshes[index][type]==null )
398
        {
399 3d8237cc Leszek Koltunski
        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 d38f1397 Leszek Koltunski
        }
404
405
      mesh = mEdgeMeshes[index][type].copy(true);
406 a64e07d0 Leszek Koltunski
      }
407
    else
408
      {
409 e4bf4d02 Leszek Koltunski
      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 a64e07d0 Leszek Koltunski
      }
417 e4bf4d02 Leszek Koltunski
418
    Static4D q = QUATS[getQuat(cubit,numCubitsPerCorner,numCubitsPerEdge)];
419 3d8237cc Leszek Koltunski
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
420 a64e07d0 Leszek Koltunski
    mesh.apply(quat,0xffffffff,0);
421
422
    return mesh;
423
    }
424
425
///////////////////////////////////////////////////////////////////////////////////////////////////
426
427 d38f1397 Leszek Koltunski
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
428 a64e07d0 Leszek Koltunski
    {
429 0e7a13b4 Leszek Koltunski
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES;
430 6e7146df Leszek Koltunski
431
    int part  = cubit % numCubitsPerCorner;
432 a64e07d0 Leszek Koltunski
    int corner= cubit / numCubitsPerCorner;
433
434 6e7146df Leszek Koltunski
    if( part==0 )
435 a64e07d0 Leszek Koltunski
      {
436 6e7146df Leszek Koltunski
      return mCornerFaceMap[corner][cubitface];
437 a64e07d0 Leszek Koltunski
      }
438
    else
439
      {
440
      int N = (numCubitsPerCorner-1)/3;
441 6e7146df Leszek Koltunski
      int block = (part-1) % N;
442
      int index = (part-1) / N;
443 a64e07d0 Leszek Koltunski
444 0e7a13b4 Leszek Koltunski
      if( block< (numLayers-3)/2 )
445 a64e07d0 Leszek Koltunski
        {
446 6e7146df Leszek Koltunski
        switch(index)
447
          {
448 0e7a13b4 Leszek Koltunski
          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 6e7146df Leszek Koltunski
          }
452 a64e07d0 Leszek Koltunski
        }
453
      else
454
        {
455 6e7146df Leszek Koltunski
        switch(index)
456
          {
457 0e7a13b4 Leszek Koltunski
          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 6e7146df Leszek Koltunski
          }
461 a64e07d0 Leszek Koltunski
        }
462
      }
463 6e7146df Leszek Koltunski
464 0e7a13b4 Leszek Koltunski
    return NUM_TEXTURES;
465 a64e07d0 Leszek Koltunski
    }
466
467 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
468
469 e4bf4d02 Leszek Koltunski
  int getEdgeColor(int edge, int cubitface, int numCubitsPerEdge)
470 d38f1397 Leszek Koltunski
    {
471 0e7a13b4 Leszek Koltunski
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES;
472 d38f1397 Leszek Koltunski
473 e4bf4d02 Leszek Koltunski
    int part    = edge % numCubitsPerEdge;
474
    int variant = edge / numCubitsPerEdge;
475 d38f1397 Leszek Koltunski
476 e4bf4d02 Leszek Koltunski
    return (part==0 || cubitface==((part+1)%2)) ? mEdgeMap[variant][cubitface+2] + (part+1)*NUM_FACES : NUM_TEXTURES;
477 d38f1397 Leszek Koltunski
    }
478
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480
481 e4bf4d02 Leszek Koltunski
  int getCenterColor(int center, int cubitface, int numLayers)
482 d38f1397 Leszek Koltunski
    {
483 e4bf4d02 Leszek Koltunski
    return cubitface>0 ? NUM_TEXTURES : center + NUM_FACES*(numLayers+1)/2;
484 d38f1397 Leszek Koltunski
    }
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 e4bf4d02 Leszek Koltunski
      int edge = cubit - NUM_CORNERS*numCubitsPerCorner;
500
      return getEdgeColor(edge,cubitface,numCubitsPerEdge);
501 d38f1397 Leszek Koltunski
      }
502
    else
503
      {
504 e4bf4d02 Leszek Koltunski
      int center = cubit-NUM_CORNERS*numCubitsPerCorner-NUM_EDGES*numCubitsPerEdge;
505
      return getCenterColor( center, cubitface, numLayers);
506 d38f1397 Leszek Koltunski
      }
507
    }
508
509 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
510
// TODO
511
512
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
513
    {
514 d38f1397 Leszek Koltunski
    paint.setColor(FACE_COLORS[face%NUM_FACES]);
515 a64e07d0 Leszek Koltunski
    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
}