Project

General

Profile

Download (17 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / objects / TwistyMegaminx.java @ 749ef882

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objects;
21

    
22
import android.content.res.Resources;
23
import android.graphics.Canvas;
24
import android.graphics.Paint;
25

    
26
import org.distorted.helpers.FactoryCubit;
27
import org.distorted.helpers.FactorySticker;
28
import org.distorted.library.effect.MatrixEffectQuaternion;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedTexture;
31
import org.distorted.library.mesh.MeshBase;
32
import org.distorted.library.mesh.MeshSquare;
33
import org.distorted.library.type.Static3D;
34
import org.distorted.library.type.Static4D;
35
import org.distorted.main.R;
36
import org.distorted.main.RubikSurfaceView;
37

    
38
import static org.distorted.helpers.FactoryCubit.COS18;
39
import static org.distorted.helpers.FactoryCubit.COS54;
40
import static org.distorted.helpers.FactoryCubit.SIN18;
41
import static org.distorted.helpers.FactoryCubit.SIN54;
42

    
43
///////////////////////////////////////////////////////////////////////////////////////////////////
44

    
45
public class TwistyMegaminx extends TwistyMinx
46
{
47
  static final float MEGA_D = 0.04f;
48

    
49
  private static final int[] QUAT_CENTER_INDICES =
50
      {
51
        16, 18, 22,  1, 20, 13, 14, 15,  0, 12,  2,  3
52
      };
53

    
54
  private static MeshBase[] mCenterMeshes, mCornerMeshes;
55
  private static MeshBase[][] mEdgeMeshes;
56

    
57
///////////////////////////////////////////////////////////////////////////////////////////////////
58

    
59
  TwistyMegaminx(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
60
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
61
    {
62
    super(size, size, quat, texture, mesh, effects, moves, ObjectList.MEGA, res, scrWidth);
63
    }
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  private int numCubitsPerCorner(int numLayers)
68
    {
69
    return 3*((numLayers-1)/2)*((numLayers-3)/2) + 1;
70
    }
71

    
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73

    
74
  private int numCubitsPerEdge(int numLayers)
75
    {
76
    return numLayers-2;
77
    }
78

    
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

    
81
  float getScreenRatio()
82
    {
83
    return 1.07f;
84
    }
85

    
86
///////////////////////////////////////////////////////////////////////////////////////////////////
87

    
88
  int getNumStickerTypes(int numLayers)
89
    {
90
    return (numLayers+3)/2;
91
    }
92

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

    
95
  float[] getCuts(int numLayers)
96
    {
97
    float[] cuts = new float[numLayers-1];
98
    float D = numLayers*MovementMinx.DIST3D;
99
    float E = 2*C1;           // 2*cos(36 deg)
100
    float X = 2*D*E/(1+2*E);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
101
                              // its height is then D*2*DIST3D, it has one 'lower' part of height X, one
102
                              // 'middle' part of height Y and one upper part of height X again.
103
                              // It's edge length = numLayers/3.0f.
104
    int num = (numLayers-1)/2;
105
    float G = X*(0.5f-MEGA_D)/num; // height of one Layer
106

    
107
    for(int i=0; i<num; i++)
108
      {
109
      cuts[        i] = -D + (i+0.5f)*G;
110
      cuts[2*num-1-i] = -cuts[i];
111
      }
112

    
113
    return cuts;
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  private float[] computeCenter(int center, int numLayers)
119
    {
120
    float[] coords = mCenterCoords[center];
121
    float A = numLayers/3.0f;
122

    
123
    return new float[] { A*coords[0], A*coords[1], A*coords[2] };
124
    }
125

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127
// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
128
// Appropriate one: QUATS[QUAT_INDICES[corner]].
129

    
130
  private void computeBasicCornerVectors(int corner)
131
    {
132
    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
133

    
134
    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
135
    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
136
    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
137
    }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

    
141
  private float[] computeCorner(int numCubitsPerCorner, int numLayers, int corner, int part)
142
    {
143
    float D = numLayers/3.0f;
144
    float[] corn = CORNERS[corner];
145

    
146
    if( part==0 )
147
      {
148
      return new float[] { corn[0]*D, corn[1]*D, corn[2]*D };
149
      }
150
    else
151
      {
152
      float E = 2.0f*D*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
153
      int N = (numCubitsPerCorner-1)/3;
154
      int block = (part-1) % N;
155
      int index = (part-1) / N;
156
      Static4D pri = mCurrCornerV[index];
157
      Static4D sec = mCurrCornerV[(index+2)%3];
158

    
159
      int layers= (numLayers-3)/2;
160
      int multP = (block % layers) + 1;
161
      int multS = (block / layers);
162

    
163
      return new float[] {
164
                          corn[0]*D + (pri.get0()*multP + sec.get0()*multS)*E,
165
                          corn[1]*D + (pri.get1()*multP + sec.get1()*multS)*E,
166
                          corn[2]*D + (pri.get2()*multP + sec.get2()*multS)*E
167
                         };
168
      }
169
    }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172

    
173
  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
174
    {
175
    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
176
    return (part+1)/2;
177
    }
178

    
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180

    
181
  private float[] computeEdge(int numLayers, int edge, int part)
182
    {
183
    float D = numLayers/3.0f;
184

    
185
    float[] c1 = CORNERS[ mEdgeMap[edge][0] ];
186
    float[] c2 = CORNERS[ mEdgeMap[edge][1] ];
187
    float x = D * (c1[0]+c2[0]) / 2;
188
    float y = D * (c1[1]+c2[1]) / 2;
189
    float z = D * (c1[2]+c2[2]) / 2;
190

    
191
    if( part==0 )
192
      {
193
      return new float[] { x, y, z };
194
      }
195
    else
196
      {
197
      int mult = (part+1)/2;
198
      int dir  = (part+1)%2;
199
      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
200

    
201
      float vX = D*center[0] - x;
202
      float vY = D*center[1] - y;
203
      float vZ = D*center[2] - z;
204

    
205
      float A = mult*D*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
206
      A /= (float)Math.sqrt(vX*vX+vY*vY+vZ*vZ);
207

    
208
      return new float[] { x+A*vX, y+A*vY, z+A*vZ };
209
      }
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  float[][] getCubitPositions(int numLayers)
215
    {
216
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
217
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
218
    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
219
    int index=0;
220

    
221
    final float[][] CENTERS = new float[numCubits][];
222

    
223
    for(int corner=0; corner<NUM_CORNERS; corner++)
224
      {
225
      computeBasicCornerVectors(corner);
226

    
227
      for(int part=0; part<numCubitsPerCorner; part++, index++)
228
        {
229
        CENTERS[index] = computeCorner(numCubitsPerCorner,numLayers,corner,part);
230
        }
231
      }
232

    
233
    for(int edge=0; edge<NUM_EDGES; edge++)
234
      {
235
      for(int part=0; part<numCubitsPerEdge; part++, index++)
236
        {
237
        CENTERS[index] = computeEdge(numLayers, edge, part );
238
        }
239
      }
240

    
241
    for(int center=0; center<NUM_CENTERS; center++, index++)
242
      {
243
      CENTERS[index] = computeCenter(center, numLayers);
244
      }
245

    
246
    return CENTERS;
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

    
251
  private int getQuat(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
252
    {
253
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
254
      {
255
      int corner = cubit/numCubitsPerCorner;
256
      return QUAT_CORNER_INDICES[corner];
257
      }
258

    
259
    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
260
      {
261
      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
262
      return QUAT_EDGE_INDICES[edge];
263
      }
264

    
265
    int center = cubit - NUM_CORNERS*numCubitsPerCorner - NUM_EDGES*numCubitsPerEdge;
266
    return QUAT_CENTER_INDICES[center];
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

    
271
  MeshBase createCubitMesh(int cubit, int numLayers)
272
    {
273
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
274
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
275
    int index = (numLayers-3)/2;
276
    int[] sizes = ObjectList.MEGA.getSizes();
277
    int variants = sizes.length;
278
    MeshBase mesh;
279

    
280
    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
281
    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][(sizes[variants-1]-1)/2];
282
    if( mCenterMeshes==null ) mCenterMeshes = new MeshBase[variants];
283

    
284
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
285
      {
286
      if( mCornerMeshes[index]==null )
287
        {
288
        float width = (numLayers/3.0f)*(0.5f-MEGA_D)/(0.5f*(numLayers-1));
289
        mCornerMeshes[index] = FactoryCubit.getInstance().createMinxCornerMesh(numLayers, width);
290
        }
291
      mesh = mCornerMeshes[index].copy(true);
292
      }
293
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
294
      {
295
      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
296

    
297
      if( mEdgeMeshes[index][type]==null )
298
        {
299
        float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
300
        float width = (numLayers/3.0f)*2*MEGA_D + 2*type*height*SIN18/COS18;
301

    
302
        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(numLayers,width,height);
303
        }
304

    
305
      mesh = mEdgeMeshes[index][type].copy(true);
306
      }
307
    else
308
      {
309
      if( mCenterMeshes[index]==null )
310
        {
311
        float width = 2 * (numLayers/3.0f) * (MEGA_D+(0.5f-MEGA_D)*SIN18);
312
        mCenterMeshes[index] = FactoryCubit.getInstance().createMegaminxCenterMesh(numLayers,width);
313
        }
314

    
315
      mesh = mCenterMeshes[index].copy(true);
316
      }
317

    
318
    Static4D q = QUATS[getQuat(cubit,numCubitsPerCorner,numCubitsPerEdge)];
319
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( q, new Static3D(0,0,0) );
320
    mesh.apply(quat,0xffffffff,0);
321

    
322
    return mesh;
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326

    
327
  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
328
    {
329
    if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES;
330

    
331
    int part  = cubit % numCubitsPerCorner;
332
    int corner= cubit / numCubitsPerCorner;
333

    
334
    if( part==0 )
335
      {
336
      return mCornerFaceMap[corner][cubitface];
337
      }
338
    else
339
      {
340
      int N = (numCubitsPerCorner-1)/3;
341
      int block = (part-1) % N;
342
      int index = (part-1) / N;
343

    
344
      if( block< (numLayers-3)/2 )
345
        {
346
        switch(index)
347
          {
348
          case 0: return cubitface==1 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
349
          case 1: return cubitface==0 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
350
          case 2: return cubitface==2 ? NUM_TEXTURES : mCornerFaceMap[corner][cubitface];
351
          }
352
        }
353
      else
354
        {
355
        switch(index)
356
          {
357
          case 0: return cubitface==0 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
358
          case 1: return cubitface==2 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
359
          case 2: return cubitface==1 ? mCornerFaceMap[corner][cubitface] : NUM_TEXTURES;
360
          }
361
        }
362
      }
363

    
364
    return NUM_TEXTURES;
365
    }
366

    
367
///////////////////////////////////////////////////////////////////////////////////////////////////
368

    
369
  int getEdgeColor(int edge, int cubitface, int numCubitsPerEdge)
370
    {
371
    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES;
372

    
373
    int part    = edge % numCubitsPerEdge;
374
    int variant = edge / numCubitsPerEdge;
375

    
376
    return (part==0 || cubitface==((part+1)%2)) ? mEdgeMap[variant][cubitface+2] + ((part+3)/2)*NUM_FACES : NUM_TEXTURES;
377
    }
378

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

    
381
  int getCenterColor(int center, int cubitface, int numLayers)
382
    {
383
    return cubitface>0 ? NUM_TEXTURES : center + NUM_FACES*(numLayers+1)/2;
384
    }
385

    
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387

    
388
  int getFaceColor(int cubit, int cubitface, int numLayers)
389
    {
390
    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
391
    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
392

    
393
    if( cubit < NUM_CORNERS*numCubitsPerCorner )
394
      {
395
      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
396
      }
397
    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
398
      {
399
      int edge = cubit - NUM_CORNERS*numCubitsPerCorner;
400
      return getEdgeColor(edge,cubitface,numCubitsPerEdge);
401
      }
402
    else
403
      {
404
      int center = cubit-NUM_CORNERS*numCubitsPerCorner-NUM_EDGES*numCubitsPerEdge;
405
      return getCenterColor( center, cubitface, numLayers);
406
      }
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
412
    {
413
    int COLORS = FACE_COLORS.length;
414
    float R,S;
415
    float[] vertices;
416

    
417
    int variant = face/COLORS;
418

    
419
    if( variant==0 )
420
      {
421
      float Y = COS54/(2*SIN54);
422
      R = 0.070f;
423
      S = 0.08f;
424
      vertices = new float[] { -0.5f, 0.0f, 0.0f, -Y, 0.5f, 0.0f, 0.0f, Y };
425
      }
426
    else
427
      {
428
      int numLayers = getNumLayers();
429
      float height= (numLayers/3.0f)*(0.5f-MEGA_D)*COS18/((numLayers-1)*0.5f);
430
      float W = height*SIN18/COS18;
431
      float width = (numLayers/3.0f)*2*MEGA_D + 2*(variant-1)*W;
432

    
433
      if( variant < (numLayers+1)/2 )
434
        {
435
        float X1 = 0.5f*height;
436
        float Y1 = 0.5f*width;
437
        float Y2 = 0.5f*width + W;
438

    
439
        R = 0.05f;
440
        S = 0.06f;
441
        vertices = new float[] { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
442
        }
443
      else
444
        {
445
        float Z  = 0.5f;
446
        float X1 = Z*COS54;
447
        float Y1 = Z*SIN54;
448
        float X2 = Z*COS18;
449
        float Y2 = Z*SIN18;
450

    
451
        R = 0.10f;
452
        S = 0.08f;
453
        vertices = new float[] { -X1,+Y1, -X2,-Y2, 0.0f,-Z, +X2,-Y2, +X1,+Y1 };
454
        }
455
      }
456

    
457
    FactorySticker factory = FactorySticker.getInstance();
458
    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face%COLORS], R);
459
    }
460

    
461
///////////////////////////////////////////////////////////////////////////////////////////////////
462
// PUBLIC API
463

    
464
  public boolean isSolved()
465
    {
466
    int index = CUBITS[0].mQuatIndex;
467

    
468
    for(int i=1; i<NUM_CUBITS; i++)
469
      {
470
      if( thereIsVisibleDifference(CUBITS[i], index) ) return false;
471
      }
472

    
473
    return true;
474
    }
475

    
476
///////////////////////////////////////////////////////////////////////////////////////////////////
477

    
478
  public int getObjectName(int numLayers)
479
    {
480
    if( numLayers==3 ) return R.string.minx3;
481
    if( numLayers==5 ) return R.string.minx5;
482

    
483
    return 0;
484
    }
485

    
486
///////////////////////////////////////////////////////////////////////////////////////////////////
487

    
488
  public int getInventor(int numLayers)
489
    {
490
    if( numLayers==3 ) return R.string.minx3_inventor;
491
    if( numLayers==5 ) return R.string.minx5_inventor;
492

    
493
    return 0;
494
    }
495

    
496
///////////////////////////////////////////////////////////////////////////////////////////////////
497

    
498
  public int getComplexity(int numLayers)
499
    {
500
    if( numLayers==3 ) return 4;
501

    
502
    return 5;
503
    }
504
}
(27-27/33)