Project

General

Profile

Download (10 KB) Statistics
| Branch: | Revision:

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObjectCubit.java @ 3788d0cd

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2019 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.main;
11

    
12
import android.content.SharedPreferences;
13

    
14
import org.distorted.library.main.QuatHelper;
15
import org.distorted.library.type.Static4D;
16

    
17
///////////////////////////////////////////////////////////////////////////////////////////////////
18

    
19
public class TwistyObjectCubit
20
  {
21
  public static final int TYPE_NORMAL   = 0;  // all 'old', 'pre-crazy' cubits
22
  public static final int TYPE_FOLLOWER = 1;  // those cubits that follow deciders (e.g. small circle edges from Crazy Plus planets)
23
  public static final int TYPE_DECIDER  = 2;  // cubits deciding about rotation rows of their followers (e.g. center cubits of Crazy Plus Planets)
24

    
25
  private final float[] mTmp;
26
  private final float[] mOrigPosition;
27
  private final float[] mCurrentPosition;
28
  private final float[] mRowOffset;
29
  private final float mOrigOffsetX, mOrigOffsetY, mOrigOffsetZ;
30
  private final int mNumAxis;
31
  private final int mLen;
32
  private final int[] mRotationRow;
33
  private final int mCubitType;
34
  private final int mOrigPuzzleFace;
35
  private final int mCubitIndex;
36
  private final int mMaxLayers;
37

    
38
  private float[] mTrackingPoint;
39
  private int mCurrentPuzzleFace;
40
  private TwistyObject mParent;
41

    
42
  int mQuatIndex;
43

    
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45

    
46
  TwistyObjectCubit(TwistyObject parent, float[] position, int numAxis, int maxLayers, int cubitIndex)
47
    {
48
    mQuatIndex= 0;
49
    mParent   = parent;
50
    mLen      = position.length;
51
    mMaxLayers= maxLayers;
52

    
53
    mCubitType    = mParent.getCubitRotationType(cubitIndex);
54
    mRowOffset    = mParent.getCubitRowOffset(cubitIndex);
55
    mTrackingPoint= mParent.getTrackingPoint(cubitIndex,mCubitType);
56
    int face      = mParent.computeCurrentPuzzleFace(mCubitType,mTrackingPoint);
57

    
58
    if( mRowOffset!=null )
59
      {
60
      mOrigOffsetX = mRowOffset[0];
61
      mOrigOffsetY = mRowOffset[1];
62
      mOrigOffsetZ = mRowOffset[2];
63
      if( mCubitType==TYPE_DECIDER ) mParent.setRotationRowOffset(face,mRowOffset);
64
      }
65
    else
66
      {
67
      mOrigOffsetX = 0;
68
      mOrigOffsetY = 0;
69
      mOrigOffsetZ = 0;
70
      }
71

    
72
    mCubitIndex       = cubitIndex;
73
    mOrigPuzzleFace   = face;
74
    mCurrentPuzzleFace= face;
75
    mOrigPosition     = new float[mLen];
76
    mCurrentPosition  = new float[mLen];
77
    mTmp              = new float[4];
78

    
79
    for(int i=0; i<mLen; i++)
80
      {
81
      mOrigPosition[i]    = position[i];
82
      mCurrentPosition[i] = position[i];
83
      }
84

    
85
    mNumAxis     = numAxis;
86
    mRotationRow = new int[mNumAxis];
87
    computeRotationRow();
88
    }
89

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91
// Because of quatMultiplication, errors can accumulate - so to avoid this, we
92
// correct the value of the 'scramble' quat to what it should be - one of the legal quats from the
93
// list QUATS.
94
//
95
// We also have to remember that the group of unit quaternions is a double-cover of rotations
96
// in 3D ( q represents the same rotation as -q ) - so invert if needed.
97

    
98
  private int normalizeScrambleQuat(Static4D quat)
99
    {
100
    float x = quat.get0();
101
    float y = quat.get1();
102
    float z = quat.get2();
103
    float w = quat.get3();
104
    float xd,yd,zd,wd;
105
    float diff, mindiff = Float.MAX_VALUE;
106
    int ret=0;
107
    int num_quats = mParent.mObjectQuats.length;
108
    Static4D qt;
109

    
110
    for(int q=0; q<num_quats; q++)
111
      {
112
      qt = mParent.mObjectQuats[q];
113

    
114
      xd = x - qt.get0();
115
      yd = y - qt.get1();
116
      zd = z - qt.get2();
117
      wd = w - qt.get3();
118

    
119
      diff = xd*xd + yd*yd + zd*zd + wd*wd;
120

    
121
      if( diff < mindiff )
122
        {
123
        ret = q;
124
        mindiff = diff;
125
        }
126

    
127
      xd = x + qt.get0();
128
      yd = y + qt.get1();
129
      zd = z + qt.get2();
130
      wd = w + qt.get3();
131

    
132
      diff = xd*xd + yd*yd + zd*zd + wd*wd;
133

    
134
      if( diff < mindiff )
135
        {
136
        ret = q;
137
        mindiff = diff;
138
        }
139
      }
140

    
141
    return ret;
142
    }
143

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

    
146
  void computeRotationRow()
147
    {
148
    for(int i=0; i<mNumAxis; i++)
149
      {
150
      mRotationRow[i] = mParent.computeRow(mCurrentPosition,i,mCubitType,mCurrentPuzzleFace);
151
      }
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  int computeAssociation()
157
    {
158
    int result = 0, accumulativeShift = 0;
159

    
160
    for(int axis=0; axis<mNumAxis; axis++)
161
      {
162
      result += (mRotationRow[axis]<<accumulativeShift);
163
      accumulativeShift += mMaxLayers;
164
      }
165

    
166
    return result;
167
    }
168

    
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170

    
171
  private String createKey(String key)
172
    {
173
    return key+"_"+mCubitIndex+"_"+mOrigPosition[0]+"_"+mOrigPosition[1]+"_"+mOrigPosition[2];
174
    }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177

    
178
  void savePreferences(String key, SharedPreferences.Editor editor)
179
    {
180
    editor.putInt(createKey(key), mQuatIndex);
181
    }
182

    
183
///////////////////////////////////////////////////////////////////////////////////////////////////
184

    
185
  void removePreferences(String key, SharedPreferences.Editor editor)
186
    {
187
    editor.remove(createKey(key));
188
    }
189

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

    
192
  int restorePreferences(String key, SharedPreferences preferences)
193
    {
194
    mQuatIndex = preferences.getInt(createKey(key), 0);
195
    return mQuatIndex;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199
// only for debugging
200

    
201
  float[] getTrackingPoint()
202
    {
203
    return mTrackingPoint;
204
    }
205

    
206
///////////////////////////////////////////////////////////////////////////////////////////////////
207

    
208
  float[] getCurrentPos()
209
    {
210
    return mCurrentPosition;
211
    }
212

    
213
///////////////////////////////////////////////////////////////////////////////////////////////////
214

    
215
  boolean rotateCubit(Static4D quat, boolean clamp)
216
    {
217
    boolean result = true;
218
    int len = mLen/3;
219

    
220
    if( clamp )
221
      {
222
      for(int i=0; i<len; i++)
223
        {
224
        QuatHelper.rotateVectorByQuat( mTmp, mCurrentPosition[3*i], mCurrentPosition[3*i+1], mCurrentPosition[3*i+2], 0, quat);
225
        mCurrentPosition[3*i  ] = mTmp[0];
226
        mCurrentPosition[3*i+1] = mTmp[1];
227
        mCurrentPosition[3*i+2] = mTmp[2];
228
        mParent.clampPos(mCurrentPosition, 3*i);
229
        }
230
      }
231
    else
232
      {
233
      for(int i=0; i<len; i++)
234
        {
235
        QuatHelper.rotateVectorByQuat( mTmp, mCurrentPosition[3*i], mCurrentPosition[3*i+1], mCurrentPosition[3*i+2], 0, quat);
236
        mCurrentPosition[3*i  ] = mTmp[0];
237
        mCurrentPosition[3*i+1] = mTmp[1];
238
        mCurrentPosition[3*i+2] = mTmp[2];
239
        }
240
      }
241

    
242
    if( mCubitType!=TYPE_NORMAL )
243
      {
244
      QuatHelper.rotateVectorByQuat( mTmp, mTrackingPoint[0], mTrackingPoint[1], mTrackingPoint[2], 0, quat);
245
      mTrackingPoint[0] = mTmp[0];
246
      mTrackingPoint[1] = mTmp[1];
247
      mTrackingPoint[2] = mTmp[2];
248
      mCurrentPuzzleFace = mParent.computeCurrentPuzzleFace(mCubitType,mTrackingPoint);
249

    
250
      if( mCurrentPuzzleFace<0 )  // unexpected error
251
        {
252
        mCurrentPuzzleFace = 0;
253
        result = false;
254
        }
255
      }
256

    
257
    if( mCubitType==TYPE_DECIDER )
258
      {
259
      QuatHelper.rotateVectorByQuat( mTmp, mRowOffset[0], mRowOffset[1], mRowOffset[2], 0, quat);
260
      mRowOffset[0] = mTmp[0];
261
      mRowOffset[1] = mTmp[1];
262
      mRowOffset[2] = mTmp[2];
263
      }
264

    
265
    return result;
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  int postRotateCubit(Static4D quat)
271
    {
272
    Static4D q = QuatHelper.quatMultiply(quat,mParent.mObjectQuats[mQuatIndex]);
273
    mQuatIndex = normalizeScrambleQuat(q);
274
    computeRotationRow();
275

    
276
 //   if( mCubitIndex==5 )
277
 //     android.util.Log.e("D", "index="+mCubitIndex+" quat: "+mQuatIndex);
278

    
279
    return mQuatIndex;
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

    
284
  void solve()
285
    {
286
    mQuatIndex = 0;
287
    mCurrentPuzzleFace = mOrigPuzzleFace;
288
    System.arraycopy(mOrigPosition, 0, mCurrentPosition, 0, mCurrentPosition.length);
289

    
290
    if( mCubitType!=TYPE_NORMAL )
291
      {
292
      mTrackingPoint = mParent.getTrackingPoint(mCubitIndex,mCubitType);
293
      if( mCubitType==TYPE_DECIDER )
294
        {
295
        mRowOffset[0] = mOrigOffsetX;
296
        mRowOffset[1] = mOrigOffsetY;
297
        mRowOffset[2] = mOrigOffsetZ;
298
        }
299
      }
300
    }
301

    
302
///////////////////////////////////////////////////////////////////////////////////////////////////
303

    
304
  void releaseResources()
305
    {
306
    mParent = null;
307
    }
308

    
309
///////////////////////////////////////////////////////////////////////////////////////////////////
310

    
311
  public int getType()
312
    {
313
    return mCubitType;
314
    }
315

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317

    
318
  public float[] getOffset()
319
    {
320
    return mRowOffset;
321
    }
322

    
323
///////////////////////////////////////////////////////////////////////////////////////////////////
324

    
325
  public int getPuzzleFace()
326
    {
327
    return mCurrentPuzzleFace;
328
    }
329

    
330
///////////////////////////////////////////////////////////////////////////////////////////////////
331

    
332
  public int getRotRow(int axisIndex)
333
    {
334
    return mRotationRow[axisIndex];
335
    }
336
}
(9-9/11)