Project

General

Profile

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

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

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.objectlib.helpers;
21

    
22
import org.distorted.library.effect.MatrixEffectMove;
23
import org.distorted.library.effect.MatrixEffectQuaternion;
24
import org.distorted.library.effect.MatrixEffectScale;
25
import org.distorted.library.effect.VertexEffect;
26
import org.distorted.library.effect.VertexEffectDeform;
27
import org.distorted.library.main.QuatHelper;
28
import org.distorted.library.mesh.MeshBase;
29
import org.distorted.library.mesh.MeshJoined;
30
import org.distorted.library.mesh.MeshPolygon;
31
import org.distorted.library.type.Static1D;
32
import org.distorted.library.type.Static3D;
33
import org.distorted.library.type.Static4D;
34

    
35
import java.util.ArrayList;
36

    
37
import static org.distorted.objectlib.main.TwistyObject.MESH_FAST;
38
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

    
42
public class FactoryCubit
43
  {
44
  private static final Static1D RADIUS = new Static1D(1);
45
  private static FactoryCubit mThis;
46

    
47
  private static final float MAX_CORE_DIFF = 0.01f;
48

    
49
  private static final float[] mBuffer = new float[3];
50
  private static final float[] mQuat1  = new float[4];
51
  private static final float[] mQuat2  = new float[4];
52
  private static final float[] mQuat3  = new float[4];
53

    
54
  public static class StickerCoords
55
    {
56
    float[] vertices;
57
    float scale;
58
    boolean outer;
59
    }
60

    
61
  private static class FaceTransform
62
    {
63
    int face;
64
    int numFaces;
65

    
66
    int sticker;
67
    float vx,vy,vz;
68
    float scale;
69
    float qx,qy,qz,qw;
70
    }
71

    
72
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
73
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
74
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
75

    
76
///////////////////////////////////////////////////////////////////////////////////////////////////
77

    
78
  private FactoryCubit()
79
    {
80

    
81
    }
82

    
83
///////////////////////////////////////////////////////////////////////////////////////////////////
84
// H - height of the band in the middle
85
// alpha - angle of the edge  [0,90]
86
// dist - often in a polygon the distance from edge to center is not 1, but something else.
87
// This is the distance.
88
// K - where to begin the second, much more flat part of the band. [0,1]
89
// N - number of bands. N>=3
90
//
91
// theory: two distinct parts to the band:
92
// 1) (0,B) - steep
93
// 2) (B,1) - flat
94
//
95
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
96
//
97
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
98
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
99
// h(x) = R*(sin(alpha) - sin(x))
100
// R = H/(1-cos(alpha))
101
// D = H*sin(alpha)
102
// B = h(K*alpha)
103
//
104
// The N points are taken at:
105
//
106
// 1) in the second part, there are K2 = (N-3)/3 such points
107
// 2) in the first - K1 = (N-3) - K2
108
// 3) also, the 3 points 0,B,1
109
//
110
// so we have the sequence A[i] of N points
111
//
112
// 0
113
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
114
// B
115
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
116
// 1
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

    
120
  private float f(float D, float B, float x)
121
    {
122
    return ((D-B)*x + B*(1-D))/(1-B);
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126

    
127
  private float g(float R, float D, float x, float cosAlpha)
128
    {
129
    float d = x-D;
130
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  private float h(float R, float sinAlpha, float x)
136
    {
137
    return R*(sinAlpha-(float)Math.sin(x));
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  private boolean areColinear(float[][] vertices, int index1, int index2, int index3)
143
    {
144
    float x1 = vertices[index1][0];
145
    float y1 = vertices[index1][1];
146
    float z1 = vertices[index1][2];
147
    float x2 = vertices[index2][0];
148
    float y2 = vertices[index2][1];
149
    float z2 = vertices[index2][2];
150
    float x3 = vertices[index3][0];
151
    float y3 = vertices[index3][1];
152
    float z3 = vertices[index3][2];
153

    
154
    float v1x = x2-x1;
155
    float v1y = y2-y1;
156
    float v1z = z2-z1;
157
    float v2x = x3-x1;
158
    float v2y = y3-y1;
159
    float v2z = z3-z1;
160

    
161
    double A = Math.sqrt( (v1x*v1x+v1y*v1y+v1z*v1z) / (v2x*v2x+v2y*v2y+v2z*v2z) );
162

    
163
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
164
    }
165

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

    
168
  private void computeNormalVector(float[][] vertices, int index1, int index2, int index3)
169
    {
170
    float x1 = vertices[index1][0];
171
    float y1 = vertices[index1][1];
172
    float z1 = vertices[index1][2];
173
    float x2 = vertices[index2][0];
174
    float y2 = vertices[index2][1];
175
    float z2 = vertices[index2][2];
176
    float x3 = vertices[index3][0];
177
    float y3 = vertices[index3][1];
178
    float z3 = vertices[index3][2];
179

    
180
    float v1x = x2-x1;
181
    float v1y = y2-y1;
182
    float v1z = z2-z1;
183
    float v2x = x3-x1;
184
    float v2y = y3-y1;
185
    float v2z = z3-z1;
186

    
187
    mBuffer[0] = v1y*v2z - v2y*v1z;
188
    mBuffer[1] = v1z*v2x - v2z*v1x;
189
    mBuffer[2] = v1x*v2y - v2x*v1y;
190

    
191
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
192
    len = Math.sqrt(len);
193
    mBuffer[0] /= len;
194
    mBuffer[1] /= len;
195
    mBuffer[2] /= len;
196
    }
197

    
198
///////////////////////////////////////////////////////////////////////////////////////////////////
199

    
200
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
201
    {
202
    float minX = Float.MAX_VALUE;
203
    float maxX =-Float.MAX_VALUE;
204
    float minY = Float.MAX_VALUE;
205
    float maxY =-Float.MAX_VALUE;
206

    
207
    for (float[] vert : vert3D)
208
      {
209
      float x = vert[0];
210
      float y = vert[1];
211

    
212
      if (x > maxX) maxX = x;
213
      if (x < minX) minX = x;
214
      if (y > maxY) maxY = y;
215
      if (y < minY) minY = y;
216
      }
217

    
218
    minX = minX<0 ? -minX:minX;
219
    maxX = maxX<0 ? -maxX:maxX;
220
    minY = minY<0 ? -minY:minY;
221
    maxY = maxY<0 ? -maxY:maxY;
222

    
223
    float max1 = Math.max(minX,minY);
224
    float max2 = Math.max(maxX,maxY);
225
    float max3 = Math.max(max1,max2);
226

    
227
    info.scale = max3/0.5f;
228

    
229
    int len = vert3D.length;
230
    StickerCoords sInfo = new StickerCoords();
231
    sInfo.outer = isOuter;
232
    sInfo.scale = info.scale;
233
    sInfo.vertices = new float[2*len];
234

    
235
    for( int vertex=0; vertex<len; vertex++ )
236
      {
237
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
238
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
239
      }
240

    
241
    mStickerCoords.add(sInfo);
242

    
243
    info.sticker = mStickerCoords.size() -1;
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
249
    {
250
    FaceTransform ft = new FaceTransform();
251
    ft.face = face;
252
    ft.numFaces = numFaces;
253

    
254
    // compute center of gravity
255
    ft.vx = 0.0f;
256
    ft.vy = 0.0f;
257
    ft.vz = 0.0f;
258
    int len = vert3D.length;
259

    
260
    for (float[] vert : vert3D)
261
      {
262
      ft.vx += vert[0];
263
      ft.vy += vert[1];
264
      ft.vz += vert[2];
265
      }
266

    
267
    ft.vx /= len;
268
    ft.vy /= len;
269
    ft.vz /= len;
270

    
271
    // move all vertices so that their center of gravity is at (0,0,0)
272
    for (int i=0; i<len; i++)
273
      {
274
      vert3D[i][0] -= ft.vx;
275
      vert3D[i][1] -= ft.vy;
276
      vert3D[i][2] -= ft.vz;
277
      }
278

    
279
    // find 3 non-colinear vertices
280
    int foundIndex = -1;
281

    
282
    for(int vertex=2; vertex<len; vertex++)
283
      {
284
      if( !areColinear(vert3D,0,1,vertex) )
285
        {
286
        foundIndex = vertex;
287
        break;
288
        }
289
      }
290

    
291
    // compute the normal vector
292
    if( foundIndex==-1 )
293
      {
294
      throw new RuntimeException("all vertices colinear");
295
      }
296

    
297
    computeNormalVector(vert3D,0,1,foundIndex);
298

    
299
    // rotate so that the normal vector becomes (0,0,1)
300
    float axisX, axisY, axisZ;
301

    
302
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
303
      {
304
      axisX = -mBuffer[1];
305
      axisY =  mBuffer[0];
306
      axisZ = 0.0f;
307

    
308
      float axiLen = axisX*axisX + axisY*axisY;
309
      axiLen = (float)Math.sqrt(axiLen);
310
      axisX /= axiLen;
311
      axisY /= axiLen;
312
      axisZ /= axiLen;
313
      }
314
    else
315
      {
316
      axisX = 0.0f;
317
      axisY = 1.0f;
318
      axisZ = 0.0f;
319
      }
320

    
321
    float cosTheta = mBuffer[2];
322
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
323
    float sinHalfTheta = computeSinHalf(cosTheta);
324
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
325

    
326
    mQuat1[0] = axisX*sinHalfTheta;
327
    mQuat1[1] = axisY*sinHalfTheta;
328
    mQuat1[2] = axisZ*sinHalfTheta;
329
    mQuat1[3] = cosHalfTheta;
330
    mQuat2[0] =-axisX*sinHalfTheta;
331
    mQuat2[1] =-axisY*sinHalfTheta;
332
    mQuat2[2] =-axisZ*sinHalfTheta;
333
    mQuat2[3] = cosHalfTheta;
334

    
335
    for (float[] vert : vert3D)
336
      {
337
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
338
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
339
      }
340

    
341
    // fit the whole thing in a square and remember the scale & 2D vertices
342
    fitInSquare(ft, vert3D, isOuter);
343

    
344
    // remember the rotation
345
    ft.qx =-mQuat1[0];
346
    ft.qy =-mQuat1[1];
347
    ft.qz =-mQuat1[2];
348
    ft.qw = mQuat1[3];
349

    
350
    return ft;
351
    }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354

    
355
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
356
    {
357
    for(int i=0; i<len; i++)
358
      {
359
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
360
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
361
      }
362
    }
363

    
364
///////////////////////////////////////////////////////////////////////////////////////////////////
365

    
366
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
367
    {
368
    float v1x = v1[2*v1i];
369
    float v1y = v1[2*v1i+1];
370
    float v2x = v2[2*v2i];
371
    float v2y = v2[2*v2i+1];
372

    
373
    float lenSq1 = v1x*v1x + v1y*v1y;
374
    float lenSq2 = v2x*v2x + v2y*v2y;
375

    
376
    return (float)Math.sqrt(lenSq2/lenSq1);
377
    }
378

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380
// valid for 0<angle<2*PI
381

    
382
  private float computeSinHalf(float cos)
383
    {
384
    return (float)Math.sqrt((1-cos)/2);
385
    }
386

    
387
///////////////////////////////////////////////////////////////////////////////////////////////////
388
// valid for 0<angle<2*PI
389

    
390
  private float computeCosHalf(float sin, float cos)
391
    {
392
    float cosHalf = (float)Math.sqrt((1+cos)/2);
393
    return sin<0 ? -cosHalf : cosHalf;
394
    }
395

    
396
///////////////////////////////////////////////////////////////////////////////////////////////////
397

    
398
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
399
    {
400
    int v = (rotatedVertex + oldVertex);
401
    if( v>=len ) v-=len;
402
    if( v< 0   ) v+=len;
403

    
404
    return v;
405
    }
406

    
407
///////////////////////////////////////////////////////////////////////////////////////////////////
408

    
409
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex)
410
    {
411
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
412
    float EPSILON = 0.001f;
413
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
414

    
415
    for(int i=1; i<len; i++)
416
      {
417
      int index = computeRotatedIndex(i,len,vertex);
418

    
419
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
420
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
421

    
422
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
423
      }
424

    
425
    return true;
426
    }
427

    
428
///////////////////////////////////////////////////////////////////////////////////////////////////
429

    
430
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
431
    {
432
    mStickerCoords.remove(info.sticker);
433

    
434
    info.sticker = oldSticker;
435
    info.scale  *= scale;
436

    
437
    mQuat1[0] = info.qx;
438
    mQuat1[1] = info.qy;
439
    mQuat1[2] = info.qz;
440
    mQuat1[3] = info.qw;
441

    
442
    float sinHalf = computeSinHalf(cos);
443
    float cosHalf = computeCosHalf(sin,cos);
444

    
445
    mQuat2[0] = 0.0f;
446
    mQuat2[1] = 0.0f;
447
    mQuat2[2] = sinHalf;
448
    mQuat2[3] = cosHalf;
449

    
450
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
451

    
452
    info.qx = mQuat3[0];
453
    info.qy = mQuat3[1];
454
    info.qz = mQuat3[2];
455
    info.qw = mQuat3[3];
456
    }
457

    
458
///////////////////////////////////////////////////////////////////////////////////////////////////
459

    
460
  private void printVert(double[] buffer)
461
    {
462
    int len = buffer.length/2;
463
    String str = "";
464

    
465
    for(int i=0; i<len; i++)
466
      {
467
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
468
      }
469

    
470
    android.util.Log.d("D", str);
471
    }
472

    
473
///////////////////////////////////////////////////////////////////////////////////////////////////
474

    
475
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert,
476
                              float[] oldVert, float lenFirstOld, int oldSticker)
477
    {
478
    for(int vertex=0; vertex<len; vertex++)
479
      {
480
      float newX = newVert[2*vertex  ];
481
      float newY = newVert[2*vertex+1];
482
      float lenIthNew = (float)Math.sqrt(newX*newX + newY*newY);
483
      float cos = (float)QuatHelper.computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
484
      float sin = (float)QuatHelper.computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
485

    
486
      rotateAllVertices(buffer,len,newVert,sin,cos);
487

    
488
      if( isScaledVersionOf(buffer,oldVert,len,vertex) )
489
        {
490
        int newZeroIndex = computeRotatedIndex(0,len,vertex);
491
        float scale = computeScale(oldVert,newVert,0,newZeroIndex);
492
        correctInfo(info,scale,sin,cos,oldSticker);
493
        return true;
494
        }
495
      }
496

    
497
    return false;
498
    }
499

    
500
///////////////////////////////////////////////////////////////////////////////////////////////////
501

    
502
  private float computeCoreDistance(float[] verts)
503
    {
504
    float ret = 0.0f;
505
    float centerX=0.0f,centerY=0.0f;
506
    int len = verts.length/2;
507

    
508
    for(int i=0; i<len; i++)
509
      {
510
      centerX += verts[2*i  ];
511
      centerY += verts[2*i+1];
512
      }
513

    
514
    centerX /= (2*len);
515
    centerY /= (2*len);
516

    
517
    for(int i=0; i<len; i++)
518
      {
519
      float distX = centerX-verts[2*i  ];
520
      float distY = centerY-verts[2*i+1];
521
      ret += (float)Math.sqrt(distX*distX + distY*distY);
522
      }
523

    
524
    return ret;
525
    }
526

    
527
///////////////////////////////////////////////////////////////////////////////////////////////////
528

    
529
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
530
    {
531
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
532
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
533

    
534
    float[] newVert = sNewInfo.vertices;
535
    float[] oldVert = sOldInfo.vertices;
536
    int oldLen = oldVert.length;
537
    int newLen = newVert.length;
538

    
539
    if( oldLen==newLen )
540
      {
541
      float coreDistOld = computeCoreDistance(oldVert);                     // the two stickers are at different scales, so
542
      float coreDistNew = computeCoreDistance(newVert);                     // so even if they are in fact the same, do not
543
      float diff = (coreDistOld*oldInfo.scale)/(coreDistNew*newInfo.scale); // collapse them into one. Example: Master Skewb
544
      if( diff<1.0-MAX_CORE_DIFF || diff>1.0+MAX_CORE_DIFF ) return false;  // and two triangular stickers of different size.
545

    
546
      int oldSticker = oldInfo.sticker;
547
      float[] buffer1 = new float[oldLen];
548
      float lenFirstOld = (float)Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
549
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker) )
550
        {
551
        if( sNewInfo.outer ) sOldInfo.outer = true;
552
        return true;
553
        }
554
      }
555

    
556
    return false;
557
    }
558

    
559
///////////////////////////////////////////////////////////////////////////////////////////////////
560

    
561
  private float[][] constructVert(float[][] vertices, int[] index)
562
    {
563
    int len = index.length;
564
    float[][] ret = new float[len][4];
565

    
566
    for(int i=0; i<len; i++)
567
      {
568
      ret[i][0] = vertices[index[i]][0];
569
      ret[i][1] = vertices[index[i]][1];
570
      ret[i][2] = vertices[index[i]][2];
571
      ret[i][3] = 1.0f;
572
      }
573

    
574
    return ret;
575
    }
576

    
577
///////////////////////////////////////////////////////////////////////////////////////////////////
578

    
579
  private void prepareAndRoundCorners(MeshBase mesh, float[][] vertices,
580
                                      float[][] corners, int[] cornerIndexes,
581
                                      float[][] centers, int[] centerIndexes )
582
    {
583
    int lenV = vertices.length;
584
    Static3D[] staticVert = new Static3D[1];
585
    Static3D center = new Static3D(0,0,0);
586

    
587
    for(int v=0; v<lenV; v++)
588
      {
589
      staticVert[0] = new Static3D( vertices[v][0],vertices[v][1],vertices[v][2] );
590

    
591
      int cent = centerIndexes[v];
592

    
593
      if( cent>=0 )
594
        {
595
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
596

    
597
        int corn = cornerIndexes[v];
598

    
599
        if( corn>=0 )
600
          {
601
          float strength = corners[corn][0];
602
          float radius   = corners[corn][1];
603
          roundCorners(mesh, center, staticVert, strength, radius);
604
          }
605
        }
606
      }
607
    }
608

    
609
///////////////////////////////////////////////////////////////////////////////////////////////////
610

    
611
  private void correctComponents(MeshBase mesh, int numComponents)
612
    {
613
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
614

    
615
    mesh.mergeEffComponents();
616

    
617
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
618
    }
619

    
620
///////////////////////////////////////////////////////////////////////////////////////////////////
621

    
622
  private void printTransform(FaceTransform f)
623
    {
624
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
625
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
626
    }
627

    
628
///////////////////////////////////////////////////////////////////////////////////////////////////
629

    
630
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
631
    {
632
    float[] bands = new float[2*N];
633

    
634
    bands[0] = 1.0f;
635
    bands[1] = 0.0f;
636

    
637
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
638
    float sinBeta = (float)Math.sin(beta);
639
    float cosBeta = (float)Math.cos(beta);
640
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
641
    float D = R*sinBeta;
642
    float B = h(R,sinBeta,K*beta);
643

    
644
    if( D>1.0f )
645
      {
646
      for(int i=1; i<N; i++)
647
        {
648
        bands[2*i  ] = (float)(N-1-i)/(N-1);
649
        bands[2*i+1] = H*(1-bands[2*i]);
650
        }
651
      }
652
    else
653
      {
654
      int K2 = (int)((N-3)*K);
655
      int K1 = (N-3)-K2;
656

    
657
      for(int i=0; i<=K1; i++)
658
        {
659
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
660
        float x = h(R,sinBeta,angle);
661
        bands[2*i+2] = 1.0f - x;
662
        bands[2*i+3] = g(R,D,x,cosBeta);
663
        }
664

    
665
      for(int i=0; i<=K2; i++)
666
        {
667
        float x = (1-B)*(i+1)/(K2+1) + B;
668
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
669
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
670
        }
671
      }
672

    
673
    bands[2*N-2] = 0.0f;
674
    bands[2*N-1] =    H;
675

    
676
    return bands;
677
    }
678

    
679
///////////////////////////////////////////////////////////////////////////////////////////////////
680

    
681
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
682
    {
683
    Static4D reg= new Static4D(0,0,0,regionRadius);
684

    
685
    float centX = center.get0();
686
    float centY = center.get1();
687
    float centZ = center.get2();
688

    
689
    for (Static3D vertex : vertices)
690
      {
691
      float x = strength*(centX - vertex.get0());
692
      float y = strength*(centY - vertex.get1());
693
      float z = strength*(centZ - vertex.get2());
694

    
695
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
696
      mesh.apply(effect);
697
      }
698
    }
699

    
700
///////////////////////////////////////////////////////////////////////////////////////////////////
701

    
702
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
703
    {
704
    if( in==null )
705
      {
706
      out[0] = out[1] = 0.0f;
707
      }
708
    else
709
      {
710
      out[0] = in[0] - ft.vx;
711
      out[1] = in[1] - ft.vy;
712
      out[2] = in[2] - ft.vz;
713
      out[3] = 1.0f;
714

    
715
      mQuat1[0] =-ft.qx;
716
      mQuat1[1] =-ft.qy;
717
      mQuat1[2] =-ft.qz;
718
      mQuat1[3] = ft.qw;
719

    
720
      mQuat2[0] = -mQuat1[0];
721
      mQuat2[1] = -mQuat1[1];
722
      mQuat2[2] = -mQuat1[2];
723
      mQuat2[3] = +mQuat1[3];
724

    
725
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
726
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
727

    
728
      out[0] /= ft.scale;
729
      out[1] /= ft.scale;
730
      out[2] /= ft.scale;
731
      }
732
    }
733

    
734
///////////////////////////////////////////////////////////////////////////////////////////////////
735

    
736
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
737
    {
738
    int len = table.length;
739

    
740
    for(int i=0; i<len; i++)
741
      {
742
      int lenInner = table[i].length;
743

    
744
      for(int j=0; j<lenInner; j++)
745
        if( table[i][j]==oldPointer ) table[i][j] = newPointer;
746
      }
747
    }
748

    
749
///////////////////////////////////////////////////////////////////////////////////////////////////
750
// INTERNAL API
751

    
752
  public int printStickerCoords()
753
    {
754
    int stickers = mStickerCoords.size();
755
    int ret = 0;
756

    
757
    android.util.Log.d("D", "---- STICKER COORDS ----");
758

    
759
    for(int s=0; s<stickers; s++)
760
      {
761
      StickerCoords info = mStickerCoords.get(s);
762

    
763
      if( info.outer )  ret++;
764

    
765
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
766
      int len = info.vertices.length/2;
767

    
768
      for(int i =0; i<len; i++)
769
        {
770
        if( i!=0 ) ver += ", ";
771
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
772
        }
773

    
774
      ver += " }";
775
      android.util.Log.d("D", ver);
776
      }
777

    
778
    android.util.Log.d("D", "---- END STICKER COORDS ----");
779

    
780
    return ret;
781
    }
782

    
783
///////////////////////////////////////////////////////////////////////////////////////////////////
784

    
785
  public void printFaceTransform()
786
    {
787
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
788

    
789
    int oldfaces = mOldFaceTransf.size();
790

    
791
    for(int f=0; f<oldfaces; f++)
792
      {
793
      printTransform(mOldFaceTransf.get(f));
794
      }
795

    
796
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
797

    
798
    int newfaces = mNewFaceTransf.size();
799

    
800
    for(int f=0; f<newfaces; f++)
801
      {
802
      printTransform(mNewFaceTransf.get(f));
803
      }
804
    }
805

    
806
///////////////////////////////////////////////////////////////////////////////////////////////////
807
// PUBLIC API
808

    
809
  public static FactoryCubit getInstance()
810
    {
811
    if( mThis==null ) mThis = new FactoryCubit();
812

    
813
    return mThis;
814
    }
815

    
816
///////////////////////////////////////////////////////////////////////////////////////////////////
817

    
818
  public float[] getStickerScales()
819
    {
820
    int index=0,num=0,len = mStickerCoords.size();
821

    
822
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
823

    
824
    if( num>0 )
825
      {
826
      float[] scales = new float[num];
827

    
828
      for(int i=0; i<len; i++)
829
        {
830
        StickerCoords sticker = mStickerCoords.get(i);
831
        if( sticker.outer ) scales[index++] = sticker.scale;
832
        }
833

    
834
      return scales;
835
      }
836

    
837
    return null;
838
    }
839

    
840
///////////////////////////////////////////////////////////////////////////////////////////////////
841

    
842
  public float[][] getStickerCoords()
843
    {
844
    int index=0,num=0,len = mStickerCoords.size();
845

    
846
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
847

    
848
    if( num>0 )
849
      {
850
      float[][] coords = new float[num][];
851

    
852
      for(int i=0; i<len; i++)
853
        {
854
        StickerCoords sticker = mStickerCoords.get(i);
855
        if( sticker.outer ) coords[index++] = sticker.vertices;
856
        }
857

    
858
      return coords;
859
      }
860

    
861
    return null;
862
    }
863

    
864
///////////////////////////////////////////////////////////////////////////////////////////////////
865

    
866
  public int[][] getStickerVariants()
867
    {
868
    int numvariants = 1; // there's one in the 'new' array
869

    
870
    int oldfaces = mOldFaceTransf.size();
871

    
872
    for(int f=0; f<oldfaces; f++)
873
      {
874
      FaceTransform ft = mOldFaceTransf.get(f);
875
      if( ft.face==0 ) numvariants++;
876
      }
877

    
878
    int[][] ret = new int[numvariants][];
879
    int inner=0, index=-1;
880

    
881
    for(int f=0; f<oldfaces; f++)
882
      {
883
      FaceTransform ft = mOldFaceTransf.get(f);
884
      if( ft.face==0 )
885
        {
886
        index++;
887
        inner=0;
888
        ret[index] = new int[ft.numFaces];
889
        }
890

    
891
      ret[index][inner++] = ft.sticker;
892
      }
893

    
894
    int newfaces = mNewFaceTransf.size();
895

    
896
    for(int f=0; f<newfaces; f++)
897
      {
898
      FaceTransform ft = mNewFaceTransf.get(f);
899
      if( ft.face==0 )
900
        {
901
        index++;
902
        inner=0;
903
        ret[index] = new int[ft.numFaces];
904
        }
905

    
906
      ret[index][inner++] = ft.sticker;
907
      }
908

    
909
    int numStickers = mStickerCoords.size();
910
    int numOuter=0;
911

    
912
    for(int i=0; i<numStickers; i++)
913
      {
914
      StickerCoords sc = mStickerCoords.get(i);
915
      if( sc.outer )
916
        {
917
        changeStickerPointers(ret,i,numOuter);
918
        numOuter++;
919
        }
920
      else
921
        {
922
        changeStickerPointers(ret,i,-1);
923
        }
924
      }
925

    
926
    return ret;
927
    }
928

    
929
///////////////////////////////////////////////////////////////////////////////////////////////////
930

    
931
  public void clear()
932
    {
933
    mStickerCoords.clear();
934
    mNewFaceTransf.clear();
935
    mOldFaceTransf.clear();
936
    }
937

    
938
///////////////////////////////////////////////////////////////////////////////////////////////////
939

    
940
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
941
    {
942
    float[][] vertices = shape.getVertices();
943
    int[][] indices = shape.getVertIndices();
944
    FaceTransform ft;
945
    int numNew = mNewFaceTransf.size();
946

    
947
    for(int i=0; i<numNew; i++)
948
      {
949
      ft = mNewFaceTransf.remove(0);
950
      mOldFaceTransf.add(ft);
951
      }
952

    
953
    int numFaces = indices.length;
954
    int numOld = mOldFaceTransf.size();
955

    
956
    for (int face=0; face<numFaces; face++)
957
      {
958
      boolean collapsed = false;
959
      boolean isOuter = (outer!=null && outer[face]>0);
960

    
961
      float[][] vert = constructVert(vertices, indices[face]);
962
      FaceTransform newT = constructNewTransform(vert,isOuter,face,numFaces);
963

    
964
      for (int old=0; !collapsed && old<numOld; old++)
965
        {
966
        ft = mOldFaceTransf.get(old);
967
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
968
        }
969

    
970
      for (int pre=0; !collapsed && pre<face; pre++)
971
        {
972
        ft = mNewFaceTransf.get(pre);
973
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
974
        }
975

    
976
      mNewFaceTransf.add(newT);
977
      }
978
    }
979

    
980
///////////////////////////////////////////////////////////////////////////////////////////////////
981

    
982
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape, int meshState, int numComponents)
983
    {
984
    float[][] vertices      = shape.getVertices();
985
    int[][] vertIndexes     = shape.getVertIndices();
986
    float[][] bands         = faceShape.getBands();
987
    int[]   bandIndexes     = faceShape.getBandIndices();
988
    float[][] corners       = faceShape.getCorners();
989
    int[]   cornerIndexes   = faceShape.getCornerIndices();
990
    float[][] centers       = faceShape.getCenters();
991
    int[]   centerIndexes   = faceShape.getCenterIndices();
992
    float[] convexityCenter = faceShape.getConvexityCenter();
993

    
994
    int numFaces = vertIndexes.length;
995
    float[] band, bandsComputed;
996
    MeshBase[] meshes = new MeshBase[numFaces];
997
    FaceTransform fInfo;
998
    StickerCoords sInfo;
999
    float[] convexXY = new float[4];
1000
    int exIndex=0, exVertices=0, alpha=0, N=0;
1001
    float height=0.0f, dist=0.0f, K=0.0f;
1002

    
1003
    for(int face=0; face<numFaces; face++)
1004
      {
1005
      fInfo = mNewFaceTransf.get(face);
1006
      sInfo = mStickerCoords.get(fInfo.sticker);
1007

    
1008
      float[] verts = sInfo.vertices;
1009
      int lenVerts = verts.length;
1010
      float[] copiedVerts = new float[lenVerts];
1011
      System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1012

    
1013
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1014

    
1015
      band = bands[bandIndexes[face]];
1016

    
1017
      switch(meshState)
1018
        {
1019
        case MESH_NICE: height     = band[0];
1020
                        alpha      = (int)band[1];
1021
                        dist       = band[2];
1022
                        K          = band[3];
1023
                        N          = (int)band[4];
1024
                        exIndex    = (int)band[5];
1025
                        exVertices = (int)band[6];
1026
                        break;
1027
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
1028
                                                               // (example: Ivy cube center and edge cubits!)
1029
                        alpha      = 0;
1030
                        dist       = 0;
1031
                        K          = 0;
1032
                        N          = 2;
1033
                        exIndex    = 0;
1034
                        exVertices = 0;
1035
                        break;
1036
        }
1037

    
1038
      bandsComputed = computeBands(height,alpha,dist,K,N);
1039
      meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1040
      meshes[face].setEffectAssociation(0,(1<<face),0);
1041
      }
1042

    
1043
    MeshBase mesh = new MeshJoined(meshes);
1044
    Static3D center = new Static3D(0,0,0);
1045

    
1046
    for(int face=0; face<numFaces; face++)
1047
      {
1048
      int assoc = (1<<face);
1049
      fInfo = mNewFaceTransf.get(face);
1050

    
1051
      float vx = fInfo.vx;
1052
      float vy = fInfo.vy;
1053
      float vz = fInfo.vz;
1054
      float sc = fInfo.scale;
1055
      float qx = fInfo.qx;
1056
      float qy = fInfo.qy;
1057
      float qz = fInfo.qz;
1058
      float qw = fInfo.qw;
1059

    
1060
      Static3D scale = new Static3D(sc,sc,sc);
1061
      Static3D move3D= new Static3D(vx,vy,vz);
1062
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1063

    
1064
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
1065
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
1066
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
1067
      }
1068

    
1069
    if( meshState==MESH_NICE )
1070
      {
1071
      prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
1072
      }
1073

    
1074
    correctComponents(mesh,numComponents);
1075

    
1076
    return mesh;
1077
    }
1078
  }
(2-2/12)