Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objectlib.objects;
21

    
22
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_DODECAHEDRON;
23
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_SPLIT_EDGE;
24
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
25
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
26
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
27

    
28
import java.io.InputStream;
29

    
30
import org.distorted.library.type.Static3D;
31
import org.distorted.library.type.Static4D;
32
import org.distorted.objectlib.main.InitData;
33
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
34
import org.distorted.objectlib.scrambling.ScrambleState;
35
import org.distorted.objectlib.main.ShapeDodecahedron;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

    
39
abstract class TwistyMinx extends ShapeDodecahedron
40
{
41
  static final int NUM_CORNERS = 20;
42
  static final int NUM_CENTERS = 12;
43
  static final int NUM_EDGES   = 30;
44

    
45
  static final float SIN18    = (SQ5-1)/4;
46
  static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
47
  static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
48
  static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
49

    
50
  // the six rotation axis of a Minx. Must be normalized.
51
  static final Static3D[] ROT_AXIS = new Static3D[]
52
         {
53
           new Static3D(    C2/LEN, SIN54/LEN,    0      ),
54
           new Static3D(   -C2/LEN, SIN54/LEN,    0      ),
55
           new Static3D( 0        ,    C2/LEN, SIN54/LEN ),
56
           new Static3D( 0        ,   -C2/LEN, SIN54/LEN ),
57
           new Static3D( SIN54/LEN,    0     ,    C2/LEN ),
58
           new Static3D( SIN54/LEN,    0     ,   -C2/LEN )
59
         };
60

    
61
  private int[][] mBasicAngle;
62
  private float[][] mCuts;
63
  float[][] mCenterCoords,mCorners;
64
  int[] mQuatEdgeIndices,mQuatCornerIndices;
65
  int[][] mEdgeMap,mCenterMap;
66
  Static4D[] mBasicCornerV, mCurrCornerV;
67
  ScrambleState[] mStates;
68

    
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

    
71
  TwistyMinx(InitData data, int meshState, int iconMode, Static4D quat, Static3D move, float scale, InputStream stream)
72
    {
73
    super(data, meshState, iconMode, data.getNumLayers()[0], quat, move, scale, stream);
74
    }
75

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

    
78
  public ScrambleState[] getScrambleStates()
79
    {
80
    if( mStates==null )
81
      {
82
      int[] numLayers = getNumLayers();
83
      initializeScrambleStates(numLayers[0]);
84
      }
85

    
86
    return mStates;
87
    }
88

    
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

    
91
  void initializeCornerV()
92
    {
93
    mBasicCornerV = new Static4D[3];
94
    mCurrCornerV  = new Static4D[3];
95

    
96
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
97
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
98
    mBasicCornerV[2] = new Static4D(              0,        -1.500f,    0.0f, 0.0f );
99
    }
100

    
101
///////////////////////////////////////////////////////////////////////////////////////////////////
102
// the five vertices that form a given face. Order: the same as colors of the faces in TwistyMinx.
103

    
104
  void initializeCenterMap()
105
    {
106
    mCenterMap = new int[][]
107
         {
108
           { 0, 12,  8, 10, 16},
109
           { 0, 12,  4, 14,  2},
110
           { 0,  2, 18,  6, 16},
111
           { 6, 18, 11, 19,  7},
112
           { 3, 15,  9, 11, 19},
113
           { 4,  5, 15,  9, 14},
114
           { 1, 13,  5, 15,  3},
115
           { 1,  3, 19,  7, 17},
116
           {10, 16,  6,  7, 17},
117
           { 8, 13,  5,  4, 12},
118
           { 1, 13,  8, 10, 17},
119
           { 2, 14,  9, 11, 18},
120
         };
121
    }
122

    
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
// the quadruple ( corner1, corner2, face1, face2 ) defining an edge.
125
// In fact the 2 corners already define it, the faces only provide easy
126
// way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
127
// the 'left' or right of vector corner1 --> corner2, according to Quat.
128

    
129
  void initializeEdgeMap()
130
    {
131
    mEdgeMap = new int[][]
132
         {
133
           {  2,  0,  1,  2}, //0
134
           {  0, 12,  1,  0},
135
           { 12,  4,  1,  9},
136
           {  4, 14,  1,  5},
137
           { 14,  2,  1, 11},
138
           { 14,  9, 11,  5}, //5
139
           {  9, 11, 11,  4},
140
           { 11, 18, 11,  3},
141
           { 18,  2, 11,  2},
142
           { 18,  6,  2,  3},
143
           {  6, 16,  2,  8}, //10
144
           { 16,  0,  2,  0},
145
           { 16, 10,  0,  8},
146
           { 10,  8,  0, 10},
147
           {  8, 12,  0,  9},
148
           {  8, 13,  9, 10}, //15
149
           { 13,  5,  9,  6},
150
           {  5,  4,  9,  5},
151
           {  5, 15,  5,  6},
152
           { 15,  9,  5,  4},
153
           { 11, 19,  3,  4}, //20
154
           { 19,  7,  3,  7},
155
           {  7,  6,  3,  8},
156
           {  7, 17,  8,  7},
157
           { 17, 10,  8, 10},
158
           { 17,  1, 10,  7}, //25
159
           {  1,  3,  6,  7},
160
           {  3, 19,  4,  7},
161
           {  1, 13, 10,  6},
162
           {  3, 15,  6,  4},
163
         };
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  void initializeQuatIndices()
169
    {
170
    mQuatEdgeIndices = new int[]
171
      {
172
         0, 17, 18, 19, 20, 56, 25,  5, 24, 16,
173
         9, 44,  1, 34, 35, 27, 41, 50, 26, 54,
174
        15, 49, 39, 28, 10,  2, 48,  6, 46,  3
175
      };
176
    mQuatCornerIndices = new int[]
177
      {
178
         0, 29, 59, 48, 18, 53, 22, 49, 11, 54,
179
        10, 52, 17, 27, 19, 26,  9, 28, 23, 45
180
      };
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184
// Coordinates of all 20 corners of a Minx
185

    
186
  void initializeCorners()
187
    {
188
    float cA = 1.5f;
189
    float cB = 3*C2;
190
    float cC = 3*SIN54;
191

    
192
    mCorners = new float[][]
193
         {
194
             {  0, cA, cB},
195
             {  0, cA,-cB},
196
             {  0,-cA, cB},
197
             {  0,-cA,-cB},
198
             { cB,  0, cA},
199
             { cB,  0,-cA},
200
             {-cB,  0, cA},
201
             {-cB,  0,-cA},
202
             { cA, cB,  0},
203
             { cA,-cB,  0},
204
             {-cA, cB,  0},
205
             {-cA,-cB,  0},
206
             { cC, cC, cC},
207
             { cC, cC,-cC},
208
             { cC,-cC, cC},
209
             { cC,-cC,-cC},
210
             {-cC, cC, cC},
211
             {-cC, cC,-cC},
212
             {-cC,-cC, cC},
213
             {-cC,-cC,-cC},
214
         };
215
    }
216

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

    
219
  void initializeCenterCoords()
220
    {
221
    if( mCorners==null ) initializeCorners();
222
    if( mCenterMap==null ) initializeCenterMap();
223

    
224
    mCenterCoords = new float[NUM_CENTERS][3];
225

    
226
    for(int center=0; center<NUM_CENTERS; center++)
227
      {
228
      int[] map = mCenterMap[center];
229

    
230
      float x = mCorners[map[0]][0] +
231
                mCorners[map[1]][0] +
232
                mCorners[map[2]][0] +
233
                mCorners[map[3]][0] +
234
                mCorners[map[4]][0] ;
235

    
236
      float y = mCorners[map[0]][1] +
237
                mCorners[map[1]][1] +
238
                mCorners[map[2]][1] +
239
                mCorners[map[3]][1] +
240
                mCorners[map[4]][1] ;
241

    
242
      float z = mCorners[map[0]][2] +
243
                mCorners[map[1]][2] +
244
                mCorners[map[2]][2] +
245
                mCorners[map[3]][2] +
246
                mCorners[map[4]][2] ;
247

    
248
      mCenterCoords[center][0] = x/5;
249
      mCenterCoords[center][1] = y/5;
250
      mCenterCoords[center][2] = z/5;
251
      }
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

    
256
  private int[] generateL(int numLayers, int index)
257
    {
258
    int rows = (numLayers-1)/2;
259
    int[] ret = new int[3*4*rows];
260

    
261
    for(int i=0; i<rows; i++)
262
      {
263
      ret[12*i   ] = i;
264
      ret[12*i+ 1] =-2;
265
      ret[12*i+ 2] = index;
266
      ret[12*i+ 3] = i;
267
      ret[12*i+ 4] =-1;
268
      ret[12*i+ 5] = index;
269
      ret[12*i+ 6] = i;
270
      ret[12*i+ 7] =+1;
271
      ret[12*i+ 8] = index;
272
      ret[12*i+ 9] = i;
273
      ret[12*i+10] =+2;
274
      ret[12*i+11] = index;
275
      }
276

    
277
    return ret;
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  private int[] generateR(int numLayers, int index)
283
    {
284
    int rows = (numLayers-1)/2;
285
    int[] ret = new int[3*4*rows];
286

    
287
    for(int i=0; i<rows; i++)
288
      {
289
      int lay = rows+i+1;
290

    
291
      ret[12*i   ] = lay;
292
      ret[12*i+ 1] =-2;
293
      ret[12*i+ 2] = index;
294
      ret[12*i+ 3] = lay;
295
      ret[12*i+ 4] =-1;
296
      ret[12*i+ 5] = index;
297
      ret[12*i+ 6] = lay;
298
      ret[12*i+ 7] =+1;
299
      ret[12*i+ 8] = index;
300
      ret[12*i+ 9] = lay;
301
      ret[12*i+10] =+2;
302
      ret[12*i+11] = index;
303
      }
304

    
305
    return ret;
306
    }
307

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309

    
310
  private int[] generateB(int numLayers, int index)
311
    {
312
    int rows = (numLayers-1);
313
    int half = rows/2;
314
    int[] ret = new int[3*4*rows];
315

    
316
    for(int i=0; i<rows; i++)
317
      {
318
      int ind = i<half? index : index+1;
319
      int lay = i<half? i : i+1;
320

    
321
      ret[12*i   ] = lay;
322
      ret[12*i+ 1] =-2;
323
      ret[12*i+ 2] = ind;
324
      ret[12*i+ 3] = lay;
325
      ret[12*i+ 4] =-1;
326
      ret[12*i+ 5] = ind;
327
      ret[12*i+ 6] = lay;
328
      ret[12*i+ 7] =+1;
329
      ret[12*i+ 8] = ind;
330
      ret[12*i+ 9] = lay;
331
      ret[12*i+10] =+2;
332
      ret[12*i+11] = ind;
333
      }
334

    
335
    return ret;
336
    }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

    
340
  private void initializeScrambleStates(int numLayers)
341
    {
342
    int[] LEFT0 = generateL(numLayers,1);
343
    int[] RIGH0 = generateR(numLayers,2);
344
    int[] LEFT1 = generateL(numLayers,3);
345
    int[] RIGH1 = generateR(numLayers,4);
346
    int[] LEFT2 = generateL(numLayers,5);
347
    int[] RIGH2 = generateR(numLayers,6);
348
    int[] LEFT3 = generateL(numLayers,7);
349
    int[] RIGH3 = generateR(numLayers,8);
350
    int[] LEFT4 = generateL(numLayers,9);
351
    int[] RIGH4 = generateR(numLayers,10);
352
    int[] LEFT5 = generateL(numLayers,11);
353
    int[] RIGH5 = generateR(numLayers,12);
354

    
355
    int[] BOTH1 = generateB(numLayers,1);
356
    int[] BOTH3 = generateB(numLayers,3);
357
    int[] BOTH5 = generateB(numLayers,5);
358
    int[] BOTH7 = generateB(numLayers,7);
359
    int[] BOTH9 = generateB(numLayers,9);
360
    int[] BOTH11= generateB(numLayers,11);
361

    
362
    mStates = new ScrambleState[]
363
      {
364
      new ScrambleState( new int[][] { BOTH1,BOTH3,BOTH5,BOTH7,BOTH9,BOTH11 } ), // beg
365
      new ScrambleState( new int[][] { {}   ,RIGH1,LEFT2,RIGH3,LEFT4,LEFT5  } ), // 0L
366
      new ScrambleState( new int[][] { {}   ,LEFT1,RIGH2,LEFT3,RIGH4,RIGH5  } ), // 0R
367
      new ScrambleState( new int[][] { RIGH0,{}   ,LEFT2,RIGH3,RIGH4,RIGH5  } ), // 1L
368
      new ScrambleState( new int[][] { LEFT0,{}   ,RIGH2,LEFT3,LEFT4,LEFT5  } ), // 1R
369
      new ScrambleState( new int[][] { LEFT0,LEFT1,{}   ,RIGH3,LEFT4,RIGH5  } ), // 2L
370
      new ScrambleState( new int[][] { RIGH0,RIGH1,{}   ,LEFT3,RIGH4,LEFT5  } ), // 2R
371
      new ScrambleState( new int[][] { RIGH0,RIGH1,RIGH2,{}   ,LEFT4,RIGH5  } ), // 3L
372
      new ScrambleState( new int[][] { LEFT0,LEFT1,LEFT2,{}   ,RIGH4,LEFT5  } ), // 3R
373
      new ScrambleState( new int[][] { LEFT0,RIGH1,LEFT2,LEFT3,{}   ,RIGH5  } ), // 4L
374
      new ScrambleState( new int[][] { RIGH0,LEFT1,RIGH2,RIGH3,{}   ,LEFT5  } ), // 4R
375
      new ScrambleState( new int[][] { LEFT0,RIGH1,RIGH2,RIGH3,RIGH4,{}     } ), // 5L
376
      new ScrambleState( new int[][] { RIGH0,LEFT1,LEFT2,LEFT3,LEFT4,{}     } ), // 5R
377
      };
378
    }
379

    
380
///////////////////////////////////////////////////////////////////////////////////////////////////
381

    
382
  float[][] genericGetCuts(int numLayers, float dist)
383
    {
384
    if( mCuts==null )
385
      {
386
      mCuts = new float[6][numLayers-1];
387
      float D = numLayers* TouchControlDodecahedron.DIST3D;
388
      float X = 2*D/(2+SIN18);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
389
                                // its height is then 2D, it has one 'lower' part of height X, one
390
                                // 'middle' part of height Y and one upper part of height X again.
391
      int num = (numLayers-1)/2;
392
      float G = X*dist/num;     // height of one Layer
393

    
394
      for(int i=0; i<num; i++)
395
        {
396
        float cut = -D + (i+0.85f)*G;  // 0.85? not fully correct; attempt to make it
397
                                       // easier to rotate the outer layers
398
        int j = 2*num-1-i;
399
        mCuts[0][i] = +cut;
400
        mCuts[0][j] = -cut;
401
        mCuts[1][i] = +cut;
402
        mCuts[1][j] = -cut;
403
        mCuts[2][i] = +cut;
404
        mCuts[2][j] = -cut;
405
        mCuts[3][i] = +cut;
406
        mCuts[3][j] = -cut;
407
        mCuts[4][i] = +cut;
408
        mCuts[4][j] = -cut;
409
        mCuts[5][i] = +cut;
410
        mCuts[5][j] = -cut;
411
        }
412
      }
413

    
414
    return mCuts;
415
    }
416

    
417
///////////////////////////////////////////////////////////////////////////////////////////////////
418

    
419
  public boolean[][] getLayerRotatable(int[] numLayers)
420
    {
421
    int numAxis = ROT_AXIS.length;
422
    boolean[][] layerRotatable = new boolean[numAxis][];
423

    
424
    for(int i=0; i<numAxis; i++)
425
      {
426
      layerRotatable[i] = new boolean[numLayers[i]];
427
      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
428
      layerRotatable[i][numLayers[i]/2] = false;
429
      }
430

    
431
    return layerRotatable;
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

    
436
  public int getTouchControlType()
437
    {
438
    return TC_DODECAHEDRON;
439
    }
440

    
441
///////////////////////////////////////////////////////////////////////////////////////////////////
442

    
443
  public int getTouchControlSplit()
444
    {
445
    return TYPE_SPLIT_EDGE;
446
    }
447

    
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449

    
450
  public int[][][] getEnabled()
451
    {
452
    return new int[][][]
453
      {
454
          {{2,3},{3,5},{1,5},{1,4},{2,4}},
455
          {{0,5},{2,5},{2,3},{3,4},{0,4}},
456
          {{2,3},{2,5},{0,5},{0,4},{3,4}},
457
          {{1,5},{3,5},{2,3},{2,4},{1,4}},
458
          {{0,3},{0,4},{4,5},{1,5},{1,3}},
459
          {{1,2},{1,4},{4,5},{0,5},{0,2}},
460
          {{4,5},{1,4},{1,2},{0,2},{0,5}},
461
          {{4,5},{0,4},{0,3},{1,3},{1,5}},
462
          {{0,2},{0,1},{1,3},{3,5},{2,5}},
463
          {{3,4},{2,4},{1,2},{0,1},{0,3}},
464
          {{2,4},{3,4},{0,3},{0,1},{1,2}},
465
          {{1,3},{0,1},{0,2},{2,5},{3,5}},
466
      };
467
    }
468

    
469
///////////////////////////////////////////////////////////////////////////////////////////////////
470

    
471
  public float[] getDist3D(int[] numLayers)
472
    {
473
    return TouchControlDodecahedron.D3D;
474
    }
475

    
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477

    
478
  public Static3D[] getFaceAxis()
479
    {
480
    return TouchControlDodecahedron.FACE_AXIS;
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484
// PUBLIC API
485

    
486
  public Static3D[] getRotationAxis()
487
    {
488
    return ROT_AXIS;
489
    }
490

    
491
///////////////////////////////////////////////////////////////////////////////////////////////////
492

    
493
  public int[][] getBasicAngles()
494
    {
495
    if( mBasicAngle ==null )
496
      {
497
      int num = getNumLayers()[0];
498
      int[] tmp = new int[num];
499
      for(int i=0; i<num; i++) tmp[i] = 5;
500
      mBasicAngle = new int[][] { tmp,tmp,tmp,tmp,tmp,tmp };
501
      }
502

    
503
    return mBasicAngle;
504
    }
505
}
(22-22/40)