Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObjectCubit.java @ 8499ba3d

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
  boolean rotateCubit(Static4D quat)
209
    {
210
    boolean result = true;
211
    int len = mLen/3;
212

    
213
    for(int i=0; i<len; i++)
214
      {
215
      QuatHelper.rotateVectorByQuat( mTmp, mCurrentPosition[3*i], mCurrentPosition[3*i+1], mCurrentPosition[3*i+2], 0, quat);
216
      mCurrentPosition[3*i  ] = mTmp[0];
217
      mCurrentPosition[3*i+1] = mTmp[1];
218
      mCurrentPosition[3*i+2] = mTmp[2];
219
      mParent.clampPos(mCurrentPosition, 3*i);
220
      }
221

    
222
    if( mCubitType!=TYPE_NORMAL )
223
      {
224
      QuatHelper.rotateVectorByQuat( mTmp, mTrackingPoint[0], mTrackingPoint[1], mTrackingPoint[2], 0, quat);
225
      mTrackingPoint[0] = mTmp[0];
226
      mTrackingPoint[1] = mTmp[1];
227
      mTrackingPoint[2] = mTmp[2];
228
      mCurrentPuzzleFace = mParent.computeCurrentPuzzleFace(mCubitType,mTrackingPoint);
229

    
230
      if( mCurrentPuzzleFace<0 )  // unexpected error
231
        {
232
        mCurrentPuzzleFace = 0;
233
        result = false;
234
        }
235
      }
236

    
237
    if( mCubitType==TYPE_DECIDER )
238
      {
239
      QuatHelper.rotateVectorByQuat( mTmp, mRowOffset[0], mRowOffset[1], mRowOffset[2], 0, quat);
240
      mRowOffset[0] = mTmp[0];
241
      mRowOffset[1] = mTmp[1];
242
      mRowOffset[2] = mTmp[2];
243
      }
244

    
245
    return result;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  int postRotateCubit(Static4D quat)
251
    {
252
    Static4D q = QuatHelper.quatMultiply(quat,mParent.mObjectQuats[mQuatIndex]);
253
    mQuatIndex = normalizeScrambleQuat(q);
254
    computeRotationRow();
255
    return mQuatIndex;
256
    }
257

    
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

    
260
  void solve()
261
    {
262
    mQuatIndex = 0;
263
    mCurrentPuzzleFace = mOrigPuzzleFace;
264
    System.arraycopy(mOrigPosition, 0, mCurrentPosition, 0, mCurrentPosition.length);
265

    
266
    if( mCubitType!=TYPE_NORMAL )
267
      {
268
      mTrackingPoint = mParent.getTrackingPoint(mCubitIndex,mCubitType);
269
      if( mCubitType==TYPE_DECIDER )
270
        {
271
        mRowOffset[0] = mOrigOffsetX;
272
        mRowOffset[1] = mOrigOffsetY;
273
        mRowOffset[2] = mOrigOffsetZ;
274
        }
275
      }
276
    }
277

    
278
///////////////////////////////////////////////////////////////////////////////////////////////////
279

    
280
  void releaseResources()
281
    {
282
    mParent = null;
283
    }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286

    
287
  public int getType()
288
    {
289
    return mCubitType;
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
  public float[] getOffset()
295
    {
296
    return mRowOffset;
297
    }
298

    
299
///////////////////////////////////////////////////////////////////////////////////////////////////
300

    
301
  public int getPuzzleFace()
302
    {
303
    return mCurrentPuzzleFace;
304
    }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307

    
308
  public int getRotRow(int axisIndex)
309
    {
310
    return mRotationRow[axisIndex];
311
    }
312
}
(8-8/10)