Project

General

Profile

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

magiccube / src / main / java / org / distorted / object / RubikCubeMovement.java @ beb325a0

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.Static4D;
23
import org.distorted.magic.RubikSurfaceView;
24

    
25
///////////////////////////////////////////////////////////////////////////////////////////////////
26

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

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

    
39
    // Moving the finger from the middle of the vertical screen to the right edge will rotate a
40
    // given face by SWIPING_SENSITIVITY/2 degrees.
41
    private final static int SWIPING_SENSITIVITY  = 240;
42

    
43
    private RubikCube mCube;
44
    private float[] mPoint, mCamera, mTouchPointCastOntoFace, mDiff, mTouchPoint; // all in screen space
45
    private int mRotationVect;
46

    
47
///////////////////////////////////////////////////////////////////////////////////////////////////
48

    
49
    private boolean isVertical(float x, float y)
50
      {
51
      return (y>x) ? (y>=-x) : (y< -x);
52
      }
53

    
54
///////////////////////////////////////////////////////////////////////////////////////////////////
55

    
56
    private boolean faceIsVisible(int face, float cubeHalfSize)
57
      {
58
      int sign = retFaceSign(face);
59
      int zAxis= retFaceZaxis(face);
60

    
61
      return sign*mCamera[zAxis] > cubeHalfSize;
62
      }
63

    
64
///////////////////////////////////////////////////////////////////////////////////////////////////
65

    
66
    private void convertTouchPointToScreenSpace(Static4D accumulated, int x, int y, int scrW, int scrH)
67
      {
68
      float halfScrWidth  = scrW*0.5f;
69
      float halfScrHeight = scrH*0.5f;
70
      Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
71
      Static4D rotatedTouchPoint= RubikSurfaceView.rotateVectorByInvertedQuat(touchPoint, accumulated);
72

    
73
      mPoint[0] = rotatedTouchPoint.get1();
74
      mPoint[1] = rotatedTouchPoint.get2();
75
      mPoint[2] = rotatedTouchPoint.get3();
76
      }
77

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
    private void convertCameraPointToScreenSpace(Static4D accumulated, float cameraDistance)
81
      {
82
      Static4D cameraPoint = new Static4D(0, 0, cameraDistance, 0);
83
      Static4D rotatedCamera= RubikSurfaceView.rotateVectorByInvertedQuat(cameraPoint, accumulated);
84

    
85
      mCamera[0] = rotatedCamera.get1();
86
      mCamera[1] = rotatedCamera.get2();
87
      mCamera[2] = rotatedCamera.get3();
88
      }
89

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

    
95
    private void castTouchPointOntoFace(int face, float cubeHalfSize, float[] output)
96
      {
97
      int sign = retFaceSign(face);
98
      int zAxis= retFaceZaxis(face);
99
      float diff = mPoint[zAxis]-mCamera[zAxis];
100

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

    
103
      output[0] = (mPoint[0]-mCamera[0])*ratio + mCamera[0];
104
      output[1] = (mPoint[1]-mCamera[1])*ratio + mCamera[1];
105
      output[2] = (mPoint[2]-mCamera[2])*ratio + mCamera[2];
106
      }
107

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109

    
110
    private int retFaceSign(int face)
111
      {
112
      return (face==FRONT || face==RIGHT || face==TOP) ? 1:-1;
113
      }
114

    
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116

    
117
    private int retFaceRotationSign(int face)
118
      {
119
      return (face==BACK || face==RIGHT || face==TOP) ? 1:-1;
120
      }
121

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

    
127
    private int retFaceXaxis(int face)
128
      {
129
      switch(face)
130
        {
131
        case FRONT :
132
        case BACK  : return RubikCube.VECTX;
133
        case LEFT  :
134
        case RIGHT : return RubikCube.VECTZ;
135
        case TOP   :
136
        case BOTTOM: return RubikCube.VECTX;
137
        }
138

    
139
      return -1;
140
      }
141

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

    
144
    private int retFaceYaxis(int face)
145
      {
146
      switch(face)
147
        {
148
        case FRONT :
149
        case BACK  : return RubikCube.VECTY;
150
        case LEFT  :
151
        case RIGHT : return RubikCube.VECTY;
152
        case TOP   :
153
        case BOTTOM: return RubikCube.VECTZ;
154
        }
155

    
156
      return -1;
157
      }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

    
161
    private int retFaceZaxis(int face)
162
      {
163
      switch(face)
164
        {
165
        case FRONT :
166
        case BACK  : return RubikCube.VECTZ;
167
        case LEFT  :
168
        case RIGHT : return RubikCube.VECTX;
169
        case TOP   :
170
        case BOTTOM: return RubikCube.VECTY;
171
        }
172

    
173
      return -1;
174
      }
175

    
176
///////////////////////////////////////////////////////////////////////////////////////////////////
177
// PUBLIC API
178
///////////////////////////////////////////////////////////////////////////////////////////////////
179

    
180
    public RubikCubeMovement(RubikCube cube)
181
      {
182
      mCube = cube;
183

    
184
      mRotationVect = VECT[0];
185

    
186
      mPoint = new float[3];
187
      mCamera= new float[3];
188
      mDiff  = new float[3];
189
      mTouchPoint = new float[3];
190
      mTouchPointCastOntoFace = new float[3];
191
      }
192

    
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194

    
195
    public int faceTouched(Static4D accumulated, float cameraDistance, int x, int y, int scrW, int scrH)
196
      {
197
      float cubeHalfSize= mCube.returnCubeSizeInScreenSpace()*0.5f;
198

    
199
      convertTouchPointToScreenSpace(accumulated,x,y, scrW, scrH);
200
      convertCameraPointToScreenSpace(accumulated, cameraDistance);
201

    
202
      for(int face=FRONT; face<=BOTTOM; face++)
203
        {
204
        if( faceIsVisible(face,cubeHalfSize) )
205
          {
206
          castTouchPointOntoFace(face,cubeHalfSize, mTouchPointCastOntoFace);
207

    
208
          float qX= (mTouchPointCastOntoFace[0]+cubeHalfSize) / (2*cubeHalfSize);
209
          float qY= (mTouchPointCastOntoFace[1]+cubeHalfSize) / (2*cubeHalfSize);
210
          float qZ= (mTouchPointCastOntoFace[2]+cubeHalfSize) / (2*cubeHalfSize);
211

    
212
          if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return face;
213
          }
214
        }
215

    
216
      return NONE;
217
      }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
    public void addNewRotation(Static4D accumulated, int lastTouchedFace, int x, int y, int scrW, int scrH)
222
      {
223
      float cubeHalfSize= mCube.returnCubeSizeInScreenSpace()*0.5f;
224

    
225
      convertTouchPointToScreenSpace(accumulated, x,y, scrW, scrH);
226
      castTouchPointOntoFace(lastTouchedFace,cubeHalfSize,mDiff);
227

    
228
      mDiff[0] -= mTouchPointCastOntoFace[0];
229
      mDiff[1] -= mTouchPointCastOntoFace[1];
230
      mDiff[2] -= mTouchPointCastOntoFace[2];
231

    
232
      int xAxis = retFaceXaxis(lastTouchedFace);
233
      int yAxis = retFaceYaxis(lastTouchedFace);
234
      mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? VECT[xAxis]:VECT[yAxis]);
235
      float offset= (mTouchPointCastOntoFace[mRotationVect]+cubeHalfSize)/(2*cubeHalfSize);
236

    
237
      mTouchPoint[0] = mPoint[0];
238
      mTouchPoint[1] = mPoint[1];
239
      mTouchPoint[2] = mPoint[2];
240

    
241
      mCube.addNewRotation(mRotationVect, (int)(mCube.getSize()*offset) );
242
      }
243

    
244
///////////////////////////////////////////////////////////////////////////////////////////////////
245

    
246
    public void continueRotation(Static4D accumulated, int lastTouchedFace, int x, int y, int scrW, int scrH)
247
      {
248
      convertTouchPointToScreenSpace(accumulated, x,y, scrW, scrH);
249

    
250
      mDiff[0] = mPoint[0]-mTouchPoint[0];
251
      mDiff[1] = mPoint[1]-mTouchPoint[1];
252
      mDiff[2] = mPoint[2]-mTouchPoint[2];
253

    
254
      int xAxis= retFaceXaxis(lastTouchedFace);
255
      int yAxis= retFaceYaxis(lastTouchedFace);
256
      int sign = retFaceRotationSign(lastTouchedFace);
257
      float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]);
258

    
259
      int scrMin = scrW<scrH ? scrW:scrH;
260

    
261
      mCube.continueRotation(SWIPING_SENSITIVITY*sign*angle/scrMin);
262
      }
263
}
(2-2/2)