Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / objects / TwistyMirrorPyraminx.java @ 33ba467a

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.objects;
11

    
12
import static org.distorted.objectlib.touchcontrol.TouchControl.TC_CHANGING_MIRROR;
13
import static org.distorted.objectlib.touchcontrol.TouchControl.TYPE_NOT_SPLIT;
14

    
15
import org.distorted.library.type.Static3D;
16
import org.distorted.library.type.Static4D;
17
import org.distorted.objectlib.helpers.FactoryCubit;
18
import org.distorted.objectlib.helpers.FactoryShape;
19
import org.distorted.objectlib.helpers.ObjectFaceShape;
20
import org.distorted.objectlib.helpers.ObjectShape;
21
import org.distorted.objectlib.helpers.ObjectVertexEffects;
22
import org.distorted.objectlib.main.InitAssets;
23
import org.distorted.objectlib.metadata.ListObjects;
24
import org.distorted.objectlib.metadata.Metadata;
25
import org.distorted.objectlib.shape.ShapeColors;
26
import org.distorted.objectlib.shape.ShapeTetrahedron;
27
import org.distorted.objectlib.touchcontrol.TouchControlTetrahedron;
28

    
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

    
31
public class TwistyMirrorPyraminx extends ShapeTetrahedron
32
{
33
  static final Static3D[] ROT_AXIS = new Static3D[]
34
    {
35
      new Static3D(     0,-SQ3/3,-SQ6/3),
36
      new Static3D(     0,-SQ3/3, SQ6/3),
37
      new Static3D( SQ6/3, SQ3/3,     0),
38
      new Static3D(-SQ6/3, SQ3/3,     0),
39
    };
40

    
41
  private static final int[] FACE_COLORS = new int[] { ShapeColors.COLOR_WHITE};
42
  private static final float[] MIRROR_VEC = { 0.06f, 0.15f, 0.02f };
43

    
44
  private int[][] mEdges;
45
  private int[][] mBasicAngle;
46
  private float[][] mCuts;
47
  private float[][] mPositions;
48
  private ObjectShape[] mShapes;
49
  private float[][] mCutPlanes;
50
  private float[] mDist3D, mDist;
51
  private float[][] mPotentialVertices;
52

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

    
55
  public TwistyMirrorPyraminx(int iconMode, Static4D quat, Static3D move, float scale, Metadata meta, InitAssets asset)
56
    {
57
    super(iconMode, meta.getNumLayers()[0], quat, move, scale, meta, asset);
58
    }
59

    
60
///////////////////////////////////////////////////////////////////////////////////////////////////
61
// here we cannot automatically detect the outer monochromatic walls -> use the old way.
62

    
63
  @Override
64
  public int getSolvedFunctionIndex()
65
    {
66
    return 0;
67
    }
68

    
69
///////////////////////////////////////////////////////////////////////////////////////////////////
70

    
71
  @Override
72
  public int[][] getSolvedQuats()
73
    {
74
    return getOldSolvedQuats();
75
    }
76

    
77
///////////////////////////////////////////////////////////////////////////////////////////////////
78

    
79
  @Override
80
  public int getInternalColor()
81
    {
82
    return 0xff333333;
83
    }
84

    
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86

    
87
  @Override
88
  public int[] getColorTable()
89
    {
90
    return FACE_COLORS;
91
    }
92

    
93
///////////////////////////////////////////////////////////////////////////////////////////////////
94

    
95
  @Override
96
  public float[][] returnRotationFactor()
97
    {
98
    float[] f = { 1.4f, 1.8f, 2.5f };
99
    return new float[][] {f,f,f,f};
100
    }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
  public int[][] getScrambleEdges()
105
    {
106
    if( mEdges==null )
107
      {
108
      int nL = getNumLayers()[0];
109
      mEdges = new int[nL][];
110

    
111
      for(int i=0; i<nL; i++)
112
        {
113
        int numEnabledMoves = 2*(nL-i);
114
        mEdges[i] = new int[4*2*numEnabledMoves];
115

    
116
        int index = 0;
117
        int startMove= 0;
118
        int offset = (i==nL-1 ? 2:0);  // if the last move was a tip, the only possible
119
                                       // next move is the second-to-largest layer.
120
        fillEdge(mEdges[i],index,startMove,offset,numEnabledMoves);
121
        index += (2*numEnabledMoves);
122
        startMove += (2*nL);
123
        fillEdge(mEdges[i],index,startMove,offset,numEnabledMoves);
124
        index += (2*numEnabledMoves);
125
        startMove += (2*nL);
126
        fillEdge(mEdges[i],index,startMove,offset,numEnabledMoves);
127
        index += (2*numEnabledMoves);
128
        startMove += (2*nL);
129
        fillEdge(mEdges[i],index,startMove,offset,numEnabledMoves);
130
        }
131
      }
132

    
133
    return mEdges;
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  private void fillEdge(int[] edge, int index, int move, int offset, int num)
139
    {
140
    for(int i=0; i<num; i++)
141
      {
142
      edge[index+2*i  ] = (move+offset);
143
      edge[index+2*i+1] = (i+offset)/2;
144
      move++;
145
      }
146
    }
147

    
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

    
150
  public float[][] getCuts(int[] numLayers)
151
    {
152
    if( mCuts==null )
153
      {
154
      float[] c = { SQ6/12, 5*SQ6/12 };
155
      mCuts = new float[][] {c,c,c,c};
156
      }
157

    
158
    return mCuts;
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  public boolean[][] getLayerRotatable(int[] numLayers)
164
    {
165
    boolean[] tmp = {true,true,true};
166
    return new boolean[][] { tmp,tmp,tmp,tmp };
167
    }
168

    
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170

    
171
  public int getTouchControlType()
172
    {
173
    return TC_CHANGING_MIRROR;
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  public int getTouchControlSplit()
179
    {
180
    return TYPE_NOT_SPLIT;
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

    
185
  public int[][][] getEnabled()
186
    {
187
    return null;
188
    }
189

    
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191
// 'full' dists (not divided by numLayers)
192

    
193
  private float[] getDist()
194
    {
195
    if( mDist==null )
196
      {
197
      float DX = MIRROR_VEC[0];
198
      float DY = MIRROR_VEC[1];
199
      float DZ = MIRROR_VEC[2];
200
      Static3D[] axis = getFaceAxis();
201
      mDist = new float[4];
202

    
203
      for( int a=0; a<4; a++ )
204
        {
205
        Static3D ax = axis[a];
206
        float d = ax.get0()*DX + ax.get1()*DY + ax.get2()*DZ;
207
        mDist[a] = SQ6/4 + d;
208
        }
209
      }
210

    
211
    return mDist;
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215
// 'regular' dists for the touchControl (have to be divided by numLayers)
216

    
217
  public float[] getDist3D(int[] numLayers)
218
    {
219
    if( mDist3D==null )
220
      {
221
      float[] d = getDist();
222
      mDist3D = new float[] { d[0]/3, d[1]/3, d[2]/3, d[3]/3 };
223
      }
224

    
225
    return mDist3D;
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229

    
230
  public Static3D[] getFaceAxis()
231
    {
232
    return TouchControlTetrahedron.FACE_AXIS;
233
    }
234

    
235
///////////////////////////////////////////////////////////////////////////////////////////////////
236

    
237
  private void addTetrahedralLattice(int size, int index, float[][] pos)
238
    {
239
    final float DX = 1.0f;
240
    final float DY = SQ2/2;
241
    final float DZ = 1.0f;
242

    
243
    float startX = 0.0f;
244
    float startY =-DY*(size-1)/2;
245
    float startZ = DZ*(size-1)/2;
246

    
247
    for(int layer=0; layer<size; layer++)
248
      {
249
      float currX = startX;
250
      float currY = startY;
251

    
252
      for(int x=0; x<layer+1; x++)
253
        {
254
        float currZ = startZ;
255

    
256
        for(int z=0; z<size-layer; z++)
257
          {
258
          pos[index] = new float[] {currX,currY,currZ};
259
          index++;
260
          currZ -= DZ;
261
          }
262

    
263
        currX += DX;
264
        }
265

    
266
      startX-=DX/2;
267
      startY+=DY;
268
      startZ-=DZ/2;
269
      }
270
    }
271

    
272
///////////////////////////////////////////////////////////////////////////////////////////////////
273

    
274
  private float[][] getPositions()
275
    {
276
    if( mPositions==null )
277
      {
278
      final float X = MIRROR_VEC[0];
279
      final float Y = MIRROR_VEC[1];
280
      final float Z = MIRROR_VEC[2];
281

    
282
      mPositions = new float[14][];
283

    
284
      addTetrahedralLattice(3, 0,mPositions);
285
      addTetrahedralLattice(2,10,mPositions);
286

    
287
      for( float[] pos : mPositions )
288
        {
289
        pos[0] += X;
290
        pos[1] += Y;
291
        pos[2] += Z;
292
        }
293
      }
294

    
295
    return mPositions;
296
    }
297

    
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

    
301
  public float[][] getCubitPositions(int[] numLayers)
302
    {
303
    return getPositions();
304
    }
305

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

    
308
  public Static4D getCubitQuats(int cubit, int[] numLayers)
309
    {
310
    return mObjectQuats[0];
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
  private void createCutPlanes()
316
    {
317
    int numPlanes = 3*4;
318
    mCutPlanes = new float[numPlanes][];
319
    Static3D[] faceAxis = getFaceAxis();
320
    float[] dist = getDist();
321
    int[] numLayers = getNumLayers();
322
    float[][] cuts = getCuts(numLayers);
323
    float cut0 = cuts[0][0];
324
    float cut1 = cuts[0][1];
325

    
326
    for(int p=0; p<4; p++)
327
      {
328
      Static3D ax = faceAxis[p];
329
      mCutPlanes[p] = new float[] { ax.get0(), ax.get1(), ax.get2(), dist[p] };
330
      }
331

    
332
    for(int p=4; p<8; p++)
333
      {
334
      Static3D ax = ROT_AXIS[p-4];
335
      mCutPlanes[p] = new float[] { ax.get0(), ax.get1(), ax.get2(), cut0 };
336
      }
337
    for(int p=8; p<12; p++)
338
      {
339
      Static3D ax = ROT_AXIS[p-8];
340
      mCutPlanes[p] = new float[] { ax.get0(), ax.get1(), ax.get2(), cut1 };
341
      }
342
    }
343

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

    
346
  private float[] internalPoint(int variant)
347
    {
348
    float[][] pos = getPositions();
349
    float[] p = pos[variant];
350
    return new float[] { p[0],p[1],p[2] };
351
    }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354

    
355
  public ObjectShape getObjectShape(int variant)
356
    {
357
    if( mShapes==null )
358
      {
359
      int[] numLayers = getNumLayers();
360
      int numV = getNumCubitVariants(numLayers);
361
      mShapes = new ObjectShape[numV];
362
      createCutPlanes();
363
      mPotentialVertices = FactoryShape.computePotentialVertices(mCutPlanes);
364
      }
365

    
366
    if( mShapes[variant]==null )
367
      {
368
      float[][] pos = getPositions();
369
      float[] point = internalPoint(variant);
370
      mShapes[variant] = FactoryShape.createShape(mCutPlanes,mPotentialVertices,pos[variant],point);
371
      }
372

    
373
    return mShapes[variant];
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377

    
378
  public ObjectFaceShape getObjectFaceShape(int variant)
379
    {
380
    ObjectShape shape = getObjectShape(variant);
381
    int[][] ind    = shape.getVertIndices();
382
    float[][] vert = shape.getVertices();
383
    float[][] pos  = getPositions();
384
    int[] indices  = FactoryShape.produceBandIndices(vert, pos[variant], ind, getFaceAxis(), getDist() );
385

    
386
    if( variant<10 )
387
      {
388
      int N = 5;
389
      int E = 0;
390
      float height = isInIconMode() ? 0.001f : 0.04f;
391
      float[][] bands = { {height,35,0.3f,0.5f,N,E,E}, {0.001f,35,0.3f,0.5f,N,E,E} };
392
      return new ObjectFaceShape(bands,indices,null);
393
      }
394
    else
395
      {
396
      int N = 5;
397
      int E = 0;
398
      float height = isInIconMode() ? 0.001f : 0.05f;
399
      float[][] bands = { {height,35,0.3f,0.5f,N,E,E}, {0.001f,35,0.3f,0.5f,N,E,E} };
400
      return new ObjectFaceShape(bands,indices,null);
401
      }
402
    }
403

    
404
///////////////////////////////////////////////////////////////////////////////////////////////////
405

    
406
  private float[][] computeVertexEffectCenter(int variant)
407
    {
408
    float A = variant<4 ? -0.5f : -1.0f;
409

    
410
    float[][] positions = getPositions();
411
    float[] p = positions[variant];
412

    
413
    return new float[][] {{ A*p[0], A*p[1], A*p[2] }};
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  public ObjectVertexEffects getVertexEffects(int variant)
419
    {
420
    ObjectShape shape  = getObjectShape(variant);
421
    float[][] vertices = shape.getVertices();
422
    float[][] centers  = computeVertexEffectCenter(variant);
423
    float[][] pos      = getPositions();
424
    int[] indices      = FactoryShape.computeVertexEffectsIndices(vertices, pos[variant], getFaceAxis(), getDist() );
425
    float[][] corners  = variant<10 ? new float[][]{{0.03f, 0.20f}} : new float[][]{{0.03f, 0.15f}};
426

    
427
    return FactoryCubit.generateVertexEffect(vertices,corners,indices,centers,indices);
428
    }
429

    
430
///////////////////////////////////////////////////////////////////////////////////////////////////
431

    
432
  public int getNumCubitVariants(int[] numLayers)
433
    {
434
    return 14;
435
    }
436

    
437
///////////////////////////////////////////////////////////////////////////////////////////////////
438

    
439
  public int getCubitVariant(int cubit, int[] numLayers)
440
    {
441
    return cubit;
442
    }
443

    
444
///////////////////////////////////////////////////////////////////////////////////////////////////
445

    
446
  public float getStickerRadius()
447
    {
448
    return 0.08f;
449
    }
450

    
451
///////////////////////////////////////////////////////////////////////////////////////////////////
452

    
453
  public float getStickerStroke()
454
    {
455
    return isInIconMode() ? 0.12f : 0.08f;
456
    }
457

    
458
///////////////////////////////////////////////////////////////////////////////////////////////////
459

    
460
  public float[][][] getStickerAngles()
461
    {
462
    return null;
463
    }
464

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466
// PUBLIC API
467

    
468
  public Static3D[] getRotationAxis()
469
    {
470
    return ROT_AXIS;
471
    }
472

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

    
475
  public int[][] getBasicAngles()
476
    {
477
    if( mBasicAngle ==null )
478
      {
479
      int num = getNumLayers()[0];
480
      int[] tmp = new int[num];
481
      for(int i=0; i<num; i++) tmp[i] = 3;
482
      mBasicAngle = new int[][] { tmp,tmp,tmp,tmp };
483
      }
484

    
485
    return mBasicAngle;
486
    }
487

    
488
///////////////////////////////////////////////////////////////////////////////////////////////////
489

    
490
  public String getShortName()
491
    {
492
    return ListObjects.MPYR_3.name();
493
    }
494

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

    
497
  public String[][] getTutorials()
498
    {
499
    return null;
500
    }
501
}
(33-33/59)