Project

General

Profile

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

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

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.objects.TwistyBandagedMegaminx;
34
import org.distorted.objectlib.objects.TwistyBandagedPyraminx;
35
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38

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

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

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

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

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

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

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

    
98
// Gigaminx has 540 such places (so more if N<=7)
99

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

    
106
    return Math.max(ret,giga);
107
    }
108

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

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

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

    
124
///////////////////////////////////////////////////////////////////////////////////////////////////
125

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

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

    
141
    mNumCubitTouches       = sig.mNumCubitTouches;
142
    mNumCentCyclesPerLayer = sig.mNumCentCyclesPerLayer;
143
    mNumLeftCyclesPerLayer = sig.mNumLeftCyclesPerLayer;
144
    mNumInneCyclesPerLayer = sig.mNumInneCyclesPerLayer;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148
// built-in objects; objects created from JSON (version1)
149

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

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

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

    
165
    char name = shortName.charAt(0);
166

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

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

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

    
191
      mLayer=new int[] {x,x,x,x,x,x};
192
      mFactoryLayer=new int[] {y,y,y,y,y,y};
193

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

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211
// BAN*** objects when read from JSON
212

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

    
217
    mLayer = new int[] {size,size,size};
218

    
219
    prepareCubitTouchCuboid();
220
    prepareTouchRowsCuboid();
221
    prepareAllCyclesCuboid();
222
    }
223

    
224
///////////////////////////////////////////////////////////////////////////////////////////////////
225
// other objects created from JSON (version2)
226

    
227
  public ObjectSignature(long[] signature)
228
    {
229
    setUpSignature(signature);
230
    }
231

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

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

    
242
    prepareCubitTouchCuboid();
243

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

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

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

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

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

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275
// Locally created bandaged pyraminxes 1<=N<=7
276

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

    
283
    prepareCubitTouchPyraminx();
284

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

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

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

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

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

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

    
327
///////////////////////////////////////////////////////////////////////////////////////////////////
328
// Locally created bandaged megaminxes size 2<=N<=5
329

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

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

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

    
347
    prepareCubitTouchMegaminx();
348

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

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

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

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

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

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380

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

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388

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

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

    
399
    return 0;
400
    }
401

    
402
///////////////////////////////////////////////////////////////////////////////////////////////////
403

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

    
411
    return true;
412
    }
413

    
414
///////////////////////////////////////////////////////////////////////////////////////////////////
415

    
416
  public long[] getArray()
417
    {
418
    return mSignature;
419
    }
420

    
421
///////////////////////////////////////////////////////////////////////////////////////////////////
422

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

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

    
436
      mName = sb.toString();
437
      }
438

    
439
    return mName;
440
    }
441

    
442
///////////////////////////////////////////////////////////////////////////////////////////////////
443

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

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

    
454
    return true;
455
    }
456

    
457
///////////////////////////////////////////////////////////////////////////////////////////////////
458

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

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

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

    
478
    return ret;
479
    }
480

    
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482

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

    
488
    long b0 = getBit(index0);
489
    long b1 = getBit(index1);
490

    
491
    setBit(index1,b0);
492
    setBit(index0,b1);
493
    }
494

    
495
///////////////////////////////////////////////////////////////////////////////////////////////////
496

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

    
503
    long b0 = getBit(index0);
504
    long b1 = getBit(index1);
505
    long b2 = getBit(index2);
506

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

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

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

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

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

    
554
///////////////////////////////////////////////////////////////////////////////////////////////////
555

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

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

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

    
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600

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

    
606
    float[][] centers = new float[numCenters][];
607
    int index = 0;
608

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

    
617
    ArrayList<float[]> mTouch = new ArrayList<>();
618

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

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

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

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

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

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

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

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

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

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

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

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

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

    
691
///////////////////////////////////////////////////////////////////////////////////////////////////
692

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

    
699
    mNumLeftCyclesPerLayer = new int[3];
700
    mNumCentCyclesPerLayer = new int[3];
701
    mNumInneCyclesPerLayer = new int[3];
702

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

    
710
    mCycles = new int[3][][][];
711

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

    
717
///////////////////////////////////////////////////////////////////////////////////////////////////
718

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

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

    
735
      int l = (int)(2*f0[axis]+mLayer[axis]);
736

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

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

    
746
///////////////////////////////////////////////////////////////////////////////////////////////////
747

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

    
755
      float[] f0 = getCubitTouchOfIndex(i);
756
      float[] f1 = getCubitTouchOfIndex(i0);
757

    
758
      int l = (int)(2*f0[axis]+mLayer[axis]);
759

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

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

    
769
///////////////////////////////////////////////////////////////////////////////////////////////////
770

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

    
776
    int numFirst = mNumCentCyclesPerLayer[axis];
777
    int numNext  = mNumLeftCyclesPerLayer[axis] + mNumInneCyclesPerLayer[axis];
778
    int numLast  = mNumLeftCyclesPerLayer[axis] + numFirst;
779

    
780
    int[][][] ret = new int[numLayers][][];
781
    ret[          0] = new int[numFirst][];
782
    ret[numLayers-1] = new int[numLast][];
783

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

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

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

    
806
    return ret;
807
    }
808

    
809
///////////////////////////////////////////////////////////////////////////////////////////////////
810

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

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

    
822
    return -1;
823
    }
824

    
825
///////////////////////////////////////////////////////////////////////////////////////////////////
826

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

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

    
838
    return -1;
839
    }
840

    
841
///////////////////////////////////////////////////////////////////////////////////////////////////
842

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

    
849
    ArrayList<float[]> mTouch = new ArrayList<>();
850

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

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

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

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

    
877
///////////////////////////////////////////////////////////////////////////////////////////////////
878

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

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

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

    
899
///////////////////////////////////////////////////////////////////////////////////////////////////
900

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

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

    
913
    mCycles = new int[4][][][];
914

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

    
922
///////////////////////////////////////////////////////////////////////////////////////////////////
923

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

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

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

    
942
///////////////////////////////////////////////////////////////////////////////////////////////////
943

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

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

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

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

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

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

    
974
    return ret;
975
    }
976

    
977
///////////////////////////////////////////////////////////////////////////////////////////////////
978

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

    
986
///////////////////////////////////////////////////////////////////////////////////////////////////
987

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

    
995
///////////////////////////////////////////////////////////////////////////////////////////////////
996

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

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

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

    
1017
    return centers[i1][i2];
1018
    }
1019

    
1020
///////////////////////////////////////////////////////////////////////////////////////////////////
1021

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

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

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

    
1041
    ArrayList<float[]> mTouch = new ArrayList<>();
1042

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

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

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

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

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

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

    
1075
///////////////////////////////////////////////////////////////////////////////////////////////////
1076

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

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

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

    
1097
///////////////////////////////////////////////////////////////////////////////////////////////////
1098

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

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

    
1115
    mCycles = new int[6][][][];
1116

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

    
1127
///////////////////////////////////////////////////////////////////////////////////////////////////
1128

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

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

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

    
1153
///////////////////////////////////////////////////////////////////////////////////////////////////
1154
// param 2 3 4 5
1155
// numL  3 3 5 5
1156

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

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

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

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

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

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

    
1189
    return ret;
1190
    }
1191

    
1192
///////////////////////////////////////////////////////////////////////////////////////////////////
1193

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

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

    
1221
    return 0;
1222
    }
1223

    
1224
///////////////////////////////////////////////////////////////////////////////////////////////////
1225

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

    
1233
///////////////////////////////////////////////////////////////////////////////////////////////////
1234

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

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

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

    
1248
    return -1;
1249
    }
1250

    
1251
///////////////////////////////////////////////////////////////////////////////////////////////////
1252

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

    
1258
///////////////////////////////////////////////////////////////////////////////////////////////////
1259

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

    
1265
///////////////////////////////////////////////////////////////////////////////////////////////////
1266

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

    
1272
///////////////////////////////////////////////////////////////////////////////////////////////////
1273

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

    
1278
    dx /= fact;
1279
    dy /= fact;
1280
    dz /= fact;
1281

    
1282
    return BandagedObjectMegaminx.isAdjacent(size,dx,dy,dz);
1283
    }
1284

    
1285
///////////////////////////////////////////////////////////////////////////////////////////////////
1286

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

    
1293
///////////////////////////////////////////////////////////////////////////////////////////////////
1294

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