Project

General

Profile

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

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

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.touchcontrol.TouchControlDodecahedron;
33
import org.distorted.objectlib.scrambling.ScrambleState;
34
import org.distorted.objectlib.main.ShapeDodecahedron;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

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

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

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

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

    
68
///////////////////////////////////////////////////////////////////////////////////////////////////
69

    
70
  TwistyMinx(int[] numL, int meshState, int iconMode, Static4D quat, Static3D move, float scale, InputStream stream)
71
    {
72
    super(numL, meshState, iconMode, numL[0], quat, move, scale, stream);
73
    }
74

    
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76

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

    
85
    return mStates;
86
    }
87

    
88
///////////////////////////////////////////////////////////////////////////////////////////////////
89

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

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

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

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

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

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

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

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

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

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

    
191
    mCorners = new float[][]
192
         {
193
             {  0, cA, cB},
194
             {  0, cA,-cB},
195
             {  0,-cA, cB},
196
             {  0,-cA,-cB},
197
             { cB,  0, cA},
198
             { cB,  0,-cA},
199
             {-cB,  0, cA},
200
             {-cB,  0,-cA},
201
             { cA, cB,  0},
202
             { cA,-cB,  0},
203
             {-cA, cB,  0},
204
             {-cA,-cB,  0},
205
             { cC, cC, cC},
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
         };
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

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

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

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

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

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

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

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

    
253
///////////////////////////////////////////////////////////////////////////////////////////////////
254

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

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

    
276
    return ret;
277
    }
278

    
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280

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

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

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

    
304
    return ret;
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

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

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

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

    
334
    return ret;
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338

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

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

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

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380

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

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

    
413
    return mCuts;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

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

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

    
430
    return layerRotatable;
431
    }
432

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

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

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

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

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

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

    
468
///////////////////////////////////////////////////////////////////////////////////////////////////
469

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

    
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476

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

    
482
///////////////////////////////////////////////////////////////////////////////////////////////////
483
// PUBLIC API
484

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

    
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491

    
492
  public int[] getBasicAngles()
493
    {
494
    if( mBasicAngle ==null ) mBasicAngle = new int[] { 5,5,5,5,5,5 };
495
    return mBasicAngle;
496
    }
497
}
(21-21/36)