Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / main / Cubit.java @ 7cd287b9

1
///////////////////////////////////////////////////////////////////////////////////////////////////
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
package org.distorted.objectlib.main;
21

    
22
import android.content.SharedPreferences;
23

    
24
import org.distorted.library.main.QuatHelper;
25
import org.distorted.library.type.Static4D;
26

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

    
29
public class Cubit
30
  {
31
  public static final int TYPE_NORMAL   = 0;  // all 'old', 'pre-crazy' cubits
32
  public static final int TYPE_FOLLOWER = 1;  // those cubits that follow deciders (e.g. small circle edges from Crazy Plus planets)
33
  public static final int TYPE_DECIDER  = 2;  // cubits deciding about rotation rows of their followers (e.g. center cubits of Crazy Plus Planets)
34

    
35
  private final float[] mTmp;
36
  private final float[] mOrigPosition;
37
  private final float[] mCurrentPosition;
38
  private final float[] mRowOffset;
39
  private final float mOrigOffsetX, mOrigOffsetY, mOrigOffsetZ;
40
  private final int mNumAxis;
41
  private final int mLen;
42
  private final int[] mRotationRow;
43
  private final int mCubitType;
44
  private final int mOrigPuzzleFace;
45
  private final int mCubitIndex;
46

    
47
  private float[] mTrackingPoint;
48
  private int mCurrentPuzzleFace;
49
  private TwistyObject mParent;
50

    
51
  int mQuatIndex;
52

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

    
55
  Cubit(TwistyObject parent, float[] position, int numAxis, int cubitIndex)
56
    {
57
    mQuatIndex= 0;
58
    mParent   = parent;
59
    mLen      = position.length;
60

    
61
    mCubitType    = mParent.getCubitRotationType(cubitIndex);
62
    mRowOffset    = mParent.getCubitRowOffset(cubitIndex);
63
    mTrackingPoint= mParent.getTrackingPoint(cubitIndex,mCubitType);
64
    int face      = mParent.computeCurrentPuzzleFace(mCubitType,mTrackingPoint);
65

    
66
    if( mRowOffset!=null )
67
      {
68
      mOrigOffsetX = mRowOffset[0];
69
      mOrigOffsetY = mRowOffset[1];
70
      mOrigOffsetZ = mRowOffset[2];
71
      if( mCubitType==TYPE_DECIDER ) mParent.setRotationRowOffset(face,mRowOffset);
72
      }
73
    else
74
      {
75
      mOrigOffsetX = 0;
76
      mOrigOffsetY = 0;
77
      mOrigOffsetZ = 0;
78
      }
79

    
80
    mCubitIndex       = cubitIndex;
81
    mOrigPuzzleFace   = face;
82
    mCurrentPuzzleFace= face;
83
    mOrigPosition     = new float[mLen];
84
    mCurrentPosition  = new float[mLen];
85
    mTmp              = new float[4];
86

    
87
    for(int i=0; i<mLen; i++)
88
      {
89
      mOrigPosition[i]    = position[i];
90
      mCurrentPosition[i] = position[i];
91
      }
92

    
93
    mNumAxis     = numAxis;
94
    mRotationRow = new int[mNumAxis];
95
    computeRotationRow();
96
    }
97

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

    
106
  private int normalizeScrambleQuat(Static4D quat)
107
    {
108
    float x = quat.get0();
109
    float y = quat.get1();
110
    float z = quat.get2();
111
    float w = quat.get3();
112
    float xd,yd,zd,wd;
113
    float diff, mindiff = Float.MAX_VALUE;
114
    int ret=0;
115
    int num_quats = mParent.mObjectQuats.length;
116
    Static4D qt;
117

    
118
    for(int q=0; q<num_quats; q++)
119
      {
120
      qt = mParent.mObjectQuats[q];
121

    
122
      xd = x - qt.get0();
123
      yd = y - qt.get1();
124
      zd = z - qt.get2();
125
      wd = w - qt.get3();
126

    
127
      diff = xd*xd + yd*yd + zd*zd + wd*wd;
128

    
129
      if( diff < mindiff )
130
        {
131
        ret = q;
132
        mindiff = diff;
133
        }
134

    
135
      xd = x + qt.get0();
136
      yd = y + qt.get1();
137
      zd = z + qt.get2();
138
      wd = w + qt.get3();
139

    
140
      diff = xd*xd + yd*yd + zd*zd + wd*wd;
141

    
142
      if( diff < mindiff )
143
        {
144
        ret = q;
145
        mindiff = diff;
146
        }
147
      }
148

    
149
    return ret;
150
    }
151

    
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153

    
154
  void computeRotationRow()
155
    {
156
    for(int i=0; i<mNumAxis; i++)
157
      {
158
      mRotationRow[i] = mParent.computeRow(mCurrentPosition,i,mCubitType,mCurrentPuzzleFace);
159
      }
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163

    
164
  int computeAssociation()
165
    {
166
    int result = 0, accumulativeShift = 0;
167

    
168
    for(int axis=0; axis<mNumAxis; axis++)
169
      {
170
      result += (mRotationRow[axis]<<accumulativeShift);
171
      accumulativeShift += mParent.mMaxNumLayers;
172
      }
173

    
174
    return result;
175
    }
176

    
177
///////////////////////////////////////////////////////////////////////////////////////////////////
178

    
179
  private String createKey(String key)
180
    {
181
    return key+"_"+mCubitIndex+"_"+mOrigPosition[0]+"_"+mOrigPosition[1]+"_"+mOrigPosition[2];
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  void savePreferences(String key, SharedPreferences.Editor editor)
187
    {
188
    editor.putInt(createKey(key), mQuatIndex);
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  void removePreferences(String key, SharedPreferences.Editor editor)
194
    {
195
    editor.remove(createKey(key));
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  int restorePreferences(String key, SharedPreferences preferences)
201
    {
202
    mQuatIndex = preferences.getInt(createKey(key), 0);
203
    return mQuatIndex;
204
    }
205

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

    
208
  void rotateCubit(Static4D quat)
209
    {
210
    int len = mLen/3;
211

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

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

    
230
    if( mCubitType==TYPE_DECIDER )
231
      {
232
      QuatHelper.rotateVectorByQuat( mTmp, mRowOffset[0], mRowOffset[1], mRowOffset[2], 0, quat);
233
      mRowOffset[0] = mTmp[0];
234
      mRowOffset[1] = mTmp[1];
235
      mRowOffset[2] = mTmp[2];
236
      }
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  int postRotateCubit(Static4D quat)
242
    {
243
    Static4D q = QuatHelper.quatMultiply(quat,mParent.mObjectQuats[mQuatIndex]);
244
    mQuatIndex = normalizeScrambleQuat(q);
245
    computeRotationRow();
246
    return mQuatIndex;
247
    }
248

    
249
///////////////////////////////////////////////////////////////////////////////////////////////////
250

    
251
  void solve()
252
    {
253
    mQuatIndex = 0;
254
    mCurrentPuzzleFace = mOrigPuzzleFace;
255
    System.arraycopy(mOrigPosition, 0, mCurrentPosition, 0, mCurrentPosition.length);
256

    
257
    if( mCubitType!=TYPE_NORMAL )
258
      {
259
      mTrackingPoint = mParent.getTrackingPoint(mCubitIndex,mCubitType);
260
      if( mCubitType==TYPE_DECIDER )
261
        {
262
        mRowOffset[0] = mOrigOffsetX;
263
        mRowOffset[1] = mOrigOffsetY;
264
        mRowOffset[2] = mOrigOffsetZ;
265
        }
266
      }
267
    }
268

    
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

    
271
  void releaseResources()
272
    {
273
    mParent = null;
274
    }
275

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

    
278
  public int getType()
279
    {
280
    return mCubitType;
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

    
285
  public float[] getOffset()
286
    {
287
    return mRowOffset;
288
    }
289

    
290
///////////////////////////////////////////////////////////////////////////////////////////////////
291

    
292
  public int getPuzzleFace()
293
    {
294
    return mCurrentPuzzleFace;
295
    }
296

    
297
///////////////////////////////////////////////////////////////////////////////////////////////////
298

    
299
  public int getRotRow(int axisIndex)
300
    {
301
    return mRotationRow[axisIndex];
302
    }
303
}
(1-1/13)