Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / bandaged / FactoryBandagedMegaminx.java @ 1eafa9c6

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 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.bandaged;
11

    
12
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.COS18;
13
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.MEGA_D;
14
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.SIN18;
15
import static org.distorted.objectlib.main.TwistyObject.SQ5;
16
import static org.distorted.objectlib.objects.TwistyDodecahedron.COS_HALFD;
17
import static org.distorted.objectlib.objects.TwistyDodecahedron.SIN_HALFD;
18
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
19
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.COS54;
20
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.DIST2D;
21
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.DIST3D;
22
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
23
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
24

    
25
import org.distorted.library.helpers.QuatHelper;
26
import org.distorted.library.type.Static3D;
27
import org.distorted.library.type.Static4D;
28
import org.distorted.objectlib.helpers.QuatGroupGenerator;
29
import org.distorted.objectlib.objects.TwistyDodecahedron;
30
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
31

    
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33

    
34
public class FactoryBandagedMegaminx extends FactoryBandaged
35
  {
36
  private static final int MAX_SUPPORTED_SIZE = 5;
37

    
38
  private static final int NUM_CORNERS = 20;
39
  private static final int NUM_CENTERS = 12;
40
  private static final int NUM_EDGES   = 30;
41

    
42
  private static final float CENT_DIST_SQ = DIST3D*DIST3D;
43
  private static final float CORN_DIST_SQ = (18+6*SQ5)/16;
44
  private static final float EDGE_DIST_SQ = (14+6*SQ5)/16;
45
  private static final float EDHA_DIST_SQ = (15+6*SQ5)/16;
46

    
47
  private static FactoryBandagedMegaminx mThis;
48

    
49
  private static final Static3D[] ROT_AXIS = new Static3D[]
50
    {
51
    new Static3D(    C2/LEN, SIN54/LEN,    0      ),
52
    new Static3D(   -C2/LEN, SIN54/LEN,    0      ),
53
    new Static3D( 0        ,    C2/LEN, SIN54/LEN ),
54
    new Static3D( 0        ,   -C2/LEN, SIN54/LEN ),
55
    new Static3D( SIN54/LEN,    0     ,    C2/LEN ),
56
    new Static3D( SIN54/LEN,    0     ,   -C2/LEN )
57
    };
58

    
59
  private int[][] mEdgeMap, mCenterMap;
60
  private float[][] mCorners;
61
  private float[][][] mVertices;
62
  private int[][][] mIndices;
63
  private Static4D[] mObjectQuats, mBasicCornerV, mCurrCornerV;
64
  private int[] mQuatEdgeIndices,mQuatCornerIndices,mQuatCenterIndices;
65
  private float[][] mCenterCoords;
66

    
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

    
69
  private FactoryBandagedMegaminx()
70
    {
71

    
72
    }
73

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

    
76
  public static FactoryBandagedMegaminx getInstance()
77
    {
78
    if( mThis==null ) mThis = new FactoryBandagedMegaminx();
79
    return mThis;
80
    }
81

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83

    
84
  private float[][] retCenterKilominx(float width)
85
    {
86
    float X = width*COS18*SIN_HALFD;
87
    float Y = width*SIN18;
88
    float Z = width*COS18*COS_HALFD;
89
    float H = width*(SIN54/COS54);
90
    float H3= H/COS_HALFD;
91
    float X3= H*SIN_HALFD;
92
    float Z3= H*COS_HALFD;
93
    float C = 1/(COS54*(float)Math.sqrt(2-2*SIN18));
94

    
95
    return new float[][]
96
      {
97
       {   0,   0  ,     0 },
98
       {   X,   Y  ,    -Z },
99
       {   0,C*2*Y ,-2*C*Z },
100
       {  -X,   Y  ,    -Z },
101
       {   0,-width,     0 },
102
       {  X3,-width,   -Z3 },
103
       {   0,-width,   -H3 },
104
       { -X3,-width,   -Z3 }
105
      };
106
    }
107

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109

    
110
  private float[][] retEdgeKilominx(int variant)
111
    {
112
    int type = variant-1;
113
    float tmpVal= 1.0f;//numL/(numL-1.0f);
114
    float height= tmpVal*COS18;
115
    float width = tmpVal + (type/2)*tmpVal*SIN18;
116
    boolean left = (type%2)==0;
117

    
118
    float X = height*SIN_HALFD;
119
    float Y = height*SIN18/COS18;
120
    float Z = height*COS_HALFD;
121

    
122
    float[][] vertices =
123
      {
124
        {   0,   0   ,   0 },
125
        {   X,   Y   ,  -Z },
126
        {   0, 2*Y   ,-2*Z },
127
        {  -X,   Y   ,  -Z },
128
        {   0, -width,   0 },
129
        {   X, -width,  -Z },
130
        {   0, -width,-2*Z },
131
        {  -X, -width,  -Z },
132
      };
133

    
134
    if( !left )
135
      {
136
      int len = vertices.length;
137
      for(int i=0; i<len; i++) vertices[i][1] = -vertices[i][1];
138
      }
139

    
140
    return vertices;
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

    
145
  private float[][] retCornerMegaminx(float width)
146
    {
147
    float X = width*COS18*SIN_HALFD;
148
    float Y = width*SIN18;
149
    float Z = width*COS18*COS_HALFD;
150

    
151
    return new float[][]
152
      {
153
        {   0,   0      ,   0 },
154
        {   X,   Y      ,  -Z },
155
        {   0, 2*Y      ,-2*Z },
156
        {  -X,   Y      ,  -Z },
157
        {   0,   0-width,   0 },
158
        {   X,   Y-width,  -Z },
159
        {   0, 2*Y-width,-2*Z },
160
        {  -X,   Y-width,  -Z },
161
      };
162
    }
163

    
164
///////////////////////////////////////////////////////////////////////////////////////////////////
165

    
166
  private float[][] retEdgeMegaminx(int numL, int variant)
167
    {
168
    int type = variant-1;
169
    float height= numL*(0.5f-MEGA_D)*COS18/((numL-1)*0.5f);
170
    float width = numL*2*MEGA_D + 2*type*height*SIN18/COS18;
171

    
172
    float W = width/2;
173
    float X = height*SIN_HALFD;
174
    float Y = height*SIN18/COS18;
175
    float Z = height*COS_HALFD;
176

    
177
    return new float[][]
178
      {
179
        {   0,   W   ,   0 },
180
        {   X, W+Y   ,  -Z },
181
        {   0, W+2*Y ,-2*Z },
182
        {  -X, W+Y   ,  -Z },
183
        {   0,  -W   ,   0 },
184
        {   X,-W-Y   ,  -Z },
185
        {   0,-W-2*Y ,-2*Z },
186
        {  -X,-W-Y   ,  -Z },
187
      };
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

    
192
  private float[][] retCenterMegaminx(int numL)
193
    {
194
    float width = 2*numL*(MEGA_D+(0.5f-MEGA_D)*SIN18);
195
    final double ANGLE = 0.825f*Math.PI;
196
    final float cosA  = (float)Math.cos(ANGLE);
197
    final float sinA  = (float)Math.sin(ANGLE);
198

    
199
    float R  = 0.5f*width/COS54;
200
    float X1 = R*COS54;
201
    float Y1 = R*SIN54;
202
    float X2 = R*COS18;
203
    float Y2 = R*SIN18;
204

    
205
    return new float[][]
206
      {
207
       {-X1, Y1*sinA, Y1*cosA},
208
       {-X2,-Y2*sinA,-Y2*cosA},
209
       { 0 ,-R*sinA ,-R*cosA },
210
       {+X2,-Y2*sinA,-Y2*cosA},
211
       {+X1, Y1*sinA, Y1*cosA},
212
       { 0 , R*cosA ,-R*sinA }
213
      };
214
    }
215

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

    
218
  private float[][] verticesKilominx()
219
    {
220
    if( mVertices[0]==null ) mVertices[0] = retCenterKilominx(1.0f);
221
    return mVertices[0];
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225

    
226
  private float[][] verticesMegaminx(int variant)
227
    {
228
    switch(variant)
229
      {
230
      case 0: if( mVertices[1]==null ) mVertices[1] = retCornerMegaminx(3*(0.5f-MEGA_D));
231
              break;
232
      case 1: if( mVertices[2]==null ) mVertices[2] = retEdgeMegaminx(3,variant);
233
              break;
234
      case 2: if( mVertices[3]==null ) mVertices[3] = retCenterMegaminx(3);
235
              break;
236
      }
237

    
238
    return mVertices[variant+1];
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  private float[][] verticesMasterKilominx(int variant)
244
    {
245
    switch(variant)
246
      {
247
      case 0: if( mVertices[4]==null ) mVertices[4] = retCornerMegaminx( 1.0f );
248
              break;
249
      case 1: if( mVertices[5]==null ) mVertices[5] = retEdgeKilominx(variant);
250
              break;
251
      case 2: if( mVertices[6]==null ) mVertices[6] = retEdgeKilominx(variant);
252
              break;
253
      case 3: if( mVertices[7]==null ) mVertices[7] = retCenterKilominx(1+SIN18);
254
              break;
255
      }
256

    
257
    return mVertices[variant+1+3];
258
    }
259

    
260
///////////////////////////////////////////////////////////////////////////////////////////////////
261

    
262
  private float[][] verticesGigaminx(int variant)
263
    {
264
    switch(variant)
265
      {
266
      case 0: if( mVertices[ 8]==null ) mVertices[ 8] = retCornerMegaminx( 2.5f*(0.5f-MEGA_D) );
267
              break;
268
      case 1: if( mVertices[ 9]==null ) mVertices[ 9] = retEdgeMegaminx(5,variant);
269
              break;
270
      case 2: if( mVertices[10]==null ) mVertices[10] = retEdgeMegaminx(5,variant);
271
              break;
272
      case 3: if( mVertices[11]==null ) mVertices[11] = retCenterMegaminx(5);
273
              break;
274
      }
275

    
276
    return mVertices[variant+1+3+4];
277
    }
278

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

    
281
  public float[][] getVertices(int[] numLayers, int variant)
282
    {
283
    if( mVertices==null ) mVertices = new float[1+3+4+4][][];
284

    
285
    switch( numLayers[0] )
286
      {
287
      case 2: return verticesKilominx();
288
      case 3: return verticesMegaminx(variant);
289
      case 4: return verticesMasterKilominx(variant);
290
      case 5: return verticesGigaminx(variant);
291
      }
292

    
293
    return null;
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  private int[][] cornerIndices()
299
    {
300
    return new int[][]
301
      {
302
        {4,5,1,0},
303
        {7,4,0,3},
304
        {0,1,2,3},
305
        {7,6,5,4},
306
        {2,1,5,6},
307
        {3,2,6,7}
308
      };
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  private int[][] centerIndices()
314
    {
315
    return new int[][]
316
      {
317
        {0,1,2,3,4},
318
        {5,1,0},
319
        {5,2,1},
320
        {5,3,2},
321
        {5,4,3},
322
        {5,0,4}
323
      };
324
    }
325

    
326
///////////////////////////////////////////////////////////////////////////////////////////////////
327

    
328
  private int[][] indicesKilominx()
329
    {
330
    if( mIndices[0]==null ) mIndices[0] = cornerIndices();
331
    return mIndices[0];
332
    }
333

    
334
///////////////////////////////////////////////////////////////////////////////////////////////////
335

    
336
  private int[][] indicesMegaminx(int variant)
337
    {
338
    switch( variant )
339
      {
340
      case 0: if( mIndices[1]==null ) mIndices[1] = cornerIndices(); break;
341
      case 1: if( mIndices[2]==null ) mIndices[2] = cornerIndices(); break;
342
      case 2: if( mIndices[3]==null ) mIndices[3] = centerIndices(); break;
343
      }
344

    
345
    return mIndices[variant+1];
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  private int[][] indicesMasterKilominx(int variant)
351
    {
352
    switch( variant )
353
      {
354
      case 0: if( mIndices[4]==null ) mIndices[4] = cornerIndices(); break;
355
      case 1: if( mIndices[5]==null ) mIndices[5] = cornerIndices(); break;
356
      case 2: if( mIndices[6]==null )
357
                {
358
                mIndices[6] = cornerIndices();
359

    
360
                int[][] indices = mIndices[6];
361
                int tmp, len = indices.length;
362

    
363
                for(int i=0; i<len; i++)
364
                  {
365
                  tmp = indices[i][0];
366
                  indices[i][0] = indices[i][3];
367
                  indices[i][3] = tmp;
368
                  tmp = indices[i][1];
369
                  indices[i][1] = indices[i][2];
370
                  indices[i][2] = tmp;
371
                  }
372
                }
373
              break;
374
      case 3: if( mIndices[7]==null ) mIndices[7] = cornerIndices(); break;
375
      }
376

    
377
    return mIndices[variant+1+3];
378
    }
379

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

    
382
  private int[][] indicesGigaminx(int variant)
383
    {
384
    switch( variant )
385
      {
386
      case 0: if( mIndices[ 8]==null ) mIndices[ 8] = cornerIndices(); break;
387
      case 1: if( mIndices[ 9]==null ) mIndices[ 9] = cornerIndices(); break;
388
      case 2: if( mIndices[10]==null ) mIndices[10] = cornerIndices(); break;
389
      case 3: if( mIndices[11]==null ) mIndices[11] = centerIndices(); break;
390
      }
391

    
392
    return mIndices[variant+1+3+4];
393
    }
394

    
395
///////////////////////////////////////////////////////////////////////////////////////////////////
396

    
397
  public int[][] getIndices(int[] numLayers, int variant)
398
    {
399
    if( mIndices==null ) mIndices = new int[1+3+4+4][][];
400

    
401
    switch( numLayers[0] )
402
      {
403
      case 2: return indicesKilominx();
404
      case 3: return indicesMegaminx(variant);
405
      case 4: return indicesMasterKilominx(variant);
406
      case 5: return indicesGigaminx(variant);
407
      }
408

    
409
    return null;
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413
// return:
414
// 0: (x,y,z) does not belong to edge corner0->corner1
415
// 1: it belongs and is closer to corner1
416
// 2: it belongs and is closer to corner0
417

    
418
  private int belongsToEdge(float[] corner0, float[] corner1, float x, float y, float z)
419
    {
420
    float MAXERR = 0.01f;
421

    
422
    float v0x = corner0[0] - x;
423
    float v0y = corner0[1] - y;
424
    float v0z = corner0[2] - z;
425
    float v1x = corner1[0] - x;
426
    float v1y = corner1[1] - y;
427
    float v1z = corner1[2] - z;
428

    
429
    float len0 = v0x*v0x + v0y*v0y + v0z*v0z;
430
    float len1 = v1x*v1x + v1y*v1y + v1z*v1z;
431

    
432
    if( v0x > MAXERR || v0x < -MAXERR )
433
      {
434
      float A = v1x/v0x;
435
      float errY = v1y - A*v0y;
436
      float errZ = v1z - A*v0z;
437
      if( errY>-MAXERR && errY<MAXERR && errZ>-MAXERR && errZ<MAXERR ) return len0>len1 ? 1:2;
438
      else return 0;
439
      }
440
    else if( v0y > MAXERR || v0y < -MAXERR )
441
      {
442
      float A = v1y/v0y;
443
      float errX = v1x - A*v0x;
444
      float errZ = v1z - A*v0z;
445
      if( errX>-MAXERR && errX<MAXERR && errZ>-MAXERR && errZ<MAXERR ) return len0>len1 ? 1:2;
446
      else return 0;
447
      }
448
    else if( v0z > MAXERR || v0z < -MAXERR )
449
      {
450
      float A = v1z/v0z;
451
      float errX = v1x - A*v0x;
452
      float errY = v1y - A*v0y;
453
      if( errX>-MAXERR && errX<MAXERR && errY>-MAXERR && errY<MAXERR ) return len0>len1 ? 1:2;
454
      else return 0;
455
      }
456

    
457
    return 0;
458
    }
459

    
460
///////////////////////////////////////////////////////////////////////////////////////////////////
461

    
462
  public int getNumVariants(int[] numLayers)
463
    {
464
    switch( numLayers[0] )
465
      {
466
      case 2: return 1;
467
      case 3: return 3;
468
      case 4:
469
      case 5: return 4;
470
      }
471

    
472
    return 0;
473
    }
474

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

    
477
  public int getElementVariant(int[] numLayers, float x, float y, float z)
478
    {
479
    int size = numLayers[0];
480
    float d = x*x + y*y + z*z;
481
    float MAXERR = 0.01f;
482

    
483
    switch(size)
484
      {
485
      case 2: return 0;
486
      case 3: float d3c = d/9 - CORN_DIST_SQ;
487
              float d3e = d/9 - EDGE_DIST_SQ;
488
              if( d3c<MAXERR && d3c>-MAXERR ) return 0;
489
              if( d3e<MAXERR && d3e>-MAXERR ) return 1;
490
              return 2;
491
      case 4: if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
492
              if( mEdgeMap==null ) mEdgeMap = TwistyDodecahedron.initializeEdgeMap();
493

    
494
              float d4c = d/16 - CORN_DIST_SQ;
495
              float d4h = d/16 - EDHA_DIST_SQ;
496
              if( d4c<MAXERR && d4c>-MAXERR ) return 0;
497
              if( d4h<MAXERR && d4h>-MAXERR )
498
                {
499
                float xCorr = 3*x/4;  // mCorners has the coords assuming edge length is 3
500
                float yCorr = 3*y/4;  // here we have edge length = 4 - so correct for that
501
                float zCorr = 3*z/4;
502

    
503
                for(int[] edge : mEdgeMap)
504
                  {
505
                  float[] c0 = mCorners[edge[0]];
506
                  float[] c1 = mCorners[edge[1]];
507

    
508
                  int loc = belongsToEdge(c0, c1, xCorr, yCorr, zCorr);
509
                  if( loc!=0 ) return loc;
510
                  }
511
                return 1;
512
                }
513
              return 3;
514
      case 5: float dist = d/25;
515
              float A = 1 - (1-SIN18)*(1-MEGA_D)/2;
516
              float D2D_prim = DIST2D*A;
517
              float EDGE2_DIST_SQ = DIST3D*DIST3D + D2D_prim*D2D_prim; // distance from the center to the position of the 'part1-2' edges
518

    
519
              if( dist< CENT_DIST_SQ + MAXERR ) return 3;
520
              if( dist> EDGE2_DIST_SQ - MAXERR && dist< EDGE2_DIST_SQ + MAXERR ) return 2;
521
              if( dist> EDGE_DIST_SQ - MAXERR && dist< EDGE_DIST_SQ + MAXERR ) return 1;
522
              return 0;
523
      }
524

    
525
    return 0;
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529

    
530
  private void createQuats()
531
    {
532
    final Static3D[] axis = new Static3D[]
533
      {
534
       new Static3D(    C2/LEN, SIN54/LEN,    0      ),
535
       new Static3D(   -C2/LEN, SIN54/LEN,    0      ),
536
       new Static3D( 0        ,    C2/LEN, SIN54/LEN ),
537
       new Static3D( 0        ,   -C2/LEN, SIN54/LEN ),
538
       new Static3D( SIN54/LEN,    0     ,    C2/LEN ),
539
       new Static3D( SIN54/LEN,    0     ,   -C2/LEN )
540
      };
541

    
542
    int[] tmp = new int[] {5,5,5};
543
    int[][] basicAngles = new int[][] { tmp,tmp,tmp,tmp,tmp,tmp };
544

    
545
    mObjectQuats = QuatGroupGenerator.computeGroup(axis,basicAngles);
546
    }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
  private void initializeQuatIndices()
551
    {
552
    mQuatEdgeIndices = new int[]
553
      {
554
       0, 17, 18, 19, 20, 56, 25,  5, 24, 16,
555
       9, 44,  1, 34, 35, 27, 41, 50, 26, 54,
556
      15, 49, 39, 28, 10,  2, 48,  6, 46,  3
557
      };
558
    mQuatCornerIndices = new int[]
559
      {
560
       0, 29, 59, 48, 18, 53, 22, 49, 11, 54,
561
      10, 52, 17, 27, 19, 26,  9, 28, 23, 45
562
      };
563
    mQuatCenterIndices = new int[]
564
      {
565
       0, 35, 55, 38, 48, 41, 42, 58, 57, 46, 29, 59
566
      };
567
    }
568

    
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570

    
571
  private int getQuatMega(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
572
    {
573
    if( mQuatCornerIndices==null || mQuatEdgeIndices==null || mQuatCenterIndices==null)
574
      initializeQuatIndices();
575

    
576
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
577
      {
578
      int corner = cubit/numCubitsPerCorner;
579
      return mQuatCornerIndices[corner];
580
      }
581

    
582
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
583
      {
584
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner);
585
      return mQuatEdgeIndices[edge<NUM_EDGES ? edge : (edge-NUM_EDGES)/2];
586
      }
587

    
588
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
589
    return mQuatCenterIndices[center];
590
    }
591

    
592
///////////////////////////////////////////////////////////////////////////////////////////////////
593

    
594
  private int getQuatKilo(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
595
    {
596
    if( mQuatCornerIndices==null || mQuatEdgeIndices==null ) initializeQuatIndices();
597
    if( mCenterMap==null ) mCenterMap = TwistyDodecahedron.initializeCenterMap();
598

    
599
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
600
      {
601
      int corner = cubit/numCubitsPerCorner;
602
      return mQuatCornerIndices[corner];
603
      }
604

    
605
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
606
      {
607
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)%NUM_EDGES;
608
      return mQuatEdgeIndices[edge];
609
      }
610

    
611
    if( numCubitsPerCorner==0 )
612
      {
613
      return mQuatCornerIndices[cubit];
614
      }
615
    else
616
      {
617
      cubit -= (NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge);
618
      int numCubitsPerCenter = 5;
619
      int face = cubit/numCubitsPerCenter;
620
      int index= cubit%numCubitsPerCenter;
621
      int center=mCenterMap[face][index];
622
      return mQuatCornerIndices[center];
623
      }
624
    }
625

    
626
///////////////////////////////////////////////////////////////////////////////////////////////////
627

    
628
  private void initializeCornerV()
629
    {
630
    mBasicCornerV = new Static4D[3];
631
    mCurrCornerV  = new Static4D[3];
632

    
633
    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
634
    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.375f, (SQ5-1)*0.375f, -0.750f, 0.0f );
635
    mBasicCornerV[2] = new Static4D(              0,        -1.500f,    0.0f, 0.0f );
636
    }
637

    
638
///////////////////////////////////////////////////////////////////////////////////////////////////
639

    
640
  private void initializeObjectQuats()
641
    {
642
    int[] tmp = new int[MAX_SUPPORTED_SIZE];
643
    for(int i=0; i<MAX_SUPPORTED_SIZE; i++) tmp[i] = 5;
644
    int[][] basicAngles = new int[][] { tmp,tmp,tmp,tmp,tmp,tmp };
645

    
646
    mObjectQuats = QuatGroupGenerator.computeGroup(ROT_AXIS,basicAngles);
647
    }
648

    
649
///////////////////////////////////////////////////////////////////////////////////////////////////
650
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
651
// Appropriate one: QUATS[QUAT_INDICES[corner]].
652

    
653
  private void computeBasicCornerVectors(int corner)
654
    {
655
    if( mQuatCornerIndices==null ) initializeQuatIndices();
656
    if( mCurrCornerV==null || mBasicCornerV==null ) initializeCornerV();
657
    if( mObjectQuats==null ) initializeObjectQuats();
658

    
659
    Static4D quat = mObjectQuats[mQuatCornerIndices[corner]];
660

    
661
    mCurrCornerV[0] = QuatHelper.rotateVectorByQuat(mBasicCornerV[0],quat);
662
    mCurrCornerV[1] = QuatHelper.rotateVectorByQuat(mBasicCornerV[1],quat);
663
    mCurrCornerV[2] = QuatHelper.rotateVectorByQuat(mBasicCornerV[2],quat);
664
    }
665

    
666
///////////////////////////////////////////////////////////////////////////////////////////////////
667

    
668
  private void initializeCenterCoords()
669
    {
670
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
671
    if( mCenterMap==null ) mCenterMap = TwistyDodecahedron.initializeCenterMap();
672

    
673
    mCenterCoords = new float[NUM_CENTERS][3];
674

    
675
    for(int center=0; center<NUM_CENTERS; center++)
676
      {
677
      int[] map = mCenterMap[center];
678

    
679
      float x = mCorners[map[0]][0] +
680
                mCorners[map[1]][0] +
681
                mCorners[map[2]][0] +
682
                mCorners[map[3]][0] +
683
                mCorners[map[4]][0] ;
684

    
685
      float y = mCorners[map[0]][1] +
686
                mCorners[map[1]][1] +
687
                mCorners[map[2]][1] +
688
                mCorners[map[3]][1] +
689
                mCorners[map[4]][1] ;
690

    
691
      float z = mCorners[map[0]][2] +
692
                mCorners[map[1]][2] +
693
                mCorners[map[2]][2] +
694
                mCorners[map[3]][2] +
695
                mCorners[map[4]][2] ;
696

    
697
      mCenterCoords[center][0] = x/5;
698
      mCenterCoords[center][1] = y/5;
699
      mCenterCoords[center][2] = z/5;
700
      }
701
    }
702

    
703
///////////////////////////////////////////////////////////////////////////////////////////////////
704

    
705
  private float[] computeCenterMega(int center, int numLayers)
706
    {
707
    if( mCenterCoords==null ) initializeCenterCoords();
708
    float[] coords = mCenterCoords[center];
709
    float A = (float)numLayers/3;
710

    
711
    return new float[] { A*coords[0], A*coords[1], A*coords[2] };
712
    }
713

    
714
///////////////////////////////////////////////////////////////////////////////////////////////////
715

    
716
  private float[] computeCenterKilo(int numLayers, int center, int part)
717
    {
718
    if( mCenterCoords==null ) initializeCenterCoords();
719
    if( mCorners     ==null ) mCorners = TwistyDodecahedron.initializeCorners();
720
    if( mCenterMap   ==null ) mCenterMap = TwistyDodecahedron.initializeCenterMap();
721

    
722
    int corner = mCenterMap[center][part];
723
    float[] cent = mCenterCoords[center];
724
    float[] corn = mCorners[corner];
725
    float D = numLayers==3 ? 1.0f : 4.0f/3;
726
    float F = 1.0f - (2.0f*numLayers-6.0f)/(numLayers-1)*COS54*COS54;
727

    
728
    return new float[]
729
      {
730
      D * ( cent[0] + (corn[0]-cent[0])*F),
731
      D * ( cent[1] + (corn[1]-cent[1])*F),
732
      D * ( cent[2] + (corn[2]-cent[2])*F)
733
      };
734
    }
735

    
736
///////////////////////////////////////////////////////////////////////////////////////////////////
737

    
738
  private float[] computeCornerMega(int numCubitsPerCorner, int numLayers, int corner, int part)
739
    {
740
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
741
    if( mCurrCornerV==null || mBasicCornerV==null ) initializeCornerV();
742

    
743
    float D = numLayers/3.0f;
744
    float[] corn = mCorners[corner];
745

    
746
    if( part==0 )
747
      {
748
      return new float[] { corn[0]*D, corn[1]*D, corn[2]*D };
749
      }
750
    else
751
      {
752
      float E = D*(1-2*MEGA_D)/(0.5f*(numLayers-1));
753
      int N = (numCubitsPerCorner-1)/3;
754
      int block = (part-1) % N;
755
      int index = (part-1) / N;
756
      Static4D pri = mCurrCornerV[index];
757
      Static4D sec = mCurrCornerV[(index+2)%3];
758

    
759
      int layers= (numLayers-3)/2;
760
      int multP = (block % layers) + 1;
761
      int multS = (block / layers);
762

    
763
      return new float[]
764
        {
765
        corn[0]*D + (pri.get0()*multP + sec.get0()*multS)*E,
766
        corn[1]*D + (pri.get1()*multP + sec.get1()*multS)*E,
767
        corn[2]*D + (pri.get2()*multP + sec.get2()*multS)*E
768
        };
769
      }
770
    }
771

    
772
///////////////////////////////////////////////////////////////////////////////////////////////////
773

    
774
  private float[] computeCornerKilo(int numCubitsPerCorner, int numLayers, int corner, int part)
775
    {
776
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
777
    if( mCurrCornerV==null || mBasicCornerV==null ) initializeCornerV();
778

    
779
    float D = numLayers==3 ? 1.0f : 4.0f/3;
780
    float[] corn = mCorners[corner];
781

    
782
    if( part==0 )
783
      {
784
      return new float[] { corn[0]*D, corn[1]*D, corn[2]*D };
785
      }
786
    else
787
      {
788
      float E = D/(0.5f*(numLayers-1));   // ?? maybe 0.5*
789
      int N = (numCubitsPerCorner-1)/3;
790
      int block = (part-1) % N;
791
      int index = (part-1) / N;
792
      Static4D pri = mCurrCornerV[index];
793
      Static4D sec = mCurrCornerV[(index+2)%3];
794

    
795
      int layers= (numLayers-5)/2;
796
      int multP = (block % layers) + 1;
797
      int multS = (block / layers);
798

    
799
      return new float[]
800
        {
801
        corn[0]*D + (pri.get0()*multP + sec.get0()*multS)*E,
802
        corn[1]*D + (pri.get1()*multP + sec.get1()*multS)*E,
803
        corn[2]*D + (pri.get2()*multP + sec.get2()*multS)*E
804
        };
805
      }
806
    }
807

    
808
///////////////////////////////////////////////////////////////////////////////////////////////////
809

    
810
  private float[] computeEdgeMega(int numLayers, int edge, int part)
811
    {
812
    if( mCenterCoords==null ) initializeCenterCoords();
813
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
814
    if( mEdgeMap==null ) mEdgeMap = TwistyDodecahedron.initializeEdgeMap();
815

    
816
    float D = numLayers/3.0f;
817
    float[] c1 = mCorners[ mEdgeMap[edge][0] ];
818
    float[] c2 = mCorners[ mEdgeMap[edge][1] ];
819
    float x = D * (c1[0]+c2[0]) / 2;
820
    float y = D * (c1[1]+c2[1]) / 2;
821
    float z = D * (c1[2]+c2[2]) / 2;
822

    
823
    if( part==0 )
824
      {
825
      return new float[] { x, y, z };
826
      }
827
    else
828
      {
829
      int mult = (part+1)/2;
830
      int dir  = (part+1)%2;
831
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
832

    
833
      float vX = D*center[0] - x;
834
      float vY = D*center[1] - y;
835
      float vZ = D*center[2] - z;
836

    
837
      float A = 3*mult*D*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
838
      A /= (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
839

    
840
      return new float[] { x+A*vX, y+A*vY, z+A*vZ };
841
      }
842
    }
843

    
844
///////////////////////////////////////////////////////////////////////////////////////////////////
845

    
846
  private float[] computeEdgeKilo(int numLayers, int edge, int part)
847
    {
848
    if( mCenterCoords==null ) initializeCenterCoords();
849
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
850
    if( mEdgeMap==null ) mEdgeMap = TwistyDodecahedron.initializeEdgeMap();
851

    
852
    float D = numLayers==3 ? 1.0f : 4.0f/3;
853
    float[] c1 = mCorners[ mEdgeMap[edge][0] ];
854
    float[] c2 = mCorners[ mEdgeMap[edge][1] ];
855

    
856
    int leftRight = 2*(part%2) -1;
857
    part /= 2;
858

    
859
    if( part==0 )
860
      {
861
      float T = 0.5f + leftRight/(numLayers-1.0f);
862
      float x = D * (T*c1[0]+(1.0f-T)*c2[0]);
863
      float y = D * (T*c1[1]+(1.0f-T)*c2[1]);
864
      float z = D * (T*c1[2]+(1.0f-T)*c2[2]);
865

    
866
      return new float[] { x, y, z };
867
      }
868
    else
869
      {
870
      int mult = (part+1)/2;
871
      int dir  = (part+1)%2;
872
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
873
      float x = 0.5f * D * (c1[0]+c2[0]);
874
      float y = 0.5f * D * (c1[1]+c2[1]);
875
      float z = 0.5f * D * (c1[2]+c2[2]);
876

    
877
      float vX = D*center[0] - x;
878
      float vY = D*center[1] - y;
879
      float vZ = D*center[2] - z;
880

    
881
      float T = 0.5f + leftRight*(mult*SIN18 + 1.0f)/(numLayers-1);
882

    
883
      x = D * (T*c1[0]+(1.0f-T)*c2[0]);
884
      y = D * (T*c1[1]+(1.0f-T)*c2[1]);
885
      z = D * (T*c1[2]+(1.0f-T)*c2[2]);
886

    
887
      float H = mult*D*COS18/(numLayers-1);
888
      H /= (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
889

    
890
      return new float[] { x + H*vX, y + H*vY, z + H*vZ };
891
      }
892
    }
893

    
894
///////////////////////////////////////////////////////////////////////////////////////////////////
895

    
896
  public float[][][] getPositions(int[] numLayers)
897
    {
898
    int size = numLayers[0];
899

    
900
    if( BandagedObjectMegaminx.isMegaminx(size) )
901
      {
902
      int numCubitsPerCorner = BandagedObjectMegaminx.numCubitsPerCornerMega(size);
903
      int numVariants = size==3 ? 3:4;
904
      final float[][][] positions = new float[numVariants][][];
905

    
906
      positions[0] = new float[NUM_CORNERS*numCubitsPerCorner][];
907
      positions[1] = new float[NUM_EDGES][];
908

    
909
      if( size==3 )
910
        {
911
        positions[2] = new float[NUM_CENTERS][];
912
        }
913
      else
914
        {
915
        positions[2] = new float[2*NUM_EDGES][];
916
        positions[3] = new float[NUM_CENTERS][];
917
        }
918

    
919
      for(int index=0,corner=0; corner<NUM_CORNERS; corner++)
920
        {
921
        computeBasicCornerVectors(corner);
922

    
923
        for(int part=0; part<numCubitsPerCorner; part++)
924
          {
925
          positions[0][index++] = computeCornerMega(numCubitsPerCorner,size,corner,part);
926
          }
927
        }
928

    
929
      if( size==3 )
930
        for(int edge=0; edge<NUM_EDGES; edge++)
931
          {
932
          positions[1][edge] = computeEdgeMega(size, edge, 0 );
933
          }
934
      else
935
        for(int edge = 0; edge<NUM_EDGES; edge++)
936
          {
937
          positions[1][  edge  ] = computeEdgeMega(size, edge, 0);
938
          positions[2][2*edge  ] = computeEdgeMega(size, edge, 1);
939
          positions[2][2*edge+1] = computeEdgeMega(size, edge, 2);
940
          }
941

    
942
      int centerIndex = size==3 ? 2:3;
943

    
944
      for(int center=0; center<NUM_CENTERS; center++)
945
        {
946
        positions[centerIndex][center] = computeCenterMega(center, size);
947
        }
948

    
949
      return positions;
950
      }
951
    else
952
      {
953
      size++;
954

    
955
      if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
956

    
957
      if( size==3 )
958
        {
959
        final float[][][] positions = new float[1][NUM_CORNERS][];
960

    
961
        for(int corner=0; corner<NUM_CORNERS; corner++)
962
          {
963
          float[] c = mCorners[corner];
964
          positions[0][corner] = new float[] { 2*c[0]/3, 2*c[1]/3, 2*c[2]/3 };
965
          }
966

    
967
        return positions;
968
        }
969

    
970
      int numCubitsPerCorner = BandagedObjectMegaminx.numCubitsPerCornerKilo(size);
971
      int numCubitsPerCenter = 5;
972

    
973
      final float[][][] positions = new float[4][][];
974
      positions[0] = new float[NUM_CORNERS][];
975
      positions[1] = new float[NUM_EDGES][];
976
      positions[2] = new float[NUM_EDGES][];
977
      positions[3] = new float[NUM_CENTERS*numCubitsPerCenter][];
978

    
979
      for(int index=0,corner=0; corner<NUM_CORNERS; corner++)
980
        {
981
        computeBasicCornerVectors(corner);
982

    
983
        for(int part=0; part<numCubitsPerCorner; part++)
984
          {
985
          positions[0][index++] = computeCornerKilo(numCubitsPerCorner,size,corner,part);
986
          }
987
        }
988

    
989
      for(int edge=0; edge<NUM_EDGES; edge++)
990
        {
991
        positions[1][edge] = computeEdgeKilo(size, edge, 0 );
992
        positions[2][edge] = computeEdgeKilo(size, edge, 1 );
993
        }
994

    
995
      for(int index=0,center=0; center<NUM_CENTERS; center++)
996
        for(int part=0; part<numCubitsPerCenter; part++)
997
          {
998
          positions[3][index++] = computeCenterKilo(size,center, part);
999
          }
1000

    
1001
      return positions;
1002
      }
1003
    }
1004

    
1005
///////////////////////////////////////////////////////////////////////////////////////////////////
1006

    
1007
  public Static4D getElementQuat(int[] numLayers, int cubitIndex)
1008
    {
1009
    if( mObjectQuats==null ) createQuats();
1010

    
1011
    switch( numLayers[0] )
1012
      {
1013
      case 2: return mObjectQuats[getQuatKilo(cubitIndex,0,0)];
1014
      case 3: return mObjectQuats[getQuatMega(cubitIndex,1,1)];
1015
      case 4: return mObjectQuats[getQuatKilo(cubitIndex,1,2)];
1016
      case 5: return mObjectQuats[getQuatMega(cubitIndex,7,3)];
1017
      }
1018

    
1019
    return QUAT;
1020
    }
1021

    
1022
///////////////////////////////////////////////////////////////////////////////////////////////////
1023

    
1024
  public Static3D[] getNormals()
1025
    {
1026
    return TouchControlDodecahedron.FACE_AXIS;
1027
    }
1028

    
1029
///////////////////////////////////////////////////////////////////////////////////////////////////
1030

    
1031
  public float[] getDist3D(int[] numLayers)
1032
    {
1033
    final float d = TouchControlDodecahedron.DIST3D*numLayers[0];
1034
    return new float[] {d,d,d,d,d,d,d,d,d,d,d,d};
1035
    }
1036

    
1037
///////////////////////////////////////////////////////////////////////////////////////////////////
1038
// all the 10 *distinct* edges of the dodecahedron
1039

    
1040
  public float[][] getDiameterAxis()
1041
    {
1042
    float A = (SQ5+1)/4;
1043
    float B = (SQ5-1)/4;
1044
    float C = 0.5f;
1045

    
1046
    return new float[][]
1047
            {
1048
              { A, B, C},
1049
              { A, B,-C},
1050
              { A,-B, C},
1051
              { A,-B,-C},
1052
              { B, C, A},
1053
              { B, C,-A},
1054
              { B,-C, A},
1055
              { B,-C,-A},
1056
              { C, A, B},
1057
              { C, A,-B},
1058
              { C,-A, B},
1059
              { C,-A,-B},
1060
            };
1061
    }
1062

    
1063
///////////////////////////////////////////////////////////////////////////////////////////////////
1064

    
1065
  public float sizeCorrection(int[] numLayers)
1066
    {
1067
    switch(numLayers[0])
1068
      {
1069
      case 2: return 2.0f/3;
1070
      case 3: return 3.0f/3;
1071
      case 4: return 4.0f/5;
1072
      case 5: return 5.0f/5;
1073
      }
1074

    
1075
    return 1.0f;
1076
    }
1077

    
1078
///////////////////////////////////////////////////////////////////////////////////////////////////
1079

    
1080
  public int diameterMap(float diameter)
1081
    {
1082
    if( diameter>=5.49f ) return 11;
1083
    if( diameter>1.1f && diameter<1.9f ) return 3;
1084
    return (int)(2*diameter+0.01f);
1085
    }
1086

    
1087
///////////////////////////////////////////////////////////////////////////////////////////////////
1088

    
1089
  public float[][] getBands(boolean iconMode, int[] numLayers)
1090
    {
1091
    float height= iconMode ? 0.001f : 0.05f;
1092
    int[] angle = {1,55,50,46,42,39,36,34,31,29,27};
1093
    float R     = 0.5f;
1094
    float S     = 0.5f;
1095
    int extraI  = 0;
1096
    int extraV  = 0;
1097
    int numVertA= numLayers[0]>=4 ? 4 : 5;
1098
    int numVertI= numLayers[0]>=4 ? 2 : 3;
1099

    
1100
    return new float[][] { {0.001f      ,angle[ 0],R,S,numVertI,extraV,extraI},
1101
                           {height      ,angle[ 1],R,S,numVertA,extraV,extraI},
1102
                           {height      ,angle[ 1],R,S,numVertA,extraV,extraI},
1103
                           {height/ 1.5f,angle[ 2],R,S,numVertA,extraV,extraI},
1104
                           {height/ 2.0f,angle[ 3],R,S,numVertA,extraV,extraI},
1105
                           {height/ 2.5f,angle[ 4],R,S,numVertA,extraV,extraI},
1106
                           {height/ 3.0f,angle[ 5],R,S,numVertA,extraV,extraI},
1107
                           {height/ 3.5f,angle[ 6],R,S,numVertA,extraV,extraI},
1108
                           {height/ 4.0f,angle[ 7],R,S,numVertA,extraV,extraI},
1109
                           {height/ 4.5f,angle[ 8],R,S,numVertA,extraV,extraI},
1110
                           {height/ 5.0f,angle[ 9],R,S,numVertA,extraV,extraI},
1111
                           {height/ 5.5f,angle[10],R,S,numVertA,extraV,extraI}
1112
                          };
1113
    }
1114
  }
(11-11/15)