Project

General

Profile

Download (16 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / objects / TwistyMinx.java @ 5d09301e

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.objects;
11

    
12
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_DODECAHEDRON;
13
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_SPLIT_EDGE;
14
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
15
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
16
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
17

    
18
import java.io.InputStream;
19

    
20
import org.distorted.library.type.Static3D;
21
import org.distorted.library.type.Static4D;
22
import org.distorted.objectlib.main.InitData;
23
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
24
import org.distorted.objectlib.scrambling.ScrambleState;
25
import org.distorted.objectlib.main.ShapeDodecahedron;
26

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

    
29
abstract class TwistyMinx extends ShapeDodecahedron
30
{
31
  static final int NUM_CORNERS = 20;
32
  static final int NUM_CENTERS = 12;
33
  static final int NUM_EDGES   = 30;
34

    
35
  static final float SIN18    = (SQ5-1)/4;
36
  static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
37
  static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
38
  static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
39

    
40
  // the six rotation axis of a Minx. Must be normalized.
41
  static final Static3D[] ROT_AXIS = new Static3D[]
42
         {
43
           new Static3D(    C2/LEN, SIN54/LEN,    0      ),
44
           new Static3D(   -C2/LEN, SIN54/LEN,    0      ),
45
           new Static3D( 0        ,    C2/LEN, SIN54/LEN ),
46
           new Static3D( 0        ,   -C2/LEN, SIN54/LEN ),
47
           new Static3D( SIN54/LEN,    0     ,    C2/LEN ),
48
           new Static3D( SIN54/LEN,    0     ,   -C2/LEN )
49
         };
50

    
51
  private int[][] mBasicAngle;
52
  private float[][] mCuts;
53
  float[][] mCenterCoords,mCorners;
54
  int[] mQuatEdgeIndices,mQuatCornerIndices;
55
  int[][] mEdgeMap,mCenterMap;
56
  Static4D[] mBasicCornerV, mCurrCornerV;
57
  ScrambleState[] mStates;
58

    
59
///////////////////////////////////////////////////////////////////////////////////////////////////
60

    
61
  TwistyMinx(InitData data, int meshState, int iconMode, Static4D quat, Static3D move, float scale, InputStream stream)
62
    {
63
    super(data, meshState, iconMode, data.getNumLayers()[0], quat, move, scale, stream);
64
    }
65

    
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67

    
68
  public ScrambleState[] getScrambleStates()
69
    {
70
    if( mStates==null )
71
      {
72
      int[] numLayers = getNumLayers();
73
      initializeScrambleStates(numLayers[0]);
74
      }
75

    
76
    return mStates;
77
    }
78

    
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

    
81
  void initializeCornerV()
82
    {
83
    mBasicCornerV = new Static4D[3];
84
    mCurrCornerV  = new Static4D[3];
85

    
86
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
87
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
88
    mBasicCornerV[2] = new Static4D(              0,        -1.500f,    0.0f, 0.0f );
89
    }
90

    
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92
// the five vertices that form a given face. Order: the same as colors of the faces in TwistyMinx.
93

    
94
  void initializeCenterMap()
95
    {
96
    mCenterMap = new int[][]
97
         {
98
           { 0, 12,  8, 10, 16},
99
           { 0, 12,  4, 14,  2},
100
           { 0,  2, 18,  6, 16},
101
           { 6, 18, 11, 19,  7},
102
           { 3, 15,  9, 11, 19},
103
           { 4,  5, 15,  9, 14},
104
           { 1, 13,  5, 15,  3},
105
           { 1,  3, 19,  7, 17},
106
           {10, 16,  6,  7, 17},
107
           { 8, 13,  5,  4, 12},
108
           { 1, 13,  8, 10, 17},
109
           { 2, 14,  9, 11, 18},
110
         };
111
    }
112

    
113
///////////////////////////////////////////////////////////////////////////////////////////////////
114
// the quadruple ( corner1, corner2, face1, face2 ) defining an edge.
115
// In fact the 2 corners already define it, the faces only provide easy
116
// way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
117
// the 'left' or right of vector corner1 --> corner2, according to Quat.
118

    
119
  void initializeEdgeMap()
120
    {
121
    mEdgeMap = new int[][]
122
         {
123
           {  2,  0,  1,  2}, //0
124
           {  0, 12,  1,  0},
125
           { 12,  4,  1,  9},
126
           {  4, 14,  1,  5},
127
           { 14,  2,  1, 11},
128
           { 14,  9, 11,  5}, //5
129
           {  9, 11, 11,  4},
130
           { 11, 18, 11,  3},
131
           { 18,  2, 11,  2},
132
           { 18,  6,  2,  3},
133
           {  6, 16,  2,  8}, //10
134
           { 16,  0,  2,  0},
135
           { 16, 10,  0,  8},
136
           { 10,  8,  0, 10},
137
           {  8, 12,  0,  9},
138
           {  8, 13,  9, 10}, //15
139
           { 13,  5,  9,  6},
140
           {  5,  4,  9,  5},
141
           {  5, 15,  5,  6},
142
           { 15,  9,  5,  4},
143
           { 11, 19,  3,  4}, //20
144
           { 19,  7,  3,  7},
145
           {  7,  6,  3,  8},
146
           {  7, 17,  8,  7},
147
           { 17, 10,  8, 10},
148
           { 17,  1, 10,  7}, //25
149
           {  1,  3,  6,  7},
150
           {  3, 19,  4,  7},
151
           {  1, 13, 10,  6},
152
           {  3, 15,  6,  4},
153
         };
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  void initializeQuatIndices()
159
    {
160
    mQuatEdgeIndices = new int[]
161
      {
162
         0, 17, 18, 19, 20, 56, 25,  5, 24, 16,
163
         9, 44,  1, 34, 35, 27, 41, 50, 26, 54,
164
        15, 49, 39, 28, 10,  2, 48,  6, 46,  3
165
      };
166
    mQuatCornerIndices = new int[]
167
      {
168
         0, 29, 59, 48, 18, 53, 22, 49, 11, 54,
169
        10, 52, 17, 27, 19, 26,  9, 28, 23, 45
170
      };
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174
// Coordinates of all 20 corners of a Minx
175

    
176
  void initializeCorners()
177
    {
178
    float cA = 1.5f;
179
    float cB = 3*C2;
180
    float cC = 3*SIN54;
181

    
182
    mCorners = new float[][]
183
         {
184
             {  0, cA, cB},
185
             {  0, cA,-cB},
186
             {  0,-cA, cB},
187
             {  0,-cA,-cB},
188
             { cB,  0, cA},
189
             { cB,  0,-cA},
190
             {-cB,  0, cA},
191
             {-cB,  0,-cA},
192
             { cA, cB,  0},
193
             { cA,-cB,  0},
194
             {-cA, cB,  0},
195
             {-cA,-cB,  0},
196
             { cC, cC, cC},
197
             { cC, cC,-cC},
198
             { cC,-cC, cC},
199
             { cC,-cC,-cC},
200
             {-cC, cC, cC},
201
             {-cC, cC,-cC},
202
             {-cC,-cC, cC},
203
             {-cC,-cC,-cC},
204
         };
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208

    
209
  void initializeCenterCoords()
210
    {
211
    if( mCorners==null ) initializeCorners();
212
    if( mCenterMap==null ) initializeCenterMap();
213

    
214
    mCenterCoords = new float[NUM_CENTERS][3];
215

    
216
    for(int center=0; center<NUM_CENTERS; center++)
217
      {
218
      int[] map = mCenterMap[center];
219

    
220
      float x = mCorners[map[0]][0] +
221
                mCorners[map[1]][0] +
222
                mCorners[map[2]][0] +
223
                mCorners[map[3]][0] +
224
                mCorners[map[4]][0] ;
225

    
226
      float y = mCorners[map[0]][1] +
227
                mCorners[map[1]][1] +
228
                mCorners[map[2]][1] +
229
                mCorners[map[3]][1] +
230
                mCorners[map[4]][1] ;
231

    
232
      float z = mCorners[map[0]][2] +
233
                mCorners[map[1]][2] +
234
                mCorners[map[2]][2] +
235
                mCorners[map[3]][2] +
236
                mCorners[map[4]][2] ;
237

    
238
      mCenterCoords[center][0] = x/5;
239
      mCenterCoords[center][1] = y/5;
240
      mCenterCoords[center][2] = z/5;
241
      }
242
    }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
  private int[] generateL(int numLayers, int index)
247
    {
248
    int rows = (numLayers-1)/2;
249
    int[] ret = new int[3*4*rows];
250

    
251
    for(int i=0; i<rows; i++)
252
      {
253
      ret[12*i   ] = i;
254
      ret[12*i+ 1] =-2;
255
      ret[12*i+ 2] = index;
256
      ret[12*i+ 3] = i;
257
      ret[12*i+ 4] =-1;
258
      ret[12*i+ 5] = index;
259
      ret[12*i+ 6] = i;
260
      ret[12*i+ 7] =+1;
261
      ret[12*i+ 8] = index;
262
      ret[12*i+ 9] = i;
263
      ret[12*i+10] =+2;
264
      ret[12*i+11] = index;
265
      }
266

    
267
    return ret;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
  private int[] generateR(int numLayers, int index)
273
    {
274
    int rows = (numLayers-1)/2;
275
    int[] ret = new int[3*4*rows];
276

    
277
    for(int i=0; i<rows; i++)
278
      {
279
      int lay = rows+i+1;
280

    
281
      ret[12*i   ] = lay;
282
      ret[12*i+ 1] =-2;
283
      ret[12*i+ 2] = index;
284
      ret[12*i+ 3] = lay;
285
      ret[12*i+ 4] =-1;
286
      ret[12*i+ 5] = index;
287
      ret[12*i+ 6] = lay;
288
      ret[12*i+ 7] =+1;
289
      ret[12*i+ 8] = index;
290
      ret[12*i+ 9] = lay;
291
      ret[12*i+10] =+2;
292
      ret[12*i+11] = index;
293
      }
294

    
295
    return ret;
296
    }
297

    
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299

    
300
  private int[] generateB(int numLayers, int index)
301
    {
302
    int rows = (numLayers-1);
303
    int half = rows/2;
304
    int[] ret = new int[3*4*rows];
305

    
306
    for(int i=0; i<rows; i++)
307
      {
308
      int ind = i<half? index : index+1;
309
      int lay = i<half? i : i+1;
310

    
311
      ret[12*i   ] = lay;
312
      ret[12*i+ 1] =-2;
313
      ret[12*i+ 2] = ind;
314
      ret[12*i+ 3] = lay;
315
      ret[12*i+ 4] =-1;
316
      ret[12*i+ 5] = ind;
317
      ret[12*i+ 6] = lay;
318
      ret[12*i+ 7] =+1;
319
      ret[12*i+ 8] = ind;
320
      ret[12*i+ 9] = lay;
321
      ret[12*i+10] =+2;
322
      ret[12*i+11] = ind;
323
      }
324

    
325
    return ret;
326
    }
327

    
328
///////////////////////////////////////////////////////////////////////////////////////////////////
329

    
330
  private void initializeScrambleStates(int numLayers)
331
    {
332
    int[] LEFT0 = generateL(numLayers,1);
333
    int[] RIGH0 = generateR(numLayers,2);
334
    int[] LEFT1 = generateL(numLayers,3);
335
    int[] RIGH1 = generateR(numLayers,4);
336
    int[] LEFT2 = generateL(numLayers,5);
337
    int[] RIGH2 = generateR(numLayers,6);
338
    int[] LEFT3 = generateL(numLayers,7);
339
    int[] RIGH3 = generateR(numLayers,8);
340
    int[] LEFT4 = generateL(numLayers,9);
341
    int[] RIGH4 = generateR(numLayers,10);
342
    int[] LEFT5 = generateL(numLayers,11);
343
    int[] RIGH5 = generateR(numLayers,12);
344

    
345
    int[] BOTH1 = generateB(numLayers,1);
346
    int[] BOTH3 = generateB(numLayers,3);
347
    int[] BOTH5 = generateB(numLayers,5);
348
    int[] BOTH7 = generateB(numLayers,7);
349
    int[] BOTH9 = generateB(numLayers,9);
350
    int[] BOTH11= generateB(numLayers,11);
351

    
352
    mStates = new ScrambleState[]
353
      {
354
      new ScrambleState( new int[][] { BOTH1,BOTH3,BOTH5,BOTH7,BOTH9,BOTH11 } ), // beg
355
      new ScrambleState( new int[][] { {}   ,RIGH1,LEFT2,RIGH3,LEFT4,LEFT5  } ), // 0L
356
      new ScrambleState( new int[][] { {}   ,LEFT1,RIGH2,LEFT3,RIGH4,RIGH5  } ), // 0R
357
      new ScrambleState( new int[][] { RIGH0,{}   ,LEFT2,RIGH3,RIGH4,RIGH5  } ), // 1L
358
      new ScrambleState( new int[][] { LEFT0,{}   ,RIGH2,LEFT3,LEFT4,LEFT5  } ), // 1R
359
      new ScrambleState( new int[][] { LEFT0,LEFT1,{}   ,RIGH3,LEFT4,RIGH5  } ), // 2L
360
      new ScrambleState( new int[][] { RIGH0,RIGH1,{}   ,LEFT3,RIGH4,LEFT5  } ), // 2R
361
      new ScrambleState( new int[][] { RIGH0,RIGH1,RIGH2,{}   ,LEFT4,RIGH5  } ), // 3L
362
      new ScrambleState( new int[][] { LEFT0,LEFT1,LEFT2,{}   ,RIGH4,LEFT5  } ), // 3R
363
      new ScrambleState( new int[][] { LEFT0,RIGH1,LEFT2,LEFT3,{}   ,RIGH5  } ), // 4L
364
      new ScrambleState( new int[][] { RIGH0,LEFT1,RIGH2,RIGH3,{}   ,LEFT5  } ), // 4R
365
      new ScrambleState( new int[][] { LEFT0,RIGH1,RIGH2,RIGH3,RIGH4,{}     } ), // 5L
366
      new ScrambleState( new int[][] { RIGH0,LEFT1,LEFT2,LEFT3,LEFT4,{}     } ), // 5R
367
      };
368
    }
369

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

    
372
  float[][] genericGetCuts(int numLayers, float dist)
373
    {
374
    if( mCuts==null )
375
      {
376
      mCuts = new float[6][numLayers-1];
377
      float D = numLayers* TouchControlDodecahedron.DIST3D;
378
      float X = 2*D/(2+SIN18);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
379
                                // its height is then 2D, it has one 'lower' part of height X, one
380
                                // 'middle' part of height Y and one upper part of height X again.
381
      int num = (numLayers-1)/2;
382
      float G = X*dist/num;     // height of one Layer
383

    
384
      for(int i=0; i<num; i++)
385
        {
386
        float cut = -D + (i+0.85f)*G;  // 0.85? not fully correct; attempt to make it
387
                                       // easier to rotate the outer layers
388
        int j = 2*num-1-i;
389
        mCuts[0][i] = +cut;
390
        mCuts[0][j] = -cut;
391
        mCuts[1][i] = +cut;
392
        mCuts[1][j] = -cut;
393
        mCuts[2][i] = +cut;
394
        mCuts[2][j] = -cut;
395
        mCuts[3][i] = +cut;
396
        mCuts[3][j] = -cut;
397
        mCuts[4][i] = +cut;
398
        mCuts[4][j] = -cut;
399
        mCuts[5][i] = +cut;
400
        mCuts[5][j] = -cut;
401
        }
402
      }
403

    
404
    return mCuts;
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408

    
409
  public boolean[][] getLayerRotatable(int[] numLayers)
410
    {
411
    int numAxis = ROT_AXIS.length;
412
    boolean[][] layerRotatable = new boolean[numAxis][];
413

    
414
    for(int i=0; i<numAxis; i++)
415
      {
416
      layerRotatable[i] = new boolean[numLayers[i]];
417
      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
418
      layerRotatable[i][numLayers[i]/2] = false;
419
      }
420

    
421
    return layerRotatable;
422
    }
423

    
424
///////////////////////////////////////////////////////////////////////////////////////////////////
425

    
426
  public int getTouchControlType()
427
    {
428
    return TC_DODECAHEDRON;
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  public int getTouchControlSplit()
434
    {
435
    return TYPE_SPLIT_EDGE;
436
    }
437

    
438
///////////////////////////////////////////////////////////////////////////////////////////////////
439

    
440
  public int[][][] getEnabled()
441
    {
442
    return new int[][][]
443
      {
444
          {{2,3},{3,5},{1,5},{1,4},{2,4}},
445
          {{0,5},{2,5},{2,3},{3,4},{0,4}},
446
          {{2,3},{2,5},{0,5},{0,4},{3,4}},
447
          {{1,5},{3,5},{2,3},{2,4},{1,4}},
448
          {{0,3},{0,4},{4,5},{1,5},{1,3}},
449
          {{1,2},{1,4},{4,5},{0,5},{0,2}},
450
          {{4,5},{1,4},{1,2},{0,2},{0,5}},
451
          {{4,5},{0,4},{0,3},{1,3},{1,5}},
452
          {{0,2},{0,1},{1,3},{3,5},{2,5}},
453
          {{3,4},{2,4},{1,2},{0,1},{0,3}},
454
          {{2,4},{3,4},{0,3},{0,1},{1,2}},
455
          {{1,3},{0,1},{0,2},{2,5},{3,5}},
456
      };
457
    }
458

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

    
461
  public float[] getDist3D(int[] numLayers)
462
    {
463
    return TouchControlDodecahedron.D3D;
464
    }
465

    
466
///////////////////////////////////////////////////////////////////////////////////////////////////
467

    
468
  public Static3D[] getFaceAxis()
469
    {
470
    return TouchControlDodecahedron.FACE_AXIS;
471
    }
472

    
473
///////////////////////////////////////////////////////////////////////////////////////////////////
474
// PUBLIC API
475

    
476
  public Static3D[] getRotationAxis()
477
    {
478
    return ROT_AXIS;
479
    }
480

    
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482

    
483
  public int[][] getBasicAngles()
484
    {
485
    if( mBasicAngle ==null )
486
      {
487
      int num = getNumLayers()[0];
488
      int[] tmp = new int[num];
489
      for(int i=0; i<num; i++) tmp[i] = 5;
490
      mBasicAngle = new int[][] { tmp,tmp,tmp,tmp,tmp,tmp };
491
      }
492

    
493
    return mBasicAngle;
494
    }
495
}
(18-18/36)