Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / objects / TwistyBandagedCuboid.java @ 1f656ca7

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_CUBOID;
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.FactoryBandagedCubit;
32
import org.distorted.objectlib.helpers.ObjectFaceShape;
33
import org.distorted.objectlib.helpers.ObjectSignature;
34
import org.distorted.objectlib.main.InitData;
35
import org.distorted.objectlib.main.ObjectType;
36
import org.distorted.objectlib.touchcontrol.TouchControlHexahedron;
37
import org.distorted.objectlib.helpers.ObjectShape;
38
import org.distorted.objectlib.scrambling.ScrambleState;
39
import org.distorted.objectlib.main.ShapeHexahedron;
40

    
41
///////////////////////////////////////////////////////////////////////////////////////////////////
42

    
43
public class TwistyBandagedCuboid extends ShapeHexahedron
44
{
45
  private static final String OBJECT_NAME = "LOCAL_BANDAGED";
46

    
47
  private static final int CUBIT_111 = 0;
48
  private static final int CUBIT_211 = 1;
49
  private static final int CUBIT_311 = 2;
50
  private static final int CUBIT_221 = 3;
51
  private static final int CUBIT_222 = 4;
52
  private static final int CUBIT_OTH = 5;
53

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

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

    
71
  public static final float[][] POS_1 = new float[][]
72
        {
73
          {-1.0f, -1.0f, +0.0f,
74
           -1.0f, -1.0f, +1.0f,
75
           -1.0f,  0.0f, +0.0f,
76
           -1.0f,  0.0f, +1.0f,
77
            0.0f, -1.0f, +0.0f,
78
            0.0f, -1.0f, +1.0f,
79
            0.0f,  0.0f, +0.0f,
80
            0.0f,  0.0f, +1.0f},
81
          {-1.0f, +1.0f, +1.0f},
82
          {-1.0f, +1.0f, +0.0f},
83
          {-1.0f, +1.0f, -1.0f},
84
          { 0.0f, +1.0f, +1.0f},
85
          { 0.0f, +1.0f, +0.0f},
86
          { 0.0f, +1.0f, -1.0f},
87
          { 1.0f, +1.0f, +1.0f},
88
          { 1.0f, +1.0f, +0.0f},
89
          { 1.0f, +1.0f, -1.0f},
90
          { 1.0f,  0.0f, +1.0f},
91
          { 1.0f,  0.0f, +0.0f},
92
          { 1.0f,  0.0f, -1.0f},
93
          { 1.0f, -1.0f, +1.0f},
94
          { 1.0f, -1.0f, +0.0f},
95
          { 1.0f, -1.0f, -1.0f},
96
          {-1.0f, -1.0f, -1.0f},
97
          {-1.0f,  0.0f, -1.0f},
98
          { 0.0f, -1.0f, -1.0f},
99
          { 0.0f,  0.0f, -1.0f}
100
        };
101

    
102
  public static final float[][] POS_2 = new float[][]
103
        {
104
          { 0.0f, +1.0f,  1.0f, 0.0f, +1.0f,  0.0f, 0.0f, +1.0f, -1.0f},
105
          {-1.0f, -1.0f,  0.0f, 0.0f, -1.0f,  0.0f, 1.0f, -1.0f,  0.0f},
106
          {-1.0f, +1.0f, +1.0f},
107
          {-1.0f, +1.0f,  0.0f},
108
          {-1.0f, +1.0f, -1.0f},
109
          {-1.0f,  0.0f, +1.0f},
110
          {-1.0f,  0.0f,  0.0f},
111
          {-1.0f,  0.0f, -1.0f},
112
          {-1.0f, -1.0f, +1.0f},
113
          {-1.0f, -1.0f, -1.0f},
114
          {+1.0f, +1.0f, +1.0f},
115
          {+1.0f, +1.0f,  0.0f},
116
          {+1.0f, +1.0f, -1.0f},
117
          {+1.0f,  0.0f, +1.0f},
118
          {+1.0f,  0.0f,  0.0f},
119
          {+1.0f,  0.0f, -1.0f},
120
          {+1.0f, -1.0f, +1.0f},
121
          {+1.0f, -1.0f, -1.0f},
122
          { 0.0f,  0.0f, +1.0f},
123
          { 0.0f, -1.0f, +1.0f},
124
          { 0.0f,  0.0f, -1.0f},
125
          { 0.0f, -1.0f, -1.0f}
126
        };
127

    
128
  public static final float[][] POS_3 = new float[][]
129
        {
130
          {-1.0f,  1.0f,  1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f,  0.0f,  0.0f,  1.0f},
131
          { 1.0f,  0.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f, -1.0f,  1.0f,  1.0f,  0.0f},
132
          {-1.0f, -1.0f, -1.0f, -1.0f, -1.0f,  0.0f,  0.0f, -1.0f, -1.0f,  0.0f, -1.0f,  0.0f},
133
          { 1.0f,  1.0f,  1.0f},
134
          { 1.0f,  0.0f,  1.0f},
135
          { 1.0f, -1.0f,  1.0f},
136
          {-1.0f, -1.0f,  1.0f},
137
          { 0.0f, -1.0f,  1.0f},
138
          { 1.0f, -1.0f,  0.0f},
139
          { 1.0f, -1.0f, -1.0f},
140
          {-1.0f,  1.0f, -1.0f},
141
          {-1.0f,  1.0f,  0.0f},
142
          { 0.0f,  1.0f, -1.0f},
143
          { 0.0f,  1.0f,  0.0f},
144
          {-1.0f,  0.0f, -1.0f},
145
          {-1.0f,  0.0f,  0.0f},
146
          { 0.0f,  0.0f, -1.0f}
147
        };
148

    
149
  public static final float[][] POS_4 = new float[][]
150
        {
151
          { 1.0f,  1.0f, -1.0f},
152
          {-1.0f, -1.0f,  0.0f, -1.0f,  0.0f,  0.0f, 0.0f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f},
153
          {-1.0f,  1.0f, -1.0f,  0.0f,  1.0f, -1.0f},
154
          {-1.0f,  0.0f, -1.0f,  0.0f,  0.0f, -1.0f},
155
          {-1.0f, -1.0f, -1.0f,  0.0f, -1.0f, -1.0f},
156
          {-1.0f,  1.0f,  0.0f, -1.0f,  1.0f,  1.0f},
157
          { 0.0f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f},
158
          { 1.0f,  1.0f,  0.0f,  1.0f,  1.0f,  1.0f},
159
          {-1.0f, -1.0f,  1.0f, -1.0f,  0.0f,  1.0f},
160
          { 0.0f, -1.0f,  1.0f,  0.0f,  0.0f,  1.0f},
161
          { 1.0f, -1.0f,  1.0f,  1.0f,  0.0f,  1.0f},
162
          { 1.0f, -1.0f,  0.0f,  1.0f,  0.0f,  0.0f},
163
          { 1.0f, -1.0f, -1.0f,  1.0f,  0.0f, -1.0f}
164
        };
165

    
166
  private int[][] mBasicAngle;
167
  private Static4D[] mInitQuats;
168
  private float[][] mCuts;
169
  private int[] mCubitVariantMap;
170
  private int[] mTypeVariantMap;
171
  private int[][] mSolvedQuatsAbstract;
172
  private float[][] mPosition;
173
  private ObjectSignature mSignature;
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  public TwistyBandagedCuboid(InitData data, int meshState, int iconMode, Static4D quat, Static3D move, float scale, InputStream stream)
178
    {
179
    super(data, meshState, iconMode, (data.getNumLayers()[0]+data.getNumLayers()[1]+data.getNumLayers()[2])/3.0f, quat, move, scale, stream);
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183
// return 0 if cubit is 'external' (it has at least two walls which belong to two different faces
184
// of the cuboid, faces which do not both rotate along the same axis! So: it is an edge, a corner,
185
// or a bandaged cubit which 'comes out' in two different, non-opposite, faces.
186
// Otherwise, if the cubit only comes out in one face or in two faces which are opposite to each other,
187
// return the index of the first of the three quats which rotate stuff in this face (so right or left
188
// return 1 because quats 1,2,3 are the ones rotating along the X axis)
189

    
190
  private int cubitIsExternal(float[] pos, float dx, float dy, float dz)
191
    {
192
    int len = pos.length/3;
193
    int x=0, y=0, z=0;
194

    
195
    for(int i=0; i<len; i++)
196
      {
197
      float cx = pos[3*i  ];
198
      float cy = pos[3*i+1];
199
      float cz = pos[3*i+2];
200

    
201
      if( cx>dx || cx<-dx ) x=1;
202
      if( cy>dy || cy<-dy ) y=1;
203
      if( cz>dz || cz<-dz ) z=1;
204
      }
205

    
206
    if( x+y+z>=2 ) return 0;
207

    
208
    if( x==1 ) return 1;
209
    if( y==1 ) return 4;
210
    if( z==1 ) return 7;
211

    
212
    android.util.Log.e("D", "ERROR: unsupported: internal cubit! ");
213
    return 0;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217
// If we have a flat cuboid than retCubitSolvedStatus() wrongly reports that the internal cubits
218
// are edges (they do have two non-black faces after all!) which leads to wrong solvedQuats and
219
// mis-detection of a solved status. Correct this manually here.
220
//
221
// Note that this is still not completely good in case of bandaged cuboids - there can be a 4x4x2
222
// bandaged cuboid whose 4 'internal' cubits from the 4x4 face are fused with the other 4 internal
223
// cubits from the other 4x4 face - and those would again get mis-detected as edges...
224

    
225
  @Override
226
  public int[][] getSolvedQuats()
227
    {
228
    if( mSolvedQuatsAbstract==null )
229
      {
230
      int[] numLayers = getNumLayers();
231
      float dx = 0.5f*(numLayers[0]-1) - 0.1f;
232
      float dy = 0.5f*(numLayers[1]-1) - 0.1f;
233
      float dz = 0.5f*(numLayers[2]-1) - 0.1f;
234

    
235
      float[][] pos = getPositions();
236
      int numTotal = pos.length;
237
      boolean[] isExternal = new boolean[numTotal];
238
      int[] internalQuat = new int[numTotal];
239
      int numExternal = 0;
240
      int pointer = 0;
241

    
242
      for(int cubit=0; cubit<numTotal; cubit++)
243
        {
244
        int q = cubitIsExternal(pos[cubit],dx,dy,dz);
245

    
246
        if( q<=0 )
247
          {
248
          isExternal[cubit] = true;
249
          numExternal++;
250
          }
251
        else
252
          {
253
          isExternal[cubit] = false;
254
          internalQuat[pointer] = q;
255
          pointer++;
256
          }
257
        }
258

    
259
      int numInternal = numTotal - numExternal;
260

    
261
      mSolvedQuatsAbstract = new int[numInternal+1][];
262
      mSolvedQuatsAbstract[0] = new int[numExternal+1];
263
      mSolvedQuatsAbstract[0][0] = numExternal;
264

    
265
      for(int i=0; i<numInternal; i++)
266
        {
267
        int q = internalQuat[i];
268
        mSolvedQuatsAbstract[i+1] = new int[5];
269
        mSolvedQuatsAbstract[i+1][0] = 1;
270
        mSolvedQuatsAbstract[i+1][2] = q;
271
        mSolvedQuatsAbstract[i+1][3] = q+1;
272
        mSolvedQuatsAbstract[i+1][4] = q+2;
273
        }
274

    
275
      int pointerExternal = 1;
276
      int pointerInternal = 1;
277

    
278
      for(int cubit=0; cubit<numTotal; cubit++)
279
        {
280
        if( isExternal[cubit] ) mSolvedQuatsAbstract[0][pointerExternal++] = cubit;
281
        else                    mSolvedQuatsAbstract[pointerInternal++][1] = cubit;
282
        }
283
      }
284

    
285
    return mSolvedQuatsAbstract;
286
    }
287

    
288
///////////////////////////////////////////////////////////////////////////////////////////////////
289
// Computing scramble states of many a bandaged cubes takes way too long time and too much space.
290
// Return null here and turn to construction of scramble tables just-in-time.
291

    
292
  @Override
293
  public ScrambleState[] getScrambleStates()
294
    {
295
    return null;
296
    }
297

    
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299

    
300
  @Override
301
  public int getScrambleType()
302
    {
303
    return 2;
304
    }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307

    
308
  private int getType(float[] pos)
309
    {
310
    switch(pos.length)
311
      {
312
      case  3: return CUBIT_111;
313
      case  6: return CUBIT_211;
314
      case  9: boolean x1 = (pos[0]==pos[3] && pos[0]==pos[6]);
315
               boolean y1 = (pos[1]==pos[4] && pos[1]==pos[7]);
316
               boolean z1 = (pos[2]==pos[5] && pos[2]==pos[8]);
317
               return ( (x1&&y1) || (x1&&z1) || (y1&&z1) ) ? CUBIT_311 : CUBIT_OTH;
318
      case 12: float x = (pos[0]+pos[3]+pos[6]+pos[ 9])/4;
319
               float y = (pos[1]+pos[4]+pos[7]+pos[10])/4;
320
               float z = (pos[2]+pos[5]+pos[8]+pos[11])/4;
321
               float d1 = (pos[0]-x)*(pos[0]-x) + (pos[ 1]-y)*(pos[ 1]-y) + (pos[ 2]-z)*(pos[ 2]-z);
322
               float d2 = (pos[3]-x)*(pos[3]-x) + (pos[ 4]-y)*(pos[ 4]-y) + (pos[ 5]-z)*(pos[ 5]-z);
323
               float d3 = (pos[6]-x)*(pos[6]-x) + (pos[ 7]-y)*(pos[ 7]-y) + (pos[ 8]-z)*(pos[ 8]-z);
324
               float d4 = (pos[9]-x)*(pos[9]-x) + (pos[10]-y)*(pos[10]-y) + (pos[11]-z)*(pos[11]-z);
325
               return ( d1==0.5f && d2==0.5f && d3==0.5f && d4==0.5f ) ? CUBIT_221 : CUBIT_OTH;
326
      case 24: float x3 = pos[0];
327
               float y3 = pos[1];
328
               float z3 = pos[2];
329
               float x4=-10,y4=-10,z4=-10;
330
               int i;
331

    
332
               for(i=0; i<8; i++)
333
                 {
334
                 if( pos[3*i]!=x3 && pos[3*i+1]!=y3 && pos[3*i+2]!=z3 )
335
                   {
336
                   x4 = pos[3*i  ];
337
                   y4 = pos[3*i+1];
338
                   z4 = pos[3*i+2];
339
                   break;
340
                   }
341
                 }
342
               if( i==9 ) return CUBIT_OTH;
343

    
344
               float dX = x4-x3;
345
               float dY = y4-y3;
346
               float dZ = z4-z3;
347

    
348
               if( (dX==1.0f || dX==-1.0f) && (dY==1.0f || dY==-1.0f) && (dZ==1.0f || dZ==-1.0f) )
349
                 {
350
                 for(i=0; i<8; i++)
351
                   {
352
                   if( (pos[3*i  ]!=x3 && pos[3*i  ]!=x4) ||
353
                       (pos[3*i+1]!=y3 && pos[3*i+1]!=y4) ||
354
                       (pos[3*i+2]!=z3 && pos[3*i+2]!=z4)  ) return CUBIT_OTH;
355
                   }
356

    
357
                 return CUBIT_222;
358
                 }
359

    
360
      default: return CUBIT_OTH;
361
      }
362
    }
363

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

    
366
  private int getQuatIndex(int cubit)
367
    {
368
    float[][] positions = getPositions();
369
    int len = positions.length;
370

    
371
    if( cubit>=0 && cubit<len )
372
      {
373
      float[] pos = positions[cubit];
374
      int type = getType(pos);
375

    
376
      switch(type)
377
        {
378
        case CUBIT_222:
379
        case CUBIT_111: return 0;
380
        case CUBIT_211:
381
        case CUBIT_311: return (pos[1]==pos[4]) ? (pos[0]==pos[3] ? 2 : 0) : 3;
382
        case CUBIT_221: if( pos[0]==pos[3] && pos[0]==pos[6] ) return 3;
383
                        if( pos[1]==pos[4] && pos[1]==pos[7] ) return 0;
384
                        if( pos[2]==pos[5] && pos[2]==pos[8] ) return 1;
385
        }
386
      }
387

    
388
    return 0;
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
  public ObjectShape getObjectShape(int variant)
394
    {
395
    int type,numTypes = mDims.length;
396
    for(type=0; type<numTypes; type++) if( mTypeVariantMap[type]==variant ) break;
397

    
398
    if( type<numTypes )
399
      {
400
      int X = mDims[type][0];
401
      int Y = mDims[type][1];
402
      int Z = mDims[type][2];
403

    
404
      float[][] vertices =
405
        {
406
          {+0.5f*X,+0.5f*Y,+0.5f*Z},
407
          {+0.5f*X,+0.5f*Y,-0.5f*Z},
408
          {+0.5f*X,-0.5f*Y,+0.5f*Z},
409
          {+0.5f*X,-0.5f*Y,-0.5f*Z},
410
          {-0.5f*X,+0.5f*Y,+0.5f*Z},
411
          {-0.5f*X,+0.5f*Y,-0.5f*Z},
412
          {-0.5f*X,-0.5f*Y,+0.5f*Z},
413
          {-0.5f*X,-0.5f*Y,-0.5f*Z}
414
        };
415

    
416
      int[][] indices =
417
        {
418
          {2,3,1,0},
419
          {7,6,4,5},
420
          {4,0,1,5},
421
          {7,3,2,6},
422
          {6,2,0,4},
423
          {3,7,5,1},
424
        };
425

    
426
      return new ObjectShape(vertices, indices);
427
      }
428

    
429
    float[][] positions = getPositions();
430
    int cubit,numCubits = positions.length;
431

    
432
    for(cubit=0; cubit<numCubits; cubit++)
433
      {
434
      if( mCubitVariantMap[cubit]==variant ) break;
435
      }
436

    
437
    if( cubit>=numCubits )
438
      {
439
      android.util.Log.e("D", "unknown variant: "+variant);
440
      return null;
441
      }
442

    
443
    FactoryBandagedCubit factory = FactoryBandagedCubit.getInstance();
444
    return factory.createIrregularShape(variant,positions[cubit]);
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
  public ObjectFaceShape getObjectFaceShape(int variant)
450
    {
451
    boolean roundCorners = DistortedLibrary.fastCompilationTF();
452
    int type,numTypes = mDims.length;
453
    for(type=0; type<numTypes; type++) if( mTypeVariantMap[type]==variant ) break;
454

    
455
    if( type<numTypes )
456
      {
457
      int val = roundCorners ? 0 : -1;
458
      int X = mDims[type][0];
459
      int Y = mDims[type][1];
460
      int Z = mDims[type][2];
461

    
462
      float height        = isInIconMode() ? 0.001f : 0.048f;
463
      int[] bandIndices   = { 0,0,1,1,2,2 };
464
      float[][] corners   = { {0.04f,0.15f} };
465
      int[] cornerIndices = { val,val,val,val,val,val,val,val };
466
      int[] centerIndices = { 0,1,2,3,4,5,6,7 };
467

    
468
      int maxXY = Math.max(X,Y);
469
      int maxXZ = Math.max(X,Z);
470
      int maxYZ = Math.max(Y,Z);
471

    
472
      int angle = 45;
473
      float R = 0.25f;
474
      float S = 0.50f;
475

    
476
      float[][] bands =
477
        {
478
          {height/maxYZ,angle,R,S,5,0,0},
479
          {height/maxXZ,angle,R,S,5,0,0},
480
          {height/maxXY,angle,R,S,5,0,0}
481
        };
482

    
483
      float[][] centers =
484
        {
485
          {+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1)},
486
          {+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1)},
487
          {+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1)},
488
          {+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1)},
489
          {-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1)},
490
          {-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1)},
491
          {-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1)},
492
          {-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1)}
493
        };
494

    
495
      return new ObjectFaceShape(bands,bandIndices,corners,cornerIndices,centers,centerIndices,null);
496
      }
497

    
498
    FactoryBandagedCubit factory = FactoryBandagedCubit.getInstance();
499
    return factory.createIrregularFaceShape(variant, isInIconMode(), roundCorners );
500
    }
501

    
502
///////////////////////////////////////////////////////////////////////////////////////////////////
503

    
504
  public float[][] getCubitPositions(int[] numLayers)
505
    {
506
    return getPositions();
507
    }
508

    
509
///////////////////////////////////////////////////////////////////////////////////////////////////
510

    
511
  public Static4D getCubitQuats(int cubit, int[] numLayers)
512
    {
513
    if( mInitQuats ==null )
514
      {
515
      mInitQuats = new Static4D[]
516
        {
517
        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
518
        new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),  // X
519
        new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),  // Y
520
        new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),  // Z
521
        new Static4D( -0.5f,  +0.5f,  -0.5f,  +0.5f),  // ZX
522
        new Static4D( +0.5f,  +0.5f,  +0.5f,  -0.5f),  // YX
523
        };
524
      }
525

    
526
    return mInitQuats[getQuatIndex(cubit)];
527
    }
528

    
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530

    
531
  public int getNumCubitVariants(int[] numLayers)
532
    {
533
    int numVariants = 0;
534
    float[][] positions = getPositions();
535
    boolean C111=false;
536
    boolean C211=false;
537
    boolean C311=false;
538
    boolean C221=false;
539
    boolean C222=false;
540

    
541
    int numCubits = positions.length;
542
    mCubitVariantMap = new int[numCubits];
543

    
544
    int numTypes = mDims.length;
545
    mTypeVariantMap = new int[numTypes];
546
    for(int i=0; i<numTypes; i++) mTypeVariantMap[i] = -1;
547

    
548
    for (int cubit=0; cubit<numCubits; cubit++)
549
      {
550
      int type = getType(positions[cubit]);
551

    
552
      switch (type)
553
        {
554
        case CUBIT_111: if (!C111) { C111 = true; mTypeVariantMap[CUBIT_111]=numVariants++; }
555
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_111];
556
                        break;
557
        case CUBIT_211: if (!C211) { C211 = true; mTypeVariantMap[CUBIT_211]=numVariants++; }
558
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_211];
559
                        break;
560
        case CUBIT_311: if (!C311) { C311 = true; mTypeVariantMap[CUBIT_311]=numVariants++; }
561
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_311];
562
                        break;
563
        case CUBIT_221: if (!C221) { C221 = true; mTypeVariantMap[CUBIT_221]=numVariants++; }
564
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_221];
565
                        break;
566
        case CUBIT_222: if (!C222) { C222 = true; mTypeVariantMap[CUBIT_222]=numVariants++; }
567
                        mCubitVariantMap[cubit]=mTypeVariantMap[CUBIT_222];
568
                        break;
569
        default       : mCubitVariantMap[cubit] = numVariants++;
570
        }
571
      }
572

    
573
    FactoryBandagedCubit factory = FactoryBandagedCubit.getInstance();
574
    factory.prepare(numVariants,numLayers[0],numLayers[1],numLayers[2]);
575

    
576
    return numVariants;
577
    }
578

    
579
///////////////////////////////////////////////////////////////////////////////////////////////////
580

    
581
  public int getCubitVariant(int cubit, int[] numLayers)
582
    {
583
    return mCubitVariantMap[cubit];
584
    }
585

    
586
///////////////////////////////////////////////////////////////////////////////////////////////////
587

    
588
  public float[][] getCuts(int[] numLayers)
589
    {
590
    if( mCuts==null )
591
      {
592
      mCuts = new float[3][];
593

    
594
      for(int axis=0; axis<3; axis++)
595
        {
596
        int len = numLayers[axis];
597
        float start = (2-len)*0.5f;
598

    
599
        if( len>=2 )
600
          {
601
          mCuts[axis] = new float[len-1];
602
          for(int i=0; i<len-1; i++) mCuts[axis][i] = start+i;
603
          }
604
        }
605
      }
606

    
607
    return mCuts;
608
    }
609

    
610
///////////////////////////////////////////////////////////////////////////////////////////////////
611

    
612
  public boolean[][] getLayerRotatable(int[] numLayers)
613
    {
614
    int numAxis = ROT_AXIS.length;
615
    boolean[][] layerRotatable = new boolean[numAxis][];
616

    
617
    for(int i=0; i<numAxis; i++)
618
      {
619
      layerRotatable[i] = new boolean[numLayers[i]];
620
      for(int j=0; j<numLayers[i]; j++) layerRotatable[i][j] = true;
621
      }
622

    
623
    return layerRotatable;
624
    }
625

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

    
628
  public int getTouchControlType()
629
    {
630
    return TC_CUBOID;
631
    }
632

    
633
///////////////////////////////////////////////////////////////////////////////////////////////////
634

    
635
  public int getTouchControlSplit()
636
    {
637
    return TYPE_NOT_SPLIT;
638
    }
639

    
640
///////////////////////////////////////////////////////////////////////////////////////////////////
641

    
642
  public int[][][] getEnabled()
643
    {
644
    return new int[][][] { {{1,2}},{{1,2}},{{0,2}},{{0,2}},{{0,1}},{{0,1}} };
645
    }
646

    
647
///////////////////////////////////////////////////////////////////////////////////////////////////
648

    
649
  public float[] getDist3D(int[] numLayers)
650
    {
651
    float x = numLayers[0];
652
    float y = numLayers[1];
653
    float z = numLayers[2];
654
    float a = (x+y+z)/1.5f;
655

    
656
    return new float[] {x/a,x/a,y/a,y/a,z/a,z/a};
657
    }
658

    
659
///////////////////////////////////////////////////////////////////////////////////////////////////
660

    
661
  public Static3D[] getFaceAxis()
662
    {
663
    return TouchControlHexahedron.FACE_AXIS;
664
    }
665

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

    
668
  public float getStickerRadius()
669
    {
670
    return 0.10f;
671
    }
672

    
673
///////////////////////////////////////////////////////////////////////////////////////////////////
674

    
675
  public float getStickerStroke()
676
    {
677
    return isInIconMode() ? 0.16f : 0.08f;
678
    }
679

    
680
///////////////////////////////////////////////////////////////////////////////////////////////////
681

    
682
  public float[][] getStickerAngles()
683
    {
684
    return null;
685
    }
686

    
687
///////////////////////////////////////////////////////////////////////////////////////////////////
688
// PUBLIC API
689

    
690
  public Static3D[] getRotationAxis()
691
    {
692
    return ROT_AXIS;
693
    }
694

    
695
///////////////////////////////////////////////////////////////////////////////////////////////////
696

    
697
  public int[][] getBasicAngles()
698
    {
699
     if( mBasicAngle==null )
700
      {
701
      int[] num = getNumLayers();
702
      int numX = num[0];
703
      int numY = num[1];
704
      int numZ = num[2];
705

    
706
      int x = numY==numZ ? 4 : 2;
707
      int y = numX==numZ ? 4 : 2;
708
      int z = numX==numY ? 4 : 2;
709

    
710
      int[] tmpX = new int[numX];
711
      for(int i=0; i<numX; i++) tmpX[i] = x;
712
      int[] tmpY = new int[numY];
713
      for(int i=0; i<numY; i++) tmpY[i] = y;
714
      int[] tmpZ = new int[numZ];
715
      for(int i=0; i<numZ; i++) tmpZ[i] = z;
716

    
717
      mBasicAngle = new int[][] { tmpX,tmpY,tmpZ };
718
      }
719

    
720
    return mBasicAngle;
721
    }
722

    
723
///////////////////////////////////////////////////////////////////////////////////////////////////
724

    
725
  float[][] getPositions()
726
    {
727
    if( mPosition==null ) mPosition = getInitData().getPos();
728
    return mPosition;
729
    }
730

    
731
///////////////////////////////////////////////////////////////////////////////////////////////////
732

    
733
  public static int getType(String shortName)
734
    {
735
    if( shortName.equals(ObjectType.BAN1_3.name()) ||
736
        shortName.equals(ObjectType.BAN2_3.name()) ||
737
        shortName.equals(ObjectType.BAN3_3.name()) ||
738
        shortName.equals(ObjectType.BAN4_3.name())  ) return 2;
739

    
740
    if( shortName.equals(OBJECT_NAME) ) return 1;
741

    
742
    return 0;
743
    }
744

    
745
///////////////////////////////////////////////////////////////////////////////////////////////////
746
// PUBLIC APi
747

    
748
  public String getShortName()
749
    {
750
    if( mPosition==null ) mPosition = getInitData().getPos();
751

    
752
    if( mPosition==POS_1 ) return ObjectType.BAN1_3.name();
753
    if( mPosition==POS_2 ) return ObjectType.BAN2_3.name();
754
    if( mPosition==POS_3 ) return ObjectType.BAN3_3.name();
755
    if( mPosition==POS_4 ) return ObjectType.BAN4_3.name();
756

    
757
    if( mSignature==null ) mSignature = getSignature();
758
    int[] numLayers = getNumLayers();
759
    int number = 100*numLayers[0]+10*numLayers[1]+numLayers[2];
760

    
761
    return number+"_"+mSignature.getString();
762
    }
763

    
764
///////////////////////////////////////////////////////////////////////////////////////////////////
765

    
766
  public ObjectSignature getSignature()
767
    {
768
    if( mSignature==null )
769
      {
770
      int[] numLayers = getNumLayers();
771
      mSignature = new ObjectSignature(numLayers[0],numLayers[1],numLayers[2],mPosition);
772
      }
773
    return mSignature;
774
    }
775

    
776
///////////////////////////////////////////////////////////////////////////////////////////////////
777

    
778
  public String getObjectName()
779
    {
780
    if( mPosition==null ) mPosition = getInitData().getPos();
781

    
782
    if( mPosition==POS_1 ) return "Fused Cube";
783
    if( mPosition==POS_2 ) return "2Bar Cube";
784
    if( mPosition==POS_3 ) return "Bandaged Cube C";
785
    if( mPosition==POS_4 ) return "BiCube";
786

    
787
    return OBJECT_NAME;
788
    }
789

    
790
///////////////////////////////////////////////////////////////////////////////////////////////////
791

    
792
  public String getInventor()
793
    {
794
    if( mPosition==null ) mPosition = getInitData().getPos();
795

    
796
    if( mPosition==POS_1 ) return "Ting Huang";
797
    if( mPosition==POS_2 ) return "Unknown";
798
    if( mPosition==POS_3 ) return "Andreas Nortmann";
799
    if( mPosition==POS_4 ) return "Uwe Meffert";
800

    
801
    return "??";
802
    }
803

    
804
///////////////////////////////////////////////////////////////////////////////////////////////////
805

    
806
  public int getYearOfInvention()
807
    {
808
    if( mPosition==null ) mPosition = getInitData().getPos();
809

    
810
    if( mPosition==POS_1 ) return 2011;
811
    if( mPosition==POS_2 ) return 0;
812
    if( mPosition==POS_3 ) return 2005;
813
    if( mPosition==POS_4 ) return 1999;
814

    
815
    return 0;
816
    }
817

    
818
///////////////////////////////////////////////////////////////////////////////////////////////////
819

    
820
  public int getComplexity()
821
    {
822
    if( mPosition==null ) mPosition = getInitData().getPos();
823

    
824
    if( mPosition==POS_1 ) return 1;
825
    if( mPosition==POS_2 ) return 2;
826
    if( mPosition==POS_3 ) return 2;
827
    if( mPosition==POS_4 ) return 3;
828

    
829
    return 4;
830
    }
831

    
832
///////////////////////////////////////////////////////////////////////////////////////////////////
833

    
834
  public String[][] getTutorials()
835
    {
836
    if( mPosition==null ) mPosition = getInitData().getPos();
837

    
838
    if( mPosition==POS_1 )
839
      {
840
      return new String[][]{
841
                            {"gb","F_iJk_IvpVo","Bandaged Cube","CanChrisSolve"},
842
                            {"es","_lTgw5aEFOg","Tutorial 3x3 Fuse Cube","QBAndo"},
843
                            {"ru","raYDwFEXIq4","Как собрать Fused Cube","Алексей Ярыгин"},
844
                            {"fr","9Cfi4rhKzIw","Tutoriel: résolution du Fused Cube","Skieur Cubb"},
845
                            {"pl","0PcUoGxQa6s","Bandaged 3x3 v.A cube","MrUK"},
846
                            {"kr","1RePOLrzJNE","밴디지 타입 A 해법","듀나메스 큐브 해법연구소"},
847
                            {"vn","vg4J0U0n1oA","Tutorial N.1 - Bandaged VA","Duy Thích Rubik"},
848
                           };
849
      }
850
    if( mPosition==POS_2 )
851
      {
852
      return new String[][]{
853
                            {"ru","lS_EK0PMWI8","Как собрать 2-bar Cube","Алексей Ярыгин"},
854
                            {"pl","tX8ubTLh6p8","Bandaged 3x3 (Two bar)","MrUK"},
855
                            {"kr","NE6XuC1r8xw","밴디지 큐브","Denzel Washington"},
856
                           };
857
      }
858
    if( mPosition==POS_3 )
859
      {
860
      return new String[][]{
861
                            {"gb","7UiCVGygUT4","Bandage Cube C Tutorial","PolyakB"},
862
                            {"ru","gXenRA92Wdc","Как собрать Bandaged 3x3 Type C","YG Cuber"},
863
                            {"pl","sKfdFLm79Zs","Bandaged 3x3 v.C cube","MrUK"},
864
                            {"kr","BcCFgeFy6Ec","밴디지 타입 C 해법","듀나메스 큐브 해법연구소"},
865
                            {"vn","9674LLkPSog","Tutorial N.2 - Bandaged VC","Duy Thích Rubik"},
866
                           };
867
      }
868
    if( mPosition==POS_4 )
869
      {
870
      return new String[][]{
871
                            {"gb","AnpdIKICBpM","Trying to Solve a Bandaged Cube","RedKB"},
872
                            {"es","cUyo5fycrvI","Tutorial Bandaged Cube en español","Rafa Garcia Benacazon"},
873
                            {"ru","-MTzeEJptsg","Как собрать bandaged Cube B","стратегия знаний"},
874
                            {"fr","3rsfIJ3roT0","Tutoriel: résolution du Bicube","Skieur Cubb"},
875
                            {"de","sqWVRwkXX9w","Bandaged Cube - Tutorial","GerCubing"},
876
                            {"pl","XcHzTvVR6Po","Bandaged 3x3 v.B cube","MrUK"},
877
                            {"kr","1gsoijF_5q0","BiCube Tutorial (해법)","듀나메스 큐브 해법연구소"},
878
                            {"vn","ZCJDaF4jEbc","Tutorial N.3 - BiCube","Duy Thích Rubik"},
879
                           };
880
      }
881

    
882
    return null;
883
    }
884
}
(2-2/35)