Project

General

Profile

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

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

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is free software: you can redistribute it and/or modify                            //
7
// it under the terms of the GNU General Public License as published by                          //
8
// the Free Software Foundation, either version 2 of the License, or                             //
9
// (at your option) any later version.                                                           //
10
//                                                                                               //
11
// Magic Cube is distributed in the hope that it will be useful,                                 //
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
14
// GNU General Public License for more details.                                                  //
15
//                                                                                               //
16
// You should have received a copy of the GNU General Public License                             //
17
// along with Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
18
///////////////////////////////////////////////////////////////////////////////////////////////////
19

    
20
package org.distorted.objectlib.helpers;
21

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

    
35
import java.util.ArrayList;
36

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

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

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

    
47
  private static final float MAX_CORE_DIFF = 0.01f;
48

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

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

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

    
67
    int sticker;
68
    float vx,vy,vz;
69
    float scale;
70
    float qx,qy,qz,qw;
71
    boolean flip;
72
    }
73

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

    
78
///////////////////////////////////////////////////////////////////////////////////////////////////
79

    
80
  private FactoryCubit()
81
    {
82

    
83
    }
84

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

    
120
///////////////////////////////////////////////////////////////////////////////////////////////////
121

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

    
127
///////////////////////////////////////////////////////////////////////////////////////////////////
128

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

    
135
///////////////////////////////////////////////////////////////////////////////////////////////////
136

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

    
142
///////////////////////////////////////////////////////////////////////////////////////////////////
143

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

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

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

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

    
168
///////////////////////////////////////////////////////////////////////////////////////////////////
169

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

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

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

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

    
200
///////////////////////////////////////////////////////////////////////////////////////////////////
201
// return quat1*quat2
202

    
203
  private static void quatMultiply( float[] quat1, float[] quat2, float[] result )
204
    {
205
    float qx = quat1[0];
206
    float qy = quat1[1];
207
    float qz = quat1[2];
208
    float qw = quat1[3];
209

    
210
    float rx = quat2[0];
211
    float ry = quat2[1];
212
    float rz = quat2[2];
213
    float rw = quat2[3];
214

    
215
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
216
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
217
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
218
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
219
    }
220

    
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

    
223
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
224
    {
225
    float minX = Float.MAX_VALUE;
226
    float maxX =-Float.MAX_VALUE;
227
    float minY = Float.MAX_VALUE;
228
    float maxY =-Float.MAX_VALUE;
229

    
230
    for (float[] vert : vert3D)
231
      {
232
      float x = vert[0];
233
      float y = vert[1];
234

    
235
      if (x > maxX) maxX = x;
236
      if (x < minX) minX = x;
237
      if (y > maxY) maxY = y;
238
      if (y < minY) minY = y;
239
      }
240

    
241
    minX = minX<0 ? -minX:minX;
242
    maxX = maxX<0 ? -maxX:maxX;
243
    minY = minY<0 ? -minY:minY;
244
    maxY = maxY<0 ? -maxY:maxY;
245

    
246
    float max1 = Math.max(minX,minY);
247
    float max2 = Math.max(maxX,maxY);
248
    float max3 = Math.max(max1,max2);
249

    
250
    info.scale = max3/0.5f;
251

    
252
    int len = vert3D.length;
253
    StickerCoords sInfo = new StickerCoords();
254
    sInfo.outer = isOuter;
255
    sInfo.scale = info.scale;
256
    sInfo.vertices = new float[2*len];
257

    
258
    for( int vertex=0; vertex<len; vertex++ )
259
      {
260
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
261
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
262
      }
263

    
264
    mStickerCoords.add(sInfo);
265

    
266
    info.sticker = mStickerCoords.size() -1;
267
    info.flip = false;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
273
    {
274
    FaceTransform ft = new FaceTransform();
275
    ft.face = face;
276
    ft.numFaces = numFaces;
277

    
278
    // compute center of gravity
279
    ft.vx = 0.0f;
280
    ft.vy = 0.0f;
281
    ft.vz = 0.0f;
282
    int len = vert3D.length;
283

    
284
    for (float[] vert : vert3D)
285
      {
286
      ft.vx += vert[0];
287
      ft.vy += vert[1];
288
      ft.vz += vert[2];
289
      }
290

    
291
    ft.vx /= len;
292
    ft.vy /= len;
293
    ft.vz /= len;
294

    
295
    // move all vertices so that their center of gravity is at (0,0,0)
296
    for (int i=0; i<len; i++)
297
      {
298
      vert3D[i][0] -= ft.vx;
299
      vert3D[i][1] -= ft.vy;
300
      vert3D[i][2] -= ft.vz;
301
      }
302

    
303
    // find 3 non-colinear vertices
304
    int foundIndex = -1;
305

    
306
    for(int vertex=2; vertex<len; vertex++)
307
      {
308
      if( !areColinear(vert3D,0,1,vertex) )
309
        {
310
        foundIndex = vertex;
311
        break;
312
        }
313
      }
314

    
315
    // compute the normal vector
316
    if( foundIndex==-1 )
317
      {
318
      throw new RuntimeException("all vertices colinear");
319
      }
320

    
321
    computeNormalVector(vert3D,0,1,foundIndex);
322

    
323
    // rotate so that the normal vector becomes (0,0,1)
324
    float axisX, axisY, axisZ;
325

    
326
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
327
      {
328
      axisX = -mBuffer[1];
329
      axisY =  mBuffer[0];
330
      axisZ = 0.0f;
331

    
332
      float axiLen = axisX*axisX + axisY*axisY;
333
      axiLen = (float)Math.sqrt(axiLen);
334
      axisX /= axiLen;
335
      axisY /= axiLen;
336
      axisZ /= axiLen;
337
      }
338
    else
339
      {
340
      axisX = 0.0f;
341
      axisY = 1.0f;
342
      axisZ = 0.0f;
343
      }
344

    
345
    float cosTheta = mBuffer[2];
346
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
347
    float sinHalfTheta = computeSinHalf(cosTheta);
348
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
349

    
350
    mQuat1[0] = axisX*sinHalfTheta;
351
    mQuat1[1] = axisY*sinHalfTheta;
352
    mQuat1[2] = axisZ*sinHalfTheta;
353
    mQuat1[3] = cosHalfTheta;
354
    mQuat2[0] =-axisX*sinHalfTheta;
355
    mQuat2[1] =-axisY*sinHalfTheta;
356
    mQuat2[2] =-axisZ*sinHalfTheta;
357
    mQuat2[3] = cosHalfTheta;
358

    
359
    for (float[] vert : vert3D)
360
      {
361
      quatMultiply(mQuat1, vert  , mQuat3);
362
      quatMultiply(mQuat3, mQuat2, vert  );
363
      }
364

    
365
    // fit the whole thing in a square and remember the scale & 2D vertices
366
    fitInSquare(ft, vert3D, isOuter);
367

    
368
    // remember the rotation
369
    ft.qx =-mQuat1[0];
370
    ft.qy =-mQuat1[1];
371
    ft.qz =-mQuat1[2];
372
    ft.qw = mQuat1[3];
373

    
374
    return ft;
375
    }
376

    
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
  private void rotateAllVertices(float[] result, int len, float[] vertices, float sin, float cos)
380
    {
381
    for(int i=0; i<len; i++)
382
      {
383
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
384
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
385
      }
386
    }
387

    
388
///////////////////////////////////////////////////////////////////////////////////////////////////
389

    
390
  private float computeScale(float[] v1, float[] v2, int v1i, int v2i)
391
    {
392
    float v1x = v1[2*v1i];
393
    float v1y = v1[2*v1i+1];
394
    float v2x = v2[2*v2i];
395
    float v2y = v2[2*v2i+1];
396

    
397
    float lenSq1 = v1x*v1x + v1y*v1y;
398
    float lenSq2 = v2x*v2x + v2y*v2y;
399

    
400
    return (float)Math.sqrt(lenSq2/lenSq1);
401
    }
402

    
403
///////////////////////////////////////////////////////////////////////////////////////////////////
404
// valid for 0<angle<2*PI
405

    
406
  private float computeSinHalf(float cos)
407
    {
408
    return (float)Math.sqrt((1-cos)/2);
409
    }
410

    
411
///////////////////////////////////////////////////////////////////////////////////////////////////
412
// valid for 0<angle<2*PI
413

    
414
  private float computeCosHalf(float sin, float cos)
415
    {
416
    float cosHalf = (float)Math.sqrt((1+cos)/2);
417
    return sin<0 ? -cosHalf : cosHalf;
418
    }
419

    
420
///////////////////////////////////////////////////////////////////////////////////////////////////
421

    
422
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
423
    {
424
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
425
    if( v>=len ) v-=len;
426
    if( v< 0   ) v+=len;
427

    
428
    return v;
429
    }
430

    
431
///////////////////////////////////////////////////////////////////////////////////////////////////
432

    
433
  private boolean isScaledVersionOf(float[] newVert, float[] oldVert, int len, int vertex, boolean inverted)
434
    {
435
    int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
436
    float EPSILON = 0.001f;
437
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
438

    
439
    for(int i=1; i<len; i++)
440
      {
441
      int index = computeRotatedIndex(i,len,vertex,inverted);
442

    
443
      float horz = oldVert[2*i  ] - scale*newVert[2*index  ];
444
      float vert = oldVert[2*i+1] - scale*newVert[2*index+1];
445

    
446
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
447
      }
448

    
449
    return true;
450
    }
451

    
452
///////////////////////////////////////////////////////////////////////////////////////////////////
453

    
454
  private void mirrorAllVertices(float[] output, int len, float[] input)
455
    {
456
    for(int vertex=0; vertex<len; vertex++)
457
      {
458
      output[2*vertex  ] = input[2*vertex  ];
459
      output[2*vertex+1] =-input[2*vertex+1];
460
      }
461
    }
462

    
463
///////////////////////////////////////////////////////////////////////////////////////////////////
464

    
465
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker, boolean flip)
466
    {
467
    mStickerCoords.remove(info.sticker);
468

    
469
    info.flip    = flip;
470
    info.sticker = oldSticker;
471
    info.scale  *= scale;
472

    
473
    mQuat1[0] = info.qx;
474
    mQuat1[1] = info.qy;
475
    mQuat1[2] = info.qz;
476
    mQuat1[3] = info.qw;
477

    
478
    float sinHalf = computeSinHalf(cos);
479
    float cosHalf = computeCosHalf(sin,cos);
480

    
481
    if( flip )
482
      {
483
      mQuat3[0] = 0.0f;
484
      mQuat3[1] = 0.0f;
485
      mQuat3[2] = sinHalf;
486
      mQuat3[3] = cosHalf;
487

    
488
      mQuat4[0] = 1.0f;
489
      mQuat4[1] = 0.0f;
490
      mQuat4[2] = 0.0f;
491
      mQuat4[3] = 0.0f;
492

    
493
      quatMultiply( mQuat3, mQuat4, mQuat2 );
494
      }
495
    else
496
      {
497
      mQuat2[0] = 0.0f;
498
      mQuat2[1] = 0.0f;
499
      mQuat2[2] = sinHalf;
500
      mQuat2[3] = cosHalf;
501
      }
502

    
503
    quatMultiply( mQuat1, mQuat2, mQuat3 );
504

    
505
    info.qx = mQuat3[0];
506
    info.qy = mQuat3[1];
507
    info.qz = mQuat3[2];
508
    info.qw = mQuat3[3];
509
    }
510

    
511
///////////////////////////////////////////////////////////////////////////////////////////////////
512

    
513
  private void printVert(double[] buffer)
514
    {
515
    int len = buffer.length/2;
516
    String str = "";
517

    
518
    for(int i=0; i<len; i++)
519
      {
520
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
521
      }
522

    
523
    android.util.Log.d("D", str);
524
    }
525

    
526
///////////////////////////////////////////////////////////////////////////////////////////////////
527

    
528
  private boolean foundVertex(FaceTransform info, float[] buffer, int len, float[] newVert,
529
                              float[] oldVert, float lenFirstOld, int oldSticker, boolean inverted)
530
    {
531
    for(int vertex=0; vertex<len; vertex++)
532
      {
533
      float newX = newVert[2*vertex  ];
534
      float newY = newVert[2*vertex+1];
535
      float lenIthNew = (float)Math.sqrt(newX*newX + newY*newY);
536
      float cos = (float)QuatHelper.computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
537
      float sin = (float)QuatHelper.computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
538

    
539
      rotateAllVertices(buffer,len,newVert,sin,cos);
540

    
541
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
542
        {
543
        int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
544
        float scale = computeScale(oldVert,newVert,0,newZeroIndex);
545
        correctInfo(info,scale,sin,cos,oldSticker,inverted);
546
        return true;
547
        }
548
      }
549

    
550
    return false;
551
    }
552

    
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554

    
555
  private float computeCoreDistance(float[] verts)
556
    {
557
    float ret = 0.0f;
558
    float centerX=0.0f,centerY=0.0f;
559
    int len = verts.length/2;
560

    
561
    for(int i=0; i<len; i++)
562
      {
563
      centerX += verts[2*i  ];
564
      centerY += verts[2*i+1];
565
      }
566

    
567
    centerX /= (2*len);
568
    centerY /= (2*len);
569

    
570
    for(int i=0; i<len; i++)
571
      {
572
      float distX = centerX-verts[2*i  ];
573
      float distY = centerY-verts[2*i+1];
574
      ret += (float)Math.sqrt(distX*distX + distY*distY);
575
      }
576

    
577
    return ret;
578
    }
579

    
580
///////////////////////////////////////////////////////////////////////////////////////////////////
581

    
582
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
583
    {
584
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
585
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
586

    
587
    float[] newVert = sNewInfo.vertices;
588
    float[] oldVert = sOldInfo.vertices;
589
    int oldLen = oldVert.length;
590
    int newLen = newVert.length;
591

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

    
599
      int oldSticker = oldInfo.sticker;
600
      float[] buffer1 = new float[oldLen];
601
      float lenFirstOld = (float)Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
602
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) )
603
        {
604
        if( sNewInfo.outer ) sOldInfo.outer = true;
605
        return true;
606
        }
607
      float[] buffer2 = new float[oldLen];
608
      mirrorAllVertices(buffer2, newLen/2, newVert);
609
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) )
610
        {
611
        if( sNewInfo.outer ) sOldInfo.outer = true;
612
        return true;
613
        }
614
      }
615

    
616
    return false;
617
    }
618

    
619
///////////////////////////////////////////////////////////////////////////////////////////////////
620

    
621
  private float[][] constructVert(float[][] vertices, int[] index)
622
    {
623
    int len = index.length;
624
    float[][] ret = new float[len][4];
625

    
626
    for(int i=0; i<len; i++)
627
      {
628
      ret[i][0] = vertices[index[i]][0];
629
      ret[i][1] = vertices[index[i]][1];
630
      ret[i][2] = vertices[index[i]][2];
631
      ret[i][3] = 1.0f;
632
      }
633

    
634
    return ret;
635
    }
636

    
637
///////////////////////////////////////////////////////////////////////////////////////////////////
638

    
639
  private void prepareAndRoundCorners(MeshBase mesh, float[][] vertices,
640
                                      float[][] corners, int[] cornerIndexes,
641
                                      float[][] centers, int[] centerIndexes )
642
    {
643
    int lenV = vertices.length;
644
    Static3D[] staticVert = new Static3D[1];
645
    Static3D center = new Static3D(0,0,0);
646

    
647
    for(int v=0; v<lenV; v++)
648
      {
649
      staticVert[0] = new Static3D( vertices[v][0],vertices[v][1],vertices[v][2] );
650

    
651
      int cent = centerIndexes[v];
652

    
653
      if( cent>=0 )
654
        {
655
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
656

    
657
        int corn = cornerIndexes[v];
658

    
659
        if( corn>=0 )
660
          {
661
          float strength = corners[corn][0];
662
          float radius   = corners[corn][1];
663
          roundCorners(mesh, center, staticVert, strength, radius);
664
          }
665
        }
666
      }
667
    }
668

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

    
671
  private void correctComponents(MeshBase mesh, int numComponents)
672
    {
673
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
674

    
675
    mesh.mergeEffComponents();
676

    
677
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
678
    }
679

    
680
///////////////////////////////////////////////////////////////////////////////////////////////////
681

    
682
  private void printTransform(FaceTransform f)
683
    {
684
    android.util.Log.e("D", "face="+f.face+" q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
685
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
686
    }
687

    
688
///////////////////////////////////////////////////////////////////////////////////////////////////
689

    
690
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
691
    {
692
    float[] bands = new float[2*N];
693

    
694
    bands[0] = 1.0f;
695
    bands[1] = 0.0f;
696

    
697
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
698
    float sinBeta = (float)Math.sin(beta);
699
    float cosBeta = (float)Math.cos(beta);
700
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
701
    float D = R*sinBeta;
702
    float B = h(R,sinBeta,K*beta);
703

    
704
    if( D>1.0f )
705
      {
706
      for(int i=1; i<N; i++)
707
        {
708
        bands[2*i  ] = (float)(N-1-i)/(N-1);
709
        bands[2*i+1] = H*(1-bands[2*i]);
710
        }
711
      }
712
    else
713
      {
714
      int K2 = (int)((N-3)*K);
715
      int K1 = (N-3)-K2;
716

    
717
      for(int i=0; i<=K1; i++)
718
        {
719
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
720
        float x = h(R,sinBeta,angle);
721
        bands[2*i+2] = 1.0f - x;
722
        bands[2*i+3] = g(R,D,x,cosBeta);
723
        }
724

    
725
      for(int i=0; i<=K2; i++)
726
        {
727
        float x = (1-B)*(i+1)/(K2+1) + B;
728
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
729
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
730
        }
731
      }
732

    
733
    bands[2*N-2] = 0.0f;
734
    bands[2*N-1] =    H;
735

    
736
    return bands;
737
    }
738

    
739
///////////////////////////////////////////////////////////////////////////////////////////////////
740

    
741
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
742
    {
743
    Static4D reg= new Static4D(0,0,0,regionRadius);
744

    
745
    float centX = center.get0();
746
    float centY = center.get1();
747
    float centZ = center.get2();
748

    
749
    for (Static3D vertex : vertices)
750
      {
751
      float x = strength*(centX - vertex.get0());
752
      float y = strength*(centY - vertex.get1());
753
      float z = strength*(centZ - vertex.get2());
754

    
755
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
756
      mesh.apply(effect);
757
      }
758
    }
759

    
760
///////////////////////////////////////////////////////////////////////////////////////////////////
761

    
762
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
763
    {
764
    if( in==null )
765
      {
766
      out[0] = out[1] = 0.0f;
767
      }
768
    else
769
      {
770
      out[0] = in[0] - ft.vx;
771
      out[1] = in[1] - ft.vy;
772
      out[2] = in[2] - ft.vz;
773
      out[3] = 1.0f;
774

    
775
      mQuat1[0] =-ft.qx;
776
      mQuat1[1] =-ft.qy;
777
      mQuat1[2] =-ft.qz;
778
      mQuat1[3] = ft.qw;
779

    
780
      mQuat2[0] = -mQuat1[0];
781
      mQuat2[1] = -mQuat1[1];
782
      mQuat2[2] = -mQuat1[2];
783
      mQuat2[3] = +mQuat1[3];
784

    
785
      quatMultiply(mQuat1, out  , mQuat3);
786
      quatMultiply(mQuat3, mQuat2, out  );
787

    
788
      out[0] /= ft.scale;
789
      out[1] /= ft.scale;
790
      out[2] /= ft.scale;
791
      }
792
    }
793

    
794
///////////////////////////////////////////////////////////////////////////////////////////////////
795

    
796
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
797
    {
798
    int len = table.length;
799

    
800
    for(int i=0; i<len; i++)
801
      {
802
      int lenInner = table[i].length;
803

    
804
      for(int j=0; j<lenInner; j++)
805
        if( table[i][j]==oldPointer ) table[i][j] = newPointer;
806
      }
807
    }
808

    
809
///////////////////////////////////////////////////////////////////////////////////////////////////
810
// INTERNAL API
811

    
812
  public int printStickerCoords()
813
    {
814
    int stickers = mStickerCoords.size();
815
    int ret = 0;
816

    
817
    android.util.Log.d("D", "---- STICKER COORDS ----");
818

    
819
    for(int s=0; s<stickers; s++)
820
      {
821
      StickerCoords info = mStickerCoords.get(s);
822

    
823
      if( info.outer )  ret++;
824

    
825
      String ver = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+" { ";
826
      int len = info.vertices.length/2;
827

    
828
      for(int i =0; i<len; i++)
829
        {
830
        if( i!=0 ) ver += ", ";
831
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
832
        }
833

    
834
      ver += " }";
835
      android.util.Log.d("D", ver);
836
      }
837

    
838
    android.util.Log.d("D", "---- END STICKER COORDS ----");
839

    
840
    return ret;
841
    }
842

    
843
///////////////////////////////////////////////////////////////////////////////////////////////////
844

    
845
  public void printFaceTransform()
846
    {
847
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
848

    
849
    int oldfaces = mOldFaceTransf.size();
850

    
851
    for(int f=0; f<oldfaces; f++)
852
      {
853
      printTransform(mOldFaceTransf.get(f));
854
      }
855

    
856
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
857

    
858
    int newfaces = mNewFaceTransf.size();
859

    
860
    for(int f=0; f<newfaces; f++)
861
      {
862
      printTransform(mNewFaceTransf.get(f));
863
      }
864
    }
865

    
866
///////////////////////////////////////////////////////////////////////////////////////////////////
867
// PUBLIC API
868

    
869
  public static FactoryCubit getInstance()
870
    {
871
    if( mThis==null ) mThis = new FactoryCubit();
872

    
873
    return mThis;
874
    }
875

    
876
///////////////////////////////////////////////////////////////////////////////////////////////////
877

    
878
  public float[] getOuterStickerScales()
879
    {
880
    int index=0,num=0,len = mStickerCoords.size();
881

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

    
884
    if( num>0 )
885
      {
886
      float[] scales = new float[num];
887

    
888
      for(int i=0; i<len; i++)
889
        {
890
        StickerCoords sticker = mStickerCoords.get(i);
891
        if( sticker.outer ) scales[index++] = sticker.scale;
892
        }
893

    
894
      return scales;
895
      }
896

    
897
    return null;
898
    }
899

    
900
///////////////////////////////////////////////////////////////////////////////////////////////////
901

    
902
  public float[][] getOuterStickerCoords()
903
    {
904
    int index=0,num=0,len = mStickerCoords.size();
905

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

    
908
    if( num>0 )
909
      {
910
      float[][] coords = new float[num][];
911

    
912
      for(int i=0; i<len; i++)
913
        {
914
        StickerCoords sticker = mStickerCoords.get(i);
915
        if( sticker.outer ) coords[index++] = sticker.vertices;
916
        }
917

    
918
      return coords;
919
      }
920

    
921
    return null;
922
    }
923

    
924
///////////////////////////////////////////////////////////////////////////////////////////////////
925

    
926
  public int[][] getStickerVariants()
927
    {
928
    int numvariants = 1; // there's one in the 'new' array
929

    
930
    int oldfaces = mOldFaceTransf.size();
931

    
932
    for(int f=0; f<oldfaces; f++)
933
      {
934
      FaceTransform ft = mOldFaceTransf.get(f);
935
      if( ft.face==0 ) numvariants++;
936
      }
937

    
938
    int[][] ret = new int[numvariants][];
939
    int inner=0, index=-1;
940

    
941
    for(int f=0; f<oldfaces; f++)
942
      {
943
      FaceTransform ft = mOldFaceTransf.get(f);
944
      if( ft.face==0 )
945
        {
946
        index++;
947
        inner=0;
948
        ret[index] = new int[ft.numFaces];
949
        }
950

    
951
      ret[index][inner++] = ft.sticker;
952
      }
953

    
954
    int newfaces = mNewFaceTransf.size();
955

    
956
    for(int f=0; f<newfaces; f++)
957
      {
958
      FaceTransform ft = mNewFaceTransf.get(f);
959
      if( ft.face==0 )
960
        {
961
        index++;
962
        inner=0;
963
        ret[index] = new int[ft.numFaces];
964
        }
965

    
966
      ret[index][inner++] = ft.sticker;
967
      }
968

    
969
    int numStickers = mStickerCoords.size();
970
    int numOuter=0;
971

    
972
    for(int i=0; i<numStickers; i++)
973
      {
974
      StickerCoords sc = mStickerCoords.get(i);
975
      if( sc.outer )
976
        {
977
        changeStickerPointers(ret,i,numOuter);
978
        numOuter++;
979
        }
980
      else
981
        {
982
        changeStickerPointers(ret,i,-1);
983
        }
984
      }
985

    
986
    return ret;
987
    }
988

    
989
///////////////////////////////////////////////////////////////////////////////////////////////////
990

    
991
  public void clear()
992
    {
993
    mStickerCoords.clear();
994
    mNewFaceTransf.clear();
995
    mOldFaceTransf.clear();
996
    }
997

    
998
///////////////////////////////////////////////////////////////////////////////////////////////////
999

    
1000
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1001
    {
1002
    float[][] vertices = shape.getVertices();
1003
    int[][] indices = shape.getVertIndices();
1004
    FaceTransform ft;
1005
    int numNew = mNewFaceTransf.size();
1006

    
1007
    for(int i=0; i<numNew; i++)
1008
      {
1009
      ft = mNewFaceTransf.remove(0);
1010
      mOldFaceTransf.add(ft);
1011
      }
1012

    
1013
    int numFaces = indices.length;
1014
    int numOld = mOldFaceTransf.size();
1015

    
1016
    for (int face=0; face<numFaces; face++)
1017
      {
1018
      boolean collapsed = false;
1019
      boolean isOuter = (outer!=null && outer[face]>0);
1020

    
1021
      float[][] vert = constructVert(vertices, indices[face]);
1022
      FaceTransform newT = constructNewTransform(vert,isOuter,face,numFaces);
1023

    
1024
      for (int old=0; !collapsed && old<numOld; old++)
1025
        {
1026
        ft = mOldFaceTransf.get(old);
1027
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1028
        }
1029

    
1030
      for (int pre=0; !collapsed && pre<face; pre++)
1031
        {
1032
        ft = mNewFaceTransf.get(pre);
1033
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1034
        }
1035

    
1036
      mNewFaceTransf.add(newT);
1037
      }
1038
    }
1039

    
1040
///////////////////////////////////////////////////////////////////////////////////////////////////
1041

    
1042
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape, int meshState, int numComponents)
1043
    {
1044
    float[][] vertices      = shape.getVertices();
1045
    int[][] vertIndexes     = shape.getVertIndices();
1046
    float[][] bands         = faceShape.getBands();
1047
    int[]   bandIndexes     = faceShape.getBandIndices();
1048
    float[][] corners       = faceShape.getCorners();
1049
    int[]   cornerIndexes   = faceShape.getCornerIndices();
1050
    float[][] centers       = faceShape.getCenters();
1051
    int[]   centerIndexes   = faceShape.getCenterIndices();
1052
    float[] convexityCenter = faceShape.getConvexityCenter();
1053

    
1054
    int numFaces = vertIndexes.length;
1055
    float[] band, bandsComputed;
1056
    MeshBase[] meshes = new MeshBase[numFaces];
1057
    FaceTransform fInfo;
1058
    StickerCoords sInfo;
1059
    float[] convexXY = new float[4];
1060
    int exIndex=0, exVertices=0, alpha=0, N=0;
1061
    float height=0.0f, dist=0.0f, K=0.0f;
1062

    
1063
    for(int face=0; face<numFaces; face++)
1064
      {
1065
      fInfo = mNewFaceTransf.get(face);
1066
      sInfo = mStickerCoords.get(fInfo.sticker);
1067

    
1068
      float[] verts = sInfo.vertices;
1069
      int lenVerts = verts.length;
1070
      float[] copiedVerts = new float[lenVerts];
1071
      System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
1072

    
1073
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1074

    
1075
      band = bands[bandIndexes[face]];
1076

    
1077
android.util.Log.e("D", "indices="+bandIndexes[face]+" band[4]="+band[4]+" meshState="+meshState+" face="+face);
1078

    
1079
      switch(meshState)
1080
        {
1081
        case MESH_NICE: height     = band[0];
1082
                        alpha      = (int)band[1];
1083
                        dist       = band[2];
1084
                        K          = band[3];
1085
                        N          = (int)band[4];
1086
                        exIndex    = (int)band[5];
1087
                        exVertices = (int)band[6];
1088
                        break;
1089
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
1090
                                                               // (example: Ivy cube center and edge cubits!)
1091
                        alpha      = 0;
1092
                        dist       = 0;
1093
                        K          = 0;
1094
                        N          = 2;
1095
                        exIndex    = 0;
1096
                        exVertices = 0;
1097
                        break;
1098
        }
1099

    
1100
      bandsComputed = computeBands(height,alpha,dist,K,N);
1101
      meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1102
      meshes[face].setEffectAssociation(0,(1<<face),0);
1103
      }
1104

    
1105
    MeshBase mesh = new MeshJoined(meshes);
1106
    Static3D center = new Static3D(0,0,0);
1107

    
1108
    for(int face=0; face<numFaces; face++)
1109
      {
1110
      int assoc = (1<<face);
1111
      fInfo = mNewFaceTransf.get(face);
1112

    
1113
      float vx = fInfo.vx;
1114
      float vy = fInfo.vy;
1115
      float vz = fInfo.vz;
1116
      float sc = fInfo.scale;
1117
      float qx = fInfo.qx;
1118
      float qy = fInfo.qy;
1119
      float qz = fInfo.qz;
1120
      float qw = fInfo.qw;
1121

    
1122
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
1123
      Static3D move3D= new Static3D(vx,vy,vz);
1124
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1125

    
1126
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
1127
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
1128
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
1129
      }
1130

    
1131
    if( meshState==MESH_NICE )
1132
      {
1133
      prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
1134
      }
1135

    
1136
    correctComponents(mesh,numComponents);
1137

    
1138
    return mesh;
1139
    }
1140
  }
(2-2/12)