Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / main / TwistyObjectCubit.java @ aacf5e27

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 org.distorted.library.helpers.QuatHelper;
13
import org.distorted.library.type.Static4D;
14
import org.distorted.objectlib.helpers.OperatingSystemInterface;
15

    
16
///////////////////////////////////////////////////////////////////////////////////////////////////
17

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

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

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

    
41
  int mQuatIndex;
42

    
43
///////////////////////////////////////////////////////////////////////////////////////////////////
44

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
140
    return ret;
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

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

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154

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

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

    
165
    return result;
166
    }
167

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

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

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  void savePreferences(String key, OperatingSystemInterface os)
178
    {
179
    os.putInt(createKey(key), mQuatIndex);
180
    }
181

    
182
///////////////////////////////////////////////////////////////////////////////////////////////////
183

    
184
  void removePreferences(String key, OperatingSystemInterface os)
185
    {
186
    os.remove(createKey(key));
187
    }
188

    
189
///////////////////////////////////////////////////////////////////////////////////////////////////
190

    
191
  int restorePreferences(String key, OperatingSystemInterface os)
192
    {
193
    mQuatIndex = os.getInt(createKey(key), 0);
194
    return mQuatIndex;
195
    }
196

    
197
///////////////////////////////////////////////////////////////////////////////////////////////////
198
// only for debugging
199

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

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206

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

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

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

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

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

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

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

    
264
    return result;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

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

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

    
278
    return mQuatIndex;
279
    }
280

    
281
///////////////////////////////////////////////////////////////////////////////////////////////////
282

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

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

    
301
///////////////////////////////////////////////////////////////////////////////////////////////////
302

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

    
308
///////////////////////////////////////////////////////////////////////////////////////////////////
309

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

    
315
///////////////////////////////////////////////////////////////////////////////////////////////////
316

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

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

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

    
329
///////////////////////////////////////////////////////////////////////////////////////////////////
330

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