Project

General

Profile

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

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

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.objects;
11

    
12
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_ICOSAHEDRON;
13
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_NOT_SPLIT;
14
import static org.distorted.objectlib.touchcontrol.TouchControlIcosahedron.*;
15

    
16
import org.distorted.library.type.Static3D;
17
import org.distorted.library.type.Static4D;
18
import org.distorted.objectlib.helpers.FactoryCubit;
19
import org.distorted.objectlib.helpers.ObjectFaceShape;
20
import org.distorted.objectlib.helpers.ObjectShape;
21
import org.distorted.objectlib.metadata.Metadata;
22
import org.distorted.objectlib.helpers.ObjectVertexEffects;
23
import org.distorted.objectlib.main.InitAssets;
24
import org.distorted.objectlib.metadata.ListObjects;
25
import org.distorted.objectlib.scrambling.ScrambleEdgeGenerator;
26
import org.distorted.objectlib.shape.ShapeIcosahedron;
27
import org.distorted.objectlib.touchcontrol.TouchControlIcosahedron;
28

    
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

    
31
public class TwistyIcosamate extends ShapeIcosahedron
32
{
33
  static final Static3D[] ROT_AXIS = new Static3D[]
34
         {
35
           new Static3D(                   0,                   1,                   0),
36
           new Static3D(                   0, VEC[1][1]/VEC[0][1], VEC[1][2]/VEC[0][1]),
37
           new Static3D( VEC[2][0]/VEC[0][1], VEC[1][1]/VEC[0][1], VEC[2][2]/VEC[0][1]),
38
           new Static3D( VEC[3][0]/VEC[0][1], VEC[1][1]/VEC[0][1], VEC[3][2]/VEC[0][1]),
39
           new Static3D(-VEC[3][0]/VEC[0][1], VEC[1][1]/VEC[0][1], VEC[3][2]/VEC[0][1]),
40
           new Static3D(-VEC[2][0]/VEC[0][1], VEC[1][1]/VEC[0][1], VEC[2][2]/VEC[0][1])
41
         };
42

    
43
  private int[][] mEdges;
44
  private int[][] mBasicAngle;
45
  private float[][] mCuts;
46
  private float[][] mPosition;
47
  private int[] mQuatIndex;
48

    
49
///////////////////////////////////////////////////////////////////////////////////////////////////
50

    
51
  public TwistyIcosamate(int iconMode, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
52
    {
53
    super(iconMode, meta.getNumLayers()[0], quat, move, scale, meta, asset);
54
    }
55

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57

    
58
  @Override
59
  public int getInternalColor()
60
    {
61
    return 0xff222222;
62
    }
63

    
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

    
66
  public int[][] getScrambleEdges()
67
    {
68
    if( mEdges==null )
69
      {
70
      int[][] basicAngle = getBasicAngles();
71
      mEdges = ScrambleEdgeGenerator.getScrambleEdgesSingle(basicAngle);
72
      }
73

    
74
    return mEdges;
75
    }
76

    
77
///////////////////////////////////////////////////////////////////////////////////////////////////
78

    
79
  public float[][] getCuts(int[] numLayers)
80
    {
81
    if( mCuts==null )
82
      {
83
      int nL = numLayers[0];
84
      float[] cut = new float[nL-1];
85
      for(int i=0; i<nL-1; i++) cut[i] = VEC[1][1]*(2*i+2-nL);
86
      mCuts = new float[][] { cut,cut,cut,cut,cut,cut };
87
      }
88

    
89
    return mCuts;
90
    }
91

    
92
///////////////////////////////////////////////////////////////////////////////////////////////////
93

    
94
  public boolean[][] getLayerRotatable(int[] numLayers)
95
    {
96
    int nL = numLayers[0];
97
    boolean[] tmp = new boolean[nL];
98
    for(int i=0; i<nL; i++) tmp[i] = true;
99
    return new boolean[][] { tmp,tmp,tmp,tmp,tmp,tmp };
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  public int getTouchControlType()
105
    {
106
    return TC_ICOSAHEDRON;
107
    }
108

    
109
///////////////////////////////////////////////////////////////////////////////////////////////////
110

    
111
  public int getTouchControlSplit()
112
    {
113
    return TYPE_NOT_SPLIT;
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  public int[][][] getEnabled()
119
    {
120
    return new int[][][]
121
      {
122
          {{3,4,5}}, {{1,4,5}}, {{1,2,5}}, {{1,2,3}}, {{2,3,4}},
123
          {{0,2,5}}, {{0,1,3}}, {{0,2,4}}, {{0,3,5}}, {{0,1,4}},
124
          {{0,2,5}}, {{0,1,3}}, {{0,2,4}}, {{0,3,5}}, {{0,1,4}},
125
          {{3,4,5}}, {{1,4,5}}, {{1,2,5}}, {{1,2,3}}, {{2,3,4}},
126
      };
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  public float[] getDist3D(int[] numLayers)
132
    {
133
    return TouchControlIcosahedron.D3D;
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  public Static3D[] getFaceAxis()
139
    {
140
    return TouchControlIcosahedron.FACE_AXIS;
141
    }
142

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

    
145
  private float[] computeOff(int index, int N)
146
    {
147
    if( N==2 )
148
      {
149
      return new float[] {0,0,0};
150
      }
151
    else
152
      {
153
      switch(index)
154
        {
155
        case 0 : return new float[] {0,SQ3/9,0};
156
        case 1 : return new float[] {-1.0f/6,-SQ3/18,0};
157
        default: return new float[] { 1.0f/6,-SQ3/18,0};
158
        }
159
      }
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163
// Rodrigues
164

    
165
  private void rotateVect(float vx, float vy, float vz, float sin, float cos, float[] vec)
166
    {
167
    float cx = vy*vec[2] - vz*vec[1];
168
    float cy = vz*vec[0] - vx*vec[2];
169
    float cz = vx*vec[1] - vy*vec[0];
170

    
171
    float scalar = vx*vec[0] + vy*vec[1] + vz*vec[2];
172

    
173
    vec[0] = vec[0]*cos + cx*sin + vx*scalar*(1-cos);
174
    vec[1] = vec[1]*cos + cy*sin + vy*scalar*(1-cos);
175
    vec[2] = vec[2]*cos + cz*sin + vz*scalar*(1-cos);
176
    }
177

    
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
  private void rotateFacePosition(float x, float y, float z, float[] off)
181
    {
182
    float cosB = (float)Math.sqrt(x*x+z*z);
183
    float sinB = y;
184
    float sinA = x/cosB;
185
    float cosA = z/cosB;
186

    
187
    float vec1X = 0;
188
    float vec1Y = 1;
189
    float vec1Z = 0;
190

    
191
    float vec2X = -z/cosB;
192
    float vec2Y = 0;
193
    float vec2Z = x/cosB;
194

    
195
    rotateVect(vec1X,vec1Y,vec1Z,sinA,cosA,off);
196
    rotateVect(vec2X,vec2Y,vec2Z,sinB,cosB,off);
197
    }
198

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  private float[] createFacePosition(float vx, float vy, float vz, float scale, boolean inverted, float[] off)
202
    {
203
    float[] tmp = new float[3];
204
    tmp[0] = off[0];
205
    tmp[1] = off[1];
206
    tmp[2] = off[2];
207

    
208
    rotateFacePosition(vx,vy,vz,tmp);
209

    
210
    if( inverted )
211
      {
212
      tmp[0] = -tmp[0];
213
      tmp[1] = -tmp[1];
214
      tmp[2] = -tmp[2];
215
      }
216

    
217
    float[] ret = new float[3];
218

    
219
    ret[0] = scale*(vx+tmp[0]);
220
    ret[1] = scale*(vy+tmp[1]);
221
    ret[2] = scale*(vz+tmp[2]);
222

    
223
    return ret;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private float[] createEdgePosition(int edge, int index, int N)
229
    {
230
    int[] edgeIndices = EDGE_INDICES[edge];
231
    int i0 = edgeIndices[0];
232
    int i1 = edgeIndices[1];
233

    
234
    float x = N*(VEC[i0][0]+VEC[i1][0])/2;
235
    float y = N*(VEC[i0][1]+VEC[i1][1])/2;
236
    float z = N*(VEC[i0][2]+VEC[i1][2])/2;
237

    
238
    return new float[] { x,y,z };
239
    }
240

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

    
243
  public float[][] getCubitPositions(int[] numLayers)
244
    {
245
    if( mPosition==null )
246
      {
247
      int N = numLayers[0];
248

    
249
      int numV = 12;
250
      int perF = N*(N-1)/2;
251
      int numF = 20*perF;
252
      int perE = N-2;
253
      int numE = 30*perE;
254

    
255
      mPosition = new float[numV+numF+numE][];
256

    
257
      for(int v=0; v<12; v++)
258
        mPosition[v] = new float[] { VEC[v][0]*N, VEC[v][1]*N, VEC[v][2]*N };
259

    
260
      float[][] off = new float[perF][];
261
      for(int i=0; i<perF; i++) off[i] = computeOff(i,N);
262

    
263
      for(int f=0; f<20; f++)
264
        {
265
        Static3D vect = TouchControlIcosahedron.FACE_AXIS[f];
266
        float x = vect.get0();
267
        float y = vect.get1();
268
        float z = vect.get2();
269
        boolean inverted = f>=10;
270

    
271
        for(int i=0; i<perF; i++)
272
          mPosition[12+f*perF+i] = createFacePosition(x,y,z,DIST3D*N,inverted,off[i]);
273
        }
274

    
275
      for(int e=0; e<30; e++)
276
        for(int i=0; i<perE; i++)
277
          mPosition[12+20*perF+e*perE+i] = createEdgePosition(e,i,N);
278
      }
279

    
280
    return mPosition;
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

    
285
  public Static4D getCubitQuats(int cubit, int[] numLayers)
286
    {
287
    if( mQuatIndex==null )
288
      {
289
      switch( numLayers[0] )
290
        {
291
        case 2: mQuatIndex = new int[]
292
                  {
293
                  0,12,5,9,13,8,14,18,7,6,10,55,
294

    
295
                  0,4,3,2,1,
296
                  6,11,32,14,26,
297
                  41,27,7,5,10,
298
                  35,18,45,33,15
299
                  };
300
                break;
301
        case 3: mQuatIndex = new int[]
302
                  {
303
                  0,12,5,9,13,8,14,18,7,6,10,55,
304

    
305
                  0,52,28,4,44,9,3,31,24,2,13,51,1,8,42,
306
                  21,30,6,16,11,49,54,32,39,48,14,23,37,43,26,
307
                  41,50,46,27,40,34,7,25,17,29,5,12,10,20,53,
308
                  56,38,35,58,22,18,57,47,45,55,36,33,59,19,15,
309

    
310
                  0,4,3,2,1,
311
                  5,20,31,13,8,
312
                  6,16,49,10,39,41,23,27,17,7,
313
                  14,22,30,11,19,
314
                  35,18,45,33,15
315
                  };
316
                break;
317
        }
318
      }
319

    
320
    return mObjectQuats[mQuatIndex[cubit]];
321
    }
322

    
323
///////////////////////////////////////////////////////////////////////////////////////////////////
324

    
325
  private float[][] getVertices(int variant)
326
    {
327
    float N = getNumLayers()[0];
328

    
329
    if( variant==0 )
330
      {
331
      float[] pos = mPosition[0];
332
      float[][] ret = new float[7][];
333
      for(int i=0; i<6; i++) ret[i] = new float[] { VEC[i][0]-pos[0], VEC[i][1]+(N-1)*VEC[0][1]-pos[1], VEC[i][2]-pos[2] };
334
      ret[6] = new float[] { -pos[0], -pos[1], -pos[2] };
335
      return ret;
336
      }
337
    else if( variant==1 )
338
      {
339
      float CX = mPosition[12][0];
340
      float CY = mPosition[12][1];
341
      float CZ = mPosition[12][2];
342

    
343
      float v1x = VEC[0][0]*(N-1)+VEC[2][0]; float v1y = VEC[0][1]*(N-1)+          VEC[2][1]; float v1z = VEC[0][2]*(N-1)+VEC[2][2];
344
      float v2x = VEC[2][0];                 float v2y = VEC[0][1]*(N-2)+VEC[1][1]+VEC[2][1]; float v2z = VEC[1][2]+VEC[2][2];
345
      float v3x = VEC[0][0]*(N-1)+VEC[1][0]; float v3y = VEC[0][1]*(N-1)+VEC[1][1]          ; float v3z = VEC[0][2]*(N-1)+VEC[1][2];
346

    
347
      return new float[][] { { v1x-CX, v1y-CY, v1z-CZ },
348
                             { v2x-CX, v2y-CY, v2z-CZ },
349
                             { v3x-CX, v3y-CY, v3z-CZ },
350
                             {    -CX,    -CY,    -CZ }
351
                           };
352
      }
353
    else
354
      {
355
      float[] pos = mPosition[72];
356

    
357
      float v1x = N*(VEC[0][0] + VEC[0][0] + VEC[1][0])/3; float v1y = N*(VEC[0][1] + VEC[0][1] + VEC[1][1])/3; float v1z = N*(VEC[0][2] + VEC[0][2] + VEC[1][2])/3;
358
      float v2x = N*(VEC[0][0] + VEC[1][0] + VEC[1][0])/3; float v2y = N*(VEC[0][1] + VEC[1][1] + VEC[1][1])/3; float v2z = N*(VEC[0][2] + VEC[1][2] + VEC[1][2])/3;
359
      float v3x = N*(VEC[0][0] + VEC[1][0] + VEC[2][0])/3; float v3y = N*(VEC[0][1] + VEC[1][1] + VEC[2][1])/3; float v3z = N*(VEC[0][2] + VEC[1][2] + VEC[2][2])/3;
360
      float v4x =-N*(VEC[0][0] + VEC[1][0] + VEC[2][0])/3; float v4y = N*(VEC[0][1] + VEC[1][1] + VEC[2][1])/3; float v4z = N*(VEC[0][2] + VEC[1][2] + VEC[2][2])/3;
361

    
362
      return new float[][] { { v1x-pos[0], v1y-pos[1], v1z-pos[2] },
363
                             { v2x-pos[0], v2y-pos[1], v2z-pos[2] },
364
                             { v3x-pos[0], v3y-pos[1], v3z-pos[2] },
365
                             { v4x-pos[0], v4y-pos[1], v4z-pos[2] },
366
                             {    -pos[0],    -pos[1],    -pos[2] }
367
                           };
368
      }
369
    }
370

    
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372

    
373
  public ObjectShape getObjectShape(int variant)
374
    {
375
    if( variant==0 )
376
      {
377
      int[][] indices =
378
          {
379
              {1,2,0},{2,3,0},{3,4,0},{4,5,0},{5,1,0}, {6,2,1},{6,3,2},{6,4,3},{6,5,4},{6,1,5}
380
          };
381

    
382
      return new ObjectShape(getVertices(variant), indices);
383
      }
384
    else if( variant==1 )
385
      {
386
      int[][] indices =
387
          {
388
              {0,2,1},{0,1,3},{2,0,3},{1,2,3}
389
          };
390

    
391
      return new ObjectShape(getVertices(variant), indices);
392
      }
393
    else
394
      {
395
      int[][] indices =
396
          {
397
              {0,1,2},{0,3,1},{4,2,1},{4,0,2},{4,3,0},{4,1,3}
398
          };
399

    
400
      return new ObjectShape(getVertices(variant), indices);
401
      }
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

    
406
  public ObjectFaceShape getObjectFaceShape(int variant)
407
    {
408
    float N = getNumLayers()[0];
409
    int angle = 25;
410
    float R = 0.7f;
411
    float S = 0.5f;
412

    
413
    if( variant==0 )
414
      {
415
      int N1 = N==2 ? 5:4;
416
      int N2 = N==2 ? 3:2;
417
      float h1 = isInIconMode() ? 0.001f : 0.04f;
418
      float h2 = 0.001f;
419
      float[][] bands = { {h1,angle,R,S,N1,0,0}, {h2,angle,R,S,N2,0,0} };
420
      int[] indices   = { 0,0,0,0,0, 1,1,1,1,1,1 };
421
      return new ObjectFaceShape(bands,indices,null);
422
      }
423
    else if( variant==1 )
424
      {
425
      int N1 = N==2 ? 5:4;
426
      int N2 = N==2 ? 3:2;
427
      float h1 = isInIconMode() ? 0.001f : 0.04f;
428
      float h2 = 0.001f;
429
      float[][] bands = { {h1,angle,R,S,N1,0,0}, {h2,angle,R,S,N2,0,0} };
430
      int[] indices   = { 0,1,1,1 };
431
      return new ObjectFaceShape(bands,indices,null);
432
      }
433
    else
434
      {
435
      int N1 = N==2 ? 5:4;
436
      int N2 = N==2 ? 3:2;
437
      float h1 = isInIconMode() ? 0.001f : 0.04f;
438
      float h2 = 0.001f;
439
      float[][] bands = { {h1,angle,R,S,N1,0,0}, {h2,angle,R,S,N2,0,0} };
440
      int[] indices   = { 0,0,1,1,1,1 };
441
      return new ObjectFaceShape(bands,indices,null);
442
      }
443
    }
444

    
445
///////////////////////////////////////////////////////////////////////////////////////////////////
446

    
447
  public ObjectVertexEffects getVertexEffects(int variant)
448
    {
449
    if( variant==0 )
450
      {
451
      float[] pos = mPosition[0];
452
      float[][] corners  = { {0.04f,0.12f},{0.04f,0.10f} };
453
      int[] cornerIndices= { 0,1,1,1,1,1,-1 };
454
      float[][] centers = { { -pos[0]/2, -pos[1]/2, -pos[2]/2} };
455
      int[] centerIndices= { 0,0,0,0,0,0,-1 };
456
      return FactoryCubit.generateVertexEffect(getVertices(variant),corners,cornerIndices,centers,centerIndices);
457
      }
458
    else if( variant==1 )
459
      {
460
      float[] pos = mPosition[12];
461
      float[][] corners = { {0.04f,0.15f} };
462
      int[] indices     = { 0,0,0,-1 };
463
      float[][] centers = { { -pos[0]/2, -pos[1]/2, -pos[2]/2} };
464
      return FactoryCubit.generateVertexEffect(getVertices(variant),corners,indices,centers,indices);
465
      }
466
    else
467
      {
468
      float[] pos = mPosition[72];
469
      float[][] corners = { {0.04f,0.15f} };
470
      int[] indices     = { 0,0,0,0,-1 };
471
      float[][] centers = { { -pos[0]/2, -pos[1]/2, -pos[2]/2} };
472
      return FactoryCubit.generateVertexEffect(getVertices(variant),corners,indices,centers,indices);
473
      }
474
    }
475

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

    
478
  public int getNumCubitVariants(int[] numLayers)
479
    {
480
    return getNumLayers()[0]==2 ? 2 : 3;
481
    }
482

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

    
485
  public int getCubitVariant(int cubit, int[] numLayers)
486
    {
487
    int N = getNumLayers()[0];
488
    return cubit<12 ? 0 : (cubit<10*N*(N-1)+12 ? 1 : 2);
489
    }
490

    
491
///////////////////////////////////////////////////////////////////////////////////////////////////
492

    
493
  public float getStickerRadius()
494
    {
495
    return 0.09f;
496
    }
497

    
498
///////////////////////////////////////////////////////////////////////////////////////////////////
499

    
500
  public float getStickerStroke()
501
    {
502
    return isInIconMode() ? 0.14f : 0.09f;
503
    }
504

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

    
507
  public float[][][] getStickerAngles()
508
    {
509
    return null;
510
    }
511

    
512
///////////////////////////////////////////////////////////////////////////////////////////////////
513
// PUBLIC API
514

    
515
  public Static3D[] getRotationAxis()
516
    {
517
    return ROT_AXIS;
518
    }
519

    
520
///////////////////////////////////////////////////////////////////////////////////////////////////
521

    
522
  public int[][] getBasicAngles()
523
    {
524
    if( mBasicAngle==null )
525
      {
526
      int num = getNumLayers()[0];
527
      int[] tmp = new int[num];
528
      for(int i=0; i<num; i++) tmp[i] = 5;
529
      mBasicAngle = new int[][] { tmp,tmp,tmp,tmp,tmp,tmp };
530
      }
531

    
532
    return mBasicAngle;
533
    }
534

    
535
///////////////////////////////////////////////////////////////////////////////////////////////////
536

    
537
  public String getShortName()
538
    {
539
    switch(getNumLayers()[0])
540
      {
541
      case 2: return ListObjects.ICOS_2.name();
542
      case 3: return ListObjects.ICOS_3.name();
543
      }
544

    
545
    return null;
546
    }
547

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

    
550
  public String[][] getTutorials()
551
    {
552
    int[] numLayers = getNumLayers();
553

    
554
    switch(numLayers[0])
555
      {
556
      case 2: return new String[][] {
557
                            {"gb","e7Es4Zx6Sl4","Icosamate introduction & algorithms","Superantoniovivaldi"},
558
                            {"gb","ZhkklbYfs98","Icosamate solve","Superantoniovivaldi"},
559
                            {"pl","eJTLTeoicWI","Icosamate TUTORIAL PL","MrUK"},
560
                            {"vn","RVjjxj9rPeg","BẠN PHẠM BẢO GIẢI ICOSAMATE","VĂN CÔNG TÙNG"},
561
                          };
562
      case 3: return new String[][] {
563
                            {"gb","77aBjBdfA2Q","Master Icosamate Algorithms","Superantoniovivaldi"},
564
                            {"gb","j6AIwlIofFU","Master Icosamate Tutorial","Superantoniovivaldi"},
565
                            {"gb","5Z1B5r6-CxM","Astrominx Tutorial","Jabberwock Technologies"},
566
                            {"pl","","Icosamate TUTORIAL PL","MrUK"},
567
                            {"vn","C4YO0B4rgTc","Tutorial N.237- Master Icosamate 1/3","Duy Thích Rubik"},
568
                            {"vn","90m_0AoyOHU","Tutorial N.237- Master Icosamate 2/3","Duy Thích Rubik"},
569
                            {"vn","LOd5qBwoP_k","Tutorial N.237- Master Icosamate 3/3","Duy Thích Rubik"},
570
                          };
571
      }
572

    
573
    return null;
574
    }
575
}
(24-24/59)