Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / ObjectSignature.java @ d2e06841

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.helpers;
11

    
12
import java.util.ArrayList;
13

    
14
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.MEGA_D;
15
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.SIN18;
16
import static org.distorted.objectlib.main.TwistyObject.SQ2;
17
import static org.distorted.objectlib.main.TwistyObject.SQ3;
18
import static org.distorted.objectlib.main.TwistyObject.SQ6;
19
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.KILOMINX3;
20
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.KILOMINX5;
21
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.MEGAMINX3;
22
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.MEGAMINX5;
23
import static org.distorted.objectlib.scrambling.ScrambleStateLocallyBandaged.MAX_SUPPORTED_SIZE;
24
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
25
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.COS54;
26
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
27
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
28

    
29
import org.distorted.library.helpers.QuatHelper;
30
import org.distorted.objectlib.bandaged.BandagedObjectMegaminx;
31
import org.distorted.objectlib.bandaged.FactoryBandagedMegaminx;
32
import org.distorted.objectlib.bandaged.FactoryBandagedPyraminx;
33
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
34

    
35
///////////////////////////////////////////////////////////////////////////////////////////////////
36

    
37
public class ObjectSignature implements Comparable<ObjectSignature>
38
{
39
  public static final int SIZE = computeNum();
40

    
41
  private static final float[][] mRotAxisPyraminx =
42
        {
43
                {     0, -SQ3/3, -SQ6/3},
44
                {     0, -SQ3/3,  SQ6/3},
45
                { SQ6/3,  SQ3/3,      0},
46
                {-SQ6/3,  SQ3/3,      0},
47
        };
48

    
49
  private static final float[][] mQuatsPyraminx =
50
        {
51
                {     0, -0.5f, -SQ2/2, 0.5f },
52
                {     0, -0.5f,  SQ2/2, 0.5f },
53
                { SQ2/2,  0.5f,      0, 0.5f },
54
                {-SQ2/2,  0.5f,      0, 0.5f },
55
        };
56

    
57
  private static final float[][] mRotAxisMegaminx =
58
        {
59
                {    C2/LEN, SIN54/LEN,    0      },
60
                {   -C2/LEN, SIN54/LEN,    0      },
61
                { 0        ,    C2/LEN, SIN54/LEN },
62
                { 0        ,   -C2/LEN, SIN54/LEN },
63
                { SIN54/LEN,    0     ,    C2/LEN },
64
                { SIN54/LEN,    0     ,   -C2/LEN }
65
        };
66

    
67
  private static final float[][] mQuatsMegaminx =
68
        {
69
                {  COS54*   C2/LEN, COS54*SIN54/LEN, 0              , SIN54 },
70
                { -COS54*   C2/LEN, COS54*SIN54/LEN, 0              , SIN54 },
71
                {  0              , COS54*   C2/LEN, COS54*SIN54/LEN, SIN54 },
72
                {  0              ,-COS54*   C2/LEN, COS54*SIN54/LEN, SIN54 },
73
                {  COS54*SIN54/LEN, 0              , COS54*   C2/LEN, SIN54 },
74
                {  COS54*SIN54/LEN, 0              ,-COS54*   C2/LEN, SIN54 }
75
        };
76

    
77
  private long[] mSignature;
78
  private int[] mLayer;
79
  private int[] mFactoryLayer;
80
  private int[][][][] mCycles;
81
  private float[][] mCubitTouch;
82
  private int[][] mTouchRows;
83
  private int mNumCubitTouches;
84
  private int[] mNumLeftCyclesPerLayer;
85
  private int[] mNumCentCyclesPerLayer;
86
  private int[] mNumInneCyclesPerLayer;
87
  private String mName=null;
88
  private float[] mTmp;
89
  private int mParam;
90

    
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92
// a cube of size N has 12*(N-1)^2 possible places two adjacent cubies can be 'glued'; therefore
93
// the signature must contain ceil( 12*(N-1)^2 / 64 ) bytes.
94
// a pyraminx of size N has 4 + 6*(N-1)(N-2) places two adjacent cubies can be 'glued' so much less.
95

    
96
// Gigaminx has 540 such places (so more if N<=7)
97

    
98
  private static int computeNum()
99
    {
100
    int max = MAX_SUPPORTED_SIZE-1;
101
    int ret = (int)(0.99f + (12*max*max)/64.0f);
102
    int giga= (int)(0.99f + (       540)/64.0f);
103

    
104
    return Math.max(ret,giga);
105
    }
106

    
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

    
109
  private void setUpSignature(long[] signature)
110
    {
111
    int size = signature.length;
112
    int diff = SIZE-size;
113

    
114
    if( diff==0 ) mSignature = signature;
115
    else
116
      {
117
      mSignature = new long[SIZE];
118
      for(int i=0; i<size; i++) mSignature[diff+i] = signature[i];
119
      }
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  public ObjectSignature(ObjectSignature sig)
125
    {
126
    int len = sig.mSignature.length;
127
    mSignature = new long[len];
128
    for(int i=0; i<len; i++) mSignature[i] = sig.mSignature[i];
129

    
130
    mLayer        = sig.mLayer;
131
    mCycles       = sig.mCycles;
132
    mCubitTouch   = sig.mCubitTouch;
133
    mTouchRows    = sig.mTouchRows;
134
    mName         = sig.mName;
135
    mTmp          = sig.mTmp;
136
    mParam        = sig.mParam;
137
    mFactoryLayer = sig.mFactoryLayer;
138

    
139
    mNumCubitTouches       = sig.mNumCubitTouches;
140
    mNumCentCyclesPerLayer = sig.mNumCentCyclesPerLayer;
141
    mNumLeftCyclesPerLayer = sig.mNumLeftCyclesPerLayer;
142
    mNumInneCyclesPerLayer = sig.mNumInneCyclesPerLayer;
143
    }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146
// built-in objects; objects created from JSON (version1)
147

    
148
  public ObjectSignature(long signature)
149
    {
150
    mSignature = new long[SIZE];
151
    mSignature[SIZE-1] = signature;
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155
// locally created bandaged cuboids created from JSON (version2)
156
// or locally created bandaged pyraminxes, or locally bandaged megaminxes.
157
// How to tell apart: pyraminx's shortName starts with a 'P'; megaminx's shortName starts with a 'M'.
158

    
159
  public ObjectSignature(String shortName, long[] signature)
160
    {
161
    setUpSignature(signature);
162

    
163
    char name = shortName.charAt(0);
164

    
165
    if( name == 'P' )
166
      {
167
      mTmp = new float[4];
168
      int x=shortName.charAt(1)-'0';
169
      mLayer=new int[] {x,x,x,x};
170

    
171
      prepareCubitTouchPyraminx();
172
      prepareTouchRowsPyraminx();
173
      prepareAllCyclesPyraminx();
174
      }
175
    else if( name == 'M' )
176
      {
177
      mTmp = new float[4];
178
      mParam=shortName.charAt(1)-'0';
179
      int x=-1, y=-1;
180

    
181
      switch(mParam)
182
        {
183
        case 2: x=3; y=2; break;
184
        case 3: x=3; y=3; break;
185
        case 4: x=5; y=4; break;
186
        case 5: x=5; y=5; break;
187
        }
188

    
189
      mLayer=new int[] {x,x,x,x,x,x};
190
      mFactoryLayer=new int[] {y,y,y,y,y,y};
191

    
192
      prepareCubitTouchMegaminx();
193
      prepareTouchRowsMegaminx();
194
      prepareAllCyclesMegaminx();
195
      }
196
    else
197
      {
198
      int x=shortName.charAt(0)-'0';
199
      int y=shortName.charAt(1)-'0';
200
      int z=shortName.charAt(2)-'0';
201
      mLayer=new int[] {x,y,z};
202
      prepareCubitTouchCuboid();
203
      prepareTouchRowsCuboid();
204
      prepareAllCyclesCuboid();
205
      }
206
    }
207

    
208
///////////////////////////////////////////////////////////////////////////////////////////////////
209
// BAN*** objects when read from JSON
210

    
211
  public ObjectSignature(int size, long[] signature)
212
    {
213
    setUpSignature(signature);
214

    
215
    mLayer = new int[] {size,size,size};
216

    
217
    prepareCubitTouchCuboid();
218
    prepareTouchRowsCuboid();
219
    prepareAllCyclesCuboid();
220
    }
221

    
222
///////////////////////////////////////////////////////////////////////////////////////////////////
223
// other objects created from JSON (version2)
224

    
225
  public ObjectSignature(long[] signature)
226
    {
227
    setUpSignature(signature);
228
    }
229

    
230
///////////////////////////////////////////////////////////////////////////////////////////////////
231
// Locally created bandaged cuboids 1<=N,M,K<=7
232
// This is the 'Andreas signature' of a bandaged cube.
233
// https://twistypuzzles.com/forum/viewtopic.php?p=415466#p415466
234

    
235
  public ObjectSignature(int lenx, int leny, int lenz, float[][] position)
236
    {
237
    mLayer = new int[] {lenx,leny,lenz};
238
    mSignature = new long[SIZE];
239

    
240
    prepareCubitTouchCuboid();
241

    
242
    for(float[] pos : position)
243
      {
244
      int numCenters = pos.length/3;
245

    
246
      for(int i=0; i<numCenters; i++)
247
        {
248
        float xi = pos[3*i  ];
249
        float yi = pos[3*i+1];
250
        float zi = pos[3*i+2];
251

    
252
        for(int j=i+1; j<numCenters; j++)
253
          {
254
          float xj = pos[3*j  ];
255
          float yj = pos[3*j+1];
256
          float zj = pos[3*j+2];
257

    
258
          if(areNeighboursCuboid(xi-xj,yi-yj,zi-zj))
259
            {
260
            float xc = (xi+xj)/2;
261
            float yc = (yi+yj)/2;
262
            float zc = (zi+zj)/2;
263

    
264
            int bitIndex = getIndexOfCubitTouch(xc,yc,zc);
265
            setBit(bitIndex,1);
266
            }
267
          }
268
        }
269
      }
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273
// Locally created bandaged pyraminxes 1<=N<=7
274

    
275
  public ObjectSignature(int len, float[][] position)
276
    {
277
    mTmp = new float[4];
278
    mLayer = new int[] {len,len,len,len};
279
    mSignature = new long[SIZE];
280

    
281
    prepareCubitTouchPyraminx();
282

    
283
    for(float[] pos : position)
284
      {
285
      int numCenters = pos.length/3;
286

    
287
      for(int i=0; i<numCenters; i++)
288
        {
289
        float xi = pos[3*i  ];
290
        float yi = pos[3*i+1];
291
        float zi = pos[3*i+2];
292

    
293
        for(int j=i+1; j<numCenters; j++)
294
          {
295
          float xj = pos[3*j  ];
296
          float yj = pos[3*j+1];
297
          float zj = pos[3*j+2];
298

    
299
          if( areNeighboursPyraminx(xi-xj,yi-yj,zi-zj) )
300
            {
301
            boolean octa = FactoryBandagedPyraminx.isOctahedron(len,yi);
302
            float xc,yc,zc;
303

    
304
            if( octa )
305
              {
306
              xc = (xi+2*xj)/3;
307
              yc = (yi+2*yj)/3;
308
              zc = (zi+2*zj)/3;
309
              }
310
            else
311
              {
312
              xc = (2*xi+xj)/3;
313
              yc = (2*yi+yj)/3;
314
              zc = (2*zi+zj)/3;
315
              }
316

    
317
            int bitIndex = getIndexOfCubitTouch(xc,yc,zc);
318
            setBit(bitIndex,1);
319
            }
320
          }
321
        }
322
      }
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326
// Locally created bandaged megaminxes size 2<=N<=5
327

    
328
  public ObjectSignature(float[][] position, int param)
329
    {
330
    int x=-1;
331

    
332
    switch(param)
333
      {
334
      case KILOMINX3: x=3; mParam=2; break;
335
      case MEGAMINX3: x=3; mParam=3; break;
336
      case KILOMINX5: x=5; mParam=4; break;
337
      case MEGAMINX5: x=5; mParam=5; break;
338
      }
339

    
340
    mLayer=new int[] {x,x,x,x,x,x};
341
    mFactoryLayer=new int[] {mParam,mParam,mParam,mParam,mParam,mParam};
342
    mSignature = new long[SIZE];
343
    mTmp = new float[4];
344

    
345
    prepareCubitTouchMegaminx();
346

    
347
    for(float[] pos : position)
348
      {
349
      int numCenters = pos.length/3;
350

    
351
      for(int i=0; i<numCenters; i++)
352
        {
353
        float xi = pos[3*i  ];
354
        float yi = pos[3*i+1];
355
        float zi = pos[3*i+2];
356

    
357
        for(int j=i+1; j<numCenters; j++)
358
          {
359
          float xj = pos[3*j  ];
360
          float yj = pos[3*j+1];
361
          float zj = pos[3*j+2];
362

    
363
          if( areNeighboursMegaminx(param,xi-xj,yi-yj,zi-zj) )
364
            {
365
            float xc = (xi+xj)/2;  // TODO
366
            float yc = (yi+yj)/2;
367
            float zc = (zi+zj)/2;
368

    
369
            int bitIndex = getIndexOfCubitTouch(xc,yc,zc);
370
            setBit(bitIndex,1);
371
            }
372
          }
373
        }
374
      }
375
    }
376

    
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
  public void setSignature(int signature)
380
    {
381
    for(int i=0; i<SIZE-1; i++) mSignature[i]=0;
382
    mSignature[SIZE-1] = signature;
383
    }
384

    
385
///////////////////////////////////////////////////////////////////////////////////////////////////
386

    
387
  public int compareTo(ObjectSignature sig)
388
    {
389
    for(int i=0; i<SIZE; i++)
390
      {
391
      long diff = mSignature[i] - sig.mSignature[i];
392

    
393
           if( diff>0 ) return +1;
394
      else if( diff<0 ) return -1;
395
      }
396

    
397
    return 0;
398
    }
399

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401

    
402
  public boolean isEqual(ObjectSignature sig)
403
    {
404
    for(int i=0; i<SIZE; i++)
405
      {
406
      if( mSignature[i] != sig.mSignature[i] ) return false;
407
      }
408

    
409
    return true;
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
  public long[] getArray()
415
    {
416
    return mSignature;
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

    
421
  public String getString()
422
    {
423
    if( mName==null )
424
      {
425
      StringBuilder sb = new StringBuilder();
426

    
427
      for(int i=0; i<SIZE; i++)
428
        {
429
        String sig = String.format("0x%016X", mSignature[i]);
430
        if( i>0 ) sb.append('_');
431
        sb.append(sig);
432
        }
433

    
434
      mName = sb.toString();
435
      }
436

    
437
    return mName;
438
    }
439

    
440
///////////////////////////////////////////////////////////////////////////////////////////////////
441

    
442
  public boolean isUnblockedFromLeft(int axis, int layer)
443
    {
444
    if(layer>0)
445
      {
446
      int[] touch = mTouchRows[axis];
447

    
448
      for( int index=0; index<mNumCubitTouches; index++)
449
        if( touch[index]==layer && getBit(index)!=0 ) return false;
450
      }
451

    
452
    return true;
453
    }
454

    
455
///////////////////////////////////////////////////////////////////////////////////////////////////
456

    
457
  public ObjectSignature turn(int axis, int layer, int turn)
458
    {
459
    ObjectSignature ret = new ObjectSignature(this);
460

    
461
    // I don't understand it, but Firebase shows mCycles is occasionally null here.
462
    if( mCycles!=null && mCycles[axis]!=null )
463
      {
464
      int[][] cycles = mCycles[axis][layer];
465

    
466
      // it can happen that there are no cycles in this layer: 2x1x2 axis 0 layer 0.
467
      if( cycles!=null && cycles.length>0 && cycles[0]!=null )
468
        {
469
             if( cycles[0].length==5 ) for(int[] cyc : cycles) ret.cycle5(turn,cyc);
470
        else if( cycles[0].length==4 ) for(int[] cyc : cycles) ret.cycle4(turn,cyc);
471
        else if( cycles[0].length==3 ) for(int[] cyc : cycles) ret.cycle3(turn,cyc);
472
        else if( cycles[0].length==2 ) for(int[] cyc : cycles) ret.cycle2(cyc);
473
        }
474
      }
475

    
476
    return ret;
477
    }
478

    
479
///////////////////////////////////////////////////////////////////////////////////////////////////
480

    
481
  private void cycle2(int[] cyc)
482
    {
483
    int index0 = cyc[0];
484
    int index1 = cyc[1];
485

    
486
    long b0 = getBit(index0);
487
    long b1 = getBit(index1);
488

    
489
    setBit(index1,b0);
490
    setBit(index0,b1);
491
    }
492

    
493
///////////////////////////////////////////////////////////////////////////////////////////////////
494

    
495
  private void cycle3(int turn, int[] cyc)
496
    {
497
    int index0 = cyc[0];
498
    int index1 = cyc[1];
499
    int index2 = cyc[2];
500

    
501
    long b0 = getBit(index0);
502
    long b1 = getBit(index1);
503
    long b2 = getBit(index2);
504

    
505
    switch(turn)
506
      {
507
      case 1: setBit(index0,b2);
508
              setBit(index1,b0);
509
              setBit(index2,b1);
510
              break;
511
      case 2: setBit(index0,b1);
512
              setBit(index1,b2);
513
              setBit(index2,b0);
514
              break;
515
      }
516
    }
517

    
518
///////////////////////////////////////////////////////////////////////////////////////////////////
519

    
520
  private void cycle4(int turn, int[] cyc)
521
    {
522
    int index0 = cyc[0];
523
    int index1 = cyc[1];
524
    int index2 = cyc[2];
525
    int index3 = cyc[3];
526

    
527
    long b0 = getBit(index0);
528
    long b1 = getBit(index1);
529
    long b2 = getBit(index2);
530
    long b3 = getBit(index3);
531

    
532
    switch(turn)
533
      {
534
      case 1: setBit(index0,b3);
535
              setBit(index1,b0);
536
              setBit(index2,b1);
537
              setBit(index3,b2);
538
              break;
539
      case 2: setBit(index0,b2);
540
              setBit(index1,b3);
541
              setBit(index2,b0);
542
              setBit(index3,b1);
543
              break;
544
      case 3: setBit(index0,b1);
545
              setBit(index1,b2);
546
              setBit(index2,b3);
547
              setBit(index3,b0);
548
              break;
549
      }
550
    }
551

    
552
///////////////////////////////////////////////////////////////////////////////////////////////////
553

    
554
  private void cycle5(int turn, int[] cyc)
555
    {
556
    int index0 = cyc[0];
557
    int index1 = cyc[1];
558
    int index2 = cyc[2];
559
    int index3 = cyc[3];
560
    int index4 = cyc[4];
561

    
562
    long b0 = getBit(index0);
563
    long b1 = getBit(index1);
564
    long b2 = getBit(index2);
565
    long b3 = getBit(index3);
566
    long b4 = getBit(index4);
567

    
568
    switch(turn)
569
      {
570
      case 1: setBit(index0,b4);
571
              setBit(index1,b0);
572
              setBit(index2,b1);
573
              setBit(index3,b2);
574
              setBit(index4,b3);
575
              break;
576
      case 2: setBit(index0,b3);
577
              setBit(index1,b4);
578
              setBit(index2,b0);
579
              setBit(index3,b1);
580
              setBit(index4,b2);
581
              break;
582
      case 3: setBit(index0,b2);
583
              setBit(index1,b3);
584
              setBit(index2,b4);
585
              setBit(index3,b0);
586
              setBit(index4,b1);
587
              break;
588
      case 4: setBit(index0,b1);
589
              setBit(index1,b2);
590
              setBit(index2,b3);
591
              setBit(index3,b4);
592
              setBit(index4,b0);
593
              break;
594
    }
595
  }
596

    
597
///////////////////////////////////////////////////////////////////////////////////////////////////
598

    
599
  private void prepareCubitTouchCuboid()
600
    {
601
    int numCenters = mLayer[0]*mLayer[1]*mLayer[2];
602
    if( mLayer[0]>1 && mLayer[1]>1 && mLayer[2]>1 ) numCenters -= (mLayer[0]-2)*(mLayer[1]-2)*(mLayer[2]-2);
603

    
604
    float[][] centers = new float[numCenters][];
605
    int index = 0;
606

    
607
    for(int i=0; i<mLayer[0]; i++)
608
      for(int j=0; j<mLayer[1]; j++)
609
        for(int k=0; k<mLayer[2]; k++)
610
          if( (i==0) || (i==mLayer[0]-1) || (j==0) || (j==mLayer[1]-1) || (k==0) || (k==mLayer[2]-1) )
611
            {
612
            centers[index++] = new float[] { i+0.5f*(1-mLayer[0]), j+0.5f*(1-mLayer[1]), k+0.5f*(1-mLayer[2]) };
613
            }
614

    
615
    ArrayList<float[]> mTouch = new ArrayList<>();
616

    
617
    for(int i=0; i<numCenters; i++)
618
      for(int j=i+1; j<numCenters; j++)
619
        {
620
        float[] c0 = centers[i];
621
        float[] c1 = centers[j];
622

    
623
        float x1 = c0[0];
624
        float y1 = c0[1];
625
        float z1 = c0[2];
626
        float x2 = c1[0];
627
        float y2 = c1[1];
628
        float z2 = c1[2];
629

    
630
        if( areNeighboursCuboid(x1-x2,y1-y2,z1-z2) )
631
          {
632
          float xc = (x1+x2)/2;
633
          float yc = (y1+y2)/2;
634
          float zc = (z1+z2)/2;
635

    
636
          float[] touch = new float[] {xc,yc,zc};
637
          mTouch.add(touch);
638
          }
639
        }
640

    
641
    mNumCubitTouches = mTouch.size();
642
    mCubitTouch = new float[mNumCubitTouches][];
643
    for(int i=0; i<mNumCubitTouches; i++) mCubitTouch[i] = mTouch.remove(0);
644

    
645
    // now sort the touches so that the order agrees with 'Andreas signature' as defined here:
646
    // https://twistypuzzles.com/forum/viewtopic.php?p=415466#p415466
647
    // i.e. we need to sort by Y first (increasing) then by Z (decreasing) then by X (decreasing)
648
    // i.e. we need to sort by 100Y-10Z-X (increasing)
649

    
650
    for(int i=0; i<mNumCubitTouches; i++)
651
      {
652
      float[] ci = mCubitTouch[i];
653
      float val_i = 100*ci[1]-10*ci[2]-ci[0];
654

    
655
      for(int j=i+1; j<mNumCubitTouches; j++)
656
        {
657
        float[] cj = mCubitTouch[j];
658
        float val_j = 100*cj[1]-10*cj[2]-cj[0];
659

    
660
        if( val_j<val_i )
661
          {
662
          mCubitTouch[i] = cj;
663
          mCubitTouch[j] = ci;
664
          val_i = val_j;
665
          ci = cj;
666
          }
667
        }
668
      }
669
    }
670

    
671
///////////////////////////////////////////////////////////////////////////////////////////////////
672

    
673
  private void prepareTouchRowsCuboid()
674
    {
675
    mTouchRows = new int[3][mNumCubitTouches];
676

    
677
    for(int i=0; i<mNumCubitTouches; i++)
678
      {
679
      float[] touch = mCubitTouch[i];
680

    
681
      for(int a=0; a<3; a++)
682
        {
683
        int l = (int)(2*touch[a] + mLayer[a] + 0.01f);
684
        mTouchRows[a][i] = ( (l%2)==0 ) ? l/2 : -1;
685
        }
686
      }
687
    }
688

    
689
///////////////////////////////////////////////////////////////////////////////////////////////////
690

    
691
  private void prepareAllCyclesCuboid()
692
    {
693
    ArrayList<float[][]> cycles0 = new ArrayList<>();
694
    ArrayList<float[][]> cycles1 = new ArrayList<>();
695
    ArrayList<float[][]> cycles2 = new ArrayList<>();
696

    
697
    mNumLeftCyclesPerLayer = new int[3];
698
    mNumCentCyclesPerLayer = new int[3];
699
    mNumInneCyclesPerLayer = new int[3];
700

    
701
    if( mLayer[1]==mLayer[2] ) generate4Cycles(cycles0,0);
702
    else                       generate2Cycles(cycles0,0);
703
    if( mLayer[0]==mLayer[2] ) generate4Cycles(cycles1,1);
704
    else                       generate2Cycles(cycles1,1);
705
    if( mLayer[0]==mLayer[1] ) generate4Cycles(cycles2,2);
706
    else                       generate2Cycles(cycles2,2);
707

    
708
    mCycles = new int[3][][][];
709

    
710
    mCycles[0] = fillUpCyclesCuboid(cycles0,0,mLayer[0]);
711
    mCycles[1] = fillUpCyclesCuboid(cycles1,1,mLayer[1]);
712
    mCycles[2] = fillUpCyclesCuboid(cycles2,2,mLayer[2]);
713
    }
714

    
715
///////////////////////////////////////////////////////////////////////////////////////////////////
716

    
717
  private void generate4Cycles(ArrayList<float[][]> cycles, int axis)
718
    {
719
    for(int i=0; i<mNumCubitTouches; i++)
720
      {
721
      int i0 = rotateIndex4(axis,i);
722
      if( i0<=i ) continue;
723
      int i1 = rotateIndex4(axis,i0);
724
      if( i1<=i ) continue;
725
      int i2 = rotateIndex4(axis,i1);
726
      if( i2<=i ) continue;
727

    
728
      float[] f0 = getCubitTouchOfIndex(i);
729
      float[] f1 = getCubitTouchOfIndex(i0);
730
      float[] f2 = getCubitTouchOfIndex(i1);
731
      float[] f3 = getCubitTouchOfIndex(i2);
732

    
733
      int l = (int)(2*f0[axis]+mLayer[axis]);
734

    
735
      if( l==2 ) mNumLeftCyclesPerLayer[axis]++;
736
      if( l==1 ) mNumCentCyclesPerLayer[axis]++;
737
      if( mLayer[axis]>2 && l==3 ) mNumInneCyclesPerLayer[axis]++;
738

    
739
      float[][] cycle = new float[][] { f0,f1,f2,f3 };
740
      cycles.add(cycle);
741
      }
742
    }
743

    
744
///////////////////////////////////////////////////////////////////////////////////////////////////
745

    
746
  private void generate2Cycles(ArrayList<float[][]> cycles, int axis)
747
    {
748
    for(int i=0; i<mNumCubitTouches; i++)
749
      {
750
      int i0 = rotateIndex2(axis,i);
751
      if( i0<=i ) continue;
752

    
753
      float[] f0 = getCubitTouchOfIndex(i);
754
      float[] f1 = getCubitTouchOfIndex(i0);
755

    
756
      int l = (int)(2*f0[axis]+mLayer[axis]);
757

    
758
      if( l==2 ) mNumLeftCyclesPerLayer[axis]++;
759
      if( l==1 ) mNumCentCyclesPerLayer[axis]++;
760
      if( mLayer[axis]>2 && l==3 ) mNumInneCyclesPerLayer[axis]++;
761

    
762
      float[][] cycle = new float[][] { f0,f1 };
763
      cycles.add(cycle);
764
      }
765
    }
766

    
767
///////////////////////////////////////////////////////////////////////////////////////////////////
768

    
769
  private int[][][] fillUpCyclesCuboid(ArrayList<float[][]> cyc, int axis, int numLayers)
770
    {
771
    int numCycles = cyc.size();
772
    int[] index = new int[numLayers];
773

    
774
    int numFirst = mNumCentCyclesPerLayer[axis];
775
    int numNext  = mNumLeftCyclesPerLayer[axis] + mNumInneCyclesPerLayer[axis];
776
    int numLast  = mNumLeftCyclesPerLayer[axis] + numFirst;
777

    
778
    int[][][] ret = new int[numLayers][][];
779
    ret[          0] = new int[numFirst][];
780
    ret[numLayers-1] = new int[numLast][];
781

    
782
    for(int i=1; i<numLayers-1; i++) ret[i] = new int[numNext][];
783

    
784
    for(int i=0; i<numCycles; i++)
785
      {
786
      float[][] cycle = cyc.remove(0);
787
      int layer = (int)(cycle[0][axis]+numLayers*0.5f + 0.01f);
788
      int i0 = getIndexOfCubitTouch(cycle[0][0],cycle[0][1],cycle[0][2]);
789
      int i1 = getIndexOfCubitTouch(cycle[1][0],cycle[1][1],cycle[1][2]);
790

    
791
      if( cycle.length==4 )
792
        {
793
        int i2 = getIndexOfCubitTouch(cycle[2][0],cycle[2][1],cycle[2][2]);
794
        int i3 = getIndexOfCubitTouch(cycle[3][0],cycle[3][1],cycle[3][2]);
795
        ret[layer][index[layer]] = new int[] {i0,i1,i2,i3};
796
        }
797
      else
798
        {
799
        ret[layer][index[layer]] = new int[] {i0,i1};
800
        }
801
      index[layer]++;
802
      }
803

    
804
    return ret;
805
    }
806

    
807
///////////////////////////////////////////////////////////////////////////////////////////////////
808

    
809
  private int rotateIndex4(int axis, int index)
810
    {
811
    float[] touch = getCubitTouchOfIndex(index);
812

    
813
    switch(axis)
814
      {
815
      case 0: return getIndexOfCubitTouch(+touch[0],+touch[2],-touch[1]);
816
      case 1: return getIndexOfCubitTouch(-touch[2],+touch[1],+touch[0]);
817
      case 2: return getIndexOfCubitTouch(+touch[1],-touch[0],+touch[2]);
818
      }
819

    
820
    return -1;
821
    }
822

    
823
///////////////////////////////////////////////////////////////////////////////////////////////////
824

    
825
  private int rotateIndex2(int axis, int index)
826
    {
827
    float[] touch = getCubitTouchOfIndex(index);
828

    
829
    switch(axis)
830
      {
831
      case 0: return getIndexOfCubitTouch(+touch[0],-touch[1],-touch[2]);
832
      case 1: return getIndexOfCubitTouch(-touch[0],+touch[1],-touch[2]);
833
      case 2: return getIndexOfCubitTouch(-touch[0],-touch[1],+touch[2]);
834
      }
835

    
836
    return -1;
837
    }
838

    
839
///////////////////////////////////////////////////////////////////////////////////////////////////
840

    
841
  private void prepareCubitTouchPyraminx()
842
    {
843
    float[][][] centers = FactoryBandagedPyraminx.createPositions(mLayer[0]);
844
    float[][] octs = centers[0];
845
    float[][] tets = centers[1];
846

    
847
    ArrayList<float[]> mTouch = new ArrayList<>();
848

    
849
    for(float[] oct : octs)
850
      for(float[] tet : tets)
851
        {
852
        float ox=oct[0];
853
        float oy=oct[1];
854
        float oz=oct[2];
855
        float tx=tet[0];
856
        float ty=tet[1];
857
        float tz=tet[2];
858

    
859
        if( areNeighboursPyraminx(ox-tx, oy-ty, oz-tz) )
860
          {
861
          float xc=(2*tx+ox)/3;
862
          float yc=(2*ty+oy)/3;
863
          float zc=(2*tz+oz)/3;
864

    
865
          float[] touch = new float[] {xc, yc, zc};
866
          mTouch.add(touch);
867
          }
868
        }
869

    
870
    mNumCubitTouches = mTouch.size();
871
    mCubitTouch = new float[mNumCubitTouches][];
872
    for(int i=0; i<mNumCubitTouches; i++) mCubitTouch[i] = mTouch.remove(0);
873
    }
874

    
875
///////////////////////////////////////////////////////////////////////////////////////////////////
876

    
877
  private void prepareTouchRowsPyraminx()
878
    {
879
    mTouchRows = new int[4][mNumCubitTouches];
880
    int num = mLayer[0];
881
    final int N = 10;
882

    
883
    for(int i=0; i<mNumCubitTouches; i++)
884
      {
885
      float[] touch = mCubitTouch[i];
886

    
887
      for(int a=0; a<4; a++)
888
        {
889
        float[] ax = mRotAxisPyraminx[a];
890
        float l = whichLayerPyraminx(touch,ax,num);
891
        int ll = (int)(N*l);
892
        mTouchRows[a][i] = ( (ll%N)==0 ) ? ll/N : -1;
893
        }
894
      }
895
    }
896

    
897
///////////////////////////////////////////////////////////////////////////////////////////////////
898

    
899
  private void prepareAllCyclesPyraminx()
900
    {
901
    ArrayList<float[][]> cycles0 = new ArrayList<>();
902
    ArrayList<float[][]> cycles1 = new ArrayList<>();
903
    ArrayList<float[][]> cycles2 = new ArrayList<>();
904
    ArrayList<float[][]> cycles3 = new ArrayList<>();
905

    
906
    generate3CyclesPyraminx(cycles0,0);
907
    generate3CyclesPyraminx(cycles1,1);
908
    generate3CyclesPyraminx(cycles2,2);
909
    generate3CyclesPyraminx(cycles3,3);
910

    
911
    mCycles = new int[4][][][];
912

    
913
    int numLayers = mLayer[0];
914
    mCycles[0] = fillUpCyclesPyraminx(cycles0,0,numLayers);
915
    mCycles[1] = fillUpCyclesPyraminx(cycles1,1,numLayers);
916
    mCycles[2] = fillUpCyclesPyraminx(cycles2,2,numLayers);
917
    mCycles[3] = fillUpCyclesPyraminx(cycles3,3,numLayers);
918
    }
919

    
920
///////////////////////////////////////////////////////////////////////////////////////////////////
921

    
922
  private void generate3CyclesPyraminx(ArrayList<float[][]> cycles, int ax)
923
    {
924
    for(int i=0; i<mNumCubitTouches; i++)
925
      {
926
      int i0 = rotateIndex3(ax,i);
927
      if( i0<=i ) continue;
928
      int i1 = rotateIndex3(ax,i0);
929
      if( i1<=i ) continue;
930

    
931
      float[] f0 = getCubitTouchOfIndex(i);
932
      float[] f1 = getCubitTouchOfIndex(i0);
933
      float[] f2 = getCubitTouchOfIndex(i1);
934

    
935
      float[][] cycle = new float[][] { f0,f1,f2 };
936
      cycles.add(cycle);
937
      }
938
    }
939

    
940
///////////////////////////////////////////////////////////////////////////////////////////////////
941

    
942
  private int[][][] fillUpCyclesPyraminx(ArrayList<float[][]> cyc, int axis, int numLayers)
943
    {
944
    int numCycles = cyc.size();
945
    int[] index = new int[numLayers];
946
    int[] numC = new int[numLayers];
947
    float[] ax = mRotAxisPyraminx[axis];
948

    
949
    for(int i=0; i<numCycles; i++)
950
      {
951
      float[][] cycle = cyc.get(i);
952
      int layer = (int)whichLayerPyraminx(cycle[0],ax,numLayers);
953
      numC[layer]++;
954
      }
955

    
956
    int[][][] ret = new int[numLayers][][];
957
    for(int i=0; i<numLayers; i++) ret[i] = new int[numC[i]][];
958

    
959
    for(int i=0; i<numCycles; i++)
960
      {
961
      float[][] cycle = cyc.remove(0);
962
      int layer = (int)whichLayerPyraminx(cycle[0],ax,numLayers);
963

    
964
      int i0 = getIndexOfCubitTouch(cycle[0][0],cycle[0][1],cycle[0][2]);
965
      int i1 = getIndexOfCubitTouch(cycle[1][0],cycle[1][1],cycle[1][2]);
966
      int i2 = getIndexOfCubitTouch(cycle[2][0],cycle[2][1],cycle[2][2]);
967

    
968
      ret[layer][index[layer]] = new int[] {i0,i1,i2};
969
      index[layer]++;
970
      }
971

    
972
    return ret;
973
    }
974

    
975
///////////////////////////////////////////////////////////////////////////////////////////////////
976

    
977
  private float whichLayerPyraminx(float[] point, float[] ax, int numLayers)
978
    {
979
    float d = point[0]*ax[0] + point[1]*ax[1] + point[2]*ax[2];
980
    float r = (SQ6/2)*d + numLayers*0.25f + 0.001f;
981
    return r>=numLayers ? numLayers-0.001f : r;
982
    }
983

    
984
///////////////////////////////////////////////////////////////////////////////////////////////////
985

    
986
  private int rotateIndex3(int ax, int index)
987
    {
988
    float[] touch = getCubitTouchOfIndex(index);
989
    QuatHelper.rotateVectorByQuat(mTmp, touch[0], touch[1], touch[2], 1.0f, mQuatsPyraminx[ax]);
990
    return getIndexOfCubitTouch(mTmp[0],mTmp[1],mTmp[2]);
991
    }
992

    
993
///////////////////////////////////////////////////////////////////////////////////////////////////
994

    
995
  private float[] getPosition(int index, float[][][] centers, int len)
996
    {
997
    int num = 0, i1=0, i2=0;
998

    
999
    for(int i=0; i<len; i++)
1000
      {
1001
      int t = centers[i].length;
1002

    
1003
      if( t > index-num )
1004
        {
1005
        i1 = i;
1006
        i2 = index-num;
1007
        break;
1008
        }
1009
      else
1010
        {
1011
        num += t;
1012
        }
1013
      }
1014

    
1015
    return centers[i1][i2];
1016
    }
1017

    
1018
///////////////////////////////////////////////////////////////////////////////////////////////////
1019

    
1020
  private void prepareCubitTouchMegaminx()
1021
    {
1022
    FactoryBandagedMegaminx factory = FactoryBandagedMegaminx.getInstance();
1023
    float[][][] centers = factory.getPositions(mFactoryLayer);
1024
    int size = mFactoryLayer[0];
1025
    float scale = 0.0f;
1026

    
1027
    switch(size)
1028
      {
1029
      case 2: scale = 1.50f; break;
1030
      case 3: scale = 1.00f; break;
1031
      case 4: scale = 1.25f; break;
1032
      case 5: scale = 1.00f; break;
1033
      }
1034

    
1035
    int numCubits=0;
1036
    int numVariants = centers.length;
1037
    for(float[][] center : centers) numCubits += center.length;
1038

    
1039
    ArrayList<float[]> mTouch = new ArrayList<>();
1040

    
1041
    for(int i=0; i<numCubits; i++)
1042
      {
1043
      float[] first = getPosition(i,centers,numVariants);
1044

    
1045
      for(int j = i+1; j<numCubits; j++)
1046
        {
1047
        float[] second = getPosition(j,centers,numVariants);
1048

    
1049
        float ox = scale*first[0];
1050
        float oy = scale*first[1];
1051
        float oz = scale*first[2];
1052
        float tx = scale*second[0];
1053
        float ty = scale*second[1];
1054
        float tz = scale*second[2];
1055

    
1056
        if( areNeighboursMegaminx(size, ox-tx, oy-ty, oz-tz) )
1057
          {
1058
          float xc = (tx+ox)/2;  // TODO; wrong
1059
          float yc = (ty+oy)/2;
1060
          float zc = (tz+oz)/2;
1061

    
1062
          float[] touch = new float[] {xc, yc, zc};
1063
          mTouch.add(touch);
1064
          }
1065
        }
1066
      }
1067

    
1068
    mNumCubitTouches = mTouch.size();
1069
    mCubitTouch = new float[mNumCubitTouches][];
1070
    for(int i=0; i<mNumCubitTouches; i++) mCubitTouch[i] = mTouch.remove(0);
1071
    }
1072

    
1073
///////////////////////////////////////////////////////////////////////////////////////////////////
1074

    
1075
  private void prepareTouchRowsMegaminx()
1076
    {
1077
    mTouchRows = new int[6][mNumCubitTouches];
1078
    int num = mFactoryLayer[0];
1079
    final int N = 10;
1080

    
1081
    for(int i=0; i<mNumCubitTouches; i++)
1082
      {
1083
      float[] touch = mCubitTouch[i];
1084

    
1085
      for(int a=0; a<6; a++)
1086
        {
1087
        float[] ax = mRotAxisMegaminx[a];
1088
        float l = whichLayerMegaminx(touch,ax,num);
1089
        int ll = (int)(N*l);
1090
        mTouchRows[a][i] = ( (ll%N)==0 ) ? ll/N : -1;
1091
        }
1092
      }
1093
    }
1094

    
1095
///////////////////////////////////////////////////////////////////////////////////////////////////
1096

    
1097
  private void prepareAllCyclesMegaminx()
1098
    {
1099
    ArrayList<float[][]> cycles0 = new ArrayList<>();
1100
    ArrayList<float[][]> cycles1 = new ArrayList<>();
1101
    ArrayList<float[][]> cycles2 = new ArrayList<>();
1102
    ArrayList<float[][]> cycles3 = new ArrayList<>();
1103
    ArrayList<float[][]> cycles4 = new ArrayList<>();
1104
    ArrayList<float[][]> cycles5 = new ArrayList<>();
1105

    
1106
    generate5CyclesMegaminx(cycles0,0);
1107
    generate5CyclesMegaminx(cycles1,1);
1108
    generate5CyclesMegaminx(cycles2,2);
1109
    generate5CyclesMegaminx(cycles3,3);
1110
    generate5CyclesMegaminx(cycles4,4);
1111
    generate5CyclesMegaminx(cycles5,5);
1112

    
1113
    mCycles = new int[6][][][];
1114

    
1115
    int param = mFactoryLayer[0];
1116
    int numLayers = mLayer[0];
1117
    mCycles[0] = fillUpCyclesMegaminx(cycles0,0,numLayers,param);
1118
    mCycles[1] = fillUpCyclesMegaminx(cycles1,1,numLayers,param);
1119
    mCycles[2] = fillUpCyclesMegaminx(cycles2,2,numLayers,param);
1120
    mCycles[3] = fillUpCyclesMegaminx(cycles3,3,numLayers,param);
1121
    mCycles[4] = fillUpCyclesMegaminx(cycles4,4,numLayers,param);
1122
    mCycles[5] = fillUpCyclesMegaminx(cycles5,5,numLayers,param);
1123
    }
1124

    
1125
///////////////////////////////////////////////////////////////////////////////////////////////////
1126

    
1127
  private void generate5CyclesMegaminx(ArrayList<float[][]> cycles, int ax)
1128
    {
1129
    for(int i=0; i<mNumCubitTouches; i++)
1130
      {
1131
      int i0 = rotateIndex5(ax,i);
1132
      if( i0<=i ) continue;
1133
      int i1 = rotateIndex5(ax,i0);
1134
      if( i1<=i ) continue;
1135
      int i2 = rotateIndex5(ax,i1);
1136
      if( i2<=i ) continue;
1137
      int i3 = rotateIndex5(ax,i2);
1138
      if( i3<=i ) continue;
1139

    
1140
      float[] f0 = getCubitTouchOfIndex(i);
1141
      float[] f1 = getCubitTouchOfIndex(i0);
1142
      float[] f2 = getCubitTouchOfIndex(i1);
1143
      float[] f3 = getCubitTouchOfIndex(i2);
1144
      float[] f4 = getCubitTouchOfIndex(i3);
1145

    
1146
      float[][] cycle = new float[][] { f0,f1,f2,f3,f4 };
1147
      cycles.add(cycle);
1148
      }
1149
    }
1150

    
1151
///////////////////////////////////////////////////////////////////////////////////////////////////
1152
// param 2 3 4 5
1153
// numL  3 3 5 5
1154

    
1155
  private int[][][] fillUpCyclesMegaminx(ArrayList<float[][]> cyc, int axis, int numL, int param)
1156
    {
1157
    int numCycles = cyc.size();
1158
    int[] index = new int[numL];
1159
    int[] numC = new int[numL];
1160
    float[] ax = mRotAxisMegaminx[axis];
1161

    
1162
    for(int i=0; i<numCycles; i++)
1163
      {
1164
      float[][] cycle = cyc.get(i);
1165
      int layer = (int)whichLayerMegaminx(cycle[0],ax,param);
1166
      numC[layer]++;
1167
      }
1168

    
1169
    int[][][] ret = new int[numL][][];
1170
    for(int i=0; i<numL; i++) ret[i] = new int[numC[i]][];
1171

    
1172
    for(int i=0; i<numCycles; i++)
1173
      {
1174
      float[][] cycle = cyc.remove(0);
1175
      int layer = (int)whichLayerMegaminx(cycle[0],ax,param);
1176

    
1177
      int i0 = getIndexOfCubitTouch(cycle[0][0],cycle[0][1],cycle[0][2]);
1178
      int i1 = getIndexOfCubitTouch(cycle[1][0],cycle[1][1],cycle[1][2]);
1179
      int i2 = getIndexOfCubitTouch(cycle[2][0],cycle[2][1],cycle[2][2]);
1180
      int i3 = getIndexOfCubitTouch(cycle[3][0],cycle[3][1],cycle[3][2]);
1181
      int i4 = getIndexOfCubitTouch(cycle[4][0],cycle[4][1],cycle[4][2]);
1182

    
1183
      ret[layer][index[layer]] = new int[] {i0,i1,i2,i3,i4};
1184
      index[layer]++;
1185
      }
1186

    
1187
    return ret;
1188
    }
1189

    
1190
///////////////////////////////////////////////////////////////////////////////////////////////////
1191

    
1192
  private float whichLayerMegaminx(float[] point, float[] ax, int numLayers)
1193
    {
1194
    float d = point[0]*ax[0] + point[1]*ax[1] + point[2]*ax[2];
1195
    float C = 0.85f;
1196

    
1197
    switch(numLayers)
1198
      {
1199
      case 2: return (d*LEN)/(6*C2*SIN54) + 1.5f;
1200
      case 3: float D3 = 3*TouchControlDodecahedron.DIST3D;
1201
              float X3 = 2*D3/(2+SIN18);
1202
              float G3 = X3*(0.5f-MEGA_D);
1203
              float cut3 = -D3 + C*G3;
1204
              return d<-cut3 ? 0 : d<cut3 ? 1:2;
1205
      case 4: float D4 = 5*TouchControlDodecahedron.DIST3D;
1206
              float X4 = 2*D4/(2+SIN18);
1207
              float G4 = X4*0.25f;
1208
              float cut41 = -D4 + C*G4;
1209
              float cut42 = -D4 + (1+C)*G4;
1210
              return d<-cut41 ? 0 : d<-cut42 ? 1: d<cut42 ? 2: d<cut41 ? 3:4;
1211
      case 5: float D5 = 5*TouchControlDodecahedron.DIST3D;
1212
              float X5 = 2*D5/(2+SIN18);
1213
              float G5 = X5*(0.5f-MEGA_D)/2;
1214
              float cut51 = -D5 + C*G5;
1215
              float cut52 = -D5 + (1+C)*G5;
1216
              return d<-cut51 ? 0 : d<-cut52 ? 1: d<cut52 ? 2: d<cut51 ? 3:4;
1217
      }
1218

    
1219
    return 0;
1220
    }
1221

    
1222
///////////////////////////////////////////////////////////////////////////////////////////////////
1223

    
1224
  private int rotateIndex5(int ax, int index)
1225
    {
1226
    float[] touch = getCubitTouchOfIndex(index);
1227
    QuatHelper.rotateVectorByQuat(mTmp, touch[0], touch[1], touch[2], 1.0f, mQuatsMegaminx[ax]);
1228
    return getIndexOfCubitTouch(mTmp[0],mTmp[1],mTmp[2]);
1229
    }
1230

    
1231
///////////////////////////////////////////////////////////////////////////////////////////////////
1232

    
1233
  private int getIndexOfCubitTouch(float x, float y, float z)
1234
    {
1235
    for(int i=0; i<mNumCubitTouches; i++)
1236
      {
1237
      float[] touch = mCubitTouch[i];
1238

    
1239
      float dx = touch[0] - x;
1240
      float dy = touch[1] - y;
1241
      float dz = touch[2] - z;
1242

    
1243
      if( dx*dx + dy*dy + dz*dz < 0.01f ) return i;
1244
      }
1245

    
1246
    return -1;
1247
    }
1248

    
1249
///////////////////////////////////////////////////////////////////////////////////////////////////
1250

    
1251
  private float[] getCubitTouchOfIndex(int index)
1252
    {
1253
    return mCubitTouch[index];
1254
    }
1255

    
1256
///////////////////////////////////////////////////////////////////////////////////////////////////
1257

    
1258
  private boolean areNeighboursCuboid(float dx, float dy, float dz)
1259
    {
1260
    return dx*dx+dy*dy+dz*dz < 1.01f;
1261
    }
1262

    
1263
///////////////////////////////////////////////////////////////////////////////////////////////////
1264

    
1265
  private boolean areNeighboursPyraminx(float dx, float dy, float dz)
1266
    {
1267
    return dx*dx+dy*dy+dz*dz < SQ6/4 + 0.01f;
1268
    }
1269

    
1270
///////////////////////////////////////////////////////////////////////////////////////////////////
1271

    
1272
  private boolean areNeighboursMegaminx(int size, float dx, float dy, float dz)
1273
    {
1274
    float fact = size==2 ? 1.5f : (size==4 ? 1.25f : 1.0f);
1275

    
1276
    dx /= fact;
1277
    dy /= fact;
1278
    dz /= fact;
1279

    
1280
    return BandagedObjectMegaminx.isAdjacent(size,dx,dy,dz);
1281
    }
1282

    
1283
///////////////////////////////////////////////////////////////////////////////////////////////////
1284

    
1285
  private long getBit(int index)
1286
    {
1287
    int sigIndex = SIZE-1-(index/64);
1288
    return (mSignature[sigIndex]>>(index%64))&0x1;
1289
    }
1290

    
1291
///////////////////////////////////////////////////////////////////////////////////////////////////
1292

    
1293
  private void setBit(int index, long bit)
1294
    {
1295
    long diff    = (1L<<(index%64));
1296
    int sigIndex = SIZE-1-(index/64);
1297
    if( bit!=0 ) mSignature[sigIndex] |= diff;
1298
    else         mSignature[sigIndex] &=~diff;
1299
    }
1300
}
(8-8/13)