Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / bandaged / FactoryBandaged.java @ 6777e712

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.SQ2;
13
import static org.distorted.objectlib.main.TwistyObject.SQ5;
14
import static org.distorted.objectlib.objects.TwistyBandagedCuboid.REGION_SIZE;
15
import static org.distorted.objectlib.objects.TwistyBandagedCuboid.STRENGTH;
16

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

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

    
30
///////////////////////////////////////////////////////////////////////////////////////////////////
31

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
138
///////////////////////////////////////////////////////////////////////////////////////////////////
139

    
140
  FactoryBandaged()
141
    {
142

    
143
    }
144

    
145
///////////////////////////////////////////////////////////////////////////////////////////////////
146

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

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

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

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

    
178
      ret[v]=vertBelongsBitmap;
179
      }
180

    
181
    return ret;
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

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

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

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

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

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

    
212
    return total + addition;
213
    }
214

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

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

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

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

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

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

    
246
    float maxDiff = 0;
247

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

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

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

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

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

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

    
280
    return bandIndices;
281
    }
282

    
283
///////////////////////////////////////////////////////////////////////////////////////////////////
284

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

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

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

    
305
///////////////////////////////////////////////////////////////////////////////////////////////////
306

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

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

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

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

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

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

    
344
    return verts;
345
    }
346

    
347
///////////////////////////////////////////////////////////////////////////////////////////////////
348

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

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

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

    
368
      indices[i] = ind;
369
      }
370

    
371
    return indices;
372
    }
373

    
374
///////////////////////////////////////////////////////////////////////////////////////////////////
375

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
523
///////////////////////////////////////////////////////////////////////////////////////////////////
524

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

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

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

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

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

    
553
///////////////////////////////////////////////////////////////////////////////////////////////////
554

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

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

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

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

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

    
579
    return ret;
580
    }
581

    
582
///////////////////////////////////////////////////////////////////////////////////////////////////
583

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

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

    
595
    return vectors;
596
    }
597

    
598
///////////////////////////////////////////////////////////////////////////////////////////////////
599

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

    
605
    for(int i=0; i<num; i++)
606
      {
607
      float[] v = vertices[indices[i]];
608
      QuatHelper.rotateVectorByQuat(mTmp,v[0],v[1],v[2],1,quat);
609

    
610
      ret[3*i  ] = mTmp[0] + pos[0];
611
      ret[3*i+1] = mTmp[1] + pos[1];
612
      ret[3*i+2] = mTmp[2] + pos[2];
613
      }
614

    
615
    return ret;
616
    }
617

    
618
///////////////////////////////////////////////////////////////////////////////////////////////////
619

    
620
  private void removeInternalWalls(ArrayList<BandagedCubitFace> list)
621
    {
622
    Collections.sort(list,new SortByCenterCast());
623

    
624
    int numElements = list.size();
625
    final float MAXDIFF = 0.01f;
626

    
627
    for(int e=0; e<numElements; e++)
628
      {
629
      int ne = e+1;
630
      BandagedCubitFace f1 = list.get(e);
631
      float[] center = f1.center;
632

    
633
      while( ne<numElements )
634
        {
635
        BandagedCubitFace f2 = list.get(ne);
636
        float diff = f2.centerCast-f1.centerCast;
637

    
638
        if( diff>-MAXDIFF && diff<MAXDIFF )
639
          {
640
          float[] c = f2.center;
641
          float dx = c[0]-center[0];
642
          float dy = c[1]-center[1];
643
          float dz = c[2]-center[2];
644

    
645
          float d = dx*dx + dy*dy + dz*dz;
646

    
647
          if( d>-MAXDIFF && d<MAXDIFF )
648
            {
649
            list.remove(ne);
650
            list.remove(e);
651
            numElements -= 2;
652
            e--;
653
            break;
654
            }
655
          }
656
        else break;
657

    
658
        ne++;
659
        }
660
      }
661
    }
662

    
663
///////////////////////////////////////////////////////////////////////////////////////////////////
664

    
665
  private float[][] getNextSection(ArrayList<BandagedCubitFace> list)
666
    {
667
    int numElements = list.size();
668
    if( numElements==0 ) return null;
669

    
670
    final float MAXDIFF = 0.01f;
671
    float[][] ret = new float[numElements][];
672
    BandagedCubitFace bcf = list.remove(0);
673
    float[] normal = bcf.normal;
674
    int removed = 1;
675

    
676
    ret[0] = bcf.vertices;
677

    
678
    for(int e=0; e<numElements-1; e++)
679
      {
680
      BandagedCubitFace f = list.get(e);
681
      float[] n = f.normal;
682

    
683
      float dx = n[0]-normal[0];
684
      float dy = n[1]-normal[1];
685
      float dz = n[2]-normal[2];
686

    
687
      float diff = dx*dx + dy*dy + dz*dz;
688

    
689
      if( diff>-MAXDIFF && diff<MAXDIFF )
690
        {
691
        list.remove(e);
692
        e--;
693
        numElements--;
694
        ret[removed++] = f.vertices;
695
        }
696
      }
697

    
698
    float[][] ret2 = new float[removed][];
699
    for(int i=0; i<removed; i++) ret2[i] = ret[i];
700

    
701
    return ret2;
702
    }
703

    
704
///////////////////////////////////////////////////////////////////////////////////////////////////
705

    
706
  private boolean isConnected(final float[] face1, final float[] face2)
707
    {
708
    float MAXDIFF = 0.01f;
709
    int l1 = face1.length/3;
710
    int l2 = face2.length/3;
711

    
712
    for(int i=0; i<l1; i++)
713
      {
714
      float x = face1[3*i  ];
715
      float y = face1[3*i+1];
716
      float z = face1[3*i+2];
717

    
718
      for(int j=0; j<l2; j++)
719
        {
720
        float dx = x-face2[3*j  ];
721
        float dy = y-face2[3*j+1];
722
        float dz = z-face2[3*j+2];
723

    
724
        if( dx*dx + dy*dy + dz*dz < MAXDIFF )
725
          {
726
          int inext = i==l1-1 ? 0 : i+1;
727
          int jprev = j==0 ? l2-1 : j-1;
728

    
729
          dx = face1[3*inext  ] - face2[3*jprev  ];
730
          dy = face1[3*inext+1] - face2[3*jprev+1];
731
          dz = face1[3*inext+2] - face2[3*jprev+2];
732

    
733
          if( dx*dx + dy*dy + dz*dz < MAXDIFF ) return true;
734

    
735
          int iprev = i==0 ? l1-1 : i-1;
736
          int jnext = j==l2-1 ? 0 : j+1;
737

    
738
          dx = face1[3*iprev  ] - face2[3*jnext  ];
739
          dy = face1[3*iprev+1] - face2[3*jnext+1];
740
          dz = face1[3*iprev+2] - face2[3*jnext+2];
741

    
742
          return dx*dx + dy*dy + dz*dz < MAXDIFF;
743
          }
744
        }
745
      }
746

    
747
    return false;
748
    }
749

    
750
///////////////////////////////////////////////////////////////////////////////////////////////////
751

    
752
  private float[][] getNextConnected(float[][] section, int nonNull)
753
    {
754
    float[][] ret = new float[nonNull][];
755
    int start,len = section.length;
756

    
757
    for(start=0; start<len; start++)
758
      if( section[start]!=null )
759
        {
760
        ret[0] = section[start];
761
        section[start] = null;
762
        break;
763
        }
764

    
765
    int firstUnverified = 0;
766
    int lastUnverified  = 0;
767
    start++;
768

    
769
    while( firstUnverified<=lastUnverified )
770
      {
771
      for(int i=start; i<len; i++)
772
        {
773
        if( section[i]!=null && isConnected(ret[firstUnverified],section[i]) )
774
          {
775
          lastUnverified++;
776
          ret[lastUnverified] = section[i];
777
          section[i] = null;
778
          }
779
        }
780
      firstUnverified++;
781
      }
782

    
783
    float[][] ret2 = new float[lastUnverified+1][];
784
    for(int i=0; i<=lastUnverified; i++) ret2[i] = ret[i];
785

    
786
    return ret2;
787
    }
788

    
789
///////////////////////////////////////////////////////////////////////////////////////////////////
790

    
791
  private void fillUpVertexArray()
792
    {
793
    ArrayList<BandagedCubitFace> list = new ArrayList<>();
794
    mTmp = new float[4];
795

    
796
    int numVariants = getNumVariants(mNumLayers);
797

    
798
    float[][][] verts = new float[numVariants][][];
799
    int[][][] inds    = new int[numVariants][][];
800

    
801
    for(int v=0; v<numVariants; v++)
802
      {
803
      verts[v] = getVertices(mNumLayers,v);
804
      inds[v]  = getIndices(mNumLayers,v);
805
      }
806

    
807
    for(int e=0; e<mNumElements; e++)
808
      {
809
      BandagedElement element = mElements[e];
810
      int variant = element.getVariant();
811
      float[] pos = element.getPos();
812
      Static4D quat = element.getQuat();
813

    
814
      for( int[] ind : inds[variant])
815
        {
816
        float[] vertices = buildFaceVertices(verts[variant],ind,pos,quat);
817
        BandagedCubitFace face = new BandagedCubitFace(vertices);
818
        list.add(face);
819
        }
820
      }
821

    
822
    removeInternalWalls(list);
823

    
824
    while(true)
825
      {
826
      float[][] section = getNextSection(list);
827

    
828
      if( section!=null )
829
        {
830
        int nonNull = section.length;
831

    
832
        while(nonNull>0)
833
          {
834
          float[][] connected = getNextConnected(section,nonNull);
835
          nonNull -= connected.length;
836
          mVertexArray.add(connected);
837
          }
838
        }
839
      else break;
840
      }
841
    }
842

    
843
///////////////////////////////////////////////////////////////////////////////////////////////////
844

    
845
  private boolean layersHaveChanged(int[] numLayers)
846
    {
847
    if( mNumLayers==null ) return true;
848

    
849
    int len = mNumLayers.length;
850

    
851
    for(int i=0; i<len; i++)
852
      if(mNumLayers[i]!=numLayers[i]) return true;
853

    
854
    return false;
855
    }
856

    
857
///////////////////////////////////////////////////////////////////////////////////////////////////
858
// PUBLIC API
859

    
860
  public void prepare(int numVariants, int[] numLayers)
861
    {
862
    if( mVertexArray==null ) mVertexArray = new ArrayList<>();
863
    mCalledFromBandagedObject = false;
864
    mVertices= new float[numVariants][][];
865
    mIndices = new int[numVariants][][][];
866
    mMove = new float[numVariants][3];
867
    mBandIndices = new int[numVariants][];
868
    mFaceBelongsBitmap= new int[numVariants][];
869

    
870
    if( layersHaveChanged(numLayers) )
871
      {
872
      mAllPositions = getPositions(numLayers);
873
      }
874

    
875
    int num = numLayers.length;
876
    mNumLayers = new int[num];
877
    for(int l=0; l<num; l++) mNumLayers[l] = numLayers[l];
878

    
879
    mPuzzleNormals= getNormals();
880
    mNumFaces     = mPuzzleNormals.length;
881
    mDist3D       = getDist3D(mNumLayers);
882
    mDiaAxis      = getDiameterAxis();
883
    mMinMax       = new float[mDiaAxis.length][2];
884
    }
885

    
886
///////////////////////////////////////////////////////////////////////////////////////////////////
887

    
888
  public Static4D getCubitQuat(float x, float y, float z)
889
    {
890
    int elementVariant = getElementVariant(mNumLayers, x,y,z);
891
    int cubitIndex = getCubitIndex(mAllPositions,elementVariant, x,y,z);
892
    return getElementQuat(mNumLayers, cubitIndex);
893
    }
894

    
895
///////////////////////////////////////////////////////////////////////////////////////////////////
896

    
897
  public ObjectShape createIrregularShape(int variant, float[] pos)
898
    {
899
    mVertexArray.clear();
900

    
901
    mNumElements = pos.length/3;
902
    mElements = new BandagedElement[mNumElements];
903

    
904
    for(int e=0; e<mNumElements; e++)
905
      {
906
      float x= pos[3*e  ];
907
      float y= pos[3*e+1];
908
      float z= pos[3*e+2];
909
      int elementVariant = getElementVariant(mNumLayers, x,y,z);
910
      int cubitIndex = getCubitIndex(mAllPositions,elementVariant, x,y,z);
911
      Static4D quat = getElementQuat(mNumLayers, cubitIndex);
912
      mElements[e] = new BandagedElement(pos, 3*e, elementVariant, quat);
913
      }
914

    
915
    fillUpVertexArray();
916

    
917
    computeMove(pos,variant);
918
    float[][] verts = getVertices(mVertexArray,variant);
919
    int[][][] inds  = getIndices(mVertexArray);
920

    
921
    compressVerticesAndIndices(variant,verts,inds);
922

    
923
    return new ObjectShape(mVertices[variant], mIndices[variant]);
924
    }
925

    
926
///////////////////////////////////////////////////////////////////////////////////////////////////
927

    
928
  public ObjectFaceShape createIrregularFaceShape(int variant, boolean iconMode)
929
    {
930
    float[][] bands = getBands(iconMode, mNumLayers);
931
    float corr = mCalledFromBandagedObject ? 1.0f : sizeCorrection(mNumLayers);
932

    
933
    if( mBandIndices[variant]==null )
934
      {
935
      mFaceBelongsBitmap[variant] = computeFaceBelongsBitmap(mVertices[variant], mMove[variant],corr);
936
      mBandIndices[variant] = generateBandIndices(mVertices[variant], mIndices[variant], mFaceBelongsBitmap[variant]);
937
      }
938

    
939
    return new ObjectFaceShape(bands,mBandIndices[variant],null);
940
    }
941

    
942
///////////////////////////////////////////////////////////////////////////////////////////////////
943

    
944
  public ObjectVertexEffects createVertexEffects(int variant, boolean roundCorners)
945
    {
946
    float[][] vertVec= generateVectors(mVertices[variant], mIndices[variant], mBandIndices[variant]);
947
    int numEffects   = mVertices[variant].length;
948
    float S          = STRENGTH;
949
    float[] region   = {0,0,0,REGION_SIZE};
950
    String[] names   = new String[numEffects];
951
    float[][] regions= new float[numEffects][];
952
    boolean[] uses   = new boolean[numEffects];
953
    float[][] vars   = new float[numEffects][];
954

    
955
    for(int i=0; i<numEffects; i++)
956
      {
957
      float[] v = vertVec[i];
958

    
959
      if( v!=null )
960
        {
961
        names[i]  = FactoryCubit.NAME;
962
        regions[i]= region;
963
        uses[i]   = roundCorners;
964
        vars[i]   = new float[] { 0, S*v[0], S*v[1], S*v[2], 1 };
965
        }
966
      }
967

    
968
    return new ObjectVertexEffects(names,vars,mVertices[variant],regions,uses);
969
    }
970

    
971
///////////////////////////////////////////////////////////////////////////////////////////////////
972

    
973
  public MeshBase createMesh(float[] pos, int[] numLayers, boolean iconMode, boolean roundCorners)
974
    {
975
    prepare(1,numLayers);
976

    
977
    mCalledFromBandagedObject = true;
978

    
979
    ObjectShape shape           = createIrregularShape(0,pos);
980
    ObjectFaceShape face        = createIrregularFaceShape(0,iconMode);
981
    ObjectVertexEffects effects = createVertexEffects(0,roundCorners);
982
    int numFaces                = shape.getNumFaces();
983

    
984
    FactoryCubit factory = FactoryCubit.getInstance();
985
    factory.clear();
986
    factory.createNewFaceTransform(shape,null);
987
    return factory.createRoundedSolid(shape,face,effects,numFaces);
988
    }
989
  }
(9-9/15)