Project

General

Profile

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

magiccube / src / main / java / org / distorted / object / RubikCubeMovement.java @ 5be1059b

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 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.object;
21

    
22
import org.distorted.library.type.Static2D;
23
import org.distorted.library.type.Static4D;
24
import org.distorted.magic.RubikRenderer;
25
import org.distorted.magic.RubikSurfaceView;
26

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

    
29
public class RubikCubeMovement
30
{
31
    private final static int NONE   =-1;
32
    private final static int FRONT  = 0;  // has to be 6 consecutive ints
33
    private final static int BACK   = 1;  // FRONT ... BOTTOM
34
    private final static int LEFT   = 2;  //
35
    private final static int RIGHT  = 3;  //
36
    private final static int TOP    = 4;  //
37
    private final static int BOTTOM = 5;  //
38

    
39
    private static final int[] VECT = {RubikCube.VECTX,RubikCube.VECTY,RubikCube.VECTZ};
40

    
41
    private float[] mPoint, mCamera, mTouchPointCastOntoFace, mDiff, mTouchPoint;
42
    private int mRotationVect, mLastTouchedFace;
43

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

    
46
    private boolean isVertical(float x, float y)
47
      {
48
      return (y>x) ? (y>=-x) : (y< -x);
49
      }
50

    
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52

    
53
    private int retFaceSign(int face)
54
      {
55
      return (face==FRONT || face==RIGHT || face==TOP) ? 1:-1;
56
      }
57

    
58
///////////////////////////////////////////////////////////////////////////////////////////////////
59

    
60
    private int retFaceRotationSign(int face)
61
      {
62
      return (face==BACK || face==RIGHT || face==TOP) ? 1:-1;
63
      }
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66
// retFace{X,Y,Z}axis: 3 functions which return which real AXIS gets mapped to which when we look
67
// directly at a given face. For example, when we look at the RIGHT face of the cube (with TOP still
68
// in the top) then the 'real' X axis becomes the 'Z' axis, thus retFaceZaxis(RIGHT) = VECTX.
69

    
70
    private int retFaceXaxis(int face)
71
      {
72
      switch(face)
73
        {
74
        case FRONT :
75
        case BACK  : return RubikCube.VECTX;
76
        case LEFT  :
77
        case RIGHT : return RubikCube.VECTZ;
78
        case TOP   :
79
        case BOTTOM: return RubikCube.VECTX;
80
        }
81

    
82
      return -1;
83
      }
84

    
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86

    
87
    private int retFaceYaxis(int face)
88
      {
89
      switch(face)
90
        {
91
        case FRONT :
92
        case BACK  : return RubikCube.VECTY;
93
        case LEFT  :
94
        case RIGHT : return RubikCube.VECTY;
95
        case TOP   :
96
        case BOTTOM: return RubikCube.VECTZ;
97
        }
98

    
99
      return -1;
100
      }
101

    
102
///////////////////////////////////////////////////////////////////////////////////////////////////
103

    
104
    private int retFaceZaxis(int face)
105
      {
106
      switch(face)
107
        {
108
        case FRONT :
109
        case BACK  : return RubikCube.VECTZ;
110
        case LEFT  :
111
        case RIGHT : return RubikCube.VECTX;
112
        case TOP   :
113
        case BOTTOM: return RubikCube.VECTY;
114
        }
115

    
116
      return -1;
117
      }
118

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

    
121
    private boolean faceIsVisible(int face, float cubeHalfSize)
122
      {
123
      int sign = retFaceSign(face);
124
      int zAxis= retFaceZaxis(face);
125

    
126
      return sign*mCamera[zAxis] > cubeHalfSize;
127
      }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
    private void convertTouchPointToScreenSpace(Static4D accumulated, float x, float y)
132
      {
133
      Static4D touchPoint = new Static4D(x, y, 0, 0);
134
      Static4D rotatedTouchPoint= RubikSurfaceView.rotateVectorByInvertedQuat(touchPoint, accumulated);
135

    
136
      mPoint[0] = rotatedTouchPoint.get1();
137
      mPoint[1] = rotatedTouchPoint.get2();
138
      mPoint[2] = rotatedTouchPoint.get3();
139
      }
140

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142

    
143
    private void convertCameraPointToScreenSpace(Static4D accumulated)
144
      {
145
      Static4D cameraPoint = new Static4D(0, 0, RubikRenderer.CAMERA_DISTANCE, 0);
146
      Static4D rotatedCamera= RubikSurfaceView.rotateVectorByInvertedQuat(cameraPoint, accumulated);
147

    
148
      mCamera[0] = rotatedCamera.get1();
149
      mCamera[1] = rotatedCamera.get2();
150
      mCamera[2] = rotatedCamera.get3();
151
      }
152

    
153
///////////////////////////////////////////////////////////////////////////////////////////////////
154
// given precomputed mCamera and mPoint, respectively camera and touch point positions in ScreenSpace,
155
// cast this touch point onto the surface defined by the 'face' and write the cast coords to 'output'.
156
// Center of the 'face' = (0,0), third coord always +- cubeHalfSize.
157

    
158
    private void castTouchPointOntoFace(int face, float cubeHalfSize, float[] output)
159
      {
160
      int sign = retFaceSign(face);
161
      int zAxis= retFaceZaxis(face);
162
      float diff = mPoint[zAxis]-mCamera[zAxis];
163

    
164
      float ratio =  diff!=0.0f ? (sign*cubeHalfSize-mCamera[zAxis])/diff : 0.0f;
165

    
166
      output[0] = (mPoint[0]-mCamera[0])*ratio + mCamera[0];
167
      output[1] = (mPoint[1]-mCamera[1])*ratio + mCamera[1];
168
      output[2] = (mPoint[2]-mCamera[2])*ratio + mCamera[2];
169
      }
170

    
171
///////////////////////////////////////////////////////////////////////////////////////////////////
172
// PUBLIC API
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

    
175
    public RubikCubeMovement()
176
      {
177
      mRotationVect = VECT[0];
178

    
179
      mPoint = new float[3];
180
      mCamera= new float[3];
181
      mDiff  = new float[3];
182
      mTouchPoint = new float[3];
183
      mTouchPointCastOntoFace = new float[3];
184
      }
185

    
186
///////////////////////////////////////////////////////////////////////////////////////////////////
187

    
188
    public boolean faceTouched(Static4D rotQuaternion, float x, float y)
189
      {
190
      float cubeHalfSize= RubikCube.CUBE_SCREEN_RATIO*0.5f;
191

    
192
      convertTouchPointToScreenSpace(rotQuaternion,x,y);
193
      convertCameraPointToScreenSpace(rotQuaternion);
194

    
195
      for( mLastTouchedFace=FRONT; mLastTouchedFace<=BOTTOM; mLastTouchedFace++)
196
        {
197
        if( faceIsVisible(mLastTouchedFace,cubeHalfSize) )
198
          {
199
          castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize, mTouchPointCastOntoFace);
200

    
201
          float qX= (mTouchPointCastOntoFace[0]+cubeHalfSize) / (2*cubeHalfSize);
202
          float qY= (mTouchPointCastOntoFace[1]+cubeHalfSize) / (2*cubeHalfSize);
203
          float qZ= (mTouchPointCastOntoFace[2]+cubeHalfSize) / (2*cubeHalfSize);
204

    
205
          if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return true;
206
          }
207
        }
208

    
209
      mLastTouchedFace = NONE;
210
      return false;
211
      }
212

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

    
215
    public Static2D newRotation(Static4D rotQuaternion, float x, float y)
216
      {
217
      float cubeHalfSize= RubikCube.CUBE_SCREEN_RATIO*0.5f;
218

    
219
      convertTouchPointToScreenSpace(rotQuaternion,x,y);
220
      castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize,mDiff);
221

    
222
      mDiff[0] -= mTouchPointCastOntoFace[0];
223
      mDiff[1] -= mTouchPointCastOntoFace[1];
224
      mDiff[2] -= mTouchPointCastOntoFace[2];
225

    
226
      int xAxis = retFaceXaxis(mLastTouchedFace);
227
      int yAxis = retFaceYaxis(mLastTouchedFace);
228
      mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? VECT[xAxis]:VECT[yAxis]);
229
      float offset= (mTouchPointCastOntoFace[mRotationVect]+cubeHalfSize)/(2*cubeHalfSize);
230

    
231
      mTouchPoint[0] = mPoint[0];
232
      mTouchPoint[1] = mPoint[1];
233
      mTouchPoint[2] = mPoint[2];
234

    
235
      return new Static2D(mRotationVect,offset);
236
      }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

    
240
    public float continueRotation(Static4D rotQuaternion, float x, float y)
241
      {
242
      convertTouchPointToScreenSpace(rotQuaternion,x,y);
243

    
244
      mDiff[0] = mPoint[0]-mTouchPoint[0];
245
      mDiff[1] = mPoint[1]-mTouchPoint[1];
246
      mDiff[2] = mPoint[2]-mTouchPoint[2];
247

    
248
      int xAxis= retFaceXaxis(mLastTouchedFace);
249
      int yAxis= retFaceYaxis(mLastTouchedFace);
250
      int sign = retFaceRotationSign(mLastTouchedFace);
251
      float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]);
252

    
253
      return sign*angle;
254
      }
255
}
(2-2/2)