Project

General

Profile

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

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

1 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6 a7a40b3c Leszek Koltunski
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
9
10 198c5bf0 Leszek Koltunski
package org.distorted.objectlib.helpers;
11 29b82486 Leszek Koltunski
12 84a17011 Leszek Koltunski
import org.distorted.library.effect.EffectName;
13 29b82486 Leszek Koltunski
import org.distorted.library.effect.MatrixEffectMove;
14
import org.distorted.library.effect.MatrixEffectQuaternion;
15
import org.distorted.library.effect.MatrixEffectScale;
16
import org.distorted.library.effect.VertexEffect;
17 aacf5e27 Leszek Koltunski
import org.distorted.library.helpers.QuatHelper;
18 29b82486 Leszek Koltunski
import org.distorted.library.mesh.MeshBase;
19
import org.distorted.library.mesh.MeshJoined;
20 fe3dec09 Leszek Koltunski
import org.distorted.library.mesh.MeshMultigon;
21 29b82486 Leszek Koltunski
import org.distorted.library.mesh.MeshPolygon;
22
import org.distorted.library.type.Static3D;
23
import org.distorted.library.type.Static4D;
24
25
import java.util.ArrayList;
26
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28
29
public class FactoryCubit
30
  {
31
  private static FactoryCubit mThis;
32
33 d99de43c Leszek Koltunski
  private static final float MAX_CORE_DIFF = 0.01f;
34
35 57ef6378 Leszek Koltunski
  private static final float[] mBuffer = new float[3];
36
  private static final float[] mQuat1  = new float[4];
37
  private static final float[] mQuat2  = new float[4];
38
  private static final float[] mQuat3  = new float[4];
39 29b82486 Leszek Koltunski
40 80fd07aa Leszek Koltunski
  public static final String NAME = EffectName.DEFORM.name();
41 84a17011 Leszek Koltunski
42 fe3dec09 Leszek Koltunski
  private static class StickerCoords
43 29b82486 Leszek Koltunski
    {
44 08bf6b98 leszek
    float[][][] outerVertices;
45 4b9d1df5 leszek
    float[][][] fullVertices;
46 1561a74f Leszek Koltunski
    float scale;
47 2617d26b Leszek Koltunski
    boolean outer;
48 29b82486 Leszek Koltunski
    }
49
50
  private static class FaceTransform
51
    {
52 7af68038 Leszek Koltunski
    int face;
53
    int numFaces;
54
55 29b82486 Leszek Koltunski
    int sticker;
56 57ef6378 Leszek Koltunski
    float vx,vy,vz;
57
    float scale;
58
    float qx,qy,qz,qw;
59 29b82486 Leszek Koltunski
    }
60
61
  private static final ArrayList<FaceTransform> mNewFaceTransf = new ArrayList<>();
62
  private static final ArrayList<FaceTransform> mOldFaceTransf = new ArrayList<>();
63
  private static final ArrayList<StickerCoords> mStickerCoords = new ArrayList<>();
64
65
///////////////////////////////////////////////////////////////////////////////////////////////////
66
67
  private FactoryCubit()
68
    {
69 3bf19410 Leszek Koltunski
70 29b82486 Leszek Koltunski
    }
71
72
///////////////////////////////////////////////////////////////////////////////////////////////////
73
// H - height of the band in the middle
74
// alpha - angle of the edge  [0,90]
75
// dist - often in a polygon the distance from edge to center is not 1, but something else.
76
// This is the distance.
77
// K - where to begin the second, much more flat part of the band. [0,1]
78
// N - number of bands. N>=3
79
//
80
// theory: two distinct parts to the band:
81
// 1) (0,B) - steep
82
// 2) (B,1) - flat
83
//
84
// In first part, we have y = g(x) ; in second - y = g(f(x)) where
85
//
86
// g(x) = sqrt( R^2 - (x-D)^2 ) - R*cos(alpha)
87
// f(x) = ((D-B)/(1-B)*x + B*(1-D)/(1-B)
88
// h(x) = R*(sin(alpha) - sin(x))
89
// R = H/(1-cos(alpha))
90
// D = H*sin(alpha)
91
// B = h(K*alpha)
92
//
93
// The N points are taken at:
94
//
95
// 1) in the second part, there are K2 = (N-3)/3 such points
96
// 2) in the first - K1 = (N-3) - K2
97
// 3) also, the 3 points 0,B,1
98
//
99
// so we have the sequence A[i] of N points
100
//
101
// 0
102
// h((i+1)*(1-K)*alpha/(K1+1)) (i=0,1,...,K1-1)
103
// B
104
// (1-B)*(i+1)/(K2+1) + B   (i=0,i,...,K2-1)
105
// 1
106
107
///////////////////////////////////////////////////////////////////////////////////////////////////
108
109
  private float f(float D, float B, float x)
110
    {
111
    return ((D-B)*x + B*(1-D))/(1-B);
112
    }
113
114
///////////////////////////////////////////////////////////////////////////////////////////////////
115
116
  private float g(float R, float D, float x, float cosAlpha)
117
    {
118
    float d = x-D;
119
    return (float)(Math.sqrt(R*R-d*d)-R*cosAlpha);
120
    }
121
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123
124
  private float h(float R, float sinAlpha, float x)
125
    {
126
    return R*(sinAlpha-(float)Math.sin(x));
127
    }
128
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130
131 4b9d1df5 leszek
  private boolean areNotColinear(float[][] vertices, int index)
132 29b82486 Leszek Koltunski
    {
133 4b9d1df5 leszek
    float x1 = vertices[0][0];
134
    float y1 = vertices[0][1];
135
    float z1 = vertices[0][2];
136
    float x2 = vertices[1][0];
137
    float y2 = vertices[1][1];
138
    float z2 = vertices[1][2];
139
    float x3 = vertices[index][0];
140
    float y3 = vertices[index][1];
141
    float z3 = vertices[index][2];
142 29b82486 Leszek Koltunski
143 57ef6378 Leszek Koltunski
    float v1x = x2-x1;
144
    float v1y = y2-y1;
145
    float v1z = z2-z1;
146
    float v2x = x3-x1;
147
    float v2y = y3-y1;
148
    float v2z = z3-z1;
149 29b82486 Leszek Koltunski
150
    double A = Math.sqrt( (v1x*v1x+v1y*v1y+v1z*v1z) / (v2x*v2x+v2y*v2y+v2z*v2z) );
151
152 7e9a35eb leszek
    return !(v1x==A*v2x && v1y==A*v2y && v1z==A*v2z);
153 29b82486 Leszek Koltunski
    }
154
155
///////////////////////////////////////////////////////////////////////////////////////////////////
156
157 4b9d1df5 leszek
  private void computeNormalVector(float[][] vertices, int index)
158 29b82486 Leszek Koltunski
    {
159 4b9d1df5 leszek
    float x1 = vertices[0][0];
160
    float y1 = vertices[0][1];
161
    float z1 = vertices[0][2];
162
    float x2 = vertices[1][0];
163
    float y2 = vertices[1][1];
164
    float z2 = vertices[1][2];
165
    float x3 = vertices[index][0];
166
    float y3 = vertices[index][1];
167
    float z3 = vertices[index][2];
168 29b82486 Leszek Koltunski
169 57ef6378 Leszek Koltunski
    float v1x = x2-x1;
170
    float v1y = y2-y1;
171
    float v1z = z2-z1;
172
    float v2x = x3-x1;
173
    float v2y = y3-y1;
174
    float v2z = z3-z1;
175 29b82486 Leszek Koltunski
176
    mBuffer[0] = v1y*v2z - v2y*v1z;
177
    mBuffer[1] = v1z*v2x - v2z*v1x;
178
    mBuffer[2] = v1x*v2y - v2x*v1y;
179
180
    double len = mBuffer[0]*mBuffer[0] + mBuffer[1]*mBuffer[1] + mBuffer[2]*mBuffer[2];
181
    len = Math.sqrt(len);
182
    mBuffer[0] /= len;
183
    mBuffer[1] /= len;
184
    mBuffer[2] /= len;
185 f4ed769a leszek
186
    // this theoretically should be uncommented to combat the same effect like in
187
    // TouchControlShapeChanging.FaceInfo, but when I try, the center sticker of
188
    // CoinTetrahedron gets inverted. Weird!
189
    // Uncommenting this does fix the fact that the convexity of the center cubits
190
    // of CoinT and CoinH goes concave
191
192
/*
193
    if( totalAngle(vertices,mBuffer)<0 )
194
      {
195
      mBuffer[0] *= -1;
196
      mBuffer[1] *= -1;
197
      mBuffer[2] *= -1;
198
      }
199
 */
200
    }
201
202
///////////////////////////////////////////////////////////////////////////////////////////////////
203
// this returns the total angle we get rotated about when we travel from the first vert to the last.
204
// It's always should be +2PI or -2PI, depending on if the verts are CW or CCW (when looking at the
205
// plane formed by the vertices from the direction the 'normal' vector points towards)
206
//
207
// The point: this way we can detect if the 'normal' vector is correct, i.e. if it points in the
208
// right direction.
209
// Sometimes it doesn't, when the first three vertices (from which the vector is computed) are 'concave'.
210
211
  public static float totalAngle(float[][] vert, float[] normal)
212
    {
213
    float ret = 0;
214
    int num = vert.length;
215
216
    for(int c=0; c<num; c++)
217
      {
218
      int n = (c==num-1 ? 0 : c+1);
219
      int m = (n==num-1 ? 0 : n+1);
220
      ret += angle( vert[c],vert[n],vert[m], normal);
221
      }
222
223
    return ret;
224
    }
225
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227
228
  private static float angle(float[] v0, float[] v1, float[] v2, float[] normal)
229
    {
230
    float px = v1[0] - v0[0];
231
    float py = v1[1] - v0[1];
232
    float pz = v1[2] - v0[2];
233
234
    float rx = v2[0] - v1[0];
235
    float ry = v2[1] - v1[1];
236
    float rz = v2[2] - v1[2];
237
238
    float l1 = (float)Math.sqrt(px*px + py*py + pz*pz);
239
    float l2 = (float)Math.sqrt(rx*rx + ry*ry + rz*rz);
240
241
    px /= l1;
242
    py /= l1;
243
    pz /= l1;
244
245
    rx /= l2;
246
    ry /= l2;
247
    rz /= l2;
248
249
    float s = px*rx + py*ry + pz*rz;
250
251
    if( s> 1 ) s= 1;
252
    if( s<-1 ) s=-1;
253
254
    float a = (float) Math.acos(s);
255
    float[] cross = crossProduct(px,py,pz,rx,ry,rz);
256
257
    float ax = cross[0] + normal[0];
258
    float ay = cross[1] + normal[1];
259
    float az = cross[2] + normal[2];
260
261
    float bx = cross[0] - normal[0];
262
    float by = cross[1] - normal[1];
263
    float bz = cross[2] - normal[2];
264
265
    float f1 = ax*ax + ay*ay + az*az;
266
    float f2 = bx*bx + by*by + bz*bz;
267
268
    return f1>f2 ? a : -a;
269
    }
270
271
///////////////////////////////////////////////////////////////////////////////////////////////////
272
273
  private static float[] crossProduct(float a1, float a2, float a3, float b1, float b2, float b3)
274
    {
275
    float[] ret = new float[3];
276
277
    ret[0] = a2*b3 - a3*b2;
278
    ret[1] = a3*b1 - a1*b3;
279
    ret[2] = a1*b2 - a2*b1;
280
281
    return ret;
282 29b82486 Leszek Koltunski
    }
283
284 fe3dec09 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
285
286 08bf6b98 leszek
  private float[][][] computeOuterEdge(float[][][] vertices)
287 fe3dec09 Leszek Koltunski
    {
288 7e9a35eb leszek
    int[][] edgesUp = MeshMultigon.computeEdgesUp(vertices);
289 08bf6b98 leszek
    return MeshMultigon.computeOuterAndHoleVertices(vertices,edgesUp);
290 fe3dec09 Leszek Koltunski
    }
291
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293
// polygon
294
295 2617d26b Leszek Koltunski
  private void fitInSquare(FaceTransform info, float[][] vert3D, boolean isOuter)
296 29b82486 Leszek Koltunski
    {
297 57ef6378 Leszek Koltunski
    float minX = Float.MAX_VALUE;
298
    float maxX =-Float.MAX_VALUE;
299
    float minY = Float.MAX_VALUE;
300
    float maxY =-Float.MAX_VALUE;
301 29b82486 Leszek Koltunski
302 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
303 29b82486 Leszek Koltunski
      {
304 57ef6378 Leszek Koltunski
      float x = vert[0];
305
      float y = vert[1];
306 29b82486 Leszek Koltunski
307
      if (x > maxX) maxX = x;
308
      if (x < minX) minX = x;
309
      if (y > maxY) maxY = y;
310
      if (y < minY) minY = y;
311
      }
312
313
    minX = minX<0 ? -minX:minX;
314
    maxX = maxX<0 ? -maxX:maxX;
315
    minY = minY<0 ? -minY:minY;
316
    maxY = maxY<0 ? -maxY:maxY;
317
318 57ef6378 Leszek Koltunski
    float max1 = Math.max(minX,minY);
319
    float max2 = Math.max(maxX,maxY);
320
    float max3 = Math.max(max1,max2);
321 29b82486 Leszek Koltunski
322 57ef6378 Leszek Koltunski
    info.scale = max3/0.5f;
323 29b82486 Leszek Koltunski
324
    int len = vert3D.length;
325
    StickerCoords sInfo = new StickerCoords();
326 2617d26b Leszek Koltunski
    sInfo.outer = isOuter;
327 1561a74f Leszek Koltunski
    sInfo.scale = info.scale;
328 08bf6b98 leszek
    sInfo.outerVertices = new float[1][len][2];
329 fe3dec09 Leszek Koltunski
    sInfo.fullVertices = null;
330 29b82486 Leszek Koltunski
331 9567a9ae leszek
    float[][] t = sInfo.outerVertices[0];
332
333 29b82486 Leszek Koltunski
    for( int vertex=0; vertex<len; vertex++ )
334
      {
335 9567a9ae leszek
      t[vertex][0] = vert3D[vertex][0] / info.scale;
336
      t[vertex][1] = vert3D[vertex][1] / info.scale;
337 29b82486 Leszek Koltunski
      }
338
339
    mStickerCoords.add(sInfo);
340
341
    info.sticker = mStickerCoords.size() -1;
342
    }
343
344 fe3dec09 Leszek Koltunski
345 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
346 fe3dec09 Leszek Koltunski
// multigon
347
348
  private void fitInSquare(FaceTransform info, float[][][] vert3D, boolean isOuter)
349
    {
350
    float minX = Float.MAX_VALUE;
351
    float maxX =-Float.MAX_VALUE;
352
    float minY = Float.MAX_VALUE;
353
    float maxY =-Float.MAX_VALUE;
354
355
    for( float[][] vert : vert3D)
356
      for( float[] v : vert)
357
        {
358
        float x = v[0];
359
        float y = v[1];
360
361
        if (x > maxX) maxX = x;
362
        if (x < minX) minX = x;
363
        if (y > maxY) maxY = y;
364
        if (y < minY) minY = y;
365
        }
366
367
    minX = minX<0 ? -minX:minX;
368
    maxX = maxX<0 ? -maxX:maxX;
369
    minY = minY<0 ? -minY:minY;
370
    maxY = maxY<0 ? -maxY:maxY;
371
372
    float max1 = Math.max(minX,minY);
373
    float max2 = Math.max(maxX,maxY);
374
    float max3 = Math.max(max1,max2);
375
376
    info.scale = max3/0.5f;
377
378
    int len = vert3D.length;
379
    StickerCoords sInfo = new StickerCoords();
380
    sInfo.outer = isOuter;
381
    sInfo.scale = info.scale;
382 4b9d1df5 leszek
    sInfo.fullVertices = new float[len][][];
383 fe3dec09 Leszek Koltunski
384
    for( int comp=0; comp<len; comp++ )
385
      {
386
      float[][] vert = vert3D[comp];
387
      int num = vert.length;
388 4b9d1df5 leszek
      sInfo.fullVertices[comp] = new float[num][2];
389
      float[][] t = sInfo.fullVertices[comp];
390 fe3dec09 Leszek Koltunski
391
      for( int vertex=0; vertex<num; vertex++)
392
        {
393 4b9d1df5 leszek
        t[vertex][0] = vert[vertex][0] / info.scale;
394
        t[vertex][1] = vert[vertex][1] / info.scale;
395 fe3dec09 Leszek Koltunski
        }
396
      }
397
398 08bf6b98 leszek
    sInfo.outerVertices = computeOuterEdge(sInfo.fullVertices);
399 fe3dec09 Leszek Koltunski
400
    mStickerCoords.add(sInfo);
401
402
    info.sticker = mStickerCoords.size() -1;
403
    }
404
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406
// polygon
407 29b82486 Leszek Koltunski
408 7af68038 Leszek Koltunski
  private FaceTransform constructNewTransform(final float[][] vert3D, boolean isOuter, int face, int numFaces)
409 29b82486 Leszek Koltunski
    {
410
    FaceTransform ft = new FaceTransform();
411 7af68038 Leszek Koltunski
    ft.face = face;
412
    ft.numFaces = numFaces;
413 29b82486 Leszek Koltunski
414
    // compute center of gravity
415
    ft.vx = 0.0f;
416
    ft.vy = 0.0f;
417
    ft.vz = 0.0f;
418
    int len = vert3D.length;
419
420 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
421 29b82486 Leszek Koltunski
      {
422
      ft.vx += vert[0];
423
      ft.vy += vert[1];
424
      ft.vz += vert[2];
425
      }
426
427
    ft.vx /= len;
428
    ft.vy /= len;
429
    ft.vz /= len;
430
431
    // move all vertices so that their center of gravity is at (0,0,0)
432
    for (int i=0; i<len; i++)
433
      {
434
      vert3D[i][0] -= ft.vx;
435
      vert3D[i][1] -= ft.vy;
436
      vert3D[i][2] -= ft.vz;
437
      }
438
439
    // find 3 non-colinear vertices
440
    int foundIndex = -1;
441
442
    for(int vertex=2; vertex<len; vertex++)
443
      {
444 4b9d1df5 leszek
      if( areNotColinear(vert3D,vertex) )
445 29b82486 Leszek Koltunski
        {
446
        foundIndex = vertex;
447
        break;
448
        }
449
      }
450
451
    // compute the normal vector
452
    if( foundIndex==-1 )
453
      {
454 03410dc1 Leszek Koltunski
      StringBuilder sb = new StringBuilder();
455
456 8e80135b Leszek Koltunski
      for (float[] floats : vert3D)
457 03410dc1 Leszek Koltunski
        {
458
        sb.append(' ');
459
        sb.append("(");
460 8e80135b Leszek Koltunski
        sb.append(floats[0]);
461 03410dc1 Leszek Koltunski
        sb.append(" ");
462 8e80135b Leszek Koltunski
        sb.append(floats[1]);
463 03410dc1 Leszek Koltunski
        sb.append(" ");
464 8e80135b Leszek Koltunski
        sb.append(floats[2]);
465 03410dc1 Leszek Koltunski
        sb.append(")");
466
        }
467
      android.util.Log.e("D", "verts: "+sb);
468
469 29b82486 Leszek Koltunski
      throw new RuntimeException("all vertices colinear");
470
      }
471
472 4b9d1df5 leszek
    computeNormalVector(vert3D,foundIndex);
473 29b82486 Leszek Koltunski
474
    // rotate so that the normal vector becomes (0,0,1)
475 57ef6378 Leszek Koltunski
    float axisX, axisY, axisZ;
476 29b82486 Leszek Koltunski
477
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
478
      {
479
      axisX = -mBuffer[1];
480
      axisY =  mBuffer[0];
481
      axisZ = 0.0f;
482
483 57ef6378 Leszek Koltunski
      float axiLen = axisX*axisX + axisY*axisY;
484
      axiLen = (float)Math.sqrt(axiLen);
485 29b82486 Leszek Koltunski
      axisX /= axiLen;
486
      axisY /= axiLen;
487
      axisZ /= axiLen;
488
      }
489
    else
490
      {
491
      axisX = 0.0f;
492
      axisY = 1.0f;
493
      axisZ = 0.0f;
494
      }
495
496 57ef6378 Leszek Koltunski
    float cosTheta = mBuffer[2];
497
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
498
    float sinHalfTheta = computeSinHalf(cosTheta);
499
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
500 29b82486 Leszek Koltunski
501
    mQuat1[0] = axisX*sinHalfTheta;
502
    mQuat1[1] = axisY*sinHalfTheta;
503
    mQuat1[2] = axisZ*sinHalfTheta;
504
    mQuat1[3] = cosHalfTheta;
505
    mQuat2[0] =-axisX*sinHalfTheta;
506
    mQuat2[1] =-axisY*sinHalfTheta;
507
    mQuat2[2] =-axisZ*sinHalfTheta;
508
    mQuat2[3] = cosHalfTheta;
509
510 57ef6378 Leszek Koltunski
    for (float[] vert : vert3D)
511 29b82486 Leszek Koltunski
      {
512 d809bf6f Leszek Koltunski
      QuatHelper.quatMultiply(mQuat3, mQuat1, vert  );
513
      QuatHelper.quatMultiply(  vert, mQuat3, mQuat2);
514 29b82486 Leszek Koltunski
      }
515
516
    // fit the whole thing in a square and remember the scale & 2D vertices
517 2617d26b Leszek Koltunski
    fitInSquare(ft, vert3D, isOuter);
518 29b82486 Leszek Koltunski
519
    // remember the rotation
520
    ft.qx =-mQuat1[0];
521
    ft.qy =-mQuat1[1];
522
    ft.qz =-mQuat1[2];
523
    ft.qw = mQuat1[3];
524
525
    return ft;
526
    }
527
528 fe3dec09 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
529
// multigon
530
531
  private FaceTransform constructNewTransform(final float[][][] vert3D, boolean isOuter, int face, int numFaces)
532
    {
533
    FaceTransform ft = new FaceTransform();
534
    ft.face = face;
535
    ft.numFaces = numFaces;
536
537
    // compute center of gravity
538
    ft.vx = 0.0f;
539
    ft.vy = 0.0f;
540
    ft.vz = 0.0f;
541
    int len = 0;
542
543
    for( float[][] vert : vert3D )
544
      for( float[] v : vert )
545
        {
546
        ft.vx += v[0];
547
        ft.vy += v[1];
548
        ft.vz += v[2];
549
        len++;
550
        }
551
552
    ft.vx /= len;
553
    ft.vy /= len;
554
    ft.vz /= len;
555
556
    // move all vertices so that their center of gravity is at (0,0,0)
557
    for( float[][] vert : vert3D )
558
      for( float[] v : vert )
559
        {
560
        v[0] -= ft.vx;
561
        v[1] -= ft.vy;
562
        v[2] -= ft.vz;
563
        }
564
565
    // find 3 non-colinear vertices
566
    int foundIndex = -1;
567
    len = vert3D[0].length;
568
569
    for(int vertex=2; vertex<len; vertex++)
570
      {
571 4b9d1df5 leszek
      if( areNotColinear(vert3D[0],vertex) )
572 fe3dec09 Leszek Koltunski
        {
573
        foundIndex = vertex;
574
        break;
575
        }
576
      }
577
578
    // compute the normal vector
579
    if( foundIndex==-1 )
580
      {
581
      StringBuilder sb = new StringBuilder();
582
583
      for (float[] v : vert3D[0])
584
        {
585
        sb.append(' ');
586
        sb.append("(");
587
        sb.append(v[0]);
588
        sb.append(" ");
589
        sb.append(v[1]);
590
        sb.append(" ");
591
        sb.append(v[2]);
592
        sb.append(")");
593
        }
594
      android.util.Log.e("D", "verts: "+sb);
595
596
      throw new RuntimeException("all vertices colinear");
597
      }
598
599 4b9d1df5 leszek
    computeNormalVector(vert3D[0],foundIndex);
600 fe3dec09 Leszek Koltunski
601
    // rotate so that the normal vector becomes (0,0,1)
602
    float axisX, axisY, axisZ;
603
604
    if( mBuffer[0]!=0.0f || mBuffer[1]!=0.0f )
605
      {
606
      axisX = -mBuffer[1];
607
      axisY =  mBuffer[0];
608
      axisZ = 0.0f;
609
610
      float axiLen = axisX*axisX + axisY*axisY;
611
      axiLen = (float)Math.sqrt(axiLen);
612
      axisX /= axiLen;
613
      axisY /= axiLen;
614
      axisZ /= axiLen;
615
      }
616
    else
617
      {
618
      axisX = 0.0f;
619
      axisY = 1.0f;
620
      axisZ = 0.0f;
621
      }
622
623
    float cosTheta = mBuffer[2];
624
    float sinTheta = (float)Math.sqrt(1-cosTheta*cosTheta);
625
    float sinHalfTheta = computeSinHalf(cosTheta);
626
    float cosHalfTheta = computeCosHalf(sinTheta,cosTheta);
627
628
    mQuat1[0] = axisX*sinHalfTheta;
629
    mQuat1[1] = axisY*sinHalfTheta;
630
    mQuat1[2] = axisZ*sinHalfTheta;
631
    mQuat1[3] = cosHalfTheta;
632
    mQuat2[0] =-axisX*sinHalfTheta;
633
    mQuat2[1] =-axisY*sinHalfTheta;
634
    mQuat2[2] =-axisZ*sinHalfTheta;
635
    mQuat2[3] = cosHalfTheta;
636
637
    for( float[][] vert : vert3D)
638
      for( float[] v : vert)
639
        {
640
        QuatHelper.quatMultiply(mQuat3, mQuat1, v  );
641
        QuatHelper.quatMultiply(  v, mQuat3, mQuat2);
642
        }
643
644
    // fit the whole thing in a square and remember the scale & 2D vertices
645
    fitInSquare(ft, vert3D, isOuter);
646
647
    // remember the rotation
648
    ft.qx =-mQuat1[0];
649
    ft.qy =-mQuat1[1];
650
    ft.qz =-mQuat1[2];
651
    ft.qw = mQuat1[3];
652
653
    return ft;
654
    }
655
656 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
657
658 7e9a35eb leszek
  private void rotateAllVertices(float[][] result, int len, float[][] vertices, float sin, float cos)
659 29b82486 Leszek Koltunski
    {
660
    for(int i=0; i<len; i++)
661
      {
662 7e9a35eb leszek
      float x = vertices[i][0];
663
      float y = vertices[i][1];
664
      result[i][0] = x*cos - y*sin;
665
      result[i][1] = x*sin + y*cos;
666 29b82486 Leszek Koltunski
      }
667
    }
668
669
///////////////////////////////////////////////////////////////////////////////////////////////////
670
671 7e9a35eb leszek
  private float computeScale(float[][] v1, float[][] v2, int v1i, int v2i)
672 29b82486 Leszek Koltunski
    {
673 7e9a35eb leszek
    float v1x = v1[v1i][0];
674
    float v1y = v1[v1i][1];
675
    float v2x = v2[v2i][0];
676
    float v2y = v2[v2i][1];
677 29b82486 Leszek Koltunski
678 57ef6378 Leszek Koltunski
    float lenSq1 = v1x*v1x + v1y*v1y;
679
    float lenSq2 = v2x*v2x + v2y*v2y;
680 29b82486 Leszek Koltunski
681 57ef6378 Leszek Koltunski
    return (float)Math.sqrt(lenSq2/lenSq1);
682 29b82486 Leszek Koltunski
    }
683
684
///////////////////////////////////////////////////////////////////////////////////////////////////
685
// valid for 0<angle<2*PI
686
687 57ef6378 Leszek Koltunski
  private float computeSinHalf(float cos)
688 29b82486 Leszek Koltunski
    {
689 57ef6378 Leszek Koltunski
    return (float)Math.sqrt((1-cos)/2);
690 29b82486 Leszek Koltunski
    }
691
692
///////////////////////////////////////////////////////////////////////////////////////////////////
693
// valid for 0<angle<2*PI
694
695 57ef6378 Leszek Koltunski
  private float computeCosHalf(float sin, float cos)
696 29b82486 Leszek Koltunski
    {
697 57ef6378 Leszek Koltunski
    float cosHalf = (float)Math.sqrt((1+cos)/2);
698 29b82486 Leszek Koltunski
    return sin<0 ? -cosHalf : cosHalf;
699
    }
700
701
///////////////////////////////////////////////////////////////////////////////////////////////////
702
703 846b69f3 Leszek Koltunski
  private int computeRotatedIndex(int oldVertex, int len, int rotatedVertex)
704 29b82486 Leszek Koltunski
    {
705 846b69f3 Leszek Koltunski
    int v = (rotatedVertex + oldVertex);
706 29b82486 Leszek Koltunski
    if( v>=len ) v-=len;
707
    if( v< 0   ) v+=len;
708
709
    return v;
710
    }
711
712
///////////////////////////////////////////////////////////////////////////////////////////////////
713
714 7e9a35eb leszek
  private boolean isScaledVersionOf(float[][] newVert, float[][] oldVert, int len, int vertex)
715 29b82486 Leszek Koltunski
    {
716 846b69f3 Leszek Koltunski
    int newZeroIndex = computeRotatedIndex(0,len,vertex);
717 57ef6378 Leszek Koltunski
    float EPSILON = 0.001f;
718
    float scale = computeScale(newVert,oldVert,newZeroIndex,0);
719 29b82486 Leszek Koltunski
720
    for(int i=1; i<len; i++)
721
      {
722 846b69f3 Leszek Koltunski
      int index = computeRotatedIndex(i,len,vertex);
723 29b82486 Leszek Koltunski
724 7e9a35eb leszek
      float horz = oldVert[i][0] - scale*newVert[index][0];
725
      float vert = oldVert[i][1] - scale*newVert[index][1];
726 29b82486 Leszek Koltunski
727
      if( horz>EPSILON || horz<-EPSILON || vert>EPSILON || vert<-EPSILON ) return false;
728
      }
729
730
    return true;
731
    }
732
733
///////////////////////////////////////////////////////////////////////////////////////////////////
734
735 846b69f3 Leszek Koltunski
  private void correctInfo(FaceTransform info, float scale, float sin, float cos, int oldSticker)
736 29b82486 Leszek Koltunski
    {
737
    mStickerCoords.remove(info.sticker);
738
739
    info.sticker = oldSticker;
740
    info.scale  *= scale;
741
742
    mQuat1[0] = info.qx;
743
    mQuat1[1] = info.qy;
744
    mQuat1[2] = info.qz;
745
    mQuat1[3] = info.qw;
746
747 57ef6378 Leszek Koltunski
    float sinHalf = computeSinHalf(cos);
748
    float cosHalf = computeCosHalf(sin,cos);
749 29b82486 Leszek Koltunski
750 846b69f3 Leszek Koltunski
    mQuat2[0] = 0.0f;
751
    mQuat2[1] = 0.0f;
752
    mQuat2[2] = sinHalf;
753
    mQuat2[3] = cosHalf;
754 29b82486 Leszek Koltunski
755 d809bf6f Leszek Koltunski
    QuatHelper.quatMultiply( mQuat3, mQuat1, mQuat2 );
756 29b82486 Leszek Koltunski
757
    info.qx = mQuat3[0];
758
    info.qy = mQuat3[1];
759
    info.qz = mQuat3[2];
760
    info.qw = mQuat3[3];
761
    }
762
763
///////////////////////////////////////////////////////////////////////////////////////////////////
764
765 7e9a35eb leszek
  private boolean foundVertex(FaceTransform info, float[][] buffer, float[][] newVert, float[][] oldVert, int oldSticker)
766 29b82486 Leszek Koltunski
    {
767 bf4e7e68 Leszek Koltunski
    float lenOld=0.0f, oldX=0.0f, oldY=0.0f;
768 7e9a35eb leszek
    int len = newVert.length;
769 bf4e7e68 Leszek Koltunski
770 7e9a35eb leszek
    for(float[] ov : oldVert)
771 bf4e7e68 Leszek Koltunski
      {
772 7e9a35eb leszek
      oldX = ov[0];
773
      oldY = ov[1];
774
      lenOld = (float) Math.sqrt(oldX*oldX+oldY*oldY);
775 bf4e7e68 Leszek Koltunski
776 7e9a35eb leszek
      if(lenOld!=0) break;
777 bf4e7e68 Leszek Koltunski
      }
778
779 29b82486 Leszek Koltunski
    for(int vertex=0; vertex<len; vertex++)
780
      {
781 7e9a35eb leszek
      float newX = newVert[vertex][0];
782
      float newY = newVert[vertex][1];
783 bf4e7e68 Leszek Koltunski
      float lenNew = (float)Math.sqrt(newX*newX + newY*newY);
784 29b82486 Leszek Koltunski
785 bf4e7e68 Leszek Koltunski
      if( lenNew!=0 )
786 29b82486 Leszek Koltunski
        {
787 bf4e7e68 Leszek Koltunski
        float cos = (float)QuatHelper.computeCos( oldX, oldY, newX, newY, lenNew, lenOld);
788
        float sin = (float)QuatHelper.computeSin( oldX, oldY, newX, newY, lenNew, lenOld);
789
790
        rotateAllVertices(buffer,len,newVert,sin,cos);
791
792
        if( isScaledVersionOf(buffer,oldVert,len,vertex) )
793
          {
794
          int newZeroIndex = computeRotatedIndex(0,len,vertex);
795
          float scale = computeScale(oldVert,newVert,0,newZeroIndex);
796
          correctInfo(info,scale,sin,cos,oldSticker);
797
          return true;
798
          }
799 29b82486 Leszek Koltunski
        }
800
      }
801
802
    return false;
803
    }
804
805 d99de43c Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
806
807 7e9a35eb leszek
  private float computeCoreDistance(float[][] verts)
808 d99de43c Leszek Koltunski
    {
809
    float ret = 0.0f;
810
    float centerX=0.0f,centerY=0.0f;
811 7e9a35eb leszek
    int len = verts.length;
812 d99de43c Leszek Koltunski
813 7e9a35eb leszek
    for(float[] vert : verts)
814 d99de43c Leszek Koltunski
      {
815 7e9a35eb leszek
      centerX += vert[0];
816
      centerY += vert[1];
817 d99de43c Leszek Koltunski
      }
818
819 7e9a35eb leszek
    centerX /= len;
820
    centerY /= len;
821 d99de43c Leszek Koltunski
822 7e9a35eb leszek
    for(float[] vert : verts)
823 d99de43c Leszek Koltunski
      {
824 7e9a35eb leszek
      float distX = centerX-vert[0];
825
      float distY = centerY-vert[1];
826
      ret += (float) Math.sqrt(distX*distX+distY*distY);
827 d99de43c Leszek Koltunski
      }
828
829
    return ret;
830
    }
831
832 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
833 9567a9ae leszek
// even if this is a multigon, then StickerCoords.outerVertices is the outer edge!
834 8aceea06 leszek
// (see fitInSquare multigon variant)
835 29b82486 Leszek Koltunski
836
  private boolean successfullyCollapsedStickers(final FaceTransform newInfo, final FaceTransform oldInfo)
837
    {
838
    StickerCoords sNewInfo = mStickerCoords.get(newInfo.sticker);
839
    StickerCoords sOldInfo = mStickerCoords.get(oldInfo.sticker);
840 d99de43c Leszek Koltunski
841 08bf6b98 leszek
    if( sNewInfo.outerVertices.length>1 || sOldInfo.outerVertices.length>1 ) // the 'outer' path is composed of more than
842
      {                                                                      // one segment, i.e. the sticker has holes.
843
      return false;                                                          // do not collapse such stickers.
844
      }
845
846
    float[][] newVert = sNewInfo.outerVertices[0];
847
    float[][] oldVert = sOldInfo.outerVertices[0];
848 29b82486 Leszek Koltunski
    int oldLen = oldVert.length;
849
    int newLen = newVert.length;
850
851 f7d2e0e1 Leszek Koltunski
    if( oldLen==newLen )
852 29b82486 Leszek Koltunski
      {
853 bf4e7e68 Leszek Koltunski
      float coreDistOld = computeCoreDistance(oldVert);                     // the two stickers are at different scales,
854 d99de43c Leszek Koltunski
      float coreDistNew = computeCoreDistance(newVert);                     // so even if they are in fact the same, do not
855
      float diff = (coreDistOld*oldInfo.scale)/(coreDistNew*newInfo.scale); // collapse them into one. Example: Master Skewb
856
      if( diff<1.0-MAX_CORE_DIFF || diff>1.0+MAX_CORE_DIFF ) return false;  // and two triangular stickers of different size.
857
858 29b82486 Leszek Koltunski
      int oldSticker = oldInfo.sticker;
859 7e9a35eb leszek
      float[][] buffer = new float[oldLen][2];
860 bf4e7e68 Leszek Koltunski
861 7e9a35eb leszek
      if( foundVertex(newInfo, buffer, newVert, oldVert, oldSticker) )
862 f7d2e0e1 Leszek Koltunski
        {
863 d99de43c Leszek Koltunski
        if( sNewInfo.outer ) sOldInfo.outer = true;
864 f7d2e0e1 Leszek Koltunski
        return true;
865
        }
866 29b82486 Leszek Koltunski
      }
867
868
    return false;
869
    }
870
871
///////////////////////////////////////////////////////////////////////////////////////////////////
872 fe3dec09 Leszek Koltunski
// polygon
873 29b82486 Leszek Koltunski
874 57ef6378 Leszek Koltunski
  private float[][] constructVert(float[][] vertices, int[] index)
875 29b82486 Leszek Koltunski
    {
876
    int len = index.length;
877 57ef6378 Leszek Koltunski
    float[][] ret = new float[len][4];
878 29b82486 Leszek Koltunski
879
    for(int i=0; i<len; i++)
880
      {
881 84a17011 Leszek Koltunski
      float[] tmp = vertices[index[i]];
882
      ret[i][0] = tmp[0];
883
      ret[i][1] = tmp[1];
884
      ret[i][2] = tmp[2];
885 29b82486 Leszek Koltunski
      ret[i][3] = 1.0f;
886
      }
887
888
    return ret;
889
    }
890
891 fe3dec09 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
892
// multigon
893
894
  private float[][][] constructVert(float[][] vertices, int[][] index)
895
    {
896
    int len = index.length;
897
    float[][][] ret = new float[len][][];
898
899
    for(int i=0; i<len; i++)
900
      {
901
      int[] ind = index[i];
902
      int num = ind.length;
903
      ret[i] = new float[num][4];
904
905
      for(int j=0; j<num; j++)
906
        {
907
        float[] r = ret[i][j];
908
        float[] v = vertices[ind[j]];
909
        r[0] = v[0];
910
        r[1] = v[1];
911
        r[2] = v[2];
912
        r[3] = 1.0f;
913
        }
914
      }
915
916
    return ret;
917
    }
918
919 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
920
921 1fda81c4 leszek
  private void applyVertexEffects(MeshBase mesh, ObjectVertexEffects effects)
922 29b82486 Leszek Koltunski
    {
923 84a17011 Leszek Koltunski
    boolean[] uses      = effects.getUses();
924
    String[] names      = effects.getNames();
925
    float[][] variables = effects.getVariables();
926
    float[][] centers   = effects.getCenters();
927
    float[][] regions   = effects.getRegions();
928
    int numEffects = uses.length;
929
930
    for(int eff=0; eff<numEffects; eff++)
931 1fda81c4 leszek
      if( names[eff]!=null )
932 29b82486 Leszek Koltunski
        {
933 84a17011 Leszek Koltunski
        VertexEffect effect = VertexEffect.constructEffect(names[eff],variables[eff],centers[eff],regions[eff]);
934
        if( effect!=null ) mesh.apply(effect);
935 29b82486 Leszek Koltunski
        }
936
    }
937
938
///////////////////////////////////////////////////////////////////////////////////////////////////
939
940
  private void correctComponents(MeshBase mesh, int numComponents)
941
    {
942
    int numTexToBeAdded = numComponents-mesh.getNumTexComponents();
943
944
    mesh.mergeEffComponents();
945
946
    for(int i=0; i<numTexToBeAdded; i++ ) mesh.addEmptyTexComponent();
947
    }
948
949
///////////////////////////////////////////////////////////////////////////////////////////////////
950
951
  private void printTransform(FaceTransform f)
952
    {
953 9567a9ae leszek
    android.util.Log.e("D", "face="+f.face+" sticker="+f.sticker+" scale="+f.scale+
954
                            " q=("+f.qx+", "+f.qy+", "+f.qz+", "+f.qw+") v=("+f.vx+", "+f.vy+", "+f.vz+")");
955 29b82486 Leszek Koltunski
    }
956
957
///////////////////////////////////////////////////////////////////////////////////////////////////
958
959 b2c77ec3 Leszek Koltunski
  private float[] computeBands(float H, int alpha, float dist, float K, int N)
960 29b82486 Leszek Koltunski
    {
961
    float[] bands = new float[2*N];
962
963
    bands[0] = 1.0f;
964
    bands[1] = 0.0f;
965
966
    float beta = (float)Math.atan(dist*Math.tan(Math.PI*alpha/180));
967
    float sinBeta = (float)Math.sin(beta);
968
    float cosBeta = (float)Math.cos(beta);
969
    float R = cosBeta<1.0f ? H/(1.0f-cosBeta) : 0.0f;
970
    float D = R*sinBeta;
971
    float B = h(R,sinBeta,K*beta);
972
973
    if( D>1.0f )
974
      {
975
      for(int i=1; i<N; i++)
976
        {
977
        bands[2*i  ] = (float)(N-1-i)/(N-1);
978
        bands[2*i+1] = H*(1-bands[2*i]);
979
        }
980
      }
981
    else
982
      {
983
      int K2 = (int)((N-3)*K);
984
      int K1 = (N-3)-K2;
985
986
      for(int i=0; i<=K1; i++)
987
        {
988
        float angle = K*beta + (1-K)*beta*(K1-i)/(K1+1);
989
        float x = h(R,sinBeta,angle);
990
        bands[2*i+2] = 1.0f - x;
991
        bands[2*i+3] = g(R,D,x,cosBeta);
992
        }
993
994
      for(int i=0; i<=K2; i++)
995
        {
996
        float x = (1-B)*(i+1)/(K2+1) + B;
997
        bands[2*K1+2 + 2*i+2] = 1.0f - x;
998
        bands[2*K1+2 + 2*i+3] = g(R,D,f(D,B,x),cosBeta);
999
        }
1000
      }
1001
1002
    bands[2*N-2] = 0.0f;
1003
    bands[2*N-1] =    H;
1004
1005
    return bands;
1006
    }
1007
1008
///////////////////////////////////////////////////////////////////////////////////////////////////
1009
1010 b2c77ec3 Leszek Koltunski
  private void computeConvexityCenter(float[] out, float[] in, FaceTransform ft)
1011
    {
1012
    if( in==null )
1013
      {
1014
      out[0] = out[1] = 0.0f;
1015
      }
1016
    else
1017
      {
1018
      out[0] = in[0] - ft.vx;
1019
      out[1] = in[1] - ft.vy;
1020
      out[2] = in[2] - ft.vz;
1021
      out[3] = 1.0f;
1022
1023
      mQuat1[0] =-ft.qx;
1024
      mQuat1[1] =-ft.qy;
1025
      mQuat1[2] =-ft.qz;
1026
      mQuat1[3] = ft.qw;
1027
1028
      mQuat2[0] = -mQuat1[0];
1029
      mQuat2[1] = -mQuat1[1];
1030
      mQuat2[2] = -mQuat1[2];
1031 84a17011 Leszek Koltunski
      mQuat2[3] =  mQuat1[3];
1032 b2c77ec3 Leszek Koltunski
1033 d809bf6f Leszek Koltunski
      QuatHelper.quatMultiply( mQuat3, mQuat1,    out);
1034
      QuatHelper.quatMultiply(    out, mQuat3, mQuat2);
1035 b2c77ec3 Leszek Koltunski
1036
      out[0] /= ft.scale;
1037
      out[1] /= ft.scale;
1038
      out[2] /= ft.scale;
1039
      }
1040
    }
1041
1042
///////////////////////////////////////////////////////////////////////////////////////////////////
1043
1044
  private void changeStickerPointers(int[][] table, int oldPointer, int newPointer)
1045
    {
1046 0d9a2083 leszek
    for(int[] tab : table)
1047 b2c77ec3 Leszek Koltunski
      {
1048 0d9a2083 leszek
      int len = tab.length;
1049 b2c77ec3 Leszek Koltunski
1050 0d9a2083 leszek
      for(int j=0; j<len; j++)
1051
        if( tab[j]==oldPointer ) tab[j] = newPointer;
1052 b2c77ec3 Leszek Koltunski
      }
1053
    }
1054
1055 9567a9ae leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1056
1057
  private String printSticker(StickerCoords info)
1058
    {
1059
    String ret = (info.outer?"OUTER":"INNER")+" scale: "+info.scale+"\n";
1060
1061
    int len = info.outerVertices.length;
1062
1063
    for(int l=0; l<len; l++)
1064
      {
1065
      float[][] outer = info.outerVertices[l];
1066
      int numV = outer.length;
1067
1068
      ret += "  Loop "+l+" verts: "+numV+" { ";
1069
      for(int v=0; v<numV; v++)
1070
        {
1071
        if(v!=0) ret += ", ";
1072
        ret += (outer[v][0]+"f, "+outer[v][1]+"f");
1073
        }
1074
1075
      ret += "}\n";
1076
      }
1077
1078
    return ret;
1079
    }
1080
1081 b2c77ec3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1082
// INTERNAL API
1083
1084 f7d2e0e1 Leszek Koltunski
  public int printStickerCoords()
1085 29b82486 Leszek Koltunski
    {
1086
    int stickers = mStickerCoords.size();
1087 f7d2e0e1 Leszek Koltunski
    int ret = 0;
1088 29b82486 Leszek Koltunski
1089
    android.util.Log.d("D", "---- STICKER COORDS ----");
1090
1091
    for(int s=0; s<stickers; s++)
1092
      {
1093
      StickerCoords info = mStickerCoords.get(s);
1094 f7d2e0e1 Leszek Koltunski
      if( info.outer )  ret++;
1095 9567a9ae leszek
      String str = printSticker(info);
1096
      android.util.Log.d("D", "Sticker "+s+" "+str);
1097 29b82486 Leszek Koltunski
      }
1098
1099
    android.util.Log.d("D", "---- END STICKER COORDS ----");
1100 f7d2e0e1 Leszek Koltunski
1101
    return ret;
1102 29b82486 Leszek Koltunski
    }
1103
1104
///////////////////////////////////////////////////////////////////////////////////////////////////
1105
1106
  public void printFaceTransform()
1107
    {
1108
    android.util.Log.d("D", "---- OLD FACE TRANSFORM ---");
1109
1110
    int oldfaces = mOldFaceTransf.size();
1111
1112
    for(int f=0; f<oldfaces; f++)
1113
      {
1114
      printTransform(mOldFaceTransf.get(f));
1115
      }
1116
1117
    android.util.Log.d("D", "---- NEW FACE TRANSFORM ---");
1118
1119
    int newfaces = mNewFaceTransf.size();
1120
1121
    for(int f=0; f<newfaces; f++)
1122
      {
1123
      printTransform(mNewFaceTransf.get(f));
1124
      }
1125
    }
1126
1127 7e9a35eb leszek
///////////////////////////////////////////////////////////////////////////////////////////////////
1128
1129
  private void printVert(double[][] buffer)
1130
    {
1131
    StringBuilder str = new StringBuilder();
1132
1133
    for(double[] buf : buffer)
1134
      {
1135
      str.append(" (");
1136
      str.append(buf[0]);
1137
      str.append(" , ");
1138
      str.append(buf[1]);
1139
      str.append(" ) ");
1140
      }
1141
1142
    android.util.Log.d("D", str.toString());
1143
    }
1144
1145 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1146 b2c77ec3 Leszek Koltunski
// PUBLIC API
1147 29b82486 Leszek Koltunski
1148 b2c77ec3 Leszek Koltunski
  public static FactoryCubit getInstance()
1149 29b82486 Leszek Koltunski
    {
1150 b2c77ec3 Leszek Koltunski
    if( mThis==null ) mThis = new FactoryCubit();
1151
    return mThis;
1152 29b82486 Leszek Koltunski
    }
1153
1154 84a17011 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1155
1156
  public static ObjectVertexEffects generateVertexEffect( float[][] vertices,
1157
                                                          float[][] corners, int[] cornerIndices,
1158
                                                          float[][] centers, int[] centerIndices )
1159
    {
1160
    int numVerts = vertices.length;
1161
    String[] names = new String[numVerts];
1162
    float[][] vars = new float[numVerts][];
1163
    float[][] cents= new float[numVerts][];
1164
    float[][] regs = new float[numVerts][];
1165
    boolean[] uses = new boolean[numVerts];
1166
1167
    for(int i=0; i<numVerts; i++)
1168
      {
1169
      int centerI = centerIndices[i];
1170
      int cornerI = cornerIndices[i];
1171
1172
      if( centerI>=0 && cornerI>=0 )
1173
        {
1174
        float[] ce = centers[centerI];
1175
        float[] ve = vertices[i];
1176
        float S = corners[cornerI][0];
1177
        float R = corners[cornerI][1];
1178
1179
        float CX = ve[0];
1180
        float CY = ve[1];
1181
        float CZ = ve[2];
1182
        float X = S*(ce[0]-CX);
1183
        float Y = S*(ce[1]-CY);
1184
        float Z = S*(ce[2]-CZ);
1185
1186
        names[i]= NAME;
1187
        vars[i] = new float[] { 0, X,Y,Z, 1 };
1188
        cents[i]= new float[] { CX, CY, CZ };
1189
        regs[i] = new float[] { 0,0,0, R };
1190
        uses[i] = false;
1191
        }
1192
      }
1193
1194
    return new ObjectVertexEffects(names,vars,cents,regs,uses);
1195
    }
1196
1197 1561a74f Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1198
1199 3d2493ea Leszek Koltunski
  public float[] getStickerScales()
1200 1561a74f Leszek Koltunski
    {
1201
    int index=0,num=0,len = mStickerCoords.size();
1202
1203 3d2493ea Leszek Koltunski
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
1204 1561a74f Leszek Koltunski
1205
    if( num>0 )
1206
      {
1207 b2c77ec3 Leszek Koltunski
      float[] scales = new float[num];
1208 1561a74f Leszek Koltunski
1209
      for(int i=0; i<len; i++)
1210
        {
1211
        StickerCoords sticker = mStickerCoords.get(i);
1212 3d2493ea Leszek Koltunski
        if( sticker.outer ) scales[index++] = sticker.scale;
1213 1561a74f Leszek Koltunski
        }
1214
1215 b2c77ec3 Leszek Koltunski
      return scales;
1216 1561a74f Leszek Koltunski
      }
1217
1218
    return null;
1219
    }
1220
1221
///////////////////////////////////////////////////////////////////////////////////////////////////
1222
1223 ebe8c08e leszek
  public float[][][][] getStickerCoords()
1224 1561a74f Leszek Koltunski
    {
1225
    int index=0,num=0,len = mStickerCoords.size();
1226
1227 3d2493ea Leszek Koltunski
    for(int i=0; i<len; i++) if( mStickerCoords.get(i).outer ) num++;
1228 1561a74f Leszek Koltunski
1229
    if( num>0 )
1230
      {
1231 ebe8c08e leszek
      float[][][][] coords = new float[num][][][];
1232 1561a74f Leszek Koltunski
1233
      for(int i=0; i<len; i++)
1234
        {
1235
        StickerCoords sticker = mStickerCoords.get(i);
1236 ebe8c08e leszek
        if( sticker.outer ) coords[index++] = sticker.outerVertices;
1237 1561a74f Leszek Koltunski
        }
1238
1239 b2c77ec3 Leszek Koltunski
      return coords;
1240 1561a74f Leszek Koltunski
      }
1241
1242
    return null;
1243
    }
1244
1245 7af68038 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1246
1247
  public int[][] getStickerVariants()
1248
    {
1249
    int numvariants = 1; // there's one in the 'new' array
1250
1251
    int oldfaces = mOldFaceTransf.size();
1252
1253
    for(int f=0; f<oldfaces; f++)
1254
      {
1255
      FaceTransform ft = mOldFaceTransf.get(f);
1256
      if( ft.face==0 ) numvariants++;
1257
      }
1258
1259
    int[][] ret = new int[numvariants][];
1260 0d9a2083 leszek
    int face=0, variant=-1;
1261 7af68038 Leszek Koltunski
1262
    for(int f=0; f<oldfaces; f++)
1263
      {
1264
      FaceTransform ft = mOldFaceTransf.get(f);
1265
      if( ft.face==0 )
1266
        {
1267 0d9a2083 leszek
        variant++;
1268
        face=0;
1269
        ret[variant] = new int[ft.numFaces];
1270 7af68038 Leszek Koltunski
        }
1271
1272 0d9a2083 leszek
      ret[variant][face++] = ft.sticker;
1273 7af68038 Leszek Koltunski
      }
1274
1275
    int newfaces = mNewFaceTransf.size();
1276
1277
    for(int f=0; f<newfaces; f++)
1278
      {
1279
      FaceTransform ft = mNewFaceTransf.get(f);
1280
      if( ft.face==0 )
1281
        {
1282 0d9a2083 leszek
        variant++;
1283
        face=0;
1284
        ret[variant] = new int[ft.numFaces];
1285 7af68038 Leszek Koltunski
        }
1286
1287 0d9a2083 leszek
      ret[variant][face++] = ft.sticker;
1288 7af68038 Leszek Koltunski
      }
1289
1290
    int numStickers = mStickerCoords.size();
1291
    int numOuter=0;
1292
1293
    for(int i=0; i<numStickers; i++)
1294
      {
1295
      StickerCoords sc = mStickerCoords.get(i);
1296
      if( sc.outer )
1297
        {
1298 0d9a2083 leszek
        changeStickerPointers(ret,i, numOuter);
1299 7af68038 Leszek Koltunski
        numOuter++;
1300
        }
1301
      else
1302
        {
1303
        changeStickerPointers(ret,i,-1);
1304
        }
1305
      }
1306
1307
    return ret;
1308
    }
1309
1310 29b82486 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1311
1312 b2c77ec3 Leszek Koltunski
  public void clear()
1313 29b82486 Leszek Koltunski
    {
1314 b2c77ec3 Leszek Koltunski
    mStickerCoords.clear();
1315
    mNewFaceTransf.clear();
1316
    mOldFaceTransf.clear();
1317
    }
1318
1319 df781f1d Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1320
// This is for FactoryBandaged3x3Cubit. We need to know which direction each face faces.
1321
// This assumes the factory has just been cleared and 'createNewFaceTransform' has just
1322
// been called.
1323
1324
  public Static4D getQuaternion(int face)
1325
    {
1326
    FaceTransform ft = mNewFaceTransf.get(face);
1327
    return ft!=null ? new Static4D(ft.qx,ft.qy,ft.qz,ft.qw) : null;
1328
    }
1329
1330 b2c77ec3 Leszek Koltunski
///////////////////////////////////////////////////////////////////////////////////////////////////
1331
1332 59a971c1 Leszek Koltunski
  public void createNewFaceTransform(final ObjectShape shape, int[] outer)
1333 b2c77ec3 Leszek Koltunski
    {
1334
    float[][] vertices = shape.getVertices();
1335
    int[][] indices = shape.getVertIndices();
1336 fe3dec09 Leszek Koltunski
    int[][][] fullIndices = shape.getMultigonIndices();
1337
    boolean isMultigon = shape.isMultigon();
1338 b2c77ec3 Leszek Koltunski
    FaceTransform ft;
1339
    int numNew = mNewFaceTransf.size();
1340
1341
    for(int i=0; i<numNew; i++)
1342
      {
1343
      ft = mNewFaceTransf.remove(0);
1344
      mOldFaceTransf.add(ft);
1345
      }
1346
1347 fe3dec09 Leszek Koltunski
    int numFaces = shape.getNumFaces();
1348 b2c77ec3 Leszek Koltunski
    int numOld = mOldFaceTransf.size();
1349
1350
    for (int face=0; face<numFaces; face++)
1351
      {
1352
      boolean collapsed = false;
1353 59a971c1 Leszek Koltunski
      boolean isOuter = (outer!=null && outer[face]>0);
1354 fe3dec09 Leszek Koltunski
      FaceTransform newT;
1355
1356
      if( !isMultigon )
1357
        {
1358
        float[][] vert = constructVert(vertices, indices[face]);
1359
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1360
        }
1361
      else
1362
        {
1363
        float[][][] vert = constructVert(vertices, fullIndices[face]);
1364
        newT = constructNewTransform(vert,isOuter,face,numFaces);
1365
        }
1366 b2c77ec3 Leszek Koltunski
1367
      for (int old=0; !collapsed && old<numOld; old++)
1368
        {
1369
        ft = mOldFaceTransf.get(old);
1370
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1371
        }
1372
1373
      for (int pre=0; !collapsed && pre<face; pre++)
1374
        {
1375
        ft = mNewFaceTransf.get(pre);
1376
        if (successfullyCollapsedStickers(newT, ft)) collapsed = true;
1377
        }
1378
1379
      mNewFaceTransf.add(newT);
1380
      }
1381 29b82486 Leszek Koltunski
    }
1382
1383
///////////////////////////////////////////////////////////////////////////////////////////////////
1384
1385 84a17011 Leszek Koltunski
  public MeshBase createRoundedSolid(final ObjectShape shape, final ObjectFaceShape faceShape,
1386 1fda81c4 leszek
                                     final ObjectVertexEffects effects, int numComponents)
1387 29b82486 Leszek Koltunski
    {
1388 b2c77ec3 Leszek Koltunski
    float[][] bands         = faceShape.getBands();
1389
    int[]   bandIndexes     = faceShape.getBandIndices();
1390
    float[] convexityCenter = faceShape.getConvexityCenter();
1391
1392 fe3dec09 Leszek Koltunski
    int numFaces = shape.getNumFaces();
1393 1fda81c4 leszek
    float[] bandsComputed;
1394 29b82486 Leszek Koltunski
    MeshBase[] meshes = new MeshBase[numFaces];
1395
    FaceTransform fInfo;
1396
    StickerCoords sInfo;
1397 57ef6378 Leszek Koltunski
    float[] convexXY = new float[4];
1398 29b82486 Leszek Koltunski
1399
    for(int face=0; face<numFaces; face++)
1400
      {
1401
      fInfo = mNewFaceTransf.get(face);
1402
      computeConvexityCenter(convexXY,convexityCenter,fInfo);
1403
1404 1fda81c4 leszek
      int index      = bandIndexes[face];
1405
      float[] band   = bands[index];
1406
      float height   = band[0];
1407
      int alpha      = (int)band[1];
1408
      float dist     = band[2];
1409
      float K        = band[3];
1410
      int N          = (int)band[4];
1411
      int exIndex    = (int)band[5];
1412
      int exVertices = (int)band[6];
1413 c3a033e9 Leszek Koltunski
1414 50fb62bf Leszek Koltunski
      bandsComputed = computeBands(height,alpha,dist,K,N);
1415 fe3dec09 Leszek Koltunski
1416 8aceea06 leszek
      sInfo = mStickerCoords.get(fInfo.sticker);
1417 4b9d1df5 leszek
      float[][][] vertsF = sInfo.fullVertices;
1418 8aceea06 leszek
1419
      // i.e. multigon which hasn't been 'successfully collapsed'
1420
      // with a previously computed polygon sticker!
1421
      if( vertsF!=null )
1422 fe3dec09 Leszek Koltunski
        {
1423 8aceea06 leszek
        int lenVerts = vertsF.length;
1424 4b9d1df5 leszek
        float[][][] copiedVerts = new float[lenVerts][][];
1425 fe3dec09 Leszek Koltunski
1426
        for(int i=0; i<lenVerts; i++)
1427
          {
1428 4b9d1df5 leszek
          float[][] v = vertsF[i];
1429 fe3dec09 Leszek Koltunski
          int len = v.length;
1430 4b9d1df5 leszek
          copiedVerts[i] = new float[len][2];
1431
1432
          for(int j=0; j<len; j++)
1433
            {
1434
            copiedVerts[i][j][0] = v[j][0];
1435
            copiedVerts[i][j][1] = v[j][1];
1436
            }
1437 fe3dec09 Leszek Koltunski
          }
1438
1439
        meshes[face] = new MeshMultigon(copiedVerts,bandsComputed,exIndex,exVertices);
1440
        }
1441 8aceea06 leszek
      else
1442
        {
1443 08bf6b98 leszek
        float[][] verts = sInfo.outerVertices[0];
1444 8aceea06 leszek
        int lenVerts = verts.length;
1445 7e9a35eb leszek
        float[][] copiedVerts = new float[lenVerts][2];
1446
1447
        for(int v=0; v<lenVerts; v++)
1448
          {
1449
          float[] ve = verts[v];
1450
          copiedVerts[v][0] = ve[0];
1451
          copiedVerts[v][1] = ve[1];
1452
          }
1453
1454 8aceea06 leszek
        meshes[face] = new MeshPolygon(copiedVerts,bandsComputed,exIndex,exVertices, convexXY[0], convexXY[1]);
1455
        }
1456 fe3dec09 Leszek Koltunski
1457 0b5d4a7b Leszek Koltunski
      meshes[face].setEffectAssociation(0,0,face);
1458 29b82486 Leszek Koltunski
      }
1459
1460
    MeshBase mesh = new MeshJoined(meshes);
1461
    Static3D center = new Static3D(0,0,0);
1462
1463
    for(int face=0; face<numFaces; face++)
1464
      {
1465
      fInfo = mNewFaceTransf.get(face);
1466
1467 57ef6378 Leszek Koltunski
      float vx = fInfo.vx;
1468
      float vy = fInfo.vy;
1469
      float vz = fInfo.vz;
1470
      float sc = fInfo.scale;
1471
      float qx = fInfo.qx;
1472
      float qy = fInfo.qy;
1473
      float qz = fInfo.qz;
1474
      float qw = fInfo.qw;
1475 29b82486 Leszek Koltunski
1476 846b69f3 Leszek Koltunski
      Static3D scale = new Static3D(sc,sc,sc);
1477 29b82486 Leszek Koltunski
      Static3D move3D= new Static3D(vx,vy,vz);
1478
      Static4D quat  = new Static4D(qx,qy,qz,qw);
1479
1480 0b5d4a7b Leszek Koltunski
      mesh.apply(new MatrixEffectScale(scale)           ,0,face);
1481
      mesh.apply(new MatrixEffectQuaternion(quat,center),0,face);
1482
      mesh.apply(new MatrixEffectMove(move3D)           ,0,face);
1483 29b82486 Leszek Koltunski
      }
1484
1485 18d97487 Leszek Koltunski
    correctComponents(mesh,numComponents);
1486 1fda81c4 leszek
    if( effects!=null ) applyVertexEffects(mesh,effects);
1487 29b82486 Leszek Koltunski
1488
    return mesh;
1489
    }
1490
  }