Project

General

Profile

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

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

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
    // this theoretically should be uncommented to combat the same effect like in
187
    // TouchControlShapeChanging.FaceInfo, but when I try, the center sticker of
188
    // CoinTetrahedron gets inverted. Weird!
189
    // Uncommenting this does fix the fact that the convexity of the center cubits
190
    // of CoinT and CoinH goes concave
191

    
192
/*
193
    if( totalAngle(vertices,mBuffer)<0 )
194
      {
195
      mBuffer[0] *= -1;
196
      mBuffer[1] *= -1;
197
      mBuffer[2] *= -1;
198
      }
199
 */
200
    }
201

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

    
211
  public static float totalAngle(float[][] vert, float[] normal)
212
    {
213
    float ret = 0;
214
    int num = vert.length;
215

    
216
    for(int c=0; c<num; c++)
217
      {
218
      int n = (c==num-1 ? 0 : c+1);
219
      int m = (n==num-1 ? 0 : n+1);
220
      ret += angle( vert[c],vert[n],vert[m], normal);
221
      }
222

    
223
    return ret;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private static float angle(float[] v0, float[] v1, float[] v2, float[] normal)
229
    {
230
    float px = v1[0] - v0[0];
231
    float py = v1[1] - v0[1];
232
    float pz = v1[2] - v0[2];
233

    
234
    float rx = v2[0] - v1[0];
235
    float ry = v2[1] - v1[1];
236
    float rz = v2[2] - v1[2];
237

    
238
    float l1 = (float)Math.sqrt(px*px + py*py + pz*pz);
239
    float l2 = (float)Math.sqrt(rx*rx + ry*ry + rz*rz);
240

    
241
    px /= l1;
242
    py /= l1;
243
    pz /= l1;
244

    
245
    rx /= l2;
246
    ry /= l2;
247
    rz /= l2;
248

    
249
    float s = px*rx + py*ry + pz*rz;
250

    
251
    if( s> 1 ) s= 1;
252
    if( s<-1 ) s=-1;
253

    
254
    float a = (float) Math.acos(s);
255
    float[] cross = crossProduct(px,py,pz,rx,ry,rz);
256

    
257
    float ax = cross[0] + normal[0];
258
    float ay = cross[1] + normal[1];
259
    float az = cross[2] + normal[2];
260

    
261
    float bx = cross[0] - normal[0];
262
    float by = cross[1] - normal[1];
263
    float bz = cross[2] - normal[2];
264

    
265
    float f1 = ax*ax + ay*ay + az*az;
266
    float f2 = bx*bx + by*by + bz*bz;
267

    
268
    return f1>f2 ? a : -a;
269
    }
270

    
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272

    
273
  private static float[] crossProduct(float a1, float a2, float a3, float b1, float b2, float b3)
274
    {
275
    float[] ret = new float[3];
276

    
277
    ret[0] = a2*b3 - a3*b2;
278
    ret[1] = a3*b1 - a1*b3;
279
    ret[2] = a1*b2 - a2*b1;
280

    
281
    return ret;
282
    }
283

    
284
///////////////////////////////////////////////////////////////////////////////////////////////////
285

    
286
  private float[][][] computeOuterEdge(float[][][] vertices)
287
    {
288
    int[][] edgesUp = MeshMultigon.computeEdgesUp(vertices);
289
    return MeshMultigon.computeOuterAndHoleVertices(vertices,edgesUp);
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293
// polygon
294

    
295
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
296
    {
297
    float minX = Float.MAX_VALUE;
298
    float maxX =-Float.MAX_VALUE;
299
    float minY = Float.MAX_VALUE;
300
    float maxY =-Float.MAX_VALUE;
301

    
302
    for (float[] vert : vert3D)
303
      {
304
      float x = vert[0];
305
      float y = vert[1];
306

    
307
      if (x > maxX) maxX = x;
308
      if (x < minX) minX = x;
309
      if (y > maxY) maxY = y;
310
      if (y < minY) minY = y;
311
      }
312

    
313
    minX = minX<0 ? -minX:minX;
314
    maxX = maxX<0 ? -maxX:maxX;
315
    minY = minY<0 ? -minY:minY;
316
    maxY = maxY<0 ? -maxY:maxY;
317

    
318
    float max1 = Math.max(minX,minY);
319
    float max2 = Math.max(maxX,maxY);
320
    float max3 = Math.max(max1,max2);
321

    
322
    info.scale = max3/0.5f;
323

    
324
    int len = vert3D.length;
325
    StickerCoords sInfo = new StickerCoords();
326
    sInfo.outer = isOuter;
327
    sInfo.scale = info.scale;
328
    sInfo.outerVertices = new float[1][len][2];
329
    sInfo.fullVertices = null;
330

    
331
    float[][] t = sInfo.outerVertices[0];
332

    
333
    for( int vertex=0; vertex<len; vertex++ )
334
      {
335
      t[vertex][0] = vert3D[vertex][0] / info.scale;
336
      t[vertex][1] = vert3D[vertex][1] / info.scale;
337
      }
338

    
339
    mStickerCoords.add(sInfo);
340

    
341
    info.sticker = mStickerCoords.size() -1;
342
    }
343

    
344

    
345
///////////////////////////////////////////////////////////////////////////////////////////////////
346
// multigon
347

    
348
  private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
349
    {
350
    float minX = Float.MAX_VALUE;
351
    float maxX =-Float.MAX_VALUE;
352
    float minY = Float.MAX_VALUE;
353
    float maxY =-Float.MAX_VALUE;
354

    
355
    for( float[][] vert : vert3D)
356
      for( float[] v : vert)
357
        {
358
        float x = v[0];
359
        float y = v[1];
360

    
361
        if (x > maxX) maxX = x;
362
        if (x < minX) minX = x;
363
        if (y > maxY) maxY = y;
364
        if (y < minY) minY = y;
365
        }
366

    
367
    minX = minX<0 ? -minX:minX;
368
    maxX = maxX<0 ? -maxX:maxX;
369
    minY = minY<0 ? -minY:minY;
370
    maxY = maxY<0 ? -maxY:maxY;
371

    
372
    float max1 = Math.max(minX,minY);
373
    float max2 = Math.max(maxX,maxY);
374
    float max3 = Math.max(max1,max2);
375

    
376
    info.scale = max3/0.5f;
377

    
378
    int len = vert3D.length;
379
    StickerCoords sInfo = new StickerCoords();
380
    sInfo.outer = isOuter;
381
    sInfo.scale = info.scale;
382
    sInfo.fullVertices = new float[len][][];
383

    
384
    for( int comp=0; comp<len; comp++ )
385
      {
386
      float[][] vert = vert3D[comp];
387
      int num = vert.length;
388
      sInfo.fullVertices[comp] = new float[num][2];
389
      float[][] t = sInfo.fullVertices[comp];
390

    
391
      for( int vertex=0; vertex<num; vertex++)
392
        {
393
        t[vertex][0] = vert[vertex][0] / info.scale;
394
        t[vertex][1] = vert[vertex][1] / info.scale;
395
        }
396
      }
397

    
398
    sInfo.outerVertices = computeOuterEdge(sInfo.fullVertices);
399

    
400
    mStickerCoords.add(sInfo);
401

    
402
    info.sticker = mStickerCoords.size() -1;
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// polygon
407

    
408
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
409
    {
410
    FaceTransform ft = new FaceTransform();
411
    ft.face = face;
412
    ft.numFaces = numFaces;
413

    
414
    // compute center of gravity
415
    ft.vx = 0.0f;
416
    ft.vy = 0.0f;
417
    ft.vz = 0.0f;
418
    int len = vert3D.length;
419

    
420
    for (float[] vert : vert3D)
421
      {
422
      ft.vx += vert[0];
423
      ft.vy += vert[1];
424
      ft.vz += vert[2];
425
      }
426

    
427
    ft.vx /= len;
428
    ft.vy /= len;
429
    ft.vz /= len;
430

    
431
    // move all vertices so that their center of gravity is at (0,0,0)
432
    for (int i=0; i<len; i++)
433
      {
434
      vert3D[i][0] -= ft.vx;
435
      vert3D[i][1] -= ft.vy;
436
      vert3D[i][2] -= ft.vz;
437
      }
438

    
439
    // find 3 non-colinear vertices
440
    int foundIndex = -1;
441

    
442
    for(int vertex=2; vertex<len; vertex++)
443
      {
444
      if( areNotColinear(vert3D,vertex) )
445
        {
446
        foundIndex = vertex;
447
        break;
448
        }
449
      }
450

    
451
    // compute the normal vector
452
    if( foundIndex==-1 )
453
      {
454
      StringBuilder sb = new StringBuilder();
455

    
456
      for (float[] floats : vert3D)
457
        {
458
        sb.append(' ');
459
        sb.append("(");
460
        sb.append(floats[0]);
461
        sb.append(" ");
462
        sb.append(floats[1]);
463
        sb.append(" ");
464
        sb.append(floats[2]);
465
        sb.append(")");
466
        }
467
      android.util.Log.e("D", "verts: "+sb);
468

    
469
      throw new RuntimeException("all vertices colinear");
470
      }
471

    
472
    computeNormalVector(vert3D,foundIndex);
473

    
474
    // rotate so that the normal vector becomes (0,0,1)
475
    float axisX, axisY, axisZ;
476

    
477
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
478
      {
479
      axisX = -mBuffer[1];
480
      axisY =  mBuffer[0];
481
      axisZ = 0.0f;
482

    
483
      float axiLen = axisX*axisX + axisY*axisY;
484
      axiLen = (float)Math.sqrt(axiLen);
485
      axisX /= axiLen;
486
      axisY /= axiLen;
487
      axisZ /= axiLen;
488
      }
489
    else
490
      {
491
      axisX = 0.0f;
492
      axisY = 1.0f;
493
      axisZ = 0.0f;
494
      }
495

    
496
    float cosTheta = mBuffer[2];
497
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
498
    float sinHalfTheta = computeSinHalf(cosTheta);
499
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
500

    
501
    mQuat1[0] = axisX*sinHalfTheta;
502
    mQuat1[1] = axisY*sinHalfTheta;
503
    mQuat1[2] = axisZ*sinHalfTheta;
504
    mQuat1[3] = cosHalfTheta;
505
    mQuat2[0] =-axisX*sinHalfTheta;
506
    mQuat2[1] =-axisY*sinHalfTheta;
507
    mQuat2[2] =-axisZ*sinHalfTheta;
508
    mQuat2[3] = cosHalfTheta;
509

    
510
    for (float[] vert : vert3D)
511
      {
512
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
513
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
514
      }
515

    
516
    // fit the whole thing in a square and remember the scale & 2D vertices
517
    fitInSquare(ft, vert3D, isOuter);
518

    
519
    // remember the rotation
520
    ft.qx =-mQuat1[0];
521
    ft.qy =-mQuat1[1];
522
    ft.qz =-mQuat1[2];
523
    ft.qw = mQuat1[3];
524

    
525
    return ft;
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529
// multigon
530

    
531
  private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
532
    {
533
    FaceTransform ft = new FaceTransform();
534
    ft.face = face;
535
    ft.numFaces = numFaces;
536

    
537
    // compute center of gravity
538
    ft.vx = 0.0f;
539
    ft.vy = 0.0f;
540
    ft.vz = 0.0f;
541
    int len = 0;
542

    
543
    for( float[][] vert : vert3D )
544
      for( float[] v : vert )
545
        {
546
        ft.vx += v[0];
547
        ft.vy += v[1];
548
        ft.vz += v[2];
549
        len++;
550
        }
551

    
552
    ft.vx /= len;
553
    ft.vy /= len;
554
    ft.vz /= len;
555

    
556
    // move all vertices so that their center of gravity is at (0,0,0)
557
    for( float[][] vert : vert3D )
558
      for( float[] v : vert )
559
        {
560
        v[0] -= ft.vx;
561
        v[1] -= ft.vy;
562
        v[2] -= ft.vz;
563
        }
564

    
565
    // find 3 non-colinear vertices
566
    int foundIndex = -1;
567
    len = vert3D[0].length;
568

    
569
    for(int vertex=2; vertex<len; vertex++)
570
      {
571
      if( areNotColinear(vert3D[0],vertex) )
572
        {
573
        foundIndex = vertex;
574
        break;
575
        }
576
      }
577

    
578
    // compute the normal vector
579
    if( foundIndex==-1 )
580
      {
581
      StringBuilder sb = new StringBuilder();
582

    
583
      for (float[] v : vert3D[0])
584
        {
585
        sb.append(' ');
586
        sb.append("(");
587
        sb.append(v[0]);
588
        sb.append(" ");
589
        sb.append(v[1]);
590
        sb.append(" ");
591
        sb.append(v[2]);
592
        sb.append(")");
593
        }
594
      android.util.Log.e("D", "verts: "+sb);
595

    
596
      throw new RuntimeException("all vertices colinear");
597
      }
598

    
599
    computeNormalVector(vert3D[0],foundIndex);
600

    
601
    // rotate so that the normal vector becomes (0,0,1)
602
    float axisX, axisY, axisZ;
603

    
604
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
605
      {
606
      axisX = -mBuffer[1];
607
      axisY =  mBuffer[0];
608
      axisZ = 0.0f;
609

    
610
      float axiLen = axisX*axisX + axisY*axisY;
611
      axiLen = (float)Math.sqrt(axiLen);
612
      axisX /= axiLen;
613
      axisY /= axiLen;
614
      axisZ /= axiLen;
615
      }
616
    else
617
      {
618
      axisX = 0.0f;
619
      axisY = 1.0f;
620
      axisZ = 0.0f;
621
      }
622

    
623
    float cosTheta = mBuffer[2];
624
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
625
    float sinHalfTheta = computeSinHalf(cosTheta);
626
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
627

    
628
    mQuat1[0] = axisX*sinHalfTheta;
629
    mQuat1[1] = axisY*sinHalfTheta;
630
    mQuat1[2] = axisZ*sinHalfTheta;
631
    mQuat1[3] = cosHalfTheta;
632
    mQuat2[0] =-axisX*sinHalfTheta;
633
    mQuat2[1] =-axisY*sinHalfTheta;
634
    mQuat2[2] =-axisZ*sinHalfTheta;
635
    mQuat2[3] = cosHalfTheta;
636

    
637
    for( float[][] vert : vert3D)
638
      for( float[] v : vert)
639
        {
640
        QuatHelper.quatMultiply(mQuat3, mQuat1, v  );
641
        QuatHelper.quatMultiply(  v, mQuat3, mQuat2);
642
        }
643

    
644
    // fit the whole thing in a square and remember the scale & 2D vertices
645
    fitInSquare(ft, vert3D, isOuter);
646

    
647
    // remember the rotation
648
    ft.qx =-mQuat1[0];
649
    ft.qy =-mQuat1[1];
650
    ft.qz =-mQuat1[2];
651
    ft.qw = mQuat1[3];
652

    
653
    return ft;
654
    }
655

    
656
///////////////////////////////////////////////////////////////////////////////////////////////////
657

    
658
  private void rotateAllVertices(float[][] result, int len, float[][] vertices, float sin, float cos)
659
    {
660
    for(int i=0; i<len; i++)
661
      {
662
      float x = vertices[i][0];
663
      float y = vertices[i][1];
664
      result[i][0] = x*cos - y*sin;
665
      result[i][1] = x*sin + y*cos;
666
      }
667
    }
668

    
669
///////////////////////////////////////////////////////////////////////////////////////////////////
670

    
671
  private float computeScale(float[][] v1, float[][] v2, int v1i, int v2i)
672
    {
673
    float v1x = v1[v1i][0];
674
    float v1y = v1[v1i][1];
675
    float v2x = v2[v2i][0];
676
    float v2y = v2[v2i][1];
677

    
678
    float lenSq1 = v1x*v1x + v1y*v1y;
679
    float lenSq2 = v2x*v2x + v2y*v2y;
680

    
681
    return (float)Math.sqrt(lenSq2/lenSq1);
682
    }
683

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

    
687
  private float computeSinHalf(float cos)
688
    {
689
    return (float)Math.sqrt((1-cos)/2);
690
    }
691

    
692
///////////////////////////////////////////////////////////////////////////////////////////////////
693
// valid for 0<angle<2*PI
694

    
695
  private float computeCosHalf(float sin, float cos)
696
    {
697
    float cosHalf = (float)Math.sqrt((1+cos)/2);
698
    return sin<0 ? -cosHalf : cosHalf;
699
    }
700

    
701
///////////////////////////////////////////////////////////////////////////////////////////////////
702

    
703
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
704
    {
705
    int v = (rotatedVertex + oldVertex);
706
    if( v>=len ) v-=len;
707
    if( v< 0   ) v+=len;
708

    
709
    return v;
710
    }
711

    
712
///////////////////////////////////////////////////////////////////////////////////////////////////
713

    
714
  private boolean isScaledVersionOf(float[][] newVert, float[][] oldVert, int len, int vertex)
715
    {
716
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
717
    float EPSILON = 0.001f;
718
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
719

    
720
    for(int i=1; i<len; i++)
721
      {
722
      int index = computeRotatedIndex(i,len,vertex);
723

    
724
      float horz = oldVert[i][0] - scale*newVert[index][0];
725
      float vert = oldVert[i][1] - scale*newVert[index][1];
726

    
727
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
728
      }
729

    
730
    return true;
731
    }
732

    
733
///////////////////////////////////////////////////////////////////////////////////////////////////
734

    
735
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
736
    {
737
    mStickerCoords.remove(info.sticker);
738

    
739
    info.sticker = oldSticker;
740
    info.scale  *= scale;
741

    
742
    mQuat1[0] = info.qx;
743
    mQuat1[1] = info.qy;
744
    mQuat1[2] = info.qz;
745
    mQuat1[3] = info.qw;
746

    
747
    float sinHalf = computeSinHalf(cos);
748
    float cosHalf = computeCosHalf(sin,cos);
749

    
750
    mQuat2[0] = 0.0f;
751
    mQuat2[1] = 0.0f;
752
    mQuat2[2] = sinHalf;
753
    mQuat2[3] = cosHalf;
754

    
755
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
756

    
757
    info.qx = mQuat3[0];
758
    info.qy = mQuat3[1];
759
    info.qz = mQuat3[2];
760
    info.qw = mQuat3[3];
761
    }
762

    
763
///////////////////////////////////////////////////////////////////////////////////////////////////
764

    
765
  private boolean foundVertex(FaceTransform info, float[][] buffer, float[][] newVert, float[][] oldVert, int oldSticker)
766
    {
767
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
768
    int len = newVert.length;
769

    
770
    for(float[] ov : oldVert)
771
      {
772
      oldX = ov[0];
773
      oldY = ov[1];
774
      lenOld = (float) Math.sqrt(oldX*oldX+oldY*oldY);
775

    
776
      if(lenOld!=0) break;
777
      }
778

    
779
    for(int vertex=0; vertex<len; vertex++)
780
      {
781
      float newX = newVert[vertex][0];
782
      float newY = newVert[vertex][1];
783
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
784

    
785
      if( lenNew!=0 )
786
        {
787
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
788
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
789

    
790
        rotateAllVertices(buffer,len,newVert,sin,cos);
791

    
792
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
793
          {
794
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
795
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
796
          correctInfo(info,scale,sin,cos,oldSticker);
797
          return true;
798
          }
799
        }
800
      }
801

    
802
    return false;
803
    }
804

    
805
///////////////////////////////////////////////////////////////////////////////////////////////////
806

    
807
  private float computeCoreDistance(float[][] verts)
808
    {
809
    float ret = 0.0f;
810
    float centerX=0.0f,centerY=0.0f;
811
    int len = verts.length;
812

    
813
    for(float[] vert : verts)
814
      {
815
      centerX += vert[0];
816
      centerY += vert[1];
817
      }
818

    
819
    centerX /= len;
820
    centerY /= len;
821

    
822
    for(float[] vert : verts)
823
      {
824
      float distX = centerX-vert[0];
825
      float distY = centerY-vert[1];
826
      ret += (float) Math.sqrt(distX*distX+distY*distY);
827
      }
828

    
829
    return ret;
830
    }
831

    
832
///////////////////////////////////////////////////////////////////////////////////////////////////
833
// even if this is a multigon, then StickerCoords.outerVertices is the outer edge!
834
// (see fitInSquare multigon variant)
835

    
836
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
837
    {
838
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
839
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
840

    
841
    if( sNewInfo.outerVertices.length>1 || sOldInfo.outerVertices.length>1 ) // the 'outer' path is composed of more than
842
      {                                                                      // one segment, i.e. the sticker has holes.
843
      return false;                                                          // do not collapse such stickers.
844
      }
845

    
846
    float[][] newVert = sNewInfo.outerVertices[0];
847
    float[][] oldVert = sOldInfo.outerVertices[0];
848
    int oldLen = oldVert.length;
849
    int newLen = newVert.length;
850

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

    
858
      int oldSticker = oldInfo.sticker;
859
      float[][] buffer = new float[oldLen][2];
860

    
861
      if( foundVertex(newInfo, buffer, newVert, oldVert, oldSticker) )
862
        {
863
        if( sNewInfo.outer ) sOldInfo.outer = true;
864
        return true;
865
        }
866
      }
867

    
868
    return false;
869
    }
870

    
871
///////////////////////////////////////////////////////////////////////////////////////////////////
872
// polygon
873

    
874
  private float[][] constructVert(float[][] vertices, int[] index)
875
    {
876
    int len = index.length;
877
    float[][] ret = new float[len][4];
878

    
879
    for(int i=0; i<len; i++)
880
      {
881
      float[] tmp = vertices[index[i]];
882
      ret[i][0] = tmp[0];
883
      ret[i][1] = tmp[1];
884
      ret[i][2] = tmp[2];
885
      ret[i][3] = 1.0f;
886
      }
887

    
888
    return ret;
889
    }
890

    
891
///////////////////////////////////////////////////////////////////////////////////////////////////
892
// multigon
893

    
894
  private float[][][] constructVert(float[][] vertices, int[][] index)
895
    {
896
    int len = index.length;
897
    float[][][] ret = new float[len][][];
898

    
899
    for(int i=0; i<len; i++)
900
      {
901
      int[] ind = index[i];
902
      int num = ind.length;
903
      ret[i] = new float[num][4];
904

    
905
      for(int j=0; j<num; j++)
906
        {
907
        float[] r = ret[i][j];
908
        float[] v = vertices[ind[j]];
909
        r[0] = v[0];
910
        r[1] = v[1];
911
        r[2] = v[2];
912
        r[3] = 1.0f;
913
        }
914
      }
915

    
916
    return ret;
917
    }
918

    
919
///////////////////////////////////////////////////////////////////////////////////////////////////
920

    
921
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects)
922
    {
923
    boolean[] uses      = effects.getUses();
924
    String[] names      = effects.getNames();
925
    float[][] variables = effects.getVariables();
926
    float[][] centers   = effects.getCenters();
927
    float[][] regions   = effects.getRegions();
928
    int numEffects = uses.length;
929

    
930
    for(int eff=0; eff<numEffects; eff++)
931
      if( names[eff]!=null )
932
        {
933
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
934
        if( effect!=null ) mesh.apply(effect);
935
        }
936
    }
937

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

    
940
  private void correctComponents(MeshBase mesh, int numComponents)
941
    {
942
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
943

    
944
    mesh.mergeEffComponents();
945

    
946
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
947
    }
948

    
949
///////////////////////////////////////////////////////////////////////////////////////////////////
950

    
951
  private void printTransform(FaceTransform f)
952
    {
953
    android.util.Log.e("D", "face="+f.face+" sticker="+f.sticker+" scale="+f.scale+
954
                            " q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("+f.vx+", "+f.vy+", "+f.vz+")");
955
    }
956

    
957
///////////////////////////////////////////////////////////////////////////////////////////////////
958

    
959
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
960
    {
961
    float[] bands = new float[2*N];
962

    
963
    bands[0] = 1.0f;
964
    bands[1] = 0.0f;
965

    
966
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
967
    float sinBeta = (float)Math.sin(beta);
968
    float cosBeta = (float)Math.cos(beta);
969
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
970
    float D = R*sinBeta;
971
    float B = h(R,sinBeta,K*beta);
972

    
973
    if( D>1.0f )
974
      {
975
      for(int i=1; i<N; i++)
976
        {
977
        bands[2*i  ] = (float)(N-1-i)/(N-1);
978
        bands[2*i+1] = H*(1-bands[2*i]);
979
        }
980
      }
981
    else
982
      {
983
      int K2 = (int)((N-3)*K);
984
      int K1 = (N-3)-K2;
985

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

    
994
      for(int i=0; i<=K2; i++)
995
        {
996
        float x = (1-B)*(i+1)/(K2+1) + B;
997
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
998
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
999
        }
1000
      }
1001

    
1002
    bands[2*N-2] = 0.0f;
1003
    bands[2*N-1] =    H;
1004

    
1005
    return bands;
1006
    }
1007

    
1008
///////////////////////////////////////////////////////////////////////////////////////////////////
1009

    
1010
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
1011
    {
1012
    if( in==null )
1013
      {
1014
      out[0] = out[1] = 0.0f;
1015
      }
1016
    else
1017
      {
1018
      out[0] = in[0] - ft.vx;
1019
      out[1] = in[1] - ft.vy;
1020
      out[2] = in[2] - ft.vz;
1021
      out[3] = 1.0f;
1022

    
1023
      mQuat1[0] =-ft.qx;
1024
      mQuat1[1] =-ft.qy;
1025
      mQuat1[2] =-ft.qz;
1026
      mQuat1[3] = ft.qw;
1027

    
1028
      mQuat2[0] = -mQuat1[0];
1029
      mQuat2[1] = -mQuat1[1];
1030
      mQuat2[2] = -mQuat1[2];
1031
      mQuat2[3] =  mQuat1[3];
1032

    
1033
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1034
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1035

    
1036
      out[0] /= ft.scale;
1037
      out[1] /= ft.scale;
1038
      out[2] /= ft.scale;
1039
      }
1040
    }
1041

    
1042
///////////////////////////////////////////////////////////////////////////////////////////////////
1043

    
1044
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
1045
    {
1046
    for(int[] tab : table)
1047
      {
1048
      int len = tab.length;
1049

    
1050
      for(int j=0; j<len; j++)
1051
        if( tab[j]==oldPointer ) tab[j] = newPointer;
1052
      }
1053
    }
1054

    
1055
///////////////////////////////////////////////////////////////////////////////////////////////////
1056

    
1057
  private String printSticker(StickerCoords info)
1058
    {
1059
    String ret = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+"\n";
1060

    
1061
    int len = info.outerVertices.length;
1062

    
1063
    for(int l=0; l<len; l++)
1064
      {
1065
      float[][] outer = info.outerVertices[l];
1066
      int numV = outer.length;
1067

    
1068
      ret += "  Loop "+l+" verts: "+numV+" { ";
1069
      for(int v=0; v<numV; v++)
1070
        {
1071
        if(v!=0) ret += ", ";
1072
        ret += (outer[v][0]+"f, "+outer[v][1]+"f");
1073
        }
1074

    
1075
      ret += "}\n";
1076
      }
1077

    
1078
    return ret;
1079
    }
1080

    
1081
///////////////////////////////////////////////////////////////////////////////////////////////////
1082
// INTERNAL API
1083

    
1084
  public int printStickerCoords()
1085
    {
1086
    int stickers = mStickerCoords.size();
1087
    int ret = 0;
1088

    
1089
    android.util.Log.d("D", "---- STICKER COORDS ----");
1090

    
1091
    for(int s=0; s<stickers; s++)
1092
      {
1093
      StickerCoords info = mStickerCoords.get(s);
1094
      if( info.outer )  ret++;
1095
      String str = printSticker(info);
1096
      android.util.Log.d("D", "Sticker "+s+" "+str);
1097
      }
1098

    
1099
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1100

    
1101
    return ret;
1102
    }
1103

    
1104
///////////////////////////////////////////////////////////////////////////////////////////////////
1105

    
1106
  public void printFaceTransform()
1107
    {
1108
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1109

    
1110
    int oldfaces = mOldFaceTransf.size();
1111

    
1112
    for(int f=0; f<oldfaces; f++)
1113
      {
1114
      printTransform(mOldFaceTransf.get(f));
1115
      }
1116

    
1117
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1118

    
1119
    int newfaces = mNewFaceTransf.size();
1120

    
1121
    for(int f=0; f<newfaces; f++)
1122
      {
1123
      printTransform(mNewFaceTransf.get(f));
1124
      }
1125
    }
1126

    
1127
///////////////////////////////////////////////////////////////////////////////////////////////////
1128

    
1129
  private void printVert(double[][] buffer)
1130
    {
1131
    StringBuilder str = new StringBuilder();
1132

    
1133
    for(double[] buf : buffer)
1134
      {
1135
      str.append(" (");
1136
      str.append(buf[0]);
1137
      str.append(" , ");
1138
      str.append(buf[1]);
1139
      str.append(" ) ");
1140
      }
1141

    
1142
    android.util.Log.d("D", str.toString());
1143
    }
1144

    
1145
///////////////////////////////////////////////////////////////////////////////////////////////////
1146
// PUBLIC API
1147

    
1148
  public static FactoryCubit getInstance()
1149
    {
1150
    if( mThis==null ) mThis = new FactoryCubit();
1151
    return mThis;
1152
    }
1153

    
1154
///////////////////////////////////////////////////////////////////////////////////////////////////
1155

    
1156
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
1157
                                                          float[][] corners, int[] cornerIndices,
1158
                                                          float[][] centers, int[] centerIndices )
1159
    {
1160
    int numVerts = vertices.length;
1161
    String[] names = new String[numVerts];
1162
    float[][] vars = new float[numVerts][];
1163
    float[][] cents= new float[numVerts][];
1164
    float[][] regs = new float[numVerts][];
1165
    boolean[] uses = new boolean[numVerts];
1166

    
1167
    for(int i=0; i<numVerts; i++)
1168
      {
1169
      int centerI = centerIndices[i];
1170
      int cornerI = cornerIndices[i];
1171

    
1172
      if( centerI>=0 && cornerI>=0 )
1173
        {
1174
        float[] ce = centers[centerI];
1175
        float[] ve = vertices[i];
1176
        float S = corners[cornerI][0];
1177
        float R = corners[cornerI][1];
1178

    
1179
        float CX = ve[0];
1180
        float CY = ve[1];
1181
        float CZ = ve[2];
1182
        float X = S*(ce[0]-CX);
1183
        float Y = S*(ce[1]-CY);
1184
        float Z = S*(ce[2]-CZ);
1185

    
1186
        names[i]= NAME;
1187
        vars[i] = new float[] { 0, X,Y,Z, 1 };
1188
        cents[i]= new float[] { CX, CY, CZ };
1189
        regs[i] = new float[] { 0,0,0, R };
1190
        uses[i] = false;
1191
        }
1192
      }
1193

    
1194
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1195
    }
1196

    
1197
///////////////////////////////////////////////////////////////////////////////////////////////////
1198

    
1199
  public float[] getStickerScales()
1200
    {
1201
    int index=0,num=0,len = mStickerCoords.size();
1202

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

    
1205
    if( num>0 )
1206
      {
1207
      float[] scales = new float[num];
1208

    
1209
      for(int i=0; i<len; i++)
1210
        {
1211
        StickerCoords sticker = mStickerCoords.get(i);
1212
        if( sticker.outer ) scales[index++] = sticker.scale;
1213
        }
1214

    
1215
      return scales;
1216
      }
1217

    
1218
    return null;
1219
    }
1220

    
1221
///////////////////////////////////////////////////////////////////////////////////////////////////
1222

    
1223
  public float[][][][] getStickerCoords()
1224
    {
1225
    int index=0,num=0,len = mStickerCoords.size();
1226

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

    
1229
    if( num>0 )
1230
      {
1231
      float[][][][] coords = new float[num][][][];
1232

    
1233
      for(int i=0; i<len; i++)
1234
        {
1235
        StickerCoords sticker = mStickerCoords.get(i);
1236
        if( sticker.outer ) coords[index++] = sticker.outerVertices;
1237
        }
1238

    
1239
      return coords;
1240
      }
1241

    
1242
    return null;
1243
    }
1244

    
1245
///////////////////////////////////////////////////////////////////////////////////////////////////
1246

    
1247
  public int[][] getStickerVariants()
1248
    {
1249
    int numvariants = 1; // there's one in the 'new' array
1250

    
1251
    int oldfaces = mOldFaceTransf.size();
1252

    
1253
    for(int f=0; f<oldfaces; f++)
1254
      {
1255
      FaceTransform ft = mOldFaceTransf.get(f);
1256
      if( ft.face==0 ) numvariants++;
1257
      }
1258

    
1259
    int[][] ret = new int[numvariants][];
1260
    int face=0, variant=-1;
1261

    
1262
    for(int f=0; f<oldfaces; f++)
1263
      {
1264
      FaceTransform ft = mOldFaceTransf.get(f);
1265
      if( ft.face==0 )
1266
        {
1267
        variant++;
1268
        face=0;
1269
        ret[variant] = new int[ft.numFaces];
1270
        }
1271

    
1272
      ret[variant][face++] = ft.sticker;
1273
      }
1274

    
1275
    int newfaces = mNewFaceTransf.size();
1276

    
1277
    for(int f=0; f<newfaces; f++)
1278
      {
1279
      FaceTransform ft = mNewFaceTransf.get(f);
1280
      if( ft.face==0 )
1281
        {
1282
        variant++;
1283
        face=0;
1284
        ret[variant] = new int[ft.numFaces];
1285
        }
1286

    
1287
      ret[variant][face++] = ft.sticker;
1288
      }
1289

    
1290
    int numStickers = mStickerCoords.size();
1291
    int numOuter=0;
1292

    
1293
    for(int i=0; i<numStickers; i++)
1294
      {
1295
      StickerCoords sc = mStickerCoords.get(i);
1296
      if( sc.outer )
1297
        {
1298
        changeStickerPointers(ret,i, numOuter);
1299
        numOuter++;
1300
        }
1301
      else
1302
        {
1303
        changeStickerPointers(ret,i,-1);
1304
        }
1305
      }
1306

    
1307
    return ret;
1308
    }
1309

    
1310
///////////////////////////////////////////////////////////////////////////////////////////////////
1311

    
1312
  public void clear()
1313
    {
1314
    mStickerCoords.clear();
1315
    mNewFaceTransf.clear();
1316
    mOldFaceTransf.clear();
1317
    }
1318

    
1319
///////////////////////////////////////////////////////////////////////////////////////////////////
1320
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
1321
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
1322
// been called.
1323

    
1324
  public Static4D getQuaternion(int face)
1325
    {
1326
    FaceTransform ft = mNewFaceTransf.get(face);
1327
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
1328
    }
1329

    
1330
///////////////////////////////////////////////////////////////////////////////////////////////////
1331

    
1332
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1333
    {
1334
    float[][] vertices = shape.getVertices();
1335
    int[][] indices = shape.getVertIndices();
1336
    int[][][] fullIndices = shape.getMultigonIndices();
1337
    boolean isMultigon = shape.isMultigon();
1338
    FaceTransform ft;
1339
    int numNew = mNewFaceTransf.size();
1340

    
1341
    for(int i=0; i<numNew; i++)
1342
      {
1343
      ft = mNewFaceTransf.remove(0);
1344
      mOldFaceTransf.add(ft);
1345
      }
1346

    
1347
    int numFaces = shape.getNumFaces();
1348
    int numOld = mOldFaceTransf.size();
1349

    
1350
    for (int face=0; face<numFaces; face++)
1351
      {
1352
      boolean collapsed = false;
1353
      boolean isOuter = (outer!=null && outer[face]>0);
1354
      FaceTransform newT;
1355

    
1356
      if( !isMultigon )
1357
        {
1358
        float[][] vert = constructVert(vertices, indices[face]);
1359
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1360
        }
1361
      else
1362
        {
1363
        float[][][] vert = constructVert(vertices, fullIndices[face]);
1364
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1365
        }
1366

    
1367
      for (int old=0; !collapsed && old<numOld; old++)
1368
        {
1369
        ft = mOldFaceTransf.get(old);
1370
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1371
        }
1372

    
1373
      for (int pre=0; !collapsed && pre<face; pre++)
1374
        {
1375
        ft = mNewFaceTransf.get(pre);
1376
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1377
        }
1378

    
1379
      mNewFaceTransf.add(newT);
1380
      }
1381
    }
1382

    
1383
///////////////////////////////////////////////////////////////////////////////////////////////////
1384

    
1385
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1386
                                     final ObjectVertexEffects effects, int numComponents)
1387
    {
1388
    float[][] bands         = faceShape.getBands();
1389
    int[]   bandIndexes     = faceShape.getBandIndices();
1390
    float[] convexityCenter = faceShape.getConvexityCenter();
1391

    
1392
    int numFaces = shape.getNumFaces();
1393
    float[] bandsComputed;
1394
    MeshBase[] meshes = new MeshBase[numFaces];
1395
    FaceTransform fInfo;
1396
    StickerCoords sInfo;
1397
    float[] convexXY = new float[4];
1398

    
1399
    for(int face=0; face<numFaces; face++)
1400
      {
1401
      fInfo = mNewFaceTransf.get(face);
1402
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1403

    
1404
      int index      = bandIndexes[face];
1405
      float[] band   = bands[index];
1406
      float height   = band[0];
1407
      int alpha      = (int)band[1];
1408
      float dist     = band[2];
1409
      float K        = band[3];
1410
      int N          = (int)band[4];
1411
      int exIndex    = (int)band[5];
1412
      int exVertices = (int)band[6];
1413

    
1414
      bandsComputed = computeBands(height,alpha,dist,K,N);
1415

    
1416
      sInfo = mStickerCoords.get(fInfo.sticker);
1417
      float[][][] vertsF = sInfo.fullVertices;
1418

    
1419
      // i.e. multigon which hasn't been 'successfully collapsed'
1420
      // with a previously computed polygon sticker!
1421
      if( vertsF!=null )
1422
        {
1423
        int lenVerts = vertsF.length;
1424
        float[][][] copiedVerts = new float[lenVerts][][];
1425

    
1426
        for(int i=0; i<lenVerts; i++)
1427
          {
1428
          float[][] v = vertsF[i];
1429
          int len = v.length;
1430
          copiedVerts[i] = new float[len][2];
1431

    
1432
          for(int j=0; j<len; j++)
1433
            {
1434
            copiedVerts[i][j][0] = v[j][0];
1435
            copiedVerts[i][j][1] = v[j][1];
1436
            }
1437
          }
1438

    
1439
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1440
        }
1441
      else
1442
        {
1443
        float[][] verts = sInfo.outerVertices[0];
1444
        int lenVerts = verts.length;
1445
        float[][] copiedVerts = new float[lenVerts][2];
1446

    
1447
        for(int v=0; v<lenVerts; v++)
1448
          {
1449
          float[] ve = verts[v];
1450
          copiedVerts[v][0] = ve[0];
1451
          copiedVerts[v][1] = ve[1];
1452
          }
1453

    
1454
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1455
        }
1456

    
1457
      meshes[face].setEffectAssociation(0,0,face);
1458
      }
1459

    
1460
    MeshBase mesh = new MeshJoined(meshes);
1461
    Static3D center = new Static3D(0,0,0);
1462

    
1463
    for(int face=0; face<numFaces; face++)
1464
      {
1465
      fInfo = mNewFaceTransf.get(face);
1466

    
1467
      float vx = fInfo.vx;
1468
      float vy = fInfo.vy;
1469
      float vz = fInfo.vz;
1470
      float sc = fInfo.scale;
1471
      float qx = fInfo.qx;
1472
      float qy = fInfo.qy;
1473
      float qz = fInfo.qz;
1474
      float qw = fInfo.qw;
1475

    
1476
      Static3D scale = new Static3D(sc,sc,sc);
1477
      Static3D move3D= new Static3D(vx,vy,vz);
1478
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1479

    
1480
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1481
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1482
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1483
      }
1484

    
1485
    correctComponents(mesh,numComponents);
1486
    if( effects!=null ) applyVertexEffects(mesh,effects);
1487

    
1488
    return mesh;
1489
    }
1490
  }
(2-2/13)