Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / FactoryBandagedCuboid.java @ c65d5889

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2020 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.helpers;
11

    
12
import java.util.ArrayList;
13

    
14
import org.distorted.library.mesh.MeshBase;
15
import org.distorted.library.type.Static3D;
16
import org.distorted.objectlib.touchcontrol.TouchControlHexahedron;
17

    
18
import static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
19

    
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21

    
22
public class FactoryBandagedCuboid
23
  {
24
  private static final int WALL_MARKED=0;
25
  private static final int WALL_EMPTY =-1;
26

    
27
  private static final int AXIS_XP = 0;
28
  private static final int AXIS_XM = 1;
29
  private static final int AXIS_YP = 2;
30
  private static final int AXIS_YM = 3;
31
  private static final int AXIS_ZP = 4;
32
  private static final int AXIS_ZM = 5;
33

    
34
  private static final float[][] VECTOR =
35
      {
36
          {-1.0f,-1.0f,-1.0f},
37
          {-1.0f,-1.0f,+1.0f},
38
          {-1.0f,+1.0f,-1.0f},
39
          {-1.0f,+1.0f,+1.0f},
40
          {+1.0f,-1.0f,-1.0f},
41
          {+1.0f,-1.0f,+1.0f},
42
          {+1.0f,+1.0f,-1.0f},
43
          {+1.0f,+1.0f,+1.0f}
44
      };
45

    
46
  private static FactoryBandagedCuboid mThis;
47
  private ArrayList<float[]> mVertexArray;
48
  private ArrayList<float[]> mTmpArray;
49
  private float[][][] mVertices;
50
  private int[][][] mIndices;
51
  private int[][] mBandIndices;
52
  private float[][] mMove;
53

    
54
  private int mX, mY, mZ, mMax;
55
  private float dX, dY, dZ;
56
  private int[][] mWall;
57
  private int[][] mPoints;
58
  private float[][] mCuts;
59
  private float[][] mNormal;
60
  private BandagedElementCuboid[] mElements;
61
  private int mNumElements;
62

    
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

    
65
  private FactoryBandagedCuboid()
66
    {
67

    
68
    }
69

    
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71

    
72
  public float[][] getCuts(int[] numLayers)
73
    {
74
    int numFaces = 6;
75
    float[][] cuts = new float[numFaces][];
76

    
77
    for(int axis=0; axis<numFaces; axis++)
78
      {
79
      int len = numLayers[axis/2];
80
      float start = 1-len*0.5f;
81

    
82
      if( len>=2 )
83
        {
84
        cuts[axis] = new float[len-1];
85
        for(int i=0; i<len-1; i++) cuts[axis][i] = start+i;
86
        }
87
      }
88

    
89
    return cuts;
90
    }
91

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

    
94
  private void createNormal()
95
    {
96
    if( mNormal==null )
97
      {
98
      mNormal = new float[][]
99
        {
100
          { 1, 0, 0 },
101
          {-1, 0, 0 },
102
          { 0, 1, 0 },
103
          { 0,-1, 0 },
104
          { 0, 0, 1 },
105
          { 0, 0,-1 }
106
        };
107
      }
108
    }
109

    
110
///////////////////////////////////////////////////////////////////////////////////////////////////
111

    
112
  private float[][] getVertices(ArrayList<float[]> list, float[] move, int variant)
113
    {
114
    int numMoves = move.length/3;
115
    mMove[variant][0]=0.0f;
116
    mMove[variant][1]=0.0f;
117
    mMove[variant][2]=0.0f;
118

    
119
    for(int m=0; m<numMoves; m++)
120
      {
121
      mMove[variant][0] += move[3*m  ];
122
      mMove[variant][1] += move[3*m+1];
123
      mMove[variant][2] += move[3*m+2];
124
      }
125

    
126
    mMove[variant][0]/=numMoves;
127
    mMove[variant][1]/=numMoves;
128
    mMove[variant][2]/=numMoves;
129

    
130
    int total  = 0;
131
    int length = list.size();
132
    float[][] vertices = new float[length][];
133

    
134
    for( int i=0; i<length; i++ )
135
      {
136
      vertices[i] = list.get(i);
137
      total += vertices[i].length/3;
138
      }
139

    
140
    float[][] verts = new float[total][3];
141
    int pointer = 0;
142

    
143
    for(int i=0; i<length; i++)
144
      {
145
      int len = vertices[i].length/3;
146

    
147
      for(int j=0; j<len; j++)
148
        {
149
        verts[pointer][0] = vertices[i][3*j  ] - mMove[variant][0];
150
        verts[pointer][1] = vertices[i][3*j+1] - mMove[variant][1];
151
        verts[pointer][2] = vertices[i][3*j+2] - mMove[variant][2];
152
        pointer++;
153
        }
154
      }
155

    
156
    return verts;
157
    }
158

    
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160

    
161
  private int[][] getIndices(ArrayList<float[]> list)
162
    {
163
    int indicesSoFar=0;
164
    int length = list.size();
165
    int[][] indices = new int[length][];
166

    
167
    for( int i=0; i<length; i++ )
168
      {
169
      float[] f = list.get(i);
170
      int len = f.length/3;
171
      int[] ind = new int[len];
172
      for(int j=0; j<len; j++) ind[j] = (indicesSoFar++);
173
      indices[i] = ind;
174
      }
175

    
176
    return indices;
177
    }
178

    
179
///////////////////////////////////////////////////////////////////////////////////////////////////
180

    
181
  private void markAllVertices(float[] vertex, float[][] vertices, int[][] indices, int pointer, int variant)
182
    {
183
    int lenI = indices.length;
184

    
185
    for(int index=0; index<lenI; index++)
186
      {
187
      int len = indices[index].length;
188

    
189
      for(int i=0; i<len; i++)
190
        {
191
        if( mIndices[variant][index][i] == -1 )
192
          {
193
          int ind = indices[index][i];
194
          float[] ver = vertices[ind];
195

    
196
          if( vertex[0]==ver[0] && vertex[1]==ver[1] && vertex[2]==ver[2] )
197
            {
198
            mIndices[variant][index][i] = pointer;
199
            }
200
          }
201
        }
202
      }
203
    }
204

    
205
///////////////////////////////////////////////////////////////////////////////////////////////////
206
// So far the 'vertices/indices' are stored inefficiently, with each vertex stored three times
207
// (each one normally is a corner of three faces) or even six times. Compress!
208
// Example of six times: the central vertex here:
209
//
210
// { 1.0f,  0.0f, -1.0f,
211
//   1.0f, -1.0f, -1.0f,
212
//   1.0f, -1.0f, +0.0f,
213
//   0.0f, -1.0f, -1.0f },
214

    
215
  private void compressVerticesAndIndices(int variant, float[][] vertices, int[][] indices)
216
    {
217
    if( mTmpArray==null ) mTmpArray = new ArrayList<>();
218

    
219
    int lenI = indices.length;
220
    int pointer=0;
221

    
222
    mIndices[variant] = new int[lenI][];
223

    
224
    for(int index=0; index<lenI; index++)
225
      {
226
      int len = indices[index].length;
227
      mIndices[variant][index] = new int[len];
228
      for(int i=0; i<len; i++) mIndices[variant][index][i] = -1;
229
      }
230

    
231
    for(int index=0; index<lenI; index++)
232
      {
233
      int len = indices[index].length;
234

    
235
      for(int i=0; i<len; i++)
236
        {
237
        if( mIndices[variant][index][i] == -1 )
238
          {
239
          int ind = indices[index][i];
240
          float[] ver = vertices[ind];
241
          mTmpArray.add(ver);
242
          markAllVertices(ver,vertices,indices,pointer,variant);
243
          pointer++;
244
          }
245
        }
246
      }
247

    
248
    int len = mTmpArray.size();
249
    mVertices[variant] = new float[len][];
250

    
251
    for(int i=0; i<len; i++)
252
      {
253
      mVertices[variant][i] = mTmpArray.remove(0);
254
      }
255
    }
256

    
257
///////////////////////////////////////////////////////////////////////////////////////////////////
258

    
259
  private boolean elementExists(int x, int y, int z)
260
    {
261
    for(int i=0; i<mNumElements; i++)
262
      {
263
      int[] row = mElements[i].getRotRow();
264
      if( row[0]==x && row[2]==y && row[4]==z ) return true;
265
      }
266

    
267
    return false;
268
    }
269

    
270
///////////////////////////////////////////////////////////////////////////////////////////////////
271

    
272
  private void displayWall(String tmp)
273
    {
274
    StringBuilder sb = new StringBuilder();
275

    
276
    for(int i=0; i<mMax; i++)
277
      {
278
      for(int j=0; j<mMax; j++)
279
        {
280
        sb.append(mWall[i][j]);
281
        sb.append(' ');
282
        }
283
      sb.append("  -  ");
284
      }
285

    
286
    android.util.Log.e("D", tmp+" : "+sb);
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

    
291
  private void createRight(int x, ArrayList<float[]> list)
292
    {
293
    for(int i=0; i<mMax; i++)
294
      for(int j=0; j<mMax; j++) mWall[i][j] = WALL_EMPTY;
295

    
296
    for(int i=0; i<mNumElements; i++)
297
      {
298
      int[] row = mElements[i].getRotRow();
299
      int y = mY-1-row[2];
300
      int z = mZ-1-row[4];
301
      if( row[0]==x ) mWall[z][y] = elementExists(x+1,y,z) ? WALL_EMPTY : WALL_MARKED;
302
      }
303

    
304
    createVertices(list,mWall,AXIS_XP,x);
305
    }
306

    
307
///////////////////////////////////////////////////////////////////////////////////////////////////
308

    
309
  private void createLeft(int x, ArrayList<float[]> list)
310
    {
311
    for(int i=0; i<mMax; i++)
312
      for(int j=0; j<mMax; j++) mWall[i][j] = WALL_EMPTY;
313

    
314
    for(int i=0; i<mNumElements; i++)
315
      {
316
      int[] row = mElements[i].getRotRow();
317
      int y = mY-1-row[2];
318
      int z = row[4];
319
      if( row[0]==x ) mWall[z][y] = elementExists(x-1,y,z) ? WALL_EMPTY : WALL_MARKED;
320
      }
321

    
322
    createVertices(list,mWall,AXIS_XM,x);
323
    }
324

    
325
///////////////////////////////////////////////////////////////////////////////////////////////////
326

    
327
  private void createTop(int y, ArrayList<float[]> list)
328
    {
329
    for(int i=0; i<mMax; i++)
330
      for(int j=0; j<mMax; j++) mWall[i][j] = WALL_EMPTY;
331

    
332
    for(int i=0; i< mNumElements; i++)
333
      {
334
      int[] row = mElements[i].getRotRow();
335
      int x = row[0];
336
      int z = row[4];
337
      if( row[2]==y ) mWall[x][z] = elementExists(x,y+1,z) ? WALL_EMPTY : WALL_MARKED;
338
      }
339

    
340
    createVertices(list,mWall,AXIS_YP,y);
341
    }
342

    
343
///////////////////////////////////////////////////////////////////////////////////////////////////
344

    
345
  private void createBottom(int y, ArrayList<float[]> list)
346
    {
347
    for(int i=0; i<mMax; i++)
348
      for(int j=0; j<mMax; j++) mWall[i][j] = WALL_EMPTY;
349

    
350
    for(int i=0; i<mNumElements; i++)
351
      {
352
      int[] row = mElements[i].getRotRow();
353
      int x = row[0];
354
      int z = mZ-1-row[4];
355
      if( row[2]==y ) mWall[x][z] = elementExists(x,y-1,z) ? WALL_EMPTY : WALL_MARKED;
356
      }
357

    
358
    createVertices(list,mWall,AXIS_YM,y);
359
    }
360

    
361
///////////////////////////////////////////////////////////////////////////////////////////////////
362

    
363
  private void createFront(int z, ArrayList<float[]> list)
364
    {
365
    for(int i=0; i<mMax; i++)
366
      for(int j=0; j<mMax; j++) mWall[i][j] = WALL_EMPTY;
367

    
368
    for(int i=0; i<mNumElements; i++)
369
      {
370
      int[] row = mElements[i].getRotRow();
371
      int x = row[0];
372
      int y = mY-1-row[2];
373
      if( row[4]==z ) mWall[x][y] = elementExists(x,y,z+1) ? WALL_EMPTY : WALL_MARKED;
374
      }
375

    
376
    createVertices(list,mWall,AXIS_ZP,z);
377
    }
378

    
379
///////////////////////////////////////////////////////////////////////////////////////////////////
380

    
381
  private void createBack(int z, ArrayList<float[]> list)
382
    {
383
    for(int i=0; i<mMax; i++)
384
      for(int j=0; j<mMax; j++) mWall[i][j] = WALL_EMPTY;
385

    
386
    for(int i=0; i<mNumElements; i++)
387
      {
388
      int[] row = mElements[i].getRotRow();
389
      int x = mX-1-row[0];
390
      int y = mY-1-row[2];
391
      if( row[4]==z ) mWall[x][y] = elementExists(x,y,z-1) ? WALL_EMPTY : WALL_MARKED;
392
      }
393

    
394
    createVertices(list,mWall,AXIS_ZM,z);
395
    }
396

    
397
///////////////////////////////////////////////////////////////////////////////////////////////////
398

    
399
  private void markNeighbours(int[][] wall, int x, int y, int section)
400
    {
401
    wall[x][y] = section;
402

    
403
    if( x  >   0 && wall[x-1][y]==WALL_MARKED ) markNeighbours(wall,x-1,y,section);
404
    if( x+1<mMax && wall[x+1][y]==WALL_MARKED ) markNeighbours(wall,x+1,y,section);
405
    if( y  >   0 && wall[x][y-1]==WALL_MARKED ) markNeighbours(wall,x,y-1,section);
406
    if( y+1<mMax && wall[x][y+1]==WALL_MARKED ) markNeighbours(wall,x,y+1,section);
407
    }
408

    
409
///////////////////////////////////////////////////////////////////////////////////////////////////
410

    
411
  private int markSections(int[][] wall)
412
    {
413
    int sections = 0;
414

    
415
    for(int x=0; x<mMax; x++)
416
      for(int y=0; y<mMax; y++)
417
        if( wall[x][y]==WALL_MARKED )
418
          {
419
          sections++;
420
          markNeighbours(wall,x,y,sections);
421
          }
422

    
423
    return sections;
424
    }
425

    
426
///////////////////////////////////////////////////////////////////////////////////////////////////
427
// return true iff exactly three or exactly one of the four values (x1,x2,x3,x4) are equal to 'value'.
428

    
429
  private boolean threeOrOne(int x1, int x2, int x3, int x4, int value)
430
    {
431
    if( x1==value ) return x2==value ? (x3==value)^(x4==value) : (x3==value)^(x4!=value);
432
    else            return x2==value ? (x3==value)^(x4!=value) : (x3==value)^(x4==value);
433
    }
434

    
435
///////////////////////////////////////////////////////////////////////////////////////////////////
436

    
437
  private boolean isOddVertical(int x, int y)
438
    {
439
    int number = 0;
440

    
441
    for(int i=0; i<y; i++)
442
      if( mPoints[x][i]==0 ) number++;
443

    
444
    return (number%2)==0;
445
    }
446

    
447
///////////////////////////////////////////////////////////////////////////////////////////////////
448

    
449
  private boolean isOddHorizontal(int x, int y)
450
    {
451
    int number = 0;
452

    
453
    for(int i=0; i<x; i++)
454
      if( mPoints[i][y]==0 ) number++;
455

    
456
    return (number%2)==0;
457
    }
458

    
459
///////////////////////////////////////////////////////////////////////////////////////////////////
460

    
461
  private int moveUp(int x, int y)
462
    {
463
    for(int i=y-1; i>=0; i--)
464
      if( mPoints[x][i]==0 ) return i;
465

    
466
    android.util.Log.e("D", "moveUp error!");
467
    return 0;
468
    }
469

    
470
///////////////////////////////////////////////////////////////////////////////////////////////////
471

    
472
  private int moveDown(int x, int y)
473
    {
474
    for(int i=y+1; i<=mMax; i++)
475
      if( mPoints[x][i]==0 ) return i;
476

    
477
    android.util.Log.e("D", "moveDown error!");
478
    return 0;
479
    }
480

    
481
///////////////////////////////////////////////////////////////////////////////////////////////////
482

    
483
  private int moveLeft(int x, int y)
484
    {
485
    for(int i=x-1; i>=0; i--)
486
      if( mPoints[i][y]==0 ) return i;
487

    
488
    android.util.Log.e("D", "moveLeft error!");
489
    return 0;
490
    }
491

    
492
///////////////////////////////////////////////////////////////////////////////////////////////////
493

    
494
  private int moveRight(int x, int y)
495
    {
496
    for(int i=x+1; i<=mMax; i++)
497
      if( mPoints[i][y]==0 ) return i;
498

    
499
    android.util.Log.e("D", "moveRight error!");
500
    return 0;
501
    }
502

    
503
///////////////////////////////////////////////////////////////////////////////////////////////////
504

    
505
  private float[] buildVertices(int[][] wall, int section, float dx, float dy)
506
    {
507
    int numPoints = buildPoints(wall,section);
508
    int numSections = numPoints/2;
509
    float[] vertices = new float[3*numPoints];
510
    int x=0,y=0,pointer=0;
511

    
512
    for(int i=0; i<=mMax; i++)
513
      for(int j=0; j<=mMax; j++)
514
        if( mPoints[i][j]==0 )
515
          {
516
          x = i;
517
          y = j;
518
          i = j = mMax+1;
519
          }
520

    
521
    for(int s=0; s<numSections; s++)
522
      {
523
      vertices[6*pointer  ] = x-dx;
524
      vertices[6*pointer+1] = dy-y;
525
      vertices[6*pointer+2] = 0.0f;
526

    
527
      y = isOddVertical(x,y) ? moveDown(x,y) : moveUp(x,y);
528

    
529
      vertices[6*pointer+3] = x-dx;
530
      vertices[6*pointer+4] = dy-y;
531
      vertices[6*pointer+5] = 0.0f;
532

    
533
      x = isOddHorizontal(x,y) ? moveRight(x,y) : moveLeft(x,y);
534

    
535
      pointer++;
536
      }
537

    
538
    return vertices;
539
    }
540

    
541
///////////////////////////////////////////////////////////////////////////////////////////////////
542

    
543
  private int buildPoints(int[][] wall, int section)
544
    {
545
    int numPoints=0;
546
    boolean thereIsCorner;
547

    
548
    for(int x=0; x<=mMax; x++)
549
      for(int y=0; y<=mMax; y++)
550
        {
551
        if( y==0 )
552
          {
553
               if( x==   0 ) thereIsCorner = (wall[     0][0]==section);
554
          else if( x==mMax ) thereIsCorner = (wall[mMax-1][0]==section);
555
          else               thereIsCorner = (wall[x-1][0]==section)^(wall[x][0]==section);
556
          }
557
        else if( y==mMax )
558
          {
559
               if( x==   0 ) thereIsCorner = (wall[     0][mMax-1]==section);
560
          else if( x==mMax ) thereIsCorner = (wall[mMax-1][mMax-1]==section);
561
          else               thereIsCorner = (wall[x-1][mMax-1]==section)^(wall[x][mMax-1]==section);
562
          }
563
        else if( x==0 )
564
          {
565
          thereIsCorner = (wall[0][y-1]==section)^(wall[0][y]==section);
566
          }
567
        else if( x==mMax )
568
          {
569
          thereIsCorner = (wall[mMax-1][y-1]==section)^(wall[mMax-1][y]==section);
570
          }
571
        else
572
          {
573
          thereIsCorner = threeOrOne(wall[x-1][y-1],wall[x-1][y],wall[x][y-1],wall[x][y],section);
574
          }
575

    
576
        if( thereIsCorner )
577
          {
578
          mPoints[x][y] = 0;
579
          numPoints++;
580
          }
581
        else
582
          {
583
          mPoints[x][y] =-1;
584
          }
585
        }
586

    
587
    return numPoints;
588
    }
589

    
590
///////////////////////////////////////////////////////////////////////////////////////////////////
591

    
592
  private void rotateAndMoveVertices(float[] vertices, int axis, int layer)
593
    {
594
    int i,len = vertices.length/3;
595

    
596
    switch(axis)
597
      {
598
      case AXIS_XP: for(i=0; i<len; i++)
599
                      {
600
                      vertices[3*i+2] =-vertices[3*i  ];
601
                      vertices[3*i  ] = layer-(dX-1.0f);
602
                      }
603
                    break;
604
      case AXIS_XM: for(i=0; i<len; i++)
605
                      {
606
                      vertices[3*i+2] = vertices[3*i  ];
607
                      vertices[3*i  ] = layer-dX;
608
                      }
609
                    break;
610
      case AXIS_YP: for(i=0; i<len; i++)
611
                      {
612
                      vertices[3*i+2] =-vertices[3*i+1];
613
                      vertices[3*i+1] = layer-(dY-1.0f);
614
                      }
615
                    break;
616
      case AXIS_YM: for(i=0; i<len; i++)
617
                      {
618
                      vertices[3*i+2] = vertices[3*i+1];
619
                      vertices[3*i+1] = layer-dY;
620
                      }
621
                    break;
622
      case AXIS_ZP: for(i=0; i<len; i++)
623
                      {
624
                      vertices[3*i+2] = layer-(dZ-1.0f);
625
                      }
626
                    break;
627
      case AXIS_ZM: for(i=0; i<len; i++)
628
                      {
629
                      vertices[3*i+2] = layer-dZ;
630
                      vertices[3*i  ] =-vertices[3*i  ];
631
                      }
632
                    break;
633
      }
634
    }
635

    
636
///////////////////////////////////////////////////////////////////////////////////////////////////
637
// 1. assume the 'wall' is in the XY plane
638
// 2. split the wall into individual connected regions and for each such region:
639
//   a. build the list of vertices (Z=0)
640
//   b. take the axis into consideration and rotate the vertices.
641
//   c. take layer into consideration and move the vertices.
642
//   d. add the resulting vertices to the list.
643

    
644
  private void createVertices(ArrayList<float[]> list, int[][] wall, int axis, int layer)
645
    {
646
    int sections = markSections(wall);
647

    
648
    float dx = (axis==AXIS_XP || axis==AXIS_XM) ? dZ : dX;
649
    float dy = (axis==AXIS_YP || axis==AXIS_YM) ? dZ : dY;
650

    
651
    for(int i=0; i<sections; i++)
652
      {
653
      float[] vertices = buildVertices(wall,i+1,dx,dy);
654

    
655
      rotateAndMoveVertices(vertices,axis,layer);
656
      list.add(vertices);
657
/*
658
      int len = vertices.length/3;
659
      String w="";
660

    
661
      for(int j=0; j<len; j++)
662
        {
663
        w += ( "["+vertices[3*j]+" "+vertices[3*j+1]+" "+vertices[3*j+2]+"] ");
664
        }
665
      android.util.Log.e("D", "1 section: "+i+" axis: "+axis+" layer: "+layer+" vertices after: "+w);
666
*/
667
      }
668
    }
669

    
670
///////////////////////////////////////////////////////////////////////////////////////////////////
671

    
672
  private static boolean vertInFace(float[] vertex, float[] move, Static3D faceAxis, float dist)
673
    {
674
    final float MAX_ERROR = 0.01f;
675

    
676
    float x= faceAxis.get0();
677
    float y= faceAxis.get1();
678
    float z= faceAxis.get2();
679

    
680
    float a = (vertex[0]+move[0])*x + (vertex[1]+move[1])*y + (vertex[2]+move[2])*z;
681
    float diff = a - dist;
682

    
683
    return diff>-MAX_ERROR && diff<MAX_ERROR;
684
    }
685

    
686
///////////////////////////////////////////////////////////////////////////////////////////////////
687
// (vertices,indices) define a cubit face, i.e. a connected subset of the NxN grid.
688
// Return its 'diameter', i.e. max(width,height)
689

    
690
  private int faceDiameter(float[][] vertices, int[] indices)
691
    {
692
    float maxX = -dX;
693
    float minX =  dX;
694
    float maxY = -dY;
695
    float minY =  dY;
696
    float maxZ = -dZ;
697
    float minZ =  dZ;
698

    
699
    for (int index : indices)
700
      {
701
      float[] v = vertices[index];
702

    
703
      if (v[0] > maxX) maxX = v[0];
704
      if (v[0] < minX) minX = v[0];
705
      if (v[1] > maxY) maxY = v[1];
706
      if (v[1] < minY) minY = v[1];
707
      if (v[2] > maxZ) maxZ = v[2];
708
      if (v[2] < minZ) minZ = v[2];
709
      }
710

    
711
    float diffX = maxX-minX;
712
    float diffY = maxY-minY;
713
    float diffZ = maxZ-minZ;
714

    
715
    float max = diffX>diffY ? Math.max(diffX,diffZ) : Math.max(diffY,diffZ);
716

    
717
    return (int)max;
718
    }
719

    
720
///////////////////////////////////////////////////////////////////////////////////////////////////
721
// return array of:
722
// 0 if this is an inner face, 1 if its diameter is 1, 2 if diameter is 2, 3 if 3, etc
723
// but only up to 5 (because the number of bands is 6 - see createIrregularFaceShape() )
724

    
725
  private int[] generateBandIndices(float[][] vertices, int[][] indices, float[] move)
726
    {
727
    int numCubitFaces = indices.length;
728
    int[] bandIndices = new int[numCubitFaces];
729

    
730
    for(int cubitFace=0; cubitFace<numCubitFaces; cubitFace++)
731
      {
732
      bandIndices[cubitFace] = 0xffffffff;
733
      int numVertices = indices[cubitFace].length;
734

    
735
      for(int vertex=0; vertex<numVertices; vertex++)
736
        {
737
        int vertBelongsBitmap = 0x00000000;
738
        float[] vert = vertices[ indices[cubitFace][vertex] ];
739

    
740
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[0], dX) ) vertBelongsBitmap |= (1   );
741
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[1], dX) ) vertBelongsBitmap |= (1<<1);
742
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[2], dY) ) vertBelongsBitmap |= (1<<2);
743
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[3], dY) ) vertBelongsBitmap |= (1<<3);
744
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[4], dZ) ) vertBelongsBitmap |= (1<<4);
745
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[5], dZ) ) vertBelongsBitmap |= (1<<5);
746

    
747
        bandIndices[cubitFace] &= vertBelongsBitmap;
748
        }
749

    
750
      if( bandIndices[cubitFace]!=0 ) // outer face
751
        {
752
        int diameter = faceDiameter(vertices, indices[cubitFace]);
753
        bandIndices[cubitFace] = (diameter>=6 ? 5:diameter);
754
        }
755

    
756
      //android.util.Log.e("D", "cubit face "+cubitFace+" : "+bandIndices[cubitFace]);
757
      }
758

    
759
    return bandIndices;
760
    }
761

    
762
///////////////////////////////////////////////////////////////////////////////////////////////////
763

    
764
  private int computeVectorFace(float[] prev, float[] curr, float[] next)
765
    {
766
    float ax = prev[0]-curr[0];
767
    float ay = prev[1]-curr[1];
768
    float az = prev[2]-curr[2];
769

    
770
    float bx = next[0]-curr[0];
771
    float by = next[1]-curr[1];
772
    float bz = next[2]-curr[2];
773

    
774
    float lena = (float)Math.sqrt(ax*ax + ay*ay + az*az);
775
    float lenb = (float)Math.sqrt(bx*bx + by*by + bz*bz);
776

    
777
    ax /= lena;
778
    ay /= lena;
779
    az /= lena;
780

    
781
    bx /= lenb;
782
    by /= lenb;
783
    bz /= lenb;
784

    
785
    float cx = ax + bx + ay*bz-az*by;
786
    float cy = ay + by + az*bx-ax*bz;
787
    float cz = az + bz + ax*by-ay*bx;
788

    
789
    return (cx<0 ? 0:4) + (cy<0 ? 0:2) + (cz<0 ? 0:1);
790
    }
791

    
792
///////////////////////////////////////////////////////////////////////////////////////////////////
793

    
794
  private float[] computeVector(int index, float[][] vertices, int[][] indices, int[] bandIndices)
795
    {
796
    int band=0;
797
    int len = indices.length;
798
    int vector=-1;
799

    
800
    for(int i=0; i<len; i++)
801
      {
802
      int len2 = indices[i].length;
803

    
804
      for(int j=0; j<len2; j++)
805
        {
806
        if( indices[i][j]==index )
807
          {
808
          int prev = j>0 ? j-1 : len2-1;
809
          int next = j<len2-1 ? j+1 : 0;
810

    
811
          int prevIndex = indices[i][prev];
812
          int currIndex = indices[i][j];
813
          int nextIndex = indices[i][next];
814

    
815
          int newVector = computeVectorFace(vertices[prevIndex],vertices[currIndex],vertices[nextIndex]);
816
          if( vector!=-1 && vector!=newVector ) return null;
817

    
818
          vector = newVector;
819
          band |= bandIndices[i];
820
          }
821
        }
822
      }
823

    
824
    return band==0 ? null : VECTOR[vector];
825
    }
826

    
827
///////////////////////////////////////////////////////////////////////////////////////////////////
828

    
829
  private float[][] generateVectors(float[][] vertices, int[][] indices, int[] bandIndices)
830
    {
831
    int len = vertices.length;
832
    float[][] vectors = new float[len][];
833

    
834
    for(int i=0; i<len; i++)
835
      {
836
      vectors[i] = computeVector(i,vertices,indices,bandIndices);
837
      }
838

    
839
    return vectors;
840
    }
841

    
842
///////////////////////////////////////////////////////////////////////////////////////////////////
843

    
844
  private void debug(float[][] vert, int[][] ind)
845
    {
846
    String vv="VERTICES: ";
847
    for (float[] floats : vert)
848
      {
849
      vv += "\n";
850
      int lenV2 = floats.length / 3;
851

    
852
      for (int v2 = 0; v2 < lenV2; v2++)
853
        {
854
        vv += " {";
855
        vv += (floats[3 * v2] + " ");
856
        vv += (floats[3 * v2 + 1] + " ");
857
        vv += (floats[3 * v2 + 2] + " ");
858
        vv += "}";
859
        }
860
      }
861
    android.util.Log.e("D", vv);
862

    
863
    String ii="INDICES: ";
864
    for (int[] ints : ind)
865
      {
866
      ii += "\n";
867
      int lenI2 = ints.length;
868

    
869
      for (int i2 = 0; i2 < lenI2; i2++)
870
        {
871
        ii += (ints[i2] + " ");
872
        }
873
      }
874
    android.util.Log.e("D", ii);
875
    }
876

    
877
///////////////////////////////////////////////////////////////////////////////////////////////////
878
// PUBLIC API
879

    
880
  public static FactoryBandagedCuboid getInstance()
881
    {
882
    if( mThis==null ) mThis = new FactoryBandagedCuboid();
883
    return mThis;
884
    }
885

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

    
888
  public void prepare(int numVariants, int[] numLayers)
889
    {
890
    if( mVertexArray==null ) mVertexArray = new ArrayList<>();
891
    mVertices= new float[numVariants][][];
892
    mIndices = new int[numVariants][][];
893
    mMove = new float[numVariants][3];
894
    mBandIndices = new int[numVariants][];
895

    
896
    mX = numLayers[0];
897
    mY = numLayers[1];
898
    mZ = numLayers[2];
899

    
900
    dX = mX/2.0f;
901
    dY = mY/2.0f;
902
    dZ = mZ/2.0f;
903

    
904
    mMax = mX>mY ? Math.max(mX,mZ) : Math.max(mY,mZ);
905

    
906
    mWall   = new int[mMax][mMax];
907
    mPoints = new int[mMax+1][mMax+1];
908
    mCuts   = getCuts(numLayers);
909

    
910
    createNormal();
911
    }
912

    
913
///////////////////////////////////////////////////////////////////////////////////////////////////
914

    
915
  public ObjectShape createIrregularShape(int variant, float[] pos)
916
    {
917
    mVertexArray.clear();
918

    
919
    mNumElements = pos.length/3;
920
    mElements = new BandagedElementCuboid[mNumElements];
921
    for(int i=0; i<mNumElements; i++) mElements[i] = new BandagedElementCuboid(pos, 3*i, mNormal, mCuts);
922

    
923
    for(int x=0; x<mX; x++) createRight (x,mVertexArray);
924
    for(int x=0; x<mX; x++) createLeft  (x,mVertexArray);
925
    for(int y=0; y<mY; y++) createTop   (y,mVertexArray);
926
    for(int y=0; y<mY; y++) createBottom(y,mVertexArray);
927
    for(int z=0; z<mZ; z++) createFront (z,mVertexArray);
928
    for(int z=0; z<mZ; z++) createBack  (z,mVertexArray);
929

    
930
    float[][] verts = getVertices(mVertexArray,pos,variant);
931
    int[][] inds    = getIndices(mVertexArray);
932

    
933
    compressVerticesAndIndices(variant,verts,inds);
934
    mBandIndices[variant] = generateBandIndices(mVertices[variant], mIndices[variant], mMove[variant]);
935

    
936
    return new ObjectShape(mVertices[variant], mIndices[variant]);
937
    }
938

    
939
///////////////////////////////////////////////////////////////////////////////////////////////////
940

    
941
  public ObjectVertexEffects createVertexEffects(int variant, boolean roundCorners)
942
    {
943
    float[][] vertVec= generateVectors(mVertices[variant], mIndices[variant], mBandIndices[variant]);
944
    int numEffects   = mVertices[variant].length;
945
    float S          = 0.04f;
946
    float[] region   = {0,0,0,0.15f};
947
    String[] names   = new String[numEffects];
948
    float[][] regions= new float[numEffects][];
949
    boolean[] uses   = new boolean[numEffects];
950
    float[][] vars   = new float[numEffects][];
951

    
952
    for(int i=0; i<numEffects; i++)
953
      {
954
      float[] v = vertVec[i];
955

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

    
965
    return new ObjectVertexEffects(names,vars,mVertices[variant],regions,uses);
966
    }
967

    
968
///////////////////////////////////////////////////////////////////////////////////////////////////
969

    
970
  public ObjectFaceShape createIrregularFaceShape(int variant, boolean iconMode)
971
    {
972
    float height= iconMode ? 0.001f : 0.048f;
973
    int angle   = 60;
974
    float R     = 0.2f;
975
    float S     = 0.5f;
976
    int numVerts= (mX+mY+mZ)>= 16 ? 4:5;
977
    int extraI  = 0;
978
    int extraV  = 0;
979

    
980
    float[][] bands  = { {  0.001f,angle,R,S,numVerts,extraV,extraI},
981
                         {height/1,angle,R,S,numVerts,extraV,extraI},
982
                         {height/2,angle,R,S,numVerts,extraV,extraI},
983
                         {height/3,angle,R,S,numVerts,extraV,extraI},
984
                         {height/4,angle,R,S,numVerts,extraV,extraI},
985
                         {height/5,angle,R,S,numVerts,extraV,extraI} };
986

    
987
    return new ObjectFaceShape(bands,mBandIndices[variant],null);
988
    }
989

    
990
///////////////////////////////////////////////////////////////////////////////////////////////////
991

    
992
  public MeshBase createMesh(float[] pos, int[] numLayers, boolean iconMode, boolean roundCorners)
993
    {
994
    prepare(1,numLayers);
995
    ObjectShape shape           = createIrregularShape(0,pos);
996
    ObjectFaceShape face        = createIrregularFaceShape(0,iconMode);
997
    ObjectVertexEffects effects = createVertexEffects(0,roundCorners);
998
    int[][] indices             = shape.getVertIndices();
999
    int numComponents           = indices.length;
1000

    
1001
    FactoryCubit factory = FactoryCubit.getInstance();
1002
    factory.clear();
1003
    factory.createNewFaceTransform(shape,null);
1004
    return factory.createRoundedSolid(shape,face,effects,MESH_NICE,numComponents);
1005
    }
1006
  }
(3-3/16)