Project

General

Profile

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

magiccube / src / main / java / org / distorted / objects / Cubit.java @ f8ce34ab

1 70b76549 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 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 1f9772f3 Leszek Koltunski
package org.distorted.objects;
21 70b76549 Leszek Koltunski
22
import android.content.SharedPreferences;
23
24 f8ce34ab Leszek Koltunski
import com.google.firebase.crashlytics.FirebaseCrashlytics;
25
26 70b76549 Leszek Koltunski
import org.distorted.library.effect.MatrixEffectMove;
27
import org.distorted.library.effect.MatrixEffectQuaternion;
28
import org.distorted.library.effect.MatrixEffectRotate;
29
import org.distorted.library.main.DistortedEffects;
30
import org.distorted.library.main.DistortedNode;
31 b32444ee Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
32 70b76549 Leszek Koltunski
import org.distorted.library.message.EffectListener;
33
import org.distorted.library.type.Dynamic1D;
34
import org.distorted.library.type.Static1D;
35
import org.distorted.library.type.Static3D;
36
import org.distorted.library.type.Static4D;
37 1f9772f3 Leszek Koltunski
import org.distorted.main.RubikSurfaceView;
38 70b76549 Leszek Koltunski
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40
41
class Cubit
42
  {
43 001cc0e4 Leszek Koltunski
  private static final int POST_ROTATION_MILLISEC = 500;
44 70b76549 Leszek Koltunski
  private static final Static3D matrCenter = new Static3D(0,0,0);
45
46
  private final Static3D mOrigPosition;
47
48
  private RubikObject mParent;
49 b32444ee Leszek Koltunski
  private MeshBase mMesh;
50 70b76549 Leszek Koltunski
  private Static3D mRotationAxis;
51
  private MatrixEffectRotate mRotateEffect;
52 0e7bcfb1 Leszek Koltunski
  private Static3D mCurrentPosition;
53 e844c116 Leszek Koltunski
  private int mNumAxis;
54 001cc0e4 Leszek Koltunski
  private Dynamic1D mRotationAngle;
55 70b76549 Leszek Koltunski
56
  DistortedNode mNode;
57
  DistortedEffects mEffect;
58
  Static4D mQuatScramble;
59 66cbdd21 Leszek Koltunski
  float[] mRotationRow;
60 70b76549 Leszek Koltunski
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
63
// correct the value of the 'scramble' quat to what it should be - one of the legal quats from the
64
// list LEGAL_QUATS.
65
//
66
// We also have to remember that the group of unit quaternions is a double-cover of rotations
67
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
68
69
  private void normalizeScrambleQuat(Static4D quat)
70
    {
71 9f4c44fe Leszek Koltunski
    final float MAX_ERROR = 0.0001f;
72
73 70b76549 Leszek Koltunski
    float x = quat.get0();
74
    float y = quat.get1();
75
    float z = quat.get2();
76
    float w = quat.get3();
77
    float diff;
78
79
    for(float legal: mParent.LEGAL_QUATS)
80
      {
81
      diff = x-legal;
82 9f4c44fe Leszek Koltunski
      if( diff*diff<MAX_ERROR ) x = legal;
83 70b76549 Leszek Koltunski
      diff = y-legal;
84 9f4c44fe Leszek Koltunski
      if( diff*diff<MAX_ERROR ) y = legal;
85 70b76549 Leszek Koltunski
      diff = z-legal;
86 9f4c44fe Leszek Koltunski
      if( diff*diff<MAX_ERROR ) z = legal;
87 70b76549 Leszek Koltunski
      diff = w-legal;
88 9f4c44fe Leszek Koltunski
      if( diff*diff<MAX_ERROR ) w = legal;
89 70b76549 Leszek Koltunski
      }
90
91
    if( w<0 )
92
      {
93
      w = -w;
94
      z = -z;
95
      y = -y;
96
      x = -x;
97
      }
98
    else if( w==0 )
99
      {
100
      if( z<0 )
101
        {
102
        z = -z;
103
        y = -y;
104
        x = -x;
105
        }
106
      else if( z==0 )
107
        {
108
        if( y<0 )
109
          {
110
          y = -y;
111
          x = -x;
112
          }
113
        else if( y==0 )
114
          {
115
          if( x<0 )
116
            {
117
            x = -x;
118
            }
119
          }
120
        }
121
      }
122
123
    quat.set(x,y,z,w);
124
    }
125
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127
128 94ad5a8f Leszek Koltunski
  private void modifyCurrentPosition(Static4D quat)
129 70b76549 Leszek Koltunski
    {
130 94ad5a8f Leszek Koltunski
    float cubitCenterX = mCurrentPosition.get0();
131
    float cubitCenterY = mCurrentPosition.get1();
132
    float cubitCenterZ = mCurrentPosition.get2();
133 70b76549 Leszek Koltunski
134
    Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
135
    Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
136
137 49f67f9b Leszek Koltunski
    float rotatedX = rotatedCenter.get0();
138
    float rotatedY = rotatedCenter.get1();
139
    float rotatedZ = rotatedCenter.get2();
140 70b76549 Leszek Koltunski
141 94ad5a8f Leszek Koltunski
    mCurrentPosition.set(rotatedX, rotatedY, rotatedZ);
142
    mParent.clampPos(mCurrentPosition);
143 70b76549 Leszek Koltunski
144 10a2e360 Leszek Koltunski
    computeRotationRow();
145
    }
146
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148 e844c116 Leszek Koltunski
// cast current position on axis; use mStart and mStep to compute the rotation row for each axis.
149 10a2e360 Leszek Koltunski
150
  private void computeRotationRow()
151
    {
152 e844c116 Leszek Koltunski
    float tmp;
153
    Static3D axis;
154
    float x = mCurrentPosition.get0();
155
    float y = mCurrentPosition.get1();
156
    float z = mCurrentPosition.get2();
157
158
    for(int i=0; i<mNumAxis; i++)
159
      {
160
      axis = mParent.ROTATION_AXIS[i];
161
      tmp = x*axis.get0() + y*axis.get1() + z*axis.get2();
162 66cbdd21 Leszek Koltunski
      mRotationRow[i] = (tmp-mParent.mStart)/mParent.mStep;
163 e844c116 Leszek Koltunski
      }
164 70b76549 Leszek Koltunski
    }
165
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167
168 b32444ee Leszek Koltunski
  Cubit(RubikObject parent, MeshBase mesh, Static3D position)
169 70b76549 Leszek Koltunski
    {
170
    float x = position.get0();
171
    float y = position.get1();
172
    float z = position.get2();
173
174 49f67f9b Leszek Koltunski
    Static3D vector = new Static3D(x,y,z);
175 70b76549 Leszek Koltunski
176
    mParent          = parent;
177 b32444ee Leszek Koltunski
    mMesh            = mesh;
178 70b76549 Leszek Koltunski
    mOrigPosition    = new Static3D(x,y,z);
179
    mQuatScramble    = new Static4D(0,0,0,1);
180
    mRotationAngle   = new Dynamic1D();
181
    mRotationAxis    = new Static3D(1,0,0);
182
    mCurrentPosition = position;
183
    mRotateEffect    = new MatrixEffectRotate(mRotationAngle, mRotationAxis, matrCenter);
184
185 e844c116 Leszek Koltunski
    mNumAxis     = mParent.ROTATION_AXIS.length;
186 66cbdd21 Leszek Koltunski
    mRotationRow = new float[mNumAxis];
187 10a2e360 Leszek Koltunski
    computeRotationRow();
188
189 36273130 Leszek Koltunski
    mEffect = new DistortedEffects();
190 70b76549 Leszek Koltunski
    mEffect.apply(mParent.mSinkEffect);
191
    mEffect.apply( new MatrixEffectMove(vector) );
192
    mEffect.apply( new MatrixEffectQuaternion(mQuatScramble, matrCenter));
193
    mEffect.apply(mRotateEffect);
194
    mEffect.apply(mParent.mQuatAEffect);
195
    mEffect.apply(mParent.mQuatCEffect);
196
    mEffect.apply(mParent.mScaleEffect);
197
198 b32444ee Leszek Koltunski
    mNode = new DistortedNode(mParent.mTexture,mEffect,mMesh);
199 70b76549 Leszek Koltunski
    }
200
201
///////////////////////////////////////////////////////////////////////////////////////////////////
202
203
  void savePreferences(SharedPreferences.Editor editor)
204
    {
205
    String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
206
207
    editor.putFloat("qx_"+number, mQuatScramble.get0());
208
    editor.putFloat("qy_"+number, mQuatScramble.get1());
209
    editor.putFloat("qz_"+number, mQuatScramble.get2());
210
    editor.putFloat("qw_"+number, mQuatScramble.get3());
211
    }
212
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214
215
  void restorePreferences(SharedPreferences preferences)
216
    {
217
    String number = mOrigPosition.get0()+"_"+mOrigPosition.get1()+"_"+mOrigPosition.get2();
218
219
    float qx = preferences.getFloat("qx_"+number, 0.0f);
220
    float qy = preferences.getFloat("qy_"+number, 0.0f);
221
    float qz = preferences.getFloat("qz_"+number, 0.0f);
222
    float qw = preferences.getFloat("qw_"+number, 1.0f);
223
224
    mQuatScramble.set(qx,qy,qz,qw);
225 94ad5a8f Leszek Koltunski
    modifyCurrentPosition(mQuatScramble);
226
    }
227
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229
// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
230
// then if it were rotated by quaternion 'quat'.
231
// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
232
// middle squares get interchanged. No visible difference!
233
//
234
// So: this is true iff the cubit
235
// a) is a corner or edge and the quaternions are the same
236
// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
237
238
  boolean thereIsNoVisibleDifference(Static4D quat)
239
    {
240
    if ( mQuatScramble.get0()==quat.get0() &&
241
         mQuatScramble.get1()==quat.get1() &&
242
         mQuatScramble.get2()==quat.get2() &&
243
         mQuatScramble.get3()==quat.get3()  ) return true;
244
245
    int belongsToHowManyFaces = 0;
246
    int size = mParent.getSize()-1;
247 7437ebb3 Leszek Koltunski
    float row;
248
    final float MAX_ERROR = 0.01f;
249 94ad5a8f Leszek Koltunski
250
    for(int i=0; i<mNumAxis; i++)
251
      {
252 7437ebb3 Leszek Koltunski
      row = mRotationRow[i];
253
      if( (row     <MAX_ERROR && row     >-MAX_ERROR) ||
254
          (row-size<MAX_ERROR && row-size>-MAX_ERROR)  ) belongsToHowManyFaces++;
255 94ad5a8f Leszek Koltunski
      }
256
257
    switch(belongsToHowManyFaces)
258
      {
259
      case 0 : return true ;  // 'inside' cubit that does not lie on any face
260
      case 1 :                // cubit that lies inside one of the faces
261
               float cubitCenterX = mCurrentPosition.get0();
262
               float cubitCenterY = mCurrentPosition.get1();
263
               float cubitCenterZ = mCurrentPosition.get2();
264
265
               Static4D cubitCenter = new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
266
               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
267
               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, mQuatScramble );
268
269 7437ebb3 Leszek Koltunski
               float row1, row2, row3, row4;
270 94ad5a8f Leszek Koltunski
               float ax,ay,az;
271
               Static3D axis;
272
               float x1 = rotated1.get0();
273
               float y1 = rotated1.get1();
274
               float z1 = rotated1.get2();
275
               float x2 = rotated2.get0();
276
               float y2 = rotated2.get1();
277
               float z2 = rotated2.get2();
278
279
               for(int i=0; i<mNumAxis; i++)
280
                 {
281
                 axis = mParent.ROTATION_AXIS[i];
282
                 ax = axis.get0();
283
                 ay = axis.get1();
284
                 az = axis.get2();
285
286 7437ebb3 Leszek Koltunski
                 row1 = ((x1*ax + y1*ay + z1*az) - mParent.mStart) / mParent.mStep;
287
                 row2 = ((x2*ax + y2*ay + z2*az) - mParent.mStart) / mParent.mStep;
288
                 row3 = row1 - size;
289
                 row4 = row2 - size;
290 94ad5a8f Leszek Koltunski
291 7437ebb3 Leszek Koltunski
                 if( (row1<MAX_ERROR && row1>-MAX_ERROR && row2<MAX_ERROR && row2>-MAX_ERROR) ||
292
                     (row3<MAX_ERROR && row3>-MAX_ERROR && row4<MAX_ERROR && row4>-MAX_ERROR)  )
293 94ad5a8f Leszek Koltunski
                   {
294
                   return true;
295
                   }
296
                 }
297
               return false;
298
      default: return false;  // edge or corner
299
      }
300 70b76549 Leszek Koltunski
    }
301
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303
304 001cc0e4 Leszek Koltunski
  void removeRotationNow(Static4D quat)
305 70b76549 Leszek Koltunski
    {
306 001cc0e4 Leszek Koltunski
    mRotationAngle.removeAll();
307
    mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
308
    normalizeScrambleQuat( mQuatScramble );
309
    modifyCurrentPosition(quat);
310 70b76549 Leszek Koltunski
    }
311
312
///////////////////////////////////////////////////////////////////////////////////////////////////
313
314 001cc0e4 Leszek Koltunski
  void beginNewRotation(int axis)
315 70b76549 Leszek Koltunski
    {
316 001cc0e4 Leszek Koltunski
    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
317
    mRotationAngle.add(mParent.mRotationAngleStatic);
318
    }
319 70b76549 Leszek Koltunski
320 001cc0e4 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
321
322
  void addNewRotation(int axis, long durationMillis, int angle)
323
    {
324
    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
325
    mRotationAngle.setDuration(durationMillis);
326
    mRotationAngle.resetToBeginning();
327
    mRotationAngle.add(new Static1D(0));
328
    mRotationAngle.add(new Static1D(angle));
329 70b76549 Leszek Koltunski
    }
330
331
///////////////////////////////////////////////////////////////////////////////////////////////////
332
333 001cc0e4 Leszek Koltunski
  void resetRotationAngle()
334 70b76549 Leszek Koltunski
    {
335 001cc0e4 Leszek Koltunski
    mRotationAngle.setDuration(POST_ROTATION_MILLISEC);
336
    mRotationAngle.resetToBeginning();
337 70b76549 Leszek Koltunski
    mRotationAngle.removeAll();
338 001cc0e4 Leszek Koltunski
    mRotationAngle.add(mParent.mRotationAngleStatic);
339
    mRotationAngle.add(mParent.mRotationAngleMiddle);
340
    mRotationAngle.add(mParent.mRotationAngleFinal);
341 70b76549 Leszek Koltunski
    }
342
343 f8ce34ab Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
344
345
  float getAngle()
346
    {
347
    int pointNum = mRotationAngle.getNumPoints();
348
349
    if( pointNum>=1 )
350
      {
351
      return mRotationAngle.getPoint(pointNum-1).get0();
352
      }
353
    else
354
      {
355
      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
356
      crashlytics.setCustomKey("getAngle", "points in RotationAngle: "+pointNum );
357
      crashlytics.log("points in RotationAngle: "+pointNum);
358
      return 0;
359
      }
360
    }
361
362 70b76549 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
363
// all DistortedTextures, DistortedNodes, DistortedFramebuffers, DistortedScreens and all types of
364
// Meshes HAVE TO be markedForDeletion when they are no longer needed- otherwise we have a major
365
// memory leak.
366
367
  void releaseResources()
368
    {
369 b32444ee Leszek Koltunski
    mMesh.markForDeletion();
370 70b76549 Leszek Koltunski
    mNode.markForDeletion();
371
    }
372
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374
375
  void solve()
376
    {
377
    mQuatScramble.set(0,0,0,1);
378
    mCurrentPosition.set(mOrigPosition);
379 0e7bcfb1 Leszek Koltunski
    computeRotationRow();
380 70b76549 Leszek Koltunski
    }
381
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
384
  long setUpCallback(EffectListener listener)
385
    {
386
    mRotateEffect.notifyWhenFinished(listener);
387
    return mRotateEffect.getID();
388
    }
389 1f9772f3 Leszek Koltunski
390 9621255f Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
391
392
  float getDistSquared(float[] point)
393
    {
394
    float dx = mCurrentPosition.get0() - point[0];
395
    float dy = mCurrentPosition.get1() - point[1];
396
    float dz = mCurrentPosition.get2() - point[2];
397
398
    return dx*dx + dy*dy + dz*dz;
399
    }
400
401 a304ee64 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
402
403
  int getColorIndex(int face)
404
    {
405
    Static4D texMap = mMesh.getTextureMap(face);
406
    return (int)(texMap.get0() / texMap.get2());
407
    }
408
409 1f9772f3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
410
411
  MeshBase getMesh()
412
    {
413
    return mMesh;
414
    }
415 70b76549 Leszek Koltunski
}