Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikSkewb.java @ eab9d8f8

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
  // centers of the 8 corners + 6 sides ( i.e. of the all 14 cubits)
99
  private static final Static3D[] CENTERS = new Static3D[]
100
         {
101
           new Static3D( 0.5f, 0.5f, 0.5f ),
102
           new Static3D( 0.5f, 0.5f,-0.5f ),
103
           new Static3D( 0.5f,-0.5f, 0.5f ),
104
           new Static3D( 0.5f,-0.5f,-0.5f ),
105
           new Static3D(-0.5f, 0.5f, 0.5f ),
106
           new Static3D(-0.5f, 0.5f,-0.5f ),
107
           new Static3D(-0.5f,-0.5f, 0.5f ),
108
           new Static3D(-0.5f,-0.5f,-0.5f ),
109

    
110
           new Static3D( 0.49f, 0.0f, 0.0f ),
111
           new Static3D(-0.49f, 0.0f, 0.0f ),
112
           new Static3D( 0.0f, 0.49f, 0.0f ),
113
           new Static3D( 0.0f,-0.49f, 0.0f ),
114
           new Static3D( 0.0f, 0.0f, 0.49f ),
115
           new Static3D( 0.0f, 0.0f,-0.49f ),
116
         };
117

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

    
131
           { 6 , 12,12,12,12,12 },
132
           { 7 , 12,12,12,12,12 },
133
           { 8 , 12,12,12,12,12 },
134
           { 9 , 12,12,12,12,12 },
135
           { 10, 12,12,12,12,12 },
136
           { 11, 12,12,12,12,12 },
137
         };
138

    
139
  private static MeshBase mCornerMesh, mFaceMesh;
140

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142

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

    
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150

    
151
  private void createCornerMesh()
152
    {
153
    float D = 0.02f;
154
    float E = 0.5f;
155
    float F = SQ2/2;
156

    
157
    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
158

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

    
167
    MeshBase[] meshes = new MeshBase[FACES_PER_CUBIT];
168

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

    
176
    float[] vertices1 = { 0,0, F,0, F/2,(SQ3/2)*F };
177
    float[] bands1 = { 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f };
178

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

    
186
    mCornerMesh = new MeshJoined(meshes);
187

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

    
203
    float d0 =-0.04f;
204
    float d1 = 0.04f;
205
    float r0 = 0.15f;
206
    float r1 = 0.10f;
207

    
208
    Static3D vec0   = new Static3D(d0*(+SQ3/3),d0*(+SQ3/3),d0*(+SQ3/3));
209
    Static3D vec1   = new Static3D(d1*(+SQ3/3),d1*(-SQ3/3),d1*(-SQ3/3));
210
    Static3D vec2   = new Static3D(d1*(-SQ3/3),d1*(+SQ3/3),d1*(-SQ3/3));
211
    Static3D vec3   = new Static3D(d1*(-SQ3/3),d1*(-SQ3/3),d1*(+SQ3/3));
212

    
213
    Static1D radius = new Static1D(0.5f);
214

    
215
    Static3D cent0  = new Static3D( 0.0f, 0.0f, 0.0f);
216
    Static3D cent1  = new Static3D(-0.5f, 0.0f, 0.0f);
217
    Static3D cent2  = new Static3D( 0.0f,-0.5f, 0.0f);
218
    Static3D cent3  = new Static3D( 0.0f, 0.0f,-0.5f);
219

    
220
    Static4D reg0   = new Static4D(0,0,0,r0);
221
    Static4D reg1   = new Static4D(0,0,0,r1);
222

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

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

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

    
250
    effect10.setMeshAssociation(63,-1); // all meshes
251
    effect11.setMeshAssociation(63,-1); // all meshes
252
    effect12.setMeshAssociation(63,-1); // all meshes
253
    effect13.setMeshAssociation(63,-1); // all meshes
254

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

    
266
    mCornerMesh.apply(effect10);
267
    mCornerMesh.apply(effect11);
268
    mCornerMesh.apply(effect12);
269
    mCornerMesh.apply(effect13);
270

    
271
    mCornerMesh.mergeEffComponents();
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  private void createFaceMesh()
277
    {
278
    int association = 1;
279

    
280
    float D = 0.03f;
281
    float E = SQ2/4;
282
    float[] vertices0 = { -E,-E, +E,-E, +E,+E, -E,+E };
283

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

    
292
    MeshBase[] meshes = new MeshBase[FACES_PER_CUBIT];
293
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
294
    meshes[0].setEffectAssociation(0,association,0);
295

    
296
    association <<= 1;
297

    
298
    float[] vertices1 = { -E,-SQ3*E, +E,-SQ3*E, 0,0 };
299
    float[] bands1 = { 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f };
300

    
301
    meshes[1] = new MeshPolygon(vertices1,bands1,0,0);
302
    meshes[1].setEffectAssociation(0,association,0);
303

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

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

    
315
    mFaceMesh = new MeshJoined(meshes);
316

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

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

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

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

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

    
373
    mFaceMesh.mergeEffComponents();
374
    }
375

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

    
378
  float getScreenRatio()
379
    {
380
    return 1.0f;
381
    }
382

    
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384

    
385
  Static4D[] getQuats()
386
    {
387
    return QUATS;
388
    }
389

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

    
392
  int getNumFaces()
393
    {
394
    return FACE_COLORS.length;
395
    }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398
// Each face has two types of a texture: the central square and the triangle in the corner.
399

    
400
  int getNumStickerTypes()
401
    {
402
    return 2;
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  int getNumCubitFaces()
408
    {
409
    return FACES_PER_CUBIT;
410
    }
411

    
412
///////////////////////////////////////////////////////////////////////////////////////////////////
413

    
414
  Static3D[] getCubitPositions(int size)
415
    {
416
    return CENTERS;
417
    }
418

    
419
///////////////////////////////////////////////////////////////////////////////////////////////////
420

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

    
441
    return null;
442
    }
443

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

    
446
  MeshBase createCubitMesh(int cubit)
447
    {
448
    MeshBase mesh;
449

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

    
461
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
462
    mesh.apply(quat,0xffffffff,0);
463

    
464
    return mesh;
465
    }
466

    
467
///////////////////////////////////////////////////////////////////////////////////////////////////
468

    
469
  int getFaceColor(int cubit, int cubitface, int size)
470
    {
471
    return mFaceMap[cubit][cubitface];
472
    }
473

    
474
///////////////////////////////////////////////////////////////////////////////////////////////////
475

    
476
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
477
    {
478
    int COLORS = FACE_COLORS.length;
479

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

    
487
      paint.setAntiAlias(true);
488
      paint.setStrokeWidth(STROKE);
489
      paint.setColor(FACE_COLORS[face]);
490
      paint.setStyle(Paint.Style.FILL);
491

    
492
      canvas.drawRect(left,top,left+side,top+side,paint);
493

    
494
      paint.setColor(INTERIOR_COLOR);
495
      paint.setStyle(Paint.Style.STROKE);
496

    
497
      canvas.drawLine( L    , H,  L+LEN, H    , paint);
498
      canvas.drawLine( L    , H,  L+LEN, H+LEN, paint);
499
      canvas.drawLine( L+LEN, H,  L+LEN, H+LEN, paint);
500

    
501
      float S1 = 0.125f*side;
502
      float S2 = 0.070f*side;
503
      float X  = 0.7f*S2;
504

    
505
      float LA = left+0.625f*side;
506
      float RA = left+0.125f*side;
507
      float TA = 0.375f*side;
508
      float BA = 0.875f*side;
509

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

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

    
525
///////////////////////////////////////////////////////////////////////////////////////////////////
526

    
527
  float returnMultiplier()
528
    {
529
    return 2.0f;
530
    }
531

    
532
///////////////////////////////////////////////////////////////////////////////////////////////////
533

    
534
  float[] getRowChances()
535
    {
536
    float[] chances = new float[2];
537

    
538
    chances[0] = 0.5f;
539
    chances[1] = 1.0f;
540

    
541
    return chances;
542
    }
543

    
544
///////////////////////////////////////////////////////////////////////////////////////////////////
545
// PUBLIC API
546

    
547
  public Static3D[] getRotationAxis()
548
    {
549
    return ROT_AXIS;
550
    }
551

    
552
///////////////////////////////////////////////////////////////////////////////////////////////////
553

    
554
  public int getBasicAngle()
555
    {
556
    return 3;
557
    }
558

    
559
///////////////////////////////////////////////////////////////////////////////////////////////////
560

    
561
  public int computeRowFromOffset(float offset)
562
    {
563
    return offset<0.5f ? 0:1;
564
    }
565

    
566
///////////////////////////////////////////////////////////////////////////////////////////////////
567

    
568
  public float returnRotationFactor(float offset)
569
    {
570
    return 1.0f;
571
    }
572

    
573
///////////////////////////////////////////////////////////////////////////////////////////////////
574

    
575
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
576
    {
577
    int numAxis = ROTATION_AXIS.length;
578

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

    
590
///////////////////////////////////////////////////////////////////////////////////////////////////
591

    
592
  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
593
    {
594
    float rowFloat = rnd.nextFloat();
595

    
596
    for(int row=0; row<mRowChances.length; row++)
597
      {
598
      if( rowFloat<=mRowChances[row] ) return row;
599
      }
600

    
601
    return 0;
602
    }
603

    
604
///////////////////////////////////////////////////////////////////////////////////////////////////
605
// remember about the double cover or unit quaternions!
606

    
607
  private int mulQuat(int q1, int q2)
608
    {
609
    Static4D result = RubikSurfaceView.quatMultiply(QUATS[q1],QUATS[q2]);
610

    
611
    float rX = result.get0();
612
    float rY = result.get1();
613
    float rZ = result.get2();
614
    float rW = result.get3();
615

    
616
    final float MAX_ERROR = 0.1f;
617
    float dX,dY,dZ,dW;
618

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

    
626
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
627
          dY<MAX_ERROR && dY>-MAX_ERROR &&
628
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
629
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
630

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

    
636
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
637
          dY<MAX_ERROR && dY>-MAX_ERROR &&
638
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
639
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
640
      }
641

    
642
    return -1;
643
    }
644

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

    
657
  public boolean isSolved()
658
    {
659
    int q = CUBITS[0].mQuatIndex;
660

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

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

    
681
    return false;
682
    }
683

    
684
///////////////////////////////////////////////////////////////////////////////////////////////////
685
// TODO  (only needed for solvers - there are no Skewb solvers ATM)
686

    
687
  public String retObjectString()
688
    {
689
    return "";
690
    }
691

    
692
}
(12-12/12)