Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / bandaged / FactoryBandaged.java @ 23a614d9

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// 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
///////////////////////////////////////////////////////////////////////////////////////////////////
9

    
10
package org.distorted.objectlib.bandaged;
11

    
12
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
13
import static org.distorted.objectlib.main.TwistyObject.SQ2;
14
import static org.distorted.objectlib.main.TwistyObject.SQ5;
15
import static org.distorted.objectlib.objects.TwistyBandagedCuboid.REGION_SIZE;
16
import static org.distorted.objectlib.objects.TwistyBandagedCuboid.STRENGTH;
17

    
18
import org.distorted.library.helpers.QuatHelper;
19
import org.distorted.library.mesh.MeshBase;
20
import org.distorted.library.type.Static3D;
21
import org.distorted.library.type.Static4D;
22
import org.distorted.objectlib.helpers.FactoryCubit;
23
import org.distorted.objectlib.helpers.ObjectFaceShape;
24
import org.distorted.objectlib.helpers.ObjectShape;
25
import org.distorted.objectlib.helpers.ObjectVertexEffects;
26

    
27
import java.util.ArrayList;
28
import java.util.Collections;
29
import java.util.Comparator;
30

    
31
///////////////////////////////////////////////////////////////////////////////////////////////////
32

    
33
abstract public class FactoryBandaged
34
  {
35
  private static class BandagedCubitFace
36
    {
37
    private static final float[] sortVect = new float[] { 1/(2*SQ2), SQ2/(2*SQ2), SQ5/(2*SQ2) };
38

    
39
    float[] vertices;
40
    float[] center;
41
    float[] normal;
42
    float centerCast;
43

    
44
    BandagedCubitFace(float[] verts)
45
      {
46
      vertices = verts;
47
      computeCenter();
48
      computeNormal();
49
      computeCenterCast();
50
      }
51

    
52
    private void computeCenter()
53
      {
54
      int num = vertices.length/3;
55
      center = new float[3];
56

    
57
      for(int v=0; v<num; v++)
58
        {
59
        center[0] += vertices[3*v  ];
60
        center[1] += vertices[3*v+1];
61
        center[2] += vertices[3*v+2];
62
        }
63

    
64
      center[0] /= num;
65
      center[1] /= num;
66
      center[2] /= num;
67
      }
68

    
69
    private void computeNormal()
70
      {
71
      normal = new float[3];
72

    
73
      float x1 = vertices[0];
74
      float y1 = vertices[1];
75
      float z1 = vertices[2];
76
      float x2 = vertices[3];
77
      float y2 = vertices[4];
78
      float z2 = vertices[5];
79
      float x3 = vertices[6];
80
      float y3 = vertices[7];
81
      float z3 = vertices[8];
82

    
83
      float v1x = x2-x1;
84
      float v1y = y2-y1;
85
      float v1z = z2-z1;
86
      float v2x = x3-x1;
87
      float v2y = y3-y1;
88
      float v2z = z3-z1;
89

    
90
      normal[0] = v1y*v2z - v2y*v1z;
91
      normal[1] = v1z*v2x - v2z*v1x;
92
      normal[2] = v1x*v2y - v2x*v1y;
93

    
94
      double len = normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2];
95
      len = Math.sqrt(len);
96
      normal[0] /= len;
97
      normal[1] /= len;
98
      normal[2] /= len;
99
      }
100

    
101
    private void computeCenterCast()
102
      {
103
      centerCast = center[0]*sortVect[0] + center[1]*sortVect[1] + center[2]*sortVect[2];
104
      }
105
    }
106

    
107
  static class SortByCenterCast implements Comparator<BandagedCubitFace>
108
    {
109
    public int compare(BandagedCubitFace a, BandagedCubitFace b)
110
      {
111
      float diff = a.centerCast - b.centerCast;
112
      return diff>0 ? 1: diff==0 ? 0: -1;
113
      }
114
    }
115

    
116
  public static Static4D QUAT = new Static4D(0,0,0,1);
117

    
118
  private ArrayList<float[]> mTmpArray;
119
  private ArrayList<float[][]> mVertexArray;
120
  private BandagedElement[] mElements;
121
  private Static3D[] mPuzzleNormals;
122
  private float[] mDist3D;
123
  private int[][] mFaceBelongsBitmap;
124
  private float[][] mDiaAxis;
125
  private float[][] mMinMax;
126
  private int mNumFaces;
127
  private int mNumElements;
128
  private float[][] mMove;
129
  private int[][][][] mIndices;
130
  private float[][][] mVertices;
131
  private int[][] mBandIndices;
132
  private int[] mNumLayers;
133
  private float[] mTmp;
134
  private float[][][] mAllPositions;
135
  private boolean mCalledFromBandagedObject; // true if this class is being called from the
136
                                             // one of the 'BandagedObject*' classes; false if
137
                                             // called from one of the 'TwistyBandaged*' classes.
138

    
139
///////////////////////////////////////////////////////////////////////////////////////////////////
140

    
141
  FactoryBandaged()
142
    {
143

    
144
    }
145

    
146
///////////////////////////////////////////////////////////////////////////////////////////////////
147

    
148
  abstract Static3D[] getNormals();
149
  abstract float[][][] getPositions(int[] numLayers);
150
  abstract Static4D getElementQuat(int[] numLayers, int cubitIndex);
151
  abstract float[][] getDiameterAxis();
152
  abstract float[] getDist3D(int[] numLayers);
153
  abstract float[][] getBands(boolean iconMode, int[] numLayers);
154
  abstract int getElementVariant(int[] numLayers, float x, float y, float z);
155
  abstract int diameterMap(float diameter);
156
  abstract float[][] getVertices(int[] numLayers, int variant);
157
  abstract int[][] getIndices(int[] numLayers, int variant);
158
  abstract int getNumVariants(int[] numLayers);
159
  abstract float sizeCorrection(int[] numLayers); // again workaround for the Megaminx
160
                                                  // '2-3-4-5' vs. '3-3-5-5' problem.
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  private int[] computeFaceBelongsBitmap(float[][] vertices, float[] move, float corr)
164
    {
165
    int numVerts = vertices.length;
166
    int[] ret = new int[numVerts];
167

    
168
    for(int v=0; v<numVerts; v++)
169
      {
170
      int vertBelongsBitmap=0x00000000;
171
      float[] vert=vertices[v];
172

    
173
      for(int f=0; f<mNumFaces; f++)
174
        if( vertInFace(vert, move, mPuzzleNormals[f], mDist3D[f], corr) )
175
          {
176
          vertBelongsBitmap |= (1<<f);
177
          }
178

    
179
      ret[v]=vertBelongsBitmap;
180
      }
181

    
182
    return ret;
183
    }
184

    
185
///////////////////////////////////////////////////////////////////////////////////////////////////
186

    
187
  private int getCubitIndex(float[][][] allPositions, int variant, float x, float y, float z)
188
    {
189
    int total = 0;
190
    for(int v=0; v<variant; v++) total += allPositions[v].length;
191

    
192
    float[][] pos = allPositions[variant];
193
    float minerror = Float.MAX_VALUE;
194
    int addition = -1;
195
    int num = pos.length;
196

    
197
    for(int n=0; n<num; n++)
198
      {
199
      float[] point = pos[n];
200
      float dx = point[0]-x;
201
      float dy = point[1]-y;
202
      float dz = point[2]-z;
203

    
204
      float diff = dx*dx + dy*dy + dz*dz;
205

    
206
      if( diff<minerror )
207
        {
208
        addition = n;
209
        minerror = diff;
210
        }
211
      }
212

    
213
    return total + addition;
214
    }
215

    
216
///////////////////////////////////////////////////////////////////////////////////////////////////
217
// (vertices,indices) define a single face of a set of connected elements.
218
// Return its 'diameter', i.e. the max distance (along any of its 'diameterAxis') between any two
219
// vertices of the face.
220

    
221
  private float faceDiameter(float[][] vertices, int[][] indices)
222
    {
223
    int num = mDiaAxis.length;
224

    
225
    for(int i=0; i<num; i++)
226
      {
227
      mMinMax[i][0] = Float.MAX_VALUE;
228
      mMinMax[i][1] =-Float.MAX_VALUE;
229
      }
230

    
231
    for (int[] ind : indices)
232
      for(int index : ind)
233
        {
234
        float[] v = vertices[index];
235

    
236
        for(int i=0; i<num; i++)
237
          {
238
          float[] mm = mMinMax[i];
239
          float[] ax = mDiaAxis[i];
240
          float dist = v[0]*ax[0] + v[1]*ax[1] + v[2]*ax[2];
241

    
242
          if ( dist > mm[1] ) mm[1] = dist;
243
          if ( dist < mm[0] ) mm[0] = dist;
244
          }
245
        }
246

    
247
    float maxDiff = 0;
248

    
249
    for(int i=0; i<num; i++)
250
      {
251
      float[] mm = mMinMax[i];
252
      float diff = mm[1]-mm[0];
253
      if( diff>maxDiff ) maxDiff = diff;
254
      }
255

    
256
    return maxDiff+0.01f; // this will be rounded down to nearest int; we don't want 1.9999 here
257
    }
258

    
259
///////////////////////////////////////////////////////////////////////////////////////////////////
260
// return array of:
261
// 0 if this is an inner face, 1 if its diameter is 1, 2 if diameter is 2, 3 if 3, etc
262
// but only up to 5 (because the number of bands is 6 - see createIrregularFaceShape() )
263

    
264
  private int[] generateBandIndices(float[][] vertices, int[][][] indices, int[] belongs)
265
    {
266
    int numCubitFaces = indices.length;
267
    int[] bandIndices = new int[numCubitFaces];
268

    
269
    for(int f=0; f<numCubitFaces; f++)
270
      {
271
      bandIndices[f] = 0xffffffff;
272
      for( int index : indices[f][0] ) bandIndices[f] &= belongs[index];
273

    
274
      if( bandIndices[f]!=0 ) // outer face
275
        {
276
        float diameter = faceDiameter(vertices, indices[f]);
277
        bandIndices[f] = diameterMap(diameter);
278
        }
279
      }
280

    
281
    return bandIndices;
282
    }
283

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

    
286
  private void computeMove(float[] pos, int variant)
287
    {
288
    int numMoves = pos.length/3;
289
    float[] m = mMove[variant];
290
    m[0]=0.0f;
291
    m[1]=0.0f;
292
    m[2]=0.0f;
293

    
294
    for(int i=0; i<numMoves; i++)
295
      {
296
      m[0] += pos[3*i  ];
297
      m[1] += pos[3*i+1];
298
      m[2] += pos[3*i+2];
299
      }
300

    
301
    m[0]/=numMoves;
302
    m[1]/=numMoves;
303
    m[2]/=numMoves;
304
    }
305

    
306
///////////////////////////////////////////////////////////////////////////////////////////////////
307

    
308
  private float[][] getVertices(ArrayList<float[][]> list, int variant)
309
    {
310
    int total  = 0;
311
    int length = list.size();
312
    float[][][] vertices = new float[length][][];
313
    float[] mo = mMove[variant];
314

    
315
    for( int i=0; i<length; i++ )
316
      {
317
      vertices[i] = list.get(i);
318
      int len = vertices[i].length;
319
      for(int j=0; j<len; j++) total += vertices[i][j].length/3;
320
      }
321

    
322
    float[][] verts = new float[total][3];
323
    int pointer = 0;
324

    
325
    for(int i=0; i<length; i++)
326
      {
327
      int len = vertices[i].length;
328

    
329
      for(int j=0; j<len; j++)
330
        {
331
        float[] v = vertices[i][j];
332
        int l = v.length/3;
333

    
334
        for(int k=0; k<l; k++)
335
          {
336
          float[] ve = verts[pointer];
337
          ve[0] = v[3*k  ] - mo[0];
338
          ve[1] = v[3*k+1] - mo[1];
339
          ve[2] = v[3*k+2] - mo[2];
340
          pointer++;
341
          }
342
        }
343
      }
344

    
345
    return verts;
346
    }
347

    
348
///////////////////////////////////////////////////////////////////////////////////////////////////
349

    
350
  private int[][][] getIndices(ArrayList<float[][]> list)
351
    {
352
    int indicesSoFar=0;
353
    int length = list.size();
354
    int[][][] indices = new int[length][][];
355

    
356
    for( int i=0; i<length; i++ )
357
      {
358
      float[][] face = list.get(i);
359
      int len = face.length;
360
      int[][] ind = new int[len][];
361

    
362
      for(int j=0; j<len; j++)
363
        {
364
        int l = face[j].length/3;
365
        ind[j] = new int[l];
366
        for(int k=0; k<l; k++) ind[j][k] = (indicesSoFar++);
367
        }
368

    
369
      indices[i] = ind;
370
      }
371

    
372
    return indices;
373
    }
374

    
375
///////////////////////////////////////////////////////////////////////////////////////////////////
376

    
377
  private void markAllVertices(float[] vertex, float[][] vertices, int[][][] indices, int pointer, int variant)
378
    {
379
    int numFaces = indices.length;
380

    
381
    for(int face=0; face<numFaces; face++)
382
      {
383
      int len = indices[face].length;
384

    
385
      for(int comp=0; comp<len; comp++)
386
        {
387
        int l = indices[face][comp].length;
388
        int[] in = mIndices[variant][face][comp];
389

    
390
        for(int v=0; v<l; v++)
391
          if( in[v]==-1 )
392
            {
393
            int ind=indices[face][comp][v];
394
            float[] ver=vertices[ind];
395
            if(vertex[0]==ver[0] && vertex[1]==ver[1] && vertex[2]==ver[2]) in[v]=pointer;
396
            }
397
        }
398
      }
399
    }
400

    
401
///////////////////////////////////////////////////////////////////////////////////////////////////
402
// So far the 'vertices/indices' are stored inefficiently, with each vertex stored three times
403
// (each one normally is a corner of three faces) or even six times. Compress!
404
// Example of six times: the central vertex here:
405
//
406
// { 1.0f,  0.0f, -1.0f,
407
//   1.0f, -1.0f, -1.0f,
408
//   1.0f, -1.0f, +0.0f,
409
//   0.0f, -1.0f, -1.0f },
410

    
411
  private void compressVerticesAndIndices(int variant, float[][] vertices, int[][][] indices)
412
    {
413
    if( mTmpArray==null ) mTmpArray = new ArrayList<>();
414

    
415
    int numFaces = indices.length;
416
    int pointer=0;
417

    
418
    mIndices[variant] = new int[numFaces][][];
419

    
420
    for(int face=0; face<numFaces;face++)
421
      {
422
      int len = indices[face].length;
423
      mIndices[variant][face] = new int[len][];
424

    
425
      for(int comp=0; comp<len; comp++)
426
        {
427
        int l = indices[face][comp].length;
428
        mIndices[variant][face][comp] = new int[l];
429
        for(int v=0; v<l; v++) mIndices[variant][face][comp][v] = -1;
430
        }
431
      }
432

    
433
    for(int face=0; face<numFaces; face++)
434
      {
435
      int len = indices[face].length;
436

    
437
      for(int comp=0; comp<len; comp++)
438
        {
439
        int l = indices[face][comp].length;
440

    
441
        for(int v=0; v<l; v++)
442
          {
443
          if( mIndices[variant][face][comp][v]==-1 )
444
            {
445
            int ind=indices[face][comp][v];
446
            float[] ver=vertices[ind];
447
            mTmpArray.add(ver);
448
            markAllVertices(ver, vertices, indices, pointer, variant);
449
            pointer++;
450
            }
451
          }
452
        }
453
      }
454

    
455
    int len = mTmpArray.size();
456
    mVertices[variant] = new float[len][];
457

    
458
    for(int i=0; i<len; i++)
459
      {
460
      mVertices[variant][i] = mTmpArray.remove(0);
461
      }
462
    }
463

    
464
///////////////////////////////////////////////////////////////////////////////////////////////////
465

    
466
  static boolean vertInFace(float[] vertex, float[] move, Static3D faceAxis, float dist, float corr)
467
    {
468
    final float MAX_ERROR = 0.01f;
469

    
470
    float x= faceAxis.get0();
471
    float y= faceAxis.get1();
472
    float z= faceAxis.get2();
473

    
474
    float vx = vertex[0]*corr;
475
    float vy = vertex[1]*corr;
476
    float vz = vertex[2]*corr;
477

    
478
    float a = (vx+move[0])*x + (vy+move[1])*y + (vz+move[2])*z;
479
    float diff = a - dist;
480

    
481
    return diff>-MAX_ERROR && diff<MAX_ERROR;
482
    }
483

    
484
///////////////////////////////////////////////////////////////////////////////////////////////////
485

    
486
  private float[] computeVector(int index, float[][] vertices, int[][][] indices, int[] bandIndices, float[][] normals)
487
    {
488
    int numFaces = indices.length;
489
    int numBordering=0, numExternal=0;
490
    float x=0, y=0, z=0;
491

    
492
    for(int f=0; f<numFaces; f++)
493
      {
494
      int numComponentsInFace = indices[f].length;
495

    
496
      for(int c=0; c<numComponentsInFace; c++)
497
        {
498
        int[] ind = indices[f][c];
499
        int numVertsInComponent = ind.length;
500

    
501
        for(int v=0; v<numVertsInComponent; v++)
502
          {
503
          if( ind[v]==index )
504
            {
505
            float[] nor = normals[f];
506

    
507
            x += nor[0];
508
            y += nor[1];
509
            z += nor[2];
510

    
511
            numBordering++;
512
            if( bandIndices[f]>0 ) numExternal++;
513

    
514
            v = numVertsInComponent;
515
            c = numComponentsInFace;
516
            }
517
          }
518
        }
519
      }
520

    
521
    return ( numExternal<2 || numBordering<3 ) ? null : new float[] { x/numBordering, y/numBordering, z/numBordering};
522
    }
523

    
524
///////////////////////////////////////////////////////////////////////////////////////////////////
525

    
526
  private void createCubitFaceNormal(float[] output, float[] v0, float[] v1, float[] v2)
527
    {
528
    float ax = v0[0]-v1[0];
529
    float ay = v0[1]-v1[1];
530
    float az = v0[2]-v1[2];
531

    
532
    float bx = v2[0]-v1[0];
533
    float by = v2[1]-v1[1];
534
    float bz = v2[2]-v1[2];
535

    
536
    output[0] = ay*bz - az*by;
537
    output[1] = az*bx - ax*bz;
538
    output[2] = ax*by - ay*bx;
539

    
540
    float len = (float)Math.sqrt(output[0]*output[0] + output[1]*output[1] + output[2]*output[2]);
541

    
542
    if( len!=0 )
543
      {
544
      output[0] /= len;
545
      output[1] /= len;
546
      output[2] /= len;
547
      }
548
    else
549
      {
550
      android.util.Log.e("D", "ERROR in createCubitFaceNormal!");
551
      }
552
    }
553

    
554
///////////////////////////////////////////////////////////////////////////////////////////////////
555

    
556
  private float[][] generateCubitFaceNormals(float[][] vertices, int[][][] indices)
557
    {
558
    int numFaces = indices.length;
559
    float[][] ret = new float[numFaces][3];
560

    
561
    for(int f=0; f<numFaces; f++)
562
      {
563
      int[] verts = indices[f][0];
564
      int numVerts = verts.length;
565

    
566
      for(int v=0; v<numVerts; v++)
567
        {
568
        int i0 = verts[0];
569
        int i1 = verts[1];
570
        int i2 = verts[2];
571

    
572
        float[] v0 = vertices[i0];
573
        float[] v1 = vertices[i1];
574
        float[] v2 = vertices[i2];
575

    
576
        createCubitFaceNormal(ret[f], v0,v1,v2);
577
        }
578
      }
579

    
580
    return ret;
581
    }
582

    
583
///////////////////////////////////////////////////////////////////////////////////////////////////
584

    
585
  private float[][] generateVectors(float[][] vertices, int[][][] indices, int[] bandIndices)
586
    {
587
    int len = vertices.length;
588
    float[][] vectors = new float[len][];
589
    float[][] normals = generateCubitFaceNormals(vertices,indices);
590

    
591
    for(int i=0; i<len; i++)
592
      {
593
      vectors[i] = computeVector(i,vertices,indices,bandIndices,normals);
594
      }
595

    
596
    return vectors;
597
    }
598

    
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600

    
601
  private float[] buildFaceVertices(float[][] vertices, int[] indices, float[] pos, Static4D quat)
602
    {
603
    int num = indices.length;
604
    float[] ret = new float[3*num];
605

    
606
    for(int i=0; i<num; i++)
607
      {
608
      if( indices[i]>=vertices.length )
609
        {
610
        android.util.Log.e("D", "ind: "+indices[i]+" num vert: "+vertices.length);
611
        }
612

    
613
      float[] v = vertices[indices[i]];
614
      QuatHelper.rotateVectorByQuat(mTmp,v[0],v[1],v[2],1,quat);
615

    
616
      ret[3*i  ] = mTmp[0] + pos[0];
617
      ret[3*i+1] = mTmp[1] + pos[1];
618
      ret[3*i+2] = mTmp[2] + pos[2];
619
      }
620

    
621
    return ret;
622
    }
623

    
624
///////////////////////////////////////////////////////////////////////////////////////////////////
625

    
626
  private void removeInternalWalls(ArrayList<BandagedCubitFace> list)
627
    {
628
    Collections.sort(list,new SortByCenterCast());
629

    
630
    int numElements = list.size();
631
    final float MAXDIFF = 0.01f;
632

    
633
    for(int e=0; e<numElements; e++)
634
      {
635
      int ne = e+1;
636
      BandagedCubitFace f1 = list.get(e);
637
      float[] center = f1.center;
638

    
639
      while( ne<numElements )
640
        {
641
        BandagedCubitFace f2 = list.get(ne);
642
        float diff = f2.centerCast-f1.centerCast;
643

    
644
        if( diff>-MAXDIFF && diff<MAXDIFF )
645
          {
646
          float[] c = f2.center;
647
          float dx = c[0]-center[0];
648
          float dy = c[1]-center[1];
649
          float dz = c[2]-center[2];
650

    
651
          float d = dx*dx + dy*dy + dz*dz;
652

    
653
          if( d>-MAXDIFF && d<MAXDIFF )
654
            {
655
            list.remove(ne);
656
            list.remove(e);
657
            numElements -= 2;
658
            e--;
659
            break;
660
            }
661
          }
662
        else break;
663

    
664
        ne++;
665
        }
666
      }
667
    }
668

    
669
///////////////////////////////////////////////////////////////////////////////////////////////////
670

    
671
  private float[][] getNextSection(ArrayList<BandagedCubitFace> list)
672
    {
673
    int numElements = list.size();
674
    if( numElements==0 ) return null;
675

    
676
    final float MAXDIFF = 0.01f;
677
    float[][] ret = new float[numElements][];
678
    BandagedCubitFace bcf = list.remove(0);
679
    float[] normal = bcf.normal;
680
    int removed = 1;
681

    
682
    ret[0] = bcf.vertices;
683

    
684
    for(int e=0; e<numElements-1; e++)
685
      {
686
      BandagedCubitFace f = list.get(e);
687
      float[] n = f.normal;
688

    
689
      float dx = n[0]-normal[0];
690
      float dy = n[1]-normal[1];
691
      float dz = n[2]-normal[2];
692

    
693
      float diff = dx*dx + dy*dy + dz*dz;
694

    
695
      if( diff>-MAXDIFF && diff<MAXDIFF )
696
        {
697
        list.remove(e);
698
        e--;
699
        numElements--;
700
        ret[removed++] = f.vertices;
701
        }
702
      }
703

    
704
    float[][] ret2 = new float[removed][];
705
    for(int i=0; i<removed; i++) ret2[i] = ret[i];
706

    
707
    return ret2;
708
    }
709

    
710
///////////////////////////////////////////////////////////////////////////////////////////////////
711

    
712
  private boolean isConnected(final float[] face1, final float[] face2)
713
    {
714
    float MAXDIFF = 0.01f;
715
    int l1 = face1.length/3;
716
    int l2 = face2.length/3;
717

    
718
    for(int i=0; i<l1; i++)
719
      {
720
      float x = face1[3*i  ];
721
      float y = face1[3*i+1];
722
      float z = face1[3*i+2];
723

    
724
      for(int j=0; j<l2; j++)
725
        {
726
        float dx = x-face2[3*j  ];
727
        float dy = y-face2[3*j+1];
728
        float dz = z-face2[3*j+2];
729

    
730
        if( dx*dx + dy*dy + dz*dz < MAXDIFF )
731
          {
732
          int inext = i==l1-1 ? 0 : i+1;
733
          int jprev = j==0 ? l2-1 : j-1;
734

    
735
          dx = face1[3*inext  ] - face2[3*jprev  ];
736
          dy = face1[3*inext+1] - face2[3*jprev+1];
737
          dz = face1[3*inext+2] - face2[3*jprev+2];
738

    
739
          if( dx*dx + dy*dy + dz*dz < MAXDIFF ) return true;
740

    
741
          int iprev = i==0 ? l1-1 : i-1;
742
          int jnext = j==l2-1 ? 0 : j+1;
743

    
744
          dx = face1[3*iprev  ] - face2[3*jnext  ];
745
          dy = face1[3*iprev+1] - face2[3*jnext+1];
746
          dz = face1[3*iprev+2] - face2[3*jnext+2];
747

    
748
          return dx*dx + dy*dy + dz*dz < MAXDIFF;
749
          }
750
        }
751
      }
752

    
753
    return false;
754
    }
755

    
756
///////////////////////////////////////////////////////////////////////////////////////////////////
757

    
758
  private float[][] getNextConnected(float[][] section, int nonNull)
759
    {
760
    float[][] ret = new float[nonNull][];
761
    int start,len = section.length;
762

    
763
    for(start=0; start<len; start++)
764
      if( section[start]!=null )
765
        {
766
        ret[0] = section[start];
767
        section[start] = null;
768
        break;
769
        }
770

    
771
    int firstUnverified = 0;
772
    int lastUnverified  = 0;
773
    start++;
774

    
775
    while( firstUnverified<=lastUnverified )
776
      {
777
      for(int i=start; i<len; i++)
778
        {
779
        if( section[i]!=null && isConnected(ret[firstUnverified],section[i]) )
780
          {
781
          lastUnverified++;
782
          ret[lastUnverified] = section[i];
783
          section[i] = null;
784
          }
785
        }
786
      firstUnverified++;
787
      }
788

    
789
    float[][] ret2 = new float[lastUnverified+1][];
790
    for(int i=0; i<=lastUnverified; i++) ret2[i] = ret[i];
791

    
792
    return ret2;
793
    }
794

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

    
797
  private void fillUpVertexArray()
798
    {
799
    ArrayList<BandagedCubitFace> list = new ArrayList<>();
800
    mTmp = new float[4];
801

    
802
    int numVariants = getNumVariants(mNumLayers);
803

    
804
    float[][][] verts = new float[numVariants][][];
805
    int[][][] inds    = new int[numVariants][][];
806

    
807
    for(int v=0; v<numVariants; v++)
808
      {
809
      verts[v] = getVertices(mNumLayers,v);
810
      inds[v]  = getIndices(mNumLayers,v);
811
      }
812

    
813
    for(int e=0; e<mNumElements; e++)
814
      {
815
      BandagedElement element = mElements[e];
816
      int variant = element.getVariant();
817
      float[] pos = element.getPos();
818
      Static4D quat = element.getQuat();
819

    
820
      for( int[] ind : inds[variant])
821
        {
822
        float[] vertices = buildFaceVertices(verts[variant],ind,pos,quat);
823
        BandagedCubitFace face = new BandagedCubitFace(vertices);
824
        list.add(face);
825
        }
826
      }
827

    
828
    removeInternalWalls(list);
829

    
830
    while(true)
831
      {
832
      float[][] section = getNextSection(list);
833

    
834
      if( section!=null )
835
        {
836
        int nonNull = section.length;
837

    
838
        while(nonNull>0)
839
          {
840
          float[][] connected = getNextConnected(section,nonNull);
841
          nonNull -= connected.length;
842
          mVertexArray.add(connected);
843
          }
844
        }
845
      else break;
846
      }
847
    }
848

    
849
///////////////////////////////////////////////////////////////////////////////////////////////////
850

    
851
  private boolean layersHaveChanged(int[] numLayers)
852
    {
853
    if( mNumLayers==null ) return true;
854

    
855
    int len = mNumLayers.length;
856

    
857
    for(int i=0; i<len; i++)
858
      if(mNumLayers[i]!=numLayers[i]) return true;
859

    
860
    return false;
861
    }
862

    
863
///////////////////////////////////////////////////////////////////////////////////////////////////
864
// PUBLIC API
865

    
866
  public void prepare(int numVariants, int[] numLayers)
867
    {
868
    if( mVertexArray==null ) mVertexArray = new ArrayList<>();
869
    mCalledFromBandagedObject = false;
870
    mVertices= new float[numVariants][][];
871
    mIndices = new int[numVariants][][][];
872
    mMove = new float[numVariants][3];
873
    mBandIndices = new int[numVariants][];
874
    mFaceBelongsBitmap= new int[numVariants][];
875

    
876
    if( layersHaveChanged(numLayers) )
877
      {
878
      mAllPositions = getPositions(numLayers);
879
      }
880

    
881
    int num = numLayers.length;
882
    mNumLayers = new int[num];
883
    for(int l=0; l<num; l++) mNumLayers[l] = numLayers[l];
884

    
885
    mPuzzleNormals= getNormals();
886
    mNumFaces     = mPuzzleNormals.length;
887
    mDist3D       = getDist3D(mNumLayers);
888
    mDiaAxis      = getDiameterAxis();
889
    mMinMax       = new float[mDiaAxis.length][2];
890
    }
891

    
892
///////////////////////////////////////////////////////////////////////////////////////////////////
893

    
894
  public Static4D getCubitQuat(float x, float y, float z)
895
    {
896
    int elementVariant = getElementVariant(mNumLayers, x,y,z);
897
    int cubitIndex = getCubitIndex(mAllPositions,elementVariant, x,y,z);
898
    return getElementQuat(mNumLayers, cubitIndex);
899
    }
900

    
901
///////////////////////////////////////////////////////////////////////////////////////////////////
902

    
903
  public ObjectShape createIrregularShape(int variant, float[] pos)
904
    {
905
    mVertexArray.clear();
906

    
907
    mNumElements = pos.length/3;
908
    mElements = new BandagedElement[mNumElements];
909

    
910
    for(int e=0; e<mNumElements; e++)
911
      {
912
      float x= pos[3*e  ];
913
      float y= pos[3*e+1];
914
      float z= pos[3*e+2];
915
      int elementVariant = getElementVariant(mNumLayers, x,y,z);
916
      int cubitIndex = getCubitIndex(mAllPositions,elementVariant, x,y,z);
917
      Static4D quat = getElementQuat(mNumLayers, cubitIndex);
918
      mElements[e] = new BandagedElement(pos, 3*e, elementVariant, quat);
919
      }
920

    
921
    fillUpVertexArray();
922

    
923
    computeMove(pos,variant);
924
    float[][] verts = getVertices(mVertexArray,variant);
925
    int[][][] inds  = getIndices(mVertexArray);
926

    
927
    compressVerticesAndIndices(variant,verts,inds);
928

    
929
    return new ObjectShape(mVertices[variant], mIndices[variant]);
930
    }
931

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

    
934
  public ObjectFaceShape createIrregularFaceShape(int variant, boolean iconMode)
935
    {
936
    float[][] bands = getBands(iconMode, mNumLayers);
937
    float corr = mCalledFromBandagedObject ? 1.0f : sizeCorrection(mNumLayers);
938

    
939
    if( mBandIndices[variant]==null )
940
      {
941
      mFaceBelongsBitmap[variant] = computeFaceBelongsBitmap(mVertices[variant], mMove[variant],corr);
942
      mBandIndices[variant] = generateBandIndices(mVertices[variant], mIndices[variant], mFaceBelongsBitmap[variant]);
943
      }
944

    
945
    return new ObjectFaceShape(bands,mBandIndices[variant],null);
946
    }
947

    
948
///////////////////////////////////////////////////////////////////////////////////////////////////
949

    
950
  public ObjectVertexEffects createVertexEffects(int variant, boolean roundCorners)
951
    {
952
    float[][] vertVec= generateVectors(mVertices[variant], mIndices[variant], mBandIndices[variant]);
953
    int numEffects   = mVertices[variant].length;
954
    float S          = STRENGTH;
955
    float[] region   = {0,0,0,REGION_SIZE};
956
    String[] names   = new String[numEffects];
957
    float[][] regions= new float[numEffects][];
958
    boolean[] uses   = new boolean[numEffects];
959
    float[][] vars   = new float[numEffects][];
960

    
961
    for(int i=0; i<numEffects; i++)
962
      {
963
      float[] v = vertVec[i];
964

    
965
      if( v!=null )
966
        {
967
        names[i]  = FactoryCubit.NAME;
968
        regions[i]= region;
969
        uses[i]   = roundCorners;
970
        vars[i]   = new float[] { 0, S*v[0], S*v[1], S*v[2], 1 };
971
        }
972
      }
973

    
974
    return new ObjectVertexEffects(names,vars,mVertices[variant],regions,uses);
975
    }
976

    
977
///////////////////////////////////////////////////////////////////////////////////////////////////
978

    
979
  public MeshBase createMesh(float[] pos, int[] numLayers, boolean iconMode, boolean roundCorners)
980
    {
981
    prepare(1,numLayers);
982

    
983
    mCalledFromBandagedObject = true;
984

    
985
    ObjectShape shape           = createIrregularShape(0,pos);
986
    ObjectFaceShape face        = createIrregularFaceShape(0,iconMode);
987
    ObjectVertexEffects effects = createVertexEffects(0,roundCorners);
988
    int numFaces                = shape.getNumFaces();
989

    
990
    FactoryCubit factory = FactoryCubit.getInstance();
991
    factory.clear();
992
    factory.createNewFaceTransform(shape,null);
993
    return factory.createRoundedSolid(shape,face,effects,MESH_NICE,numFaces);
994
    }
995
  }
(9-9/15)