Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / RubikHelicopter.java @ ee35e63c

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.type.Static1D;
38
import org.distorted.library.type.Static3D;
39
import org.distorted.library.type.Static4D;
40
import org.distorted.main.RubikSurfaceView;
41

    
42
import java.util.Random;
43

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

    
46
///////////////////////////////////////////////////////////////////////////////////////////////////
47

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

    
53
  private static final int FACES_PER_CUBIT =6;
54

    
55
  // the six rotation axis of a Helicopter. Must be normalized.
56
  static final Static3D[] ROT_AXIS = new Static3D[]
57
         {
58
           new Static3D(     0, +SQ2/2, -SQ2/2),
59
           new Static3D(     0, -SQ2/2, -SQ2/2),
60
           new Static3D(+SQ2/2,      0, -SQ2/2),
61
           new Static3D(-SQ2/2,      0, -SQ2/2),
62
           new Static3D(+SQ2/2, -SQ2/2,      0),
63
           new Static3D(-SQ2/2, -SQ2/2,      0)
64
         };
65

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

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

    
81
  // All legal rotation quats of a HELICOPTER (same as the Cube!)
82
  private static final Static4D[] QUATS = new Static4D[]
83
         {
84
           new Static4D( 0.00f,  0.00f,  0.00f,  1.00f ),
85
           new Static4D( 1.00f,  0.00f,  0.00f,  0.00f ),
86
           new Static4D( 0.00f,  1.00f,  0.00f,  0.00f ),
87
           new Static4D( 0.00f,  0.00f,  1.00f,  0.00f ),
88

    
89
           new Static4D( SQ2/2,  SQ2/2,  0.00f,  0.00f ),
90
           new Static4D( SQ2/2, -SQ2/2,  0.00f,  0.00f ),
91
           new Static4D( SQ2/2,  0.00f,  SQ2/2,  0.00f ),
92
           new Static4D( SQ2/2,  0.00f, -SQ2/2,  0.00f ),
93
           new Static4D( SQ2/2,  0.00f,  0.00f,  SQ2/2 ),
94
           new Static4D( SQ2/2,  0.00f,  0.00f, -SQ2/2 ),
95
           new Static4D( 0.00f,  SQ2/2,  SQ2/2,  0.00f ),
96
           new Static4D( 0.00f,  SQ2/2, -SQ2/2,  0.00f ),
97
           new Static4D( 0.00f,  SQ2/2,  0.00f,  SQ2/2 ),
98
           new Static4D( 0.00f,  SQ2/2,  0.00f, -SQ2/2 ),
99
           new Static4D( 0.00f,  0.00f,  SQ2/2,  SQ2/2 ),
100
           new Static4D( 0.00f,  0.00f,  SQ2/2, -SQ2/2 ),
101

    
102
           new Static4D( 0.50f,  0.50f,  0.50f,  0.50f ),
103
           new Static4D( 0.50f,  0.50f,  0.50f, -0.50f ),
104
           new Static4D( 0.50f,  0.50f, -0.50f,  0.50f ),
105
           new Static4D( 0.50f,  0.50f, -0.50f, -0.50f ),
106
           new Static4D( 0.50f, -0.50f,  0.50f,  0.50f ),
107
           new Static4D( 0.50f, -0.50f,  0.50f, -0.50f ),
108
           new Static4D( 0.50f, -0.50f, -0.50f,  0.50f ),
109
           new Static4D( 0.50f, -0.50f, -0.50f, -0.50f )
110
         };
111

    
112
  private static final float DIST_CORNER = 0.50f;
113
  private static final float DIST_CENTER = 0.49f;
114
  private static final float XY_CENTER   = DIST_CORNER/3;
115

    
116
  // centers of the 8 corners + 6*4 face triangles ( i.e. of the all 32 cubits)
117
  private static final Static3D[] CENTERS = new Static3D[]
118
         {
119
           new Static3D(   DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
120
           new Static3D(   DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
121
           new Static3D(   DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
122
           new Static3D(   DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
123
           new Static3D(  -DIST_CORNER,   DIST_CORNER,   DIST_CORNER ),
124
           new Static3D(  -DIST_CORNER,   DIST_CORNER,  -DIST_CORNER ),
125
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,   DIST_CORNER ),
126
           new Static3D(  -DIST_CORNER,  -DIST_CORNER,  -DIST_CORNER ),
127

    
128
           new Static3D(   DIST_CENTER,     XY_CENTER,     XY_CENTER ),
129
           new Static3D(   DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
130
           new Static3D(   DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
131
           new Static3D(   DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
132

    
133
           new Static3D(  -DIST_CENTER,     XY_CENTER,     XY_CENTER ),
134
           new Static3D(  -DIST_CENTER,     XY_CENTER,    -XY_CENTER ),
135
           new Static3D(  -DIST_CENTER,    -XY_CENTER,     XY_CENTER ),
136
           new Static3D(  -DIST_CENTER,    -XY_CENTER,    -XY_CENTER ),
137

    
138
           new Static3D(   XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
139
           new Static3D(   XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
140
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,     XY_CENTER ),
141
           new Static3D(  -XY_CENTER  ,   DIST_CENTER,    -XY_CENTER ),
142

    
143
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
144
           new Static3D(   XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
145
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,     XY_CENTER ),
146
           new Static3D(  -XY_CENTER  ,  -DIST_CENTER,    -XY_CENTER ),
147

    
148
           new Static3D(   XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
149
           new Static3D(   XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
150
           new Static3D(  -XY_CENTER  ,     XY_CENTER,   DIST_CENTER ),
151
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,   DIST_CENTER ),
152

    
153
           new Static3D(   XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
154
           new Static3D(   XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
155
           new Static3D(  -XY_CENTER  ,     XY_CENTER,  -DIST_CENTER ),
156
           new Static3D(  -XY_CENTER  ,    -XY_CENTER,  -DIST_CENTER ),
157
         };
158

    
159
  // Colors of the faces of cubits. Each cubit has 6 faces
160
  private static final int[][] mFaceMap = new int[][]
161
         {
162
           { 4,2,0, 6,6,6 },
163
           { 2,5,0, 6,6,6 },
164
           { 3,4,0, 6,6,6 },
165
           { 5,3,0, 6,6,6 },
166
           { 1,2,4, 6,6,6 },
167
           { 5,2,1, 6,6,6 },
168
           { 4,3,1, 6,6,6 },
169
           { 1,3,5, 6,6,6 },
170

    
171
           { 0 , 6,6,6,6,6 },
172
           { 0 , 6,6,6,6,6 },
173
           { 0 , 6,6,6,6,6 },
174
           { 0 , 6,6,6,6,6 },
175

    
176
           { 1 , 6,6,6,6,6 },
177
           { 1 , 6,6,6,6,6 },
178
           { 1 , 6,6,6,6,6 },
179
           { 1 , 6,6,6,6,6 },
180

    
181
           { 2 , 6,6,6,6,6 },
182
           { 2 , 6,6,6,6,6 },
183
           { 2 , 6,6,6,6,6 },
184
           { 2 , 6,6,6,6,6 },
185

    
186
           { 3 , 6,6,6,6,6 },
187
           { 3 , 6,6,6,6,6 },
188
           { 3 , 6,6,6,6,6 },
189
           { 3 , 6,6,6,6,6 },
190

    
191
           { 4 , 6,6,6,6,6 },
192
           { 4 , 6,6,6,6,6 },
193
           { 4 , 6,6,6,6,6 },
194
           { 4 , 6,6,6,6,6 },
195

    
196
           { 5 , 6,6,6,6,6 },
197
           { 5 , 6,6,6,6,6 },
198
           { 5 , 6,6,6,6,6 },
199
           { 5 , 6,6,6,6,6 },
200
         };
201

    
202
  private static MeshBase mCornerMesh, mFaceMesh;
203

    
204
///////////////////////////////////////////////////////////////////////////////////////////////////
205

    
206
  RubikHelicopter(int size, Static4D quat, DistortedTexture texture,
207
                  MeshSquare mesh, DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
208
    {
209
    super(size, 60, quat, texture, mesh, effects, moves, RubikObjectList.HELI, res, scrWidth);
210
    }
211

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

    
214
  private void createCornerMesh()
215
    {
216
    float D = 0.02f;
217
    float E = 0.5f;
218
    float F = SQ2/4;
219

    
220
    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
221

    
222
    float[] bands0 = { 1.0f    , 0,
223
                       1.0f-2*D, D*0.25f,
224
                       1.0f-4*D, D*0.35f,
225
                       1.0f-8*D, D*0.6f,
226
                       0.60f   , D*1.0f,
227
                       0.30f   , D*1.375f,
228
                       0.0f    , D*1.4f };
229

    
230
    MeshBase[] meshes = new MeshBase[6];
231

    
232
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
233
    meshes[0].setEffectAssociation(0,1,0);
234
    meshes[1] = meshes[0].copy(true);
235
    meshes[1].setEffectAssociation(0,2,0);
236
    meshes[2] = meshes[0].copy(true);
237
    meshes[2].setEffectAssociation(0,4,0);
238

    
239
    float[] vertices1 = { -F,-1.0f/12, +F,-1.0f/12, 0,1.0f/6 };
240
    float[] bands1 = { 1.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f };
241

    
242
    meshes[3] = new MeshPolygon(vertices1,bands1,1,3);
243
    meshes[3].setEffectAssociation(0,8,0);
244
    meshes[4] = meshes[3].copy(true);
245
    meshes[4].setEffectAssociation(0,16,0);
246
    meshes[5] = meshes[3].copy(true);
247
    meshes[5].setEffectAssociation(0,32,0);
248

    
249
    mCornerMesh = new MeshJoined(meshes);
250

    
251
    Static3D axisX  = new Static3D(1,0,0);
252
    Static3D axisY  = new Static3D(0,1,0);
253
    Static3D axis0  = new Static3D(-SQ2/2,0,SQ2/2);
254
    Static3D axis1  = new Static3D(+SQ3/3,+SQ3/3,+SQ3/3);
255
    Static1D angle1 = new Static1D(+90);
256
    Static1D angle2 = new Static1D(-90);
257
    Static1D angle3 = new Static1D(-135);
258
    Static1D angle4 = new Static1D(90);
259
    Static1D angle5 = new Static1D(120);
260
    Static1D angle6 = new Static1D(240);
261
    Static3D center1= new Static3D(0,0,0);
262
    Static3D center2= new Static3D(-0.25f,-0.25f,-0.25f);
263
    Static3D move1  = new Static3D(-E/4,-E/4,0);
264
    Static3D move2  = new Static3D(-0.25f,(-1.0f/6)-0.25f,-0.25f);
265

    
266
    float d0 =-0.04f;
267
    float d1 = 0.04f;
268
    float r0 = 0.15f;
269
    float r1 = 0.10f;
270

    
271
    Static3D vec0   = new Static3D(d0*(+SQ3/3),d0*(+SQ3/3),d0*(+SQ3/3));
272
    Static3D vec1   = new Static3D(d1*(+SQ3/3),d1*(-SQ3/3),d1*(-SQ3/3));
273
    Static3D vec2   = new Static3D(d1*(-SQ3/3),d1*(+SQ3/3),d1*(-SQ3/3));
274
    Static3D vec3   = new Static3D(d1*(-SQ3/3),d1*(-SQ3/3),d1*(+SQ3/3));
275

    
276
    Static1D radius = new Static1D(0.5f);
277

    
278
    Static3D cent0  = new Static3D( 0.0f, 0.0f, 0.0f);
279
    Static3D cent1  = new Static3D(-0.5f, 0.0f, 0.0f);
280
    Static3D cent2  = new Static3D( 0.0f,-0.5f, 0.0f);
281
    Static3D cent3  = new Static3D( 0.0f, 0.0f,-0.5f);
282

    
283
    Static4D reg0   = new Static4D(0,0,0,r0);
284
    Static4D reg1   = new Static4D(0,0,0,r1);
285

    
286
    VertexEffectMove   effect0 = new VertexEffectMove(move1);
287
    VertexEffectScale  effect1 = new VertexEffectScale(new Static3D(1,1,-1));
288
    VertexEffectRotate effect2 = new VertexEffectRotate(angle1,axisX,center1);
289
    VertexEffectRotate effect3 = new VertexEffectRotate(angle2,axisY,center1);
290
    VertexEffectMove   effect4 = new VertexEffectMove(move2);
291
    VertexEffectRotate effect5 = new VertexEffectRotate(angle1,axisX,center2);
292
    VertexEffectRotate effect6 = new VertexEffectRotate(angle3,axisY,center2);
293
    VertexEffectRotate effect7 = new VertexEffectRotate(angle4,axis0,center2);
294
    VertexEffectRotate effect8 = new VertexEffectRotate(angle5,axis1,center2);
295
    VertexEffectRotate effect9 = new VertexEffectRotate(angle6,axis1,center2);
296

    
297
    VertexEffectDeform effect10= new VertexEffectDeform(vec0,radius,cent0,reg0);
298
    VertexEffectDeform effect11= new VertexEffectDeform(vec1,radius,cent1,reg1);
299
    VertexEffectDeform effect12= new VertexEffectDeform(vec2,radius,cent2,reg1);
300
    VertexEffectDeform effect13= new VertexEffectDeform(vec3,radius,cent3,reg1);
301

    
302
    effect0.setMeshAssociation( 7,-1);  // meshes 0,1,2
303
    effect1.setMeshAssociation( 6,-1);  // meshes 1,2
304
    effect2.setMeshAssociation( 2,-1);  // mesh 1
305
    effect3.setMeshAssociation( 4,-1);  // mesh 2
306
    effect4.setMeshAssociation(56,-1);  // meshes 3,4,5
307
    effect5.setMeshAssociation(56,-1);  // meshes 3,4,5
308
    effect6.setMeshAssociation(56,-1);  // meshes 3,4,5
309
    effect7.setMeshAssociation(56,-1);  // meshes 3,4,5
310
    effect8.setMeshAssociation(16,-1);  // mesh 4
311
    effect9.setMeshAssociation(32,-1);  // mesh 5
312

    
313
    effect10.setMeshAssociation(63,-1); // all meshes
314
    effect11.setMeshAssociation(63,-1); // all meshes
315
    effect12.setMeshAssociation(63,-1); // all meshes
316
    effect13.setMeshAssociation(63,-1); // all meshes
317

    
318
    mCornerMesh.apply(effect0);
319
    mCornerMesh.apply(effect1);
320
    mCornerMesh.apply(effect2);
321
    mCornerMesh.apply(effect3);
322
    mCornerMesh.apply(effect4);
323
    mCornerMesh.apply(effect5);
324
    mCornerMesh.apply(effect6);
325
    mCornerMesh.apply(effect7);
326
    mCornerMesh.apply(effect8);
327
    mCornerMesh.apply(effect9);
328

    
329
    mCornerMesh.apply(effect10);
330
    mCornerMesh.apply(effect11);
331
    mCornerMesh.apply(effect12);
332
    mCornerMesh.apply(effect13);
333

    
334
    mCornerMesh.mergeEffComponents();
335
    }
336

    
337
///////////////////////////////////////////////////////////////////////////////////////////////////
338

    
339
  private void createFaceMesh()
340
    {
341
    float D = 0.02f;
342
    float E = 0.5f;
343
    float F = SQ2/4;
344

    
345
    float[] vertices0 = { -E+E/4,E/4, E/4,-E+E/4, E/4,E/4};
346

    
347
    float[] bands0 = { 1.0f    , 0,
348
                       1.0f-2*D, D*0.25f,
349
                       1.0f-4*D, D*0.35f,
350
                       1.0f-8*D, D*0.6f,
351
                       0.60f   , D*1.0f,
352
                       0.30f   , D*1.375f,
353
                       0.0f    , D*1.4f };
354

    
355
    MeshBase[] meshes = new MeshBase[6];
356

    
357
    meshes[0] = new MeshPolygon(vertices0, bands0, 3, 3);
358
    meshes[0].setEffectAssociation(0,1,0);
359

    
360
    // TODO
361

    
362
    mFaceMesh.mergeEffComponents();
363
    }
364

    
365
///////////////////////////////////////////////////////////////////////////////////////////////////
366

    
367
  float getScreenRatio()
368
    {
369
    return 1.0f;
370
    }
371

    
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373

    
374
  Static4D[] getQuats()
375
    {
376
    return QUATS;
377
    }
378

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

    
381
  int getNumFaces()
382
    {
383
    return FACE_COLORS.length;
384
    }
385

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

    
388
  int getNumStickerTypes()
389
    {
390
    return 1;
391
    }
392

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

    
395
  int getNumCubitFaces()
396
    {
397
    return FACES_PER_CUBIT;
398
    }
399

    
400
///////////////////////////////////////////////////////////////////////////////////////////////////
401

    
402
  Static3D[] getCubitPositions(int size)
403
    {
404
    return CENTERS;
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408
// TODO
409

    
410
  private int getQuatIndex(int cubit)
411
    {
412
    switch(cubit)
413
      {
414
      case  0:
415
      case  1:
416
      case  2:
417
      case  3:
418
      case  4:
419
      case  5:
420
      case  6:
421
      case  7:
422
      case  8:
423
      case  9:
424
      case 10:
425
      case 11:
426
      case 12:
427
      case 13:
428
      case 14:
429
      case 15:
430
      case 16:
431
      case 17:
432
      case 18:
433
      case 19:
434
      case 20:
435
      case 21:
436
      case 22:
437
      case 23:
438
      case 24:
439
      case 25:
440
      case 26:
441
      case 27:
442
      case 28:
443
      case 29:
444
      case 30:
445
      case 31:
446
      }
447

    
448
    return -1;
449
    }
450

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

    
453
  MeshBase createCubitMesh(int cubit)
454
    {
455
    MeshBase mesh;
456

    
457
    if( cubit<8 )
458
      {
459
      if( mCornerMesh==null ) createCornerMesh();
460
      mesh = mCornerMesh.copy(true);
461
      }
462
    else
463
      {
464
      if( mFaceMesh==null ) createFaceMesh();
465
      mesh = mFaceMesh.copy(true);
466
      }
467

    
468
    int index = getQuatIndex(cubit);
469
    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[index], new Static3D(0,0,0) );
470
    mesh.apply(quat,0xffffffff,0);
471

    
472
    return mesh;
473
    }
474

    
475
///////////////////////////////////////////////////////////////////////////////////////////////////
476

    
477
  int getFaceColor(int cubit, int cubitface, int size)
478
    {
479
    return mFaceMap[cubit][cubitface];
480
    }
481

    
482
///////////////////////////////////////////////////////////////////////////////////////////////////
483

    
484
  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side)
485
    {
486
    float STROKE = 0.035f*side;
487
    float L= left+0.125f*side;
488
    float H= 0.375f*side;
489
    float LEN = 0.5f*side;
490

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

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

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

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

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

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

    
514
    canvas.drawArc( LA-S1, TA     , LA     , TA+S1, 270, 90, false, paint);
515
    canvas.drawArc( RA+X , TA     , RA+X+S2, TA+S2, 135,135, false, paint);
516
    canvas.drawArc( LA-S2, BA-X-S2, LA     , BA-X ,   0,135, false, paint);
517
    }
518

    
519
///////////////////////////////////////////////////////////////////////////////////////////////////
520

    
521
  float returnMultiplier()
522
    {
523
    return 2.0f;
524
    }
525

    
526
///////////////////////////////////////////////////////////////////////////////////////////////////
527

    
528
  float[] getRowChances()
529
    {
530
    float[] chances = new float[4];
531

    
532
    chances[0] = 0.5f;
533
    chances[1] = 0.5f;
534
    chances[2] = 0.5f;
535
    chances[3] = 1.0f;
536

    
537
    return chances;
538
    }
539

    
540
///////////////////////////////////////////////////////////////////////////////////////////////////
541
// PUBLIC API
542

    
543
  public Static3D[] getRotationAxis()
544
    {
545
    return ROT_AXIS;
546
    }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
  public int getBasicAngle()
551
    {
552
    return 2;
553
    }
554

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

    
557
  public int computeRowFromOffset(float offset)
558
    {
559
    return offset<0.25f ? 0:1;
560
    }
561

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

    
564
  public float returnRotationFactor(float offset)
565
    {
566
    return 1.0f;
567
    }
568

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

    
571
  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
572
    {
573
    int numAxis = ROTATION_AXIS.length;
574

    
575
    if( oldRotAxis == START_AXIS )
576
      {
577
      return rnd.nextInt(numAxis);
578
      }
579
    else
580
      {
581
      int newVector = rnd.nextInt(numAxis-2);
582

    
583
      switch(oldRotAxis)
584
        {
585
        case  0:
586
        case  1: return newVector+2;
587
        case  2:
588
        case  3: return (newVector==0 || newVector==1) ? newVector:newVector+2;
589
        default: return newVector;
590
        }
591
      }
592
    }
593

    
594
///////////////////////////////////////////////////////////////////////////////////////////////////
595

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

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

    
605
    return 0;
606
    }
607

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

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

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

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

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

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

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

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

    
646
    return -1;
647
    }
648

    
649
///////////////////////////////////////////////////////////////////////////////////////////////////
650
// The Helicopter is solved if and only if:
651
//
652
// 1) all of its corner cubits are rotated with the same quat
653
// 2) all its face cubits are rotated with the same quat like the corner ones,
654
//    and optionally they also might be turned by a multiple of 90 degrees along
655
//    a vector perpendicular to the face they lie on.
656
//
657
// i.e.
658
// cubits  8, 9,10,11,12,13,14,15 - might be extra QUAT 1,8,9
659
// cubits 16,17,18,19,20,21,22,23 - might be extra QUAT 2,12,13
660
// cubits 24,25,26,27,28,29,30,31 - might be extra QUAT 3,14,15
661

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

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

    
678
      for(int index=8; index<16; index++)
679
        {
680
        int qIndex = CUBITS[index].mQuatIndex;
681
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
682
        }
683

    
684
      q1 = mulQuat(q, 2);
685
      q2 = mulQuat(q,12);
686
      q3 = mulQuat(q,13);
687

    
688
      for(int index=16; index<24; index++)
689
        {
690
        int qIndex = CUBITS[index].mQuatIndex;
691
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
692
        }
693

    
694
      q1 = mulQuat(q, 3);
695
      q2 = mulQuat(q,14);
696
      q3 = mulQuat(q,15);
697

    
698
      for(int index=24; index<32; index++)
699
        {
700
        int qIndex = CUBITS[index].mQuatIndex;
701
        if( qIndex!=q && qIndex!=q1 && qIndex!=q2 && qIndex!=q3 ) return false;
702
        }
703

    
704
      return true;
705
      }
706

    
707
    return false;
708
    }
709

    
710
///////////////////////////////////////////////////////////////////////////////////////////////////
711
// only needed for solvers - there are no Helicopter solvers ATM)
712

    
713
  public String retObjectString()
714
    {
715
    return "";
716
    }
717

    
718
}
(4-4/14)