Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / objects / TwistyBandagedAbstract.java @ db758bd0

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objectlib.objects;
21

    
22
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_HEXAHEDRON;
23
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_NOT_SPLIT;
24

    
25
import java.io.InputStream;
26

    
27
import org.distorted.library.main.DistortedLibrary;
28
import org.distorted.library.type.Static3D;
29
import org.distorted.library.type.Static4D;
30

    
31
import org.distorted.objectlib.helpers.FactoryBandaged3x3Cubit;
32
import org.distorted.objectlib.helpers.ObjectFaceShape;
33
import org.distorted.objectlib.scrambling.ScrambleStateBandaged3x3;
34
import org.distorted.objectlib.touchcontrol.TouchControlHexahedron;
35
import org.distorted.objectlib.helpers.ObjectShape;
36
import org.distorted.objectlib.scrambling.ScrambleState;
37
import org.distorted.objectlib.main.ShapeHexahedron;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

    
41
abstract class TwistyBandagedAbstract extends ShapeHexahedron
42
{
43
  private static final int CUBIT_111 = 0;
44
  private static final int CUBIT_211 = 1;
45
  private static final int CUBIT_311 = 2;
46
  private static final int CUBIT_221 = 3;
47
  private static final int CUBIT_222 = 4;
48
  private static final int CUBIT_OTH = 5;
49

    
50
  // the three rotation axis of a 3x3 Cube. Must be normalized.
51
  static final Static3D[] ROT_AXIS = new Static3D[]
52
         {
53
           new Static3D(1,0,0),
54
           new Static3D(0,1,0),
55
           new Static3D(0,0,1)
56
         };
57

    
58
  private static final int[][] mDims = new int[][]
59
        {
60
         {1,1,1},  // has to be X>=Z>=Y so that all
61
         {2,1,1},  // the faces are horizontal
62
         {3,1,1},
63
         {2,1,2},
64
         {2,2,2},
65
        };
66

    
67
  private int[] mBasicAngle;
68
  private Static4D[] mInitQuats;
69
  private float[][] mCuts;
70
  private ScrambleState[] mStates;
71
  private int[] mCubitVariantMap;
72
  private int[] mTypeVariantMap;
73

    
74
  float[][] POSITIONS;
75

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

    
78
  TwistyBandagedAbstract(int[] numL, int meshState, int iconMode, Static4D quat, Static3D move, float scale, InputStream stream)
79
    {
80
    super(numL, meshState, iconMode, numL[0], quat, move, scale, stream);
81
    }
82

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84

    
85
  abstract float[][] getPositions();
86

    
87
///////////////////////////////////////////////////////////////////////////////////////////////////
88

    
89
  public ScrambleState[] getScrambleStates()
90
    {
91
    if( mStates==null && !isInIconMode() )
92
      {
93
      long signature = getSignature();
94
      mStates = ScrambleStateBandaged3x3.computeGraph(signature);
95
      }
96

    
97
    return mStates;
98
    }
99

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

    
102
  private int getType(float[] pos)
103
    {
104
    switch(pos.length)
105
      {
106
      case  3: return CUBIT_111;
107
      case  6: return CUBIT_211;
108
      case  9: boolean x1 = (pos[0]==pos[3] && pos[0]==pos[6]);
109
               boolean y1 = (pos[1]==pos[4] && pos[1]==pos[7]);
110
               boolean z1 = (pos[2]==pos[5] && pos[2]==pos[8]);
111
               return ( (x1&&y1) || (x1&&z1) || (y1&&z1) ) ? CUBIT_311 : CUBIT_OTH;
112
      case 12: float x = (pos[0]+pos[3]+pos[6]+pos[ 9])/4;
113
               float y = (pos[1]+pos[4]+pos[7]+pos[10])/4;
114
               float z = (pos[2]+pos[5]+pos[8]+pos[11])/4;
115
               float d1 = (pos[0]-x)*(pos[0]-x) + (pos[ 1]-y)*(pos[ 1]-y) + (pos[ 2]-z)*(pos[ 2]-z);
116
               float d2 = (pos[3]-x)*(pos[3]-x) + (pos[ 4]-y)*(pos[ 4]-y) + (pos[ 5]-z)*(pos[ 5]-z);
117
               float d3 = (pos[6]-x)*(pos[6]-x) + (pos[ 7]-y)*(pos[ 7]-y) + (pos[ 8]-z)*(pos[ 8]-z);
118
               float d4 = (pos[9]-x)*(pos[9]-x) + (pos[10]-y)*(pos[10]-y) + (pos[11]-z)*(pos[11]-z);
119
               return ( d1==0.5f && d2==0.5f && d3==0.5f && d4==0.5f ) ? CUBIT_221 : CUBIT_OTH;
120
      case 24: float x3 = pos[0];
121
               float y3 = pos[1];
122
               float z3 = pos[2];
123
               float x4=-10,y4=-10,z4=-10;
124
               int i;
125

    
126
               for(i=0; i<8; i++)
127
                 {
128
                 if( pos[3*i]!=x3 && pos[3*i+1]!=y3 && pos[3*i+2]!=z3 )
129
                   {
130
                   x4 = pos[3*i  ];
131
                   y4 = pos[3*i+1];
132
                   z4 = pos[3*i+2];
133
                   break;
134
                   }
135
                 }
136
               if( i==9 ) return CUBIT_OTH;
137

    
138
               float dX = x4-x3;
139
               float dY = y4-y3;
140
               float dZ = z4-z3;
141

    
142
               if( (dX==1.0f || dX==-1.0f) && (dY==1.0f || dY==-1.0f) && (dZ==1.0f || dZ==-1.0f) )
143
                 {
144
                 for(i=0; i<8; i++)
145
                   {
146
                   if( (pos[3*i  ]!=x3 && pos[3*i  ]!=x4) ||
147
                       (pos[3*i+1]!=y3 && pos[3*i+1]!=y4) ||
148
                       (pos[3*i+2]!=z3 && pos[3*i+2]!=z4)  ) return CUBIT_OTH;
149
                   }
150

    
151
                 return CUBIT_222;
152
                 }
153

    
154
      default: return CUBIT_OTH;
155
      }
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private int getQuatIndex(int cubit)
161
    {
162
    float[][] positions = getPositions();
163
    int len = positions.length;
164

    
165
    if( cubit>=0 && cubit<len )
166
      {
167
      float[] pos = positions[cubit];
168
      int type = getType(pos);
169

    
170
      switch(type)
171
        {
172
        case CUBIT_222:
173
        case CUBIT_111: return 0;
174
        case CUBIT_211:
175
        case CUBIT_311: return (pos[1]==pos[4]) ? (pos[0]==pos[3] ? 2 : 0) : 3;
176
        case CUBIT_221: if( pos[0]==pos[3] && pos[0]==pos[6] ) return 3;
177
                        if( pos[1]==pos[4] && pos[1]==pos[7] ) return 0;
178
                        if( pos[2]==pos[5] && pos[2]==pos[8] ) return 1;
179
        }
180
      }
181

    
182
    return 0;
183
    }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

    
187
  private int getSigIndex(float x, float y, float z)
188
    {
189
    if( x==-1.0f )
190
      {
191
           if( y==-1.0f ) return z==0.5f ? 4:9;
192
      else if( y==-0.5f ) return z==1.0f ? 14 : (z==0.0f ? 17:20);
193
      else if( y== 0.0f ) return z==0.5f ? 25:30;
194
      else if( y== 0.5f ) return z==1.0f ? 35 : (z==0.0f ? 38:41);
195
      else if( y== 1.0f ) return z==0.5f ? 46:51;
196
      }
197
    else if( x==-0.5f )
198
      {
199
           if( y==-1.0f ) return z==1.0f ? 1  : (z==0.0f ?  6:11);
200
      else if( y== 0.0f ) return z==1.0f ? 22 : (z==0.0f ? 27:32);
201
      else if( y== 1.0f ) return z==1.0f ? 43 : (z==0.0f ? 48:53);
202
      }
203
    else if( x==0.0f )
204
      {
205
           if( y==-1.0f ) return z==0.5f ? 3:8;
206
      else if( y==-0.5f ) return z==1.0f ? 13 : (z==0.0f ? 16:19);
207
      else if( y== 0.0f ) return z==0.5f ? 24:29;
208
      else if( y== 0.5f ) return z==1.0f ? 34 : (z==0.0f ? 37:40);
209
      else if( y== 1.0f ) return z==0.5f ? 45:50;
210
      }
211
    else if( x==0.5f )
212
      {
213
           if( y==-1.0f ) return z==1.0f ? 0  : (z==0.0f ?  5:10);
214
      else if( y== 0.0f ) return z==1.0f ? 21 : (z==0.0f ? 26:31);
215
      else if( y== 1.0f ) return z==1.0f ? 42 : (z==0.0f ? 47:52);
216
      }
217
    else if( x==1.0f )
218
      {
219
           if( y==-1.0f ) return z==0.5f ? 2:7;
220
      else if( y==-0.5f ) return z==1.0f ? 12 : (z==0.0f ? 15:18);
221
      else if( y== 0.0f ) return z==0.5f ? 23:28;
222
      else if( y== 0.5f ) return z==1.0f ? 33 : (z==0.0f ? 36:39);
223
      else if( y== 1.0f ) return z==0.5f ? 44:49;
224
      }
225
    else
226
      {
227
      android.util.Log.e("D", "ERROR! mx="+x);
228
      }
229

    
230
    return -1;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  private long markConnection(float x1, float y1, float z1, float x2, float y2, float z2)
236
    {
237
    float dx = x1-x2;
238
    float dy = y1-y2;
239
    float dz = z1-z2;
240

    
241
    if( (dx==0 && dy==0 && (dz==1 || dz==-1) ) ||
242
        (dz==0 && dx==0 && (dy==1 || dy==-1) ) ||
243
        (dy==0 && dz==0 && (dx==1 || dx==-1) )  )
244
      {
245
      float mx = (x1+x2)/2;
246
      float my = (y1+y2)/2;
247
      float mz = (z1+z2)/2;
248

    
249
      int index = getSigIndex(mx,my,mz);
250

    
251
      return (1L<<index);
252
      }
253

    
254
    return 0;
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  long markConnections(long signature, float[] position)
260
    {
261
    int len = position.length/3;
262

    
263
    for(int i=0; i<len; i++)
264
      {
265
      float x = position[3*i  ];
266
      float y = position[3*i+1];
267
      float z = position[3*i+2];
268

    
269
      for(int j=i+1; j<len; j++)
270
        {
271
        signature |= markConnection(x,y,z,position[3*j],position[3*j+1],position[3*j+2]);
272
        }
273
      }
274

    
275
    return signature;
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  public long getSignature()
281
    {
282
    long signature = 0;
283
    float[][] positions = getPositions();
284
    for(float[] pos : positions ) signature = markConnections(signature,pos);
285
    return signature;
286
    }
287

    
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289

    
290
  public ObjectShape getObjectShape(int variant)
291
    {
292
    int type,numTypes = mDims.length;
293
    for(type=0; type<numTypes; type++) if( mTypeVariantMap[type]==variant ) break;
294

    
295
    if( type<numTypes )
296
      {
297
      int X = mDims[type][0];
298
      int Y = mDims[type][1];
299
      int Z = mDims[type][2];
300

    
301
      float[][] vertices =
302
        {
303
          {+0.5f*X,+0.5f*Y,+0.5f*Z},
304
          {+0.5f*X,+0.5f*Y,-0.5f*Z},
305
          {+0.5f*X,-0.5f*Y,+0.5f*Z},
306
          {+0.5f*X,-0.5f*Y,-0.5f*Z},
307
          {-0.5f*X,+0.5f*Y,+0.5f*Z},
308
          {-0.5f*X,+0.5f*Y,-0.5f*Z},
309
          {-0.5f*X,-0.5f*Y,+0.5f*Z},
310
          {-0.5f*X,-0.5f*Y,-0.5f*Z}
311
        };
312

    
313
      int[][] indices =
314
        {
315
          {2,3,1,0},
316
          {7,6,4,5},
317
          {4,0,1,5},
318
          {7,3,2,6},
319
          {6,2,0,4},
320
          {3,7,5,1},
321
        };
322

    
323
      return new ObjectShape(vertices, indices);
324
      }
325

    
326
    float[][] positions = getPositions();
327
    int cubit,numCubits = positions.length;
328

    
329
    for(cubit=0; cubit<numCubits; cubit++)
330
      {
331
      if( mCubitVariantMap[cubit]==variant ) break;
332
      }
333

    
334
    if( cubit>=numCubits )
335
      {
336
      android.util.Log.e("D", "unknown variant: "+variant);
337
      return null;
338
      }
339

    
340
    FactoryBandaged3x3Cubit factory = FactoryBandaged3x3Cubit.getInstance();
341
    return factory.createIrregularShape(variant,positions[cubit]);
342
    }
343

    
344
///////////////////////////////////////////////////////////////////////////////////////////////////
345

    
346
  public ObjectFaceShape getObjectFaceShape(int variant)
347
    {
348
    int driver = DistortedLibrary.getGLSL();
349
    boolean roundCorners = (driver>300);
350
    int type,numTypes = mDims.length;
351
    for(type=0; type<numTypes; type++) if( mTypeVariantMap[type]==variant ) break;
352

    
353
    if( type<numTypes )
354
      {
355
      int val = roundCorners ? 0 : -1;
356
      int X = mDims[type][0];
357
      int Y = mDims[type][1];
358
      int Z = mDims[type][2];
359

    
360
      float height        = isInIconMode() ? 0.001f : 0.048f;
361
      int[] bandIndices   = { 0,0,1,1,2,2 };
362
      float[][] corners   = { {0.04f,0.15f} };
363
      int[] cornerIndices = { val,val,val,val,val,val,val,val };
364
      int[] centerIndices = { 0,1,2,3,4,5,6,7 };
365

    
366
      int maxXY = Math.max(X,Y);
367
      int maxXZ = Math.max(X,Z);
368
      int maxYZ = Math.max(Y,Z);
369

    
370
      float[][] bands =
371
        {
372
          {height/maxYZ,45,0.25f,0.5f,5,1,1},
373
          {height/maxXZ,45,0.25f,0.5f,5,1,1},
374
          {height/maxXY,45,0.25f,0.5f,5,1,1}
375
        };
376

    
377
      float[][] centers =
378
        {
379
          {+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1)},
380
          {+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1)},
381
          {+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1)},
382
          {+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1)},
383
          {-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1)},
384
          {-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1)},
385
          {-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1)},
386
          {-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1)}
387
        };
388

    
389
      return new ObjectFaceShape(bands,bandIndices,corners,cornerIndices,centers,centerIndices,null);
390
      }
391

    
392
    FactoryBandaged3x3Cubit factory = FactoryBandaged3x3Cubit.getInstance();
393
    return factory.createIrregularFaceShape(variant, isInIconMode(), roundCorners );
394
    }
395

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

    
398
  public float[][] getCubitPositions(int[] numLayers)
399
    {
400
    return getPositions();
401
    }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404

    
405
  public Static4D getCubitQuats(int cubit, int[] numLayers)
406
    {
407
    if( mInitQuats ==null )
408
      {
409
      mInitQuats = new Static4D[]
410
        {
411
        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
412
        new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),  // X
413
        new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),  // Y
414
        new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),  // Z
415
        new Static4D( -0.5f,  +0.5f,  -0.5f,  +0.5f),  // ZX
416
        new Static4D( +0.5f,  +0.5f,  +0.5f,  -0.5f),  // YX
417
        };
418
      }
419

    
420
    return mInitQuats[getQuatIndex(cubit)];
421
    }
422

    
423
///////////////////////////////////////////////////////////////////////////////////////////////////
424

    
425
  public int getNumCubitVariants(int[] numLayers)
426
    {
427
    int numVariants = 0;
428
    float[][] positions = getPositions();
429
    boolean C111=false;
430
    boolean C211=false;
431
    boolean C311=false;
432
    boolean C221=false;
433
    boolean C222=false;
434

    
435
    int numCubits = positions.length;
436
    mCubitVariantMap = new int[numCubits];
437

    
438
    int numTypes = mDims.length;
439
    mTypeVariantMap = new int[numTypes];
440
    for(int i=0; i<numTypes; i++) mTypeVariantMap[i] = -1;
441

    
442
    for (int cubit=0; cubit<numCubits; cubit++)
443
      {
444
      int type = getType(positions[cubit]);
445

    
446
      switch (type)
447
        {
448
        case CUBIT_111: if (!C111) { C111 = true; mTypeVariantMap[CUBIT_111]=numVariants++; }
449
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_111];
450
                        break;
451
        case CUBIT_211: if (!C211) { C211 = true; mTypeVariantMap[CUBIT_211]=numVariants++; }
452
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_211];
453
                        break;
454
        case CUBIT_311: if (!C311) { C311 = true; mTypeVariantMap[CUBIT_311]=numVariants++; }
455
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_311];
456
                        break;
457
        case CUBIT_221: if (!C221) { C221 = true; mTypeVariantMap[CUBIT_221]=numVariants++; }
458
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_221];
459
                        break;
460
        case CUBIT_222: if (!C222) { C222 = true; mTypeVariantMap[CUBIT_222]=numVariants++; }
461
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_222];
462
                        break;
463
        default       : mCubitVariantMap[cubit] = numVariants++;
464
        }
465
      }
466

    
467
    FactoryBandaged3x3Cubit factory = FactoryBandaged3x3Cubit.getInstance();
468
    factory.prepare(numVariants);
469

    
470
    return numVariants;
471
    }
472

    
473
///////////////////////////////////////////////////////////////////////////////////////////////////
474

    
475
  public int getCubitVariant(int cubit, int[] numLayers)
476
    {
477
    return mCubitVariantMap[cubit];
478
    }
479

    
480
///////////////////////////////////////////////////////////////////////////////////////////////////
481

    
482
  public float[][] getCuts(int[] numLayers)
483
    {
484
    int numL = numLayers[0];
485

    
486
    if( numL<2 ) return null;
487

    
488
    if( mCuts==null )
489
      {
490
      mCuts = new float[3][numL-1];
491

    
492
      for(int i=0; i<numL-1; i++)
493
        {
494
        float cut = (2-numL)*0.5f + i;
495
        mCuts[0][i] = cut;
496
        mCuts[1][i] = cut;
497
        mCuts[2][i] = cut;
498
        }
499
      }
500

    
501
    return mCuts;
502
    }
503

    
504
///////////////////////////////////////////////////////////////////////////////////////////////////
505

    
506
  public boolean[][] getLayerRotatable(int[] numLayers)
507
    {
508
    int numAxis = ROT_AXIS.length;
509
    boolean[][] layerRotatable = new boolean[numAxis][];
510

    
511
    for(int i=0; i<numAxis; i++)
512
      {
513
      layerRotatable[i] = new boolean[numLayers[i]];
514
      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
515
      }
516

    
517
    return layerRotatable;
518
    }
519

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

    
522
  public int getTouchControlType()
523
    {
524
    return TC_HEXAHEDRON;
525
    }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528

    
529
  public int getTouchControlSplit()
530
    {
531
    return TYPE_NOT_SPLIT;
532
    }
533

    
534
///////////////////////////////////////////////////////////////////////////////////////////////////
535

    
536
  public int[][][] getEnabled()
537
    {
538
    return new int[][][] { {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}} };
539
    }
540

    
541
///////////////////////////////////////////////////////////////////////////////////////////////////
542

    
543
  public float[] getDist3D(int[] numLayers)
544
    {
545
    return TouchControlHexahedron.D3D;
546
    }
547

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

    
550
  public Static3D[] getFaceAxis()
551
    {
552
    return TouchControlHexahedron.FACE_AXIS;
553
    }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556

    
557
  public float getStickerRadius()
558
    {
559
    return 0.10f;
560
    }
561

    
562
///////////////////////////////////////////////////////////////////////////////////////////////////
563

    
564
  public float getStickerStroke()
565
    {
566
    return isInIconMode() ? 0.16f : 0.08f;
567
    }
568

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

    
571
  public float[][] getStickerAngles()
572
    {
573
    return null;
574
    }
575

    
576
///////////////////////////////////////////////////////////////////////////////////////////////////
577
// PUBLIC API
578

    
579
  public Static3D[] getRotationAxis()
580
    {
581
    return ROT_AXIS;
582
    }
583

    
584
///////////////////////////////////////////////////////////////////////////////////////////////////
585

    
586
  public int[] getBasicAngles()
587
    {
588
    if( mBasicAngle ==null ) mBasicAngle = new int[] { 4,4,4 };
589
    return mBasicAngle;
590
    }
591
}
(4-4/34)