Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikSkewb.java @ 940100d1

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.library.effect.MatrixEffectQuaternion;
27
import org.distorted.library.effect.VertexEffectDeform;
28
import org.distorted.library.effect.VertexEffectMove;
29
import org.distorted.library.effect.VertexEffectRotate;
30
import org.distorted.library.effect.VertexEffectScale;
31
import org.distorted.library.main.DistortedEffects;
32
import org.distorted.library.main.DistortedTexture;
33
import org.distorted.library.mesh.MeshBase;
34
import org.distorted.library.mesh.MeshJoined;
35
import org.distorted.library.mesh.MeshPolygon;
36
import org.distorted.library.mesh.MeshSquare;
37
import org.distorted.library.mesh.MeshTriangle;
38
import org.distorted.library.type.Static1D;
39
import org.distorted.library.type.Static3D;
40
import org.distorted.library.type.Static4D;
41
import org.distorted.main.RubikSurfaceView;
42

    
43
import java.util.Random;
44

    
45
import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
public class RubikSkewb extends RubikObject
50
{
51
  private static final float SQ2 = (float)Math.sqrt(2);
52
  private static final float SQ3 = (float)Math.sqrt(3);
53

    
54
  private static final int FACES_PER_CUBIT =6;
55

    
56
  // the four rotation axis of a RubikSkewb. Must be normalized.
57
  static final Static3D[] ROT_AXIS = new Static3D[]
58
         {
59
           new Static3D(+SQ3/3,+SQ3/3,+SQ3/3),
60
           new Static3D(+SQ3/3,+SQ3/3,-SQ3/3),
61
           new Static3D(+SQ3/3,-SQ3/3,+SQ3/3),
62
           new Static3D(+SQ3/3,-SQ3/3,-SQ3/3)
63
         };
64

    
65
  // the six axis that determine the faces
66
  static final Static3D[] FACE_AXIS = new Static3D[]
67
         {
68
           new Static3D(1,0,0), new Static3D(-1,0,0),
69
           new Static3D(0,1,0), new Static3D(0,-1,0),
70
           new Static3D(0,0,1), new Static3D(0,0,-1)
71
         };
72

    
73
  private static final int[] FACE_COLORS = new int[]
74
         {
75
           0xffffff00, 0xffffffff,   // FACE_AXIS[0] (right-YELLOW) FACE_AXIS[1] (left  -WHITE)
76
           0xff0000ff, 0xff00ff00,   // FACE_AXIS[2] (top  -BLUE  ) FACE_AXIS[3] (bottom-GREEN)
77
           0xffff0000, 0xffb5651d    // FACE_AXIS[4] (front-RED   ) FACE_AXIS[5] (back  -BROWN)
78
         };
79

    
80
  // All legal rotation quats of a RubikSkewb
81
  private static final Static4D[] QUATS = new Static4D[]
82
         {
83
           new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
84
           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
85
           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
86
           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
87

    
88
           new Static4D(  0.5f,  0.5f,  0.5f,  0.5f ),
89
           new Static4D(  0.5f,  0.5f,  0.5f, -0.5f ),
90
           new Static4D(  0.5f,  0.5f, -0.5f,  0.5f ),
91
           new Static4D(  0.5f,  0.5f, -0.5f, -0.5f ),
92
           new Static4D(  0.5f, -0.5f,  0.5f,  0.5f ),
93
           new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
94
           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
95
           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
96
         };
97

    
98
  private static final float DIST_CORNER = 0.50f;
99
  private static final float DIST_CENTER = 0.49f;
100

    
101
  // centers of the 8 corners + 6 sides ( i.e. of the all 14 cubits)
102
  private static final Static3D[] CENTERS = new Static3D[]
103
         {
104
           new Static3D( DIST_CORNER, DIST_CORNER, DIST_CORNER ),
105
           new Static3D( DIST_CORNER, DIST_CORNER,-DIST_CORNER ),
106
           new Static3D( DIST_CORNER,-DIST_CORNER, DIST_CORNER ),
107
           new Static3D( DIST_CORNER,-DIST_CORNER,-DIST_CORNER ),
108
           new Static3D(-DIST_CORNER, DIST_CORNER, DIST_CORNER ),
109
           new Static3D(-DIST_CORNER, DIST_CORNER,-DIST_CORNER ),
110
           new Static3D(-DIST_CORNER,-DIST_CORNER, DIST_CORNER ),
111
           new Static3D(-DIST_CORNER,-DIST_CORNER,-DIST_CORNER ),
112

    
113
           new Static3D( DIST_CENTER,        0.0f,        0.0f ),
114
           new Static3D(-DIST_CENTER,        0.0f,        0.0f ),
115
           new Static3D(        0.0f, DIST_CENTER,        0.0f ),
116
           new Static3D(        0.0f,-DIST_CENTER,        0.0f ),
117
           new Static3D(        0.0f,        0.0f, DIST_CENTER ),
118
           new Static3D(        0.0f,        0.0f,-DIST_CENTER ),
119
         };
120

    
121
  // Colors of the faces of cubits. Each cubit, even the face pyramid, has 6 faces
122
  // (the face has one extra 'fake' face so that everything would have the same number)
123
  private static final int[][] mFaceMap = new int[][]
124
         {
125
           { 4,2,0, 12,12,12 },
126
           { 2,5,0, 12,12,12 },
127
           { 3,4,0, 12,12,12 },
128
           { 5,3,0, 12,12,12 },
129
           { 1,2,4, 12,12,12 },
130
           { 5,2,1, 12,12,12 },
131
           { 4,3,1, 12,12,12 },
132
           { 1,3,5, 12,12,12 },
133

    
134
           { 6 , 12,12,12,12,12 },
135
           { 7 , 12,12,12,12,12 },
136
           { 8 , 12,12,12,12,12 },
137
           { 9 , 12,12,12,12,12 },
138
           { 10, 12,12,12,12,12 },
139
           { 11, 12,12,12,12,12 },
140
         };
141

    
142
  private static MeshBase mCornerMesh, mFaceMesh;
143

    
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

    
146
  RubikSkewb(int size, Static4D quat, DistortedTexture texture,
147
             MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
148
    {
149
    super(size, 60, quat, texture, mesh, effects, moves, RubikObjectList.SKEW, res, scrWidth);
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  private void createCornerMesh()
155
    {
156
    float D = 0.02f;
157
    float E = 0.5f;
158
    float F = SQ2/2;
159

    
160
    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
161

    
162
    float[] bands0 = { 1.0f    , 0,
163
                       1.0f-2*D, D*0.25f,
164
                       1.0f-4*D, D*0.35f,
165
                       1.0f-8*D, D*0.6f,
166
                       0.60f   , D*1.0f,
167
                       0.30f   , D*1.375f,
168
                       0.0f    , D*1.4f };
169

    
170
    MeshBase[] meshes = new MeshBase[FACES_PER_CUBIT];
171

    
172
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
173
    meshes[0].setEffectAssociation(0,1,0);
174
    meshes[1] = meshes[0].copy(true);
175
    meshes[1].setEffectAssociation(0,2,0);
176
    meshes[2] = meshes[0].copy(true);
177
    meshes[2].setEffectAssociation(0,4,0);
178

    
179
    float[] vertices1 = { 0,0, F,0, F/2,(SQ3/2)*F };
180
    float[] bands1 = { 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f };
181

    
182
    meshes[3] = new MeshPolygon(vertices1,bands1,1,5);
183
    meshes[3].setEffectAssociation(0,8,0);
184
    meshes[4] = meshes[3].copy(true);
185
    meshes[4].setEffectAssociation(0,16,0);
186
    meshes[5] = meshes[3].copy(true);
187
    meshes[5].setEffectAssociation(0,32,0);
188

    
189
    mCornerMesh = new MeshJoined(meshes);
190

    
191
    Static3D axisX  = new Static3D(1,0,0);
192
    Static3D axisY  = new Static3D(0,1,0);
193
    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
194
    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
195
    Static1D angle1 = new Static1D(+90);
196
    Static1D angle2 = new Static1D(-90);
197
    Static1D angle3 = new Static1D(-15);
198
    Static1D angle4 = new Static1D((float)((180.0f/Math.PI)*Math.acos(SQ3/3)));
199
    Static1D angle5 = new Static1D(120);
200
    Static1D angle6 = new Static1D(240);
201
    Static3D center1= new Static3D(0,0,0);
202
    Static3D center2= new Static3D(-0.5f,-0.5f,-0.5f);
203
    Static3D move1  = new Static3D(-E/4,-E/4,0);
204
    Static3D move2  = new Static3D(-0.5f,-0.5f,-0.5f);
205

    
206
    float d0 =-0.04f;
207
    float d1 = 0.04f;
208
    float r0 = 0.15f;
209
    float r1 = 0.10f;
210

    
211
    Static3D vec0   = new Static3D(d0*(+SQ3/3),d0*(+SQ3/3),d0*(+SQ3/3));
212
    Static3D vec1   = new Static3D(d1*(+SQ3/3),d1*(-SQ3/3),d1*(-SQ3/3));
213
    Static3D vec2   = new Static3D(d1*(-SQ3/3),d1*(+SQ3/3),d1*(-SQ3/3));
214
    Static3D vec3   = new Static3D(d1*(-SQ3/3),d1*(-SQ3/3),d1*(+SQ3/3));
215

    
216
    Static1D radius = new Static1D(0.5f);
217

    
218
    Static3D cent0  = new Static3D( 0.0f, 0.0f, 0.0f);
219
    Static3D cent1  = new Static3D(-0.5f, 0.0f, 0.0f);
220
    Static3D cent2  = new Static3D( 0.0f,-0.5f, 0.0f);
221
    Static3D cent3  = new Static3D( 0.0f, 0.0f,-0.5f);
222

    
223
    Static4D reg0   = new Static4D(0,0,0,r0);
224
    Static4D reg1   = new Static4D(0,0,0,r1);
225

    
226
    VertexEffectMove   effect0 = new VertexEffectMove(move1);
227
    VertexEffectScale  effect1 = new VertexEffectScale(new Static3D(1,1,-1));
228
    VertexEffectRotate effect2 = new VertexEffectRotate(angle1,axisX,center1);
229
    VertexEffectRotate effect3 = new VertexEffectRotate(angle2,axisY,center1);
230
    VertexEffectMove   effect4 = new VertexEffectMove(move2);
231
    VertexEffectRotate effect5 = new VertexEffectRotate(angle1,axisX,center2);
232
    VertexEffectRotate effect6 = new VertexEffectRotate(angle3,axisY,center2);
233
    VertexEffectRotate effect7 = new VertexEffectRotate(angle4,axis0,center2);
234
    VertexEffectRotate effect8 = new VertexEffectRotate(angle5,axis1,center2);
235
    VertexEffectRotate effect9 = new VertexEffectRotate(angle6,axis1,center2);
236

    
237
    VertexEffectDeform effect10= new VertexEffectDeform(vec0,radius,cent0,reg0);
238
    VertexEffectDeform effect11= new VertexEffectDeform(vec1,radius,cent1,reg1);
239
    VertexEffectDeform effect12= new VertexEffectDeform(vec2,radius,cent2,reg1);
240
    VertexEffectDeform effect13= new VertexEffectDeform(vec3,radius,cent3,reg1);
241

    
242
    effect0.setMeshAssociation( 7,-1);  // meshes 0,1,2
243
    effect1.setMeshAssociation( 6,-1);  // meshes 1,2
244
    effect2.setMeshAssociation( 2,-1);  // mesh 1
245
    effect3.setMeshAssociation( 4,-1);  // mesh 2
246
    effect4.setMeshAssociation(56,-1);  // meshes 3,4,5
247
    effect5.setMeshAssociation(56,-1);  // meshes 3,4,5
248
    effect6.setMeshAssociation(56,-1);  // meshes 3,4,5
249
    effect7.setMeshAssociation(56,-1);  // meshes 3,4,5
250
    effect8.setMeshAssociation(16,-1);  // mesh 4
251
    effect9.setMeshAssociation(32,-1);  // mesh 5
252

    
253
    effect10.setMeshAssociation(63,-1); // all meshes
254
    effect11.setMeshAssociation(63,-1); // all meshes
255
    effect12.setMeshAssociation(63,-1); // all meshes
256
    effect13.setMeshAssociation(63,-1); // all meshes
257

    
258
    mCornerMesh.apply(effect0);
259
    mCornerMesh.apply(effect1);
260
    mCornerMesh.apply(effect2);
261
    mCornerMesh.apply(effect3);
262
    mCornerMesh.apply(effect4);
263
    mCornerMesh.apply(effect5);
264
    mCornerMesh.apply(effect6);
265
    mCornerMesh.apply(effect7);
266
    mCornerMesh.apply(effect8);
267
    mCornerMesh.apply(effect9);
268

    
269
    mCornerMesh.apply(effect10);
270
    mCornerMesh.apply(effect11);
271
    mCornerMesh.apply(effect12);
272
    mCornerMesh.apply(effect13);
273

    
274
    mCornerMesh.mergeEffComponents();
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  private void createFaceMesh()
280
    {
281
    int association = 1;
282

    
283
    float D = 0.03f;
284
    float E = SQ2/4;
285
    float[] vertices0 = { -E,-E, +E,-E, +E,+E, -E,+E };
286

    
287
    float[] bands0 = { 1.0f    , 0,
288
                       1.0f-D/2, D*0.30f,
289
                       1.0f- D , D*0.50f,
290
                       1.0f-2*D, D*0.80f,
291
                       0.60f   , D*1.40f,
292
                       0.30f   , D*1.60f,
293
                       0.0f    , D*1.70f };
294

    
295
    MeshBase[] meshes = new MeshBase[FACES_PER_CUBIT];
296
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
297
    meshes[0].setEffectAssociation(0,association,0);
298

    
299
    association <<= 1;
300

    
301
    float[] vertices1 = { -E,-SQ3*E, +E,-SQ3*E, 0,0 };
302
    float[] bands1 = { 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f };
303

    
304
    meshes[1] = new MeshPolygon(vertices1,bands1,0,0);
305
    meshes[1].setEffectAssociation(0,association,0);
306

    
307
    for(int i=2; i<FACES_PER_CUBIT-1; i++)
308
      {
309
      association <<= 1;
310
      meshes[i] = meshes[1].copy(true);
311
      meshes[i].setEffectAssociation(0,association,0);
312
      }
313

    
314
    association <<= 1;
315
    meshes[FACES_PER_CUBIT-1] = new MeshTriangle(1);                  // empty triangle so that
316
    meshes[FACES_PER_CUBIT-1].setEffectAssociation(0,association,0);  // all cubits have 6 faces
317

    
318
    mFaceMesh = new MeshJoined(meshes);
319

    
320
    Static3D center = new Static3D(0,0,0);
321
    Static3D axis1   = new Static3D(1,0,0);
322
    Static3D axis2   = new Static3D(0,0,1);
323
    float angle = -(float)((180.0f/Math.PI)*Math.acos(SQ3/3));
324

    
325
    float f = 0.05f;
326
    float r = 0.10f;
327
    float d = 0.5f;
328
    float e = +D*0.6f;
329
    Static3D vector0 = new Static3D(-f, 0, 0);
330
    Static3D vector1 = new Static3D( 0,+f, 0);
331
    Static3D vector2 = new Static3D(+f, 0, 0);
332
    Static3D vector3 = new Static3D( 0,-f, 0);
333
    Static1D radius  = new Static1D(1.0f);
334
    Static4D region  = new Static4D(0,0,0,r);
335
    Static3D center0 = new Static3D(+d, 0, e);
336
    Static3D center1 = new Static3D( 0,-d, e);
337
    Static3D center2 = new Static3D(-d, 0, e);
338
    Static3D center3 = new Static3D( 0,+d, e);
339

    
340
    VertexEffectRotate effect0 = new VertexEffectRotate( new Static1D(angle), axis1, center);
341
    VertexEffectRotate effect1 = new VertexEffectRotate( new Static1D(  135), axis2, center);
342
    VertexEffectRotate effect2 = new VertexEffectRotate( new Static1D(   45), axis2, center);
343
    VertexEffectRotate effect3 = new VertexEffectRotate( new Static1D(  -45), axis2, center);
344
    VertexEffectRotate effect4 = new VertexEffectRotate( new Static1D( -135), axis2, center);
345
    VertexEffectMove   effect5 = new VertexEffectMove( new Static3D(0,0,-0.5f) );
346
    VertexEffectDeform effect6 = new VertexEffectDeform(vector0,radius,center0,region);
347
    VertexEffectDeform effect7 = new VertexEffectDeform(vector1,radius,center1,region);
348
    VertexEffectDeform effect8 = new VertexEffectDeform(vector2,radius,center2,region);
349
    VertexEffectDeform effect9 = new VertexEffectDeform(vector3,radius,center3,region);
350
    VertexEffectScale  effect10= new VertexEffectScale(0.01f);
351

    
352
    effect0.setMeshAssociation(30,-1);  // meshes 1,2,3,4
353
    effect1.setMeshAssociation( 2,-1);  // mesh 1
354
    effect2.setMeshAssociation( 5,-1);  // meshes 0,2
355
    effect3.setMeshAssociation( 8,-1);  // mesh 3
356
    effect4.setMeshAssociation(16,-1);  // mesh 4
357
    effect5.setMeshAssociation(30,-1);  // meshes 1,2,3,4
358
    effect6.setMeshAssociation(31,-1);  // meshes 0,1,2,3,4
359
    effect7.setMeshAssociation(31,-1);  // meshes 0,1,2,3,4
360
    effect8.setMeshAssociation(31,-1);  // meshes 0,1,2,3,4
361
    effect9.setMeshAssociation(31,-1);  // meshes 0,1,2,3,4
362
    effect10.setMeshAssociation(32,-1); // mesh 5
363

    
364
    mFaceMesh.apply(effect0);
365
    mFaceMesh.apply(effect1);
366
    mFaceMesh.apply(effect2);
367
    mFaceMesh.apply(effect3);
368
    mFaceMesh.apply(effect4);
369
    mFaceMesh.apply(effect5);
370
    mFaceMesh.apply(effect6);
371
    mFaceMesh.apply(effect7);
372
    mFaceMesh.apply(effect8);
373
    mFaceMesh.apply(effect9);
374
    mFaceMesh.apply(effect10);
375

    
376
    mFaceMesh.mergeEffComponents();
377
    }
378

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

    
381
  float getScreenRatio()
382
    {
383
    return 1.0f;
384
    }
385

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

    
388
  Static4D[] getQuats()
389
    {
390
    return QUATS;
391
    }
392

    
393
///////////////////////////////////////////////////////////////////////////////////////////////////
394

    
395
  int getNumFaces()
396
    {
397
    return FACE_COLORS.length;
398
    }
399

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401
// Each face has two types of a texture: the central square and the triangle in the corner.
402

    
403
  int getNumStickerTypes()
404
    {
405
    return 2;
406
    }
407

    
408
///////////////////////////////////////////////////////////////////////////////////////////////////
409

    
410
  int getNumCubitFaces()
411
    {
412
    return FACES_PER_CUBIT;
413
    }
414

    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416

    
417
  Static3D[] getCubitPositions(int size)
418
    {
419
    return CENTERS;
420
    }
421

    
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423

    
424
  private Static4D getQuat(int cubit)
425
    {
426
    switch(cubit)
427
      {
428
      case  0: return QUATS[0];                          //  unit quat
429
      case  1: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
430
      case  2: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
431
      case  3: return QUATS[1];                          // 180 along X
432
      case  4: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
433
      case  5: return QUATS[2];                          // 180 along Y
434
      case  6: return QUATS[3];                          // 180 along Z
435
      case  7: return new Static4D(SQ2/2,0,-SQ2/2,0);    // 180 along (SQ2/2,0,-SQ2/2)
436
      case  8: return new Static4D(0,-SQ2/2,0,SQ2/2);    // -90 along Y
437
      case  9: return new Static4D(0, SQ2/2,0,SQ2/2);    //  90 along Y
438
      case 10: return new Static4D( SQ2/2,0,0,SQ2/2);    //  90 along X
439
      case 11: return new Static4D(-SQ2/2,0,0,SQ2/2);    // -90 along X
440
      case 12: return QUATS[0];                          //  unit quaternion
441
      case 13: return QUATS[1];                          // 180 along X
442
      }
443

    
444
    return null;
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
  MeshBase createCubitMesh(int cubit)
450
    {
451
    MeshBase mesh;
452

    
453
    if( cubit<8 )
454
      {
455
      if( mCornerMesh==null ) createCornerMesh();
456
      mesh = mCornerMesh.copy(true);
457
      }
458
    else
459
      {
460
      if( mFaceMesh==null ) createFaceMesh();
461
      mesh = mFaceMesh.copy(true);
462
      }
463

    
464
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
465
    mesh.apply(quat,0xffffffff,0);
466

    
467
    return mesh;
468
    }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471

    
472
  int getFaceColor(int cubit, int cubitface, int size)
473
    {
474
    return mFaceMap[cubit][cubitface];
475
    }
476

    
477
///////////////////////////////////////////////////////////////////////////////////////////////////
478

    
479
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
480
    {
481
    int COLORS = FACE_COLORS.length;
482

    
483
    if( face<COLORS )
484
      {
485
      float STROKE = 0.035f*side;
486
      float L= left+0.125f*side;
487
      float H= 0.375f*side;
488
      float LEN = 0.5f*side;
489

    
490
      paint.setAntiAlias(true);
491
      paint.setStrokeWidth(STROKE);
492
      paint.setColor(FACE_COLORS[face]);
493
      paint.setStyle(Paint.Style.FILL);
494

    
495
      canvas.drawRect(left,top,left+side,top+side,paint);
496

    
497
      paint.setColor(INTERIOR_COLOR);
498
      paint.setStyle(Paint.Style.STROKE);
499

    
500
      canvas.drawLine( L    , H,  L+LEN, H    , paint);
501
      canvas.drawLine( L    , H,  L+LEN, H+LEN, paint);
502
      canvas.drawLine( L+LEN, H,  L+LEN, H+LEN, paint);
503

    
504
      float S1 = 0.125f*side;
505
      float S2 = 0.070f*side;
506
      float X  = 0.7f*S2;
507

    
508
      float LA = left+0.625f*side;
509
      float RA = left+0.125f*side;
510
      float TA = 0.375f*side;
511
      float BA = 0.875f*side;
512

    
513
      canvas.drawArc( LA-S1, TA     , LA     , TA+S1, 270, 90, false, paint);
514
      canvas.drawArc( RA+X , TA     , RA+X+S2, TA+S2, 135,135, false, paint);
515
      canvas.drawArc( LA-S2, BA-X-S2, LA     , BA-X ,   0,135, false, paint);
516
      }
517
    else
518
      {
519
      final float R = (SQ2/2)*side*0.10f;
520
      final float M = side*(0.5f-SQ2/4+0.018f);
521

    
522
      paint.setColor(FACE_COLORS[face-COLORS]);
523
      paint.setStyle(Paint.Style.FILL);
524
      canvas.drawRoundRect( left+M, top+M, left+side-M, top+side-M, R, R, paint);
525
      }
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529

    
530
  float returnMultiplier()
531
    {
532
    return 2.0f;
533
    }
534

    
535
///////////////////////////////////////////////////////////////////////////////////////////////////
536

    
537
  float[] getRowChances()
538
    {
539
    float[] chances = new float[2];
540

    
541
    chances[0] = 0.5f;
542
    chances[1] = 1.0f;
543

    
544
    return chances;
545
    }
546

    
547
///////////////////////////////////////////////////////////////////////////////////////////////////
548
// PUBLIC API
549

    
550
  public Static3D[] getRotationAxis()
551
    {
552
    return ROT_AXIS;
553
    }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556

    
557
  public int getBasicAngle()
558
    {
559
    return 3;
560
    }
561

    
562
///////////////////////////////////////////////////////////////////////////////////////////////////
563

    
564
  public int computeRowFromOffset(float offset)
565
    {
566
    return offset<0.25f ? 0:1;
567
    }
568

    
569
///////////////////////////////////////////////////////////////////////////////////////////////////
570

    
571
  public float returnRotationFactor(float offset)
572
    {
573
    return 1.0f;
574
    }
575

    
576
///////////////////////////////////////////////////////////////////////////////////////////////////
577

    
578
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
579
    {
580
    int numAxis = ROTATION_AXIS.length;
581

    
582
    if( oldRotAxis == START_AXIS )
583
      {
584
      return rnd.nextInt(numAxis);
585
      }
586
    else
587
      {
588
      int newVector = rnd.nextInt(numAxis-1);
589
      return (newVector>=oldRotAxis ? newVector+1 : newVector);
590
      }
591
    }
592

    
593
///////////////////////////////////////////////////////////////////////////////////////////////////
594

    
595
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
596
    {
597
    float rowFloat = rnd.nextFloat();
598

    
599
    for(int row=0; row<mRowChances.length; row++)
600
      {
601
      if( rowFloat<=mRowChances[row] ) return row;
602
      }
603

    
604
    return 0;
605
    }
606

    
607
///////////////////////////////////////////////////////////////////////////////////////////////////
608
// remember about the double cover or unit quaternions!
609

    
610
  private int mulQuat(int q1, int q2)
611
    {
612
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
613

    
614
    float rX = result.get0();
615
    float rY = result.get1();
616
    float rZ = result.get2();
617
    float rW = result.get3();
618

    
619
    final float MAX_ERROR = 0.1f;
620
    float dX,dY,dZ,dW;
621

    
622
    for(int i=0; i<QUATS.length; i++)
623
      {
624
      dX = QUATS[i].get0() - rX;
625
      dY = QUATS[i].get1() - rY;
626
      dZ = QUATS[i].get2() - rZ;
627
      dW = QUATS[i].get3() - rW;
628

    
629
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
630
          dY<MAX_ERROR && dY>-MAX_ERROR &&
631
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
632
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
633

    
634
      dX = QUATS[i].get0() + rX;
635
      dY = QUATS[i].get1() + rY;
636
      dZ = QUATS[i].get2() + rZ;
637
      dW = QUATS[i].get3() + rW;
638

    
639
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
640
          dY<MAX_ERROR && dY>-MAX_ERROR &&
641
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
642
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
643
      }
644

    
645
    return -1;
646
    }
647

    
648
///////////////////////////////////////////////////////////////////////////////////////////////////
649
// The Skewb is solved if and only if:
650
//
651
// 1) all of its corner cubits are rotated with the same quat
652
// 2) all its face cubits are rotated with the same quat like the corner ones,
653
//    and optionally they also might be upside down.
654
//
655
// i.e.
656
// cubits [ 8] and [ 9] - might be extra QUAT[1]
657
// cubits [10] and [11] - might be extra QUAT[2]
658
// cubits [12] and [13] - might be extra QUAT[3]
659

    
660
  public boolean isSolved()
661
    {
662
    int q = CUBITS[0].mQuatIndex;
663

    
664
    if ( CUBITS[1].mQuatIndex == q &&
665
         CUBITS[2].mQuatIndex == q &&
666
         CUBITS[3].mQuatIndex == q &&
667
         CUBITS[4].mQuatIndex == q &&
668
         CUBITS[5].mQuatIndex == q &&
669
         CUBITS[6].mQuatIndex == q &&
670
         CUBITS[7].mQuatIndex == q  )
671
      {
672
      int q1 = mulQuat(q,1);
673
      int q2 = mulQuat(q,2);
674
      int q3 = mulQuat(q,3);
675

    
676
      return (CUBITS[ 8].mQuatIndex == q || CUBITS[ 8].mQuatIndex == q1) &&
677
             (CUBITS[ 9].mQuatIndex == q || CUBITS[ 9].mQuatIndex == q1) &&
678
             (CUBITS[10].mQuatIndex == q || CUBITS[10].mQuatIndex == q2) &&
679
             (CUBITS[11].mQuatIndex == q || CUBITS[11].mQuatIndex == q2) &&
680
             (CUBITS[12].mQuatIndex == q || CUBITS[12].mQuatIndex == q3) &&
681
             (CUBITS[13].mQuatIndex == q || CUBITS[13].mQuatIndex == q3)  ;
682
      }
683

    
684
    return false;
685
    }
686

    
687
///////////////////////////////////////////////////////////////////////////////////////////////////
688
// TODO  (only needed for solvers - there are no Skewb solvers ATM)
689

    
690
  public String retObjectString()
691
    {
692
    return "";
693
    }
694

    
695
}
(12-12/12)