Project

General

Profile

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

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

1 9659b849 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
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 2a495bdb leszek
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.COS18;
13 9659b849 leszek
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 2a495bdb leszek
import static org.distorted.objectlib.objects.TwistyDodecahedron.COS_HALFD;
17
import static org.distorted.objectlib.objects.TwistyDodecahedron.SIN_HALFD;
18 5c825988 leszek
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
19 2a495bdb leszek
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.COS54;
20 a662c27e leszek
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.DIST2D;
21
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.DIST3D;
22 5c825988 leszek
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
23 9659b849 leszek
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
24
25 5c825988 leszek
import org.distorted.library.helpers.QuatHelper;
26 9659b849 leszek
import org.distorted.library.type.Static3D;
27 6155e738 leszek
import org.distorted.library.type.Static4D;
28 5c825988 leszek
import org.distorted.objectlib.helpers.QuatGroupGenerator;
29 22e5106b leszek
import org.distorted.objectlib.objects.TwistyDodecahedron;
30 9659b849 leszek
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
31
32
///////////////////////////////////////////////////////////////////////////////////////////////////
33
34
public class FactoryBandagedMegaminx extends FactoryBandaged
35
  {
36 5c825988 leszek
  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 60cc43cc leszek
  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 9659b849 leszek
  private static FactoryBandagedMegaminx mThis;
48
49 5c825988 leszek
  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 22e5106b leszek
  private float[][] mCorners;
61 2a495bdb leszek
  private float[][][] mVertices;
62
  private int[][][] mIndices;
63 5c825988 leszek
  private Static4D[] mObjectQuats, mBasicCornerV, mCurrCornerV;
64
  private int[] mQuatEdgeIndices,mQuatCornerIndices,mQuatCenterIndices;
65
  private float[][] mCenterCoords;
66 22e5106b leszek
67 9659b849 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
68
69
  private FactoryBandagedMegaminx()
70
    {
71
72
    }
73
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75
76 2a495bdb leszek
  public static FactoryBandagedMegaminx getInstance()
77
    {
78
    if( mThis==null ) mThis = new FactoryBandagedMegaminx();
79
    return mThis;
80
    }
81
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
84 60cc43cc leszek
  private float[][] retCenterKilominx(float width)
85 2a495bdb leszek
    {
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 60cc43cc leszek
    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 2a495bdb leszek
95
    return new float[][]
96
      {
97 60cc43cc leszek
       {   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 2a495bdb leszek
      };
106
    }
107
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109
110 60cc43cc leszek
  private float[][] retEdgeKilominx(int variant)
111 9659b849 leszek
    {
112 2a495bdb leszek
    int type = variant-1;
113 a662c27e leszek
    float tmpVal= 1.0f;//numL/(numL-1.0f);
114 2a495bdb leszek
    float height= tmpVal*COS18;
115
    float width = tmpVal + (type/2)*tmpVal*SIN18;
116
    boolean left = (type%2)==0;
117 9659b849 leszek
118 2a495bdb leszek
    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 9659b849 leszek
      {
136 2a495bdb leszek
      int len = vertices.length;
137
      for(int i=0; i<len; i++) vertices[i][1] = -vertices[i][1];
138 9659b849 leszek
      }
139
140 2a495bdb leszek
    return vertices;
141 9659b849 leszek
    }
142
143 2a495bdb leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
144
145 a662c27e leszek
  private float[][] retCornerMegaminx(float width)
146 2a495bdb leszek
    {
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 60cc43cc leszek
  private float[][] verticesKilominx()
219 2a495bdb leszek
    {
220 60cc43cc leszek
    if( mVertices[0]==null ) mVertices[0] = retCenterKilominx(1.0f);
221 2a495bdb leszek
    return mVertices[0];
222
    }
223
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225
226
  private float[][] verticesMegaminx(int variant)
227
    {
228
    switch(variant)
229
      {
230 a662c27e leszek
      case 0: if( mVertices[1]==null ) mVertices[1] = retCornerMegaminx(3*(0.5f-MEGA_D));
231 2a495bdb leszek
              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 a662c27e leszek
      case 0: if( mVertices[4]==null ) mVertices[4] = retCornerMegaminx( 1.0f );
248 2a495bdb leszek
              break;
249 60cc43cc leszek
      case 1: if( mVertices[5]==null ) mVertices[5] = retEdgeKilominx(variant);
250 2a495bdb leszek
              break;
251 60cc43cc leszek
      case 2: if( mVertices[6]==null ) mVertices[6] = retEdgeKilominx(variant);
252 2a495bdb leszek
              break;
253 60cc43cc leszek
      case 3: if( mVertices[7]==null ) mVertices[7] = retCenterKilominx(1+SIN18);
254 2a495bdb leszek
              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 a662c27e leszek
      case 0: if( mVertices[ 8]==null ) mVertices[ 8] = retCornerMegaminx( 2.5f*(0.5f-MEGA_D) );
267 2a495bdb leszek
              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 9659b849 leszek
    }
278
279
///////////////////////////////////////////////////////////////////////////////////////////////////
280
281 6155e738 leszek
  public float[][] getVertices(int[] numLayers, int variant)
282 9659b849 leszek
    {
283 2a495bdb leszek
    if( mVertices==null ) mVertices = new float[1+3+4+4][][];
284
285 6155e738 leszek
    switch( numLayers[0] )
286 2a495bdb leszek
      {
287 60cc43cc leszek
      case 2: return verticesKilominx();
288 5c825988 leszek
      case 3: return verticesMegaminx(variant);
289
      case 4: return verticesMasterKilominx(variant);
290
      case 5: return verticesGigaminx(variant);
291 2a495bdb leszek
      }
292
293 9659b849 leszek
    return null;
294
    }
295
296 2a495bdb leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
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 60cc43cc leszek
  private int[][] indicesKilominx()
329 2a495bdb leszek
    {
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 a662c27e leszek
      case 1: if( mIndices[5]==null ) mIndices[5] = cornerIndices(); break;
356
      case 2: if( mIndices[6]==null )
357 2a495bdb leszek
                {
358 a662c27e leszek
                mIndices[6] = cornerIndices();
359 2a495bdb leszek
360 a662c27e leszek
                int[][] indices = mIndices[6];
361 2a495bdb leszek
                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 9659b849 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
396
397 6155e738 leszek
  public int[][] getIndices(int[] numLayers, int variant)
398 9659b849 leszek
    {
399 2a495bdb leszek
    if( mIndices==null ) mIndices = new int[1+3+4+4][][];
400
401 6155e738 leszek
    switch( numLayers[0] )
402 2a495bdb leszek
      {
403 60cc43cc leszek
      case 2: return indicesKilominx();
404 5c825988 leszek
      case 3: return indicesMegaminx(variant);
405
      case 4: return indicesMasterKilominx(variant);
406
      case 5: return indicesGigaminx(variant);
407 2a495bdb leszek
      }
408
409 45aedaa7 leszek
    return null;
410 9659b849 leszek
    }
411
412 22e5106b leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
413
// return:
414
// 0: (x,y,z) does not belong to edge corner0->corner1
415 a662c27e leszek
// 1: it belongs and is closer to corner1
416
// 2: it belongs and is closer to corner0
417 22e5106b leszek
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 60cc43cc leszek
    if( v0x > MAXERR || v0x < -MAXERR )
433 22e5106b leszek
      {
434
      float A = v1x/v0x;
435
      float errY = v1y - A*v0y;
436
      float errZ = v1z - A*v0z;
437 a662c27e leszek
      if( errY>-MAXERR && errY<MAXERR && errZ>-MAXERR && errZ<MAXERR ) return len0>len1 ? 1:2;
438 22e5106b leszek
      else return 0;
439
      }
440 60cc43cc leszek
    else if( v0y > MAXERR || v0y < -MAXERR )
441 22e5106b leszek
      {
442
      float A = v1y/v0y;
443
      float errX = v1x - A*v0x;
444
      float errZ = v1z - A*v0z;
445 a662c27e leszek
      if( errX>-MAXERR && errX<MAXERR && errZ>-MAXERR && errZ<MAXERR ) return len0>len1 ? 1:2;
446 22e5106b leszek
      else return 0;
447
      }
448 60cc43cc leszek
    else if( v0z > MAXERR || v0z < -MAXERR )
449 22e5106b leszek
      {
450
      float A = v1z/v0z;
451
      float errX = v1x - A*v0x;
452
      float errY = v1y - A*v0y;
453 a662c27e leszek
      if( errX>-MAXERR && errX<MAXERR && errY>-MAXERR && errY<MAXERR ) return len0>len1 ? 1:2;
454 22e5106b leszek
      else return 0;
455
      }
456
457
    return 0;
458
    }
459
460 a662c27e leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
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 9659b849 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
476
477 6155e738 leszek
  public int getElementVariant(int[] numLayers, float x, float y, float z)
478 9659b849 leszek
    {
479 6155e738 leszek
    int size = numLayers[0];
480 22e5106b leszek
    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 a662c27e leszek
              float d4c = d/16 - CORN_DIST_SQ;
495
              float d4h = d/16 - EDHA_DIST_SQ;
496 22e5106b leszek
              if( d4c<MAXERR && d4c>-MAXERR ) return 0;
497
              if( d4h<MAXERR && d4h>-MAXERR )
498
                {
499 a662c27e leszek
                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 22e5106b leszek
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 a662c27e leszek
              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 22e5106b leszek
519
              if( dist< CENT_DIST_SQ + MAXERR ) return 3;
520 a662c27e leszek
              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 22e5106b leszek
              return 0;
523
      }
524
525 9659b849 leszek
    return 0;
526
    }
527
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529
530 5c825988 leszek
  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 c85a4378 leszek
    mQuatCenterIndices = new int[]
564
      {
565
       0, 35, 55, 38, 48, 41, 42, 58, 57, 46, 29, 59
566
      };
567 5c825988 leszek
    }
568
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570
571 a662c27e leszek
  private int getQuatMega(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
572 5c825988 leszek
    {
573 c85a4378 leszek
    if( mQuatCornerIndices==null || mQuatEdgeIndices==null || mQuatCenterIndices==null)
574
      initializeQuatIndices();
575 5c825988 leszek
576 a662c27e leszek
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
577 5c825988 leszek
      {
578 a662c27e leszek
      int corner = cubit/numCubitsPerCorner;
579 5c825988 leszek
      return mQuatCornerIndices[corner];
580
      }
581
582 a662c27e leszek
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
583 5c825988 leszek
      {
584 a662c27e leszek
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner);
585
      return mQuatEdgeIndices[edge<NUM_EDGES ? edge : (edge-NUM_EDGES)/2];
586 5c825988 leszek
      }
587
588 a662c27e leszek
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
589 5c825988 leszek
    return mQuatCenterIndices[center];
590
    }
591
592
///////////////////////////////////////////////////////////////////////////////////////////////////
593
594 a662c27e leszek
  private int getQuatKilo(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
595 5c825988 leszek
    {
596
    if( mQuatCornerIndices==null || mQuatEdgeIndices==null ) initializeQuatIndices();
597 a662c27e leszek
    if( mCenterMap==null ) mCenterMap = TwistyDodecahedron.initializeCenterMap();
598 5c825988 leszek
599 a662c27e leszek
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
600 5c825988 leszek
      {
601 a662c27e leszek
      int corner = cubit/numCubitsPerCorner;
602 5c825988 leszek
      return mQuatCornerIndices[corner];
603
      }
604
605 a662c27e leszek
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
606 5c825988 leszek
      {
607 a662c27e leszek
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)%NUM_EDGES;
608 5c825988 leszek
      return mQuatEdgeIndices[edge];
609
      }
610
611
    if( numCubitsPerCorner==0 )
612
      {
613 a662c27e leszek
      return mQuatCornerIndices[cubit];
614 5c825988 leszek
      }
615
    else
616
      {
617 a662c27e leszek
      cubit -= (NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge);
618 5c825988 leszek
      int numCubitsPerCenter = 5;
619 a662c27e leszek
      int face = cubit/numCubitsPerCenter;
620
      int index= cubit%numCubitsPerCenter;
621 5c825988 leszek
      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 a662c27e leszek
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
671
    if( mCenterMap==null ) mCenterMap = TwistyDodecahedron.initializeCenterMap();
672 5c825988 leszek
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 a662c27e leszek
                mCorners[map[1]][0] +
681
                mCorners[map[2]][0] +
682
                mCorners[map[3]][0] +
683
                mCorners[map[4]][0] ;
684 5c825988 leszek
685
      float y = mCorners[map[0]][1] +
686 a662c27e leszek
                mCorners[map[1]][1] +
687
                mCorners[map[2]][1] +
688
                mCorners[map[3]][1] +
689
                mCorners[map[4]][1] ;
690 5c825988 leszek
691
      float z = mCorners[map[0]][2] +
692 a662c27e leszek
                mCorners[map[1]][2] +
693
                mCorners[map[2]][2] +
694
                mCorners[map[3]][2] +
695
                mCorners[map[4]][2] ;
696 5c825988 leszek
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 9659b849 leszek
    {
718 5c825988 leszek
    if( mCenterCoords==null ) initializeCenterCoords();
719 a662c27e leszek
    if( mCorners     ==null ) mCorners = TwistyDodecahedron.initializeCorners();
720
    if( mCenterMap   ==null ) mCenterMap = TwistyDodecahedron.initializeCenterMap();
721 5c825988 leszek
722
    int corner = mCenterMap[center][part];
723
    float[] cent = mCenterCoords[center];
724
    float[] corn = mCorners[corner];
725 a662c27e leszek
    float D = numLayers==3 ? 1.0f : 4.0f/3;
726 5c825988 leszek
    float F = 1.0f - (2.0f*numLayers-6.0f)/(numLayers-1)*COS54*COS54;
727
728 c85a4378 leszek
    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 5c825988 leszek
    }
735
736
///////////////////////////////////////////////////////////////////////////////////////////////////
737
738
  private float[] computeCornerMega(int numCubitsPerCorner, int numLayers, int corner, int part)
739
    {
740 a662c27e leszek
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
741 5c825988 leszek
    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 a662c27e leszek
      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 5c825988 leszek
      }
770
    }
771
772
///////////////////////////////////////////////////////////////////////////////////////////////////
773
774
  private float[] computeCornerKilo(int numCubitsPerCorner, int numLayers, int corner, int part)
775
    {
776 a662c27e leszek
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
777 5c825988 leszek
    if( mCurrCornerV==null || mBasicCornerV==null ) initializeCornerV();
778
779 a662c27e leszek
    float D = numLayers==3 ? 1.0f : 4.0f/3;
780 5c825988 leszek
    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 c85a4378 leszek
      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 5c825988 leszek
      }
806
    }
807
808
///////////////////////////////////////////////////////////////////////////////////////////////////
809
810
  private float[] computeEdgeMega(int numLayers, int edge, int part)
811
    {
812
    if( mCenterCoords==null ) initializeCenterCoords();
813 a662c27e leszek
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
814
    if( mEdgeMap==null ) mEdgeMap = TwistyDodecahedron.initializeEdgeMap();
815 5c825988 leszek
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 a662c27e leszek
    if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
850
    if( mEdgeMap==null ) mEdgeMap = TwistyDodecahedron.initializeEdgeMap();
851 5c825988 leszek
852 a662c27e leszek
    float D = numLayers==3 ? 1.0f : 4.0f/3;
853 5c825988 leszek
    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 48986ca8 leszek
        for(int edge = 0; edge<NUM_EDGES; edge++)
936 5c825988 leszek
          {
937 48986ca8 leszek
          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 5c825988 leszek
          }
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 a662c27e leszek
      if( mCorners==null ) mCorners = TwistyDodecahedron.initializeCorners();
956 5c825988 leszek
957 c85a4378 leszek
      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 5c825988 leszek
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 6155e738 leszek
    return QUAT;
1020 9659b849 leszek
    }
1021
1022
///////////////////////////////////////////////////////////////////////////////////////////////////
1023
1024 6155e738 leszek
  public Static3D[] getNormals()
1025 9659b849 leszek
    {
1026 6155e738 leszek
    return TouchControlDodecahedron.FACE_AXIS;
1027 9659b849 leszek
    }
1028
1029
///////////////////////////////////////////////////////////////////////////////////////////////////
1030
1031 6155e738 leszek
  public float[] getDist3D(int[] numLayers)
1032 9659b849 leszek
    {
1033 6155e738 leszek
    final float d = TouchControlDodecahedron.DIST3D*numLayers[0];
1034
    return new float[] {d,d,d,d,d,d,d,d,d,d,d,d};
1035 9659b849 leszek
    }
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 c8f3a765 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
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 9659b849 leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
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 6155e738 leszek
  public float[][] getBands(boolean iconMode, int[] numLayers)
1090 9659b849 leszek
    {
1091 48986ca8 leszek
    float height= iconMode ? 0.001f : 0.05f;
1092 c8f3a765 leszek
    int[] angle = {1,55,50,46,42,39,36,34,31,29,27};
1093 48986ca8 leszek
    float R     = 0.5f;
1094 9659b849 leszek
    float S     = 0.5f;
1095
    int extraI  = 0;
1096
    int extraV  = 0;
1097 6155e738 leszek
    int numVertA= numLayers[0]>=4 ? 4 : 5;
1098
    int numVertI= numLayers[0]>=4 ? 2 : 3;
1099 9659b849 leszek
1100 c8f3a765 leszek
    return new float[][] { {0.001f      ,angle[ 0],R,S,numVertI,extraV,extraI},
1101 9659b849 leszek
                           {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
  }