Project

General

Profile

Download (51.7 KB) Statistics
| Branch: | Tag: | Revision:

magiccube / src / main / java / org / distorted / helpers / FactoryCubit.java @ 5e06e92f

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.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.effect.VertexEffectMove;
28
import org.distorted.library.effect.VertexEffectRotate;
29
import org.distorted.library.effect.VertexEffectScale;
30
import org.distorted.library.mesh.MeshBase;
31
import org.distorted.library.mesh.MeshJoined;
32
import org.distorted.library.mesh.MeshPolygon;
33
import org.distorted.library.type.Static1D;
34
import org.distorted.library.type.Static3D;
35
import org.distorted.library.type.Static4D;
36

    
37
import java.util.ArrayList;
38

    
39
///////////////////////////////////////////////////////////////////////////////////////////////////
40

    
41
public class FactoryCubit
42
  {
43
  private static final float SQ2 = (float)Math.sqrt(2);
44
  private static final float SQ5 = (float)Math.sqrt(5);
45

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

    
49
  // IVY
50
  static final float IVY_D = 0.003f;
51
  static final float IVY_C = 0.59f;
52
  static final float IVY_M = 0.35f;
53
  private static final int IVY_N = 8;
54

    
55
  // REX
56
  public static final float REX_D = 0.2f;
57

    
58
  // KILO / MEGAMINX
59
  public static final float SIN54    = (SQ5+1)/4;
60
  public static final float COS54    = (float)(Math.sqrt(10-2*SQ5)/4);
61
  public static final float SIN18    = (SQ5-1)/4;
62
  public static final float COS18    = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
63
  public static final float COS_HALFD= (float)(Math.sqrt(0.5f-0.1f*SQ5)); // cos(half the dihedral angle)
64
  public static final float SIN_HALFD= (float)(Math.sqrt(0.5f+0.1f*SQ5)); // sin(half the dihedral angle)
65
  public static final float DIHEDRAL1= (float)(Math.acos(-SQ5/5)*180/Math.PI);
66
  public static final float DIHEDRAL2= (float)((180/Math.PI)*Math.asin((2*SIN54*SIN54-1)/COS54) - 90);
67

    
68
  private static final double[] mBuffer = new double[3];
69
  private static final double[] mQuat1  = new double[4];
70
  private static final double[] mQuat2  = new double[4];
71
  private static final double[] mQuat3  = new double[4];
72
  private static final double[] mQuat4  = new double[4];
73

    
74
  private static class StickerCoords
75
    {
76
    double[] vertices;
77
    }
78

    
79
  private static class FaceTransform
80
    {
81
    int sticker;
82
    double vx,vy,vz;
83
    double scale;
84
    double qx,qy,qz,qw;
85
    boolean flip;
86
    }
87

    
88
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
89
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
90
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
91

    
92
///////////////////////////////////////////////////////////////////////////////////////////////////
93

    
94
  private FactoryCubit()
95
    {
96

    
97
    }
98

    
99
///////////////////////////////////////////////////////////////////////////////////////////////////
100

    
101
  public static FactoryCubit getInstance()
102
    {
103
    if( mThis==null ) mThis = new FactoryCubit();
104

    
105
    return mThis;
106
    }
107

    
108
///////////////////////////////////////////////////////////////////////////////////////////////////
109
// H - height of the band in the middle
110
// alpha - angle of the edge  [0,90]
111
// dist - often in a polygon the distance from edge to center is not 1, but something else.
112
// This is the distance.
113
// K - where to begin the second, much more flat part of the band. [0,1]
114
// N - number of bands. N>=3
115
//
116
// theory: two distinct parts to the band:
117
// 1) (0,B) - steep
118
// 2) (B,1) - flat
119
//
120
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
121
//
122
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
123
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
124
// h(x) = R*(sin(alpha) - sin(x))
125
// R = H/(1-cos(alpha))
126
// D = H*sin(alpha)
127
// B = h(K*alpha)
128
//
129
// The N points are taken at:
130
//
131
// 1) in the second part, there are K2 = (N-3)/3 such points
132
// 2) in the first - K1 = (N-3) - K2
133
// 3) also, the 3 points 0,B,1
134
//
135
// so we have the sequence A[i] of N points
136
//
137
// 0
138
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
139
// B
140
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
141
// 1
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

    
145
  private float f(float D, float B, float x)
146
    {
147
    return ((D-B)*x + B*(1-D))/(1-B);
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  private float g(float R, float D, float x, float cosAlpha)
153
    {
154
    float d = x-D;
155
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
156
    }
157

    
158
///////////////////////////////////////////////////////////////////////////////////////////////////
159

    
160
  private float h(float R, float sinAlpha, float x)
161
    {
162
    return R*(sinAlpha-(float)Math.sin(x));
163
    }
164

    
165
///////////////////////////////////////////////////////////////////////////////////////////////////
166

    
167
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
168
    {
169
    float[] bands = new float[2*N];
170

    
171
    bands[0] = 1.0f;
172
    bands[1] = 0.0f;
173

    
174
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
175
    float sinBeta = (float)Math.sin(beta);
176
    float cosBeta = (float)Math.cos(beta);
177
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
178
    float D = R*sinBeta;
179
    float B = h(R,sinBeta,K*beta);
180

    
181
    if( D>1.0f )
182
      {
183
      for(int i=1; i<N; i++)
184
        {
185
        bands[2*i  ] = (float)(N-1-i)/(N-1);
186
        bands[2*i+1] = H*(1-bands[2*i]);
187
        }
188
      }
189
    else
190
      {
191
      int K2 = (int)((N-3)*K);
192
      int K1 = (N-3)-K2;
193

    
194
      for(int i=0; i<=K1; i++)
195
        {
196
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
197
        float x = h(R,sinBeta,angle);
198
        bands[2*i+2] = 1.0f - x;
199
        bands[2*i+3] = g(R,D,x,cosBeta);
200
        }
201

    
202
      for(int i=0; i<=K2; i++)
203
        {
204
        float x = (1-B)*(i+1)/(K2+1) + B;
205
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
206
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
207
        }
208
      }
209

    
210
    bands[2*N-2] = 0.0f;
211
    bands[2*N-1] =    H;
212

    
213
    return bands;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217

    
218
  private void roundCorners(MeshBase mesh, Static3D center, Static3D[] vertices, float strength, float regionRadius)
219
    {
220
    Static4D reg= new Static4D(0,0,0,regionRadius);
221

    
222
    float centX = center.get0();
223
    float centY = center.get1();
224
    float centZ = center.get2();
225

    
226
    for (Static3D vertex : vertices)
227
      {
228
      float x = strength*(centX - vertex.get0());
229
      float y = strength*(centY - vertex.get1());
230
      float z = strength*(centZ - vertex.get2());
231

    
232
      VertexEffect effect = new VertexEffectDeform(new Static3D(x,y,z), RADIUS, vertex, reg);
233
      mesh.apply(effect);
234
      }
235
    }
236

    
237
///////////////////////////////////////////////////////////////////////////////////////////////////
238

    
239
  MeshBase createFacesIvyCorner()
240
    {
241
    MeshBase[] meshes = new MeshBase[6];
242

    
243
    final float angle = (float)Math.PI/(2*IVY_N);
244
    final float CORR  = 1.0f - 2*IVY_D;
245
    final float DIST  = -0.5f*CORR + IVY_D;
246
    float[] vertices  = new float[2*(IVY_N+1)+6];
247

    
248
    vertices[0] = (0.5f-IVY_M) * IVY_C;
249
    vertices[1] = (DIST-IVY_M) * IVY_C;
250
    vertices[2] = (0.5f-IVY_M) * IVY_C;
251
    vertices[3] = (0.5f-IVY_M) * IVY_C;
252
    vertices[4] = (DIST-IVY_M) * IVY_C;
253
    vertices[5] = (0.5f-IVY_M) * IVY_C;
254

    
255
    for(int i=0; i<=IVY_N; i++)
256
      {
257
      float ang = (IVY_N-i)*angle;
258
      float sin = (float)Math.sin(ang);
259
      float cos = (float)Math.cos(ang);
260

    
261
      vertices[2*i+6] = (CORR*(cos-0.5f)-IVY_M)*IVY_C;
262
      vertices[2*i+7] = (CORR*(sin-0.5f)-IVY_M)*IVY_C;
263
      }
264

    
265
    float[] bands0 = computeBands(+0.012f,20,0.2f,0.5f,7);
266
    float[] bands1 = computeBands(-0.100f,20,0.2f,0.0f,2);
267

    
268
    meshes[0] = new MeshPolygon(vertices,bands0,1,2);
269
    meshes[0].setEffectAssociation(0,1,0);
270
    meshes[1] = meshes[0].copy(true);
271
    meshes[1].setEffectAssociation(0,2,0);
272
    meshes[2] = meshes[0].copy(true);
273
    meshes[2].setEffectAssociation(0,4,0);
274
    meshes[3] = new MeshPolygon(vertices,bands1,1,2);
275
    meshes[3].setEffectAssociation(0,8,0);
276
    meshes[4] = meshes[3].copy(true);
277
    meshes[4].setEffectAssociation(0,16,0);
278
    meshes[5] = meshes[3].copy(true);
279
    meshes[5].setEffectAssociation(0,32,0);
280

    
281
    return new MeshJoined(meshes);
282
    }
283

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

    
286
  MeshBase createFacesIvyFace()
287
    {
288
    MeshBase[] meshes = new MeshBase[2];
289

    
290
    final float angle = (float)Math.PI/(2*IVY_N);
291
    final float CORR  = 1.0f - 2*IVY_D;
292
    float[] vertices = new float[4*IVY_N];
293

    
294
    for(int i=0; i<IVY_N; i++)
295
      {
296
      float sin = (float)Math.sin(i*angle);
297
      float cos = (float)Math.cos(i*angle);
298

    
299
      vertices[2*i          ] = CORR*(0.5f-cos);
300
      vertices[2*i+1        ] = CORR*(0.5f-sin);
301
      vertices[2*i  +2*IVY_N] = CORR*(cos-0.5f);
302
      vertices[2*i+1+2*IVY_N] = CORR*(sin-0.5f);
303
      }
304

    
305
    float[] bands0 = computeBands(+0.03f,35,0.5f,0.5f,5);
306
    float[] bands1 = computeBands(-0.10f,45,0.5f,0.0f,2);
307

    
308
    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
309
    meshes[0].setEffectAssociation(0,1,0);
310
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
311
    meshes[1].setEffectAssociation(0,2,0);
312

    
313
    return new MeshJoined(meshes);
314
    }
315

    
316
///////////////////////////////////////////////////////////////////////////////////////////////////
317

    
318
  MeshBase createFacesRexCorner()
319
    {
320
    MeshBase[] meshes = new MeshBase[2];
321

    
322
    float F = REX_D*SQ2;
323
    float G = (1-REX_D)*SQ2/2;
324
    float H = 0.1f;
325
    float J = +2*G/3 - H*G;
326

    
327
    float[] vertices = { -F/2, -G/3, +F/2, -G/3, H*F/2, J, -H*F/2, J};
328

    
329
    float[] bands0 = computeBands(+0.016f,10,G/3,0.5f,5);
330
    float[] bands1 = computeBands(-0.230f,45,G/3,0.0f,2);
331

    
332
    meshes[0] = new MeshPolygon(vertices,bands0,1,1);
333
    meshes[0].setEffectAssociation(0,1,0);
334
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
335
    meshes[1].setEffectAssociation(0,2,0);
336

    
337
    return new MeshJoined(meshes);
338
    }
339

    
340
///////////////////////////////////////////////////////////////////////////////////////////////////
341

    
342
  MeshBase createFacesRexFace()
343
    {
344
    MeshBase[] meshes = new MeshBase[2];
345

    
346
    float[] vertices = { -REX_D,0.0f, 0.0f, -REX_D, +REX_D, 0.0f, 0.0f, +REX_D};
347

    
348
    float[] bands0 = computeBands(0.016f,10,REX_D/2,0.5f,5);
349
    float[] bands1 = computeBands(0.000f,45,REX_D/2,0.0f,2);
350

    
351
    meshes[0] = new MeshPolygon(vertices,bands0,0,0);
352
    meshes[0].setEffectAssociation(0,1,0);
353
    meshes[1] = new MeshPolygon(vertices,bands1,0,0);
354
    meshes[1].setEffectAssociation(0,2,0);
355

    
356
    return new MeshJoined(meshes);
357
    }
358

    
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360

    
361
  MeshBase createFacesRexEdge()
362
    {
363
    MeshBase[] meshes = new MeshPolygon[6];
364

    
365
    float E = 0.5f - REX_D;
366
    float F = 0.5f;
367
    float[] vertices0 = { -F,E/3, 0,-2*E/3, +F,E/3 };
368
    float[] bands0 = computeBands(0.03f,27,F/3,0.8f,5);
369

    
370
    meshes[0] = new MeshPolygon(vertices0, bands0, 2, 3);
371
    meshes[0].setEffectAssociation(0,1,0);
372
    meshes[1] = meshes[0].copy(true);
373
    meshes[1].setEffectAssociation(0,2,0);
374

    
375
    float G = (float)Math.sqrt(E*E+F*F);
376
    float[] vertices1 = { -2*G/3, -E/3, G/3, -E/3, G/3, 2*E/3 };
377
    float[] bands1 = computeBands(0.00f,45,G/3,0.2f,3);
378

    
379
    meshes[2] = new MeshPolygon(vertices1, bands1, 1, 2);
380
    meshes[2].setEffectAssociation(0,4,0);
381
    meshes[3] = meshes[2].copy(true);
382
    meshes[3].setEffectAssociation(0,8,0);
383
    meshes[4] = meshes[2].copy(true);
384
    meshes[4].setEffectAssociation(0,16,0);
385
    meshes[5] = meshes[2].copy(true);
386
    meshes[5].setEffectAssociation(0,32,0);
387

    
388
    return new MeshJoined(meshes);
389
    }
390

    
391
///////////////////////////////////////////////////////////////////////////////////////////////////
392

    
393
  MeshBase createFacesMegaminxEdge(int numLayers, float width, float height)
394
    {
395
    MeshBase[] meshes = new MeshPolygon[6];
396

    
397
    float D = height/COS18;
398
    float W = D*SIN18;
399

    
400
    float Y1 = 0.5f*width;
401
    float Y2 = 0.5f*width + W;
402
    float Y3 = 0.5f*width + 2*W;
403
    float X2 = D*SIN54;
404
    float X1 = 0.5f*height;
405
    float Y4 = D*COS54;
406

    
407
    float[] vertices0 = { -X1, Y1, -X1, -Y1, X1, -Y2, X1, Y2 };
408
    float[] vertices1 = { -X1, Y3, -X1, -Y3, X1, -Y2, X1, Y2 };
409
    float[] vertices2 = { -X2, 0.0f, 0.0f, -Y4, X2, 0.0f, 0.0f, Y4 };
410

    
411
    int numBands0 = numLayers==3 ? 5 : 3;
412
    int numBands1 = numLayers==3 ? 2 : 2;
413
    float h       = numLayers==3 ? 0.03f : 0.03f;
414

    
415
    float[] bands0 = computeBands(h    ,34,0.2f,0.2f,numBands0);
416
    float[] bands1 = computeBands(0.00f,34,0.3f,0.2f,numBands1);
417

    
418
    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
419
    meshes[0].setEffectAssociation(0, 1,0);
420
    meshes[1] = meshes[0].copy(true);
421
    meshes[1].setEffectAssociation(0, 2,0);
422
    meshes[2] = new MeshPolygon(vertices1, bands1, 0, 0);
423
    meshes[2].setEffectAssociation(0, 4,0);
424
    meshes[3] = meshes[2].copy(true);
425
    meshes[3].setEffectAssociation(0, 8,0);
426
    meshes[4] = new MeshPolygon(vertices2, bands1, 0, 0);
427
    meshes[4].setEffectAssociation(0,16,0);
428
    meshes[5] = meshes[4].copy(true);
429
    meshes[5].setEffectAssociation(0,32,0);
430

    
431
    return new MeshJoined(meshes);
432
    }
433

    
434
///////////////////////////////////////////////////////////////////////////////////////////////////
435

    
436
  MeshBase createFacesMegaminxCenter(int numLayers)
437
    {
438
    MeshBase[] meshes = new MeshPolygon[2];
439

    
440
    float R  = 0.5f;
441
    float X1 = R*COS54;
442
    float Y1 = R*SIN54;
443
    float X2 = R*COS18;
444
    float Y2 = R*SIN18;
445

    
446
    float[] vertices0 = { -X1,+Y1, -X2,-Y2, 0.0f,-R, +X2,-Y2, +X1,+Y1 };
447

    
448
    int numBands0 = numLayers==3 ? 4 : 3;
449
    int numBands1 = numLayers==3 ? 2 : 2;
450
    float h       = numLayers==3 ? 0.04f : 0.04f;
451

    
452
    float[] bands0 = computeBands( h    ,45, R/3,0.2f, numBands0);
453
    float[] bands1 = computeBands( 0.00f,34, R/3,0.2f, numBands1);
454

    
455
    meshes[0] = new MeshPolygon(vertices0, bands0, 0, 0);
456
    meshes[0].setEffectAssociation(0,1,0);
457
    meshes[1] = new MeshPolygon(vertices0, bands1, 0, 0);
458
    meshes[1].setEffectAssociation(0,2,0);
459

    
460
    return new MeshJoined(meshes);
461
    }
462

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

    
465
  private float[] createVertices(int A, int B)
466
    {
467
    float E = 0.5f / Math.max(A,B);
468
    return new float[] { -A*E,-B*E, +A*E,-B*E, +A*E,+B*E, -A*E,+B*E };
469
    }
470

    
471
///////////////////////////////////////////////////////////////////////////////////////////////////
472

    
473
  MeshBase createCuboid(int[] dimensions)
474
    {
475
    int X = dimensions[0];
476
    int Y = dimensions[1];
477
    int Z = dimensions[2];
478

    
479
    float[] verticesXY = createVertices(X,Y);
480
    float[] verticesXZ = createVertices(X,Z);
481
    float[] verticesYZ = createVertices(Z,Y);
482

    
483
    float defHeight = 0.048f;
484

    
485
    float[] bandsX = computeBands( defHeight/X,65,0.25f,0.5f,5);
486
    float[] bandsY = computeBands( defHeight/Y,65,0.25f,0.5f,5);
487
    float[] bandsZ = computeBands( defHeight/Z,65,0.25f,0.5f,5);
488

    
489
    MeshBase[] meshes = new MeshPolygon[6];
490

    
491
    meshes[0] = new MeshPolygon(verticesYZ,bandsX,1,2);
492
    meshes[0].setEffectAssociation(0,1,0);
493
    meshes[1] = meshes[0].copy(true);
494
    meshes[1].setEffectAssociation(0,2,0);
495
    meshes[2] = new MeshPolygon(verticesXZ,bandsY,1,2);
496
    meshes[2].setEffectAssociation(0,4,0);
497
    meshes[3] = meshes[2].copy(true);
498
    meshes[3].setEffectAssociation(0,8,0);
499
    meshes[4] = new MeshPolygon(verticesXY,bandsZ,1,2);
500
    meshes[4].setEffectAssociation(0,16,0);
501
    meshes[5] = meshes[4].copy(true);
502
    meshes[5].setEffectAssociation(0,32,0);
503

    
504
    return new MeshJoined(meshes);
505
    }
506

    
507
///////////////////////////////////////////////////////////////////////////////////////////////////
508
// EFFECTS
509
///////////////////////////////////////////////////////////////////////////////////////////////////
510

    
511
  VertexEffect[] createVertexEffectsIvyCorner()
512
    {
513
    Static3D axisX  = new Static3D(1,0,0);
514
    Static3D axisY  = new Static3D(0,1,0);
515
    Static1D angle1 = new Static1D(+90);
516
    Static1D angle2 = new Static1D(-90);
517
    Static3D center = new Static3D(0,0,0);
518
    Static3D move1  = new Static3D(IVY_M-0.5f,IVY_M-0.5f,0);
519

    
520
    VertexEffect[] effect = new VertexEffect[5];
521

    
522
    effect[0] = new VertexEffectScale(1/IVY_C);
523
    effect[1] = new VertexEffectMove(move1);
524
    effect[2] = new VertexEffectScale(new Static3D(1,1,-1));
525
    effect[3] = new VertexEffectRotate(angle1,axisX,center);
526
    effect[4] = new VertexEffectRotate(angle2,axisY,center);
527

    
528
    effect[2].setMeshAssociation(54,-1);  // meshes 1,2,4,5
529
    effect[3].setMeshAssociation(18,-1);  // meshes 1,4
530
    effect[4].setMeshAssociation(36,-1);  // meshes 2,5
531

    
532
    return effect;
533
    }
534

    
535
///////////////////////////////////////////////////////////////////////////////////////////////////
536

    
537
  VertexEffect[] createVertexEffectsRexEdge()
538
    {
539
    float E = 0.5f - REX_D;
540
    float F = 0.5f;
541
    float G = (float)Math.sqrt(E*E+F*F);
542
    float A = (float)((180/Math.PI)*Math.asin(E/G));
543

    
544
    Static3D move1 = new Static3D(    0.0f, -E/3, 0.0f);
545
    Static3D move2 = new Static3D(2*G/3 -F, +E/3, 0.0f);
546

    
547
    Static3D center0= new Static3D(0.0f, 0.0f, 0.0f);
548
    Static3D center1= new Static3D(  -F, 0.0f, 0.0f);
549
    Static3D center2= new Static3D(  +F, 0.0f, 0.0f);
550
    Static3D axisX  = new Static3D(1.0f, 0.0f, 0.0f);
551
    Static3D axisY  = new Static3D(0.0f, 1.0f, 0.0f);
552
    Static3D axisZ  = new Static3D(0.0f, 0.0f, 1.0f);
553

    
554
    Static1D angle180 = new Static1D(180);
555
    Static1D angle90  = new Static1D( 90);
556
    Static1D angle270 = new Static1D(270);
557
    Static1D angle1   = new Static1D(+A);
558
    Static1D angle2   = new Static1D(-A);
559

    
560
    VertexEffect[] effect = new VertexEffect[12];
561

    
562
    effect[0] = new VertexEffectMove(move1);
563
    effect[1] = new VertexEffectMove(move2);
564
    effect[2] = new VertexEffectRotate(  angle90, axisX, center0 );
565
    effect[3] = new VertexEffectRotate( angle270, axisX, center0 );
566
    effect[4] = new VertexEffectRotate( angle180, axisX, center0 );
567
    effect[5] = new VertexEffectRotate( angle180, axisY, center0 );
568
    effect[6] = new VertexEffectScale ( new Static3D(-1, 1, 1) );
569
    effect[7] = new VertexEffectScale ( new Static3D( 1,-1, 1) );
570
    effect[8] = new VertexEffectRotate(   angle1, axisY, center1);
571
    effect[9] = new VertexEffectRotate(   angle2, axisY, center2);
572
    effect[10]= new VertexEffectRotate(   angle2, axisZ, center1);
573
    effect[11]= new VertexEffectRotate(   angle1, axisZ, center2);
574

    
575
    effect[0].setMeshAssociation( 3,-1);  // meshes 0 & 1
576
    effect[1].setMeshAssociation(60,-1);  // meshes 2,3,4,5
577
    effect[2].setMeshAssociation( 2,-1);  // meshes 1
578
    effect[3].setMeshAssociation(12,-1);  // meshes 2,3
579
    effect[4].setMeshAssociation(48,-1);  // meshes 4,5
580
    effect[5].setMeshAssociation(32,-1);  // mesh 5
581
    effect[6].setMeshAssociation( 8,-1);  // apply to mesh 3
582
    effect[7].setMeshAssociation( 2,-1);  // apply to mesh 1
583
    effect[8].setMeshAssociation(16,-1);  // apply to mesh 4
584
    effect[9].setMeshAssociation(32,-1);  // apply to mesh 5
585
    effect[10].setMeshAssociation(4,-1);  // apply to mesh 2
586
    effect[11].setMeshAssociation(8,-1);  // apply to mesh 3
587

    
588
    return effect;
589
    }
590

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

    
593
  VertexEffect[] createVertexEffectsRexCorner()
594
    {
595
    Static3D center= new Static3D(0.0f, 0.0f, 0.0f);
596
    Static3D axisZ = new Static3D(0.0f, 0.0f, 1.0f);
597
    Static1D angle = new Static1D(225);
598

    
599
    VertexEffect[] effect = new VertexEffect[1];
600
    effect[0] = new VertexEffectRotate(angle, axisZ, center);
601

    
602
    return effect;
603
    }
604

    
605
///////////////////////////////////////////////////////////////////////////////////////////////////
606

    
607
  VertexEffect[] createVertexEffectsMegaminxEdge(float width, float height)
608
    {
609
    VertexEffect[] effect = new VertexEffect[11];
610

    
611
    float X = 0.5f*height;
612
    float Y = height*(COS54/COS18) + width*0.5f;
613
    float Z = 2*height*COS_HALFD;
614

    
615
    float alpha = 90-DIHEDRAL1/2;
616
    float beta  = DIHEDRAL2;
617

    
618
    Static1D angle1 = new Static1D(alpha);
619
    Static1D angle2 = new Static1D(180-alpha);
620
    Static1D angle3 = new Static1D(beta);
621

    
622
    Static3D move1 = new Static3D(X,0,0);
623
    Static3D move2 = new Static3D(X,0,-Z);
624
    Static3D move3 = new Static3D(0,+Y,0);
625
    Static3D move4 = new Static3D(0,-Y,0);
626
    Static3D scale = new Static3D(+1,+1,-1);
627

    
628
    Static3D axisXplus = new Static3D(+1, 0, 0);
629
    Static3D axisXminus= new Static3D(-1, 0, 0);
630
    Static3D axisYplus = new Static3D( 0,+1, 0);
631
    Static3D axisYminus= new Static3D( 0,-1, 0);
632

    
633
    Static3D center1= new Static3D( 0, 0, 0);
634
    Static3D center2= new Static3D( 0, 0,-Z);
635
    Static3D center3= new Static3D( 0,+width*0.5f, 0);
636
    Static3D center4= new Static3D( 0,-width*0.5f, 0);
637

    
638
    effect[ 0] = new VertexEffectMove(move1);
639
    effect[ 1] = new VertexEffectMove(move2);
640
    effect[ 2] = new VertexEffectMove(move3);
641
    effect[ 3] = new VertexEffectMove(move4);
642
    effect[ 4] = new VertexEffectScale(scale);
643
    effect[ 5] = new VertexEffectRotate(angle1, axisYplus , center1);
644
    effect[ 6] = new VertexEffectRotate(angle2, axisYplus , center1);
645
    effect[ 7] = new VertexEffectRotate(angle1, axisYminus, center2);
646
    effect[ 8] = new VertexEffectRotate(angle2, axisYminus, center2);
647
    effect[ 9] = new VertexEffectRotate(angle3, axisXplus , center3);
648
    effect[10] = new VertexEffectRotate(angle3, axisXminus, center4);
649

    
650
    effect[ 0].setMeshAssociation( 3,-1);  // meshes 0,1
651
    effect[ 1].setMeshAssociation(12,-1);  // meshes 2,3
652
    effect[ 2].setMeshAssociation(16,-1);  // mesh 4
653
    effect[ 3].setMeshAssociation(32,-1);  // mesh 5
654
    effect[ 4].setMeshAssociation( 2,-1);  // mesh 1
655
    effect[ 5].setMeshAssociation( 1,-1);  // mesh 0
656
    effect[ 6].setMeshAssociation( 2,-1);  // mesh 1
657
    effect[ 7].setMeshAssociation( 4,-1);  // mesh 2
658
    effect[ 8].setMeshAssociation( 8,-1);  // mesh 3
659
    effect[ 9].setMeshAssociation(16,-1);  // mesh 4
660
    effect[10].setMeshAssociation(32,-1);  // mesh 5
661

    
662
    return effect;
663
    }
664

    
665
///////////////////////////////////////////////////////////////////////////////////////////////////
666

    
667
  VertexEffect[] createVertexEffectsMegaminxCenter(float width)
668
    {
669
    VertexEffect[] effect = new VertexEffect[2];
670

    
671
    Static1D angle = new Static1D(DIHEDRAL2);
672
    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
673
    Static3D center= new Static3D( 0, 0, 0);
674

    
675
    effect[0] = new VertexEffectScale(width/COS54);
676
    effect[1] = new VertexEffectRotate(angle, axisX, center);
677

    
678
    return effect;
679
    }
680

    
681
///////////////////////////////////////////////////////////////////////////////////////////////////
682

    
683
  VertexEffect[] createCuboidEffects(int[] dimensions)
684
    {
685
    float X = dimensions[0];
686
    float Y = dimensions[1];
687
    float Z = dimensions[2];
688

    
689
    float MAX_XY = Math.max(X,Y);
690
    float MAX_XZ = Math.max(X,Z);
691
    float MAX_YZ = Math.max(Z,Y);
692

    
693
    Static1D angle = new Static1D(90);
694
    Static3D move  = new Static3D( 0.0f, 0.0f, 0.5f);
695
    Static3D axisX = new Static3D( 1.0f, 0.0f, 0.0f);
696
    Static3D axisY = new Static3D( 0.0f, 1.0f, 0.0f);
697
    Static3D center= new Static3D( 0.0f, 0.0f, 0.0f);
698

    
699
    Static3D scale3 = new Static3D(MAX_XY,MAX_XY,+Z);
700
    Static3D scale4 = new Static3D(MAX_XY,MAX_XY,-Z);
701
    Static3D scale5 = new Static3D(MAX_XZ,+Y,MAX_XZ);
702
    Static3D scale6 = new Static3D(MAX_XZ,-Y,MAX_XZ);
703
    Static3D scale7 = new Static3D(+X,MAX_YZ,MAX_YZ);
704
    Static3D scale8 = new Static3D(-X,MAX_YZ,MAX_YZ);
705

    
706
    VertexEffect[] effect = new VertexEffect[9];
707

    
708
    effect[0] = new VertexEffectMove(move);
709
    effect[1] = new VertexEffectRotate(angle, axisX, center);
710
    effect[2] = new VertexEffectRotate(angle, axisY, center);
711
    effect[3] = new VertexEffectScale(scale3);
712
    effect[4] = new VertexEffectScale(scale4);
713
    effect[5] = new VertexEffectScale(scale5);
714
    effect[6] = new VertexEffectScale(scale6);
715
    effect[7] = new VertexEffectScale(scale7);
716
    effect[8] = new VertexEffectScale(scale8);
717

    
718
    effect[1].setMeshAssociation(12,-1);  // meshes 2,3
719
    effect[2].setMeshAssociation( 3,-1);  // meshes 0,1
720
    effect[3].setMeshAssociation(16,-1);  // mesh 4
721
    effect[4].setMeshAssociation(32,-1);  // mesh 5
722
    effect[5].setMeshAssociation( 8,-1);  // mesh 3
723
    effect[6].setMeshAssociation( 4,-1);  // mesh 2
724
    effect[7].setMeshAssociation( 1,-1);  // mesh 0
725
    effect[8].setMeshAssociation( 2,-1);  // mesh 1
726

    
727
    return effect;
728
    }
729

    
730
///////////////////////////////////////////////////////////////////////////////////////////////////
731
// OBJECTS
732
///////////////////////////////////////////////////////////////////////////////////////////////////
733

    
734
  public MeshBase createIvyCornerMesh()
735
    {
736
    MeshBase mesh = createFacesIvyCorner();
737
    VertexEffect[] effects = createVertexEffectsIvyCorner();
738
    for( VertexEffect effect : effects ) mesh.apply(effect);
739

    
740
    Static3D center = new Static3D(-0.5f,-0.5f,-0.5f);
741
    Static3D[] vertices = new Static3D[4];
742
    vertices[0] = new Static3D(+0.0f,+0.0f,+0.0f);
743
    vertices[1] = new Static3D(-1.0f,+0.0f,+0.0f);
744
    vertices[2] = new Static3D(+0.0f,-1.0f,+0.0f);
745
    vertices[3] = new Static3D(+0.0f,+0.0f,-1.0f);
746

    
747
    roundCorners(mesh,center,vertices,0.03f,0.10f);
748

    
749
    mesh.mergeEffComponents();
750

    
751
    return mesh;
752
    }
753

    
754
///////////////////////////////////////////////////////////////////////////////////////////////////
755

    
756
  public MeshBase createIvyFaceMesh()
757
    {
758
    MeshBase mesh = createFacesIvyFace();
759

    
760
    Static3D center = new Static3D(-0.0f,-0.0f,-0.5f);
761
    Static3D[] vertices = new Static3D[2];
762
    vertices[0] = new Static3D(-0.5f,+0.5f,+0.0f);
763
    vertices[1] = new Static3D(+0.5f,-0.5f,+0.0f);
764

    
765
    roundCorners(mesh,center,vertices,0.03f,0.10f);
766

    
767
    mesh.mergeEffComponents();
768
    mesh.addEmptyTexComponent();
769
    mesh.addEmptyTexComponent();
770
    mesh.addEmptyTexComponent();
771
    mesh.addEmptyTexComponent();
772

    
773
    return mesh;
774
    }
775

    
776
///////////////////////////////////////////////////////////////////////////////////////////////////
777

    
778
  public MeshBase createRexCornerMesh()
779
    {
780
    MeshBase mesh = createFacesRexCorner();
781
    VertexEffect[] effects = createVertexEffectsRexCorner();
782
    for( VertexEffect effect : effects ) mesh.apply(effect);
783

    
784
    final float G = (1-REX_D)/3;
785
    Static3D center = new Static3D(0.0f,0.0f,-G*SQ2/2);
786
    Static3D[] vertices = new Static3D[1];
787
    vertices[0] = new Static3D(+G,-G,+0.0f);
788
    roundCorners(mesh,center,vertices,0.10f,0.10f);
789

    
790
    mesh.mergeEffComponents();
791
    mesh.addEmptyTexComponent();
792
    mesh.addEmptyTexComponent();
793
    mesh.addEmptyTexComponent();
794
    mesh.addEmptyTexComponent();
795

    
796
    return mesh;
797
    }
798

    
799
///////////////////////////////////////////////////////////////////////////////////////////////////
800

    
801
  public MeshBase createRexFaceMesh()
802
    {
803
    MeshBase mesh = createFacesRexFace();
804

    
805
    mesh.mergeEffComponents();
806
    mesh.addEmptyTexComponent();
807
    mesh.addEmptyTexComponent();
808
    mesh.addEmptyTexComponent();
809
    mesh.addEmptyTexComponent();
810

    
811
    return mesh;
812
    }
813

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

    
816
  public MeshBase createRexEdgeMesh()
817
    {
818
    MeshBase mesh = createFacesRexEdge();
819
    VertexEffect[] effects = createVertexEffectsRexEdge();
820
    for( VertexEffect effect : effects ) mesh.apply(effect);
821

    
822
    Static3D center = new Static3D(0.0f,-0.5f,-0.5f);
823
    Static3D[] vertices = new Static3D[2];
824
    vertices[0] = new Static3D(+0.5f,+0.0f,+0.0f);
825
    vertices[1] = new Static3D(-0.5f,+0.0f,+0.0f);
826
    roundCorners(mesh,center,vertices,0.06f,0.10f);
827

    
828
    mesh.mergeEffComponents();
829

    
830
    return mesh;
831
    }
832

    
833
///////////////////////////////////////////////////////////////////////////////////////////////////
834
// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
835
// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
836

    
837
  public MeshBase createMegaminxEdgeMesh(int numLayers, float width, float height)
838
    {
839
    MeshBase mesh = createFacesMegaminxEdge(numLayers,width,height);
840
    VertexEffect[] effects = createVertexEffectsMegaminxEdge(width,height);
841
    for( VertexEffect effect : effects ) mesh.apply(effect);
842

    
843
    mesh.mergeEffComponents();
844

    
845
    return mesh;
846
    }
847

    
848
///////////////////////////////////////////////////////////////////////////////////////////////////
849

    
850
  public MeshBase createMegaminxCenterMesh(int numLayers, float width)
851
    {
852
    MeshBase mesh = createFacesMegaminxCenter(numLayers);
853
    VertexEffect[] effects = createVertexEffectsMegaminxCenter(width);
854
    for( VertexEffect effect : effects ) mesh.apply(effect);
855

    
856
    mesh.mergeEffComponents();
857
    mesh.addEmptyTexComponent();
858
    mesh.addEmptyTexComponent();
859
    mesh.addEmptyTexComponent();
860
    mesh.addEmptyTexComponent();
861

    
862
    return mesh;
863
    }
864

    
865
///////////////////////////////////////////////////////////////////////////////////////////////////
866

    
867
  public MeshBase createCuboidMesh(int[] dimensions)
868
    {
869
    MeshBase mesh = createCuboid(dimensions);
870
    VertexEffect[] effects = createCuboidEffects(dimensions);
871
    for( VertexEffect effect : effects ) mesh.apply(effect);
872

    
873
    int X = dimensions[0];
874
    int Y = dimensions[1];
875
    int Z = dimensions[2];
876

    
877
    float strength = 0.04f;
878
    float radius   = 0.15f;
879

    
880
    Static3D[] vertices = new Static3D[1];
881
    Static3D center;
882

    
883
    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,+0.5f*Z);
884
    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
885
    roundCorners(mesh, center, vertices, strength, radius);
886

    
887
    vertices[0] = new Static3D(+0.5f*X,+0.5f*Y,-0.5f*Z);
888
    center = new Static3D(+0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
889
    roundCorners(mesh, center, vertices, strength, radius);
890

    
891
    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,+0.5f*Z);
892
    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
893
    roundCorners(mesh, center, vertices, strength, radius);
894

    
895
    vertices[0] = new Static3D(+0.5f*X,-0.5f*Y,-0.5f*Z);
896
    center = new Static3D(+0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
897
    roundCorners(mesh, center, vertices, strength, radius);
898

    
899
    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,+0.5f*Z);
900
    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),+0.5f*(Z-1));
901
    roundCorners(mesh, center, vertices, strength, radius);
902

    
903
    vertices[0] = new Static3D(-0.5f*X,+0.5f*Y,-0.5f*Z);
904
    center = new Static3D(-0.5f*(X-1),+0.5f*(Y-1),-0.5f*(Z-1));
905
    roundCorners(mesh, center, vertices, strength, radius);
906

    
907
    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,+0.5f*Z);
908
    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),+0.5f*(Z-1));
909
    roundCorners(mesh, center, vertices, strength, radius);
910

    
911
    vertices[0] = new Static3D(-0.5f*X,-0.5f*Y,-0.5f*Z);
912
    center = new Static3D(-0.5f*(X-1),-0.5f*(Y-1),-0.5f*(Z-1));
913
    roundCorners(mesh, center, vertices, strength, radius);
914

    
915
    mesh.mergeEffComponents();
916

    
917
    return mesh;
918
    }
919

    
920
///////////////////////////////////////////////////////////////////////////////////////////////////
921

    
922
  private boolean areColinear(double[][] vertices, int index1, int index2, int index3)
923
    {
924
    double x1 = vertices[index1][0];
925
    double y1 = vertices[index1][1];
926
    double z1 = vertices[index1][2];
927
    double x2 = vertices[index2][0];
928
    double y2 = vertices[index2][1];
929
    double z2 = vertices[index2][2];
930
    double x3 = vertices[index3][0];
931
    double y3 = vertices[index3][1];
932
    double z3 = vertices[index3][2];
933

    
934
    double v1x = x2-x1;
935
    double v1y = y2-y1;
936
    double v1z = z2-z1;
937
    double v2x = x3-x1;
938
    double v2y = y3-y1;
939
    double v2z = z3-z1;
940

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

    
943
    return (v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
944
    }
945

    
946
///////////////////////////////////////////////////////////////////////////////////////////////////
947

    
948
  private void computeNormalVector(double[][] vertices, int index1, int index2, int index3)
949
    {
950
    double x1 = vertices[index1][0];
951
    double y1 = vertices[index1][1];
952
    double z1 = vertices[index1][2];
953
    double x2 = vertices[index2][0];
954
    double y2 = vertices[index2][1];
955
    double z2 = vertices[index2][2];
956
    double x3 = vertices[index3][0];
957
    double y3 = vertices[index3][1];
958
    double z3 = vertices[index3][2];
959

    
960
    double v1x = x2-x1;
961
    double v1y = y2-y1;
962
    double v1z = z2-z1;
963
    double v2x = x3-x1;
964
    double v2y = y3-y1;
965
    double v2z = z3-z1;
966

    
967
    mBuffer[0] = v1y*v2z - v2y*v1z;
968
    mBuffer[1] = v1z*v2x - v2z*v1x;
969
    mBuffer[2] = v1x*v2y - v2x*v1y;
970

    
971
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
972
    len = Math.sqrt(len);
973
    mBuffer[0] /= len;
974
    mBuffer[1] /= len;
975
    mBuffer[2] /= len;
976
    }
977

    
978
///////////////////////////////////////////////////////////////////////////////////////////////////
979
// return quat1*quat2
980

    
981
  private static void quatMultiply( double[] quat1, double[] quat2, double[] result )
982
    {
983
    double qx = quat1[0];
984
    double qy = quat1[1];
985
    double qz = quat1[2];
986
    double qw = quat1[3];
987

    
988
    double rx = quat2[0];
989
    double ry = quat2[1];
990
    double rz = quat2[2];
991
    double rw = quat2[3];
992

    
993
    result[0] = rw*qx - rz*qy + ry*qz + rx*qw;
994
    result[1] = rw*qy + rz*qx + ry*qw - rx*qz;
995
    result[2] = rw*qz + rz*qw - ry*qx + rx*qy;
996
    result[3] = rw*qw - rz*qz - ry*qy - rx*qx;
997
    }
998

    
999
///////////////////////////////////////////////////////////////////////////////////////////////////
1000

    
1001
  private void fitInSquare(FaceTransform info, double[][] vert3D)
1002
    {
1003
    double minX = Double.MAX_VALUE;
1004
    double maxX =-Double.MAX_VALUE;
1005
    double minY = Double.MAX_VALUE;
1006
    double maxY =-Double.MAX_VALUE;
1007

    
1008
    for (double[] vert : vert3D)
1009
      {
1010
      double x = vert[0];
1011
      double y = vert[1];
1012

    
1013
      if (x > maxX) maxX = x;
1014
      if (x < minX) minX = x;
1015
      if (y > maxY) maxY = y;
1016
      if (y < minY) minY = y;
1017
      }
1018

    
1019
    minX = minX<0 ? -minX:minX;
1020
    maxX = maxX<0 ? -maxX:maxX;
1021
    minY = minY<0 ? -minY:minY;
1022
    maxY = maxY<0 ? -maxY:maxY;
1023

    
1024
    double max1 = Math.max(minX,minY);
1025
    double max2 = Math.max(maxX,maxY);
1026
    double max3 = Math.max(max1,max2);
1027

    
1028
    info.scale = max3/0.5;
1029

    
1030
    int len = vert3D.length;
1031
    StickerCoords sInfo = new StickerCoords();
1032
    sInfo.vertices = new double[2*len];
1033

    
1034
    for( int vertex=0; vertex<len; vertex++ )
1035
      {
1036
      sInfo.vertices[2*vertex  ] = vert3D[vertex][0] / info.scale;
1037
      sInfo.vertices[2*vertex+1] = vert3D[vertex][1] / info.scale;
1038
      }
1039

    
1040
    mStickerCoords.add(sInfo);
1041

    
1042
    info.sticker = mStickerCoords.size() -1;
1043
    info.flip = false;
1044
    }
1045

    
1046
///////////////////////////////////////////////////////////////////////////////////////////////////
1047

    
1048
  private FaceTransform constructNewTransform(final double[][] vert3D)
1049
    {
1050
    FaceTransform ft = new FaceTransform();
1051

    
1052
    // compute center of gravity
1053
    ft.vx = 0.0f;
1054
    ft.vy = 0.0f;
1055
    ft.vz = 0.0f;
1056
    int len = vert3D.length;
1057

    
1058
    for (double[] vert : vert3D)
1059
      {
1060
      ft.vx += vert[0];
1061
      ft.vy += vert[1];
1062
      ft.vz += vert[2];
1063
      }
1064

    
1065
    ft.vx /= len;
1066
    ft.vy /= len;
1067
    ft.vz /= len;
1068

    
1069
    // move all vertices so that their center of gravity is at (0,0,0)
1070
    for (int i=0; i<len; i++)
1071
      {
1072
      vert3D[i][0] -= ft.vx;
1073
      vert3D[i][1] -= ft.vy;
1074
      vert3D[i][2] -= ft.vz;
1075
      }
1076

    
1077
    // find 3 non-colinear vertices
1078
    int foundIndex = -1;
1079

    
1080
    for(int vertex=2; vertex<len; vertex++)
1081
      {
1082
      if( !areColinear(vert3D,0,1,vertex) )
1083
        {
1084
        foundIndex = vertex;
1085
        break;
1086
        }
1087
      }
1088

    
1089
    // compute the normal vector
1090
    if( foundIndex==-1 )
1091
      {
1092
      throw new RuntimeException("all vertices colinear");
1093
      }
1094

    
1095
    computeNormalVector(vert3D,0,1,foundIndex);
1096

    
1097
    // rotate so that the normal vector becomes (0,0,1)
1098
    double axisX, axisY, axisZ;
1099

    
1100
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
1101
      {
1102
      axisX = -mBuffer[1];
1103
      axisY =  mBuffer[0];
1104
      axisZ = 0.0f;
1105

    
1106
      double axiLen = axisX*axisX + axisY*axisY;
1107
      axiLen = Math.sqrt(axiLen);
1108
      axisX /= axiLen;
1109
      axisY /= axiLen;
1110
      axisZ /= axiLen;
1111
      }
1112
    else
1113
      {
1114
      axisX = 0.0f;
1115
      axisY = 1.0f;
1116
      axisZ = 0.0f;
1117
      }
1118

    
1119
    double cosTheta = mBuffer[2];
1120
    double sinTheta = Math.sqrt(1-cosTheta*cosTheta);
1121
    double sinHalfTheta = computeSinHalf(cosTheta);
1122
    double cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
1123

    
1124
    mQuat1[0] = axisX*sinHalfTheta;
1125
    mQuat1[1] = axisY*sinHalfTheta;
1126
    mQuat1[2] = axisZ*sinHalfTheta;
1127
    mQuat1[3] = cosHalfTheta;
1128
    mQuat2[0] =-axisX*sinHalfTheta;
1129
    mQuat2[1] =-axisY*sinHalfTheta;
1130
    mQuat2[2] =-axisZ*sinHalfTheta;
1131
    mQuat2[3] = cosHalfTheta;
1132

    
1133
    for (double[] vert : vert3D)
1134
      {
1135
      quatMultiply(mQuat1, vert  , mQuat3);
1136
      quatMultiply(mQuat3, mQuat2, vert  );
1137
      }
1138

    
1139
    // fit the whole thing in a square and remember the scale & 2D vertices
1140
    fitInSquare(ft, vert3D);
1141

    
1142
    // remember the rotation
1143
    ft.qx =-mQuat1[0];
1144
    ft.qy =-mQuat1[1];
1145
    ft.qz =-mQuat1[2];
1146
    ft.qw = mQuat1[3];
1147

    
1148
    return ft;
1149
    }
1150

    
1151
///////////////////////////////////////////////////////////////////////////////////////////////////
1152

    
1153
  private double computeCos(double oldX, double oldY, double newX, double newY, double len1, double len2)
1154
    {
1155
    double ret= (oldX*newX+oldY*newY) / (len1*len2);
1156
    if( ret<-1.0 ) return -1.0;
1157
    if( ret> 1.0 ) return  1.0;
1158

    
1159
    return ret;
1160
    }
1161

    
1162
///////////////////////////////////////////////////////////////////////////////////////////////////
1163
// sin of (signed!) angle between vectors 'old' and 'new', counterclockwise!
1164

    
1165
  private double computeSin(double oldX, double oldY, double newX, double newY, double len1, double len2)
1166
    {
1167
    double ret= (newX*oldY-oldX*newY) / (len1*len2);
1168
    if( ret<-1.0 ) return -1.0;
1169
    if( ret> 1.0 ) return  1.0;
1170

    
1171
    return ret;
1172
    }
1173

    
1174
///////////////////////////////////////////////////////////////////////////////////////////////////
1175

    
1176
  private void rotateAllVertices(double[] result, int len, double[] vertices, double sin, double cos)
1177
    {
1178
    for(int i=0; i<len; i++)
1179
      {
1180
      result[2*i  ] = vertices[2*i  ]*cos - vertices[2*i+1]*sin;
1181
      result[2*i+1] = vertices[2*i  ]*sin + vertices[2*i+1]*cos;
1182
      }
1183
    }
1184

    
1185
///////////////////////////////////////////////////////////////////////////////////////////////////
1186

    
1187
  private double computeScale(double[] v1, double[] v2, int v1i, int v2i)
1188
    {
1189
    double v1x = v1[2*v1i];
1190
    double v1y = v1[2*v1i+1];
1191
    double v2x = v2[2*v2i];
1192
    double v2y = v2[2*v2i+1];
1193

    
1194
    double lenSq1 = v1x*v1x + v1y*v1y;
1195
    double lenSq2 = v2x*v2x + v2y*v2y;
1196

    
1197
    return Math.sqrt(lenSq2/lenSq1);
1198
    }
1199

    
1200
///////////////////////////////////////////////////////////////////////////////////////////////////
1201
// valid for 0<angle<2*PI
1202

    
1203
  private double computeSinHalf(double cos)
1204
    {
1205
    return Math.sqrt((1-cos)/2);
1206
    }
1207

    
1208
///////////////////////////////////////////////////////////////////////////////////////////////////
1209
// valid for 0<angle<2*PI
1210

    
1211
  private double computeCosHalf(double sin, double cos)
1212
    {
1213
    double cosHalf = Math.sqrt((1+cos)/2);
1214
    return sin<0 ? -cosHalf : cosHalf;
1215
    }
1216

    
1217
///////////////////////////////////////////////////////////////////////////////////////////////////
1218

    
1219
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex, boolean inverted)
1220
    {
1221
    int v = (rotatedVertex + (inverted? -oldVertex : oldVertex));
1222
    if( v>=len ) v-=len;
1223
    if( v< 0   ) v+=len;
1224

    
1225
    return v;
1226
    }
1227

    
1228
///////////////////////////////////////////////////////////////////////////////////////////////////
1229

    
1230
  private boolean isScaledVersionOf(double[] newVert, double[] oldVert, int len, int vertex, boolean inverted)
1231
    {
1232
    int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
1233
    double EPSILON = 0.001;
1234
    double scale = computeScale(newVert,oldVert,newZeroIndex,0);
1235

    
1236
    for(int i=1; i<len; i++)
1237
      {
1238
      int index = computeRotatedIndex(i,len,vertex,inverted);
1239

    
1240
      double horz = oldVert[2*i  ] - scale*newVert[2*index  ];
1241
      double vert = oldVert[2*i+1] - scale*newVert[2*index+1];
1242

    
1243
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
1244
      }
1245

    
1246
    return true;
1247
    }
1248

    
1249
///////////////////////////////////////////////////////////////////////////////////////////////////
1250

    
1251
  private void mirrorAllVertices(double[] output, int len, double[] input)
1252
    {
1253
    for(int vertex=0; vertex<len; vertex++)
1254
      {
1255
      output[2*vertex  ] = input[2*vertex  ];
1256
      output[2*vertex+1] =-input[2*vertex+1];
1257
      }
1258
    }
1259

    
1260
///////////////////////////////////////////////////////////////////////////////////////////////////
1261

    
1262
  private void correctInfo(FaceTransform info, double scale, double sin, double cos, int oldSticker, boolean flip)
1263
    {
1264
    mStickerCoords.remove(info.sticker);
1265

    
1266
    info.flip    = flip;
1267
    info.sticker = oldSticker;
1268
    info.scale  *= scale;
1269

    
1270
    mQuat1[0] = info.qx;
1271
    mQuat1[1] = info.qy;
1272
    mQuat1[2] = info.qz;
1273
    mQuat1[3] = info.qw;
1274

    
1275
    double sinHalf = computeSinHalf(cos);
1276
    double cosHalf = computeCosHalf(sin,cos);
1277

    
1278
    if( flip )
1279
      {
1280
      mQuat3[0] = 0.0f;
1281
      mQuat3[1] = 0.0f;
1282
      mQuat3[2] = sinHalf;
1283
      mQuat3[3] = cosHalf;
1284

    
1285
      mQuat4[0] = 1.0;
1286
      mQuat4[1] = 0.0;
1287
      mQuat4[2] = 0.0;
1288
      mQuat4[3] = 0.0;
1289

    
1290
      quatMultiply( mQuat3, mQuat4, mQuat2 );
1291
      }
1292
    else
1293
      {
1294
      mQuat2[0] = 0.0f;
1295
      mQuat2[1] = 0.0f;
1296
      mQuat2[2] = sinHalf;
1297
      mQuat2[3] = cosHalf;
1298
      }
1299

    
1300
    quatMultiply( mQuat1, mQuat2, mQuat3 );
1301

    
1302
    info.qx = mQuat3[0];
1303
    info.qy = mQuat3[1];
1304
    info.qz = mQuat3[2];
1305
    info.qw = mQuat3[3];
1306
    }
1307

    
1308
///////////////////////////////////////////////////////////////////////////////////////////////////
1309

    
1310
  private void printVert(double[] buffer)
1311
    {
1312
    int len = buffer.length/2;
1313
    String str = "";
1314

    
1315
    for(int i=0; i<len; i++)
1316
      {
1317
      str += (" ("+buffer[2*i]+" , "+buffer[2*i+1]+" ) ");
1318
      }
1319

    
1320
    android.util.Log.d("D", str);
1321
    }
1322

    
1323
///////////////////////////////////////////////////////////////////////////////////////////////////
1324

    
1325
  private boolean foundVertex(FaceTransform info, double[] buffer, int len, double[] newVert,
1326
                              double[] oldVert, double lenFirstOld, int oldSticker, boolean inverted)
1327
    {
1328
    for(int vertex=0; vertex<len; vertex++)
1329
      {
1330
      double newX = newVert[2*vertex  ];
1331
      double newY = newVert[2*vertex+1];
1332
      double lenIthNew = Math.sqrt(newX*newX + newY*newY);
1333
      double cos = computeCos( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
1334
      double sin = computeSin( oldVert[0], oldVert[1], newX, newY, lenIthNew, lenFirstOld);
1335

    
1336
      rotateAllVertices(buffer,len,newVert,sin,cos);
1337

    
1338
      if( isScaledVersionOf(buffer,oldVert,len,vertex,inverted) )
1339
        {
1340
        int newZeroIndex = computeRotatedIndex(0,len,vertex,inverted);
1341
        double scale = computeScale(oldVert,newVert,0,newZeroIndex);
1342
        correctInfo(info,scale,sin,cos,oldSticker,inverted);
1343
        return true;
1344
        }
1345
      }
1346

    
1347
    return false;
1348
    }
1349

    
1350
///////////////////////////////////////////////////////////////////////////////////////////////////
1351

    
1352
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
1353
    {
1354
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
1355
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
1356
    double[] newVert = sNewInfo.vertices;
1357
    double[] oldVert = sOldInfo.vertices;
1358
    int oldLen = oldVert.length;
1359
    int newLen = newVert.length;
1360

    
1361
    if( oldLen == newLen )
1362
      {
1363
      int oldSticker = oldInfo.sticker;
1364
      double[] buffer1 = new double[oldLen];
1365
      double lenFirstOld = Math.sqrt(oldVert[0]*oldVert[0] + oldVert[1]*oldVert[1]);
1366
      if( foundVertex(newInfo, buffer1, oldLen/2, newVert, oldVert, lenFirstOld, oldSticker, false) ) return true;
1367
      double[] buffer2 = new double[oldLen];
1368
      mirrorAllVertices(buffer2, newLen/2, newVert);
1369
      if( foundVertex(newInfo, buffer1, oldLen/2, buffer2, oldVert, lenFirstOld, oldSticker, true ) ) return true;
1370
      }
1371

    
1372
    return false;
1373
    }
1374

    
1375
///////////////////////////////////////////////////////////////////////////////////////////////////
1376

    
1377
  private double[][] constructVert(double[][] vertices, int[] index)
1378
    {
1379
    int len = index.length;
1380
    double[][] ret = new double[len][4];
1381

    
1382
    for(int i=0; i<len; i++)
1383
      {
1384
      ret[i][0] = vertices[index[i]][0];
1385
      ret[i][1] = vertices[index[i]][1];
1386
      ret[i][2] = vertices[index[i]][2];
1387
      ret[i][3] = 1.0f;
1388
      }
1389

    
1390
    return ret;
1391
    }
1392

    
1393
///////////////////////////////////////////////////////////////////////////////////////////////////
1394

    
1395
  private void prepareAndRoundCorners(MeshBase mesh, double[][] vertices,
1396
                                      float[][] corners, int[] cornerIndexes,
1397
                                      float[][] centers, int[] centerIndexes )
1398
    {
1399
    int lenV = vertices.length;
1400
    Static3D[] staticVert = new Static3D[1];
1401
    Static3D center = new Static3D(0,0,0);
1402

    
1403
    for(int v=0; v<lenV; v++)
1404
      {
1405
      staticVert[0] = new Static3D( (float)vertices[v][0], (float)vertices[v][1], (float)vertices[v][2]);
1406

    
1407
      int cent = centerIndexes[v];
1408

    
1409
      if( cent>=0 )
1410
        {
1411
        center.set( centers[cent][0], centers[cent][1], centers[cent][2]);
1412

    
1413
        int corn = cornerIndexes[v];
1414
        float strength = corners[corn][0];
1415
        float radius   = corners[corn][1];
1416

    
1417
        roundCorners(mesh, center, staticVert, strength, radius);
1418
        }
1419
      }
1420
    }
1421

    
1422
///////////////////////////////////////////////////////////////////////////////////////////////////
1423

    
1424
  private void correctComponents(MeshBase mesh, int numComponents)
1425
    {
1426
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
1427

    
1428
    mesh.mergeEffComponents();
1429

    
1430
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
1431
    }
1432

    
1433
///////////////////////////////////////////////////////////////////////////////////////////////////
1434

    
1435
  private void printTransform(FaceTransform f)
1436
    {
1437
    android.util.Log.e("D", "q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("
1438
                       +f.vx+", "+f.vy+", "+f.vz+") scale="+f.scale+" sticker="+f.sticker);
1439
    }
1440

    
1441
///////////////////////////////////////////////////////////////////////////////////////////////////
1442
// PUBLIC
1443

    
1444
  public void printStickerCoords()
1445
    {
1446
    int stickers = mStickerCoords.size();
1447

    
1448
    android.util.Log.d("D", "---- STICKER COORDS ----");
1449

    
1450
    for(int s=0; s<stickers; s++)
1451
      {
1452
      String ver = "{ ";
1453
      StickerCoords info = mStickerCoords.get(s);
1454
      int len = info.vertices.length/2;
1455

    
1456
      for(int i =0; i<len; i++)
1457
        {
1458
        if( i!=0 ) ver += ", ";
1459
        ver += ( (float)info.vertices[2*i]+"f, "+(float)info.vertices[2*i+1]+"f");
1460
        }
1461

    
1462
      ver += " }";
1463
      android.util.Log.d("D", ver);
1464
      }
1465

    
1466
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1467
    }
1468

    
1469
///////////////////////////////////////////////////////////////////////////////////////////////////
1470

    
1471
  public void printFaceTransform()
1472
    {
1473
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1474

    
1475
    int oldfaces = mOldFaceTransf.size();
1476

    
1477
    for(int f=0; f<oldfaces; f++)
1478
      {
1479
      printTransform(mOldFaceTransf.get(f));
1480
      }
1481

    
1482
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1483

    
1484
    int newfaces = mNewFaceTransf.size();
1485

    
1486
    for(int f=0; f<newfaces; f++)
1487
      {
1488
      printTransform(mNewFaceTransf.get(f));
1489
      }
1490
    }
1491

    
1492
///////////////////////////////////////////////////////////////////////////////////////////////////
1493

    
1494
  public void clear()
1495
    {
1496
    mStickerCoords.clear();
1497
    mNewFaceTransf.clear();
1498
    mOldFaceTransf.clear();
1499
    }
1500

    
1501
///////////////////////////////////////////////////////////////////////////////////////////////////
1502

    
1503
  public void createNewFaceTransform( final double[][] vertices, final int[][] indexes)
1504
    {
1505
    FaceTransform ft;
1506
    int numNew = mNewFaceTransf.size();
1507

    
1508
    for(int i=0; i<numNew; i++)
1509
      {
1510
      ft = mNewFaceTransf.remove(0);
1511
      mOldFaceTransf.add(ft);
1512
      }
1513

    
1514
    int numFaces = indexes.length;
1515
    int numOld = mOldFaceTransf.size();
1516

    
1517
    for (int face=0; face<numFaces; face++)
1518
      {
1519
      boolean collapsed = false;
1520

    
1521
      double[][] vert = constructVert(vertices, indexes[face]);
1522
      FaceTransform newT = constructNewTransform(vert);
1523

    
1524
      for (int old=0; !collapsed && old<numOld; old++)
1525
        {
1526
        ft = mOldFaceTransf.get(old);
1527
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1528
        }
1529

    
1530
      for (int pre=0; !collapsed && pre<face; pre++)
1531
        {
1532
        ft = mNewFaceTransf.get(pre);
1533
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1534
        }
1535

    
1536
      mNewFaceTransf.add(newT);
1537
      }
1538

    
1539
    printStickerCoords();
1540
    }
1541

    
1542
///////////////////////////////////////////////////////////////////////////////////////////////////
1543

    
1544
  public MeshBase createRoundedSolid(final double[][] vertices, final int[][] vertIndexes,
1545
                                     final float[][] bands    , final int[]   bandIndexes,
1546
                                     final float[][] corners  , final int[]   cornerIndexes,
1547
                                     final float[][] centers  , final int[]   centerIndexes,
1548
                                     final int numComponents )
1549
    {
1550
    int numFaces = vertIndexes.length;
1551
    float[] band, bandsComputed;
1552
    MeshBase[] meshes = new MeshBase[numFaces];
1553
    FaceTransform fInfo;
1554
    StickerCoords sInfo;
1555

    
1556
    for(int face=0; face<numFaces; face++)
1557
      {
1558
      fInfo = mNewFaceTransf.get(face);
1559
      sInfo = mStickerCoords.get(fInfo.sticker);
1560

    
1561
      double[] verts = sInfo.vertices;
1562
      int lenVerts = verts.length;
1563
      float[] vertsFloat = new float[lenVerts];
1564
      for(int i=0; i<lenVerts; i++) vertsFloat[i] = (float)verts[i];
1565

    
1566
      band = bands[bandIndexes[face]];
1567
      bandsComputed = computeBands( band[0], (int)band[1], band[2], band[3], (int)band[4]);
1568
      meshes[face] = new MeshPolygon(vertsFloat,bandsComputed,(int)band[5],(int)band[6]);
1569
      meshes[face].setEffectAssociation(0,(1<<face),0);
1570
      }
1571

    
1572
    MeshBase mesh = new MeshJoined(meshes);
1573
    Static3D center = new Static3D(0,0,0);
1574

    
1575
    for(int face=0; face<numFaces; face++)
1576
      {
1577
      int assoc = (1<<face);
1578
      fInfo = mNewFaceTransf.get(face);
1579

    
1580
      float vx = (float)fInfo.vx;
1581
      float vy = (float)fInfo.vy;
1582
      float vz = (float)fInfo.vz;
1583
      float sc = (float)fInfo.scale;
1584
      float qx = (float)fInfo.qx;
1585
      float qy = (float)fInfo.qy;
1586
      float qz = (float)fInfo.qz;
1587
      float qw = (float)fInfo.qw;
1588

    
1589
      Static3D scale = new Static3D(sc,sc, fInfo.flip ? -sc : sc);
1590
      Static3D move3D= new Static3D(vx,vy,vz);
1591
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1592

    
1593
      mesh.apply(new MatrixEffectScale(scale)           ,assoc,-1);
1594
      mesh.apply(new MatrixEffectQuaternion(quat,center),assoc,-1);
1595
      mesh.apply(new MatrixEffectMove(move3D)           ,assoc,-1);
1596
      }
1597

    
1598
    prepareAndRoundCorners(mesh, vertices, corners, cornerIndexes, centers, centerIndexes);
1599

    
1600
    correctComponents(mesh,numComponents);
1601

    
1602
    return mesh;
1603
    }
1604
  }
(3-3/4)