Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / helpers / ObjectShape.java @ b28f909c

1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2021 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 org.distorted.library.helpers.QuatHelper;
13
import org.distorted.library.type.Static3D;
14
import org.distorted.library.type.Static4D;
15
import org.distorted.objectlib.main.TwistyObject;
16

    
17
///////////////////////////////////////////////////////////////////////////////////////////////////
18

    
19
public class ObjectShape
20
  {
21
  private static final float[] mTmp1 = new float[4];
22
  private static final float[] mTmp2 = new float[4];
23

    
24
  private final float[][] mVertices;
25
  private final int[][] mVertIndices;
26

    
27
  private final boolean mFacesMultigon;
28
  private final int mNumFaces;
29
  private final int[][][] mMultigonIndices;
30

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

    
33
  public ObjectShape(float[][] vertices, int[][] vertIndices)
34
    {
35
    mVertices        = vertices;
36
    mVertIndices     = vertIndices;
37
    mMultigonIndices = null;
38
    mFacesMultigon   = false;
39
    mNumFaces        = vertIndices.length;
40
    }
41

    
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

    
44
  public ObjectShape(float[][] vertices, int[][][] vertIndices)
45
    {
46
    mVertices       = vertices;
47
    mVertIndices    = null;
48
    mMultigonIndices= vertIndices;
49
    mFacesMultigon  = true;
50
    mNumFaces       = vertIndices.length;
51
    }
52

    
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

    
55
  public void debug()
56
    {
57
    StringBuilder str = new StringBuilder();
58
    str.append("isMultigon: ");
59
    str.append(mFacesMultigon);
60
    str.append("\n");
61
    str.append("numVertices: ");
62
    int numV =mVertices.length;
63
    str.append(numV);
64
    str.append("\n");
65

    
66
    for(float[] v : mVertices)
67
      {
68
      str.append(" {");
69
      str.append(v[0]);
70
      str.append("f, ");
71
      str.append(v[1]);
72
      str.append("f, ");
73
      str.append(v[2]);
74
      str.append("f },\n");
75
      }
76

    
77
    if( mFacesMultigon )
78
      {
79
      int numFaces =mMultigonIndices.length;
80
      str.append("numFaces: ");
81
      str.append(numFaces);
82
      str.append("\n");
83

    
84
      for(int[][] mMultigonIndex : mMultigonIndices)
85
        {
86
        for(int[] multigonIndex : mMultigonIndex)
87
          {
88
          int len = multigonIndex.length;
89
          str.append(" {");
90

    
91
          for(int i=0; i<len; i++)
92
            {
93
            str.append( i==0 ? " " : ", ");
94
            str.append(multigonIndex[i]);
95
            }
96
          str.append("},");
97
          }
98
        str.append("\n");
99
        }
100
      }
101
    else
102
      {
103
      int numFaces =mVertIndices.length;
104
      str.append("\nnumFaces: ");
105
      str.append(numFaces);
106
      str.append("\n   ");
107

    
108
      for(int[] vertIndex : mVertIndices)
109
        {
110
        for(int index : vertIndex)
111
          {
112
          str.append(" ");
113
          str.append(index);
114
          }
115
        str.append("\n   ");
116
        }
117
      }
118

    
119
    android.util.Log.e("D", "ObjectShape: \n"+str);
120
    }
121

    
122
///////////////////////////////////////////////////////////////////////////////////////////////////
123

    
124
  public int getNumFaces()
125
    {
126
    return mNumFaces;
127
    }
128

    
129
///////////////////////////////////////////////////////////////////////////////////////////////////
130

    
131
  public boolean isMultigon()
132
    {
133
    return mFacesMultigon;
134
    }
135

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

    
138
  public float[][] getVertices()
139
    {
140
    return mVertices;
141
    }
142

    
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144

    
145
  public int[][] getVertIndices()
146
    {
147
    return mVertIndices;
148
    }
149

    
150
///////////////////////////////////////////////////////////////////////////////////////////////////
151

    
152
  public int[][][] getMultigonIndices()
153
    {
154
    return mMultigonIndices;
155
    }
156

    
157
///////////////////////////////////////////////////////////////////////////////////////////////////
158

    
159
  public float[] getFirstVertexInFace(int face)
160
    {
161
    if( mFacesMultigon )
162
      {
163
      int[][][] indices=getMultigonIndices();
164
      int vertIndex=indices[face][0][0];
165
      return getVertices()[vertIndex];
166
      }
167
    else
168
      {
169
      int[][] indices=getVertIndices();
170
      int vertIndex=indices[face][0];
171
      return getVertices()[vertIndex];
172
      }
173
    }
174

    
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176

    
177
  private void computeNormalVector(float[] v0, float[] v1, float[] v2, float[] output)
178
    {
179
    float x1 = v0[0];
180
    float y1 = v0[1];
181
    float z1 = v0[2];
182
    float x2 = v1[0];
183
    float y2 = v1[1];
184
    float z2 = v1[2];
185
    float x3 = v2[0];
186
    float y3 = v2[1];
187
    float z3 = v2[2];
188

    
189
    float v1x = x2-x1;
190
    float v1y = y2-y1;
191
    float v1z = z2-z1;
192
    float v2x = x3-x1;
193
    float v2y = y3-y1;
194
    float v2z = z3-z1;
195

    
196
    output[0] = v1y*v2z - v2y*v1z;
197
    output[1] = v1z*v2x - v2z*v1x;
198
    output[2] = v1x*v2y - v2x*v1y;
199

    
200
    double len = output[0]*output[0] + output[1]*output[1] + output[2]*output[2];
201
    len = Math.sqrt(len);
202
    output[0] /= len;
203
    output[1] /= len;
204
    output[2] /= len;
205
    }
206

    
207
///////////////////////////////////////////////////////////////////////////////////////////////////
208
// Attention: ATM this can return either (nx,ny,nz) or the negative (-nx,-ny,-nz)
209
// (negative if the first three points of the first loop are 'concave' - as for example are the
210
// first three points of the 'center' cubit variant of CoinTetrahedron)
211

    
212
  public void getFaceNormal(int face, float[] output)
213
    {
214
    int[] loopI = mFacesMultigon ? getMultigonIndices()[face][0] : getVertIndices()[face];
215

    
216
    float[] v0 = mVertices[loopI[0]];
217
    float[] v1 = mVertices[loopI[1]];
218
    float[] v2 = mVertices[loopI[2]];
219

    
220
    computeNormalVector(v0,v1,v2,output);
221
    }
222

    
223
///////////////////////////////////////////////////////////////////////////////////////////////////
224
// return any point laying inside the face
225

    
226
  public void getFacePoint(int face, float[] output)
227
    {
228
    int[] loopI = mFacesMultigon ? getMultigonIndices()[face][0] : getVertIndices()[face];
229

    
230
    float[] v0 = mVertices[loopI[0]];
231
    float[] v1 = mVertices[loopI[1]];
232
    float[] v2 = mVertices[loopI[2]];
233

    
234
    output[0] = (v0[0] + v1[0] + v2[0]) / 3;
235
    output[1] = (v0[1] + v1[1] + v2[1]) / 3;
236
    output[2] = (v0[2] + v1[2] + v2[2]) / 3;
237
    }
238

    
239
///////////////////////////////////////////////////////////////////////////////////////////////////
240

    
241
  public static int computeNumComponents(ObjectShape[] shapes)
242
    {
243
    int ret = 0;
244

    
245
    for( ObjectShape shape : shapes )
246
      {
247
      int numShape = shape.mNumFaces;
248
      if( numShape>ret ) ret = numShape;
249
      }
250

    
251
    return ret;
252
    }
253

    
254
///////////////////////////////////////////////////////////////////////////////////////////////////
255
// take vertex, apply quat, apply move, write to output
256

    
257
  private static void computeVertex(float[] output, float[] vertex, float[] move, Static4D quat)
258
    {
259
    QuatHelper.rotateVectorByQuat(mTmp2,vertex[0],vertex[1],vertex[2],1.0f,quat);
260

    
261
    int numMoves = move.length/3;
262
    float moveX=0.0f, moveY=0.0f, moveZ=0.0f;
263

    
264
    for(int m=0; m<numMoves; m++)
265
      {
266
      moveX += move[3*m  ];
267
      moveY += move[3*m+1];
268
      moveZ += move[3*m+2];
269
      }
270

    
271
    output[0] = mTmp2[0] + moveX/numMoves;
272
    output[1] = mTmp2[1] + moveY/numMoves;
273
    output[2] = mTmp2[2] + moveZ/numMoves;
274
    }
275

    
276
///////////////////////////////////////////////////////////////////////////////////////////////////
277

    
278
  private static boolean vertInFace(float[] vertex, Static3D faceAxis, float dist)
279
    {
280
    final float MAX_ERROR = 0.04f;  // Rex Cube requires this
281

    
282
    float x= faceAxis.get0();
283
    float y= faceAxis.get1();
284
    float z= faceAxis.get2();
285

    
286
    float a = vertex[0]*x + vertex[1]*y + vertex[2]*z;
287
    float diff = a - dist;
288

    
289
    return diff>-MAX_ERROR && diff<MAX_ERROR;
290
    }
291

    
292
///////////////////////////////////////////////////////////////////////////////////////////////////
293

    
294
  private static boolean indicesContain(int[][] indices, int index)
295
    {
296
    for( int[] ind : indices )
297
      for( int i : ind )
298
        if( i==index ) return true;
299

    
300
    return false;
301
    }
302

    
303
///////////////////////////////////////////////////////////////////////////////////////////////////
304

    
305
  private static boolean indicesContain(int[] indices, int index)
306
    {
307
    for( int j : indices )
308
      if( j==index ) return true;
309

    
310
    return false;
311
    }
312

    
313
///////////////////////////////////////////////////////////////////////////////////////////////////
314

    
315
  private static int[] computeCubitFaceColors(ObjectShape shape, float[] move, Static4D quat, Static3D[] faceAxis, float[] dist3D, float size)
316
    {
317
    float[][] vertices = shape.getVertices();
318
    int numVert = vertices.length;
319
    int numPuzzleFaces = faceAxis.length;
320
    int numCubitFaces = shape.mNumFaces;
321
    int[] cubitFaceColor = new int[numCubitFaces];
322
    for(int face=0; face<numCubitFaces; face++) cubitFaceColor[face] = 0xffffffff;
323

    
324
    for(int vert=0; vert<numVert; vert++)
325
      {
326
      computeVertex(mTmp1,vertices[vert],move,quat);
327
      int vertBelongsBitmap = 0x00000000;
328

    
329
      for(int face=0; face<numPuzzleFaces; face++)
330
        if( vertInFace(mTmp1,faceAxis[face],dist3D[face]*size) ) vertBelongsBitmap |= (1<<face);
331

    
332
      if( shape.mFacesMultigon )
333
        {
334
        for(int index=0; index<numCubitFaces; index++)
335
          if( cubitFaceColor[index]!=0 && indicesContain(shape.mMultigonIndices[index],vert) ) cubitFaceColor[index] &= vertBelongsBitmap;
336
        }
337
      else
338
        {
339
        for(int index=0; index<numCubitFaces; index++)
340
          if( cubitFaceColor[index]!=0 && indicesContain(shape.mVertIndices[index],vert) ) cubitFaceColor[index] &= vertBelongsBitmap;
341
        }
342
      }
343

    
344
    return cubitFaceColor;
345
    }
346

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

    
349
  private static void translateFromBitmap(int cubit, int[] colorsBitmap)
350
    {
351
    int len = colorsBitmap.length;
352

    
353
    for(int face=0; face<len; face++)
354
      {
355
      if( colorsBitmap[face]==0 ) colorsBitmap[face] = -1;
356
      else
357
        {
358
        int shift=0;
359

    
360
        while( (colorsBitmap[face]&0x1) != 1 )
361
          {
362
          colorsBitmap[face]>>=1;
363
          shift++;
364
          }
365

    
366
        if( colorsBitmap[face]!=1 )
367
          {
368
          android.util.Log.e("ObjectShape", "ERROR, cubit= "+cubit+" face "+face+" seems to belong to "+shift+" and still "+colorsBitmap[face]);
369
          }
370

    
371
        colorsBitmap[face] = shift;
372
        }
373
      }
374
    }
375

    
376
///////////////////////////////////////////////////////////////////////////////////////////////////
377

    
378
  public static int[][] computeColors(ObjectShape[] shapes, float[][] moves, Static4D[] quats, TwistyObject object)
379
    {
380
    int numCubits = moves.length;
381
    int[][] colors = new int[numCubits][];
382
    int[] numLayers = object.getNumLayers();
383
    Static3D[] faceAxis = object.getFaceAxis();
384
    float[] dist3D = object.getDist3D(numLayers);
385
    float size = object.getSize();
386

    
387
    for(int cubit=0; cubit<numCubits; cubit++)
388
      {
389
      int variant = object.getCubitVariant(cubit,numLayers);
390
      colors[cubit] = computeCubitFaceColors(shapes[variant],moves[cubit],quats[cubit],faceAxis,dist3D,size);
391
      translateFromBitmap(cubit,colors[cubit]);
392
      }
393

    
394
    return colors;
395
    }
396
  }
(8-8/13)