Project

General

Profile

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

examples / src / main / java / org / distorted / examples / meshfile / FactoryCubit.java @ 3083fab8

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.examples.meshfile;
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.mesh.MeshBase;
28
import org.distorted.library.mesh.MeshJoined;
29
import org.distorted.library.mesh.MeshPolygon;
30
import org.distorted.library.type.Static1D;
31
import org.distorted.library.type.Static3D;
32
import org.distorted.library.type.Static4D;
33

    
34
import java.util.ArrayList;
35

    
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

    
38
class FactoryCubit
39
  {
40
  private static final double[] mBuffer = new double[3];
41
  private static final double[] mQuat1  = new double[4];
42
  private static final double[] mQuat2  = new double[4];
43
  private static final double[] mQuat3  = new double[4];
44
  private static final double[] mQuat4  = new double[4];
45

    
46
  private static final Static1D RADIUS = new Static1D(1);
47

    
48
  private static FactoryCubit mThis;
49

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

    
55
  private static class FaceInfo
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<FaceInfo>       mFaceInfo = new ArrayList<>();
65
  private static final ArrayList<StickerInfo> mStickerInfo = new ArrayList<>();
66

    
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

    
69
  private FactoryCubit()
70
    {
71

    
72
    }
73

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

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

    
80
    return mThis;
81
    }
82

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

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

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

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

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

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

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

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

    
142
  float[] computeBands(float H, int alpha, float dist, float K, int N)
143
    {
144
    float[] bands = new float[2*N];
145

    
146
    bands[0] = 1.0f;
147
    bands[1] = 0.0f;
148

    
149
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
150
    float sinBeta = (float)Math.sin(beta);
151
    float cosBeta = (float)Math.cos(beta);
152
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
153
    float D = R*sinBeta;
154
    float B = h(R,sinBeta,K*beta);
155

    
156
    if( D>1.0f )
157
      {
158
      for(int i=1; i<N; i++)
159
        {
160
        bands[2*i  ] = (float)(N-1-i)/(N-1);
161
        bands[2*i+1] = H*(1-bands[2*i]);
162
        }
163
      }
164
    else
165
      {
166
      int K2 = (int)((N-3)*K);
167
      int K1 = (N-3)-K2;
168

    
169
      for(int i=0; i<=K1; i++)
170
        {
171
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
172
        float x = h(R,sinBeta,angle);
173
        bands[2*i+2] = 1.0f - x;
174
        bands[2*i+3] = g(R,D,x,cosBeta);
175
        }
176

    
177
      for(int i=0; i<=K2; i++)
178
        {
179
        float x = (1-B)*(i+1)/(K2+1) + B;
180
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
181
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
182
        }
183
      }
184

    
185
    bands[2*N-2] = 0.0f;
186
    bands[2*N-1] =    H;
187

    
188
    return bands;
189
    }
190

    
191
///////////////////////////////////////////////////////////////////////////////////////////////////
192

    
193
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
194
    {
195
    Static4D region= new Static4D(0,0,0,regionRadius);
196

    
197
    float centX = center.get0();
198
    float centY = center.get1();
199
    float centZ = center.get2();
200

    
201
    for (Static3D vertex : vertices)
202
      {
203
      float x = strength*(centX - vertex.get0());
204
      float y = strength*(centY - vertex.get1());
205
      float z = strength*(centZ - vertex.get2());
206

    
207
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, region);
208
      mesh.apply(effect);
209
      }
210
    }
211

    
212
///////////////////////////////////////////////////////////////////////////////////////////////////
213

    
214
  private boolean areColinear(double[][] vertices, int index1, int index2, int index3)
215
    {
216
    double x1 = vertices[index1][0];
217
    double y1 = vertices[index1][1];
218
    double z1 = vertices[index1][2];
219
    double x2 = vertices[index2][0];
220
    double y2 = vertices[index2][1];
221
    double z2 = vertices[index2][2];
222
    double x3 = vertices[index3][0];
223
    double y3 = vertices[index3][1];
224
    double z3 = vertices[index3][2];
225

    
226
    double v1x = x2-x1;
227
    double v1y = y2-y1;
228
    double v1z = z2-z1;
229
    double v2x = x3-x1;
230
    double v2y = y3-y1;
231
    double v2z = z3-z1;
232

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

    
235
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
236
    }
237

    
238
///////////////////////////////////////////////////////////////////////////////////////////////////
239

    
240
  private void computeNormalVector(double[][] vertices, int index1, int index2, int index3)
241
    {
242
    double x1 = vertices[index1][0];
243
    double y1 = vertices[index1][1];
244
    double z1 = vertices[index1][2];
245
    double x2 = vertices[index2][0];
246
    double y2 = vertices[index2][1];
247
    double z2 = vertices[index2][2];
248
    double x3 = vertices[index3][0];
249
    double y3 = vertices[index3][1];
250
    double z3 = vertices[index3][2];
251

    
252
    double v1x = x2-x1;
253
    double v1y = y2-y1;
254
    double v1z = z2-z1;
255
    double v2x = x3-x1;
256
    double v2y = y3-y1;
257
    double v2z = z3-z1;
258

    
259
    mBuffer[0] = v1y*v2z - v2y*v1z;
260
    mBuffer[1] = v1z*v2x - v2z*v1x;
261
    mBuffer[2] = v1x*v2y - v2x*v1y;
262

    
263
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
264
    len = Math.sqrt(len);
265
    mBuffer[0] /= len;
266
    mBuffer[1] /= len;
267
    mBuffer[2] /= len;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271
// return quat1*quat2
272

    
273
  private static void quatMultiply( double[] quat1, double[] quat2, double[] result )
274
    {
275
    double qx = quat1[0];
276
    double qy = quat1[1];
277
    double qz = quat1[2];
278
    double qw = quat1[3];
279

    
280
    double rx = quat2[0];
281
    double ry = quat2[1];
282
    double rz = quat2[2];
283
    double rw = quat2[3];
284

    
285
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
286
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
287
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
288
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
289
    }
290

    
291
///////////////////////////////////////////////////////////////////////////////////////////////////
292

    
293
  private void fitInSquare(FaceInfo info, double[][] vert3D)
294
    {
295
    double minX = Double.MAX_VALUE;
296
    double maxX =-Double.MAX_VALUE;
297
    double minY = Double.MAX_VALUE;
298
    double maxY =-Double.MAX_VALUE;
299

    
300
    for (double[] vert : vert3D)
301
      {
302
      double x = vert[0];
303
      double y = vert[1];
304

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

    
311
    minX = minX<0 ? -minX:minX;
312
    maxX = maxX<0 ? -maxX:maxX;
313
    minY = minY<0 ? -minY:minY;
314
    maxY = maxY<0 ? -maxY:maxY;
315

    
316
    double max1 = Math.max(minX,minY);
317
    double max2 = Math.max(maxX,maxY);
318
    double max3 = Math.max(max1,max2);
319

    
320
    info.scale = max3/0.5;
321

    
322
    int len = vert3D.length;
323
    StickerInfo sInfo = new StickerInfo();
324
    sInfo.vertices = new double[2*len];
325

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

    
332
    mStickerInfo.add(sInfo);
333

    
334
    info.sticker = mStickerInfo.size() -1;
335
    info.flip = false;
336
    }
337

    
338
///////////////////////////////////////////////////////////////////////////////////////////////////
339

    
340
  private void constructNew(FaceInfo info, final double[][] vert3D)
341
    {
342
    // compute center of gravity
343
    info.vx = 0.0f;
344
    info.vy = 0.0f;
345
    info.vz = 0.0f;
346
    int len = vert3D.length;
347

    
348
    for (double[] vert : vert3D)
349
      {
350
      info.vx += vert[0];
351
      info.vy += vert[1];
352
      info.vz += vert[2];
353
      }
354

    
355
    info.vx /= len;
356
    info.vy /= len;
357
    info.vz /= len;
358

    
359
    // move all vertices so that their center of gravity is at (0,0,0)
360
    for (int i=0; i<len; i++)
361
      {
362
      vert3D[i][0] -= info.vx;
363
      vert3D[i][1] -= info.vy;
364
      vert3D[i][2] -= info.vz;
365
      }
366

    
367
    // find 3 non-colinear vertices
368
    int foundIndex = -1;
369

    
370
    for(int vertex=2; vertex<len; vertex++)
371
      {
372
      if( !areColinear(vert3D,0,1,vertex) )
373
        {
374
        foundIndex = vertex;
375
        break;
376
        }
377
      }
378

    
379
    // compute the normal vector
380
    if( foundIndex==-1 )
381
      {
382
      throw new RuntimeException("all vertices colinear");
383
      }
384

    
385
    computeNormalVector(vert3D,0,1,foundIndex);
386

    
387
    // rotate so that the normal vector becomes (0,0,1)
388
    double axisX, axisY, axisZ;
389

    
390
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
391
      {
392
      axisX = -mBuffer[1];
393
      axisY =  mBuffer[0];
394
      axisZ = 0.0f;
395

    
396
      double axiLen = axisX*axisX + axisY*axisY;
397
      axiLen = Math.sqrt(axiLen);
398
      axisX /= axiLen;
399
      axisY /= axiLen;
400
      axisZ /= axiLen;
401
      }
402
    else
403
      {
404
      axisX = 0.0f;
405
      axisY = 1.0f;
406
      axisZ = 0.0f;
407
      }
408

    
409
    double cosTheta = mBuffer[2];
410
    double sinTheta = Math.sqrt(1-cosTheta*cosTheta);
411
    double sinHalfTheta = computeSinHalf(cosTheta);
412
    double cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
413

    
414
    mQuat1[0] = axisX*sinHalfTheta;
415
    mQuat1[1] = axisY*sinHalfTheta;
416
    mQuat1[2] = axisZ*sinHalfTheta;
417
    mQuat1[3] = cosHalfTheta;
418
    mQuat2[0] =-axisX*sinHalfTheta;
419
    mQuat2[1] =-axisY*sinHalfTheta;
420
    mQuat2[2] =-axisZ*sinHalfTheta;
421
    mQuat2[3] = cosHalfTheta;
422

    
423
    for (double[] vert : vert3D)
424
      {
425
      quatMultiply(mQuat1, vert  , mQuat3);
426
      quatMultiply(mQuat3, mQuat2, vert  );
427
      }
428

    
429
    // fit the whole thing in a square and remember the scale & 2D vertices
430
    fitInSquare(info, vert3D);
431

    
432
    // remember the rotation
433
    info.qx =-mQuat1[0];
434
    info.qy =-mQuat1[1];
435
    info.qz =-mQuat1[2];
436
    info.qw = mQuat1[3];
437
    }
438

    
439
///////////////////////////////////////////////////////////////////////////////////////////////////
440

    
441
  private double computeCos(double oldX, double oldY, double newX, double newY, double len1, double len2)
442
    {
443
    double ret= (oldX*newX+oldY*newY) / (len1*len2);
444
    if( ret<-1.0 ) return -1.0;
445
    if( ret> 1.0 ) return  1.0;
446

    
447
    return ret;
448
    }
449

    
450
///////////////////////////////////////////////////////////////////////////////////////////////////
451
// sin of (signed!) angle between vectors 'old' and 'new', counterclockwise!
452

    
453
  private double computeSin(double oldX, double oldY, double newX, double newY, double len1, double len2)
454
    {
455
    double ret= (newX*oldY-oldX*newY) / (len1*len2);
456
    if( ret<-1.0 ) return -1.0;
457
    if( ret> 1.0 ) return  1.0;
458

    
459
    return ret;
460
    }
461

    
462
///////////////////////////////////////////////////////////////////////////////////////////////////
463

    
464
  private void rotateAllVertices(double[] result, int len, double[] vertices, double sin, double cos)
465
    {
466
    for(int i=0; i<len; i++)
467
      {
468
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
469
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
470
      }
471
    }
472

    
473
///////////////////////////////////////////////////////////////////////////////////////////////////
474

    
475
  private double computeScale(double[] v1, double[] v2)
476
    {
477
    double lenSq1 = v1[0]*v1[0] + v1[1]*v1[1];
478
    double lenSq2 = v2[0]*v2[0] + v2[1]*v2[1];
479

    
480
    return Math.sqrt(lenSq2/lenSq1);
481
    }
482

    
483
///////////////////////////////////////////////////////////////////////////////////////////////////
484

    
485
  private double computeSinHalf(double cos)
486
    {
487
    return Math.sqrt((1-cos)/2);
488
    }
489

    
490
///////////////////////////////////////////////////////////////////////////////////////////////////
491

    
492
  private double computeCosHalf(double sin, double cos)
493
    {
494
    double cosHalf = Math.sqrt((1+cos)/2);
495
    return sin<0 ? -cosHalf : cosHalf;
496
    }
497

    
498
///////////////////////////////////////////////////////////////////////////////////////////////////
499

    
500
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
501
    {
502
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
503
    if( v>=len ) v-=len;
504
    if( v< 0   ) v+=len;
505

    
506
    return v;
507
    }
508

    
509
///////////////////////////////////////////////////////////////////////////////////////////////////
510

    
511
  private boolean isScaledVersionOf(double[] newVert, double[] oldVert, int len, int vertex, boolean inverted)
512
    {
513
    double EPSILON = 0.001;
514
    double scale = computeScale(newVert,oldVert);
515

    
516
    for(int i=1; i<len; i++)
517
      {
518
      int index = computeRotatedIndex(i,len,vertex,inverted);
519

    
520
      double horz = oldVert[2*i  ] - scale*newVert[2*index  ];
521
      double vert = oldVert[2*i+1] - scale*newVert[2*index+1];
522

    
523
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
524
      }
525

    
526
    return true;
527
    }
528

    
529
///////////////////////////////////////////////////////////////////////////////////////////////////
530

    
531
  private void mirrorAllVertices(double[] output, int len, double[] input)
532
    {
533
    for(int vertex=0; vertex<len; vertex++)
534
      {
535
      output[2*vertex  ] = input[2*vertex  ];
536
      output[2*vertex+1] =-input[2*vertex+1];
537
      }
538
    }
539

    
540
///////////////////////////////////////////////////////////////////////////////////////////////////
541

    
542
  private void correctInfo(FaceInfo info, double scale, double sin, double cos, int oldSticker, boolean flip)
543
    {
544
    mStickerInfo.remove(info.sticker);
545

    
546
    info.flip    = flip;
547
    info.sticker = oldSticker;
548
    info.scale  *= scale;
549

    
550
    mQuat1[0] = info.qx;
551
    mQuat1[1] = info.qy;
552
    mQuat1[2] = info.qz;
553
    mQuat1[3] = info.qw;
554

    
555
    double sinHalf = computeSinHalf(cos);
556
    double cosHalf = computeCosHalf(sin,cos);
557

    
558
    if( flip )
559
      {
560
      mQuat3[0] = 0.0f;
561
      mQuat3[1] = 0.0f;
562
      mQuat3[2] = sinHalf;
563
      mQuat3[3] = cosHalf;
564

    
565
      mQuat4[0] = 1.0;
566
      mQuat4[1] = 0.0;
567
      mQuat4[2] = 0.0;
568
      mQuat4[3] = 0.0;
569

    
570
      quatMultiply( mQuat3, mQuat4, mQuat2 );
571
      }
572
    else
573
      {
574
      mQuat2[0] = 0.0f;
575
      mQuat2[1] = 0.0f;
576
      mQuat2[2] = sinHalf;
577
      mQuat2[3] = cosHalf;
578
      }
579

    
580
    quatMultiply( mQuat1, mQuat2, mQuat3 );
581

    
582
    info.qx = mQuat3[0];
583
    info.qy = mQuat3[1];
584
    info.qz = mQuat3[2];
585
    info.qw = mQuat3[3];
586
    }
587

    
588
///////////////////////////////////////////////////////////////////////////////////////////////////
589

    
590
  private void printVert(double[] buffer)
591
    {
592
    int len = buffer.length/2;
593
    String str = "";
594

    
595
    for(int i=0; i<len; i++)
596
      {
597
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
598
      }
599

    
600
    android.util.Log.d("D", str);
601
    }
602

    
603
///////////////////////////////////////////////////////////////////////////////////////////////////
604

    
605
  private boolean foundVertex(FaceInfo info, double[] buffer, int len, double[] newVert,
606
                              double[] oldVert, double lenFirstOld, int oldSticker, boolean inverted)
607
    {
608
    for(int vertex=0; vertex<len; vertex++)
609
      {
610
      double newX = newVert[2*vertex  ];
611
      double newY = newVert[2*vertex+1];
612
      double lenIthNew = Math.sqrt(newX*newX + newY*newY);
613
      double cos = computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
614
      double sin = computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
615

    
616
      rotateAllVertices(buffer,len,newVert,sin,cos);
617

    
618
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
619
        {
620
        double scale = computeScale(oldVert,newVert);
621
        correctInfo(info,scale,sin,cos,oldSticker,inverted);
622
        return true;
623
        }
624
      }
625

    
626
    return false;
627
    }
628

    
629
///////////////////////////////////////////////////////////////////////////////////////////////////
630

    
631
  private boolean successfullyCollapsedStickers(final FaceInfo newInfo, final FaceInfo oldInfo)
632
    {
633
    StickerInfo sNewInfo = mStickerInfo.get(newInfo.sticker);
634
    StickerInfo sOldInfo = mStickerInfo.get(oldInfo.sticker);
635
    double[] newVert = sNewInfo.vertices;
636
    double[] oldVert = sOldInfo.vertices;
637
    int oldLen = oldVert.length;
638
    int newLen = newVert.length;
639

    
640
    if( oldLen == newLen )
641
      {
642
      int oldSticker = oldInfo.sticker;
643
      double[] buffer1 = new double[oldLen];
644
      double lenFirstOld = Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
645
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) ) return true;
646
      double[] buffer2 = new double[oldLen];
647
      mirrorAllVertices(buffer2, newLen/2, newVert);
648
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) ) return true;
649
      }
650

    
651
    return false;
652
    }
653

    
654
///////////////////////////////////////////////////////////////////////////////////////////////////
655

    
656
  private double[][] constructVert(double[][] vertices, int[] index)
657
    {
658
    int len = index.length;
659
    double[][] ret = new double[len][4];
660

    
661
    for(int i=0; i<len; i++)
662
      {
663
      ret[i][0] = vertices[index[i]][0];
664
      ret[i][1] = vertices[index[i]][1];
665
      ret[i][2] = vertices[index[i]][2];
666
      ret[i][3] = 1.0f;
667
      }
668

    
669
    return ret;
670
    }
671

    
672
///////////////////////////////////////////////////////////////////////////////////////////////////
673

    
674
  private void prepareFaceInfo( final double[][] vertices, final int[][] indexes)
675
    {
676
    mFaceInfo.clear();
677
    mStickerInfo.clear();
678

    
679
    int numFaces = indexes.length;
680
    FaceInfo oldInfo;
681

    
682
    for(int face=0; face<numFaces; face++)
683
      {
684
      FaceInfo newInfo = new FaceInfo();
685
      int[] index = indexes[face];
686
      double[][] vert = constructVert(vertices,index);
687
      constructNew(newInfo,vert);
688

    
689
      for(int previous=0; previous<face; previous++)
690
        {
691
        oldInfo = mFaceInfo.get(previous);
692
        if( successfullyCollapsedStickers(newInfo,oldInfo) ) break;
693
        }
694

    
695
      mFaceInfo.add(newInfo);
696
      }
697
    }
698

    
699
///////////////////////////////////////////////////////////////////////////////////////////////////
700

    
701
  private void prepareAndRoundCorners(MeshBase mesh, double[][] vertices, int[][] vertIndexes,
702
                                      float[][] corners, int[] cornerIndexes )
703
    {
704
    int numNeig, lenFV;
705
    int lenV = vertices.length;
706
    int[] verts = new int[2*(lenV-1)];
707
    Static3D[] staticVert = new Static3D[1];
708
    Static3D center = new Static3D(0,0,0);
709
    double cx, cy, cz;
710
    double[] singleV;
711

    
712
    for(int v=0; v<lenV; v++)
713
      {
714
      // prepare verts[]
715
      numNeig = 0;
716

    
717
      for (int[] vertIndex : vertIndexes)
718
        {
719
        lenFV = vertIndex.length;
720

    
721
        for (int fv = 0; fv < lenFV; fv++)
722
          if (vertIndex[fv] == v)
723
            {
724
            int prev = fv > 0 ? fv - 1 : lenFV - 1;
725
            int next = fv < lenFV - 1 ? fv + 1 : 0;
726

    
727
            verts[numNeig++] = vertIndex[prev];
728
            verts[numNeig++] = vertIndex[next];
729
            }
730
        }
731

    
732
      cx=cy=cz=0.0f;
733

    
734
      // from verts[] prepare center
735
      for(int n=0; n<numNeig; n++)
736
        {
737
        singleV = vertices[verts[n]];
738

    
739
        cx += singleV[0];
740
        cy += singleV[1];
741
        cz += singleV[2];
742
        }
743
      center.set( (float)(cx/numNeig - vertices[v][0]),
744
                  (float)(cy/numNeig - vertices[v][1]),
745
                  (float)(cz/numNeig - vertices[v][2]));
746

    
747
      // round Corners
748
      staticVert[0] = new Static3D( (float)vertices[v][0], (float)vertices[v][1], (float)vertices[v][2]);
749

    
750
      int corn = cornerIndexes[v];
751
      float strength = corners[corn][0];
752
      float radius   = corners[corn][1];
753

    
754
      roundCorners(mesh, center, staticVert, strength, radius);
755
      }
756
    }
757

    
758
///////////////////////////////////////////////////////////////////////////////////////////////////
759

    
760
  private void printInfo()
761
    {
762
    int stickers = mStickerInfo.size();
763

    
764
    android.util.Log.d("D", "-------------------------");
765

    
766
    for(int s=0; s<stickers; s++)
767
      {
768
      String ver = "";
769
      StickerInfo info = mStickerInfo.get(s);
770
      int len = info.vertices.length/2;
771

    
772
      for(int i =0; i<len; i++)
773
        {
774
        ver += ("("+info.vertices[2*i]+","+info.vertices[2*i+1]+") ");
775
        }
776

    
777
      android.util.Log.e("D", "sticker "+s+" "+ver);
778
      }
779

    
780
    android.util.Log.d("D", "-------------------------");
781

    
782
    int faces = mFaceInfo.size();
783

    
784
    for(int f=0; f<faces; f++)
785
      {
786
      FaceInfo info = mFaceInfo.get(f);
787

    
788
      android.util.Log.e("D", "q=("+info.qx+", "+info.qy+", "+info.qz+", "+info.qw+") v=("
789
                       +info.vx+", "+info.vy+", "+info.vz+") scale="+info.scale+" sticker="+info.sticker);
790
      }
791

    
792
    android.util.Log.d("D", "-------------------------");
793
    }
794

    
795
///////////////////////////////////////////////////////////////////////////////////////////////////
796

    
797
  MeshBase createRoundedSolid(final double[][] vertices, final int[][] vertIndexes,
798
                              final float[][] bands    , final int[]   bandIndexes,
799
                              final float[][] corners  , final int[]   cornerIndexes)
800
    {
801
    prepareFaceInfo(vertices,vertIndexes);
802

    
803
    int numFaces = vertIndexes.length;
804
    float[] band, bandsComputed;
805
    MeshBase[] meshes = new MeshBase[numFaces];
806
    FaceInfo fInfo;
807
    StickerInfo sInfo;
808

    
809
    printInfo();
810

    
811
    for(int face=0; face<numFaces; face++)
812
      {
813
      fInfo = mFaceInfo.get(face);
814
      sInfo = mStickerInfo.get(fInfo.sticker);
815

    
816
      double[] verts = sInfo.vertices;
817
      int lenVerts = verts.length;
818
      float[] vertsFloat = new float[lenVerts];
819
      for(int i=0; i<lenVerts; i++) vertsFloat[i] = (float)verts[i];
820

    
821
      band = bands[bandIndexes[face]];
822
      bandsComputed = computeBands( band[0], (int)band[1], band[2], band[3], (int)band[4]);
823
      meshes[face] = new MeshPolygon(vertsFloat,bandsComputed,(int)band[5],(int)band[6]);
824
      meshes[face].setEffectAssociation(0,(1<<face),0);
825
      }
826

    
827
    MeshBase mesh = new MeshJoined(meshes);
828
    Static3D center = new Static3D(0,0,0);
829

    
830
    for(int face=0; face<numFaces; face++)
831
      {
832
      int assoc = (1<<face);
833
      fInfo = mFaceInfo.get(face);
834

    
835
      float vx = (float)fInfo.vx;
836
      float vy = (float)fInfo.vy;
837
      float vz = (float)fInfo.vz;
838
      float sc = (float)fInfo.scale;
839
      float qx = (float)fInfo.qx;
840
      float qy = (float)fInfo.qy;
841
      float qz = (float)fInfo.qz;
842
      float qw = (float)fInfo.qw;
843

    
844
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
845
      Static3D move3D= new Static3D(vx,vy,vz);
846
      Static4D quat  = new Static4D(qx,qy,qz,qw);
847

    
848
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
849
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
850
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
851
      }
852

    
853
    prepareAndRoundCorners(mesh, vertices, vertIndexes, corners, cornerIndexes);
854

    
855
    return mesh;
856
    }
857
  }
(1-1/5)