Project

General

Profile

« Previous | Next » 

Revision 840d83be

Added by Leszek Koltunski over 5 years ago

Improve the Rubik App.

View differences:

src/main/java/org/distorted/examples/rubik/RubikRenderer.java
46 46

  
47 47
class RubikRenderer implements GLSurfaceView.Renderer
48 48
{
49
            static final int NUM_CUBES =   6;
50
    private static final int VERTICES  =  10;
49
            static final int NUM_CUBES =   3;
51 50
    private static final int SIZE      = 200;
52 51

  
53 52
    private static final float CUBE_SCREEN_RATIO = 0.5f;
......
87 86
      mEffects = new DistortedEffects[NUM_CUBES][NUM_CUBES][NUM_CUBES];
88 87
      Static3D[][][] cubeVectors = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
89 88

  
90
      VertexEffectSink sink = new VertexEffectSink( new Static1D(3.0f),
89
      float sinkDegree = 3.0f - 1.7f/NUM_CUBES; // f(1)=1.3, f(inf)=3
90

  
91
      VertexEffectSink sink = new VertexEffectSink( new Static1D(sinkDegree),
91 92
                                                    new Static3D(SIZE*0.5f, SIZE*0.5f, SIZE*0.5f),
92 93
                                                    new Static4D(0,0,0, SIZE*0.72f) );
93 94
      mMove  = new Static3D(0,0,0);
......
96 97

  
97 98
      mLastRow = mLastCol = mLastSli = 0;
98 99

  
99
      mGlowRadius = new Static1D(10);
100
      mGlowRadius = new Static1D(5);
100 101
      mGlowColor  = new Static4D(1.0f,1.0f,1.0f,0.6f);
101 102

  
102 103
      MatrixEffectMove       move  = new MatrixEffectMove(mMove);
......
125 126
      final Static4D mapBlack = new Static4D(ze,ze, ze+of,ze+of);
126 127

  
127 128
      Static4D tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom;
129
      float nc = 0.5f*(NUM_CUBES-1);
130
      int vertices = (int)(24.0f/NUM_CUBES + 2.0f);
128 131

  
129 132
      for(int x = 0; x< NUM_CUBES; x++)
130 133
        for(int y = 0; y< NUM_CUBES; y++)
131 134
          for(int z = 0; z< NUM_CUBES; z++)
132 135
            {
133
            tmpLeft  = (x==            0 ? mapLeft  :mapBlack);
134
            tmpRight = (x== NUM_CUBES -1 ? mapRight :mapBlack);
135
            tmpFront = (z== NUM_CUBES -1 ? mapFront :mapBlack);
136
            tmpBack  = (z==            0 ? mapBack  :mapBlack);
137
            tmpTop   = (y== NUM_CUBES -1 ? mapTop   :mapBlack);
138
            tmpBottom= (y==            0 ? mapBottom:mapBlack);
139

  
140
            mCubes[x][y][z] = new MeshCubes(VERTICES,VERTICES,VERTICES, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
141

  
142
            cubeVectors[x][y][z] = new Static3D( SIZE*(x-0.5f*(NUM_CUBES -1)), SIZE*(y-0.5f*(NUM_CUBES -1)), SIZE*(z-0.5f*(NUM_CUBES -1)) );
143

  
144
            mEffects[x][y][z] = new DistortedEffects();
145

  
146
            mEffects[x][y][z].apply(sink);
147
            mEffects[x][y][z].apply(move);
148
            mEffects[x][y][z].apply(scale);
149
            mEffects[x][y][z].apply(quat1);
150
            mEffects[x][y][z].apply(quat2);
151
            mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
136
            if( x==0 || x==NUM_CUBES-1 || y==0 || y==NUM_CUBES-1 || z==0 || z==NUM_CUBES-1 ) // only the external walls
137
              {
138
              tmpLeft  = (x==            0 ? mapLeft  :mapBlack);
139
              tmpRight = (x== NUM_CUBES -1 ? mapRight :mapBlack);
140
              tmpFront = (z== NUM_CUBES -1 ? mapFront :mapBlack);
141
              tmpBack  = (z==            0 ? mapBack  :mapBlack);
142
              tmpTop   = (y== NUM_CUBES -1 ? mapTop   :mapBlack);
143
              tmpBottom= (y==            0 ? mapBottom:mapBlack);
144

  
145
              mCubes[x][y][z] = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
146

  
147
              cubeVectors[x][y][z] = new Static3D( SIZE*(x-nc), SIZE*(y-nc), SIZE*(z-nc) );
148

  
149
              mEffects[x][y][z] = new DistortedEffects();
150
              mEffects[x][y][z].apply(sink);
151
              mEffects[x][y][z].apply(move);
152
              mEffects[x][y][z].apply(scale);
153
              mEffects[x][y][z].apply(quat1);
154
              mEffects[x][y][z].apply(quat2);
155
              mEffects[x][y][z].apply( new MatrixEffectMove(cubeVectors[x][y][z]) );
156
              }
152 157
            }
153 158
      }
154 159

  
......
232 237
      for(int x = 0; x< NUM_CUBES; x++)
233 238
        for(int y = 0; y< NUM_CUBES; y++)
234 239
          for(int z = 0; z< NUM_CUBES; z++)
235
             mScreen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
240
            if( x==0 || x==NUM_CUBES-1 || y==0 || y==NUM_CUBES-1 || z==0 || z==NUM_CUBES-1 ) // only the external walls
241
              {
242
              mScreen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
243
              }
236 244

  
237 245
      PostprocessEffectGlow.enable();
238 246
      VertexEffectSink.enable();
src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java
25 25
import android.opengl.GLSurfaceView;
26 26
import android.view.MotionEvent;
27 27

  
28
import org.distorted.library.type.Static3D;
28 29
import org.distorted.library.type.Static4D;
29 30

  
30 31
///////////////////////////////////////////////////////////////////////////////////////////////////
31 32

  
32 33
class RubikSurfaceView extends GLSurfaceView
33 34
{
34
    private final static int NONE  =-1;
35
    private final static int NONE   =-1;
35 36
    private final static int FRONT  = 0;
36 37
    private final static int BACK   = 1;
37 38
    private final static int LEFT   = 2;
......
39 40
    private final static int TOP    = 4;
40 41
    private final static int BOTTOM = 5;
41 42

  
42
    private boolean mDragging;
43
    private static final int DIR_UP   =0;
44
    private static final int DIR_DOWN =1;
45
    private static final int DIR_LEFT =2;
46
    private static final int DIR_RIGHT=3;
47

  
48
    private static final Static3D VECTX = new Static3D(1,0,0);
49
    private static final Static3D VECTY = new Static3D(0,1,0);
50
    private static final Static3D VECTZ = new Static3D(0,0,1);
51

  
52
    private boolean mDragging, mRotating;
43 53
    private int mX, mY;
44 54
    private int mTouchedRow, mTouchedCol, mTouchedSli;
45 55
    private Static4D mQuatCurrent, mQuatAccumulated;
46 56
    private RubikRenderer mRenderer;
47 57

  
58
    private float mPoiX, mPoiY, mPoiZ, mCamX, mCamY, mCamZ;
59
    private float mStartX, mStartY, mStartZ;
60
    private int mLastTouchedFace;
61

  
48 62
///////////////////////////////////////////////////////////////////////////////////////////////////
49 63

  
50 64
    public RubikSurfaceView(Context context)
......
52 66
      super(context);
53 67

  
54 68
      mDragging = false;
69
      mRotating = false;
55 70
      mRenderer = new RubikRenderer(this);
56 71

  
57 72
      mQuatCurrent     = new Static4D(0,0,0,1);
......
81 96

  
82 97
      switch(action)
83 98
         {
84
         case MotionEvent.ACTION_DOWN: if( faceTouched(x,y) != NONE )
99
         case MotionEvent.ACTION_DOWN: mX = x;
100
                                       mY = y;
101

  
102
                                       mLastTouchedFace = faceTouched(x,y);
103

  
104
                                       if( mLastTouchedFace != NONE )
85 105
                                         {
86 106
                                         mRenderer.abortLastEffect();
87 107
                                         mRenderer.applyNewEffect(mTouchedCol, mTouchedRow, mTouchedSli);
108
                                         mRotating = true;
88 109
                                         }
89 110
                                       else
90 111
                                         {
91
                                         mX = x;
92
                                         mY = y;
93 112
                                         mDragging = true;
94 113
                                         }
95 114
                                       break;
......
98 117
                                         mQuatCurrent.set(quatFromDrag(mX-x,mY-y));
99 118
                                         mRenderer.setQuatCurrent(mQuatCurrent);
100 119
                                         }
120
                                       else if( mRotating )
121
                                         {
122
                                         int minimumToRotate = (mRenderer.mScreenMin*mRenderer.mScreenMin)/36;
123

  
124
                                         if( (mX-x)*(mX-x)+(mY-y)*(mY-y)>minimumToRotate )
125
                                           {
126
                                           rotateFace(x,y);
127
                                           mRotating = false;
128
                                           }
129
                                         }
101 130
                                       break;
102 131
         case MotionEvent.ACTION_UP  : mDragging = false;
132
                                       mRotating = false;
133

  
103 134
                                       mQuatAccumulated.set(quatMultiply(mQuatCurrent, mQuatAccumulated));
104 135
                                       mQuatCurrent.set(0f, 0f, 0f, 1f);
105

  
106 136
                                       mRenderer.setQuatCurrent(mQuatCurrent);
107 137
                                       mRenderer.setQuatAccumulated(mQuatAccumulated);
108 138
                                       break;
......
111 141
      return true;
112 142
      }
113 143

  
144
///////////////////////////////////////////////////////////////////////////////////////////////////
145

  
146
    private void rotateFace(int x, int y)
147
      {
148
      fillCameraAndTouchPoint(x,y);
149
      float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
150
      float A=0f;
151

  
152
      switch(mLastTouchedFace)
153
        {
154
        case FRONT : A = ( mPoiZ!=mCamZ ? ( cubeHalfSize-mCamZ)/(mPoiZ-mCamZ) : 0f); break;
155
        case BACK  : A = ( mPoiZ!=mCamZ ? (-cubeHalfSize-mCamZ)/(mPoiZ-mCamZ) : 0f); break;
156
        case LEFT  : A = ( mPoiX!=mCamX ? (-cubeHalfSize-mCamX)/(mPoiX-mCamX) : 0f); break;
157
        case RIGHT : A = ( mPoiX!=mCamX ? ( cubeHalfSize-mCamX)/(mPoiX-mCamX) : 0f); break;
158
        case TOP   : A = ( mPoiY!=mCamY ? ( cubeHalfSize-mCamY)/(mPoiY-mCamY) : 0f); break;
159
        case BOTTOM: A = ( mPoiY!=mCamY ? (-cubeHalfSize-mCamY)/(mPoiY-mCamY) : 0f); break;
160
        }
161
      float diffX = (mPoiX-mCamX)*A + mCamX - mStartX;
162
      float diffY = (mPoiY-mCamY)*A + mCamY - mStartY;
163
      float diffZ = (mPoiZ-mCamZ)*A + mCamZ - mStartZ;
164

  
165
      Static3D rotV=VECTX;
166
      int dir, rotA =1, rotRC=1;
167

  
168
      switch(mLastTouchedFace)
169
        {
170
        case FRONT : dir = retDirection( diffX, diffY);
171
                     rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTY;
172
                     rotA = (dir==DIR_UP || dir==DIR_LEFT) ? -90:90;
173
                     rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
174
                     break;
175
        case BACK  : dir = retDirection(-diffX, diffY);
176
                     rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTY;
177
                     rotA = (dir==DIR_UP || dir==DIR_RIGHT) ? 90:-90;
178
                     rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
179
                     break;
180
        case LEFT  : dir = retDirection( diffZ, diffY);
181
                     rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTZ:VECTY;
182
                     rotA = (dir==DIR_UP || dir==DIR_LEFT) ? -90:90;
183
                     rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTZ?mStartZ:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
184
                     break;
185
        case RIGHT : dir = retDirection(-diffZ, diffY);
186
                     rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTZ:VECTY;
187
                     rotA = (dir==DIR_UP || dir==DIR_RIGHT) ? 90:-90;
188
                     rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTZ?mStartZ:mStartY)+cubeHalfSize)/(2*cubeHalfSize) );
189
                     break;
190
        case TOP   : dir = retDirection( diffX,-diffZ);
191
                     rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTZ;
192
                     rotA = (dir==DIR_UP || dir==DIR_RIGHT) ? -90:90;
193
                     rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartZ)+cubeHalfSize)/(2*cubeHalfSize) );
194
                     break;
195
        case BOTTOM: dir = retDirection( diffX, diffZ);
196
                     rotV = (dir==DIR_UP || dir==DIR_DOWN) ? VECTX:VECTZ;
197
                     rotA = (dir==DIR_UP || dir==DIR_LEFT) ? -90:90;
198
                     rotRC = (int)( RubikRenderer.NUM_CUBES*((rotV==VECTX?mStartX:mStartZ)+cubeHalfSize)/(2*cubeHalfSize) );
199
                     break;
200
        }
201

  
202
      //if( rotRC==cubeHalfSize+1 ) rotRC=cubeHalfSize;
203

  
204
      String vect = (rotV==VECTX ? "X" : (rotV==VECTY? "Y":"Z") );
205

  
206
      android.util.Log.e("rubik", "rotating by "+rotA+" degrees, face="+rotRC+" vector: "+vect);
207
      }
208

  
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210

  
211
    private int retDirection(float a, float b)
212
      {
213
      if( b>a ) return a>-b ? DIR_UP   :DIR_LEFT;
214
      else      return a>-b ? DIR_RIGHT:DIR_DOWN;
215
      }
216

  
114 217
///////////////////////////////////////////////////////////////////////////////////////////////////
115 218
// return quat1*quat2
116 219

  
......
221 324

  
222 325
    private int faceTouched(int xTouch, int yTouch)
223 326
      {
224
      float cameraDistance = mRenderer.returnCameraDistance();
225
      float halfScrWidth   = mRenderer.getScreenWidth()*0.5f;
226
      float halfScrHeight  = mRenderer.getScreenHeight()*0.5f;
227
      float cubeHalfSize   = mRenderer.returnCubeSize()*0.5f;
327
      float cubeHalfSize= mRenderer.returnCubeSize()*0.5f;
228 328

  
229
      Static4D cameraPoint = new Static4D(                  0,                    0, cameraDistance, 0);
230
      Static4D touchPoint  = new Static4D(xTouch-halfScrWidth, halfScrHeight-yTouch,              0, 0);
231

  
232
      Static4D rotatedCamera    = rotateVector(cameraPoint);
233
      Static4D rotatedTouchPoint= rotateVector(touchPoint);
234

  
235
      float camX = rotatedCamera.get1();
236
      float camY = rotatedCamera.get2();
237
      float camZ = rotatedCamera.get3();
238

  
239
      float poiX = rotatedTouchPoint.get1();
240
      float poiY = rotatedTouchPoint.get2();
241
      float poiZ = rotatedTouchPoint.get3();
329
      fillCameraAndTouchPoint(xTouch,yTouch);
242 330

  
243 331
      if( faceIsVisible(FRONT) )
244 332
        {
245
        if( poiZ!= camZ )
333
        if( mPoiZ!= mCamZ )
246 334
          {
247
          float A = (cubeHalfSize-camZ)/(poiZ-camZ);
248
          float X = (poiX-camX)*A + camX;
249
          float Y = (poiY-camY)*A + camY;
250
          float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
251
          float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
335
          float A = (cubeHalfSize-mCamZ)/(mPoiZ-mCamZ);
336
          mStartX = (mPoiX-mCamX)*A + mCamX;
337
          mStartY = (mPoiY-mCamY)*A + mCamY;
338
          mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
339
          float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
340
          float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
252 341

  
253 342
          if( qX<=1 && qX>=0 && qY<=1 && qY>=0 )
254 343
            {
......
261 350
        }
262 351
      if( faceIsVisible(BACK) )
263 352
        {
264
        if( poiZ!= camZ )
353
        if( mPoiZ!= mCamZ )
265 354
          {
266
          float A = (-cubeHalfSize-camZ)/(poiZ-camZ);
267
          float X = (poiX-camX)*A + camX;
268
          float Y = (poiY-camY)*A + camY;
269
          float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
270
          float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
355
          float A = (-cubeHalfSize-mCamZ)/(mPoiZ-mCamZ);
356
          mStartX = (mPoiX-mCamX)*A + mCamX;
357
          mStartY = (mPoiY-mCamY)*A + mCamY;
358
          mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
359
          float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
360
          float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
271 361

  
272 362
          if( qX<=1 && qX>=0 && qY<=1 && qY>=0 )
273 363
            {
......
280 370
        }
281 371
      if( faceIsVisible(LEFT) )
282 372
        {
283
        if( poiX!= camX )
373
        if( mPoiX!= mCamX )
284 374
          {
285
          float A = (-cubeHalfSize-camX)/(poiX-camX);
286
          float Y = (poiY-camY)*A + camY;
287
          float Z = (poiZ-camZ)*A + camZ;
288
          float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
289
          float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
375
          float A = (-cubeHalfSize-mCamX)/(mPoiX-mCamX);
376
          mStartX = (mPoiX-mCamX)*A + mCamX;
377
          mStartY = (mPoiY-mCamY)*A + mCamY;
378
          mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
379
          float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
380
          float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
290 381

  
291 382
          if( qZ<=1 && qZ>=0 && qY<=1 && qY>=0 )
292 383
            {
......
299 390
        }
300 391
      if( faceIsVisible(RIGHT) )
301 392
        {
302
        if( poiX!= camX )
393
        if( mPoiX!= mCamX )
303 394
          {
304
          float A = (cubeHalfSize-camX)/(poiX-camX);
305
          float Y = (poiY-camY)*A + camY;
306
          float Z = (poiZ-camZ)*A + camZ;
307
          float qY= (Y+cubeHalfSize) / (2*cubeHalfSize);
308
          float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
395
          float A = (cubeHalfSize-mCamX)/(mPoiX-mCamX);
396
          mStartX = (mPoiX-mCamX)*A + mCamX;
397
          mStartY = (mPoiY-mCamY)*A + mCamY;
398
          mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
399
          float qY= (mStartY+cubeHalfSize) / (2*cubeHalfSize);
400
          float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
309 401

  
310 402
          if( qZ<=1 && qZ>=0 && qY<=1 && qY>=0 )
311 403
            {
......
318 410
        }
319 411
      if( faceIsVisible(TOP) )
320 412
        {
321
        if( poiY!= camY )
413
        if( mPoiY!= mCamY )
322 414
          {
323
          float A = (cubeHalfSize-camY)/(poiY-camY);
324
          float X = (poiX-camX)*A + camX;
325
          float Z = (poiZ-camZ)*A + camZ;
326
          float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
327
          float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
415
          float A = (cubeHalfSize-mCamY)/(mPoiY-mCamY);
416
          mStartX = (mPoiX-mCamX)*A + mCamX;
417
          mStartY = (mPoiY-mCamY)*A + mCamY;
418
          mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
419
          float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
420
          float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
328 421

  
329 422
          if( qZ<=1 && qZ>=0 && qX<=1 && qX>=0 )
330 423
            {
......
337 430
        }
338 431
      if( faceIsVisible(BOTTOM) )
339 432
        {
340
        if( poiY!= camY )
433
        if( mPoiY!= mCamY )
341 434
          {
342
          float A = (-cubeHalfSize-camY)/(poiY-camY);
343
          float X = (poiX-camX)*A + camX;
344
          float Z = (poiZ-camZ)*A + camZ;
345
          float qX= (X+cubeHalfSize) / (2*cubeHalfSize);
346
          float qZ= (Z+cubeHalfSize) / (2*cubeHalfSize);
435
          float A = (-cubeHalfSize-mCamY)/(mPoiY-mCamY);
436
          mStartX = (mPoiX-mCamX)*A + mCamX;
437
          mStartY = (mPoiY-mCamY)*A + mCamY;
438
          mStartZ = (mPoiZ-mCamZ)*A + mCamZ;
439
          float qX= (mStartX+cubeHalfSize) / (2*cubeHalfSize);
440
          float qZ= (mStartZ+cubeHalfSize) / (2*cubeHalfSize);
347 441

  
348 442
          if( qZ<=1 && qZ>=0 && qX<=1 && qX>=0 )
349 443
            {
......
361 455

  
362 456
      return NONE;
363 457
      }
458

  
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

  
461
    void fillCameraAndTouchPoint(int x, int y)
462
      {
463
      float cameraDistance = mRenderer.returnCameraDistance();
464
      float halfScrWidth   = mRenderer.getScreenWidth()*0.5f;
465
      float halfScrHeight  = mRenderer.getScreenHeight()*0.5f;
466

  
467
      Static4D cameraPoint = new Static4D(             0,               0, cameraDistance, 0);
468
      Static4D touchPoint  = new Static4D(x-halfScrWidth, halfScrHeight-y,              0, 0);
469

  
470
      Static4D rotatedCamera    = rotateVector(cameraPoint);
471
      Static4D rotatedTouchPoint= rotateVector(touchPoint);
472

  
473
      mCamX = rotatedCamera.get1();
474
      mCamY = rotatedCamera.get2();
475
      mCamZ = rotatedCamera.get3();
476

  
477
      mPoiX = rotatedTouchPoint.get1();
478
      mPoiY = rotatedTouchPoint.get2();
479
      mPoiZ = rotatedTouchPoint.get3();
480
      }
364 481
}
365 482

  

Also available in: Unified diff