Project

General

Profile

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

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

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
///////////////////////////////////////////////////////////////////////////////////////////////////
38

    
39
public class FactoryCubit
40
  {
41
  private static final Static1D RADIUS = new Static1D(1);
42
  private static FactoryCubit mThis;
43

    
44
  private static final double[] mBuffer = new double[3];
45
  private static final double[] mQuat1  = new double[4];
46
  private static final double[] mQuat2  = new double[4];
47
  private static final double[] mQuat3  = new double[4];
48
  private static final double[] mQuat4  = new double[4];
49

    
50
  private static class StickerCoords
51
    {
52
    double[] vertices;
53
    }
54

    
55
  private static class FaceTransform
56
    {
57
    int sticker;
58
    double vx,vy,vz;
59
    double scale;
60
    double qx,qy,qz,qw;
61
    boolean flip;
62
    }
63

    
64
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
65
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
66
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
67

    
68
///////////////////////////////////////////////////////////////////////////////////////////////////
69

    
70
  private FactoryCubit()
71
    {
72

    
73
    }
74

    
75
///////////////////////////////////////////////////////////////////////////////////////////////////
76

    
77
  public static FactoryCubit getInstance()
78
    {
79
    if( mThis==null ) mThis = new FactoryCubit();
80

    
81
    return mThis;
82
    }
83

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

    
119
///////////////////////////////////////////////////////////////////////////////////////////////////
120

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

    
126
///////////////////////////////////////////////////////////////////////////////////////////////////
127

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

    
134
///////////////////////////////////////////////////////////////////////////////////////////////////
135

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

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142

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

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

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

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

    
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168

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

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

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

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

    
199
///////////////////////////////////////////////////////////////////////////////////////////////////
200
// return quat1*quat2
201

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

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

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

    
220
///////////////////////////////////////////////////////////////////////////////////////////////////
221

    
222
  private void fitInSquare(FaceTransform info, double[][] vert3D)
223
    {
224
    double minX = Double.MAX_VALUE;
225
    double maxX =-Double.MAX_VALUE;
226
    double minY = Double.MAX_VALUE;
227
    double maxY =-Double.MAX_VALUE;
228

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

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

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

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

    
249
    info.scale = max3/0.5;
250

    
251
    int len = vert3D.length;
252
    StickerCoords sInfo = new StickerCoords();
253
    sInfo.vertices = new double[2*len];
254

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

    
261
    mStickerCoords.add(sInfo);
262

    
263
    info.sticker = mStickerCoords.size() -1;
264
    info.flip = false;
265
    }
266

    
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

    
269
  private FaceTransform constructNewTransform(final double[][] vert3D)
270
    {
271
    FaceTransform ft = new FaceTransform();
272

    
273
    // compute center of gravity
274
    ft.vx = 0.0f;
275
    ft.vy = 0.0f;
276
    ft.vz = 0.0f;
277
    int len = vert3D.length;
278

    
279
    for (double[] vert : vert3D)
280
      {
281
      ft.vx += vert[0];
282
      ft.vy += vert[1];
283
      ft.vz += vert[2];
284
      }
285

    
286
    ft.vx /= len;
287
    ft.vy /= len;
288
    ft.vz /= len;
289

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

    
298
    // find 3 non-colinear vertices
299
    int foundIndex = -1;
300

    
301
    for(int vertex=2; vertex<len; vertex++)
302
      {
303
      if( !areColinear(vert3D,0,1,vertex) )
304
        {
305
        foundIndex = vertex;
306
        break;
307
        }
308
      }
309

    
310
    // compute the normal vector
311
    if( foundIndex==-1 )
312
      {
313
      throw new RuntimeException("all vertices colinear");
314
      }
315

    
316
    computeNormalVector(vert3D,0,1,foundIndex);
317

    
318
    // rotate so that the normal vector becomes (0,0,1)
319
    double axisX, axisY, axisZ;
320

    
321
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
322
      {
323
      axisX = -mBuffer[1];
324
      axisY =  mBuffer[0];
325
      axisZ = 0.0f;
326

    
327
      double axiLen = axisX*axisX + axisY*axisY;
328
      axiLen = Math.sqrt(axiLen);
329
      axisX /= axiLen;
330
      axisY /= axiLen;
331
      axisZ /= axiLen;
332
      }
333
    else
334
      {
335
      axisX = 0.0f;
336
      axisY = 1.0f;
337
      axisZ = 0.0f;
338
      }
339

    
340
    double cosTheta = mBuffer[2];
341
    double sinTheta = Math.sqrt(1-cosTheta*cosTheta);
342
    double sinHalfTheta = computeSinHalf(cosTheta);
343
    double cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
344

    
345
    mQuat1[0] = axisX*sinHalfTheta;
346
    mQuat1[1] = axisY*sinHalfTheta;
347
    mQuat1[2] = axisZ*sinHalfTheta;
348
    mQuat1[3] = cosHalfTheta;
349
    mQuat2[0] =-axisX*sinHalfTheta;
350
    mQuat2[1] =-axisY*sinHalfTheta;
351
    mQuat2[2] =-axisZ*sinHalfTheta;
352
    mQuat2[3] = cosHalfTheta;
353

    
354
    for (double[] vert : vert3D)
355
      {
356
      quatMultiply(mQuat1, vert  , mQuat3);
357
      quatMultiply(mQuat3, mQuat2, vert  );
358
      }
359

    
360
    // fit the whole thing in a square and remember the scale & 2D vertices
361
    fitInSquare(ft, vert3D);
362

    
363
    // remember the rotation
364
    ft.qx =-mQuat1[0];
365
    ft.qy =-mQuat1[1];
366
    ft.qz =-mQuat1[2];
367
    ft.qw = mQuat1[3];
368

    
369
    return ft;
370
    }
371

    
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373

    
374
  private void rotateAllVertices(double[] result, int len, double[] vertices, double sin, double cos)
375
    {
376
    for(int i=0; i<len; i++)
377
      {
378
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
379
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
380
      }
381
    }
382

    
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384

    
385
  private double computeScale(double[] v1, double[] v2, int v1i, int v2i)
386
    {
387
    double v1x = v1[2*v1i];
388
    double v1y = v1[2*v1i+1];
389
    double v2x = v2[2*v2i];
390
    double v2y = v2[2*v2i+1];
391

    
392
    double lenSq1 = v1x*v1x + v1y*v1y;
393
    double lenSq2 = v2x*v2x + v2y*v2y;
394

    
395
    return Math.sqrt(lenSq2/lenSq1);
396
    }
397

    
398
///////////////////////////////////////////////////////////////////////////////////////////////////
399
// valid for 0<angle<2*PI
400

    
401
  private double computeSinHalf(double cos)
402
    {
403
    return Math.sqrt((1-cos)/2);
404
    }
405

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

    
409
  private double computeCosHalf(double sin, double cos)
410
    {
411
    double cosHalf = Math.sqrt((1+cos)/2);
412
    return sin<0 ? -cosHalf : cosHalf;
413
    }
414

    
415
///////////////////////////////////////////////////////////////////////////////////////////////////
416

    
417
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
418
    {
419
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
420
    if( v>=len ) v-=len;
421
    if( v< 0   ) v+=len;
422

    
423
    return v;
424
    }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427

    
428
  private boolean isScaledVersionOf(double[] newVert, double[] oldVert, int len, int vertex, boolean inverted)
429
    {
430
    int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
431
    double EPSILON = 0.001;
432
    double scale = computeScale(newVert,oldVert,newZeroIndex,0);
433

    
434
    for(int i=1; i<len; i++)
435
      {
436
      int index = computeRotatedIndex(i,len,vertex,inverted);
437

    
438
      double horz = oldVert[2*i  ] - scale*newVert[2*index  ];
439
      double vert = oldVert[2*i+1] - scale*newVert[2*index+1];
440

    
441
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
442
      }
443

    
444
    return true;
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
  private void mirrorAllVertices(double[] output, int len, double[] input)
450
    {
451
    for(int vertex=0; vertex<len; vertex++)
452
      {
453
      output[2*vertex  ] = input[2*vertex  ];
454
      output[2*vertex+1] =-input[2*vertex+1];
455
      }
456
    }
457

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

    
460
  private void correctInfo(FaceTransform info, double scale, double sin, double cos, int oldSticker, boolean flip)
461
    {
462
    mStickerCoords.remove(info.sticker);
463

    
464
    info.flip    = flip;
465
    info.sticker = oldSticker;
466
    info.scale  *= scale;
467

    
468
    mQuat1[0] = info.qx;
469
    mQuat1[1] = info.qy;
470
    mQuat1[2] = info.qz;
471
    mQuat1[3] = info.qw;
472

    
473
    double sinHalf = computeSinHalf(cos);
474
    double cosHalf = computeCosHalf(sin,cos);
475

    
476
    if( flip )
477
      {
478
      mQuat3[0] = 0.0f;
479
      mQuat3[1] = 0.0f;
480
      mQuat3[2] = sinHalf;
481
      mQuat3[3] = cosHalf;
482

    
483
      mQuat4[0] = 1.0;
484
      mQuat4[1] = 0.0;
485
      mQuat4[2] = 0.0;
486
      mQuat4[3] = 0.0;
487

    
488
      quatMultiply( mQuat3, mQuat4, mQuat2 );
489
      }
490
    else
491
      {
492
      mQuat2[0] = 0.0f;
493
      mQuat2[1] = 0.0f;
494
      mQuat2[2] = sinHalf;
495
      mQuat2[3] = cosHalf;
496
      }
497

    
498
    quatMultiply( mQuat1, mQuat2, mQuat3 );
499

    
500
    info.qx = mQuat3[0];
501
    info.qy = mQuat3[1];
502
    info.qz = mQuat3[2];
503
    info.qw = mQuat3[3];
504
    }
505

    
506
///////////////////////////////////////////////////////////////////////////////////////////////////
507

    
508
  private void printVert(double[] buffer)
509
    {
510
    int len = buffer.length/2;
511
    String str = "";
512

    
513
    for(int i=0; i<len; i++)
514
      {
515
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
516
      }
517

    
518
    android.util.Log.d("D", str);
519
    }
520

    
521
///////////////////////////////////////////////////////////////////////////////////////////////////
522

    
523
  private boolean foundVertex(FaceTransform info, double[] buffer, int len, double[] newVert,
524
                              double[] oldVert, double lenFirstOld, int oldSticker, boolean inverted)
525
    {
526
    for(int vertex=0; vertex<len; vertex++)
527
      {
528
      double newX = newVert[2*vertex  ];
529
      double newY = newVert[2*vertex+1];
530
      double lenIthNew = Math.sqrt(newX*newX + newY*newY);
531
      double cos = QuatHelper.computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
532
      double sin = QuatHelper.computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
533

    
534
      rotateAllVertices(buffer,len,newVert,sin,cos);
535

    
536
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
537
        {
538
        int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
539
        double scale = computeScale(oldVert,newVert,0,newZeroIndex);
540
        correctInfo(info,scale,sin,cos,oldSticker,inverted);
541
        return true;
542
        }
543
      }
544

    
545
    return false;
546
    }
547

    
548
///////////////////////////////////////////////////////////////////////////////////////////////////
549

    
550
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
551
    {
552
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
553
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
554
    double[] newVert = sNewInfo.vertices;
555
    double[] oldVert = sOldInfo.vertices;
556
    int oldLen = oldVert.length;
557
    int newLen = newVert.length;
558

    
559
    if( oldLen == newLen )
560
      {
561
      int oldSticker = oldInfo.sticker;
562
      double[] buffer1 = new double[oldLen];
563
      double lenFirstOld = Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
564
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) ) return true;
565
      double[] buffer2 = new double[oldLen];
566
      mirrorAllVertices(buffer2, newLen/2, newVert);
567
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) ) return true;
568
      }
569

    
570
    return false;
571
    }
572

    
573
///////////////////////////////////////////////////////////////////////////////////////////////////
574

    
575
  private double[][] constructVert(double[][] vertices, int[] index)
576
    {
577
    int len = index.length;
578
    double[][] ret = new double[len][4];
579

    
580
    for(int i=0; i<len; i++)
581
      {
582
      ret[i][0] = vertices[index[i]][0];
583
      ret[i][1] = vertices[index[i]][1];
584
      ret[i][2] = vertices[index[i]][2];
585
      ret[i][3] = 1.0f;
586
      }
587

    
588
    return ret;
589
    }
590

    
591
///////////////////////////////////////////////////////////////////////////////////////////////////
592

    
593
  private void prepareAndRoundCorners(MeshBase mesh, double[][] vertices,
594
                                      float[][] corners, int[] cornerIndexes,
595
                                      float[][] centers, int[] centerIndexes )
596
    {
597
    int lenV = vertices.length;
598
    Static3D[] staticVert = new Static3D[1];
599
    Static3D center = new Static3D(0,0,0);
600

    
601
    for(int v=0; v<lenV; v++)
602
      {
603
      staticVert[0] = new Static3D( (float)vertices[v][0], (float)vertices[v][1], (float)vertices[v][2]);
604

    
605
      int cent = centerIndexes[v];
606

    
607
      if( cent>=0 )
608
        {
609
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
610

    
611
        int corn = cornerIndexes[v];
612

    
613
        if( corn>=0 )
614
          {
615
          float strength = corners[corn][0];
616
          float radius   = corners[corn][1];
617
          roundCorners(mesh, center, staticVert, strength, radius);
618
          }
619
        }
620
      }
621
    }
622

    
623
///////////////////////////////////////////////////////////////////////////////////////////////////
624

    
625
  private void correctComponents(MeshBase mesh, int numComponents)
626
    {
627
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
628

    
629
    mesh.mergeEffComponents();
630

    
631
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
632
    }
633

    
634
///////////////////////////////////////////////////////////////////////////////////////////////////
635

    
636
  private void printTransform(FaceTransform f)
637
    {
638
    android.util.Log.e("D", "q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
639
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
640
    }
641

    
642
///////////////////////////////////////////////////////////////////////////////////////////////////
643
// PUBLIC
644

    
645
  public float[] computeBands(float H, int alpha, float dist, float K, int N)
646
    {
647
    float[] bands = new float[2*N];
648

    
649
    bands[0] = 1.0f;
650
    bands[1] = 0.0f;
651

    
652
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
653
    float sinBeta = (float)Math.sin(beta);
654
    float cosBeta = (float)Math.cos(beta);
655
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
656
    float D = R*sinBeta;
657
    float B = h(R,sinBeta,K*beta);
658

    
659
    if( D>1.0f )
660
      {
661
      for(int i=1; i<N; i++)
662
        {
663
        bands[2*i  ] = (float)(N-1-i)/(N-1);
664
        bands[2*i+1] = H*(1-bands[2*i]);
665
        }
666
      }
667
    else
668
      {
669
      int K2 = (int)((N-3)*K);
670
      int K1 = (N-3)-K2;
671

    
672
      for(int i=0; i<=K1; i++)
673
        {
674
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
675
        float x = h(R,sinBeta,angle);
676
        bands[2*i+2] = 1.0f - x;
677
        bands[2*i+3] = g(R,D,x,cosBeta);
678
        }
679

    
680
      for(int i=0; i<=K2; i++)
681
        {
682
        float x = (1-B)*(i+1)/(K2+1) + B;
683
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
684
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
685
        }
686
      }
687

    
688
    bands[2*N-2] = 0.0f;
689
    bands[2*N-1] =    H;
690

    
691
    return bands;
692
    }
693

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

    
696
  public void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
697
    {
698
    Static4D reg= new Static4D(0,0,0,regionRadius);
699

    
700
    float centX = center.get0();
701
    float centY = center.get1();
702
    float centZ = center.get2();
703

    
704
    for (Static3D vertex : vertices)
705
      {
706
      float x = strength*(centX - vertex.get0());
707
      float y = strength*(centY - vertex.get1());
708
      float z = strength*(centZ - vertex.get2());
709

    
710
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
711
      mesh.apply(effect);
712
      }
713
    }
714

    
715
///////////////////////////////////////////////////////////////////////////////////////////////////
716

    
717
  public void printStickerCoords()
718
    {
719
    int stickers = mStickerCoords.size();
720

    
721
    android.util.Log.d("D", "---- STICKER COORDS ----");
722

    
723
    for(int s=0; s<stickers; s++)
724
      {
725
      String ver = "{ ";
726
      StickerCoords info = mStickerCoords.get(s);
727
      int len = info.vertices.length/2;
728

    
729
      for(int i =0; i<len; i++)
730
        {
731
        if( i!=0 ) ver += ", ";
732
        ver += ( (float)info.vertices[2*i]+"f, "+(float)info.vertices[2*i+1]+"f");
733
        }
734

    
735
      ver += " }";
736
      android.util.Log.d("D", ver);
737
      }
738

    
739
    android.util.Log.d("D", "---- END STICKER COORDS ----");
740
    }
741

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

    
744
  public void printFaceTransform()
745
    {
746
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
747

    
748
    int oldfaces = mOldFaceTransf.size();
749

    
750
    for(int f=0; f<oldfaces; f++)
751
      {
752
      printTransform(mOldFaceTransf.get(f));
753
      }
754

    
755
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
756

    
757
    int newfaces = mNewFaceTransf.size();
758

    
759
    for(int f=0; f<newfaces; f++)
760
      {
761
      printTransform(mNewFaceTransf.get(f));
762
      }
763
    }
764

    
765
///////////////////////////////////////////////////////////////////////////////////////////////////
766

    
767
  public void clear()
768
    {
769
    mStickerCoords.clear();
770
    mNewFaceTransf.clear();
771
    mOldFaceTransf.clear();
772
    }
773

    
774
///////////////////////////////////////////////////////////////////////////////////////////////////
775

    
776
  public void createNewFaceTransform( final double[][] vertices, final int[][] indexes)
777
    {
778
    FaceTransform ft;
779
    int numNew = mNewFaceTransf.size();
780

    
781
    for(int i=0; i<numNew; i++)
782
      {
783
      ft = mNewFaceTransf.remove(0);
784
      mOldFaceTransf.add(ft);
785
      }
786

    
787
    int numFaces = indexes.length;
788
    int numOld = mOldFaceTransf.size();
789

    
790
    for (int face=0; face<numFaces; face++)
791
      {
792
      boolean collapsed = false;
793

    
794
      double[][] vert = constructVert(vertices, indexes[face]);
795
      FaceTransform newT = constructNewTransform(vert);
796

    
797
      for (int old=0; !collapsed && old<numOld; old++)
798
        {
799
        ft = mOldFaceTransf.get(old);
800
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
801
        }
802

    
803
      for (int pre=0; !collapsed && pre<face; pre++)
804
        {
805
        ft = mNewFaceTransf.get(pre);
806
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
807
        }
808

    
809
      mNewFaceTransf.add(newT);
810
      }
811
    }
812

    
813

    
814
///////////////////////////////////////////////////////////////////////////////////////////////////
815

    
816
  public void createNewFaceTransform(final ObjectShape shape)
817
    {
818
    double[][] vertices = shape.getVertices();
819
    int[][] indices = shape.getVertIndices();
820
    createNewFaceTransform(vertices,indices);
821
    }
822

    
823
///////////////////////////////////////////////////////////////////////////////////////////////////
824

    
825
  private void computeConvexityCenter(double[] out, float[] in, FaceTransform ft)
826
    {
827
    if( in==null )
828
      {
829
      out[0] = out[1] = 0.0f;
830
      }
831
    else
832
      {
833
      out[0] = in[0] - ft.vx;
834
      out[1] = in[1] - ft.vy;
835
      out[2] = in[2] - ft.vz;
836
      out[3] = 1.0f;
837

    
838
      mQuat1[0] =-ft.qx;
839
      mQuat1[1] =-ft.qy;
840
      mQuat1[2] =-ft.qz;
841
      mQuat1[3] = ft.qw;
842

    
843
      mQuat2[0] = -mQuat1[0];
844
      mQuat2[1] = -mQuat1[1];
845
      mQuat2[2] = -mQuat1[2];
846
      mQuat2[3] = +mQuat1[3];
847

    
848
      quatMultiply(mQuat1, out  , mQuat3);
849
      quatMultiply(mQuat3, mQuat2, out  );
850

    
851
      out[0] /= ft.scale;
852
      out[1] /= ft.scale;
853
      out[2] /= ft.scale;
854
      }
855
    }
856

    
857
///////////////////////////////////////////////////////////////////////////////////////////////////
858

    
859
  public MeshBase createRoundedSolid(final ObjectShape shape)
860
    {
861
    double[][] vertices     = shape.getVertices();
862
    int[][] vertIndexes     = shape.getVertIndices();
863
    float[][] bands         = shape.getBands();
864
    int[]   bandIndexes     = shape.getBandIndices();
865
    float[][] corners       = shape.getCorners();
866
    int[]   cornerIndexes   = shape.getCornerIndices();
867
    float[][] centers       = shape.getCenters();
868
    int[]   centerIndexes   = shape.getCenterIndices();
869
    int numComponents       = shape.getNumComponents();
870
    float[] convexityCenter = shape.getConvexityCenter();
871

    
872
    return createRoundedSolid(vertices,vertIndexes,bands,bandIndexes,corners,cornerIndexes,
873
                              centers,centerIndexes,numComponents,convexityCenter);
874
    }
875

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

    
878
  public MeshBase createRoundedSolid(final double[][] vertices, final int[][] vertIndexes,
879
                                     final float[][] bands    , final int[]   bandIndexes,
880
                                     final float[][] corners  , final int[]   cornerIndexes,
881
                                     final float[][] centers  , final int[]   centerIndexes,
882
                                     final int numComponents  , final float[] convexityCenter )
883
    {
884
    int numFaces = vertIndexes.length;
885
    float[] band, bandsComputed;
886
    MeshBase[] meshes = new MeshBase[numFaces];
887
    FaceTransform fInfo;
888
    StickerCoords sInfo;
889
    double[] convexXY = new double[4];
890

    
891
    for(int face=0; face<numFaces; face++)
892
      {
893
      fInfo = mNewFaceTransf.get(face);
894
      sInfo = mStickerCoords.get(fInfo.sticker);
895

    
896
      double[] verts = sInfo.vertices;
897
      int lenVerts = verts.length;
898
      float[] vertsFloat = new float[lenVerts];
899
      for(int i=0; i<lenVerts; i++) vertsFloat[i] = (float)verts[i];
900

    
901
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
902

    
903
      band = bands[bandIndexes[face]];
904
      bandsComputed = computeBands( band[0], (int)band[1], band[2], band[3], (int)band[4]);
905
      meshes[face] = new MeshPolygon(vertsFloat,bandsComputed,(int)band[5],(int)band[6], (float)convexXY[0], (float)convexXY[1]);
906
      meshes[face].setEffectAssociation(0,(1<<face),0);
907
      }
908

    
909
    MeshBase mesh = new MeshJoined(meshes);
910
    Static3D center = new Static3D(0,0,0);
911

    
912
    for(int face=0; face<numFaces; face++)
913
      {
914
      int assoc = (1<<face);
915
      fInfo = mNewFaceTransf.get(face);
916

    
917
      float vx = (float)fInfo.vx;
918
      float vy = (float)fInfo.vy;
919
      float vz = (float)fInfo.vz;
920
      float sc = (float)fInfo.scale;
921
      float qx = (float)fInfo.qx;
922
      float qy = (float)fInfo.qy;
923
      float qz = (float)fInfo.qz;
924
      float qw = (float)fInfo.qw;
925

    
926
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
927
      Static3D move3D= new Static3D(vx,vy,vz);
928
      Static4D quat  = new Static4D(qx,qy,qz,qw);
929

    
930
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
931
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
932
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
933
      }
934

    
935
    prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
936

    
937
    correctComponents(mesh,numComponents);
938

    
939
    return mesh;
940
    }
941
  }
(2-2/11)