Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / TwistyMegaminx.java @ 51df47f3

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 ede1b68c Leszek Koltunski
import static org.distorted.objects.FactoryCubit.COS54;
38 3d8237cc Leszek Koltunski
import static org.distorted.objects.FactoryCubit.SIN18;
39 ede1b68c Leszek Koltunski
import static org.distorted.objects.FactoryCubit.SIN54;
40 3d8237cc Leszek Koltunski
41 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
42
43
public class TwistyMegaminx extends TwistyMinx
44
{
45 e4bf4d02 Leszek Koltunski
  static final float MEGA_D = 0.04f;
46 a64e07d0 Leszek Koltunski
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 d38f1397 Leszek Koltunski
  // 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 a64e07d0 Leszek Koltunski
         {
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 d38f1397 Leszek Koltunski
           { 4,  5, 15,  9, 14},
60
           { 1, 13,  5, 15,  3},
61 a64e07d0 Leszek Koltunski
           { 1,  3, 19,  7, 17},
62 d38f1397 Leszek Koltunski
           {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 a64e07d0 Leszek Koltunski
         };
68
69 d38f1397 Leszek Koltunski
  // 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 3d8237cc Leszek Koltunski
           { 18,  6,  1,  2},
85
           {  6, 16,  1,  7},
86 d38f1397 Leszek Koltunski
           { 16,  0,  8,  1},
87 3d8237cc Leszek Koltunski
           { 16, 10,  7,  8},
88
           { 10,  8, 10,  8},
89
           {  8, 12,  9,  8},
90 d38f1397 Leszek Koltunski
           {  8, 13,  9, 10},
91
           { 13,  5,  9,  5},
92
           {  5,  4,  9,  4},
93 3d8237cc Leszek Koltunski
           {  5, 15,  5,  4},
94
           { 15,  9,  3,  4},
95 d38f1397 Leszek Koltunski
           { 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 3d8237cc Leszek Koltunski
           { 17,  1, 10,  6},
101
           {  1,  3,  5,  6},
102
           {  3, 19,  3,  6},
103 d38f1397 Leszek Koltunski
           {  1, 13, 10,  5},
104 3d8237cc Leszek Koltunski
           {  3, 15,  3,  5},
105 d38f1397 Leszek Koltunski
         };
106 a64e07d0 Leszek Koltunski
107 e4bf4d02 Leszek Koltunski
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 d38f1397 Leszek Koltunski
  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
121 a64e07d0 Leszek Koltunski
122
  static
123
    {
124 d38f1397 Leszek Koltunski
    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 a64e07d0 Leszek Koltunski
157 d38f1397 Leszek Koltunski
  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 a64e07d0 Leszek Koltunski
    };
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
  int getNumStickerTypes(int numLayers)
192
    {
193 e4bf4d02 Leszek Koltunski
    return (numLayers+3)/2;
194 a64e07d0 Leszek Koltunski
    }
195
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
198
  float[] getCuts(int numLayers)
199
    {
200
    float[] cuts = new float[numLayers-1];
201 ede1b68c Leszek Koltunski
    float D = numLayers*MovementMinx.DIST3D;
202 a64e07d0 Leszek Koltunski
    float E = 2*C1;           // 2*cos(36 deg)
203
    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
204 ede1b68c Leszek Koltunski
                              // its height is then D*2*DIST3D, it has one 'lower' part of height X, one
205 a64e07d0 Leszek Koltunski
                              // 'middle' part of height Y and one upper part of height X again.
206
                              // It's edge length = numLayers/3.0f.
207
    int num = (numLayers-1)/2;
208
    float G = X*(0.5f-MEGA_D)/num; // height of one Layer
209
210
    for(int i=0; i<num; i++)
211
      {
212 ede1b68c Leszek Koltunski
      cuts[        i] = -D + (i+0.5f)*G;
213 a64e07d0 Leszek Koltunski
      cuts[2*num-1-i] = -cuts[i];
214
      }
215
216
    return cuts;
217
    }
218
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220
221 e4bf4d02 Leszek Koltunski
  private void computeCenter(Static3D pos, int center, int numLayers)
222 a64e07d0 Leszek Koltunski
    {
223 d38f1397 Leszek Koltunski
    float[] coords = mCenterCoords[center];
224 e4bf4d02 Leszek Koltunski
    float A = numLayers/3.0f;
225
226
    pos.set( A*coords[0], A*coords[1], A*coords[2] );
227 a64e07d0 Leszek Koltunski
    }
228
229
///////////////////////////////////////////////////////////////////////////////////////////////////
230 d38f1397 Leszek Koltunski
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
231 a64e07d0 Leszek Koltunski
// Appropriate one: QUATS[QUAT_INDICES[corner]].
232
233 d38f1397 Leszek Koltunski
  private void computeBasicCornerVectors(int corner)
234 a64e07d0 Leszek Koltunski
    {
235 d38f1397 Leszek Koltunski
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
236 a64e07d0 Leszek Koltunski
237 d38f1397 Leszek Koltunski
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
238
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
239
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
240 a64e07d0 Leszek Koltunski
    }
241
242
///////////////////////////////////////////////////////////////////////////////////////////////////
243
244
  private void computeCorner(Static3D pos, int numCubitsPerCorner, int numLayers, int corner, int part)
245
    {
246
    float D = numLayers/3.0f;
247
    Static3D corn = CORNERS[corner];
248
249
    if( part==0 )
250
      {
251
      pos.set( corn.get0()*D, corn.get1()*D, corn.get2()*D );
252
      }
253
    else
254
      {
255 3d8237cc Leszek Koltunski
      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
256 a64e07d0 Leszek Koltunski
      int N = (numCubitsPerCorner-1)/3;
257 6e7146df Leszek Koltunski
      int block = (part-1) % N;
258
      int index = (part-1) / N;
259 d38f1397 Leszek Koltunski
      Static4D pri = mCurrCornerV[index];
260
      Static4D sec = mCurrCornerV[(index+2)%3];
261 a64e07d0 Leszek Koltunski
262 6e7146df Leszek Koltunski
      int multP = (block % ((numLayers-3)/2)) + 1;
263
      int multS = (block / ((numLayers-3)/2));
264 a64e07d0 Leszek Koltunski
265
      pos.set( corn.get0()*D + (pri.get0()*multP + sec.get0()*multS)*E,
266
               corn.get1()*D + (pri.get1()*multP + sec.get1()*multS)*E,
267
               corn.get2()*D + (pri.get2()*multP + sec.get2()*multS)*E );
268
      }
269
    }
270
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272
273 d38f1397 Leszek Koltunski
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
274 a64e07d0 Leszek Koltunski
    {
275 d38f1397 Leszek Koltunski
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
276
    return (part+1)/2;
277
    }
278 a64e07d0 Leszek Koltunski
279 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
280
281
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
282
    {
283 3d8237cc Leszek Koltunski
    float corr = numLayers/3.0f;
284
285 d38f1397 Leszek Koltunski
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
286
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
287 3d8237cc Leszek Koltunski
    float x = corr*(c1.get0() + c2.get0())/2;
288
    float y = corr*(c1.get1() + c2.get1())/2;
289
    float z = corr*(c1.get2() + c2.get2())/2;
290 d38f1397 Leszek Koltunski
291
    if( part==0 )
292
      {
293
      pos.set(x,y,z);
294
      }
295
    else
296
      {
297
      int mult = (part+1)/2;
298
      int dir  = (part+1)%2;
299
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
300
301 3d8237cc Leszek Koltunski
      float vX = corr*center[0] - x;
302
      float vY = corr*center[1] - y;
303
      float vZ = corr*center[2] - z;
304 d38f1397 Leszek Koltunski
305 3d8237cc Leszek Koltunski
      float len = (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
306
      float A = mult*corr*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f)/len;
307 d38f1397 Leszek Koltunski
308
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
309
      }
310 a64e07d0 Leszek Koltunski
    }
311
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313
314
  Static3D[] getCubitPositions(int numLayers)
315
    {
316
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
317 d38f1397 Leszek Koltunski
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
318 e4bf4d02 Leszek Koltunski
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
319 a64e07d0 Leszek Koltunski
    int index=0;
320
321
    final Static3D[] CENTERS = new Static3D[numCubits];
322
323
    for(int corner=0; corner<NUM_CORNERS; corner++)
324
      {
325 d38f1397 Leszek Koltunski
      computeBasicCornerVectors(corner);
326 a64e07d0 Leszek Koltunski
327
      for(int part=0; part<numCubitsPerCorner; part++, index++)
328
        {
329
        CENTERS[index] = new Static3D(0,0,0);
330
        computeCorner(CENTERS[index],numCubitsPerCorner,numLayers,corner,part);
331
        }
332
      }
333 d38f1397 Leszek Koltunski
334 a64e07d0 Leszek Koltunski
    for(int edge=0; edge<NUM_EDGES; edge++)
335
      {
336
      for(int part=0; part<numCubitsPerEdge; part++, index++)
337
        {
338 d38f1397 Leszek Koltunski
        CENTERS[index] = new Static3D(0,0,0);
339
        computeEdge(CENTERS[index], numLayers, edge, part );
340 a64e07d0 Leszek Koltunski
        }
341
      }
342 e4bf4d02 Leszek Koltunski
343 a64e07d0 Leszek Koltunski
    for(int center=0; center<NUM_CENTERS; center++, index++)
344
      {
345 e4bf4d02 Leszek Koltunski
      CENTERS[index] = new Static3D(0,0,0);
346
      computeCenter(CENTERS[index], center, numLayers);
347 a64e07d0 Leszek Koltunski
      }
348 e4bf4d02 Leszek Koltunski
349 a64e07d0 Leszek Koltunski
    return CENTERS;
350
    }
351
352
///////////////////////////////////////////////////////////////////////////////////////////////////
353
354 e4bf4d02 Leszek Koltunski
  private int getQuat(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
355 a64e07d0 Leszek Koltunski
    {
356
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
357
      {
358
      int corner = cubit/numCubitsPerCorner;
359 d38f1397 Leszek Koltunski
      return QUAT_CORNER_INDICES[corner];
360 a64e07d0 Leszek Koltunski
      }
361
362 d38f1397 Leszek Koltunski
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
363
      {
364
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
365
      return QUAT_EDGE_INDICES[edge];
366
      }
367
368 e4bf4d02 Leszek Koltunski
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
369
    return QUAT_CENTER_INDICES[center];
370 a64e07d0 Leszek Koltunski
    }
371
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373
374
  MeshBase createCubitMesh(int cubit, int numLayers)
375
    {
376
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
377
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
378 28b54fe3 Leszek Koltunski
    int index = (numLayers-3)/2;
379 db608887 Leszek Koltunski
    int[] sizes = ObjectList.MEGA.getSizes();
380
    int variants = sizes.length;
381 a64e07d0 Leszek Koltunski
    MeshBase mesh;
382
383 d38f1397 Leszek Koltunski
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
384 db608887 Leszek Koltunski
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
385 e4bf4d02 Leszek Koltunski
    if( mCenterMeshes==null ) mCenterMeshes = new MeshBase[variants];
386 28b54fe3 Leszek Koltunski
387 d38f1397 Leszek Koltunski
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
388 a64e07d0 Leszek Koltunski
      {
389 d38f1397 Leszek Koltunski
      if( mCornerMeshes[index]==null )
390
        {
391
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
392
        }
393 28b54fe3 Leszek Koltunski
      mesh = mCornerMeshes[index].copy(true);
394 a64e07d0 Leszek Koltunski
      }
395 e4bf4d02 Leszek Koltunski
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
396 a64e07d0 Leszek Koltunski
      {
397 d38f1397 Leszek Koltunski
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
398
399
      if( mEdgeMeshes[index][type]==null )
400
        {
401 3d8237cc Leszek Koltunski
        float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
402
        float width = (numLayers/3.0f)*2*MEGA_D + 2*type*height*SIN18/COS18;
403
404
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(width,height);
405 d38f1397 Leszek Koltunski
        }
406
407
      mesh = mEdgeMeshes[index][type].copy(true);
408 a64e07d0 Leszek Koltunski
      }
409
    else
410
      {
411 e4bf4d02 Leszek Koltunski
      if( mCenterMeshes[index]==null )
412
        {
413
        float width = 2 * (numLayers/3.0f) * (MEGA_D+(0.5f-MEGA_D)*SIN18);
414
        mCenterMeshes[index] = FactoryCubit.getInstance().createMegaminxCenterMesh(width);
415
        }
416
417
      mesh = mCenterMeshes[index].copy(true);
418 a64e07d0 Leszek Koltunski
      }
419 e4bf4d02 Leszek Koltunski
420
    Static4D q = QUATS[getQuat(cubit,numCubitsPerCorner,numCubitsPerEdge)];
421 3d8237cc Leszek Koltunski
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
422 a64e07d0 Leszek Koltunski
    mesh.apply(quat,0xffffffff,0);
423
424
    return mesh;
425
    }
426
427
///////////////////////////////////////////////////////////////////////////////////////////////////
428
429 d38f1397 Leszek Koltunski
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
430 a64e07d0 Leszek Koltunski
    {
431 0e7a13b4 Leszek Koltunski
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES;
432 6e7146df Leszek Koltunski
433
    int part  = cubit % numCubitsPerCorner;
434 a64e07d0 Leszek Koltunski
    int corner= cubit / numCubitsPerCorner;
435
436 6e7146df Leszek Koltunski
    if( part==0 )
437 a64e07d0 Leszek Koltunski
      {
438 6e7146df Leszek Koltunski
      return mCornerFaceMap[corner][cubitface];
439 a64e07d0 Leszek Koltunski
      }
440
    else
441
      {
442
      int N = (numCubitsPerCorner-1)/3;
443 6e7146df Leszek Koltunski
      int block = (part-1) % N;
444
      int index = (part-1) / N;
445 a64e07d0 Leszek Koltunski
446 0e7a13b4 Leszek Koltunski
      if( block< (numLayers-3)/2 )
447 a64e07d0 Leszek Koltunski
        {
448 6e7146df Leszek Koltunski
        switch(index)
449
          {
450 0e7a13b4 Leszek Koltunski
          case 0: return cubitface==1 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
451
          case 1: return cubitface==0 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
452
          case 2: return cubitface==2 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
453 6e7146df Leszek Koltunski
          }
454 a64e07d0 Leszek Koltunski
        }
455
      else
456
        {
457 6e7146df Leszek Koltunski
        switch(index)
458
          {
459 0e7a13b4 Leszek Koltunski
          case 0: return cubitface==0 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
460
          case 1: return cubitface==2 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
461
          case 2: return cubitface==1 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
462 6e7146df Leszek Koltunski
          }
463 a64e07d0 Leszek Koltunski
        }
464
      }
465 6e7146df Leszek Koltunski
466 0e7a13b4 Leszek Koltunski
    return NUM_TEXTURES;
467 a64e07d0 Leszek Koltunski
    }
468
469 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
470
471 e4bf4d02 Leszek Koltunski
  int getEdgeColor(int edge, int cubitface, int numCubitsPerEdge)
472 d38f1397 Leszek Koltunski
    {
473 0e7a13b4 Leszek Koltunski
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES;
474 d38f1397 Leszek Koltunski
475 e4bf4d02 Leszek Koltunski
    int part    = edge % numCubitsPerEdge;
476
    int variant = edge / numCubitsPerEdge;
477 d38f1397 Leszek Koltunski
478 51df47f3 Leszek Koltunski
    return (part==0 || cubitface==((part+1)%2)) ? mEdgeMap[variant][cubitface+2] + ((part+3)/2)*NUM_FACES : NUM_TEXTURES;
479 d38f1397 Leszek Koltunski
    }
480
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482
483 e4bf4d02 Leszek Koltunski
  int getCenterColor(int center, int cubitface, int numLayers)
484 d38f1397 Leszek Koltunski
    {
485 e4bf4d02 Leszek Koltunski
    return cubitface>0 ? NUM_TEXTURES : center + NUM_FACES*(numLayers+1)/2;
486 d38f1397 Leszek Koltunski
    }
487
488
///////////////////////////////////////////////////////////////////////////////////////////////////
489
490
  int getFaceColor(int cubit, int cubitface, int numLayers)
491
    {
492
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
493
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
494
495
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
496
      {
497
      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
498
      }
499
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
500
      {
501 e4bf4d02 Leszek Koltunski
      int edge = cubit - NUM_CORNERS*numCubitsPerCorner;
502
      return getEdgeColor(edge,cubitface,numCubitsPerEdge);
503 d38f1397 Leszek Koltunski
      }
504
    else
505
      {
506 e4bf4d02 Leszek Koltunski
      int center = cubit-NUM_CORNERS*numCubitsPerCorner-NUM_EDGES*numCubitsPerEdge;
507
      return getCenterColor( center, cubitface, numLayers);
508 d38f1397 Leszek Koltunski
      }
509
    }
510
511 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
512
513
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
514
    {
515 ede1b68c Leszek Koltunski
    int COLORS = FACE_COLORS.length;
516
    float R,S;
517
    float[] vertices;
518
519
    int variant = face/COLORS;
520
521
    if( variant==0 )
522
      {
523
      float Y = COS54/(2*SIN54);
524 51df47f3 Leszek Koltunski
      R = 0.06f;
525
      S = 0.065f;
526 ede1b68c Leszek Koltunski
      vertices = new float[] { -0.5f, 0.0f, 0.0f, -Y, 0.5f, 0.0f, 0.0f, Y };
527
      }
528
    else
529
      {
530
      int numLayers = getNumLayers();
531
      float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
532
      float W = height*SIN18/COS18;
533
      float width = (numLayers/3.0f)*2*MEGA_D + 2*(variant-1)*W;
534
535
      if( variant < (numLayers+1)/2 )
536
        {
537
        float X1 = 0.5f*height;
538
        float Y1 = 0.5f*width;
539
        float Y2 = 0.5f*width + W;
540
541
        R = 0.04f;
542 51df47f3 Leszek Koltunski
        S = 0.05f;
543 ede1b68c Leszek Koltunski
        vertices = new float[] { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
544
        }
545
      else
546
        {
547
        float Z = width/(2*COS54);
548
        float X1 = 0.5f*width;
549
        float Y1 = Z*SIN54;
550
        float X2 = Z*COS18;
551
        float Y2 = Z*SIN18;
552
553
        R = 0.05f;
554
        S = 0.05f;
555
        vertices = new float[] { -X1,+Y1, -X2,-Y2, 0.0f,-Z, +X2,-Y2, +X1,+Y1 };
556
        }
557
      }
558
559
    FactorySticker factory = FactorySticker.getInstance();
560
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face%COLORS], R);
561 a64e07d0 Leszek Koltunski
    }
562
563
///////////////////////////////////////////////////////////////////////////////////////////////////
564
// PUBLIC API
565
566
  public boolean isSolved()
567
    {
568
    int index = CUBITS[0].mQuatIndex;
569
570
    for(int i=1; i<NUM_CUBITS; i++)
571
      {
572
      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
573
      }
574
575
    return true;
576
    }
577
578
///////////////////////////////////////////////////////////////////////////////////////////////////
579
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
580
// then if it were rotated by quaternion 'quat'.
581
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
582
// middle squares get interchanged. No visible difference!
583
//
584
// So: this is true iff the cubit
585
// a) is a corner or edge and the quaternions are the same
586
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
587
588
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
589
    {
590
    if ( cubit.mQuatIndex == quatIndex ) return true;
591
592
    int belongsToHowManyFaces = 0;
593
    int lastLayer = getNumLayers()-1;
594
    float row;
595
    final float MAX_ERROR = 0.01f;
596
597
    for(int i=0; i<NUM_AXIS; i++)
598
      {
599
      row = cubit.mRotationRow[i];
600
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
601
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
602
      }
603
604
    switch(belongsToHowManyFaces)
605
      {
606
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
607
      case 1 :                // cubit that lies inside one of the faces
608
               Static3D orig = cubit.getOrigPosition();
609
               Static4D quat1 = QUATS[quatIndex];
610
               Static4D quat2 = QUATS[cubit.mQuatIndex];
611
612
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
613
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
614
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
615
616
               float row1, row2;
617
               float x1 = rotated1.get0();
618
               float y1 = rotated1.get1();
619
               float z1 = rotated1.get2();
620
               float x2 = rotated2.get0();
621
               float y2 = rotated2.get1();
622
               float z2 = rotated2.get2();
623
624
               for(int i=0; i<NUM_AXIS; i++)
625
                 {
626
                 row1 = computeRow(x1,y1,z1,i);
627
                 row2 = computeRow(x2,y2,z2,i);
628
629
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
630
                 }
631
               return false;
632
633
      default: return false;  // edge or corner
634
      }
635
    }
636
637
///////////////////////////////////////////////////////////////////////////////////////////////////
638
639
  public int getObjectName(int numLayers)
640
    {
641
    if( numLayers==3 ) return R.string.minx3;
642
    if( numLayers==5 ) return R.string.minx4;
643
644
    return 0;
645
    }
646
647
///////////////////////////////////////////////////////////////////////////////////////////////////
648
649
  public int getInventor(int numLayers)
650
    {
651
    if( numLayers==3 ) return R.string.minx3_inventor;
652
    if( numLayers==5 ) return R.string.minx4_inventor;
653
654
    return 0;
655
    }
656
657
///////////////////////////////////////////////////////////////////////////////////////////////////
658
659
  public int getComplexity(int numLayers)
660
    {
661
    if( numLayers==3 ) return 4;
662
663
    return 5;
664
    }
665
}