Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / FactoryBandagedPyraminx.java @ c18507d9

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 static org.distorted.objectlib.main.TwistyObject.MESH_NICE;
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 java.util.ArrayList;
19

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

    
22
public class FactoryBandagedPyraminx
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 FactoryBandagedPyraminx 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 boolean[][][] mTmp;
59

    
60
///////////////////////////////////////////////////////////////////////////////////////////////////
61

    
62
  private FactoryBandagedPyraminx()
63
    {
64

    
65
    }
66

    
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68

    
69
  private float[][] getVertices(ArrayList<float[]> list, float[] move, int variant)
70
    {
71
    int numMoves = move.length/3;
72
    mMove[variant][0]=0.0f;
73
    mMove[variant][1]=0.0f;
74
    mMove[variant][2]=0.0f;
75

    
76
    for(int m=0; m<numMoves; m++)
77
      {
78
      mMove[variant][0] += move[3*m  ];
79
      mMove[variant][1] += move[3*m+1];
80
      mMove[variant][2] += move[3*m+2];
81
      }
82

    
83
    mMove[variant][0]/=numMoves;
84
    mMove[variant][1]/=numMoves;
85
    mMove[variant][2]/=numMoves;
86

    
87
    int total  = 0;
88
    int length = list.size();
89
    float[][] vertices = new float[length][];
90

    
91
    for( int i=0; i<length; i++ )
92
      {
93
      vertices[i] = list.get(i);
94
      total += vertices[i].length/3;
95
      }
96

    
97
    float[][] verts = new float[total][3];
98
    int pointer = 0;
99

    
100
    for(int i=0; i<length; i++)
101
      {
102
      int len = vertices[i].length/3;
103

    
104
      for(int j=0; j<len; j++)
105
        {
106
        verts[pointer][0] = vertices[i][3*j  ] - mMove[variant][0];
107
        verts[pointer][1] = vertices[i][3*j+1] - mMove[variant][1];
108
        verts[pointer][2] = vertices[i][3*j+2] - mMove[variant][2];
109
        pointer++;
110
        }
111
      }
112

    
113
    return verts;
114
    }
115

    
116
///////////////////////////////////////////////////////////////////////////////////////////////////
117

    
118
  private int[][] getIndices(ArrayList<float[]> list)
119
    {
120
    int indicesSoFar=0;
121
    int length = list.size();
122
    int[][] indices = new int[length][];
123

    
124
    for( int i=0; i<length; i++ )
125
      {
126
      float[] f = list.get(i);
127
      int len = f.length/3;
128
      int[] ind = new int[len];
129
      for(int j=0; j<len; j++) ind[j] = (indicesSoFar++);
130
      indices[i] = ind;
131
      }
132

    
133
    return indices;
134
    }
135

    
136
///////////////////////////////////////////////////////////////////////////////////////////////////
137

    
138
  private void markAllVertices(float[] vertex, float[][] vertices, int[][] indices, int pointer, int variant)
139
    {
140
    int lenI = indices.length;
141

    
142
    for(int index=0; index<lenI; index++)
143
      {
144
      int len = indices[index].length;
145

    
146
      for(int i=0; i<len; i++)
147
        {
148
        if( mIndices[variant][index][i] == -1 )
149
          {
150
          int ind = indices[index][i];
151
          float[] ver = vertices[ind];
152

    
153
          if( vertex[0]==ver[0] && vertex[1]==ver[1] && vertex[2]==ver[2] )
154
            {
155
            mIndices[variant][index][i] = pointer;
156
            }
157
          }
158
        }
159
      }
160
    }
161

    
162
///////////////////////////////////////////////////////////////////////////////////////////////////
163
// So far the 'vertices/indices' are stored inefficiently, with each vertex stored three times
164
// (each one normally is a corner of three faces) or even six times. Compress!
165
// Example of six times: the central vertex here:
166
//
167
// { 1.0f,  0.0f, -1.0f,
168
//   1.0f, -1.0f, -1.0f,
169
//   1.0f, -1.0f, +0.0f,
170
//   0.0f, -1.0f, -1.0f },
171

    
172
  private void compressVerticesAndIndices(int variant, float[][] vertices, int[][] indices)
173
    {
174
    if( mTmpArray==null ) mTmpArray = new ArrayList<>();
175

    
176
    int lenI = indices.length;
177
    int pointer=0;
178

    
179
    mIndices[variant] = new int[lenI][];
180

    
181
    for(int index=0; index<lenI; index++)
182
      {
183
      int len = indices[index].length;
184
      mIndices[variant][index] = new int[len];
185
      for(int i=0; i<len; i++) mIndices[variant][index][i] = -1;
186
      }
187

    
188
    for(int index=0; index<lenI; index++)
189
      {
190
      int len = indices[index].length;
191

    
192
      for(int i=0; i<len; i++)
193
        {
194
        if( mIndices[variant][index][i] == -1 )
195
          {
196
          int ind = indices[index][i];
197
          float[] ver = vertices[ind];
198
          mTmpArray.add(ver);
199
          markAllVertices(ver,vertices,indices,pointer,variant);
200
          pointer++;
201
          }
202
        }
203
      }
204

    
205
    int len = mTmpArray.size();
206
    mVertices[variant] = new float[len][];
207

    
208
    for(int i=0; i<len; i++)
209
      {
210
      mVertices[variant][i] = mTmpArray.remove(0);
211
      }
212
    }
213

    
214
///////////////////////////////////////////////////////////////////////////////////////////////////
215

    
216
  private boolean cubitExists(float[] pos, float x, float y, float z)
217
    {
218
    int len = pos.length/3;
219

    
220
    for(int i=0; i<len; i++)
221
      if( pos[3*i]==x && pos[3*i+1]==y && pos[3*i+2]==z ) return true;
222

    
223
    return false;
224
    }
225

    
226
///////////////////////////////////////////////////////////////////////////////////////////////////
227

    
228
  private void createRight(int x, ArrayList<float[]> list)
229
    {
230
    for(int y=0; y<mMax; y++)
231
      for(int z=0; z<mMax; z++)
232
        {
233
        boolean b = (y<mY && z<mZ) && ( mTmp[x][mY-1-y][mZ-1-z] && (x+1>=mX || !mTmp[x+1][mY-1-y][mZ-1-z]) );
234
        mWall[z][y] = b ? WALL_MARKED : WALL_EMPTY;
235
        }
236

    
237
    createVertices(list,mWall,AXIS_XP,x);
238
    }
239

    
240
///////////////////////////////////////////////////////////////////////////////////////////////////
241

    
242
  private void createLeft(int x, ArrayList<float[]> list)
243
    {
244
    for(int y=0; y<mMax; y++)
245
      for(int z=0; z<mMax; z++)
246
        {
247
        boolean b = (y<mY && z<mZ) && ( mTmp[x][mY-1-y][z] && (x<1 || !mTmp[x-1][mY-1-y][z]) );
248
        mWall[z][y] = b ? WALL_MARKED : WALL_EMPTY;
249
        }
250

    
251
    createVertices(list,mWall,AXIS_XM,x);
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255

    
256
  private void createTop(int y, ArrayList<float[]> list)
257
    {
258
    for(int z=0; z<mMax; z++)
259
      for(int x=0; x<mMax; x++)
260
        {
261
        boolean b = (x<mX && z<mZ) && ( mTmp[x][y][z] && (y+1>=mY || !mTmp[x][y+1][z]) );
262
        mWall[x][z] = b ? WALL_MARKED : WALL_EMPTY;
263
        }
264

    
265
    createVertices(list,mWall,AXIS_YP,y);
266
    }
267

    
268
///////////////////////////////////////////////////////////////////////////////////////////////////
269

    
270
  private void createBottom(int y, ArrayList<float[]> list)
271
    {
272
    for(int z=0; z<mMax; z++)
273
      for(int x=0; x<mMax; x++)
274
        {
275
        boolean b = (x<mX && z<mZ) && ( mTmp[x][y][mZ-1-z] && (y<1 || !mTmp[x][y-1][mZ-1-z]) );
276
        mWall[x][z] = b ? WALL_MARKED : WALL_EMPTY;
277
        }
278

    
279
    createVertices(list,mWall,AXIS_YM,y);
280
    }
281

    
282
///////////////////////////////////////////////////////////////////////////////////////////////////
283

    
284
  private void createFront(int z, ArrayList<float[]> list)
285
    {
286
    for(int y=0; y<mMax; y++)
287
      for(int x=0; x<mMax; x++)
288
        {
289
        boolean b = (x<mX && y<mY) && ( mTmp[x][mY-1-y][z] && (z+1>=mZ || !mTmp[x][mY-1-y][z+1]) );
290
        mWall[x][y] = b ? WALL_MARKED : WALL_EMPTY;
291
        }
292

    
293
    createVertices(list,mWall,AXIS_ZP,z);
294
    }
295

    
296
///////////////////////////////////////////////////////////////////////////////////////////////////
297

    
298
  private void createBack(int z, ArrayList<float[]> list)
299
    {
300
    for(int y=0; y<mMax; y++)
301
      for(int x=0; x<mMax; x++)
302
        {
303
        boolean b = (x<mX && y<mY) && ( mTmp[mX-1-x][mY-1-y][z] && (z<1 || !mTmp[mX-1-x][mY-1-y][z-1]) );
304
        mWall[x][y] = b ? WALL_MARKED : WALL_EMPTY;
305
        }
306

    
307
    createVertices(list,mWall,AXIS_ZM,z);
308
    }
309

    
310
///////////////////////////////////////////////////////////////////////////////////////////////////
311

    
312
  private void markNeighbours(int[][] wall, int x, int y, int section)
313
    {
314
    wall[x][y] = section;
315

    
316
    if( x  >   0 && wall[x-1][y]==WALL_MARKED ) markNeighbours(wall,x-1,y,section);
317
    if( x+1<mMax && wall[x+1][y]==WALL_MARKED ) markNeighbours(wall,x+1,y,section);
318
    if( y  >   0 && wall[x][y-1]==WALL_MARKED ) markNeighbours(wall,x,y-1,section);
319
    if( y+1<mMax && wall[x][y+1]==WALL_MARKED ) markNeighbours(wall,x,y+1,section);
320
    }
321

    
322
///////////////////////////////////////////////////////////////////////////////////////////////////
323

    
324
  private int markSections(int[][] wall)
325
    {
326
    int sections = 0;
327

    
328
    for(int x=0; x<mMax; x++)
329
      for(int y=0; y<mMax; y++)
330
        if( wall[x][y]==WALL_MARKED )
331
          {
332
          sections++;
333
          markNeighbours(wall,x,y,sections);
334
          }
335

    
336
    return sections;
337
    }
338

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

    
342
  private boolean threeOrOne(int x1, int x2, int x3, int x4, int value)
343
    {
344
    if( x1==value ) return x2==value ? (x3==value)^(x4==value) : (x3==value)^(x4!=value);
345
    else            return x2==value ? (x3==value)^(x4!=value) : (x3==value)^(x4==value);
346
    }
347

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

    
350
  private boolean isOddVertical(int x, int y)
351
    {
352
    int number = 0;
353

    
354
    for(int i=0; i<y; i++)
355
      if( mPoints[x][i]==0 ) number++;
356

    
357
    return (number%2)==0;
358
    }
359

    
360
///////////////////////////////////////////////////////////////////////////////////////////////////
361

    
362
  private boolean isOddHorizontal(int x, int y)
363
    {
364
    int number = 0;
365

    
366
    for(int i=0; i<x; i++)
367
      if( mPoints[i][y]==0 ) number++;
368

    
369
    return (number%2)==0;
370
    }
371

    
372
///////////////////////////////////////////////////////////////////////////////////////////////////
373

    
374
  private int moveUp(int x, int y)
375
    {
376
    for(int i=y-1; i>=0; i--)
377
      if( mPoints[x][i]==0 ) return i;
378

    
379
    android.util.Log.e("D", "moveUp error!");
380
    return 0;
381
    }
382

    
383
///////////////////////////////////////////////////////////////////////////////////////////////////
384

    
385
  private int moveDown(int x, int y)
386
    {
387
    for(int i=y+1; i<=mMax; i++)
388
      if( mPoints[x][i]==0 ) return i;
389

    
390
    android.util.Log.e("D", "moveDown error!");
391
    return 0;
392
    }
393

    
394
///////////////////////////////////////////////////////////////////////////////////////////////////
395

    
396
  private int moveLeft(int x, int y)
397
    {
398
    for(int i=x-1; i>=0; i--)
399
      if( mPoints[i][y]==0 ) return i;
400

    
401
    android.util.Log.e("D", "moveLeft error!");
402
    return 0;
403
    }
404

    
405
///////////////////////////////////////////////////////////////////////////////////////////////////
406

    
407
  private int moveRight(int x, int y)
408
    {
409
    for(int i=x+1; i<=mMax; i++)
410
      if( mPoints[i][y]==0 ) return i;
411

    
412
    android.util.Log.e("D", "moveRight error!");
413
    return 0;
414
    }
415

    
416
///////////////////////////////////////////////////////////////////////////////////////////////////
417

    
418
  private float[] buildVertices(int[][] wall, int section, float dx, float dy)
419
    {
420
    int numPoints = buildPoints(wall,section);
421
    int numSections = numPoints/2;
422
    float[] vertices = new float[3*numPoints];
423
    int x=0,y=0,pointer=0;
424

    
425
    for(int i=0; i<=mMax; i++)
426
      for(int j=0; j<=mMax; j++)
427
        if( mPoints[i][j]==0 )
428
          {
429
          x = i;
430
          y = j;
431
          i = j = mMax+1;
432
          }
433

    
434
    for(int s=0; s<numSections; s++)
435
      {
436
      vertices[6*pointer  ] = x-dx;
437
      vertices[6*pointer+1] = dy-y;
438
      vertices[6*pointer+2] = 0.0f;
439

    
440
      y = isOddVertical(x,y) ? moveDown(x,y) : moveUp(x,y);
441

    
442
      vertices[6*pointer+3] = x-dx;
443
      vertices[6*pointer+4] = dy-y;
444
      vertices[6*pointer+5] = 0.0f;
445

    
446
      x = isOddHorizontal(x,y) ? moveRight(x,y) : moveLeft(x,y);
447

    
448
      pointer++;
449
      }
450

    
451
    return vertices;
452
    }
453

    
454
///////////////////////////////////////////////////////////////////////////////////////////////////
455

    
456
  private int buildPoints(int[][] wall, int section)
457
    {
458
    int numPoints=0;
459
    boolean thereIsCorner;
460

    
461
    for(int x=0; x<=mMax; x++)
462
      for(int y=0; y<=mMax; y++)
463
        {
464
        if( y==0 )
465
          {
466
               if( x==   0 ) thereIsCorner = (wall[     0][0]==section);
467
          else if( x==mMax ) thereIsCorner = (wall[mMax-1][0]==section);
468
          else               thereIsCorner = (wall[x-1][0]==section)^(wall[x][0]==section);
469
          }
470
        else if( y==mMax )
471
          {
472
               if( x==   0 ) thereIsCorner = (wall[     0][mMax-1]==section);
473
          else if( x==mMax ) thereIsCorner = (wall[mMax-1][mMax-1]==section);
474
          else               thereIsCorner = (wall[x-1][mMax-1]==section)^(wall[x][mMax-1]==section);
475
          }
476
        else if( x==0 )
477
          {
478
          thereIsCorner = (wall[0][y-1]==section)^(wall[0][y]==section);
479
          }
480
        else if( x==mMax )
481
          {
482
          thereIsCorner = (wall[mMax-1][y-1]==section)^(wall[mMax-1][y]==section);
483
          }
484
        else
485
          {
486
          thereIsCorner = threeOrOne(wall[x-1][y-1],wall[x-1][y],wall[x][y-1],wall[x][y],section);
487
          }
488

    
489
        if( thereIsCorner )
490
          {
491
          mPoints[x][y] = 0;
492
          numPoints++;
493
          }
494
        else
495
          {
496
          mPoints[x][y] =-1;
497
          }
498
        }
499

    
500
    return numPoints;
501
    }
502

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

    
505
  private void rotateAndMoveVertices(float[] vertices, int axis, int layer)
506
    {
507
    int i,len = vertices.length/3;
508

    
509
    switch(axis)
510
      {
511
      case AXIS_XP: for(i=0; i<len; i++)
512
                      {
513
                      vertices[3*i+2] =-vertices[3*i  ];
514
                      vertices[3*i  ] = layer-(dX-1.0f);
515
                      }
516
                    break;
517
      case AXIS_XM: for(i=0; i<len; i++)
518
                      {
519
                      vertices[3*i+2] = vertices[3*i  ];
520
                      vertices[3*i  ] = layer-dX;
521
                      }
522
                    break;
523
      case AXIS_YP: for(i=0; i<len; i++)
524
                      {
525
                      vertices[3*i+2] =-vertices[3*i+1];
526
                      vertices[3*i+1] = layer-(dY-1.0f);
527
                      }
528
                    break;
529
      case AXIS_YM: for(i=0; i<len; i++)
530
                      {
531
                      vertices[3*i+2] = vertices[3*i+1];
532
                      vertices[3*i+1] = layer-dY;
533
                      }
534
                    break;
535
      case AXIS_ZP: for(i=0; i<len; i++)
536
                      {
537
                      vertices[3*i+2] = layer-(dZ-1.0f);
538
                      }
539
                    break;
540
      case AXIS_ZM: for(i=0; i<len; i++)
541
                      {
542
                      vertices[3*i+2] = layer-dZ;
543
                      vertices[3*i  ] =-vertices[3*i  ];
544
                      }
545
                    break;
546
      }
547
    }
548

    
549
///////////////////////////////////////////////////////////////////////////////////////////////////
550
// 1. assume the 'wall' is in the XY plane
551
// 2. split the wall into individual connected regions and for each such region:
552
//   a. build the list of vertices (Z=0)
553
//   b. take the axis into consideration and rotate the vertices.
554
//   c. take layer into consideration and move the vertices.
555
//   d. add the resulting vertices to the list.
556

    
557
  private void createVertices(ArrayList<float[]> list, int[][] wall, int axis, int layer)
558
    {
559
    int sections = markSections(wall);
560

    
561
    float dx = (axis==AXIS_XP || axis==AXIS_XM) ? dZ : dX;
562
    float dy = (axis==AXIS_YP || axis==AXIS_YM) ? dZ : dY;
563

    
564
    for(int i=0; i<sections; i++)
565
      {
566
      float[] vertices = buildVertices(wall,i+1,dx,dy);
567

    
568
      rotateAndMoveVertices(vertices,axis,layer);
569
      list.add(vertices);
570
/*
571
      int len = vertices.length/3;
572
      String w="";
573

    
574
      for(int j=0; j<len; j++)
575
        {
576
        w += ( "["+vertices[3*j]+" "+vertices[3*j+1]+" "+vertices[3*j+2]+"] ");
577
        }
578
      android.util.Log.e("D", "1 section: "+i+" axis: "+axis+" layer: "+layer+" vertices after: "+w);
579
*/
580
      }
581
    }
582

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

    
585
  private static boolean vertInFace(float[] vertex, float[] move, Static3D faceAxis, float dist)
586
    {
587
    final float MAX_ERROR = 0.01f;
588

    
589
    float x= faceAxis.get0();
590
    float y= faceAxis.get1();
591
    float z= faceAxis.get2();
592

    
593
    float a = (vertex[0]+move[0])*x + (vertex[1]+move[1])*y + (vertex[2]+move[2])*z;
594
    float diff = a - dist;
595

    
596
    return diff>-MAX_ERROR && diff<MAX_ERROR;
597
    }
598

    
599
///////////////////////////////////////////////////////////////////////////////////////////////////
600
// (vertices,indices) define a cubit face, i.e. a connected subset of the NxN grid.
601
// Return its 'diameter', i.e. max(width,height)
602

    
603
  private int faceDiameter(float[][] vertices, int[] indices)
604
    {
605
    float maxX = -dX;
606
    float minX =  dX;
607
    float maxY = -dY;
608
    float minY =  dY;
609
    float maxZ = -dZ;
610
    float minZ =  dZ;
611

    
612
    for (int index : indices)
613
      {
614
      float[] v = vertices[index];
615

    
616
      if (v[0] > maxX) maxX = v[0];
617
      if (v[0] < minX) minX = v[0];
618
      if (v[1] > maxY) maxY = v[1];
619
      if (v[1] < minY) minY = v[1];
620
      if (v[2] > maxZ) maxZ = v[2];
621
      if (v[2] < minZ) minZ = v[2];
622
      }
623

    
624
    float diffX = maxX-minX;
625
    float diffY = maxY-minY;
626
    float diffZ = maxZ-minZ;
627

    
628
    float max = diffX>diffY ? Math.max(diffX,diffZ) : Math.max(diffY,diffZ);
629

    
630
    return (int)max;
631
    }
632

    
633
///////////////////////////////////////////////////////////////////////////////////////////////////
634
// return array of:
635
// 0 if this is an inner face, 1 if its diameter is 1, 2 if diameter is 2, 3 if 3, etc
636
// but only up to 5 (because the number of bands is 6 - see createIrregularFaceShape() )
637

    
638
  private int[] generateBandIndices(float[][] vertices, int[][] indices, float[] move)
639
    {
640
    int numCubitFaces = indices.length;
641
    int[] bandIndices = new int[numCubitFaces];
642

    
643
    for(int cubitFace=0; cubitFace<numCubitFaces; cubitFace++)
644
      {
645
      bandIndices[cubitFace] = 0xffffffff;
646
      int numVertices = indices[cubitFace].length;
647

    
648
      for(int vertex=0; vertex<numVertices; vertex++)
649
        {
650
        int vertBelongsBitmap = 0x00000000;
651
        float[] vert = vertices[ indices[cubitFace][vertex] ];
652

    
653
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[0], dX) ) vertBelongsBitmap |= (1   );
654
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[1], dX) ) vertBelongsBitmap |= (1<<1);
655
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[2], dY) ) vertBelongsBitmap |= (1<<2);
656
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[3], dY) ) vertBelongsBitmap |= (1<<3);
657
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[4], dZ) ) vertBelongsBitmap |= (1<<4);
658
        if( vertInFace(vert, move, TouchControlHexahedron.FACE_AXIS[5], dZ) ) vertBelongsBitmap |= (1<<5);
659

    
660
        bandIndices[cubitFace] &= vertBelongsBitmap;
661
        }
662

    
663
      if( bandIndices[cubitFace]!=0 ) // outer face
664
        {
665
        int diameter = faceDiameter(vertices, indices[cubitFace]);
666
        bandIndices[cubitFace] = (diameter>=6 ? 5:diameter);
667
        }
668

    
669
      //android.util.Log.e("D", "cubit face "+cubitFace+" : "+bandIndices[cubitFace]);
670
      }
671

    
672
    return bandIndices;
673
    }
674

    
675
///////////////////////////////////////////////////////////////////////////////////////////////////
676

    
677
  private int computeVectorFace(float[] prev, float[] curr, float[] next)
678
    {
679
    float ax = prev[0]-curr[0];
680
    float ay = prev[1]-curr[1];
681
    float az = prev[2]-curr[2];
682

    
683
    float bx = next[0]-curr[0];
684
    float by = next[1]-curr[1];
685
    float bz = next[2]-curr[2];
686

    
687
    float lena = (float)Math.sqrt(ax*ax + ay*ay + az*az);
688
    float lenb = (float)Math.sqrt(bx*bx + by*by + bz*bz);
689

    
690
    ax /= lena;
691
    ay /= lena;
692
    az /= lena;
693

    
694
    bx /= lenb;
695
    by /= lenb;
696
    bz /= lenb;
697

    
698
    float cx = ax + bx + ay*bz-az*by;
699
    float cy = ay + by + az*bx-ax*bz;
700
    float cz = az + bz + ax*by-ay*bx;
701

    
702
    return (cx<0 ? 0:4) + (cy<0 ? 0:2) + (cz<0 ? 0:1);
703
    }
704

    
705
///////////////////////////////////////////////////////////////////////////////////////////////////
706

    
707
  private float[] computeVector(int index, float[][] vertices, int[][] indices, int[] bandIndices)
708
    {
709
    int band=0;
710
    int len = indices.length;
711
    int vector=-1;
712

    
713
    for(int i=0; i<len; i++)
714
      {
715
      int len2 = indices[i].length;
716

    
717
      for(int j=0; j<len2; j++)
718
        {
719
        if( indices[i][j]==index )
720
          {
721
          int prev = j>0 ? j-1 : len2-1;
722
          int next = j<len2-1 ? j+1 : 0;
723

    
724
          int prevIndex = indices[i][prev];
725
          int currIndex = indices[i][j];
726
          int nextIndex = indices[i][next];
727

    
728
          int newVector = computeVectorFace(vertices[prevIndex],vertices[currIndex],vertices[nextIndex]);
729
          if( vector!=-1 && vector!=newVector ) return null;
730

    
731
          vector = newVector;
732
          band |= bandIndices[i];
733
          }
734
        }
735
      }
736

    
737
    return band==0 ? null : VECTOR[vector];
738
    }
739

    
740
///////////////////////////////////////////////////////////////////////////////////////////////////
741

    
742
  private float[][] generateVectors(float[][] vertices, int[][] indices, int[] bandIndices)
743
    {
744
    int len = vertices.length;
745
    float[][] vectors = new float[len][];
746

    
747
    for(int i=0; i<len; i++)
748
      {
749
      vectors[i] = computeVector(i,vertices,indices,bandIndices);
750
      }
751

    
752
    return vectors;
753
    }
754

    
755
///////////////////////////////////////////////////////////////////////////////////////////////////
756

    
757
  private void debug(float[][] vert, int[][] ind)
758
    {
759
    String vv="VERTICES: ";
760
    for (float[] floats : vert)
761
      {
762
      vv += "\n";
763
      int lenV2 = floats.length / 3;
764

    
765
      for (int v2 = 0; v2 < lenV2; v2++)
766
        {
767
        vv += " {";
768
        vv += (floats[3 * v2] + " ");
769
        vv += (floats[3 * v2 + 1] + " ");
770
        vv += (floats[3 * v2 + 2] + " ");
771
        vv += "}";
772
        }
773
      }
774
    android.util.Log.e("D", vv);
775

    
776
    String ii="INDICES: ";
777
    for (int[] ints : ind)
778
      {
779
      ii += "\n";
780
      int lenI2 = ints.length;
781

    
782
      for (int i2 = 0; i2 < lenI2; i2++)
783
        {
784
        ii += (ints[i2] + " ");
785
        }
786
      }
787
    android.util.Log.e("D", ii);
788
    }
789

    
790
///////////////////////////////////////////////////////////////////////////////////////////////////
791
// PUBLIC API
792

    
793
  public static FactoryBandagedPyraminx getInstance()
794
    {
795
    if( mThis==null ) mThis = new FactoryBandagedPyraminx();
796
    return mThis;
797
    }
798

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

    
801
  public void prepare(int numVariants, int x)
802
    {
803
    if( mVertexArray==null ) mVertexArray = new ArrayList<>();
804
    mVertices= new float[numVariants][][];
805
    mIndices = new int[numVariants][][];
806
    mMove = new float[numVariants][3];
807
    mBandIndices = new int[numVariants][];
808

    
809
    mX = x;
810

    
811

    
812
    dX = mX/2.0f;
813
    dY = mY/2.0f;
814
    dZ = mZ/2.0f;
815

    
816
    mMax = mX>mY ? Math.max(mX,mZ) : Math.max(mY,mZ);
817

    
818
    mWall   = new int[mMax][mMax];
819
    mPoints = new int[mMax+1][mMax+1];
820
    mTmp    = new boolean[mX][mY][mZ];
821
    }
822

    
823
///////////////////////////////////////////////////////////////////////////////////////////////////
824

    
825
  public ObjectShape createIrregularShape(int variant, float[] pos)
826
    {
827
    mVertexArray.clear();
828

    
829
    float begX = 0.5f*(1-mX);
830
    float begY = 0.5f*(1-mY);
831
    float begZ = 0.5f*(1-mZ);
832

    
833
    for(int x=0; x<mX; x++)
834
      for(int y=0; y<mY; y++)
835
        for(int z=0; z<mZ; z++) mTmp[x][y][z] = cubitExists(pos,begX+x,begY+y,begZ+z);
836

    
837
    for(int x=0; x<mX; x++) createRight (x,mVertexArray);
838
    for(int x=0; x<mX; x++) createLeft  (x,mVertexArray);
839
    for(int y=0; y<mY; y++) createTop   (y,mVertexArray);
840
    for(int y=0; y<mY; y++) createBottom(y,mVertexArray);
841
    for(int z=0; z<mZ; z++) createFront (z,mVertexArray);
842
    for(int z=0; z<mZ; z++) createBack  (z,mVertexArray);
843

    
844
    float[][] verts = getVertices(mVertexArray,pos,variant);
845
    int[][] inds    = getIndices(mVertexArray);
846

    
847
    compressVerticesAndIndices(variant,verts,inds);
848
    mBandIndices[variant] = generateBandIndices(mVertices[variant], mIndices[variant], mMove[variant]);
849

    
850
    return new ObjectShape(mVertices[variant], mIndices[variant]);
851
    }
852

    
853
///////////////////////////////////////////////////////////////////////////////////////////////////
854

    
855
  public ObjectVertexEffects createVertexEffects(int variant, boolean roundCorners)
856
    {
857
    float[][] vertVec= generateVectors(mVertices[variant], mIndices[variant], mBandIndices[variant]);
858
    int numEffects   = mVertices[variant].length;
859
    float S          = 0.04f;
860
    float[] region   = {0,0,0,0.15f};
861
    String[] names   = new String[numEffects];
862
    float[][] regions= new float[numEffects][];
863
    boolean[] uses   = new boolean[numEffects];
864
    float[][] vars   = new float[numEffects][];
865

    
866
    for(int i=0; i<numEffects; i++)
867
      {
868
      float[] v = vertVec[i];
869

    
870
      if( v!=null )
871
        {
872
        names[i]  = FactoryCubit.NAME;
873
        regions[i]= region;
874
        uses[i]   = roundCorners;
875
        vars[i]   = new float[] { 0, S*v[0], S*v[1], S*v[2], 1 };
876
        }
877
      }
878

    
879
    return new ObjectVertexEffects(names,vars,mVertices[variant],regions,uses);
880
    }
881

    
882
///////////////////////////////////////////////////////////////////////////////////////////////////
883

    
884
  public ObjectFaceShape createIrregularFaceShape(int variant, boolean iconMode)
885
    {
886
    float height= iconMode ? 0.001f : 0.048f;
887
    int angle   = 60;
888
    float R     = 0.2f;
889
    float S     = 0.5f;
890
    int numVerts= 5;
891
    int extraI  = 0;
892
    int extraV  = 0;
893

    
894
    float[][] bands  = { {  0.001f,angle,R,S,numVerts,extraV,extraI},
895
                         {height/1,angle,R,S,numVerts,extraV,extraI},
896
                         {height/2,angle,R,S,numVerts,extraV,extraI},
897
                         {height/3,angle,R,S,numVerts,extraV,extraI},
898
                         {height/4,angle,R,S,numVerts,extraV,extraI},
899
                         {height/5,angle,R,S,numVerts,extraV,extraI} };
900

    
901
    return new ObjectFaceShape(bands,mBandIndices[variant],null);
902
    }
903

    
904
///////////////////////////////////////////////////////////////////////////////////////////////////
905

    
906
  public MeshBase createMesh(float[] pos, int x, boolean iconMode, boolean roundCorners)
907
    {
908
    prepare(1,x);
909
    ObjectShape shape           = createIrregularShape(0,pos);
910
    ObjectFaceShape face        = createIrregularFaceShape(0,iconMode);
911
    ObjectVertexEffects effects = createVertexEffects(0,roundCorners);
912
    int[][] indices             = shape.getVertIndices();
913
    int numComponents           = indices.length;
914

    
915
    FactoryCubit factory = FactoryCubit.getInstance();
916
    factory.clear();
917
    factory.createNewFaceTransform(shape,null);
918
    return factory.createRoundedSolid(shape,face,effects,MESH_NICE,numComponents);
919
    }
920
  }
(3-3/15)