Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / touchcontrol / TouchControlBarrel.java @ 1c7eebdc

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2024 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.touchcontrol;
11

    
12
import static org.distorted.objectlib.main.TwistyObject.SQ2;
13

    
14
import org.distorted.library.helpers.QuatHelper;
15
import org.distorted.library.type.Static3D;
16
import org.distorted.library.type.Static4D;
17
import org.distorted.objectlib.main.TwistyObject;
18

    
19
///////////////////////////////////////////////////////////////////////////////////////////////////
20
// Barrel-shaped objects: map the 2D swipes of user's fingers to 3D rotations
21

    
22
public class TouchControlBarrel extends TouchControl
23
{
24
  private static final float MIN_LEN = 0.35f;
25
  private static final float[] mTmp = new float[4];
26

    
27
  private final Static3D[] mRotAxis;
28
  private final float[] mPoint, mCamera, mTouch;
29
  private final int[] mEnabledRotAxis;
30
  private final int[][][] mEnabled;
31
  private final float[] mMove2D;
32
  private final float[][] mCastedRotAxis;
33
  private float[][] mTouchBorders;
34

    
35
  private float mRadius, mHeight;
36
  private float mX, mY, mZ;
37

    
38
  private static final float X = (float)Math.sqrt( (2-SQ2)/(6+SQ2) );
39
  private static final float Y = (float)Math.sqrt( (2+SQ2)/(6+SQ2) );
40

    
41
  public static final Static3D[] FACE_AXIS = new Static3D[]
42
        {
43
          new Static3D( X, Y, Y),
44
          new Static3D( X,-Y, Y),
45
          new Static3D( Y, Y, X),
46
          new Static3D( Y,-Y, X),
47
          new Static3D( Y, Y,-X),
48
          new Static3D( Y,-Y,-X),
49
          new Static3D( X, Y,-Y),
50
          new Static3D( X,-Y,-Y),
51
          new Static3D(-X, Y,-Y),
52
          new Static3D(-X,-Y,-Y),
53
          new Static3D(-Y, Y,-X),
54
          new Static3D(-Y,-Y,-X),
55
          new Static3D(-Y, Y, X),
56
          new Static3D(-Y,-Y, X),
57
          new Static3D(-X, Y, Y),
58
          new Static3D(-X,-Y, Y),
59
        };
60

    
61
///////////////////////////////////////////////////////////////////////////////////////////////////
62

    
63
  public TouchControlBarrel(TwistyObject object)
64
    {
65
    super(object);
66

    
67
    int[] numLayers       = object.getNumLayers();
68
    float[][] cuts        = object.getCuts(numLayers);
69
    boolean[][] rotatable = object.getLayerRotatable(numLayers);
70
    float size            = object.getSize();
71
    mRotAxis = object.getRotationAxis();
72
    mEnabled = object.getEnabled();
73

    
74
    mMove2D  = new float[2];
75

    
76
    mPoint = new float[3];
77
    mCamera= new float[3];
78
    mTouch = new float[3];
79

    
80
    int numRotAxis = mRotAxis.length;
81
    mEnabledRotAxis= new int[numRotAxis+1];
82
    mCastedRotAxis = new float[numRotAxis][2];
83

    
84
    mGhostAxisEnabled = -1;
85

    
86
    computeBorders(cuts,rotatable,size);
87
    }
88

    
89
///////////////////////////////////////////////////////////////////////////////////////////////////
90

    
91
  private float[] computeBorder(float[] cuts, boolean[] rotatable, float size)
92
    {
93
    if( cuts==null ) return null;
94

    
95
    int len = cuts.length;
96
    float[] border = new float[len];
97

    
98
    for(int i=0; i<len; i++)
99
      {
100
      if( !rotatable[i] )
101
        {
102
        border[i] = i>0 ? border[i-1] : -Float.MAX_VALUE;
103
        }
104
      else
105
        {
106
        if( rotatable[i+1] ) border[i] = cuts[i]/size;
107
        else
108
          {
109
          int found = -1;
110

    
111
          for(int j=i+2; j<=len; j++)
112
            {
113
            if( rotatable[j] )
114
              {
115
              found=j;
116
              break;
117
              }
118
            }
119

    
120
          border[i] = found>0 ? (cuts[i]+cuts[found-1])/(2*size) : Float.MAX_VALUE;
121
          }
122
        }
123
      }
124

    
125
    return border;
126
    }
127

    
128
///////////////////////////////////////////////////////////////////////////////////////////////////
129
// size, not numLayers (see Master Skewb where size!=numLayers) - also cuboids.
130

    
131
  void computeBorders(float[][] cuts, boolean[][] rotatable, float size)
132
    {
133
    int numCuts = cuts.length;
134
    mTouchBorders = new float[numCuts][];
135

    
136
    for(int axis=0; axis<numCuts; axis++)
137
      {
138
      mTouchBorders[axis] = computeBorder(cuts[axis],rotatable[axis],size);
139
      }
140
    }
141

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

    
144
  private int computeRowFromOffset(int axisIndex, float offset)
145
    {
146
    float[] borders = mTouchBorders[axisIndex];
147
    if( borders==null ) return 0;
148
    int len = borders.length;
149

    
150
    for(int i=0; i<len; i++)
151
      {
152
      if( offset<borders[i] ) return i;
153
      }
154

    
155
    return len;
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private float computeOffset(int rotIndex)
161
    {
162
    Static3D axis = mRotAxis[rotIndex];
163
    return mX*axis.get0() + mY*axis.get1() + mZ*axis.get2();
164
    }
165

    
166
///////////////////////////////////////////////////////////////////////////////////////////////////
167

    
168
  private void computeEnabledAxis()
169
    {
170
    if( mGhostAxisEnabled<0 )
171
      {
172
      int face = 0;//returnTouchedFace();
173
      int part = 0;//returnTouchedPart();
174
      int num = mEnabled[face][0].length;
175
      mEnabledRotAxis[0] = num;
176
      System.arraycopy(mEnabled[face][part], 0, mEnabledRotAxis, 1, num);
177
      }
178
    else
179
      {
180
      mEnabledRotAxis[0] = 1;  // if in 'ghost' mode, only one axis is enabled.
181
      mEnabledRotAxis[1] = mGhostAxisEnabled;
182
      }
183
    }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

    
187
  private boolean crossesPipe(float radius, float vx, float vy, float vz)
188
    {
189
    return false;
190
    }
191

    
192
///////////////////////////////////////////////////////////////////////////////////////////////////
193

    
194
  private boolean crossesPlane(float nx, float ny, float nz, float d, float vx, float vy, float vz)
195
    {
196
    return false;
197
    }
198

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200

    
201
  public boolean axisAndFaceAgree(int axisIndex)
202
    {
203
    return false;
204
    }
205

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

    
208
  public int getTouchedCubitFace()
209
    {
210
    return 0;
211
    }
212

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

    
215
  public float[] getTouchedPuzzleCenter()
216
    {
217
    return null;
218
    }
219

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221

    
222
  public int getTouchedCubit()
223
    {
224
    return 0;
225
    }
226

    
227
///////////////////////////////////////////////////////////////////////////////////////////////////
228
// simply cast the appropriate rotational axis of the object to the screen surface.
229

    
230
  public void getCastedRotAxis(float[] output, Static4D quat, int axisIndex)
231
    {
232
    Static3D a = mRotAxis[axisIndex];
233
    getCastedRotAxis(output,quat,a.get0(),a.get1(),a.get2(),0);
234
    }
235

    
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237

    
238
  public boolean objectTouched(Static4D rotatedTouchPoint, Static4D rotatedCamera)
239
    {
240
    mPoint[0]  = rotatedTouchPoint.get0()/mObjectRatio;
241
    mPoint[1]  = rotatedTouchPoint.get1()/mObjectRatio;
242
    mPoint[2]  = rotatedTouchPoint.get2()/mObjectRatio;
243

    
244
    mCamera[0] = rotatedCamera.get0()/mObjectRatio;
245
    mCamera[1] = rotatedCamera.get1()/mObjectRatio;
246
    mCamera[2] = rotatedCamera.get2()/mObjectRatio;
247

    
248
    float vx = mCamera[0]-mPoint[0];
249
    float vy = mCamera[1]-mPoint[1];
250
    float vz = mCamera[2]-mPoint[2];
251
    float x1=0,y1=0,z1=0;
252
    float x2=0,y2=0,z2=0;
253
    float x3=0,y3=0,z3=0;
254
    float len1=Float.MAX_VALUE;
255
    float len2=Float.MAX_VALUE;
256
    float len3=Float.MAX_VALUE;
257

    
258
    if( crossesPipe(mRadius,vx,vy,vz) )
259
      {
260
      x1 = mX;
261
      y1 = mY;
262
      z1 = mZ;
263
      float dx = mX-mCamera[0];
264
      float dy = mY-mCamera[1];
265
      float dz = mZ-mCamera[2];
266
      len1 = dx*dx + dy*dy + dz*dz;
267
      }
268
    if( crossesPlane(0,1,0,mHeight,vx,vy,vz) )
269
      {
270
      x2 = mX;
271
      y2 = mY;
272
      z2 = mZ;
273
      float dx = mX-mCamera[0];
274
      float dy = mY-mCamera[1];
275
      float dz = mZ-mCamera[2];
276
      len2 = dx*dx + dy*dy + dz*dz;
277
      }
278
    if( crossesPlane(0,-1,0,mHeight,vx,vy,vz) )
279
      {
280
      x3 = mX;
281
      y3 = mY;
282
      z3 = mZ;
283
      float dx = mX-mCamera[0];
284
      float dy = mY-mCamera[1];
285
      float dz = mZ-mCamera[2];
286
      len3 = dx*dx + dy*dy + dz*dz;
287
      }
288

    
289
    if( len1<len2 && len1<len3 )
290
      {
291
      mX = x1;
292
      mY = y1;
293
      mZ = z1;
294
      return true;
295
      }
296
    if( len2<len1 && len2<len3 )
297
      {
298
      mX = x2;
299
      mY = y2;
300
      mZ = z2;
301
      return true;
302
      }
303
    if( len3<len1 && len3<len2 )
304
      {
305
      mX = x3;
306
      mY = y3;
307
      mZ = z3;
308
      return true;
309
      }
310

    
311
    return false;
312
    }
313

    
314
///////////////////////////////////////////////////////////////////////////////////////////////////
315

    
316
  public void newRotation(int[] output, Static4D rotatedTouchPoint, Static4D quat)
317
    {
318
    computeEnabledAxis();
319

    
320
    mTouch[0]  = rotatedTouchPoint.get0()/mObjectRatio;
321
    mTouch[1]  = rotatedTouchPoint.get1()/mObjectRatio;
322
    mTouch[2]  = rotatedTouchPoint.get2()/mObjectRatio;
323

    
324
    float x = mTouch[0]-mPoint[0];
325
    float y = mTouch[1]-mPoint[1];
326
    float z = mTouch[2]-mPoint[2];
327

    
328
    QuatHelper.rotateVectorByQuat(mTmp,x,y,z,0,quat);
329
    mMove2D[0] = mTmp[0];
330
    mMove2D[1] = mTmp[1];
331

    
332
    for(int i=1; i<=mEnabledRotAxis[0]; i++)
333
      {
334
      int enabled = mEnabledRotAxis[i];
335
      Static3D axis = mRotAxis[enabled];
336
      float[] vector = mCastedRotAxis[enabled];
337
      float bx = axis.get0();
338
      float by = axis.get1();
339
      float bz = axis.get2();
340

    
341
      QuatHelper.rotateVectorByQuat(mTmp,bx,by,bz,0,quat);
342
      float len = (float)Math.sqrt(mTmp[0]*mTmp[0] + mTmp[1]*mTmp[1]);
343

    
344
      if( len<MIN_LEN )
345
        {
346
        vector[0] = 1000f;  // switch off the axis because when casted
347
        vector[1] = 1000f;  // onto the screen it is too short
348
        }
349
      else
350
        {
351
        vector[0] = mTmp[0]/len;
352
        vector[1] = mTmp[1]/len;
353
        }
354
      }
355

    
356
    int rotIndex = computeRotationIndex( mCastedRotAxis, mMove2D, mEnabledRotAxis);
357
    float offset = computeOffset(rotIndex);
358
    int row      = computeRowFromOffset(rotIndex,offset);
359

    
360
    output[0] = rotIndex;
361
    output[1] = row;
362
    }
363
}
(3-3/14)