Project

General

Profile

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

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

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

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

    
27
public class RubikCubeMovement
28
{
29
    private 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
    private float[] mPoint, mCamera, mDiff, mTouch;
40
    private int mRotationVect, mLastTouchedFace;
41

    
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

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

    
49
///////////////////////////////////////////////////////////////////////////////////////////////////
50

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

    
56
///////////////////////////////////////////////////////////////////////////////////////////////////
57

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

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

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

    
80
      return -1;
81
      }
82

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84

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

    
97
      return -1;
98
      }
99

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101

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

    
114
      return -1;
115
      }
116

    
117
///////////////////////////////////////////////////////////////////////////////////////////////////
118

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

    
124
      return sign*mCamera[zAxis] > cubeHalfSize;
125
      }
126

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

    
132
    private void castTouchPointOntoFace(int face, float cubeHalfSize, float[] output)
133
      {
134
      int sign = retFaceSign(face);
135
      int zAxis= retFaceZaxis(face);
136
      float diff = mPoint[zAxis]-mCamera[zAxis];
137

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

    
140
      output[0] = (mPoint[0]-mCamera[0])*ratio + mCamera[0];
141
      output[1] = (mPoint[1]-mCamera[1])*ratio + mCamera[1];
142
      output[2] = (mPoint[2]-mCamera[2])*ratio + mCamera[2];
143
      }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146
// PUBLIC API
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
    public RubikCubeMovement()
150
      {
151
      mPoint = new float[3];
152
      mCamera= new float[3];
153
      mDiff  = new float[3];
154
      mTouch = new float[3];
155
      }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
    public boolean faceTouched(Static4D rotatedTouchPoint, Static4D rotatedCamera)
160
      {
161
      float cubeHalfSize= RubikCube.CUBE_SCREEN_RATIO*0.5f;
162

    
163
      mPoint[0]  = rotatedTouchPoint.get0();
164
      mPoint[1]  = rotatedTouchPoint.get1();
165
      mPoint[2]  = rotatedTouchPoint.get2();
166

    
167
      mCamera[0] = rotatedCamera.get0();
168
      mCamera[1] = rotatedCamera.get1();
169
      mCamera[2] = rotatedCamera.get2();
170

    
171
      for( mLastTouchedFace=FRONT; mLastTouchedFace<=BOTTOM; mLastTouchedFace++)
172
        {
173
        if( faceIsVisible(mLastTouchedFace,cubeHalfSize) )
174
          {
175
          castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize, mTouch);
176

    
177
          float qX= (mTouch[0]+cubeHalfSize) / (2*cubeHalfSize);
178
          float qY= (mTouch[1]+cubeHalfSize) / (2*cubeHalfSize);
179
          float qZ= (mTouch[2]+cubeHalfSize) / (2*cubeHalfSize);
180

    
181
          if( qX<=1 && qX>=0 && qY<=1 && qY>=0 && qZ<=1 && qZ>=0 ) return true;
182
          }
183
        }
184

    
185
      mLastTouchedFace = NONE;
186
      return false;
187
      }
188

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

    
191
    public Static2D newRotation(Static4D rotatedTouchPoint)
192
      {
193
      float cubeHalfSize= RubikCube.CUBE_SCREEN_RATIO*0.5f;
194

    
195
      mPoint[0] = rotatedTouchPoint.get0();
196
      mPoint[1] = rotatedTouchPoint.get1();
197
      mPoint[2] = rotatedTouchPoint.get2();
198

    
199
      castTouchPointOntoFace(mLastTouchedFace,cubeHalfSize,mDiff);
200

    
201
      mDiff[0] -= mTouch[0];
202
      mDiff[1] -= mTouch[1];
203
      mDiff[2] -= mTouch[2];
204

    
205
      int xAxis = retFaceXaxis(mLastTouchedFace);
206
      int yAxis = retFaceYaxis(mLastTouchedFace);
207
      mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? VECT[xAxis]:VECT[yAxis]);
208
      float offset= (mTouch[mRotationVect]+cubeHalfSize)/(2*cubeHalfSize);
209

    
210
      mTouch[0] = mPoint[0];
211
      mTouch[1] = mPoint[1];
212
      mTouch[2] = mPoint[2];
213

    
214
      return new Static2D(mRotationVect,offset);
215
      }
216

    
217
///////////////////////////////////////////////////////////////////////////////////////////////////
218

    
219
    public float continueRotation(Static4D rotatedTouchPoint)
220
      {
221
      mDiff[0] = rotatedTouchPoint.get0()-mTouch[0];
222
      mDiff[1] = rotatedTouchPoint.get1()-mTouch[1];
223
      mDiff[2] = rotatedTouchPoint.get2()-mTouch[2];
224

    
225
      int xAxis= retFaceXaxis(mLastTouchedFace);
226
      int yAxis= retFaceYaxis(mLastTouchedFace);
227
      int sign = retFaceRotationSign(mLastTouchedFace);
228
      float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]);
229

    
230
      return sign*angle;
231
      }
232
}
(2-2/3)