Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / FactoryCubit.java @ a7a40b3c

1 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 a7a40b3c Leszek Koltunski
// 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 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 198c5bf0 Leszek Koltunski
package org.distorted.objectlib.helpers;
11 29b82486 Leszek Koltunski
12
import org.distorted.library.effect.MatrixEffectMove;
13
import org.distorted.library.effect.MatrixEffectQuaternion;
14
import org.distorted.library.effect.MatrixEffectScale;
15
import org.distorted.library.effect.VertexEffect;
16
import org.distorted.library.effect.VertexEffectDeform;
17 a706f8e0 Leszek Koltunski
import org.distorted.library.main.QuatHelper;
18 29b82486 Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
19
import org.distorted.library.mesh.MeshJoined;
20
import org.distorted.library.mesh.MeshPolygon;
21
import org.distorted.library.type.Static1D;
22
import org.distorted.library.type.Static3D;
23
import org.distorted.library.type.Static4D;
24
25
import java.util.ArrayList;
26
27 c3a033e9 Leszek Koltunski
import static org.distorted.objectlib.main.TwistyObject.MESH_FAST;
28
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
29
30 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
31
32
public class FactoryCubit
33
  {
34
  private static final Static1D RADIUS = new Static1D(1);
35
  private static FactoryCubit mThis;
36
37 d99de43c Leszek Koltunski
  private static final float MAX_CORE_DIFF = 0.01f;
38
39 57ef6378 Leszek Koltunski
  private static final float[] mBuffer = new float[3];
40
  private static final float[] mQuat1  = new float[4];
41
  private static final float[] mQuat2  = new float[4];
42
  private static final float[] mQuat3  = new float[4];
43 29b82486 Leszek Koltunski
44 1561a74f Leszek Koltunski
  public static class StickerCoords
45 29b82486 Leszek Koltunski
    {
46 57ef6378 Leszek Koltunski
    float[] vertices;
47 1561a74f Leszek Koltunski
    float scale;
48 2617d26b Leszek Koltunski
    boolean outer;
49 29b82486 Leszek Koltunski
    }
50
51
  private static class FaceTransform
52
    {
53 7af68038 Leszek Koltunski
    int face;
54
    int numFaces;
55
56 29b82486 Leszek Koltunski
    int sticker;
57 57ef6378 Leszek Koltunski
    float vx,vy,vz;
58
    float scale;
59
    float qx,qy,qz,qw;
60 29b82486 Leszek Koltunski
    }
61
62
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
63
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
64
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
65
66
///////////////////////////////////////////////////////////////////////////////////////////////////
67
68
  private FactoryCubit()
69
    {
70 3bf19410 Leszek Koltunski
71 29b82486 Leszek Koltunski
    }
72
73
///////////////////////////////////////////////////////////////////////////////////////////////////
74
// H - height of the band in the middle
75
// alpha - angle of the edge  [0,90]
76
// dist - often in a polygon the distance from edge to center is not 1, but something else.
77
// This is the distance.
78
// K - where to begin the second, much more flat part of the band. [0,1]
79
// N - number of bands. N>=3
80
//
81
// theory: two distinct parts to the band:
82
// 1) (0,B) - steep
83
// 2) (B,1) - flat
84
//
85
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
86
//
87
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
88
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
89
// h(x) = R*(sin(alpha) - sin(x))
90
// R = H/(1-cos(alpha))
91
// D = H*sin(alpha)
92
// B = h(K*alpha)
93
//
94
// The N points are taken at:
95
//
96
// 1) in the second part, there are K2 = (N-3)/3 such points
97
// 2) in the first - K1 = (N-3) - K2
98
// 3) also, the 3 points 0,B,1
99
//
100
// so we have the sequence A[i] of N points
101
//
102
// 0
103
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
104
// B
105
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
106
// 1
107
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109
110
  private float f(float D, float B, float x)
111
    {
112
    return ((D-B)*x + B*(1-D))/(1-B);
113
    }
114
115
///////////////////////////////////////////////////////////////////////////////////////////////////
116
117
  private float g(float R, float D, float x, float cosAlpha)
118
    {
119
    float d = x-D;
120
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
121
    }
122
123
///////////////////////////////////////////////////////////////////////////////////////////////////
124
125
  private float h(float R, float sinAlpha, float x)
126
    {
127
    return R*(sinAlpha-(float)Math.sin(x));
128
    }
129
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131
132 57ef6378 Leszek Koltunski
  private boolean areColinear(float[][] vertices, int index1, int index2, int index3)
133 29b82486 Leszek Koltunski
    {
134 57ef6378 Leszek Koltunski
    float x1 = vertices[index1][0];
135
    float y1 = vertices[index1][1];
136
    float z1 = vertices[index1][2];
137
    float x2 = vertices[index2][0];
138
    float y2 = vertices[index2][1];
139
    float z2 = vertices[index2][2];
140
    float x3 = vertices[index3][0];
141
    float y3 = vertices[index3][1];
142
    float z3 = vertices[index3][2];
143 29b82486 Leszek Koltunski
144 57ef6378 Leszek Koltunski
    float v1x = x2-x1;
145
    float v1y = y2-y1;
146
    float v1z = z2-z1;
147
    float v2x = x3-x1;
148
    float v2y = y3-y1;
149
    float v2z = z3-z1;
150 29b82486 Leszek Koltunski
151
    double A = Math.sqrt( (v1x*v1x+v1y*v1y+v1z*v1z) / (v2x*v2x+v2y*v2y+v2z*v2z) );
152
153
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
154
    }
155
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157
158 57ef6378 Leszek Koltunski
  private void computeNormalVector(float[][] vertices, int index1, int index2, int index3)
159 29b82486 Leszek Koltunski
    {
160 57ef6378 Leszek Koltunski
    float x1 = vertices[index1][0];
161
    float y1 = vertices[index1][1];
162
    float z1 = vertices[index1][2];
163
    float x2 = vertices[index2][0];
164
    float y2 = vertices[index2][1];
165
    float z2 = vertices[index2][2];
166
    float x3 = vertices[index3][0];
167
    float y3 = vertices[index3][1];
168
    float z3 = vertices[index3][2];
169 29b82486 Leszek Koltunski
170 57ef6378 Leszek Koltunski
    float v1x = x2-x1;
171
    float v1y = y2-y1;
172
    float v1z = z2-z1;
173
    float v2x = x3-x1;
174
    float v2y = y3-y1;
175
    float v2z = z3-z1;
176 29b82486 Leszek Koltunski
177
    mBuffer[0] = v1y*v2z - v2y*v1z;
178
    mBuffer[1] = v1z*v2x - v2z*v1x;
179
    mBuffer[2] = v1x*v2y - v2x*v1y;
180
181
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
182
    len = Math.sqrt(len);
183
    mBuffer[0] /= len;
184
    mBuffer[1] /= len;
185
    mBuffer[2] /= len;
186
    }
187
188
///////////////////////////////////////////////////////////////////////////////////////////////////
189
190 2617d26b Leszek Koltunski
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
191 29b82486 Leszek Koltunski
    {
192 57ef6378 Leszek Koltunski
    float minX = Float.MAX_VALUE;
193
    float maxX =-Float.MAX_VALUE;
194
    float minY = Float.MAX_VALUE;
195
    float maxY =-Float.MAX_VALUE;
196 29b82486 Leszek Koltunski
197 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
198 29b82486 Leszek Koltunski
      {
199 57ef6378 Leszek Koltunski
      float x = vert[0];
200
      float y = vert[1];
201 29b82486 Leszek Koltunski
202
      if (x > maxX) maxX = x;
203
      if (x < minX) minX = x;
204
      if (y > maxY) maxY = y;
205
      if (y < minY) minY = y;
206
      }
207
208
    minX = minX<0 ? -minX:minX;
209
    maxX = maxX<0 ? -maxX:maxX;
210
    minY = minY<0 ? -minY:minY;
211
    maxY = maxY<0 ? -maxY:maxY;
212
213 57ef6378 Leszek Koltunski
    float max1 = Math.max(minX,minY);
214
    float max2 = Math.max(maxX,maxY);
215
    float max3 = Math.max(max1,max2);
216 29b82486 Leszek Koltunski
217 57ef6378 Leszek Koltunski
    info.scale = max3/0.5f;
218 29b82486 Leszek Koltunski
219
    int len = vert3D.length;
220
    StickerCoords sInfo = new StickerCoords();
221 2617d26b Leszek Koltunski
    sInfo.outer = isOuter;
222 1561a74f Leszek Koltunski
    sInfo.scale = info.scale;
223 57ef6378 Leszek Koltunski
    sInfo.vertices = new float[2*len];
224 29b82486 Leszek Koltunski
225
    for( int vertex=0; vertex<len; vertex++ )
226
      {
227
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
228
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
229
      }
230
231
    mStickerCoords.add(sInfo);
232
233
    info.sticker = mStickerCoords.size() -1;
234
    }
235
236
///////////////////////////////////////////////////////////////////////////////////////////////////
237
238 7af68038 Leszek Koltunski
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
239 29b82486 Leszek Koltunski
    {
240
    FaceTransform ft = new FaceTransform();
241 7af68038 Leszek Koltunski
    ft.face = face;
242
    ft.numFaces = numFaces;
243 29b82486 Leszek Koltunski
244
    // compute center of gravity
245
    ft.vx = 0.0f;
246
    ft.vy = 0.0f;
247
    ft.vz = 0.0f;
248
    int len = vert3D.length;
249
250 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
251 29b82486 Leszek Koltunski
      {
252
      ft.vx += vert[0];
253
      ft.vy += vert[1];
254
      ft.vz += vert[2];
255
      }
256
257
    ft.vx /= len;
258
    ft.vy /= len;
259
    ft.vz /= len;
260
261
    // move all vertices so that their center of gravity is at (0,0,0)
262
    for (int i=0; i<len; i++)
263
      {
264
      vert3D[i][0] -= ft.vx;
265
      vert3D[i][1] -= ft.vy;
266
      vert3D[i][2] -= ft.vz;
267
      }
268
269
    // find 3 non-colinear vertices
270
    int foundIndex = -1;
271
272
    for(int vertex=2; vertex<len; vertex++)
273
      {
274
      if( !areColinear(vert3D,0,1,vertex) )
275
        {
276
        foundIndex = vertex;
277
        break;
278
        }
279
      }
280
281
    // compute the normal vector
282
    if( foundIndex==-1 )
283
      {
284
      throw new RuntimeException("all vertices colinear");
285
      }
286
287
    computeNormalVector(vert3D,0,1,foundIndex);
288
289
    // rotate so that the normal vector becomes (0,0,1)
290 57ef6378 Leszek Koltunski
    float axisX, axisY, axisZ;
291 29b82486 Leszek Koltunski
292
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
293
      {
294
      axisX = -mBuffer[1];
295
      axisY =  mBuffer[0];
296
      axisZ = 0.0f;
297
298 57ef6378 Leszek Koltunski
      float axiLen = axisX*axisX + axisY*axisY;
299
      axiLen = (float)Math.sqrt(axiLen);
300 29b82486 Leszek Koltunski
      axisX /= axiLen;
301
      axisY /= axiLen;
302
      axisZ /= axiLen;
303
      }
304
    else
305
      {
306
      axisX = 0.0f;
307
      axisY = 1.0f;
308
      axisZ = 0.0f;
309
      }
310
311 57ef6378 Leszek Koltunski
    float cosTheta = mBuffer[2];
312
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
313
    float sinHalfTheta = computeSinHalf(cosTheta);
314
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
315 29b82486 Leszek Koltunski
316
    mQuat1[0] = axisX*sinHalfTheta;
317
    mQuat1[1] = axisY*sinHalfTheta;
318
    mQuat1[2] = axisZ*sinHalfTheta;
319
    mQuat1[3] = cosHalfTheta;
320
    mQuat2[0] =-axisX*sinHalfTheta;
321
    mQuat2[1] =-axisY*sinHalfTheta;
322
    mQuat2[2] =-axisZ*sinHalfTheta;
323
    mQuat2[3] = cosHalfTheta;
324
325 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
326 29b82486 Leszek Koltunski
      {
327 d809bf6f Leszek Koltunski
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
328
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
329 29b82486 Leszek Koltunski
      }
330
331
    // fit the whole thing in a square and remember the scale & 2D vertices
332 2617d26b Leszek Koltunski
    fitInSquare(ft, vert3D, isOuter);
333 29b82486 Leszek Koltunski
334
    // remember the rotation
335
    ft.qx =-mQuat1[0];
336
    ft.qy =-mQuat1[1];
337
    ft.qz =-mQuat1[2];
338
    ft.qw = mQuat1[3];
339
340
    return ft;
341
    }
342
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344
345 57ef6378 Leszek Koltunski
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
346 29b82486 Leszek Koltunski
    {
347
    for(int i=0; i<len; i++)
348
      {
349
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
350
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
351
      }
352
    }
353
354
///////////////////////////////////////////////////////////////////////////////////////////////////
355
356 57ef6378 Leszek Koltunski
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
357 29b82486 Leszek Koltunski
    {
358 57ef6378 Leszek Koltunski
    float v1x = v1[2*v1i];
359
    float v1y = v1[2*v1i+1];
360
    float v2x = v2[2*v2i];
361
    float v2y = v2[2*v2i+1];
362 29b82486 Leszek Koltunski
363 57ef6378 Leszek Koltunski
    float lenSq1 = v1x*v1x + v1y*v1y;
364
    float lenSq2 = v2x*v2x + v2y*v2y;
365 29b82486 Leszek Koltunski
366 57ef6378 Leszek Koltunski
    return (float)Math.sqrt(lenSq2/lenSq1);
367 29b82486 Leszek Koltunski
    }
368
369
///////////////////////////////////////////////////////////////////////////////////////////////////
370
// valid for 0<angle<2*PI
371
372 57ef6378 Leszek Koltunski
  private float computeSinHalf(float cos)
373 29b82486 Leszek Koltunski
    {
374 57ef6378 Leszek Koltunski
    return (float)Math.sqrt((1-cos)/2);
375 29b82486 Leszek Koltunski
    }
376
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378
// valid for 0<angle<2*PI
379
380 57ef6378 Leszek Koltunski
  private float computeCosHalf(float sin, float cos)
381 29b82486 Leszek Koltunski
    {
382 57ef6378 Leszek Koltunski
    float cosHalf = (float)Math.sqrt((1+cos)/2);
383 29b82486 Leszek Koltunski
    return sin<0 ? -cosHalf : cosHalf;
384
    }
385
386
///////////////////////////////////////////////////////////////////////////////////////////////////
387
388 846b69f3 Leszek Koltunski
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
389 29b82486 Leszek Koltunski
    {
390 846b69f3 Leszek Koltunski
    int v = (rotatedVertex + oldVertex);
391 29b82486 Leszek Koltunski
    if( v>=len ) v-=len;
392
    if( v< 0   ) v+=len;
393
394
    return v;
395
    }
396
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398
399 846b69f3 Leszek Koltunski
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex)
400 29b82486 Leszek Koltunski
    {
401 846b69f3 Leszek Koltunski
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
402 57ef6378 Leszek Koltunski
    float EPSILON = 0.001f;
403
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
404 29b82486 Leszek Koltunski
405
    for(int i=1; i<len; i++)
406
      {
407 846b69f3 Leszek Koltunski
      int index = computeRotatedIndex(i,len,vertex);
408 29b82486 Leszek Koltunski
409 57ef6378 Leszek Koltunski
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
410
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
411 29b82486 Leszek Koltunski
412
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
413
      }
414
415
    return true;
416
    }
417
418
///////////////////////////////////////////////////////////////////////////////////////////////////
419
420 846b69f3 Leszek Koltunski
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
421 29b82486 Leszek Koltunski
    {
422
    mStickerCoords.remove(info.sticker);
423
424
    info.sticker = oldSticker;
425
    info.scale  *= scale;
426
427
    mQuat1[0] = info.qx;
428
    mQuat1[1] = info.qy;
429
    mQuat1[2] = info.qz;
430
    mQuat1[3] = info.qw;
431
432 57ef6378 Leszek Koltunski
    float sinHalf = computeSinHalf(cos);
433
    float cosHalf = computeCosHalf(sin,cos);
434 29b82486 Leszek Koltunski
435 846b69f3 Leszek Koltunski
    mQuat2[0] = 0.0f;
436
    mQuat2[1] = 0.0f;
437
    mQuat2[2] = sinHalf;
438
    mQuat2[3] = cosHalf;
439 29b82486 Leszek Koltunski
440 d809bf6f Leszek Koltunski
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
441 29b82486 Leszek Koltunski
442
    info.qx = mQuat3[0];
443
    info.qy = mQuat3[1];
444
    info.qz = mQuat3[2];
445
    info.qw = mQuat3[3];
446
    }
447
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449
450
  private void printVert(double[] buffer)
451
    {
452
    int len = buffer.length/2;
453
    String str = "";
454
455
    for(int i=0; i<len; i++)
456
      {
457
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
458
      }
459
460
    android.util.Log.d("D", str);
461
    }
462
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464
465 bf4e7e68 Leszek Koltunski
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert, float[] oldVert, int oldSticker)
466 29b82486 Leszek Koltunski
    {
467 bf4e7e68 Leszek Koltunski
    int lenVertOld = oldVert.length/2;
468
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
469
470
    for(int oldV=0; oldV<lenVertOld; oldV++)
471
      {
472
      oldX = oldVert[2*oldV];
473
      oldY = oldVert[2*oldV+1];
474
      lenOld = (float)Math.sqrt(oldX*oldX + oldY*oldY);
475
476
      if( lenOld!=0 ) break;
477
      }
478
479 29b82486 Leszek Koltunski
    for(int vertex=0; vertex<len; vertex++)
480
      {
481 57ef6378 Leszek Koltunski
      float newX = newVert[2*vertex  ];
482
      float newY = newVert[2*vertex+1];
483 bf4e7e68 Leszek Koltunski
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
484 29b82486 Leszek Koltunski
485 bf4e7e68 Leszek Koltunski
      if( lenNew!=0 )
486 29b82486 Leszek Koltunski
        {
487 bf4e7e68 Leszek Koltunski
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
488
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
489
490
        rotateAllVertices(buffer,len,newVert,sin,cos);
491
492
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
493
          {
494
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
495
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
496
          correctInfo(info,scale,sin,cos,oldSticker);
497
          return true;
498
          }
499 29b82486 Leszek Koltunski
        }
500
      }
501
502
    return false;
503
    }
504
505 d99de43c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
506
507
  private float computeCoreDistance(float[] verts)
508
    {
509
    float ret = 0.0f;
510
    float centerX=0.0f,centerY=0.0f;
511
    int len = verts.length/2;
512
513
    for(int i=0; i<len; i++)
514
      {
515
      centerX += verts[2*i  ];
516
      centerY += verts[2*i+1];
517
      }
518
519
    centerX /= (2*len);
520
    centerY /= (2*len);
521
522
    for(int i=0; i<len; i++)
523
      {
524
      float distX = centerX-verts[2*i  ];
525
      float distY = centerY-verts[2*i+1];
526
      ret += (float)Math.sqrt(distX*distX + distY*distY);
527
      }
528
529
    return ret;
530
    }
531
532 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
533
534
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
535
    {
536
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
537
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
538 d99de43c Leszek Koltunski
539 57ef6378 Leszek Koltunski
    float[] newVert = sNewInfo.vertices;
540
    float[] oldVert = sOldInfo.vertices;
541 29b82486 Leszek Koltunski
    int oldLen = oldVert.length;
542
    int newLen = newVert.length;
543
544 f7d2e0e1 Leszek Koltunski
    if( oldLen==newLen )
545 29b82486 Leszek Koltunski
      {
546 bf4e7e68 Leszek Koltunski
      float coreDistOld = computeCoreDistance(oldVert);                     // the two stickers are at different scales,
547 d99de43c Leszek Koltunski
      float coreDistNew = computeCoreDistance(newVert);                     // so even if they are in fact the same, do not
548
      float diff = (coreDistOld*oldInfo.scale)/(coreDistNew*newInfo.scale); // collapse them into one. Example: Master Skewb
549
      if( diff<1.0-MAX_CORE_DIFF || diff>1.0+MAX_CORE_DIFF ) return false;  // and two triangular stickers of different size.
550
551 29b82486 Leszek Koltunski
      int oldSticker = oldInfo.sticker;
552 57ef6378 Leszek Koltunski
      float[] buffer1 = new float[oldLen];
553 bf4e7e68 Leszek Koltunski
554
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, oldSticker) )
555 f7d2e0e1 Leszek Koltunski
        {
556 d99de43c Leszek Koltunski
        if( sNewInfo.outer ) sOldInfo.outer = true;
557 f7d2e0e1 Leszek Koltunski
        return true;
558
        }
559 29b82486 Leszek Koltunski
      }
560
561
    return false;
562
    }
563
564
///////////////////////////////////////////////////////////////////////////////////////////////////
565
566 57ef6378 Leszek Koltunski
  private float[][] constructVert(float[][] vertices, int[] index)
567 29b82486 Leszek Koltunski
    {
568
    int len = index.length;
569 57ef6378 Leszek Koltunski
    float[][] ret = new float[len][4];
570 29b82486 Leszek Koltunski
571
    for(int i=0; i<len; i++)
572
      {
573
      ret[i][0] = vertices[index[i]][0];
574
      ret[i][1] = vertices[index[i]][1];
575
      ret[i][2] = vertices[index[i]][2];
576
      ret[i][3] = 1.0f;
577
      }
578
579
    return ret;
580
    }
581
582
///////////////////////////////////////////////////////////////////////////////////////////////////
583
584 57ef6378 Leszek Koltunski
  private void prepareAndRoundCorners(MeshBase mesh, float[][] vertices,
585 29b82486 Leszek Koltunski
                                      float[][] corners, int[] cornerIndexes,
586
                                      float[][] centers, int[] centerIndexes )
587
    {
588
    int lenV = vertices.length;
589
    Static3D[] staticVert = new Static3D[1];
590
    Static3D center = new Static3D(0,0,0);
591
592
    for(int v=0; v<lenV; v++)
593
      {
594 2617d26b Leszek Koltunski
      staticVert[0] = new Static3D( vertices[v][0],vertices[v][1],vertices[v][2] );
595 29b82486 Leszek Koltunski
596
      int cent = centerIndexes[v];
597
598
      if( cent>=0 )
599
        {
600
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
601
602
        int corn = cornerIndexes[v];
603
604
        if( corn>=0 )
605
          {
606
          float strength = corners[corn][0];
607
          float radius   = corners[corn][1];
608
          roundCorners(mesh, center, staticVert, strength, radius);
609
          }
610
        }
611
      }
612
    }
613
614
///////////////////////////////////////////////////////////////////////////////////////////////////
615
616
  private void correctComponents(MeshBase mesh, int numComponents)
617
    {
618
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
619
620
    mesh.mergeEffComponents();
621
622
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
623
    }
624
625
///////////////////////////////////////////////////////////////////////////////////////////////////
626
627
  private void printTransform(FaceTransform f)
628
    {
629 7af68038 Leszek Koltunski
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
630 846b69f3 Leszek Koltunski
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
631 29b82486 Leszek Koltunski
    }
632
633
///////////////////////////////////////////////////////////////////////////////////////////////////
634
635 b2c77ec3 Leszek Koltunski
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
636 29b82486 Leszek Koltunski
    {
637
    float[] bands = new float[2*N];
638
639
    bands[0] = 1.0f;
640
    bands[1] = 0.0f;
641
642
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
643
    float sinBeta = (float)Math.sin(beta);
644
    float cosBeta = (float)Math.cos(beta);
645
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
646
    float D = R*sinBeta;
647
    float B = h(R,sinBeta,K*beta);
648
649
    if( D>1.0f )
650
      {
651
      for(int i=1; i<N; i++)
652
        {
653
        bands[2*i  ] = (float)(N-1-i)/(N-1);
654
        bands[2*i+1] = H*(1-bands[2*i]);
655
        }
656
      }
657
    else
658
      {
659
      int K2 = (int)((N-3)*K);
660
      int K1 = (N-3)-K2;
661
662
      for(int i=0; i<=K1; i++)
663
        {
664
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
665
        float x = h(R,sinBeta,angle);
666
        bands[2*i+2] = 1.0f - x;
667
        bands[2*i+3] = g(R,D,x,cosBeta);
668
        }
669
670
      for(int i=0; i<=K2; i++)
671
        {
672
        float x = (1-B)*(i+1)/(K2+1) + B;
673
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
674
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
675
        }
676
      }
677
678
    bands[2*N-2] = 0.0f;
679
    bands[2*N-1] =    H;
680
681
    return bands;
682
    }
683
684
///////////////////////////////////////////////////////////////////////////////////////////////////
685
686 b2c77ec3 Leszek Koltunski
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
687 29b82486 Leszek Koltunski
    {
688
    Static4D reg= new Static4D(0,0,0,regionRadius);
689
690
    float centX = center.get0();
691
    float centY = center.get1();
692
    float centZ = center.get2();
693
694
    for (Static3D vertex : vertices)
695
      {
696
      float x = strength*(centX - vertex.get0());
697
      float y = strength*(centY - vertex.get1());
698
      float z = strength*(centZ - vertex.get2());
699
700
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
701
      mesh.apply(effect);
702
      }
703
    }
704
705
///////////////////////////////////////////////////////////////////////////////////////////////////
706
707 b2c77ec3 Leszek Koltunski
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
708
    {
709
    if( in==null )
710
      {
711
      out[0] = out[1] = 0.0f;
712
      }
713
    else
714
      {
715
      out[0] = in[0] - ft.vx;
716
      out[1] = in[1] - ft.vy;
717
      out[2] = in[2] - ft.vz;
718
      out[3] = 1.0f;
719
720
      mQuat1[0] =-ft.qx;
721
      mQuat1[1] =-ft.qy;
722
      mQuat1[2] =-ft.qz;
723
      mQuat1[3] = ft.qw;
724
725
      mQuat2[0] = -mQuat1[0];
726
      mQuat2[1] = -mQuat1[1];
727
      mQuat2[2] = -mQuat1[2];
728
      mQuat2[3] = +mQuat1[3];
729
730 d809bf6f Leszek Koltunski
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
731
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
732 b2c77ec3 Leszek Koltunski
733
      out[0] /= ft.scale;
734
      out[1] /= ft.scale;
735
      out[2] /= ft.scale;
736
      }
737
    }
738
739
///////////////////////////////////////////////////////////////////////////////////////////////////
740
741
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
742
    {
743
    int len = table.length;
744
745
    for(int i=0; i<len; i++)
746
      {
747
      int lenInner = table[i].length;
748
749
      for(int j=0; j<lenInner; j++)
750
        if( table[i][j]==oldPointer ) table[i][j] = newPointer;
751
      }
752
    }
753
754
///////////////////////////////////////////////////////////////////////////////////////////////////
755
// INTERNAL API
756
757 f7d2e0e1 Leszek Koltunski
  public int printStickerCoords()
758 29b82486 Leszek Koltunski
    {
759
    int stickers = mStickerCoords.size();
760 f7d2e0e1 Leszek Koltunski
    int ret = 0;
761 29b82486 Leszek Koltunski
762
    android.util.Log.d("D", "---- STICKER COORDS ----");
763
764
    for(int s=0; s<stickers; s++)
765
      {
766
      StickerCoords info = mStickerCoords.get(s);
767
768 f7d2e0e1 Leszek Koltunski
      if( info.outer )  ret++;
769 29b82486 Leszek Koltunski
770 1561a74f Leszek Koltunski
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
771 f7d2e0e1 Leszek Koltunski
      int len = info.vertices.length/2;
772 2617d26b Leszek Koltunski
773 f7d2e0e1 Leszek Koltunski
      for(int i =0; i<len; i++)
774
        {
775
        if( i!=0 ) ver += ", ";
776
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
777 2617d26b Leszek Koltunski
        }
778 f7d2e0e1 Leszek Koltunski
779
      ver += " }";
780
      android.util.Log.d("D", ver);
781 29b82486 Leszek Koltunski
      }
782
783
    android.util.Log.d("D", "---- END STICKER COORDS ----");
784 f7d2e0e1 Leszek Koltunski
785
    return ret;
786 29b82486 Leszek Koltunski
    }
787
788
///////////////////////////////////////////////////////////////////////////////////////////////////
789
790
  public void printFaceTransform()
791
    {
792
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
793
794
    int oldfaces = mOldFaceTransf.size();
795
796
    for(int f=0; f<oldfaces; f++)
797
      {
798
      printTransform(mOldFaceTransf.get(f));
799
      }
800
801
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
802
803
    int newfaces = mNewFaceTransf.size();
804
805
    for(int f=0; f<newfaces; f++)
806
      {
807
      printTransform(mNewFaceTransf.get(f));
808
      }
809
    }
810
811
///////////////////////////////////////////////////////////////////////////////////////////////////
812 b2c77ec3 Leszek Koltunski
// PUBLIC API
813 29b82486 Leszek Koltunski
814 b2c77ec3 Leszek Koltunski
  public static FactoryCubit getInstance()
815 29b82486 Leszek Koltunski
    {
816 b2c77ec3 Leszek Koltunski
    if( mThis==null ) mThis = new FactoryCubit();
817 29b82486 Leszek Koltunski
818 b2c77ec3 Leszek Koltunski
    return mThis;
819 29b82486 Leszek Koltunski
    }
820
821 1561a74f Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
822
823 3d2493ea Leszek Koltunski
  public float[] getStickerScales()
824 1561a74f Leszek Koltunski
    {
825
    int index=0,num=0,len = mStickerCoords.size();
826
827 3d2493ea Leszek Koltunski
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
828 1561a74f Leszek Koltunski
829
    if( num>0 )
830
      {
831 b2c77ec3 Leszek Koltunski
      float[] scales = new float[num];
832 1561a74f Leszek Koltunski
833
      for(int i=0; i<len; i++)
834
        {
835
        StickerCoords sticker = mStickerCoords.get(i);
836 3d2493ea Leszek Koltunski
        if( sticker.outer ) scales[index++] = sticker.scale;
837 1561a74f Leszek Koltunski
        }
838
839 b2c77ec3 Leszek Koltunski
      return scales;
840 1561a74f Leszek Koltunski
      }
841
842
    return null;
843
    }
844
845
///////////////////////////////////////////////////////////////////////////////////////////////////
846
847 3d2493ea Leszek Koltunski
  public float[][] getStickerCoords()
848 1561a74f Leszek Koltunski
    {
849
    int index=0,num=0,len = mStickerCoords.size();
850
851 3d2493ea Leszek Koltunski
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
852 1561a74f Leszek Koltunski
853
    if( num>0 )
854
      {
855 b2c77ec3 Leszek Koltunski
      float[][] coords = new float[num][];
856 1561a74f Leszek Koltunski
857
      for(int i=0; i<len; i++)
858
        {
859
        StickerCoords sticker = mStickerCoords.get(i);
860 3d2493ea Leszek Koltunski
        if( sticker.outer ) coords[index++] = sticker.vertices;
861 1561a74f Leszek Koltunski
        }
862
863 b2c77ec3 Leszek Koltunski
      return coords;
864 1561a74f Leszek Koltunski
      }
865
866
    return null;
867
    }
868
869 7af68038 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
870
871
  public int[][] getStickerVariants()
872
    {
873
    int numvariants = 1; // there's one in the 'new' array
874
875
    int oldfaces = mOldFaceTransf.size();
876
877
    for(int f=0; f<oldfaces; f++)
878
      {
879
      FaceTransform ft = mOldFaceTransf.get(f);
880
      if( ft.face==0 ) numvariants++;
881
      }
882
883
    int[][] ret = new int[numvariants][];
884
    int inner=0, index=-1;
885
886
    for(int f=0; f<oldfaces; f++)
887
      {
888
      FaceTransform ft = mOldFaceTransf.get(f);
889
      if( ft.face==0 )
890
        {
891
        index++;
892
        inner=0;
893
        ret[index] = new int[ft.numFaces];
894
        }
895
896
      ret[index][inner++] = ft.sticker;
897
      }
898
899
    int newfaces = mNewFaceTransf.size();
900
901
    for(int f=0; f<newfaces; f++)
902
      {
903
      FaceTransform ft = mNewFaceTransf.get(f);
904
      if( ft.face==0 )
905
        {
906
        index++;
907
        inner=0;
908
        ret[index] = new int[ft.numFaces];
909
        }
910
911
      ret[index][inner++] = ft.sticker;
912
      }
913
914
    int numStickers = mStickerCoords.size();
915
    int numOuter=0;
916
917
    for(int i=0; i<numStickers; i++)
918
      {
919
      StickerCoords sc = mStickerCoords.get(i);
920
      if( sc.outer )
921
        {
922
        changeStickerPointers(ret,i,numOuter);
923
        numOuter++;
924
        }
925
      else
926
        {
927
        changeStickerPointers(ret,i,-1);
928
        }
929
      }
930
931
    return ret;
932
    }
933
934 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
935
936 b2c77ec3 Leszek Koltunski
  public void clear()
937 29b82486 Leszek Koltunski
    {
938 b2c77ec3 Leszek Koltunski
    mStickerCoords.clear();
939
    mNewFaceTransf.clear();
940
    mOldFaceTransf.clear();
941
    }
942
943 df781f1d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
944
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
945
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
946
// been called.
947
948
  public Static4D getQuaternion(int face)
949
    {
950
    FaceTransform ft = mNewFaceTransf.get(face);
951
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
952
    }
953
954 b2c77ec3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
955
956 59a971c1 Leszek Koltunski
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
957 b2c77ec3 Leszek Koltunski
    {
958
    float[][] vertices = shape.getVertices();
959
    int[][] indices = shape.getVertIndices();
960
    FaceTransform ft;
961
    int numNew = mNewFaceTransf.size();
962
963
    for(int i=0; i<numNew; i++)
964
      {
965
      ft = mNewFaceTransf.remove(0);
966
      mOldFaceTransf.add(ft);
967
      }
968
969
    int numFaces = indices.length;
970
    int numOld = mOldFaceTransf.size();
971
972
    for (int face=0; face<numFaces; face++)
973
      {
974
      boolean collapsed = false;
975 59a971c1 Leszek Koltunski
      boolean isOuter = (outer!=null && outer[face]>0);
976 b2c77ec3 Leszek Koltunski
977
      float[][] vert = constructVert(vertices, indices[face]);
978
      FaceTransform newT = constructNewTransform(vert,isOuter,face,numFaces);
979
980
      for (int old=0; !collapsed && old<numOld; old++)
981
        {
982
        ft = mOldFaceTransf.get(old);
983
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
984
        }
985
986
      for (int pre=0; !collapsed && pre<face; pre++)
987
        {
988
        ft = mNewFaceTransf.get(pre);
989
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
990
        }
991
992
      mNewFaceTransf.add(newT);
993
      }
994 29b82486 Leszek Koltunski
    }
995
996
///////////////////////////////////////////////////////////////////////////////////////////////////
997
998 b2c77ec3 Leszek Koltunski
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape, int meshState, int numComponents)
999 29b82486 Leszek Koltunski
    {
1000 b2c77ec3 Leszek Koltunski
    float[][] vertices      = shape.getVertices();
1001
    int[][] vertIndexes     = shape.getVertIndices();
1002
    float[][] bands         = faceShape.getBands();
1003
    int[]   bandIndexes     = faceShape.getBandIndices();
1004
    float[][] corners       = faceShape.getCorners();
1005
    int[]   cornerIndexes   = faceShape.getCornerIndices();
1006
    float[][] centers       = faceShape.getCenters();
1007
    int[]   centerIndexes   = faceShape.getCenterIndices();
1008
    float[] convexityCenter = faceShape.getConvexityCenter();
1009
1010 29b82486 Leszek Koltunski
    int numFaces = vertIndexes.length;
1011 50fb62bf Leszek Koltunski
    float[] band, bandsComputed;
1012 29b82486 Leszek Koltunski
    MeshBase[] meshes = new MeshBase[numFaces];
1013
    FaceTransform fInfo;
1014
    StickerCoords sInfo;
1015 57ef6378 Leszek Koltunski
    float[] convexXY = new float[4];
1016 50fb62bf Leszek Koltunski
    int exIndex=0, exVertices=0, alpha=0, N=0;
1017
    float height=0.0f, dist=0.0f, K=0.0f;
1018 29b82486 Leszek Koltunski
1019
    for(int face=0; face<numFaces; face++)
1020
      {
1021
      fInfo = mNewFaceTransf.get(face);
1022
      sInfo = mStickerCoords.get(fInfo.sticker);
1023
1024 57ef6378 Leszek Koltunski
      float[] verts = sInfo.vertices;
1025 c850eb4f Leszek Koltunski
      int lenVerts = verts.length;
1026
      float[] copiedVerts = new float[lenVerts];
1027
      System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1028 29b82486 Leszek Koltunski
1029
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1030
1031
      band = bands[bandIndexes[face]];
1032 c3a033e9 Leszek Koltunski
1033
      switch(meshState)
1034
        {
1035 50fb62bf Leszek Koltunski
        case MESH_NICE: height     = band[0];
1036
                        alpha      = (int)band[1];
1037
                        dist       = band[2];
1038
                        K          = band[3];
1039
                        N          = (int)band[4];
1040 c3a033e9 Leszek Koltunski
                        exIndex    = (int)band[5];
1041
                        exVertices = (int)band[6];
1042
                        break;
1043 50fb62bf Leszek Koltunski
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
1044
                                                               // (example: Ivy cube center and edge cubits!)
1045
                        alpha      = 0;
1046
                        dist       = 0;
1047
                        K          = 0;
1048
                        N          = 2;
1049 c3a033e9 Leszek Koltunski
                        exIndex    = 0;
1050
                        exVertices = 0;
1051
                        break;
1052
        }
1053
1054 50fb62bf Leszek Koltunski
      bandsComputed = computeBands(height,alpha,dist,K,N);
1055 c3a033e9 Leszek Koltunski
      meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1056 0b5d4a7b Leszek Koltunski
      meshes[face].setEffectAssociation(0,0,face);
1057 29b82486 Leszek Koltunski
      }
1058
1059
    MeshBase mesh = new MeshJoined(meshes);
1060
    Static3D center = new Static3D(0,0,0);
1061
1062
    for(int face=0; face<numFaces; face++)
1063
      {
1064
      fInfo = mNewFaceTransf.get(face);
1065
1066 57ef6378 Leszek Koltunski
      float vx = fInfo.vx;
1067
      float vy = fInfo.vy;
1068
      float vz = fInfo.vz;
1069
      float sc = fInfo.scale;
1070
      float qx = fInfo.qx;
1071
      float qy = fInfo.qy;
1072
      float qz = fInfo.qz;
1073
      float qw = fInfo.qw;
1074 29b82486 Leszek Koltunski
1075 846b69f3 Leszek Koltunski
      Static3D scale = new Static3D(sc,sc,sc);
1076 29b82486 Leszek Koltunski
      Static3D move3D= new Static3D(vx,vy,vz);
1077
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1078
1079 0b5d4a7b Leszek Koltunski
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1080
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1081
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1082 29b82486 Leszek Koltunski
      }
1083
1084 18d97487 Leszek Koltunski
    correctComponents(mesh,numComponents);
1085
1086 c3a033e9 Leszek Koltunski
    if( meshState==MESH_NICE )
1087
      {
1088
      prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
1089
      }
1090 29b82486 Leszek Koltunski
1091
    return mesh;
1092
    }
1093
  }