Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.helpers;
11

    
12
import org.distorted.library.effect.EffectName;
13
import org.distorted.library.effect.MatrixEffectMove;
14
import org.distorted.library.effect.MatrixEffectQuaternion;
15
import org.distorted.library.effect.MatrixEffectScale;
16
import org.distorted.library.effect.VertexEffect;
17
import org.distorted.library.helpers.QuatHelper;
18
import org.distorted.library.mesh.MeshBase;
19
import org.distorted.library.mesh.MeshJoined;
20
import org.distorted.library.mesh.MeshMultigon;
21
import org.distorted.library.mesh.MeshPolygon;
22
import org.distorted.library.type.Static3D;
23
import org.distorted.library.type.Static4D;
24

    
25
import java.util.ArrayList;
26

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

    
29
public class FactoryCubit
30
  {
31
  private static FactoryCubit mThis;
32

    
33
  private static final float MAX_CORE_DIFF = 0.01f;
34

    
35
  private static final float[] mBuffer = new float[3];
36
  private static final float[] mQuat1  = new float[4];
37
  private static final float[] mQuat2  = new float[4];
38
  private static final float[] mQuat3  = new float[4];
39

    
40
  public static final String NAME = EffectName.DEFORM.name();
41

    
42
  private static class StickerCoords
43
    {
44
    float[][][] outerVertices;
45
    float[][][] fullVertices;
46
    float scale;
47
    boolean outer;
48
    }
49

    
50
  private static class FaceTransform
51
    {
52
    int face;
53
    int numFaces;
54

    
55
    int sticker;
56
    float vx,vy,vz;
57
    float scale;
58
    float qx,qy,qz,qw;
59
    }
60

    
61
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
62
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
63
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
64

    
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66

    
67
  private FactoryCubit()
68
    {
69

    
70
    }
71

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

    
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108

    
109
  private float f(float D, float B, float x)
110
    {
111
    return ((D-B)*x + B*(1-D))/(1-B);
112
    }
113

    
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115

    
116
  private float g(float R, float D, float x, float cosAlpha)
117
    {
118
    float d = x-D;
119
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  private float h(float R, float sinAlpha, float x)
125
    {
126
    return R*(sinAlpha-(float)Math.sin(x));
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  private boolean areNotColinear(float[][] vertices, int index)
132
    {
133
    float x1 = vertices[0][0];
134
    float y1 = vertices[0][1];
135
    float z1 = vertices[0][2];
136
    float x2 = vertices[1][0];
137
    float y2 = vertices[1][1];
138
    float z2 = vertices[1][2];
139
    float x3 = vertices[index][0];
140
    float y3 = vertices[index][1];
141
    float z3 = vertices[index][2];
142

    
143
    float v1x = x2-x1;
144
    float v1y = y2-y1;
145
    float v1z = z2-z1;
146
    float v2x = x3-x1;
147
    float v2y = y3-y1;
148
    float v2z = z3-z1;
149

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

    
152
    return !(v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
153
    }
154

    
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156

    
157
  private void computeNormalVector(float[][] vertices, int index)
158
    {
159
    float x1 = vertices[0][0];
160
    float y1 = vertices[0][1];
161
    float z1 = vertices[0][2];
162
    float x2 = vertices[1][0];
163
    float y2 = vertices[1][1];
164
    float z2 = vertices[1][2];
165
    float x3 = vertices[index][0];
166
    float y3 = vertices[index][1];
167
    float z3 = vertices[index][2];
168

    
169
    float v1x = x2-x1;
170
    float v1y = y2-y1;
171
    float v1z = z2-z1;
172
    float v2x = x3-x1;
173
    float v2y = y3-y1;
174
    float v2z = z3-z1;
175

    
176
    mBuffer[0] = v1y*v2z - v2y*v1z;
177
    mBuffer[1] = v1z*v2x - v2z*v1x;
178
    mBuffer[2] = v1x*v2y - v2x*v1y;
179

    
180
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
181
    len = Math.sqrt(len);
182
    mBuffer[0] /= len;
183
    mBuffer[1] /= len;
184
    mBuffer[2] /= len;
185

    
186
    // combat the same effect like in TouchControlShapeChanging.FaceInfo
187
    if( totalAngle(vertices,mBuffer)<0 )
188
      {
189
      mBuffer[0] *= -1;
190
      mBuffer[1] *= -1;
191
      mBuffer[2] *= -1;
192
      }
193
    }
194

    
195
///////////////////////////////////////////////////////////////////////////////////////////////////
196
// this returns the total angle we get rotated about when we travel from the first vert to the last.
197
// It's always should be +2PI or -2PI, depending on if the verts are CW or CCW (when looking at the
198
// plane formed by the vertices from the direction the 'normal' vector points towards)
199
//
200
// The point: this way we can detect if the 'normal' vector is correct, i.e. if it points in the
201
// right direction.
202
// Sometimes it doesn't, when the first three vertices (from which the vector is computed) are 'concave'.
203

    
204
  public static float totalAngle(float[][] vert, float[] normal)
205
    {
206
    float ret = 0;
207
    int num = vert.length;
208

    
209
    for(int c=0; c<num; c++)
210
      {
211
      int n = (c==num-1 ? 0 : c+1);
212
      int m = (n==num-1 ? 0 : n+1);
213
      ret += angle( vert[c],vert[n],vert[m], normal);
214
      }
215

    
216
    return ret;
217
    }
218

    
219
///////////////////////////////////////////////////////////////////////////////////////////////////
220

    
221
  private static float angle(float[] v0, float[] v1, float[] v2, float[] normal)
222
    {
223
    float px = v1[0] - v0[0];
224
    float py = v1[1] - v0[1];
225
    float pz = v1[2] - v0[2];
226

    
227
    float rx = v2[0] - v1[0];
228
    float ry = v2[1] - v1[1];
229
    float rz = v2[2] - v1[2];
230

    
231
    float l1 = (float)Math.sqrt(px*px + py*py + pz*pz);
232
    float l2 = (float)Math.sqrt(rx*rx + ry*ry + rz*rz);
233

    
234
    px /= l1;
235
    py /= l1;
236
    pz /= l1;
237

    
238
    rx /= l2;
239
    ry /= l2;
240
    rz /= l2;
241

    
242
    float s = px*rx + py*ry + pz*rz;
243

    
244
    if( s> 1 ) s= 1;
245
    if( s<-1 ) s=-1;
246

    
247
    float a = (float) Math.acos(s);
248
    float[] cross = crossProduct(px,py,pz,rx,ry,rz);
249

    
250
    float ax = cross[0] + normal[0];
251
    float ay = cross[1] + normal[1];
252
    float az = cross[2] + normal[2];
253

    
254
    float bx = cross[0] - normal[0];
255
    float by = cross[1] - normal[1];
256
    float bz = cross[2] - normal[2];
257

    
258
    float f1 = ax*ax + ay*ay + az*az;
259
    float f2 = bx*bx + by*by + bz*bz;
260

    
261
    return f1>f2 ? a : -a;
262
    }
263

    
264
///////////////////////////////////////////////////////////////////////////////////////////////////
265

    
266
  private static float[] crossProduct(float a1, float a2, float a3, float b1, float b2, float b3)
267
    {
268
    float[] ret = new float[3];
269

    
270
    ret[0] = a2*b3 - a3*b2;
271
    ret[1] = a3*b1 - a1*b3;
272
    ret[2] = a1*b2 - a2*b1;
273

    
274
    return ret;
275
    }
276

    
277
///////////////////////////////////////////////////////////////////////////////////////////////////
278

    
279
  private float[][][] computeOuterEdge(float[][][] vertices)
280
    {
281
    int[][] edgesUp = MeshMultigon.computeEdgesUp(vertices);
282
    return MeshMultigon.computeOuterAndHoleVertices(vertices,edgesUp);
283
    }
284

    
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286
// polygon
287

    
288
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
289
    {
290
    float minX = Float.MAX_VALUE;
291
    float maxX =-Float.MAX_VALUE;
292
    float minY = Float.MAX_VALUE;
293
    float maxY =-Float.MAX_VALUE;
294

    
295
    for (float[] vert : vert3D)
296
      {
297
      float x = vert[0];
298
      float y = vert[1];
299

    
300
      if (x > maxX) maxX = x;
301
      if (x < minX) minX = x;
302
      if (y > maxY) maxY = y;
303
      if (y < minY) minY = y;
304
      }
305

    
306
    minX = minX<0 ? -minX:minX;
307
    maxX = maxX<0 ? -maxX:maxX;
308
    minY = minY<0 ? -minY:minY;
309
    maxY = maxY<0 ? -maxY:maxY;
310

    
311
    float max1 = Math.max(minX,minY);
312
    float max2 = Math.max(maxX,maxY);
313
    float max3 = Math.max(max1,max2);
314

    
315
    info.scale = max3/0.5f;
316

    
317
    int len = vert3D.length;
318
    StickerCoords sInfo = new StickerCoords();
319
    sInfo.outer = isOuter;
320
    sInfo.scale = info.scale;
321
    sInfo.outerVertices = new float[1][len][2];
322
    sInfo.fullVertices = null;
323

    
324
    float[][] t = sInfo.outerVertices[0];
325

    
326
    for( int vertex=0; vertex<len; vertex++ )
327
      {
328
      t[vertex][0] = vert3D[vertex][0] / info.scale;
329
      t[vertex][1] = vert3D[vertex][1] / info.scale;
330
      }
331

    
332
    mStickerCoords.add(sInfo);
333

    
334
    info.sticker = mStickerCoords.size() -1;
335
    }
336

    
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339
// multigon
340

    
341
  private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
342
    {
343
    float minX = Float.MAX_VALUE;
344
    float maxX =-Float.MAX_VALUE;
345
    float minY = Float.MAX_VALUE;
346
    float maxY =-Float.MAX_VALUE;
347

    
348
    for( float[][] vert : vert3D)
349
      for( float[] v : vert)
350
        {
351
        float x = v[0];
352
        float y = v[1];
353

    
354
        if (x > maxX) maxX = x;
355
        if (x < minX) minX = x;
356
        if (y > maxY) maxY = y;
357
        if (y < minY) minY = y;
358
        }
359

    
360
    minX = minX<0 ? -minX:minX;
361
    maxX = maxX<0 ? -maxX:maxX;
362
    minY = minY<0 ? -minY:minY;
363
    maxY = maxY<0 ? -maxY:maxY;
364

    
365
    float max1 = Math.max(minX,minY);
366
    float max2 = Math.max(maxX,maxY);
367
    float max3 = Math.max(max1,max2);
368

    
369
    info.scale = max3/0.5f;
370

    
371
    int len = vert3D.length;
372
    StickerCoords sInfo = new StickerCoords();
373
    sInfo.outer = isOuter;
374
    sInfo.scale = info.scale;
375
    sInfo.fullVertices = new float[len][][];
376

    
377
    for( int comp=0; comp<len; comp++ )
378
      {
379
      float[][] vert = vert3D[comp];
380
      int num = vert.length;
381
      sInfo.fullVertices[comp] = new float[num][2];
382
      float[][] t = sInfo.fullVertices[comp];
383

    
384
      for( int vertex=0; vertex<num; vertex++)
385
        {
386
        t[vertex][0] = vert[vertex][0] / info.scale;
387
        t[vertex][1] = vert[vertex][1] / info.scale;
388
        }
389
      }
390

    
391
    sInfo.outerVertices = computeOuterEdge(sInfo.fullVertices);
392

    
393
    mStickerCoords.add(sInfo);
394

    
395
    info.sticker = mStickerCoords.size() -1;
396
    }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399
// polygon
400

    
401
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
402
    {
403
    FaceTransform ft = new FaceTransform();
404
    ft.face = face;
405
    ft.numFaces = numFaces;
406

    
407
    // compute center of gravity
408
    ft.vx = 0.0f;
409
    ft.vy = 0.0f;
410
    ft.vz = 0.0f;
411
    int len = vert3D.length;
412

    
413
    for (float[] vert : vert3D)
414
      {
415
      ft.vx += vert[0];
416
      ft.vy += vert[1];
417
      ft.vz += vert[2];
418
      }
419

    
420
    ft.vx /= len;
421
    ft.vy /= len;
422
    ft.vz /= len;
423

    
424
    // move all vertices so that their center of gravity is at (0,0,0)
425
    for (int i=0; i<len; i++)
426
      {
427
      vert3D[i][0] -= ft.vx;
428
      vert3D[i][1] -= ft.vy;
429
      vert3D[i][2] -= ft.vz;
430
      }
431

    
432
    // find 3 non-colinear vertices
433
    int foundIndex = -1;
434

    
435
    for(int vertex=2; vertex<len; vertex++)
436
      {
437
      if( areNotColinear(vert3D,vertex) )
438
        {
439
        foundIndex = vertex;
440
        break;
441
        }
442
      }
443

    
444
    // compute the normal vector
445
    if( foundIndex==-1 )
446
      {
447
      StringBuilder sb = new StringBuilder();
448

    
449
      for (float[] floats : vert3D)
450
        {
451
        sb.append(' ');
452
        sb.append("(");
453
        sb.append(floats[0]);
454
        sb.append(" ");
455
        sb.append(floats[1]);
456
        sb.append(" ");
457
        sb.append(floats[2]);
458
        sb.append(")");
459
        }
460
      android.util.Log.e("D", "verts: "+sb);
461

    
462
      throw new RuntimeException("all vertices colinear");
463
      }
464

    
465
    computeNormalVector(vert3D,foundIndex);
466

    
467
    // rotate so that the normal vector becomes (0,0,1)
468
    float axisX, axisY, axisZ;
469

    
470
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
471
      {
472
      axisX = -mBuffer[1];
473
      axisY =  mBuffer[0];
474
      axisZ = 0.0f;
475

    
476
      float axiLen = axisX*axisX + axisY*axisY;
477
      axiLen = (float)Math.sqrt(axiLen);
478
      axisX /= axiLen;
479
      axisY /= axiLen;
480
      axisZ /= axiLen;
481
      }
482
    else
483
      {
484
      axisX = 0.0f;
485
      axisY = 1.0f;
486
      axisZ = 0.0f;
487
      }
488

    
489
    float cosTheta = mBuffer[2];
490
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
491
    float sinHalfTheta = computeSinHalf(cosTheta);
492
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
493

    
494
    mQuat1[0] = axisX*sinHalfTheta;
495
    mQuat1[1] = axisY*sinHalfTheta;
496
    mQuat1[2] = axisZ*sinHalfTheta;
497
    mQuat1[3] = cosHalfTheta;
498
    mQuat2[0] =-axisX*sinHalfTheta;
499
    mQuat2[1] =-axisY*sinHalfTheta;
500
    mQuat2[2] =-axisZ*sinHalfTheta;
501
    mQuat2[3] = cosHalfTheta;
502

    
503
    for (float[] vert : vert3D)
504
      {
505
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
506
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
507
      }
508

    
509
    // fit the whole thing in a square and remember the scale & 2D vertices
510
    fitInSquare(ft, vert3D, isOuter);
511

    
512
    // remember the rotation
513
    ft.qx =-mQuat1[0];
514
    ft.qy =-mQuat1[1];
515
    ft.qz =-mQuat1[2];
516
    ft.qw = mQuat1[3];
517

    
518
    return ft;
519
    }
520

    
521
///////////////////////////////////////////////////////////////////////////////////////////////////
522
// multigon
523

    
524
  private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
525
    {
526
    FaceTransform ft = new FaceTransform();
527
    ft.face = face;
528
    ft.numFaces = numFaces;
529

    
530
    // compute center of gravity
531
    ft.vx = 0.0f;
532
    ft.vy = 0.0f;
533
    ft.vz = 0.0f;
534
    int len = 0;
535

    
536
    for( float[][] vert : vert3D )
537
      for( float[] v : vert )
538
        {
539
        ft.vx += v[0];
540
        ft.vy += v[1];
541
        ft.vz += v[2];
542
        len++;
543
        }
544

    
545
    ft.vx /= len;
546
    ft.vy /= len;
547
    ft.vz /= len;
548

    
549
    // move all vertices so that their center of gravity is at (0,0,0)
550
    for( float[][] vert : vert3D )
551
      for( float[] v : vert )
552
        {
553
        v[0] -= ft.vx;
554
        v[1] -= ft.vy;
555
        v[2] -= ft.vz;
556
        }
557

    
558
    // find 3 non-colinear vertices
559
    int foundIndex = -1;
560
    len = vert3D[0].length;
561

    
562
    for(int vertex=2; vertex<len; vertex++)
563
      {
564
      if( areNotColinear(vert3D[0],vertex) )
565
        {
566
        foundIndex = vertex;
567
        break;
568
        }
569
      }
570

    
571
    // compute the normal vector
572
    if( foundIndex==-1 )
573
      {
574
      StringBuilder sb = new StringBuilder();
575

    
576
      for (float[] v : vert3D[0])
577
        {
578
        sb.append(' ');
579
        sb.append("(");
580
        sb.append(v[0]);
581
        sb.append(" ");
582
        sb.append(v[1]);
583
        sb.append(" ");
584
        sb.append(v[2]);
585
        sb.append(")");
586
        }
587
      android.util.Log.e("D", "verts: "+sb);
588

    
589
      throw new RuntimeException("all vertices colinear");
590
      }
591

    
592
    computeNormalVector(vert3D[0],foundIndex);
593

    
594
    // rotate so that the normal vector becomes (0,0,1)
595
    float axisX, axisY, axisZ;
596

    
597
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
598
      {
599
      axisX = -mBuffer[1];
600
      axisY =  mBuffer[0];
601
      axisZ = 0.0f;
602

    
603
      float axiLen = axisX*axisX + axisY*axisY;
604
      axiLen = (float)Math.sqrt(axiLen);
605
      axisX /= axiLen;
606
      axisY /= axiLen;
607
      axisZ /= axiLen;
608
      }
609
    else
610
      {
611
      axisX = 0.0f;
612
      axisY = 1.0f;
613
      axisZ = 0.0f;
614
      }
615

    
616
    float cosTheta = mBuffer[2];
617
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
618
    float sinHalfTheta = computeSinHalf(cosTheta);
619
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
620

    
621
    mQuat1[0] = axisX*sinHalfTheta;
622
    mQuat1[1] = axisY*sinHalfTheta;
623
    mQuat1[2] = axisZ*sinHalfTheta;
624
    mQuat1[3] = cosHalfTheta;
625
    mQuat2[0] =-axisX*sinHalfTheta;
626
    mQuat2[1] =-axisY*sinHalfTheta;
627
    mQuat2[2] =-axisZ*sinHalfTheta;
628
    mQuat2[3] = cosHalfTheta;
629

    
630
    for( float[][] vert : vert3D)
631
      for( float[] v : vert)
632
        {
633
        QuatHelper.quatMultiply(mQuat3, mQuat1, v  );
634
        QuatHelper.quatMultiply(  v, mQuat3, mQuat2);
635
        }
636

    
637
    // fit the whole thing in a square and remember the scale & 2D vertices
638
    fitInSquare(ft, vert3D, isOuter);
639

    
640
    // remember the rotation
641
    ft.qx =-mQuat1[0];
642
    ft.qy =-mQuat1[1];
643
    ft.qz =-mQuat1[2];
644
    ft.qw = mQuat1[3];
645

    
646
    return ft;
647
    }
648

    
649
///////////////////////////////////////////////////////////////////////////////////////////////////
650

    
651
  private void rotateAllVertices(float[][] result, int len, float[][] vertices, float sin, float cos)
652
    {
653
    for(int i=0; i<len; i++)
654
      {
655
      float x = vertices[i][0];
656
      float y = vertices[i][1];
657
      result[i][0] = x*cos - y*sin;
658
      result[i][1] = x*sin + y*cos;
659
      }
660
    }
661

    
662
///////////////////////////////////////////////////////////////////////////////////////////////////
663

    
664
  private float computeScale(float[][] v1, float[][] v2, int v1i, int v2i)
665
    {
666
    float v1x = v1[v1i][0];
667
    float v1y = v1[v1i][1];
668
    float v2x = v2[v2i][0];
669
    float v2y = v2[v2i][1];
670

    
671
    float lenSq1 = v1x*v1x + v1y*v1y;
672
    float lenSq2 = v2x*v2x + v2y*v2y;
673

    
674
    return (float)Math.sqrt(lenSq2/lenSq1);
675
    }
676

    
677
///////////////////////////////////////////////////////////////////////////////////////////////////
678
// valid for 0<angle<2*PI
679

    
680
  private float computeSinHalf(float cos)
681
    {
682
    return (float)Math.sqrt((1-cos)/2);
683
    }
684

    
685
///////////////////////////////////////////////////////////////////////////////////////////////////
686
// valid for 0<angle<2*PI
687

    
688
  private float computeCosHalf(float sin, float cos)
689
    {
690
    float cosHalf = (float)Math.sqrt((1+cos)/2);
691
    return sin<0 ? -cosHalf : cosHalf;
692
    }
693

    
694
///////////////////////////////////////////////////////////////////////////////////////////////////
695

    
696
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
697
    {
698
    int v = (rotatedVertex + oldVertex);
699
    if( v>=len ) v-=len;
700
    if( v< 0   ) v+=len;
701

    
702
    return v;
703
    }
704

    
705
///////////////////////////////////////////////////////////////////////////////////////////////////
706

    
707
  private boolean isScaledVersionOf(float[][] newVert, float[][] oldVert, int len, int vertex)
708
    {
709
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
710
    float EPSILON = 0.001f;
711
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
712

    
713
    for(int i=1; i<len; i++)
714
      {
715
      int index = computeRotatedIndex(i,len,vertex);
716

    
717
      float horz = oldVert[i][0] - scale*newVert[index][0];
718
      float vert = oldVert[i][1] - scale*newVert[index][1];
719

    
720
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
721
      }
722

    
723
    return true;
724
    }
725

    
726
///////////////////////////////////////////////////////////////////////////////////////////////////
727

    
728
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
729
    {
730
    mStickerCoords.remove(info.sticker);
731

    
732
    info.sticker = oldSticker;
733
    info.scale  *= scale;
734

    
735
    mQuat1[0] = info.qx;
736
    mQuat1[1] = info.qy;
737
    mQuat1[2] = info.qz;
738
    mQuat1[3] = info.qw;
739

    
740
    float sinHalf = computeSinHalf(cos);
741
    float cosHalf = computeCosHalf(sin,cos);
742

    
743
    mQuat2[0] = 0.0f;
744
    mQuat2[1] = 0.0f;
745
    mQuat2[2] = sinHalf;
746
    mQuat2[3] = cosHalf;
747

    
748
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
749

    
750
    info.qx = mQuat3[0];
751
    info.qy = mQuat3[1];
752
    info.qz = mQuat3[2];
753
    info.qw = mQuat3[3];
754
    }
755

    
756
///////////////////////////////////////////////////////////////////////////////////////////////////
757

    
758
  private boolean foundVertex(FaceTransform info, float[][] buffer, float[][] newVert, float[][] oldVert, int oldSticker)
759
    {
760
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
761
    int len = newVert.length;
762

    
763
    for(float[] ov : oldVert)
764
      {
765
      oldX = ov[0];
766
      oldY = ov[1];
767
      lenOld = (float) Math.sqrt(oldX*oldX+oldY*oldY);
768

    
769
      if(lenOld!=0) break;
770
      }
771

    
772
    for(int vertex=0; vertex<len; vertex++)
773
      {
774
      float newX = newVert[vertex][0];
775
      float newY = newVert[vertex][1];
776
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
777

    
778
      if( lenNew!=0 )
779
        {
780
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
781
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
782

    
783
        rotateAllVertices(buffer,len,newVert,sin,cos);
784

    
785
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
786
          {
787
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
788
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
789
          correctInfo(info,scale,sin,cos,oldSticker);
790
          return true;
791
          }
792
        }
793
      }
794

    
795
    return false;
796
    }
797

    
798
///////////////////////////////////////////////////////////////////////////////////////////////////
799

    
800
  private float computeCoreDistance(float[][] verts)
801
    {
802
    float ret = 0.0f;
803
    float centerX=0.0f,centerY=0.0f;
804
    int len = verts.length;
805

    
806
    for(float[] vert : verts)
807
      {
808
      centerX += vert[0];
809
      centerY += vert[1];
810
      }
811

    
812
    centerX /= len;
813
    centerY /= len;
814

    
815
    for(float[] vert : verts)
816
      {
817
      float distX = centerX-vert[0];
818
      float distY = centerY-vert[1];
819
      ret += (float) Math.sqrt(distX*distX+distY*distY);
820
      }
821

    
822
    return ret;
823
    }
824

    
825
///////////////////////////////////////////////////////////////////////////////////////////////////
826
// even if this is a multigon, then StickerCoords.outerVertices is the outer edge!
827
// (see fitInSquare multigon variant)
828

    
829
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
830
    {
831
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
832
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
833

    
834
    if( sNewInfo.outerVertices.length>1 || sOldInfo.outerVertices.length>1 ) // the 'outer' path is composed of more than
835
      {                                                                      // one segment, i.e. the sticker has holes.
836
      return false;                                                          // do not collapse such stickers.
837
      }
838

    
839
    float[][] newVert = sNewInfo.outerVertices[0];
840
    float[][] oldVert = sOldInfo.outerVertices[0];
841
    int oldLen = oldVert.length;
842
    int newLen = newVert.length;
843

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

    
851
      int oldSticker = oldInfo.sticker;
852
      float[][] buffer = new float[oldLen][2];
853

    
854
      if( foundVertex(newInfo, buffer, newVert, oldVert, oldSticker) )
855
        {
856
        if( sNewInfo.outer ) sOldInfo.outer = true;
857
        return true;
858
        }
859
      }
860

    
861
    return false;
862
    }
863

    
864
///////////////////////////////////////////////////////////////////////////////////////////////////
865
// polygon
866

    
867
  private float[][] constructVert(float[][] vertices, int[] index)
868
    {
869
    int len = index.length;
870
    float[][] ret = new float[len][4];
871

    
872
    for(int i=0; i<len; i++)
873
      {
874
      float[] tmp = vertices[index[i]];
875
      ret[i][0] = tmp[0];
876
      ret[i][1] = tmp[1];
877
      ret[i][2] = tmp[2];
878
      ret[i][3] = 1.0f;
879
      }
880

    
881
    return ret;
882
    }
883

    
884
///////////////////////////////////////////////////////////////////////////////////////////////////
885
// multigon
886

    
887
  private float[][][] constructVert(float[][] vertices, int[][] index)
888
    {
889
    int len = index.length;
890
    float[][][] ret = new float[len][][];
891

    
892
    for(int i=0; i<len; i++)
893
      {
894
      int[] ind = index[i];
895
      int num = ind.length;
896
      ret[i] = new float[num][4];
897

    
898
      for(int j=0; j<num; j++)
899
        {
900
        float[] r = ret[i][j];
901
        float[] v = vertices[ind[j]];
902
        r[0] = v[0];
903
        r[1] = v[1];
904
        r[2] = v[2];
905
        r[3] = 1.0f;
906
        }
907
      }
908

    
909
    return ret;
910
    }
911

    
912
///////////////////////////////////////////////////////////////////////////////////////////////////
913

    
914
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects)
915
    {
916
    boolean[] uses      = effects.getUses();
917
    String[] names      = effects.getNames();
918
    float[][] variables = effects.getVariables();
919
    float[][] centers   = effects.getCenters();
920
    float[][] regions   = effects.getRegions();
921
    int numEffects = uses.length;
922

    
923
    for(int eff=0; eff<numEffects; eff++)
924
      if( names[eff]!=null )
925
        {
926
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
927
        if( effect!=null ) mesh.apply(effect);
928
        }
929
    }
930

    
931
///////////////////////////////////////////////////////////////////////////////////////////////////
932

    
933
  private void correctComponents(MeshBase mesh, int numComponents)
934
    {
935
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
936

    
937
    mesh.mergeEffComponents();
938

    
939
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
940
    }
941

    
942
///////////////////////////////////////////////////////////////////////////////////////////////////
943

    
944
  private void printTransform(FaceTransform f)
945
    {
946
    android.util.Log.e("D", "face="+f.face+" sticker="+f.sticker+" scale="+f.scale+
947
                            " q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("+f.vx+", "+f.vy+", "+f.vz+")");
948
    }
949

    
950
///////////////////////////////////////////////////////////////////////////////////////////////////
951

    
952
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
953
    {
954
    float[] bands = new float[2*N];
955

    
956
    bands[0] = 1.0f;
957
    bands[1] = 0.0f;
958

    
959
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
960
    float sinBeta = (float)Math.sin(beta);
961
    float cosBeta = (float)Math.cos(beta);
962
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
963
    float D = R*sinBeta;
964
    float B = h(R,sinBeta,K*beta);
965

    
966
    if( D>1.0f )
967
      {
968
      for(int i=1; i<N; i++)
969
        {
970
        bands[2*i  ] = (float)(N-1-i)/(N-1);
971
        bands[2*i+1] = H*(1-bands[2*i]);
972
        }
973
      }
974
    else
975
      {
976
      int K2 = (int)((N-3)*K);
977
      int K1 = (N-3)-K2;
978

    
979
      for(int i=0; i<=K1; i++)
980
        {
981
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
982
        float x = h(R,sinBeta,angle);
983
        bands[2*i+2] = 1.0f - x;
984
        bands[2*i+3] = g(R,D,x,cosBeta);
985
        }
986

    
987
      for(int i=0; i<=K2; i++)
988
        {
989
        float x = (1-B)*(i+1)/(K2+1) + B;
990
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
991
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
992
        }
993
      }
994

    
995
    bands[2*N-2] = 0.0f;
996
    bands[2*N-1] =    H;
997

    
998
    return bands;
999
    }
1000

    
1001
///////////////////////////////////////////////////////////////////////////////////////////////////
1002

    
1003
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
1004
    {
1005
    if( in==null )
1006
      {
1007
      out[0] = out[1] = 0.0f;
1008
      }
1009
    else
1010
      {
1011
      out[0] = in[0] - ft.vx;
1012
      out[1] = in[1] - ft.vy;
1013
      out[2] = in[2] - ft.vz;
1014
      out[3] = 1.0f;
1015

    
1016
      mQuat1[0] =-ft.qx;
1017
      mQuat1[1] =-ft.qy;
1018
      mQuat1[2] =-ft.qz;
1019
      mQuat1[3] = ft.qw;
1020

    
1021
      mQuat2[0] = -mQuat1[0];
1022
      mQuat2[1] = -mQuat1[1];
1023
      mQuat2[2] = -mQuat1[2];
1024
      mQuat2[3] =  mQuat1[3];
1025

    
1026
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1027
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1028

    
1029
      out[0] /= ft.scale;
1030
      out[1] /= ft.scale;
1031
      out[2] /= ft.scale;
1032
      }
1033
    }
1034

    
1035
///////////////////////////////////////////////////////////////////////////////////////////////////
1036

    
1037
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
1038
    {
1039
    for(int[] tab : table)
1040
      {
1041
      int len = tab.length;
1042

    
1043
      for(int j=0; j<len; j++)
1044
        if( tab[j]==oldPointer ) tab[j] = newPointer;
1045
      }
1046
    }
1047

    
1048
///////////////////////////////////////////////////////////////////////////////////////////////////
1049

    
1050
  private String printSticker(StickerCoords info)
1051
    {
1052
    String ret = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+"\n";
1053

    
1054
    int len = info.outerVertices.length;
1055

    
1056
    for(int l=0; l<len; l++)
1057
      {
1058
      float[][] outer = info.outerVertices[l];
1059
      int numV = outer.length;
1060

    
1061
      ret += "  Loop "+l+" verts: "+numV+" { ";
1062
      for(int v=0; v<numV; v++)
1063
        {
1064
        if(v!=0) ret += ", ";
1065
        ret += (outer[v][0]+"f, "+outer[v][1]+"f");
1066
        }
1067

    
1068
      ret += "}\n";
1069
      }
1070

    
1071
    return ret;
1072
    }
1073

    
1074
///////////////////////////////////////////////////////////////////////////////////////////////////
1075
// INTERNAL API
1076

    
1077
  public int printStickerCoords()
1078
    {
1079
    int stickers = mStickerCoords.size();
1080
    int ret = 0;
1081

    
1082
    android.util.Log.d("D", "---- STICKER COORDS ----");
1083

    
1084
    for(int s=0; s<stickers; s++)
1085
      {
1086
      StickerCoords info = mStickerCoords.get(s);
1087
      if( info.outer )  ret++;
1088
      String str = printSticker(info);
1089
      android.util.Log.d("D", "Sticker "+s+" "+str);
1090
      }
1091

    
1092
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1093

    
1094
    return ret;
1095
    }
1096

    
1097
///////////////////////////////////////////////////////////////////////////////////////////////////
1098

    
1099
  public void printFaceTransform()
1100
    {
1101
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1102

    
1103
    int oldfaces = mOldFaceTransf.size();
1104

    
1105
    for(int f=0; f<oldfaces; f++)
1106
      {
1107
      printTransform(mOldFaceTransf.get(f));
1108
      }
1109

    
1110
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1111

    
1112
    int newfaces = mNewFaceTransf.size();
1113

    
1114
    for(int f=0; f<newfaces; f++)
1115
      {
1116
      printTransform(mNewFaceTransf.get(f));
1117
      }
1118
    }
1119

    
1120
///////////////////////////////////////////////////////////////////////////////////////////////////
1121

    
1122
  private void printVert(double[][] buffer)
1123
    {
1124
    StringBuilder str = new StringBuilder();
1125

    
1126
    for(double[] buf : buffer)
1127
      {
1128
      str.append(" (");
1129
      str.append(buf[0]);
1130
      str.append(" , ");
1131
      str.append(buf[1]);
1132
      str.append(" ) ");
1133
      }
1134

    
1135
    android.util.Log.d("D", str.toString());
1136
    }
1137

    
1138
///////////////////////////////////////////////////////////////////////////////////////////////////
1139
// PUBLIC API
1140

    
1141
  public static FactoryCubit getInstance()
1142
    {
1143
    if( mThis==null ) mThis = new FactoryCubit();
1144
    return mThis;
1145
    }
1146

    
1147
///////////////////////////////////////////////////////////////////////////////////////////////////
1148

    
1149
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
1150
                                                          float[][] corners, int[] cornerIndices,
1151
                                                          float[][] centers, int[] centerIndices )
1152
    {
1153
    int numVerts = vertices.length;
1154
    String[] names = new String[numVerts];
1155
    float[][] vars = new float[numVerts][];
1156
    float[][] cents= new float[numVerts][];
1157
    float[][] regs = new float[numVerts][];
1158
    boolean[] uses = new boolean[numVerts];
1159

    
1160
    for(int i=0; i<numVerts; i++)
1161
      {
1162
      int centerI = centerIndices[i];
1163
      int cornerI = cornerIndices[i];
1164

    
1165
      if( centerI>=0 && cornerI>=0 )
1166
        {
1167
        float[] ce = centers[centerI];
1168
        float[] ve = vertices[i];
1169
        float S = corners[cornerI][0];
1170
        float R = corners[cornerI][1];
1171

    
1172
        float CX = ve[0];
1173
        float CY = ve[1];
1174
        float CZ = ve[2];
1175
        float X = S*(ce[0]-CX);
1176
        float Y = S*(ce[1]-CY);
1177
        float Z = S*(ce[2]-CZ);
1178

    
1179
        names[i]= NAME;
1180
        vars[i] = new float[] { 0, X,Y,Z, 1 };
1181
        cents[i]= new float[] { CX, CY, CZ };
1182
        regs[i] = new float[] { 0,0,0, R };
1183
        uses[i] = false;
1184
        }
1185
      }
1186

    
1187
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1188
    }
1189

    
1190
///////////////////////////////////////////////////////////////////////////////////////////////////
1191

    
1192
  public float[] getStickerScales()
1193
    {
1194
    int index=0,num=0,len = mStickerCoords.size();
1195

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

    
1198
    if( num>0 )
1199
      {
1200
      float[] scales = new float[num];
1201

    
1202
      for(int i=0; i<len; i++)
1203
        {
1204
        StickerCoords sticker = mStickerCoords.get(i);
1205
        if( sticker.outer ) scales[index++] = sticker.scale;
1206
        }
1207

    
1208
      return scales;
1209
      }
1210

    
1211
    return null;
1212
    }
1213

    
1214
///////////////////////////////////////////////////////////////////////////////////////////////////
1215

    
1216
  public float[][][][] getStickerCoords()
1217
    {
1218
    int index=0,num=0,len = mStickerCoords.size();
1219

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

    
1222
    if( num>0 )
1223
      {
1224
      float[][][][] coords = new float[num][][][];
1225

    
1226
      for(int i=0; i<len; i++)
1227
        {
1228
        StickerCoords sticker = mStickerCoords.get(i);
1229
        if( sticker.outer ) coords[index++] = sticker.outerVertices;
1230
        }
1231

    
1232
      return coords;
1233
      }
1234

    
1235
    return null;
1236
    }
1237

    
1238
///////////////////////////////////////////////////////////////////////////////////////////////////
1239

    
1240
  public int[][] getStickerVariants()
1241
    {
1242
    int numvariants = 1; // there's one in the 'new' array
1243

    
1244
    int oldfaces = mOldFaceTransf.size();
1245

    
1246
    for(int f=0; f<oldfaces; f++)
1247
      {
1248
      FaceTransform ft = mOldFaceTransf.get(f);
1249
      if( ft.face==0 ) numvariants++;
1250
      }
1251

    
1252
    int[][] ret = new int[numvariants][];
1253
    int face=0, variant=-1;
1254

    
1255
    for(int f=0; f<oldfaces; f++)
1256
      {
1257
      FaceTransform ft = mOldFaceTransf.get(f);
1258
      if( ft.face==0 )
1259
        {
1260
        variant++;
1261
        face=0;
1262
        ret[variant] = new int[ft.numFaces];
1263
        }
1264

    
1265
      ret[variant][face++] = ft.sticker;
1266
      }
1267

    
1268
    int newfaces = mNewFaceTransf.size();
1269

    
1270
    for(int f=0; f<newfaces; f++)
1271
      {
1272
      FaceTransform ft = mNewFaceTransf.get(f);
1273
      if( ft.face==0 )
1274
        {
1275
        variant++;
1276
        face=0;
1277
        ret[variant] = new int[ft.numFaces];
1278
        }
1279

    
1280
      ret[variant][face++] = ft.sticker;
1281
      }
1282

    
1283
    int numStickers = mStickerCoords.size();
1284
    int numOuter=0;
1285

    
1286
    for(int i=0; i<numStickers; i++)
1287
      {
1288
      StickerCoords sc = mStickerCoords.get(i);
1289
      if( sc.outer )
1290
        {
1291
        changeStickerPointers(ret,i, numOuter);
1292
        numOuter++;
1293
        }
1294
      else
1295
        {
1296
        changeStickerPointers(ret,i,-1);
1297
        }
1298
      }
1299

    
1300
    return ret;
1301
    }
1302

    
1303
///////////////////////////////////////////////////////////////////////////////////////////////////
1304

    
1305
  public void clear()
1306
    {
1307
    mStickerCoords.clear();
1308
    mNewFaceTransf.clear();
1309
    mOldFaceTransf.clear();
1310
    }
1311

    
1312
///////////////////////////////////////////////////////////////////////////////////////////////////
1313
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
1314
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
1315
// been called.
1316

    
1317
  public Static4D getQuaternion(int face)
1318
    {
1319
    FaceTransform ft = mNewFaceTransf.get(face);
1320
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
1321
    }
1322

    
1323
///////////////////////////////////////////////////////////////////////////////////////////////////
1324

    
1325
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1326
    {
1327
    float[][] vertices = shape.getVertices();
1328
    int[][] indices = shape.getVertIndices();
1329
    int[][][] fullIndices = shape.getMultigonIndices();
1330
    boolean isMultigon = shape.isMultigon();
1331
    FaceTransform ft;
1332
    int numNew = mNewFaceTransf.size();
1333

    
1334
    for(int i=0; i<numNew; i++)
1335
      {
1336
      ft = mNewFaceTransf.remove(0);
1337
      mOldFaceTransf.add(ft);
1338
      }
1339

    
1340
    int numFaces = shape.getNumFaces();
1341
    int numOld = mOldFaceTransf.size();
1342

    
1343
    for (int face=0; face<numFaces; face++)
1344
      {
1345
      boolean collapsed = false;
1346
      boolean isOuter = (outer!=null && outer[face]>0);
1347
      FaceTransform newT;
1348

    
1349
      if( !isMultigon )
1350
        {
1351
        float[][] vert = constructVert(vertices, indices[face]);
1352
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1353
        }
1354
      else
1355
        {
1356
        float[][][] vert = constructVert(vertices, fullIndices[face]);
1357
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1358
        }
1359

    
1360
      for (int old=0; !collapsed && old<numOld; old++)
1361
        {
1362
        ft = mOldFaceTransf.get(old);
1363
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1364
        }
1365

    
1366
      for (int pre=0; !collapsed && pre<face; pre++)
1367
        {
1368
        ft = mNewFaceTransf.get(pre);
1369
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1370
        }
1371

    
1372
      mNewFaceTransf.add(newT);
1373
      }
1374
    }
1375

    
1376
///////////////////////////////////////////////////////////////////////////////////////////////////
1377

    
1378
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1379
                                     final ObjectVertexEffects effects, int numComponents)
1380
    {
1381
    float[][] bands         = faceShape.getBands();
1382
    int[]   bandIndexes     = faceShape.getBandIndices();
1383
    float[] convexityCenter = faceShape.getConvexityCenter();
1384

    
1385
    int numFaces = shape.getNumFaces();
1386
    float[] bandsComputed;
1387
    MeshBase[] meshes = new MeshBase[numFaces];
1388
    FaceTransform fInfo;
1389
    StickerCoords sInfo;
1390
    float[] convexXY = new float[4];
1391

    
1392
    for(int face=0; face<numFaces; face++)
1393
      {
1394
      fInfo = mNewFaceTransf.get(face);
1395
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1396

    
1397
      int index      = bandIndexes[face];
1398
      float[] band   = bands[index];
1399
      float height   = band[0];
1400
      int alpha      = (int)band[1];
1401
      float dist     = band[2];
1402
      float K        = band[3];
1403
      int N          = (int)band[4];
1404
      int exIndex    = (int)band[5];
1405
      int exVertices = (int)band[6];
1406

    
1407
      bandsComputed = computeBands(height,alpha,dist,K,N);
1408

    
1409
      sInfo = mStickerCoords.get(fInfo.sticker);
1410
      float[][][] vertsF = sInfo.fullVertices;
1411

    
1412
      // i.e. multigon which hasn't been 'successfully collapsed'
1413
      // with a previously computed polygon sticker!
1414
      if( vertsF!=null )
1415
        {
1416
        int lenVerts = vertsF.length;
1417
        float[][][] copiedVerts = new float[lenVerts][][];
1418

    
1419
        for(int i=0; i<lenVerts; i++)
1420
          {
1421
          float[][] v = vertsF[i];
1422
          int len = v.length;
1423
          copiedVerts[i] = new float[len][2];
1424

    
1425
          for(int j=0; j<len; j++)
1426
            {
1427
            copiedVerts[i][j][0] = v[j][0];
1428
            copiedVerts[i][j][1] = v[j][1];
1429
            }
1430
          }
1431

    
1432
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1433
        }
1434
      else
1435
        {
1436
        float[][] verts = sInfo.outerVertices[0];
1437
        int lenVerts = verts.length;
1438
        float[][] copiedVerts = new float[lenVerts][2];
1439

    
1440
        for(int v=0; v<lenVerts; v++)
1441
          {
1442
          float[] ve = verts[v];
1443
          copiedVerts[v][0] = ve[0];
1444
          copiedVerts[v][1] = ve[1];
1445
          }
1446

    
1447
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1448
        }
1449

    
1450
      meshes[face].setEffectAssociation(0,0,face);
1451
      }
1452

    
1453
    MeshBase mesh = new MeshJoined(meshes);
1454
    Static3D center = new Static3D(0,0,0);
1455

    
1456
    for(int face=0; face<numFaces; face++)
1457
      {
1458
      fInfo = mNewFaceTransf.get(face);
1459

    
1460
      float vx = fInfo.vx;
1461
      float vy = fInfo.vy;
1462
      float vz = fInfo.vz;
1463
      float sc = fInfo.scale;
1464
      float qx = fInfo.qx;
1465
      float qy = fInfo.qy;
1466
      float qz = fInfo.qz;
1467
      float qw = fInfo.qw;
1468

    
1469
      Static3D scale = new Static3D(sc,sc,sc);
1470
      Static3D move3D= new Static3D(vx,vy,vz);
1471
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1472

    
1473
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1474
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1475
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1476
      }
1477

    
1478
    correctComponents(mesh,numComponents);
1479
    if( effects!=null ) applyVertexEffects(mesh,effects);
1480

    
1481
    return mesh;
1482
    }
1483
  }
(2-2/13)