Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / signature / ObjectSignatureMegaminx.java @ 6777e712

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.signature;
11

    
12
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.MEGA_D;
13
import static org.distorted.objectlib.bandaged.BandagedObjectMegaminx.SIN18;
14
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.KILOMINX3;
15
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.KILOMINX5;
16
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.MEGAMINX3;
17
import static org.distorted.objectlib.objects.TwistyBandagedMegaminx.MEGAMINX5;
18
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
19
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.COS54;
20
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
21
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
22

    
23
import org.distorted.library.helpers.QuatHelper;
24
import org.distorted.objectlib.bandaged.BandagedObjectMegaminx;
25
import org.distorted.objectlib.bandaged.FactoryBandagedMegaminx;
26
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
27

    
28
import java.util.ArrayList;
29

    
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

    
32
public class ObjectSignatureMegaminx extends ObjectSignature
33
{
34
  private static final float[][] ROT_AXIS =
35
        {
36
                {    C2/LEN, SIN54/LEN,    0      },
37
                {   -C2/LEN, SIN54/LEN,    0      },
38
                { 0        ,    C2/LEN, SIN54/LEN },
39
                { 0        ,   -C2/LEN, SIN54/LEN },
40
                { SIN54/LEN,    0     ,    C2/LEN },
41
                { SIN54/LEN,    0     ,   -C2/LEN }
42
        };
43

    
44
  private static final float[][] QUATS =
45
        {
46
                {  COS54*   C2/LEN, COS54*SIN54/LEN, 0              , SIN54 },
47
                { -COS54*   C2/LEN, COS54*SIN54/LEN, 0              , SIN54 },
48
                {  0              , COS54*   C2/LEN, COS54*SIN54/LEN, SIN54 },
49
                {  0              ,-COS54*   C2/LEN, COS54*SIN54/LEN, SIN54 },
50
                {  COS54*SIN54/LEN, 0              , COS54*   C2/LEN, SIN54 },
51
                {  COS54*SIN54/LEN, 0              ,-COS54*   C2/LEN, SIN54 }
52
        };
53

    
54
///////////////////////////////////////////////////////////////////////////////////////////////////
55
// Bandaged Megaminx objects when read from JSON
56

    
57
  public ObjectSignatureMegaminx(int x, long[] signature)
58
    {
59
    super(signature);
60

    
61
    mTmp = new float[4];
62
    mParam=x;
63
    int z=-1, y=-1;
64

    
65
    switch(mParam)
66
      {
67
      case 2: z=3; y=2; break;
68
      case 3: z=3; y=3; break;
69
      case 4: z=5; y=4; break;
70
      case 5: z=5; y=5; break;
71
      }
72

    
73
    mLayer=new int[] {z,z,z,z,z,z};
74
    mFactoryLayer=new int[] {y,y,y,y,y,y};
75

    
76
    prepareCubitTouch();
77
    prepareTouchRows();
78
    prepareAllCycles();
79
    }
80

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82
// Locally created bandaged megaminxes size 2<=N<=5
83

    
84
  public ObjectSignatureMegaminx(int x, float[][] position)
85
    {
86
    int y=-1;
87

    
88
    switch(x)
89
      {
90
      case KILOMINX3: y=3; mParam=2; break;
91
      case MEGAMINX3: y=3; mParam=3; break;
92
      case KILOMINX5: y=5; mParam=4; break;
93
      case MEGAMINX5: y=5; mParam=5; break;
94
      }
95

    
96
    mLayer=new int[] {y,y,y,y,y,y};
97
    mFactoryLayer=new int[] {mParam,mParam,mParam,mParam,mParam,mParam};
98
    mSignature = new long[SIZE];
99
    mTmp = new float[4];
100

    
101
    prepareCubitTouch();
102

    
103
    for(float[] pos : position)
104
      {
105
      int numCenters = pos.length/3;
106

    
107
      for(int i=0; i<numCenters; i++)
108
        {
109
        float xi = pos[3*i  ];
110
        float yi = pos[3*i+1];
111
        float zi = pos[3*i+2];
112

    
113
        for(int j=i+1; j<numCenters; j++)
114
          {
115
          float xj = pos[3*j  ];
116
          float yj = pos[3*j+1];
117
          float zj = pos[3*j+2];
118

    
119
          if( areNeighbours(x,xi-xj,yi-yj,zi-zj) )
120
            {
121
            float xc = (xi+xj)/2;  // TODO; wrong; consequence of this is: mTouchRows
122
            float yc = (yi+yj)/2;  // in case of Megaminx and larger - not Kilominx -
123
            float zc = (zi+zj)/2;  // are wrong, and scrambling is not so perfect.
124

    
125
            int bitIndex = getIndexOfCubitTouch(xc,yc,zc);
126
            setBit(bitIndex,1);
127
            }
128
          }
129
        }
130
      }
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  private void prepareCubitTouch()
136
    {
137
    FactoryBandagedMegaminx factory = FactoryBandagedMegaminx.getInstance();
138
    float[][][] centers = factory.getPositions(mFactoryLayer);
139
    int size = mFactoryLayer[0];
140
    float scale = 0.0f;
141

    
142
    switch(size)
143
      {
144
      case 2: scale = 1.50f; break;
145
      case 3: scale = 1.00f; break;
146
      case 4: scale = 1.25f; break;
147
      case 5: scale = 1.00f; break;
148
      }
149

    
150
    int numCubits=0;
151
    int numVariants = centers.length;
152
    for(float[][] center : centers) numCubits += center.length;
153

    
154
    ArrayList<float[]> touch = new ArrayList<>();
155

    
156
    for(int i=0; i<numCubits; i++)
157
      {
158
      float[] first = getPosition(i,centers,numVariants);
159
      float ox = scale*first[0];
160
      float oy = scale*first[1];
161
      float oz = scale*first[2];
162

    
163
      for(int j=i+1; j<numCubits; j++)
164
        {
165
        float[] second = getPosition(j,centers,numVariants);
166
        float tx = scale*second[0];
167
        float ty = scale*second[1];
168
        float tz = scale*second[2];
169

    
170
        if( areNeighbours(size, ox-tx, oy-ty, oz-tz) )
171
          {
172
          float xc = (tx+ox)/2;  // TODO; wrong; consequence of this is: mTouchRows
173
          float yc = (ty+oy)/2;  // in case of Megaminx and larger - not Kilominx -
174
          float zc = (tz+oz)/2;  // are wrong, and scrambling is not so perfect.
175

    
176
          float[] t = new float[] {xc, yc, zc};
177
          touch.add(t);
178
          }
179
        }
180
      }
181

    
182
    mNumCubitTouches = touch.size();
183
    mCubitTouch = new float[mNumCubitTouches][];
184
    for(int i=0; i<mNumCubitTouches; i++) mCubitTouch[i] = touch.remove(0);
185
    }
186

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

    
189
  private void prepareTouchRows()
190
    {
191
    mTouchRows = new int[6][mNumCubitTouches];
192
    int num = mFactoryLayer[0];
193
    final int N = 10;
194

    
195
    for(int i=0; i<mNumCubitTouches; i++)
196
      {
197
      float[] touch = mCubitTouch[i];
198

    
199
      for(int a=0; a<6; a++)
200
        {
201
        float[] ax = ROT_AXIS[a];
202
        float l = whichLayer(touch,ax,num);
203
        int ll = (int)(N*l);
204
        mTouchRows[a][i] = ( (ll%N)==0 ) ? ll/N : -1;
205
        }
206
      }
207
    }
208

    
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
  private void prepareAllCycles()
212
    {
213
    ArrayList<float[][]> cycles0 = new ArrayList<>();
214
    ArrayList<float[][]> cycles1 = new ArrayList<>();
215
    ArrayList<float[][]> cycles2 = new ArrayList<>();
216
    ArrayList<float[][]> cycles3 = new ArrayList<>();
217
    ArrayList<float[][]> cycles4 = new ArrayList<>();
218
    ArrayList<float[][]> cycles5 = new ArrayList<>();
219

    
220
    generate5Cycles(cycles0,0);
221
    generate5Cycles(cycles1,1);
222
    generate5Cycles(cycles2,2);
223
    generate5Cycles(cycles3,3);
224
    generate5Cycles(cycles4,4);
225
    generate5Cycles(cycles5,5);
226

    
227
    mCycles = new int[6][][][];
228

    
229
    int param = mFactoryLayer[0];
230
    int numLayers = mLayer[0];
231
    mCycles[0] = fillUpCycles(cycles0,0,numLayers,param);
232
    mCycles[1] = fillUpCycles(cycles1,1,numLayers,param);
233
    mCycles[2] = fillUpCycles(cycles2,2,numLayers,param);
234
    mCycles[3] = fillUpCycles(cycles3,3,numLayers,param);
235
    mCycles[4] = fillUpCycles(cycles4,4,numLayers,param);
236
    mCycles[5] = fillUpCycles(cycles5,5,numLayers,param);
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  private void generate5Cycles(ArrayList<float[][]> cycles, int ax)
242
    {
243
    for(int i=0; i<mNumCubitTouches; i++)
244
      {
245
      int i0 = rotateIndex5(ax,i);
246
      if( i0<=i ) continue;
247
      int i1 = rotateIndex5(ax,i0);
248
      if( i1<=i ) continue;
249
      int i2 = rotateIndex5(ax,i1);
250
      if( i2<=i ) continue;
251
      int i3 = rotateIndex5(ax,i2);
252
      if( i3<=i ) continue;
253

    
254
      float[] f0 = getCubitTouchOfIndex(i);
255
      float[] f1 = getCubitTouchOfIndex(i0);
256
      float[] f2 = getCubitTouchOfIndex(i1);
257
      float[] f3 = getCubitTouchOfIndex(i2);
258
      float[] f4 = getCubitTouchOfIndex(i3);
259

    
260
      float[][] cycle = new float[][] { f0,f1,f2,f3,f4 };
261
      cycles.add(cycle);
262
      }
263
    }
264

    
265
///////////////////////////////////////////////////////////////////////////////////////////////////
266
// param 2 3 4 5
267
// numL  3 3 5 5
268

    
269
  private int[][][] fillUpCycles(ArrayList<float[][]> cyc, int axis, int numL, int param)
270
    {
271
    int numCycles = cyc.size();
272
    int[] index = new int[numL];
273
    int[] numC = new int[numL];
274
    float[] ax = ROT_AXIS[axis];
275

    
276
    for(int i=0; i<numCycles; i++)
277
      {
278
      float[][] cycle = cyc.get(i);
279
      int layer = (int)whichLayer(cycle[0],ax,param);
280
      numC[layer]++;
281
      }
282

    
283
    int[][][] ret = new int[numL][][];
284
    for(int i=0; i<numL; i++) ret[i] = new int[numC[i]][];
285

    
286
    for(int i=0; i<numCycles; i++)
287
      {
288
      float[][] cycle = cyc.remove(0);
289
      int layer = (int)whichLayer(cycle[0],ax,param);
290

    
291
      int i0 = getIndexOfCubitTouch(cycle[0][0],cycle[0][1],cycle[0][2]);
292
      int i1 = getIndexOfCubitTouch(cycle[1][0],cycle[1][1],cycle[1][2]);
293
      int i2 = getIndexOfCubitTouch(cycle[2][0],cycle[2][1],cycle[2][2]);
294
      int i3 = getIndexOfCubitTouch(cycle[3][0],cycle[3][1],cycle[3][2]);
295
      int i4 = getIndexOfCubitTouch(cycle[4][0],cycle[4][1],cycle[4][2]);
296

    
297
      ret[layer][index[layer]] = new int[] {i0,i1,i2,i3,i4};
298
      index[layer]++;
299
      }
300

    
301
    return ret;
302
    }
303

    
304
///////////////////////////////////////////////////////////////////////////////////////////////////
305

    
306
  private float whichLayer(float[] point, float[] ax, int numLayers)
307
    {
308
    float d = point[0]*ax[0] + point[1]*ax[1] + point[2]*ax[2];
309
    float C = 0.85f;
310

    
311
    switch(numLayers)
312
      {
313
      case 2: return (d*LEN)/(6*C2*SIN54) + 1.5f;
314
      case 3: float D3 = 3*TouchControlDodecahedron.DIST3D;
315
              float X3 = 2*D3/(2+SIN18);
316
              float G3 = X3*(0.5f-MEGA_D);
317
              float cut3 = -D3 + C*G3;
318
              return d<-cut3 ? 0 : d<cut3 ? 1:2;
319
      case 4: float D4 = 5*TouchControlDodecahedron.DIST3D;
320
              float X4 = 2*D4/(2+SIN18);
321
              float G4 = X4*0.25f;
322
              float cut41 = -D4 + C*G4;
323
              float cut42 = -D4 + (1+C)*G4;
324
              return d<-cut41 ? 0 : d<-cut42 ? 1: d<cut42 ? 2: d<cut41 ? 3:4;
325
      case 5: float D5 = 5*TouchControlDodecahedron.DIST3D;
326
              float X5 = 2*D5/(2+SIN18);
327
              float G5 = X5*(0.5f-MEGA_D)/2;
328
              float cut51 = -D5 + C*G5;
329
              float cut52 = -D5 + (1+C)*G5;
330
              return d<-cut51 ? 0 : d<-cut52 ? 1: d<cut52 ? 2: d<cut51 ? 3:4;
331
      }
332

    
333
    return 0;
334
    }
335

    
336
///////////////////////////////////////////////////////////////////////////////////////////////////
337

    
338
  private int rotateIndex5(int ax, int index)
339
    {
340
    float[] touch = getCubitTouchOfIndex(index);
341
    QuatHelper.rotateVectorByQuat(mTmp, touch[0], touch[1], touch[2], 1.0f, QUATS[ax]);
342
    return getIndexOfCubitTouch(mTmp[0],mTmp[1],mTmp[2]);
343
    }
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346

    
347
  private boolean areNeighbours(int size, float dx, float dy, float dz)
348
    {
349
    float fact = size==2 ? 1.5f : (size==4 ? 1.25f : 1.0f);
350

    
351
    dx /= fact;
352
    dy /= fact;
353
    dz /= fact;
354

    
355
    return BandagedObjectMegaminx.isAdjacent(size,dx,dy,dz);
356
    }
357
}
(4-4/6)