Project

General

Profile

« Previous | Next » 

Revision f16ff19d

Added by Leszek Koltunski over 4 years ago

Separate RubikCubit inner class.

View differences:

src/main/java/org/distorted/object/RubikCube.java
52 52
    private static final Static3D VectY = new Static3D(0,1,0);
53 53
    private static final Static3D VectZ = new Static3D(0,0,1);
54 54

  
55
    private DistortedNode[][][] mNodes;
56
    private MeshCubes[][][] mCubes;
57
    private DistortedEffects[][][] mEffects;
58
    private Static4D[][][] mQuatScramble;
59
    private Static3D[][][] mRotationAxis;
60
    private Dynamic1D[][][] mRotationAngle;
61
    private Static3D[][][] mCurrentPosition;
62
    private MatrixEffectRotate[][][] mRotateEffect;
55
    private static final Static3D matrCenter = new Static3D(0,0,0);
63 56

  
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65
// All legal rotation quats must have all four of their components equal to either
66
// 0, 1, -1, 0.5, -0.5 or +-sqrt(2)/2.
67
//
68
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
69
// correct the value of the 'scramble' quat to what it should be.
70
//
71
// We also have to remember that the group of unit quaternions is a double-cover of rotations
72
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
57
    /////////////////////////////////////////////////////////////////////////////////
73 58

  
74
    private static final float SQ2 = 0.5f*((float)Math.sqrt(2));
75
    private static final float[] LEGAL = { 0.0f , 0.5f , -0.5f , 1.0f , -1.0f , SQ2 , -SQ2 };
76

  
77
    private void normalizeScrambleQuat(int i, int j, int k)
59
    private class Cubit
78 60
      {
79
      Static4D quat = mQuatScramble[i][j][k];
61
      private final Static3D mOrigPosition;
62

  
63
      DistortedNode mNode;
64
      MeshCubes mCube;
65
      DistortedEffects mEffect;
66
      Static4D mQuatScramble;
67
      Static3D mRotationAxis;
68
      Dynamic1D mRotationAngle;
69
      Static3D mCurrentPosition;
80 70

  
81
      float x = quat.get0();
82
      float y = quat.get1();
83
      float z = quat.get2();
84
      float w = quat.get3();
85
      float diff;
71
      MatrixEffectRotate mRotateEffect;
86 72

  
87
      for(float legal: LEGAL)
73
    /////////////////////////////////////////////////////////////////////////////////
74

  
75
      Cubit(MeshCubes mesh,Static3D vector, Static3D position)
88 76
        {
89
        diff = x-legal;
90
        if( diff*diff<0.01f ) x = legal;
91
        diff = y-legal;
92
        if( diff*diff<0.01f ) y = legal;
93
        diff = z-legal;
94
        if( diff*diff<0.01f ) z = legal;
95
        diff = w-legal;
96
        if( diff*diff<0.01f ) w = legal;
77
        mOrigPosition = new Static3D( position.get0(), position.get1(), position.get2() );
78

  
79
        mCube = mesh;
80
        mQuatScramble    = new Static4D(0,0,0,1);
81
        mRotationAngle   = new Dynamic1D();
82
        mRotationAxis    = new Static3D(1,0,0);
83
        mCurrentPosition = position;
84
        mRotateEffect    = new MatrixEffectRotate(mRotationAngle, mRotationAxis, matrCenter);
85

  
86
        mEffect = new DistortedEffects();
87
        mEffect.apply(mSinkEffect);
88
        mEffect.apply( new MatrixEffectMove(vector) );
89
        mEffect.apply( new MatrixEffectQuaternion(mQuatScramble, matrCenter));
90
        mEffect.apply(mRotateEffect);
91
        mEffect.apply(mQuatAEffect);
92
        mEffect.apply(mQuatCEffect);
93
        mEffect.apply(mScaleEffect);
94
        mEffect.apply(mMoveEffect);
95

  
96
        mNode = new DistortedNode(mTexture,mEffect,mCube);
97 97
        }
98 98

  
99
      if( w<0 )
99
    /////////////////////////////////////////////////////////////////////////////////
100

  
101
      void savePreferences(SharedPreferences.Editor editor)
100 102
        {
101
        w = -w;
102
        z = -z;
103
        y = -y;
104
        x = -x;
103
        String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
104

  
105
        editor.putFloat("qx_"+number, mQuatScramble.get0());
106
        editor.putFloat("qy_"+number, mQuatScramble.get1());
107
        editor.putFloat("qz_"+number, mQuatScramble.get2());
108
        editor.putFloat("qw_"+number, mQuatScramble.get3());
105 109
        }
106
      else if( w==0 )
110

  
111
    /////////////////////////////////////////////////////////////////////////////////
112

  
113
      void restorePreferences(SharedPreferences preferences)
107 114
        {
108
        if( z<0 )
115
        String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
116

  
117
        float qx = preferences.getFloat("qx_"+number, 0.0f);
118
        float qy = preferences.getFloat("qy_"+number, 0.0f);
119
        float qz = preferences.getFloat("qz_"+number, 0.0f);
120
        float qw = preferences.getFloat("qw_"+number, 1.0f);
121

  
122
        mQuatScramble.set(qx,qy,qz,qw);
123
        modifyCurrentPosition( mCurrentPosition, mQuatScramble);
124
        }
125

  
126
    /////////////////////////////////////////////////////////////////////////////////
127

  
128
      long finishRotationNow(EffectListener listener)
129
        {
130
        int pointNum = mRotationAngle.getNumPoints();
131

  
132
        if( pointNum>=1 )
109 133
          {
110
          z = -z;
111
          y = -y;
112
          x = -x;
134
          float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
135
          int nearestAngleInDegrees = computeNearestAngle(startingAngle);
136
          mRotationAngleStatic.set0(startingAngle);
137
          mRotationAngleFinal.set0(nearestAngleInDegrees);
138
          mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
139
          return setUpCallback(listener);
113 140
          }
114
        else if( z==0 )
141
        else
115 142
          {
116
          if( y<0 )
117
            {
118
            y = -y;
119
            x = -x;
120
            }
121
          else if( y==0 )
122
            {
123
            if( x<0 )
124
              {
125
              x = -x;
126
              }
127
            }
143
          return 0;
128 144
          }
129 145
        }
130 146

  
131
      mQuatScramble[i][j][k].set(x,y,z,w);
132
      }
147
    /////////////////////////////////////////////////////////////////////////////////
133 148

  
134
///////////////////////////////////////////////////////////////////////////////////////////////////
149
      Static4D returnRotationQuat(float qx,float qy,float qz)
150
        {
151
        int pointNum = mRotationAngle.getNumPoints();
135 152

  
136
    private boolean belongsToRotation(int x, int y, int z, int vector, int row)
137
      {
138
      switch(vector)
153
        if( pointNum>=1 )
154
          {
155
          float startingAngle = mRotationAngle.getPoint(pointNum-1).get0();
156
          int nearestAngleInDegrees = computeNearestAngle(startingAngle);
157
          double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
158
          float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
159
          float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
160
          return new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
161
          }
162
        else
163
          {
164
          return null;
165
          }
166
        }
167

  
168
    /////////////////////////////////////////////////////////////////////////////////
169

  
170
      void removeRotationNow(Static4D quat)
139 171
        {
140
        case VECTX: return mCurrentPosition[x][y][z].get0()==row;
141
        case VECTY: return mCurrentPosition[x][y][z].get1()==row;
142
        case VECTZ: return mCurrentPosition[x][y][z].get2()==row;
172
        mRotationAngle.removeAll();
173
        mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
174
        normalizeScrambleQuat( mQuatScramble );
175
        modifyCurrentPosition( mCurrentPosition,quat);
143 176
        }
144 177

  
145
      return false;
178
    /////////////////////////////////////////////////////////////////////////////////
179

  
180
      void releaseResources()
181
        {
182
        mCube.markForDeletion();
183
        mNode.markForDeletion();
184
        }
185

  
186
    /////////////////////////////////////////////////////////////////////////////////
187

  
188
      void solve()
189
        {
190
        mQuatScramble.set(0,0,0,1);
191
        mCurrentPosition.set(mOrigPosition);
192
        }
193

  
194
    /////////////////////////////////////////////////////////////////////////////////
195

  
196
      void beginNewRotation(Static3D axis)
197
        {
198
        mRotationAxis.set(axis);
199
        mRotationAngle.add(mRotationAngleStatic);
200
        }
201

  
202
    /////////////////////////////////////////////////////////////////////////////////
203

  
204
      void addNewRotation(Static3D axis, long durationMillis, int angle)
205
        {
206
        mRotationAxis.set(axis);
207
        mRotationAngle.setDuration(durationMillis);
208
        mRotationAngle.resetToBeginning();
209
        mRotationAngle.add(new Static1D(0));
210
        mRotationAngle.add(new Static1D(angle));
211
        }
212

  
213

  
214
    /////////////////////////////////////////////////////////////////////////////////
215

  
216
      long setUpCallback(EffectListener listener)
217
        {
218
        mRotateEffect.notifyWhenFinished(listener);
219
        return mRotateEffect.getID();
220
        }
146 221
      }
147 222

  
223
    private Cubit[][][] mCubits;
224

  
148 225
///////////////////////////////////////////////////////////////////////////////////////////////////
226
// All legal rotation quats must have all four of their components equal to either
227
// 0, 1, -1, 0.5, -0.5 or +-sqrt(2)/2.
149 228

  
150
    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
229
    float[] getLegalQuats()
151 230
      {
152
      Static3D current = mCurrentPosition[x][y][z];
153
      float diff = 0.5f*(mSize-1);
154
      float cubitCenterX = current.get0() - diff;
155
      float cubitCenterY = current.get1() - diff;
156
      float cubitCenterZ = current.get2() - diff;
157

  
158
      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
159
      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
160

  
161
      float rotatedX = rotatedCenter.get0() + diff;
162
      float rotatedY = rotatedCenter.get1() + diff;
163
      float rotatedZ = rotatedCenter.get2() + diff;
164

  
165
      int roundedX = (int)(rotatedX+0.1f);
166
      int roundedY = (int)(rotatedY+0.1f);
167
      int roundedZ = (int)(rotatedZ+0.1f);
168

  
169
      mCurrentPosition[x][y][z].set0(roundedX);
170
      mCurrentPosition[x][y][z].set1(roundedY);
171
      mCurrentPosition[x][y][z].set2(roundedZ);
231
      final float SQ2 = 0.5f*((float)Math.sqrt(2));
232
      return new float[] { 0.0f , 0.5f , -0.5f , 1.0f , -1.0f , SQ2 , -SQ2 };
233
      }
234

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

  
237
    private boolean belongsToRotation( Static3D currentPosition, int vector, int row)
238
      {
239
      switch(vector)
240
        {
241
        case VECTX: return currentPosition.get0()==row;
242
        case VECTY: return currentPosition.get1()==row;
243
        case VECTZ: return currentPosition.get2()==row;
244
        }
245

  
246
      return false;
172 247
      }
173 248

  
174 249
///////////////////////////////////////////////////////////////////////////////////////////////////
......
179 254

  
180 255
      mRotAxis = VECTX;
181 256
      mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
182

  
183
      mNodes          = new DistortedNode[mSize][mSize][mSize];
184
      mCubes          = new MeshCubes[mSize][mSize][mSize];
185
      mEffects        = new DistortedEffects[mSize][mSize][mSize];
186
      mQuatScramble   = new Static4D[mSize][mSize][mSize];
187
      mRotationAxis   = new Static3D[mSize][mSize][mSize];
188
      mRotationAngle  = new Dynamic1D[mSize][mSize][mSize];
189
      mCurrentPosition= new Static3D[mSize][mSize][mSize];
190
      mRotateEffect   = new MatrixEffectRotate[mSize][mSize][mSize];
191

  
192
      Static3D[][][] cubeVectors = new Static3D[mSize][mSize][mSize];
193
      Static3D matrCenter = new Static3D(0,0,0);
257
      mCubits  = new Cubit[mSize][mSize][mSize];
194 258

  
195 259
      // 3x2 bitmap = 6 squares:
196 260
      //
......
229 293
              tmpTop   = (y== mSize-1 ? mapTop   :mapBlack);
230 294
              tmpBottom= (y==       0 ? mapBottom:mapBlack);
231 295

  
232
              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
233
              cubeVectors[x][y][z]      = new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) );
234
              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
235
              mRotationAngle[x][y][z]   = new Dynamic1D();
236
              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
237
              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
238
              mRotateEffect[x][y][z]    = new MatrixEffectRotate(mRotationAngle[x][y][z], mRotationAxis[x][y][z], matrCenter);
239

  
240
              mEffects[x][y][z] = new DistortedEffects();
241
              mEffects[x][y][z].apply(mSinkEffect);
242
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
243
              mEffects[x][y][z].apply( new MatrixEffectQuaternion(mQuatScramble[x][y][z], matrCenter));
244
              mEffects[x][y][z].apply(mRotateEffect[x][y][z]);
245
              mEffects[x][y][z].apply(mQuatAEffect);
246
              mEffects[x][y][z].apply(mQuatCEffect);
247
              mEffects[x][y][z].apply(mScaleEffect);
248
              mEffects[x][y][z].apply(mMoveEffect);
249

  
250
              mNodes[x][y][z] = new DistortedNode(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
251

  
252
              attach(mNodes[x][y][z]);
296
              mCubits[x][y][z] = new Cubit(new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom),
297
                                           new Static3D( TEXTURE_SIZE*(x-nc), TEXTURE_SIZE*(y-nc), TEXTURE_SIZE*(z-nc) ),
298
                                           new Static3D(x,y,z) );
299

  
300
              attach(mCubits[x][y][z].mNode);
253 301
              }
254 302
            }
255 303
      }
......
261 309

  
262 310
   public void savePreferences(SharedPreferences.Editor editor)
263 311
     {
264
     float qx,qy,qz,qw;
265

  
266 312
     for(int x=0; x<mSize; x++)
267 313
        for(int y=0; y<mSize; y++)
268 314
          for(int z=0; z<mSize; z++)
269 315
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
270 316
              {
271
              qx = mQuatScramble[x][y][z].get0();
272
              qy = mQuatScramble[x][y][z].get1();
273
              qz = mQuatScramble[x][y][z].get2();
274
              qw = mQuatScramble[x][y][z].get3();
275

  
276
              editor.putFloat("qx_"+x+"_"+y+"_"+z, qx);
277
              editor.putFloat("qy_"+x+"_"+y+"_"+z, qy);
278
              editor.putFloat("qz_"+x+"_"+y+"_"+z, qz);
279
              editor.putFloat("qw_"+x+"_"+y+"_"+z, qw);
317
              mCubits[x][y][z].savePreferences(editor);
280 318
              }
281 319
     }
282 320

  
......
284 322

  
285 323
   public void restorePreferences(SharedPreferences preferences)
286 324
     {
287
     float qx,qy,qz,qw;
288

  
289 325
     for(int x=0; x<mSize; x++)
290 326
        for(int y=0; y<mSize; y++)
291 327
          for(int z=0; z<mSize; z++)
292 328
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
293 329
              {
294
              qx = preferences.getFloat("qx_"+x+"_"+y+"_"+z, 0.0f);
295
              qy = preferences.getFloat("qy_"+x+"_"+y+"_"+z, 0.0f);
296
              qz = preferences.getFloat("qz_"+x+"_"+y+"_"+z, 0.0f);
297
              qw = preferences.getFloat("qw_"+x+"_"+y+"_"+z, 1.0f);
298

  
299
              mQuatScramble[x][y][z].set(qx,qy,qz,qw);
300
              modifyCurrentPosition(x, y, z, mQuatScramble[x][y][z]);
330
              mCubits[x][y][z].restorePreferences(preferences);
301 331
              }
302 332
     }
303 333

  
......
313 343
         for(int z=0; z<mSize; z++)
314 344
           if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
315 345
             {
316
             if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
346
             if( belongsToRotation(mCubits[x][y][z].mCurrentPosition,mRotAxis,mRotRow) )
317 347
               {
318 348
               if( first )
319 349
                 {
320 350
                 first = false;
321
                 mRotateEffect[x][y][z].notifyWhenFinished(listener);
322
                 effectID = mRotateEffect[x][y][z].getID();
323
                 int pointNum = mRotationAngle[x][y][z].getNumPoints();
324

  
325
                 if( pointNum>=1 )
326
                   {
327
                   float startingAngle = mRotationAngle[x][y][z].getPoint(pointNum-1).get0();
328
                   int nearestAngleInDegrees = computeNearestAngle(startingAngle);
329
                   mRotationAngleStatic.set0(startingAngle);
330
                   mRotationAngleFinal.set0(nearestAngleInDegrees);
331
                   mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-startingAngle)*0.2f );
332
                   }
333
                 else
334
                   {
335
                   android.util.Log.e("cube", "ERROR finishing rotation!");
336
                   return 0;
337
                   }
351
                 effectID = mCubits[x][y][z].finishRotationNow(listener);
338 352
                 }
339 353

  
340
               mRotationAngle[x][y][z].setDuration(POST_ROTATION_MILLISEC);
341
               mRotationAngle[x][y][z].resetToBeginning();
342
               mRotationAngle[x][y][z].removeAll();
343
               mRotationAngle[x][y][z].add(mRotationAngleStatic);
344
               mRotationAngle[x][y][z].add(mRotationAngleMiddle);
345
               mRotationAngle[x][y][z].add(mRotationAngleFinal);
354
               resetRotationAngle(mCubits[x][y][z].mRotationAngle);
346 355
               }
347 356
             }
348 357

  
......
364 373
           {
365 374
           if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
366 375
             {
367
             mCubes[x][y][z].markForDeletion();
368
             mNodes[x][y][z].markForDeletion();
376
             mCubits[x][y][z].releaseResources();
369 377
             }
370 378
           }
371 379
     }
......
424 432
           {
425 433
           if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
426 434
             {
427
             mEffects[x][y][z].apply(effect, position);
435
             mCubits[x][y][z].mEffect.apply(effect, position);
428 436
             }
429 437
           }
430 438
      }
......
439 447
           {
440 448
           if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
441 449
             {
442
             mEffects[x][y][z].abortById(effectID);
450
             mCubits[x][y][z].mEffect.abortById(effectID);
443 451
             }
444 452
           }
445 453
      }
......
453 461
         for(int z=0; z<mSize; z++)
454 462
           if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
455 463
             {
456
             mQuatScramble[x][y][z].set(0,0,0,1);
457
             mCurrentPosition[x][y][z].set(x,y,z);
464
             mCubits[x][y][z].solve();
458 465
             }
459 466
      }
460 467

  
......
462 469

  
463 470
   public boolean isSolved()
464 471
     {
465
     Static4D q = mQuatScramble[0][0][0];
472
     Static4D q = mCubits[0][0][0].mQuatScramble;
466 473

  
467 474
     float x = q.get0();
468 475
     float y = q.get1();
......
475 482
           {
476 483
           if( i==0 || i==mSize-1 || j==0 || j==mSize-1 || k==0 || k==mSize-1 )
477 484
             {
478
             q = mQuatScramble[i][j][k];
485
             q = mCubits[i][j][k].mQuatScramble;
479 486

  
480 487
             if( q.get0()!=x || q.get1()!=y || q.get2()!=z || q.get3()!=w )
481 488
               {
......
510 517
         for(int z=0; z<mSize; z++)
511 518
           if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
512 519
             {
513
             if( belongsToRotation(x,y,z,vector,mRotRow) )
520
             if( belongsToRotation( mCubits[x][y][z].mCurrentPosition,vector,mRotRow) )
514 521
               {
515
               mRotationAxis[x][y][z].set(axis);
516
               mRotationAngle[x][y][z].add(mRotationAngleStatic);
522
               mCubits[x][y][z].beginNewRotation(axis);
517 523
               }
518 524
             }
519 525
     }
......
543 549
          for(int z=0; z<mSize; z++)
544 550
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
545 551
              {
546
              if( belongsToRotation(x,y,z,vector,mRotRow) )
552
              if( belongsToRotation(mCubits[x][y][z].mCurrentPosition,vector,mRotRow) )
547 553
                {
548
                mRotationAxis[x][y][z].set(axis);
549
                mRotationAngle[x][y][z].setDuration(durationMillis);
550
                mRotationAngle[x][y][z].resetToBeginning();
551
                mRotationAngle[x][y][z].add(new Static1D(0));
552
                mRotationAngle[x][y][z].add(new Static1D(angle));
554
                mCubits[x][y][z].addNewRotation(axis,durationMillis,angle);
553 555

  
554 556
                if( first )
555 557
                  {
556 558
                  first = false;
557
                  effectID = mRotateEffect[x][y][z].getID();
558
                  mRotateEffect[x][y][z].notifyWhenFinished(listener);
559
                  effectID = mCubits[x][y][z].setUpCallback(listener);
559 560
                  }
560 561
                }
561 562
              }
......
583 584
          for(int z=0; z<mSize; z++)
584 585
            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
585 586
              {
586
              if( belongsToRotation(x,y,z,mRotAxis,mRotRow) )
587
              if( belongsToRotation(mCubits[x][y][z].mCurrentPosition,mRotAxis,mRotRow) )
587 588
                {
588 589
                if( first )
589 590
                  {
590 591
                  first = false;
591
                  int pointNum = mRotationAngle[x][y][z].getNumPoints();
592

  
593
                  if( pointNum>=1 )
594
                    {
595
                    float startingAngle = mRotationAngle[x][y][z].getPoint(pointNum-1).get0();
596
                    int nearestAngleInDegrees = computeNearestAngle(startingAngle);
597
                    double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
598
                    float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
599
                    float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
600
                    quat = new Static4D(qx*sinA, qy*sinA, qz*sinA, cosA);
601
                    }
602
                  else
603
                    {
604
                    android.util.Log.e("cube", "ERROR removing rotation!");
605
                    return;
606
                    }
592
                  quat = mCubits[x][y][z].returnRotationQuat(qx,qy,qz);
607 593
                  }
608 594

  
609
                mRotationAngle[x][y][z].removeAll();
610
                mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
611
                normalizeScrambleQuat(x,y,z);
612
                modifyCurrentPosition(x,y,z,quat);
595
                mCubits[x][y][z].removeRotationNow(quat);
613 596
                }
614 597
              }
615 598

  
src/main/java/org/distorted/object/RubikObject.java
31 31
import org.distorted.library.main.DistortedTexture;
32 32
import org.distorted.library.mesh.MeshRectangles;
33 33
import org.distorted.library.message.EffectListener;
34
import org.distorted.library.type.Dynamic1D;
34 35
import org.distorted.library.type.Static1D;
35 36
import org.distorted.library.type.Static3D;
36 37
import org.distorted.library.type.Static4D;
38
import org.distorted.magic.RubikSurfaceView;
37 39

  
38 40
///////////////////////////////////////////////////////////////////////////////////////////////////
39 41

  
40 42
public abstract class RubikObject extends DistortedNode
41 43
  {
42 44
  static final float OBJECT_SCREEN_RATIO = 0.5f;
43
  static final int POST_ROTATION_MILLISEC = 500;
44 45
  static final int TEXTURE_SIZE = 100;
45 46

  
47
  private static final int POST_ROTATION_MILLISEC = 500;
48
  private final float[] LEGAL_QUATS;
49

  
46 50
  private Static3D mMove, mScale, mNodeMove, mNodeScale;
47 51
  private Static4D mQuatAccumulated;
48 52
  private DistortedTexture mNodeTexture;
......
64 68
    {
65 69
    super(texture,effects,mesh);
66 70

  
71
    LEGAL_QUATS = getLegalQuats();
67 72
    mNodeTexture = texture;
68

  
69 73
    mSize = size;
70 74

  
71 75
    mRotationAngleStatic = new Static1D(0);
......
96 100
    effects.apply(nodeMoveEffect);
97 101
    }
98 102

  
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
105
// correct the value of the 'scramble' quat to what it should be - one of the legal quats from the
106
// list LEGAL_QUATS.
107
//
108
// We also have to remember that the group of unit quaternions is a double-cover of rotations
109
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
110

  
111
    void normalizeScrambleQuat(Static4D quat)
112
      {
113
      float x = quat.get0();
114
      float y = quat.get1();
115
      float z = quat.get2();
116
      float w = quat.get3();
117
      float diff;
118

  
119
      for(float legal: LEGAL_QUATS)
120
        {
121
        diff = x-legal;
122
        if( diff*diff<0.01f ) x = legal;
123
        diff = y-legal;
124
        if( diff*diff<0.01f ) y = legal;
125
        diff = z-legal;
126
        if( diff*diff<0.01f ) z = legal;
127
        diff = w-legal;
128
        if( diff*diff<0.01f ) w = legal;
129
        }
130

  
131
      if( w<0 )
132
        {
133
        w = -w;
134
        z = -z;
135
        y = -y;
136
        x = -x;
137
        }
138
      else if( w==0 )
139
        {
140
        if( z<0 )
141
          {
142
          z = -z;
143
          y = -y;
144
          x = -x;
145
          }
146
        else if( z==0 )
147
          {
148
          if( y<0 )
149
            {
150
            y = -y;
151
            x = -x;
152
            }
153
          else if( y==0 )
154
            {
155
            if( x<0 )
156
              {
157
              x = -x;
158
              }
159
            }
160
          }
161
        }
162

  
163
      quat.set(x,y,z,w);
164
      }
165

  
99 166
///////////////////////////////////////////////////////////////////////////////////////////////////
100 167

  
101 168
  int computeNearestAngle(float angle)
......
108 175
    return NEAREST*tmp;
109 176
    }
110 177

  
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

  
180
  void resetRotationAngle(Dynamic1D rotationAngle)
181
    {
182
    rotationAngle.setDuration(POST_ROTATION_MILLISEC);
183
    rotationAngle.resetToBeginning();
184
    rotationAngle.removeAll();
185
    rotationAngle.add(mRotationAngleStatic);
186
    rotationAngle.add(mRotationAngleMiddle);
187
    rotationAngle.add(mRotationAngleFinal);
188
    }
189

  
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191

  
192
  void modifyCurrentPosition(Static3D currentPosition, Static4D quat)
193
    {
194
    float diff = 0.5f*(mSize-1);
195
    float cubitCenterX = currentPosition.get0() - diff;
196
    float cubitCenterY = currentPosition.get1() - diff;
197
    float cubitCenterZ = currentPosition.get2() - diff;
198

  
199
    Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
200
    Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
201

  
202
    float rotatedX = rotatedCenter.get0() + diff;
203
    float rotatedY = rotatedCenter.get1() + diff;
204
    float rotatedZ = rotatedCenter.get2() + diff;
205

  
206
    int roundedX = (int)(rotatedX+0.1f);
207
    int roundedY = (int)(rotatedY+0.1f);
208
    int roundedZ = (int)(rotatedZ+0.1f);
209

  
210
    currentPosition.set(roundedX, roundedY, roundedZ);
211
    }
212

  
111 213
///////////////////////////////////////////////////////////////////////////////////////////////////
112 214

  
113 215
  private float getSinkStrength()
......
173 275

  
174 276
///////////////////////////////////////////////////////////////////////////////////////////////////
175 277

  
278
  abstract float[] getLegalQuats();
279

  
176 280
  public abstract void savePreferences(SharedPreferences.Editor editor);
177 281
  public abstract void restorePreferences(SharedPreferences preferences);
178 282

  

Also available in: Unified diff