Project

General

Profile

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

magiccube / src / main / java / org / distorted / bandaged / BandagedCreatorTouchControl.java @ 707f79ff

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2022 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.bandaged;
21

    
22
import org.distorted.library.main.QuatHelper;
23
import org.distorted.library.type.Static3D;
24
import org.distorted.library.type.Static4D;
25
import org.distorted.objectlib.touchcontrol.TouchControlHexahedron;
26

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

    
29
public class BandagedCreatorTouchControl
30
{
31
  private static final float DIST3D = 0.5f;
32
  private static final float DIST2D = 0.5f;
33

    
34
  private final Static4D CAMERA_POINT;
35
  private final float[] mPoint, mCamera, mTouch, mPos;
36
  private final float[] mPoint2D;
37
  private float mObjectRatio;
38
  private final Static3D[] mFaceAxis;
39

    
40
  private BandagedCubit[] mCubits;
41
  private int mNumCubits;
42
  private int mLastTouchedFace;
43

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

    
46
  private boolean isInsideFace(float[] p)
47
    {
48
    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
49
    }
50

    
51
///////////////////////////////////////////////////////////////////////////////////////////////////
52
// Convert the 3D point3D into a 2D point on the same face surface, but in a different
53
// coordinate system: a in-plane 2D coord where the origin is in the point where the axis intersects
54
// the surface, and whose Y axis points 'north' i.e. is in the plane given by the 3D origin, the
55
// original 3D Y axis and our 2D in-plane origin.
56
// If those 3 points constitute a degenerate triangle which does not define a plane - which can only
57
// happen if axis is vertical (or in theory when 2D origin and 3D origin meet, but that would have to
58
// mean that the distance between the center of the Object and its faces is 0) - then we arbitrarily
59
// decide that 2D Y = (0,0,-1) in the North Pole and (0,0,1) in the South Pole)
60
// (ax,ay,az) - vector normal to the face surface.
61

    
62
  void convertTo2Dcoords(float[] point3D, float ax, float ay, float az , float[] output)
63
    {
64
    float y0,y1,y2; // base Y vector of the 2D coord system
65

    
66
    if( ax==0.0f && az==0.0f )
67
      {
68
      y0=0; y1=0; y2=-ay;
69
      }
70
    else if( ay==0.0f )
71
      {
72
      y0=0; y1=1; y2=0;
73
      }
74
    else
75
      {
76
      float norm = (float)(-ay/Math.sqrt(1-ay*ay));
77
      y0 = norm*ax; y1= norm*(ay-1/ay); y2=norm*az;
78
      }
79

    
80
    float x0 = y1*az - y2*ay;  //
81
    float x1 = y2*ax - y0*az;  // (2D coord baseY) x (axis) = 2D coord baseX
82
    float x2 = y0*ay - y1*ax;  //
83

    
84
    float originAlpha = point3D[0]*ax + point3D[1]*ay + point3D[2]*az;
85

    
86
    float origin0 = originAlpha*ax; // coords of the point where axis
87
    float origin1 = originAlpha*ay; // intersects surface plane i.e.
88
    float origin2 = originAlpha*az; // the origin of our 2D coord system
89

    
90
    float v0 = point3D[0] - origin0;
91
    float v1 = point3D[1] - origin1;
92
    float v2 = point3D[2] - origin2;
93

    
94
    output[0] = v0*x0 + v1*x1 + v2*x2;
95
    output[1] = v0*y0 + v1*y1 + v2*y2;
96
    }
97

    
98
///////////////////////////////////////////////////////////////////////////////////////////////////
99
// given precomputed mCamera and mPoint, respectively camera and touch point positions in ScreenSpace,
100
// compute point 'output[]' which:
101
// 1) lies on a face of the Object, i.e. surface defined by (axis, distance from (0,0,0))
102
// 2) is co-linear with mCamera and mPoint
103
//
104
// output = camera + alpha*(point-camera), where alpha = [dist-axis*camera] / [axis*(point-camera)]
105

    
106
  private void castTouchPointOntoFace(int index, float[] output)
107
    {
108
    Static3D faceAxis = mFaceAxis[index];
109

    
110
    float d0 = mPoint[0]-mCamera[0];
111
    float d1 = mPoint[1]-mCamera[1];
112
    float d2 = mPoint[2]-mCamera[2];
113
    float a0 = faceAxis.get0();
114
    float a1 = faceAxis.get1();
115
    float a2 = faceAxis.get2();
116

    
117
    float denom = a0*d0 + a1*d1 + a2*d2;
118

    
119
    if( denom != 0.0f )
120
      {
121
      float axisCam = a0*mCamera[0] + a1*mCamera[1] + a2*mCamera[2];
122
      float alpha = (DIST3D-axisCam)/denom;
123

    
124
      output[0] = mCamera[0] + d0*alpha;
125
      output[1] = mCamera[1] + d1*alpha;
126
      output[2] = mCamera[2] + d2*alpha;
127
      }
128
    }
129

    
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

    
132
  private boolean faceIsVisible(int index)
133
    {
134
    Static3D faceAxis = mFaceAxis[index];
135
    float castCameraOnAxis = mCamera[0]*faceAxis.get0() + mCamera[1]*faceAxis.get1() + mCamera[2]*faceAxis.get2();
136
    return castCameraOnAxis > DIST3D;
137
    }
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

    
141
  private boolean objectTouched(Static4D rotatedTouchPoint, Static4D rotatedCamera)
142
    {
143
    mPoint[0]  = rotatedTouchPoint.get0()/mObjectRatio;
144
    mPoint[1]  = rotatedTouchPoint.get1()/mObjectRatio;
145
    mPoint[2]  = rotatedTouchPoint.get2()/mObjectRatio;
146

    
147
    mCamera[0] = rotatedCamera.get0()/mObjectRatio;
148
    mCamera[1] = rotatedCamera.get1()/mObjectRatio;
149
    mCamera[2] = rotatedCamera.get2()/mObjectRatio;
150

    
151
    for( mLastTouchedFace=0; mLastTouchedFace<6; mLastTouchedFace++)
152
      {
153
      if( faceIsVisible(mLastTouchedFace) )
154
        {
155
        castTouchPointOntoFace(mLastTouchedFace, mTouch);
156

    
157
        float ax = mFaceAxis[mLastTouchedFace].get0();
158
        float ay = mFaceAxis[mLastTouchedFace].get1();
159
        float az = mFaceAxis[mLastTouchedFace].get2();
160

    
161
        convertTo2Dcoords(mTouch, ax,ay,az, mPoint2D);
162
        if( isInsideFace(mPoint2D) ) return true;
163
        }
164
      }
165

    
166
    return false;
167
    }
168

    
169
///////////////////////////////////////////////////////////////////////////////////////////////////
170

    
171
  private void computePosition(int face, float pointX, float pointY)
172
    {
173
    int x = (int)(3*pointX+1.5f) -1;
174
    int y = (int)(3*pointY+1.5f) -1;
175

    
176
    switch(face)
177
      {
178
      case 0: mPos[0] = 1.0f; mPos[1] =    y; mPos[2] =   -x; break;
179
      case 1: mPos[0] =-1.0f; mPos[1] =    y; mPos[2] =    x; break;
180
      case 2: mPos[0] =    x; mPos[1] = 1.0f; mPos[2] =   -y; break;
181
      case 3: mPos[0] =    x; mPos[1] =-1.0f; mPos[2] =    y; break;
182
      case 4: mPos[0] =    x; mPos[1] =    y; mPos[2] = 1.0f; break;
183
      case 5: mPos[0] =   -x; mPos[1] =    y; mPos[2] =-1.0f; break;
184
      }
185
    }
186

    
187
///////////////////////////////////////////////////////////////////////////////////////////////////
188

    
189
  private int whichCubitTouched(int face, float pointX, float pointY)
190
    {
191
    computePosition(face,pointX,pointY);
192

    
193
    for(int c=0; c<mNumCubits; c++)
194
      if( mCubits[c].isAttached() )
195
        {
196
        float[] pos = mCubits[c].getPosition();
197
        int len = pos.length/3;
198

    
199
        for(int p=0; p<len; p++)
200
          if( pos[3*p]==mPos[0] && pos[3*p+1]==mPos[1] && pos[3*p+2]==mPos[2] ) return c;
201
        }
202

    
203
    android.util.Log.e("D", "whichCubitTouched: IMPOSSIBLE!!");
204
    return -1;
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208
// PUBLIC API
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

    
211
  public BandagedCreatorTouchControl(float ratio, float fov)
212
    {
213
    mPoint = new float[3];
214
    mCamera= new float[3];
215
    mTouch = new float[3];
216
    mPos   = new float[3];
217
    mPoint2D = new float[2];
218
    mFaceAxis = TouchControlHexahedron.FACE_AXIS;
219
    mObjectRatio = ratio;
220

    
221
    double halfFOV = fov * (Math.PI/360);
222
    float tanHalf = (float)Math.tan(halfFOV);
223
    float dist = 0.5f/tanHalf;
224

    
225
    CAMERA_POINT = new Static4D(0,0,dist,0);
226
    }
227

    
228
///////////////////////////////////////////////////////////////////////////////////////////////////
229

    
230
  public void setCubits(BandagedCubit[] cubits)
231
    {
232
    mCubits = cubits;
233
    mNumCubits = cubits.length;
234
    }
235

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

    
238
  public void setObjectRatio(float ratio)
239
    {
240
    mObjectRatio = ratio;
241
    }
242

    
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244
// return the index of the cubit touched; if none, return -1.
245

    
246
  public int cubitTouched(float x, float y, Static4D quat)
247
    {
248
    Static4D touchPoint = new Static4D(x, y, 0, 0);
249
    Static4D rotatedTouchPoint= QuatHelper.rotateVectorByInvertedQuat(touchPoint, quat);
250
    Static4D rotatedCamera= QuatHelper.rotateVectorByInvertedQuat(CAMERA_POINT, quat);
251

    
252
    boolean touched = objectTouched(rotatedTouchPoint,rotatedCamera);
253

    
254
    if( !touched ) return -1;
255

    
256
    return whichCubitTouched(mLastTouchedFace,mPoint2D[0],mPoint2D[1]);
257
    }
258
}
259

    
(5-5/13)