Project

General

Profile

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

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

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.helpers.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 ScrambleState[] mStates;
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

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

    
70
  TwistyMinx(int[] numL, int meshState, Static4D quat, Static3D move, float scale, InputStream stream)
71
    {
72
    super(numL, meshState, 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,  4, 14,  2},
108
           { 0,  2, 18,  6, 16},
109
           { 6, 18, 11, 19,  7},
110
           { 3, 15,  9, 11, 19},
111
           { 4,  5, 15,  9, 14},
112
           { 1, 13,  5, 15,  3},
113
           { 1,  3, 19,  7, 17},
114
           {10, 16,  6,  7, 17},
115
           { 0, 12,  8, 10, 16},
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
           {  0, 12,  0,  8}, //0
133
           { 12,  4,  0,  9},
134
           {  4, 14,  0,  4},
135
           { 14,  2,  0, 11},
136
           {  2,  0,  0,  1},
137
           { 14,  9, 11,  4}, //5
138
           {  9, 11, 11,  3},
139
           { 11, 18, 11,  2},
140
           { 18,  2, 11,  1},
141
           { 18,  6,  1,  2},
142
           {  6, 16,  1,  7}, //10
143
           { 16,  0,  1,  8},
144
           { 16, 10,  8,  7},
145
           { 10,  8,  8, 10},
146
           {  8, 12,  8,  9},
147
           {  8, 13,  9, 10}, //15
148
           { 13,  5,  9,  5},
149
           {  5,  4,  9,  4},
150
           {  5, 15,  4,  5},
151
           { 15,  9,  4,  3},
152
           { 11, 19,  2,  3}, //20
153
           { 19,  7,  2,  6},
154
           {  7,  6,  2,  7},
155
           {  7, 17,  7,  6},
156
           { 17, 10,  7, 10},
157
           { 17,  1, 10,  6}, //25
158
           {  1,  3,  5,  6},
159
           {  3, 19,  3,  6},
160
           {  1, 13, 10,  5},
161
           {  3, 15,  5,  3},
162
         };
163
    }
164

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

    
167
  void initializeQuatIndices()
168
    {
169
    mQuatEdgeIndices = new int[]
170
      {
171
        17, 18, 19, 20,  0, 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
  public int[] getSolvedQuats(int cubit, int[] numLayers)
382
    {
383
    int status = retCubitSolvedStatus(cubit,numLayers);
384
    return status<0 ? null : buildSolvedQuats(TouchControlDodecahedron.FACE_AXIS[status],mObjectQuats);
385
    }
386

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

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

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

    
421
    return mCuts;
422
    }
423

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

    
426
  public boolean[][] getLayerRotatable(int[] numLayers)
427
    {
428
    int numAxis = ROT_AXIS.length;
429
    boolean[][] layerRotatable = new boolean[numAxis][];
430

    
431
    for(int i=0; i<numAxis; i++)
432
      {
433
      layerRotatable[i] = new boolean[numLayers[i]];
434
      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
435
      layerRotatable[i][numLayers[i]/2] = false;
436
      }
437

    
438
    return layerRotatable;
439
    }
440

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

    
443
  public int getTouchControlType()
444
    {
445
    return TC_DODECAHEDRON;
446
    }
447

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

    
450
  public int getTouchControlSplit()
451
    {
452
    return TYPE_SPLIT_EDGE;
453
    }
454

    
455
///////////////////////////////////////////////////////////////////////////////////////////////////
456

    
457
  public int[][][] getEnabled()
458
    {
459
    return new int[][][]
460
      {
461
          {{2,3},{3,5},{1,5},{1,4},{2,4}},
462
          {{0,5},{2,5},{2,3},{3,4},{0,4}},
463
          {{2,3},{2,5},{0,5},{0,4},{3,4}},
464
          {{1,5},{3,5},{2,3},{2,4},{1,4}},
465
          {{0,3},{0,4},{4,5},{1,5},{1,3}},
466
          {{1,2},{1,4},{4,5},{0,5},{0,2}},
467
          {{4,5},{1,4},{1,2},{0,2},{0,5}},
468
          {{4,5},{0,4},{0,3},{1,3},{1,5}},
469
          {{0,2},{0,1},{1,3},{3,5},{2,5}},
470
          {{3,4},{2,4},{1,2},{0,1},{0,3}},
471
          {{2,4},{3,4},{0,3},{0,1},{1,2}},
472
          {{1,3},{0,1},{0,2},{2,5},{3,5}},
473
      };
474
    }
475

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

    
478
  public float[] getDist3D(int[] numLayers)
479
    {
480
    return TouchControlDodecahedron.D3D;
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484

    
485
  public Static3D[] getFaceAxis()
486
    {
487
    return TouchControlDodecahedron.FACE_AXIS;
488
    }
489

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

    
492
  public int getSolvedFunctionIndex()
493
    {
494
    return 0;
495
    }
496

    
497
///////////////////////////////////////////////////////////////////////////////////////////////////
498
// PUBLIC API
499

    
500
  public Static3D[] getRotationAxis()
501
    {
502
    return ROT_AXIS;
503
    }
504

    
505
///////////////////////////////////////////////////////////////////////////////////////////////////
506

    
507
  public int[] getBasicAngles()
508
    {
509
    if( mBasicAngle ==null ) mBasicAngle = new int[] { 5,5,5,5,5,5 };
510
    return mBasicAngle;
511
    }
512
}
(16-16/26)