Project

General

Profile

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

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

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
  private static class StickerCoords
56
    {
57
    float[] vertices;
58
    boolean outer;
59
    }
60

    
61
  private static class FaceTransform
62
    {
63
    int sticker;
64
    float vx,vy,vz;
65
    float scale;
66
    float qx,qy,qz,qw;
67
    boolean flip;
68
    }
69

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

    
74
///////////////////////////////////////////////////////////////////////////////////////////////////
75

    
76
  private FactoryCubit()
77
    {
78

    
79
    }
80

    
81
///////////////////////////////////////////////////////////////////////////////////////////////////
82

    
83
  public static FactoryCubit getInstance()
84
    {
85
    if( mThis==null ) mThis = new FactoryCubit();
86

    
87
    return mThis;
88
    }
89

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

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

    
127
  private float f(float D, float B, float x)
128
    {
129
    return ((D-B)*x + B*(1-D))/(1-B);
130
    }
131

    
132
///////////////////////////////////////////////////////////////////////////////////////////////////
133

    
134
  private float g(float R, float D, float x, float cosAlpha)
135
    {
136
    float d = x-D;
137
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
138
    }
139

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

    
142
  private float h(float R, float sinAlpha, float x)
143
    {
144
    return R*(sinAlpha-(float)Math.sin(x));
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
  private boolean areColinear(float[][] vertices, int index1, int index2, int index3)
150
    {
151
    float x1 = vertices[index1][0];
152
    float y1 = vertices[index1][1];
153
    float z1 = vertices[index1][2];
154
    float x2 = vertices[index2][0];
155
    float y2 = vertices[index2][1];
156
    float z2 = vertices[index2][2];
157
    float x3 = vertices[index3][0];
158
    float y3 = vertices[index3][1];
159
    float z3 = vertices[index3][2];
160

    
161
    float v1x = x2-x1;
162
    float v1y = y2-y1;
163
    float v1z = z2-z1;
164
    float v2x = x3-x1;
165
    float v2y = y3-y1;
166
    float v2z = z3-z1;
167

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

    
170
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
171
    }
172

    
173
///////////////////////////////////////////////////////////////////////////////////////////////////
174

    
175
  private void computeNormalVector(float[][] vertices, int index1, int index2, int index3)
176
    {
177
    float x1 = vertices[index1][0];
178
    float y1 = vertices[index1][1];
179
    float z1 = vertices[index1][2];
180
    float x2 = vertices[index2][0];
181
    float y2 = vertices[index2][1];
182
    float z2 = vertices[index2][2];
183
    float x3 = vertices[index3][0];
184
    float y3 = vertices[index3][1];
185
    float z3 = vertices[index3][2];
186

    
187
    float v1x = x2-x1;
188
    float v1y = y2-y1;
189
    float v1z = z2-z1;
190
    float v2x = x3-x1;
191
    float v2y = y3-y1;
192
    float v2z = z3-z1;
193

    
194
    mBuffer[0] = v1y*v2z - v2y*v1z;
195
    mBuffer[1] = v1z*v2x - v2z*v1x;
196
    mBuffer[2] = v1x*v2y - v2x*v1y;
197

    
198
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
199
    len = Math.sqrt(len);
200
    mBuffer[0] /= len;
201
    mBuffer[1] /= len;
202
    mBuffer[2] /= len;
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206
// return quat1*quat2
207

    
208
  private static void quatMultiply( float[] quat1, float[] quat2, float[] result )
209
    {
210
    float qx = quat1[0];
211
    float qy = quat1[1];
212
    float qz = quat1[2];
213
    float qw = quat1[3];
214

    
215
    float rx = quat2[0];
216
    float ry = quat2[1];
217
    float rz = quat2[2];
218
    float rw = quat2[3];
219

    
220
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
221
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
222
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
223
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
224
    }
225

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

    
228
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
229
    {
230
    float minX = Float.MAX_VALUE;
231
    float maxX =-Float.MAX_VALUE;
232
    float minY = Float.MAX_VALUE;
233
    float maxY =-Float.MAX_VALUE;
234

    
235
    for (float[] vert : vert3D)
236
      {
237
      float x = vert[0];
238
      float y = vert[1];
239

    
240
      if (x > maxX) maxX = x;
241
      if (x < minX) minX = x;
242
      if (y > maxY) maxY = y;
243
      if (y < minY) minY = y;
244
      }
245

    
246
    minX = minX<0 ? -minX:minX;
247
    maxX = maxX<0 ? -maxX:maxX;
248
    minY = minY<0 ? -minY:minY;
249
    maxY = maxY<0 ? -maxY:maxY;
250

    
251
    float max1 = Math.max(minX,minY);
252
    float max2 = Math.max(maxX,maxY);
253
    float max3 = Math.max(max1,max2);
254

    
255
    info.scale = max3/0.5f;
256

    
257
    int len = vert3D.length;
258
    StickerCoords sInfo = new StickerCoords();
259
    sInfo.outer = isOuter;
260
    sInfo.vertices = new float[2*len];
261

    
262
    for( int vertex=0; vertex<len; vertex++ )
263
      {
264
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
265
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
266
      }
267

    
268
    mStickerCoords.add(sInfo);
269

    
270
    info.sticker = mStickerCoords.size() -1;
271
    info.flip = false;
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter)
277
    {
278
    FaceTransform ft = new FaceTransform();
279

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

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

    
293
    ft.vx /= len;
294
    ft.vy /= len;
295
    ft.vz /= len;
296

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

    
305
    // find 3 non-colinear vertices
306
    int foundIndex = -1;
307

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

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

    
323
    computeNormalVector(vert3D,0,1,foundIndex);
324

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

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

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

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

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

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

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

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

    
376
    return ft;
377
    }
378

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380

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

    
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391

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

    
399
    float lenSq1 = v1x*v1x + v1y*v1y;
400
    float lenSq2 = v2x*v2x + v2y*v2y;
401

    
402
    return (float)Math.sqrt(lenSq2/lenSq1);
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// valid for 0<angle<2*PI
407

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

    
413
///////////////////////////////////////////////////////////////////////////////////////////////////
414
// valid for 0<angle<2*PI
415

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

    
422
///////////////////////////////////////////////////////////////////////////////////////////////////
423

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

    
430
    return v;
431
    }
432

    
433
///////////////////////////////////////////////////////////////////////////////////////////////////
434

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

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

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

    
448
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
449
      }
450

    
451
    return true;
452
    }
453

    
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455

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

    
465
///////////////////////////////////////////////////////////////////////////////////////////////////
466

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

    
471
    info.flip    = flip;
472
    info.sticker = oldSticker;
473
    info.scale  *= scale;
474

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

    
480
    float sinHalf = computeSinHalf(cos);
481
    float cosHalf = computeCosHalf(sin,cos);
482

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

    
490
      mQuat4[0] = 1.0f;
491
      mQuat4[1] = 0.0f;
492
      mQuat4[2] = 0.0f;
493
      mQuat4[3] = 0.0f;
494

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

    
505
    quatMultiply( mQuat1, mQuat2, mQuat3 );
506

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

    
513
///////////////////////////////////////////////////////////////////////////////////////////////////
514

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

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

    
525
    android.util.Log.d("D", str);
526
    }
527

    
528
///////////////////////////////////////////////////////////////////////////////////////////////////
529

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

    
541
      rotateAllVertices(buffer,len,newVert,sin,cos);
542

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

    
552
    return false;
553
    }
554

    
555
///////////////////////////////////////////////////////////////////////////////////////////////////
556

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

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

    
569
    centerX /= (2*len);
570
    centerY /= (2*len);
571

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

    
579
    return ret;
580
    }
581

    
582
///////////////////////////////////////////////////////////////////////////////////////////////////
583

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

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

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

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

    
618
    return false;
619
    }
620

    
621
///////////////////////////////////////////////////////////////////////////////////////////////////
622

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

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

    
636
    return ret;
637
    }
638

    
639
///////////////////////////////////////////////////////////////////////////////////////////////////
640

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

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

    
653
      int cent = centerIndexes[v];
654

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

    
659
        int corn = cornerIndexes[v];
660

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

    
671
///////////////////////////////////////////////////////////////////////////////////////////////////
672

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

    
677
    mesh.mergeEffComponents();
678

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

    
682
///////////////////////////////////////////////////////////////////////////////////////////////////
683

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

    
690
///////////////////////////////////////////////////////////////////////////////////////////////////
691
// PUBLIC
692

    
693
  public float[] computeBands(float H, int alpha, float dist, float K, int N)
694
    {
695
    float[] bands = new float[2*N];
696

    
697
    bands[0] = 1.0f;
698
    bands[1] = 0.0f;
699

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

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

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

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

    
736
    bands[2*N-2] = 0.0f;
737
    bands[2*N-1] =    H;
738

    
739
    return bands;
740
    }
741

    
742
///////////////////////////////////////////////////////////////////////////////////////////////////
743

    
744
  public void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
745
    {
746
    Static4D reg= new Static4D(0,0,0,regionRadius);
747

    
748
    float centX = center.get0();
749
    float centY = center.get1();
750
    float centZ = center.get2();
751

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

    
758
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
759
      mesh.apply(effect);
760
      }
761
    }
762

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

    
765
  public int printStickerCoords()
766
    {
767
    int stickers = mStickerCoords.size();
768
    int ret = 0;
769

    
770
    android.util.Log.d("D", "---- STICKER COORDS ----");
771

    
772
    for(int s=0; s<stickers; s++)
773
      {
774
      StickerCoords info = mStickerCoords.get(s);
775

    
776
      if( info.outer )  ret++;
777

    
778
      String ver = info.outer+" { ";
779
      int len = info.vertices.length/2;
780

    
781
      for(int i =0; i<len; i++)
782
        {
783
        if( i!=0 ) ver += ", ";
784
        ver += ( info.vertices[2*i]+"f, "+info.vertices[2*i+1]+"f");
785
        }
786

    
787
      ver += " }";
788
      android.util.Log.d("D", ver);
789
      }
790

    
791
    android.util.Log.d("D", "---- END STICKER COORDS ----");
792

    
793
    return ret;
794
    }
795

    
796
///////////////////////////////////////////////////////////////////////////////////////////////////
797

    
798
  public void printFaceTransform()
799
    {
800
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
801

    
802
    int oldfaces = mOldFaceTransf.size();
803

    
804
    for(int f=0; f<oldfaces; f++)
805
      {
806
      printTransform(mOldFaceTransf.get(f));
807
      }
808

    
809
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
810

    
811
    int newfaces = mNewFaceTransf.size();
812

    
813
    for(int f=0; f<newfaces; f++)
814
      {
815
      printTransform(mNewFaceTransf.get(f));
816
      }
817
    }
818

    
819
///////////////////////////////////////////////////////////////////////////////////////////////////
820

    
821
  public void clear()
822
    {
823
    mStickerCoords.clear();
824
    mNewFaceTransf.clear();
825
    mOldFaceTransf.clear();
826
    }
827

    
828
///////////////////////////////////////////////////////////////////////////////////////////////////
829

    
830
  public void createNewFaceTransform( final float[][] vertices, final int[][] indexes, int outer)
831
    {
832
    FaceTransform ft;
833
    int numNew = mNewFaceTransf.size();
834

    
835
    for(int i=0; i<numNew; i++)
836
      {
837
      ft = mNewFaceTransf.remove(0);
838
      mOldFaceTransf.add(ft);
839
      }
840

    
841
    int numFaces = indexes.length;
842
    int numOld = mOldFaceTransf.size();
843

    
844
    for (int face=0; face<numFaces; face++)
845
      {
846
      boolean collapsed = false;
847
      boolean isOuter = face<outer;
848

    
849
      float[][] vert = constructVert(vertices, indexes[face]);
850
      FaceTransform newT = constructNewTransform(vert,isOuter);
851

    
852
      for (int old=0; !collapsed && old<numOld; old++)
853
        {
854
        ft = mOldFaceTransf.get(old);
855
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
856
        }
857

    
858
      for (int pre=0; !collapsed && pre<face; pre++)
859
        {
860
        ft = mNewFaceTransf.get(pre);
861
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
862
        }
863

    
864
      mNewFaceTransf.add(newT);
865
      }
866
    }
867

    
868

    
869
///////////////////////////////////////////////////////////////////////////////////////////////////
870

    
871
  public void createNewFaceTransform(final ObjectShape shape)
872
    {
873
    float[][] vertices = shape.getVertices();
874
    int[][] indices = shape.getVertIndices();
875
    int outer = shape.getNumOutside();
876
    createNewFaceTransform(vertices,indices,outer);
877
    }
878

    
879
///////////////////////////////////////////////////////////////////////////////////////////////////
880

    
881
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
882
    {
883
    if( in==null )
884
      {
885
      out[0] = out[1] = 0.0f;
886
      }
887
    else
888
      {
889
      out[0] = in[0] - ft.vx;
890
      out[1] = in[1] - ft.vy;
891
      out[2] = in[2] - ft.vz;
892
      out[3] = 1.0f;
893

    
894
      mQuat1[0] =-ft.qx;
895
      mQuat1[1] =-ft.qy;
896
      mQuat1[2] =-ft.qz;
897
      mQuat1[3] = ft.qw;
898

    
899
      mQuat2[0] = -mQuat1[0];
900
      mQuat2[1] = -mQuat1[1];
901
      mQuat2[2] = -mQuat1[2];
902
      mQuat2[3] = +mQuat1[3];
903

    
904
      quatMultiply(mQuat1, out  , mQuat3);
905
      quatMultiply(mQuat3, mQuat2, out  );
906

    
907
      out[0] /= ft.scale;
908
      out[1] /= ft.scale;
909
      out[2] /= ft.scale;
910
      }
911
    }
912

    
913
///////////////////////////////////////////////////////////////////////////////////////////////////
914

    
915
  public MeshBase createRoundedSolid(final ObjectShape shape, int meshState)
916
    {
917
    float[][] vertices      = shape.getVertices();
918
    int[][] vertIndexes     = shape.getVertIndices();
919
    float[][] bands         = shape.getBands();
920
    int[]   bandIndexes     = shape.getBandIndices();
921
    float[][] corners       = shape.getCorners();
922
    int[]   cornerIndexes   = shape.getCornerIndices();
923
    float[][] centers       = shape.getCenters();
924
    int[]   centerIndexes   = shape.getCenterIndices();
925
    int numComponents       = shape.getNumComponents();
926
    float[] convexityCenter = shape.getConvexityCenter();
927

    
928
    return createRoundedSolid(vertices,vertIndexes,bands,bandIndexes,corners,cornerIndexes,
929
                              centers,centerIndexes,numComponents,convexityCenter, meshState);
930
    }
931

    
932
///////////////////////////////////////////////////////////////////////////////////////////////////
933

    
934
  public MeshBase createRoundedSolid(final float[][] vertices, final int[][] vertIndexes,
935
                                     final float[][] bands   , final int[]   bandIndexes,
936
                                     final float[][] corners , final int[]   cornerIndexes,
937
                                     final float[][] centers , final int[]   centerIndexes,
938
                                     final int numComponents , final float[] convexityCenter,
939
                                     final int meshState  )
940
    {
941
    int numFaces = vertIndexes.length;
942
    float[] band, bandsComputed;
943
    MeshBase[] meshes = new MeshBase[numFaces];
944
    FaceTransform fInfo;
945
    StickerCoords sInfo;
946
    float[] convexXY = new float[4];
947
    int exIndex=0, exVertices=0, alpha=0, N=0;
948
    float height=0.0f, dist=0.0f, K=0.0f;
949

    
950
    for(int face=0; face<numFaces; face++)
951
      {
952
      fInfo = mNewFaceTransf.get(face);
953
      sInfo = mStickerCoords.get(fInfo.sticker);
954

    
955
      float[] verts = sInfo.vertices;
956
      int lenVerts = verts.length;
957
      float[] copiedVerts = new float[lenVerts];
958
      System.arraycopy(verts, 0, copiedVerts, 0, lenVerts);
959

    
960
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
961

    
962
      band = bands[bandIndexes[face]];
963

    
964
      switch(meshState)
965
        {
966
        case MESH_NICE: height     = band[0];
967
                        alpha      = (int)band[1];
968
                        dist       = band[2];
969
                        K          = band[3];
970
                        N          = (int)band[4];
971
                        exIndex    = (int)band[5];
972
                        exVertices = (int)band[6];
973
                        break;
974
        case MESH_FAST: height     = band[0]<0 ? band[0] : 0;  // the negative heights are of the internal walls, leave that
975
                                                               // (example: Ivy cube center and edge cubits!)
976
                        alpha      = 0;
977
                        dist       = 0;
978
                        K          = 0;
979
                        N          = 2;
980
                        exIndex    = 0;
981
                        exVertices = 0;
982
                        break;
983
        }
984

    
985
      bandsComputed = computeBands(height,alpha,dist,K,N);
986
      meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
987
      meshes[face].setEffectAssociation(0,(1<<face),0);
988
      }
989

    
990
    MeshBase mesh = new MeshJoined(meshes);
991
    Static3D center = new Static3D(0,0,0);
992

    
993
    for(int face=0; face<numFaces; face++)
994
      {
995
      int assoc = (1<<face);
996
      fInfo = mNewFaceTransf.get(face);
997

    
998
      float vx = fInfo.vx;
999
      float vy = fInfo.vy;
1000
      float vz = fInfo.vz;
1001
      float sc = fInfo.scale;
1002
      float qx = fInfo.qx;
1003
      float qy = fInfo.qy;
1004
      float qz = fInfo.qz;
1005
      float qw = fInfo.qw;
1006

    
1007
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
1008
      Static3D move3D= new Static3D(vx,vy,vz);
1009
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1010

    
1011
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
1012
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
1013
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
1014
      }
1015

    
1016
    if( meshState==MESH_NICE )
1017
      {
1018
      prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
1019
      }
1020

    
1021
    correctComponents(mesh,numComponents);
1022

    
1023
    return mesh;
1024
    }
1025
  }
(2-2/10)