Project

General

Profile

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

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

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 ab210d63 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
190
191
  float getScreenRatio()
192
    {
193
    return 1.07f;
194
    }
195
196 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
197
198
  int getNumStickerTypes(int numLayers)
199
    {
200 e4bf4d02 Leszek Koltunski
    return (numLayers+3)/2;
201 a64e07d0 Leszek Koltunski
    }
202
203
///////////////////////////////////////////////////////////////////////////////////////////////////
204
205
  float[] getCuts(int numLayers)
206
    {
207
    float[] cuts = new float[numLayers-1];
208 ede1b68c Leszek Koltunski
    float D = numLayers*MovementMinx.DIST3D;
209 a64e07d0 Leszek Koltunski
    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 ede1b68c Leszek Koltunski
                              // its height is then D*2*DIST3D, it has one 'lower' part of height X, one
212 a64e07d0 Leszek Koltunski
                              // '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 ede1b68c Leszek Koltunski
      cuts[        i] = -D + (i+0.5f)*G;
220 a64e07d0 Leszek Koltunski
      cuts[2*num-1-i] = -cuts[i];
221
      }
222
223
    return cuts;
224
    }
225
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227
228 e4bf4d02 Leszek Koltunski
  private void computeCenter(Static3D pos, int center, int numLayers)
229 a64e07d0 Leszek Koltunski
    {
230 d38f1397 Leszek Koltunski
    float[] coords = mCenterCoords[center];
231 e4bf4d02 Leszek Koltunski
    float A = numLayers/3.0f;
232
233
    pos.set( A*coords[0], A*coords[1], A*coords[2] );
234 a64e07d0 Leszek Koltunski
    }
235
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237 d38f1397 Leszek Koltunski
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
238 a64e07d0 Leszek Koltunski
// Appropriate one: QUATS[QUAT_INDICES[corner]].
239
240 d38f1397 Leszek Koltunski
  private void computeBasicCornerVectors(int corner)
241 a64e07d0 Leszek Koltunski
    {
242 d38f1397 Leszek Koltunski
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
243 a64e07d0 Leszek Koltunski
244 d38f1397 Leszek Koltunski
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
245
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
246
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
247 a64e07d0 Leszek Koltunski
    }
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 3d8237cc Leszek Koltunski
      float E = 2.0f*(numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
263 a64e07d0 Leszek Koltunski
      int N = (numCubitsPerCorner-1)/3;
264 6e7146df Leszek Koltunski
      int block = (part-1) % N;
265
      int index = (part-1) / N;
266 d38f1397 Leszek Koltunski
      Static4D pri = mCurrCornerV[index];
267
      Static4D sec = mCurrCornerV[(index+2)%3];
268 a64e07d0 Leszek Koltunski
269 6e7146df Leszek Koltunski
      int multP = (block % ((numLayers-3)/2)) + 1;
270
      int multS = (block / ((numLayers-3)/2));
271 a64e07d0 Leszek Koltunski
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 d38f1397 Leszek Koltunski
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
281 a64e07d0 Leszek Koltunski
    {
282 d38f1397 Leszek Koltunski
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
283
    return (part+1)/2;
284
    }
285 a64e07d0 Leszek Koltunski
286 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
287
288
  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
289
    {
290 3d8237cc Leszek Koltunski
    float corr = numLayers/3.0f;
291
292 d38f1397 Leszek Koltunski
    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
293
    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
294 3d8237cc Leszek Koltunski
    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 d38f1397 Leszek Koltunski
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 3d8237cc Leszek Koltunski
      float vX = corr*center[0] - x;
309
      float vY = corr*center[1] - y;
310
      float vZ = corr*center[2] - z;
311 d38f1397 Leszek Koltunski
312 3d8237cc Leszek Koltunski
      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 d38f1397 Leszek Koltunski
315
      pos.set( x+A*vX, y+A*vY, z+A*vZ );
316
      }
317 a64e07d0 Leszek Koltunski
    }
318
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320
321
  Static3D[] getCubitPositions(int numLayers)
322
    {
323
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
324 d38f1397 Leszek Koltunski
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
325 e4bf4d02 Leszek Koltunski
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
326 a64e07d0 Leszek Koltunski
    int index=0;
327
328
    final Static3D[] CENTERS = new Static3D[numCubits];
329
330
    for(int corner=0; corner<NUM_CORNERS; corner++)
331
      {
332 d38f1397 Leszek Koltunski
      computeBasicCornerVectors(corner);
333 a64e07d0 Leszek Koltunski
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 d38f1397 Leszek Koltunski
341 a64e07d0 Leszek Koltunski
    for(int edge=0; edge<NUM_EDGES; edge++)
342
      {
343
      for(int part=0; part<numCubitsPerEdge; part++, index++)
344
        {
345 d38f1397 Leszek Koltunski
        CENTERS[index] = new Static3D(0,0,0);
346
        computeEdge(CENTERS[index], numLayers, edge, part );
347 a64e07d0 Leszek Koltunski
        }
348
      }
349 e4bf4d02 Leszek Koltunski
350 a64e07d0 Leszek Koltunski
    for(int center=0; center<NUM_CENTERS; center++, index++)
351
      {
352 e4bf4d02 Leszek Koltunski
      CENTERS[index] = new Static3D(0,0,0);
353
      computeCenter(CENTERS[index], center, numLayers);
354 a64e07d0 Leszek Koltunski
      }
355 e4bf4d02 Leszek Koltunski
356 a64e07d0 Leszek Koltunski
    return CENTERS;
357
    }
358
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
361 e4bf4d02 Leszek Koltunski
  private int getQuat(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
362 a64e07d0 Leszek Koltunski
    {
363
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
364
      {
365
      int corner = cubit/numCubitsPerCorner;
366 d38f1397 Leszek Koltunski
      return QUAT_CORNER_INDICES[corner];
367 a64e07d0 Leszek Koltunski
      }
368
369 d38f1397 Leszek Koltunski
    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 e4bf4d02 Leszek Koltunski
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
376
    return QUAT_CENTER_INDICES[center];
377 a64e07d0 Leszek Koltunski
    }
378
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380
381
  MeshBase createCubitMesh(int cubit, int numLayers)
382
    {
383
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
384
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
385 28b54fe3 Leszek Koltunski
    int index = (numLayers-3)/2;
386 db608887 Leszek Koltunski
    int[] sizes = ObjectList.MEGA.getSizes();
387
    int variants = sizes.length;
388 a64e07d0 Leszek Koltunski
    MeshBase mesh;
389
390 d38f1397 Leszek Koltunski
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
391 db608887 Leszek Koltunski
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
392 e4bf4d02 Leszek Koltunski
    if( mCenterMeshes==null ) mCenterMeshes = new MeshBase[variants];
393 28b54fe3 Leszek Koltunski
394 d38f1397 Leszek Koltunski
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
395 a64e07d0 Leszek Koltunski
      {
396 d38f1397 Leszek Koltunski
      if( mCornerMeshes[index]==null )
397
        {
398
        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
399
        }
400 28b54fe3 Leszek Koltunski
      mesh = mCornerMeshes[index].copy(true);
401 a64e07d0 Leszek Koltunski
      }
402 e4bf4d02 Leszek Koltunski
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
403 a64e07d0 Leszek Koltunski
      {
404 d38f1397 Leszek Koltunski
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
405
406
      if( mEdgeMeshes[index][type]==null )
407
        {
408 3d8237cc Leszek Koltunski
        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 61b217a5 Leszek Koltunski
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(numLayers,width,height);
412 d38f1397 Leszek Koltunski
        }
413
414
      mesh = mEdgeMeshes[index][type].copy(true);
415 a64e07d0 Leszek Koltunski
      }
416
    else
417
      {
418 e4bf4d02 Leszek Koltunski
      if( mCenterMeshes[index]==null )
419
        {
420
        float width = 2 * (numLayers/3.0f) * (MEGA_D+(0.5f-MEGA_D)*SIN18);
421 61b217a5 Leszek Koltunski
        mCenterMeshes[index] = FactoryCubit.getInstance().createMegaminxCenterMesh(numLayers,width);
422 e4bf4d02 Leszek Koltunski
        }
423
424
      mesh = mCenterMeshes[index].copy(true);
425 a64e07d0 Leszek Koltunski
      }
426 e4bf4d02 Leszek Koltunski
427
    Static4D q = QUATS[getQuat(cubit,numCubitsPerCorner,numCubitsPerEdge)];
428 3d8237cc Leszek Koltunski
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
429 a64e07d0 Leszek Koltunski
    mesh.apply(quat,0xffffffff,0);
430
431
    return mesh;
432
    }
433
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435
436 d38f1397 Leszek Koltunski
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
437 a64e07d0 Leszek Koltunski
    {
438 0e7a13b4 Leszek Koltunski
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES;
439 6e7146df Leszek Koltunski
440
    int part  = cubit % numCubitsPerCorner;
441 a64e07d0 Leszek Koltunski
    int corner= cubit / numCubitsPerCorner;
442
443 6e7146df Leszek Koltunski
    if( part==0 )
444 a64e07d0 Leszek Koltunski
      {
445 6e7146df Leszek Koltunski
      return mCornerFaceMap[corner][cubitface];
446 a64e07d0 Leszek Koltunski
      }
447
    else
448
      {
449
      int N = (numCubitsPerCorner-1)/3;
450 6e7146df Leszek Koltunski
      int block = (part-1) % N;
451
      int index = (part-1) / N;
452 a64e07d0 Leszek Koltunski
453 0e7a13b4 Leszek Koltunski
      if( block< (numLayers-3)/2 )
454 a64e07d0 Leszek Koltunski
        {
455 6e7146df Leszek Koltunski
        switch(index)
456
          {
457 0e7a13b4 Leszek Koltunski
          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 6e7146df Leszek Koltunski
          }
461 a64e07d0 Leszek Koltunski
        }
462
      else
463
        {
464 6e7146df Leszek Koltunski
        switch(index)
465
          {
466 0e7a13b4 Leszek Koltunski
          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 6e7146df Leszek Koltunski
          }
470 a64e07d0 Leszek Koltunski
        }
471
      }
472 6e7146df Leszek Koltunski
473 0e7a13b4 Leszek Koltunski
    return NUM_TEXTURES;
474 a64e07d0 Leszek Koltunski
    }
475
476 d38f1397 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
477
478 e4bf4d02 Leszek Koltunski
  int getEdgeColor(int edge, int cubitface, int numCubitsPerEdge)
479 d38f1397 Leszek Koltunski
    {
480 0e7a13b4 Leszek Koltunski
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES;
481 d38f1397 Leszek Koltunski
482 e4bf4d02 Leszek Koltunski
    int part    = edge % numCubitsPerEdge;
483
    int variant = edge / numCubitsPerEdge;
484 d38f1397 Leszek Koltunski
485 51df47f3 Leszek Koltunski
    return (part==0 || cubitface==((part+1)%2)) ? mEdgeMap[variant][cubitface+2] + ((part+3)/2)*NUM_FACES : NUM_TEXTURES;
486 d38f1397 Leszek Koltunski
    }
487
488
///////////////////////////////////////////////////////////////////////////////////////////////////
489
490 e4bf4d02 Leszek Koltunski
  int getCenterColor(int center, int cubitface, int numLayers)
491 d38f1397 Leszek Koltunski
    {
492 e4bf4d02 Leszek Koltunski
    return cubitface>0 ? NUM_TEXTURES : center + NUM_FACES*(numLayers+1)/2;
493 d38f1397 Leszek Koltunski
    }
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 e4bf4d02 Leszek Koltunski
      int edge = cubit - NUM_CORNERS*numCubitsPerCorner;
509
      return getEdgeColor(edge,cubitface,numCubitsPerEdge);
510 d38f1397 Leszek Koltunski
      }
511
    else
512
      {
513 e4bf4d02 Leszek Koltunski
      int center = cubit-NUM_CORNERS*numCubitsPerCorner-NUM_EDGES*numCubitsPerEdge;
514
      return getCenterColor( center, cubitface, numLayers);
515 d38f1397 Leszek Koltunski
      }
516
    }
517
518 a64e07d0 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
519
520
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
521
    {
522 ede1b68c Leszek Koltunski
    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 329d21a5 Leszek Koltunski
      R = 0.070f;
532 673d7b24 Leszek Koltunski
      S = 0.08f;
533 ede1b68c Leszek Koltunski
      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 329d21a5 Leszek Koltunski
        R = 0.05f;
549 673d7b24 Leszek Koltunski
        S = 0.07f;
550 ede1b68c Leszek Koltunski
        vertices = new float[] { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
551
        }
552
      else
553
        {
554 ed01e351 Leszek Koltunski
        float Z  = 0.5f;
555
        float X1 = Z*COS54;
556 ede1b68c Leszek Koltunski
        float Y1 = Z*SIN54;
557
        float X2 = Z*COS18;
558
        float Y2 = Z*SIN18;
559
560 ed01e351 Leszek Koltunski
        R = 0.10f;
561 673d7b24 Leszek Koltunski
        S = 0.08f;
562 ede1b68c Leszek Koltunski
        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 a64e07d0 Leszek Koltunski
    }
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( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
580
      }
581
582
    return true;
583
    }
584
585
///////////////////////////////////////////////////////////////////////////////////////////////////
586
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
587
// then if it were rotated by quaternion 'quat'.
588
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
589
// middle squares get interchanged. No visible difference!
590
//
591
// So: this is true iff the cubit
592
// a) is a corner or edge and the quaternions are the same
593
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
594
595
  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
596
    {
597
    if ( cubit.mQuatIndex == quatIndex ) return true;
598
599
    int belongsToHowManyFaces = 0;
600
    int lastLayer = getNumLayers()-1;
601
    float row;
602
    final float MAX_ERROR = 0.01f;
603
604
    for(int i=0; i<NUM_AXIS; i++)
605
      {
606
      row = cubit.mRotationRow[i];
607
      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
608
          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
609
      }
610
611
    switch(belongsToHowManyFaces)
612
      {
613
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
614
      case 1 :                // cubit that lies inside one of the faces
615
               Static3D orig = cubit.getOrigPosition();
616
               Static4D quat1 = QUATS[quatIndex];
617
               Static4D quat2 = QUATS[cubit.mQuatIndex];
618
619
               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
620
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
621
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
622
623
               float row1, row2;
624
               float x1 = rotated1.get0();
625
               float y1 = rotated1.get1();
626
               float z1 = rotated1.get2();
627
               float x2 = rotated2.get0();
628
               float y2 = rotated2.get1();
629
               float z2 = rotated2.get2();
630
631
               for(int i=0; i<NUM_AXIS; i++)
632
                 {
633
                 row1 = computeRow(x1,y1,z1,i);
634
                 row2 = computeRow(x2,y2,z2,i);
635
636
                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
637
                 }
638
               return false;
639
640
      default: return false;  // edge or corner
641
      }
642
    }
643
644
///////////////////////////////////////////////////////////////////////////////////////////////////
645
646
  public int getObjectName(int numLayers)
647
    {
648
    if( numLayers==3 ) return R.string.minx3;
649
    if( numLayers==5 ) return R.string.minx4;
650
651
    return 0;
652
    }
653
654
///////////////////////////////////////////////////////////////////////////////////////////////////
655
656
  public int getInventor(int numLayers)
657
    {
658
    if( numLayers==3 ) return R.string.minx3_inventor;
659
    if( numLayers==5 ) return R.string.minx4_inventor;
660
661
    return 0;
662
    }
663
664
///////////////////////////////////////////////////////////////////////////////////////////////////
665
666
  public int getComplexity(int numLayers)
667
    {
668
    if( numLayers==3 ) return 4;
669
670
    return 5;
671
    }
672
}