Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / objects / TwistyDodecahedron.java @ 8f5116ec

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 org.distorted.library.type.Static3D;
19
import org.distorted.library.type.Static4D;
20
import org.distorted.objectlib.main.InitAssets;
21
import org.distorted.objectlib.metadata.Metadata;
22
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
23
import org.distorted.objectlib.shape.ShapeDodecahedron;
24

    
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26

    
27
public abstract class TwistyDodecahedron extends ShapeDodecahedron
28
{
29
  public static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
30
  public static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
31

    
32
  static final int NUM_CORNERS = 20;
33
  static final int NUM_CENTERS = 12;
34
  static final int NUM_EDGES   = 30;
35

    
36
  static final float SIN18    = (SQ5-1)/4;
37
  static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
38

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

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

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

    
60
  TwistyDodecahedron(int iconMode, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
61
    {
62
    super(iconMode, meta.getNumLayers()[0], quat, move, scale, meta, asset);
63
    }
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  private void fillRet(int[] table, int index, int count, int startMove, int graphVertex)
68
    {
69
    for(int i=0; i<count; i++)
70
      {
71
      table[index+2*i  ] = startMove++;
72
      table[index+2*i+1] = graphVertex;
73
      }
74
    }
75

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

    
78
  private int[] genEdge(int numLayers, int x0, int x1, int x2, int x3, int x4, int x5,
79
                                       int x6, int x7, int x8, int x9, int x10,int x11)
80
    {
81
    int layers = (numLayers-1)/2;
82
    int num = 8*layers;
83
    int size = 0;
84

    
85
    int count   = 4*layers;
86
    int offset1 = 4*layers + (numLayers%2==1 ? 4:0);  // omit the middle layer, if it exists.
87
    int offset2 = 4*layers;
88

    
89
    if( x0 >=0 ) size += num;
90
    if( x1 >=0 ) size += num;
91
    if( x2 >=0 ) size += num;
92
    if( x3 >=0 ) size += num;
93
    if( x4 >=0 ) size += num;
94
    if( x5 >=0 ) size += num;
95
    if( x6 >=0 ) size += num;
96
    if( x7 >=0 ) size += num;
97
    if( x8 >=0 ) size += num;
98
    if( x9 >=0 ) size += num;
99
    if( x10>=0 ) size += num;
100
    if( x11>=0 ) size += num;
101

    
102
    int[] ret = new int[size];
103
    int index = 0;
104
    int startMove = 0;
105

    
106
    if( x0 >=0 ) { fillRet(ret,index,count,startMove ,x0 ); index+=num; }
107
    startMove += offset1;
108
    if( x1 >=0 ) { fillRet(ret,index,count,startMove ,x1 ); index+=num; }
109
    startMove += offset2;
110
    if( x2 >=0 ) { fillRet(ret,index,count,startMove ,x2 ); index+=num; }
111
    startMove += offset1;
112
    if( x3 >=0 ) { fillRet(ret,index,count,startMove ,x3 ); index+=num; }
113
    startMove += offset2;
114
    if( x4 >=0 ) { fillRet(ret,index,count,startMove ,x4 ); index+=num; }
115
    startMove += offset1;
116
    if( x5 >=0 ) { fillRet(ret,index,count,startMove ,x5 ); index+=num; }
117
    startMove += offset2;
118
    if( x6 >=0 ) { fillRet(ret,index,count,startMove ,x6 ); index+=num; }
119
    startMove += offset1;
120
    if( x7 >=0 ) { fillRet(ret,index,count,startMove ,x7 ); index+=num; }
121
    startMove += offset2;
122
    if( x8 >=0 ) { fillRet(ret,index,count,startMove ,x8 ); index+=num; }
123
    startMove += offset1;
124
    if( x9 >=0 ) { fillRet(ret,index,count,startMove ,x9 ); index+=num; }
125
    startMove += offset2;
126
    if( x10>=0 ) { fillRet(ret,index,count,startMove ,x10); index+=num; }
127
    startMove += offset1;
128
    if( x11>=0 ) { fillRet(ret,index,count,startMove ,x11);             }
129

    
130
    return ret;
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  public int[][] getScrambleEdges()
136
    {
137
    if( mEdges==null )
138
      {
139
      int nL = getNumLayers()[0];
140

    
141
      mEdges = new int[][]
142
        {
143
        genEdge(nL, 1, 2,  3, 4,  5, 6,  7, 8,  9,10, 11,12),  // 0
144
        genEdge(nL,-1,-1, -1, 4,  5,-1, -1, 8,  9,-1, 11,-1),  // 0L
145
        genEdge(nL,-1,-1,  3,-1, -1, 6,  7,-1, -1,10, -1,12),  // 0R
146
        genEdge(nL,-1, 2, -1,-1,  5,-1, -1, 8, -1,10, -1,12),  // 1L
147
        genEdge(nL, 1,-1, -1,-1, -1, 6,  7,-1,  9,-1, 11,-1),  // 1R
148
        genEdge(nL, 1,-1,  3,-1, -1,-1, -1, 8,  9,-1, -1,12),  // 2L
149
        genEdge(nL,-1, 2, -1, 4, -1,-1,  7,-1, -1,10, 11,-1),  // 2R
150
        genEdge(nL,-1, 2, -1, 4, -1, 6, -1,-1,  9,-1, -1,12),  // 3L
151
        genEdge(nL, 1,-1,  3,-1,  5,-1, -1,-1, -1,10, 11,-1),  // 3R
152
        genEdge(nL, 1,-1, -1, 4,  5,-1,  7,-1, -1,-1, -1,12),  // 4L
153
        genEdge(nL,-1, 2,  3,-1,  5,-1, -1, 8, -1,-1, 11,-1),  // 4R
154
        genEdge(nL, 1,-1, -1, 4, -1, 6, -1, 8, -1,10, -1,-1),  // 5L
155
        genEdge(nL,-1, 2,  3,-1,  5,-1,  7,-1,  9,-1, -1,-1),  // 5R
156
        };
157
      }
158

    
159
    return mEdges;
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

    
164
  void initializeCornerV()
165
    {
166
    mBasicCornerV = new Static4D[3];
167
    mCurrCornerV  = new Static4D[3];
168

    
169
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
170
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
171
    mBasicCornerV[2] = new Static4D(              0,        -1.500f,    0.0f, 0.0f );
172
    }
173

    
174
///////////////////////////////////////////////////////////////////////////////////////////////////
175
// the five vertices that form a given face. Order: the same as colors of the faces in TwistyMinx.
176

    
177
  public static int[][] initializeCenterMap()
178
    {
179
    return new int[][]
180
         {
181
           { 0, 12,  8, 10, 16},
182
           { 0, 12,  4, 14,  2},
183
           { 0,  2, 18,  6, 16},
184
           { 6, 18, 11, 19,  7},
185
           { 3, 15,  9, 11, 19},
186
           { 4,  5, 15,  9, 14},
187
           { 1, 13,  5, 15,  3},
188
           { 1,  3, 19,  7, 17},
189
           {10, 16,  6,  7, 17},
190
           { 8, 13,  5,  4, 12},
191
           { 1, 13,  8, 10, 17},
192
           { 2, 14,  9, 11, 18},
193
         };
194
    }
195

    
196
///////////////////////////////////////////////////////////////////////////////////////////////////
197
// the quadruple ( corner1, corner2, face1, face2 ) defining an edge.
198
// In fact the 2 corners already define it, the faces only provide easy
199
// way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
200
// the 'left' or right of vector corner1 --> corner2, according to Quat.
201

    
202
  public static int[][] initializeEdgeMap()
203
    {
204
    return new int[][]
205
         {
206
           {  2,  0,  1,  2}, //0
207
           {  0, 12,  1,  0},
208
           { 12,  4,  1,  9},
209
           {  4, 14,  1,  5},
210
           { 14,  2,  1, 11},
211
           { 14,  9, 11,  5}, //5
212
           {  9, 11, 11,  4},
213
           { 11, 18, 11,  3},
214
           { 18,  2, 11,  2},
215
           { 18,  6,  2,  3},
216
           {  6, 16,  2,  8}, //10
217
           { 16,  0,  2,  0},
218
           { 16, 10,  0,  8},
219
           { 10,  8,  0, 10},
220
           {  8, 12,  0,  9},
221
           {  8, 13,  9, 10}, //15
222
           { 13,  5,  9,  6},
223
           {  5,  4,  9,  5},
224
           {  5, 15,  5,  6},
225
           { 15,  9,  5,  4},
226
           { 11, 19,  3,  4}, //20
227
           { 19,  7,  3,  7},
228
           {  7,  6,  3,  8},
229
           {  7, 17,  8,  7},
230
           { 17, 10,  8, 10},
231
           { 17,  1, 10,  7}, //25
232
           {  1,  3,  6,  7},
233
           {  3, 19,  4,  7},
234
           {  1, 13, 10,  6},
235
           {  3, 15,  6,  4},
236
         };
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  void initializeQuatIndices()
242
    {
243
    mQuatEdgeIndices = new int[]
244
      {
245
         0, 17, 18, 19, 20, 56, 25,  5, 24, 16,
246
         9, 44,  1, 34, 35, 27, 41, 50, 26, 54,
247
        15, 49, 39, 28, 10,  2, 48,  6, 46,  3
248
      };
249
    mQuatCornerIndices = new int[]
250
      {
251
         0, 29, 59, 48, 18, 53, 22, 49, 11, 54,
252
        10, 52, 17, 27, 19, 26,  9, 28, 23, 45
253
      };
254
    }
255

    
256
///////////////////////////////////////////////////////////////////////////////////////////////////
257
// Coordinates of all 20 corners of a Minx
258

    
259
  public static float[][] initializeCorners()
260
    {
261
    float cA = 1.5f;
262
    float cB = 3*C2;
263
    float cC = 3*SIN54;
264

    
265
    return new float[][]
266
         {
267
             {  0, cA, cB},
268
             {  0, cA,-cB},
269
             {  0,-cA, cB},
270
             {  0,-cA,-cB},
271
             { cB,  0, cA},
272
             { cB,  0,-cA},
273
             {-cB,  0, cA},
274
             {-cB,  0,-cA},
275
             { cA, cB,  0},
276
             { cA,-cB,  0},
277
             {-cA, cB,  0},
278
             {-cA,-cB,  0},
279
             { cC, cC, cC},
280
             { cC, cC,-cC},
281
             { cC,-cC, cC},
282
             { cC,-cC,-cC},
283
             {-cC, cC, cC},
284
             {-cC, cC,-cC},
285
             {-cC,-cC, cC},
286
             {-cC,-cC,-cC},
287
         };
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  void initializeCenterCoords()
293
    {
294
    if( mCorners==null ) mCorners = initializeCorners();
295
    if( mCenterMap==null ) mCenterMap = initializeCenterMap();
296

    
297
    mCenterCoords = new float[NUM_CENTERS][3];
298

    
299
    for(int center=0; center<NUM_CENTERS; center++)
300
      {
301
      int[] map = mCenterMap[center];
302

    
303
      float x = mCorners[map[0]][0] +
304
                mCorners[map[1]][0] +
305
                mCorners[map[2]][0] +
306
                mCorners[map[3]][0] +
307
                mCorners[map[4]][0] ;
308

    
309
      float y = mCorners[map[0]][1] +
310
                mCorners[map[1]][1] +
311
                mCorners[map[2]][1] +
312
                mCorners[map[3]][1] +
313
                mCorners[map[4]][1] ;
314

    
315
      float z = mCorners[map[0]][2] +
316
                mCorners[map[1]][2] +
317
                mCorners[map[2]][2] +
318
                mCorners[map[3]][2] +
319
                mCorners[map[4]][2] ;
320

    
321
      mCenterCoords[center][0] = x/5;
322
      mCenterCoords[center][1] = y/5;
323
      mCenterCoords[center][2] = z/5;
324
      }
325
    }
326

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328

    
329
  float[][] genericGetCuts(int numLayers, float dist)
330
    {
331
    if( mCuts==null )
332
      {
333
      mCuts = new float[6][numLayers-1];
334
      float D = numLayers* TouchControlDodecahedron.DIST3D;
335
      float X = 2*D/(2+SIN18);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
336
                                // its height is then 2D, it has one 'lower' part of height X, one
337
                                // 'middle' part of height Y and one upper part of height X again.
338
      int num = (numLayers-1)/2;
339
      float G = X*dist/num;     // height of one Layer
340

    
341
      for(int i=0; i<num; i++)
342
        {
343
        float cut = -D + (i+0.85f)*G;  // 0.85? not fully correct; attempt to make it
344
                                       // easier to rotate the outer layers
345
        int j = 2*num-1-i;
346
        mCuts[0][i] =  cut;
347
        mCuts[0][j] = -cut;
348
        mCuts[1][i] =  cut;
349
        mCuts[1][j] = -cut;
350
        mCuts[2][i] =  cut;
351
        mCuts[2][j] = -cut;
352
        mCuts[3][i] =  cut;
353
        mCuts[3][j] = -cut;
354
        mCuts[4][i] =  cut;
355
        mCuts[4][j] = -cut;
356
        mCuts[5][i] =  cut;
357
        mCuts[5][j] = -cut;
358
        }
359
      }
360

    
361
    return mCuts;
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  public boolean[][] getLayerRotatable(int[] numLayers)
367
    {
368
    int numAxis = ROT_AXIS.length;
369
    boolean[][] layerRotatable = new boolean[numAxis][];
370

    
371
    for(int i=0; i<numAxis; i++)
372
      {
373
      int num = numLayers[i];
374
      layerRotatable[i] = new boolean[num];
375
      for(int j=0; j<num; j++) layerRotatable[i][j] = true;
376
      layerRotatable[i][num/2] = false;
377
      }
378

    
379
    return layerRotatable;
380
    }
381

    
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383

    
384
  public int getTouchControlType()
385
    {
386
    return TC_DODECAHEDRON;
387
    }
388

    
389
///////////////////////////////////////////////////////////////////////////////////////////////////
390

    
391
  public int getTouchControlSplit()
392
    {
393
    return TYPE_SPLIT_EDGE;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  public int[][][] getEnabled()
399
    {
400
    return new int[][][]
401
      {
402
          {{2,3},{3,5},{1,5},{1,4},{2,4}},
403
          {{0,5},{2,5},{2,3},{3,4},{0,4}},
404
          {{2,3},{2,5},{0,5},{0,4},{3,4}},
405
          {{1,5},{3,5},{2,3},{2,4},{1,4}},
406
          {{0,3},{0,4},{4,5},{1,5},{1,3}},
407
          {{1,2},{1,4},{4,5},{0,5},{0,2}},
408
          {{4,5},{1,4},{1,2},{0,2},{0,5}},
409
          {{4,5},{0,4},{0,3},{1,3},{1,5}},
410
          {{0,2},{0,1},{1,3},{3,5},{2,5}},
411
          {{3,4},{2,4},{1,2},{0,1},{0,3}},
412
          {{2,4},{3,4},{0,3},{0,1},{1,2}},
413
          {{1,3},{0,1},{0,2},{2,5},{3,5}},
414
      };
415
    }
416

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

    
419
  public float[] getDist3D(int[] numLayers)
420
    {
421
    return TouchControlDodecahedron.D3D;
422
    }
423

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

    
426
  public Static3D[] getFaceAxis()
427
    {
428
    return TouchControlDodecahedron.FACE_AXIS;
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432
// PUBLIC API
433

    
434
  public Static3D[] getRotationAxis()
435
    {
436
    return ROT_AXIS;
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

    
441
  public int[][] getBasicAngles()
442
    {
443
    if( mBasicAngle==null )
444
      {
445
      int num = getNumLayers()[0];
446
      int[] tmp = new int[num];
447
      for(int i=0; i<num; i++) tmp[i] = 5;
448
      mBasicAngle = new int[][] { tmp,tmp,tmp,tmp,tmp,tmp };
449
      }
450

    
451
    return mBasicAngle;
452
    }
453
}
(21-21/59)