Project

General

Profile

« Previous | Next » 

Revision 5b75cdcb

Added by Leszek Koltunski 6 months ago

progress with unification of cubits created by FacotyCutSolid

View differences:

src/main/java/org/distorted/objectlib/helpers/FactoryCutSolid.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2025 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.type.Static3D;
13
import org.distorted.library.type.Static4D;
14
import org.distorted.objectlib.main.TwistyObjectControllable;
15

  
16
///////////////////////////////////////////////////////////////////////////////////////////////////
17

  
18
public class FactoryCutSolid
19
  {
20
  public static class CutSolidInfo
21
    {
22
    private final int[][] mVariantQuatMap;
23
    private final ObjectShape[] mShapes;
24
    CutSolidInfo(ObjectShape[] shapes, int[][] map ) { mShapes = shapes; mVariantQuatMap = map; }
25
    public ObjectShape[] getShapes()   { return mShapes; }
26
    public int[][] getVariantQuatMap() { return mVariantQuatMap; }
27
    };
28

  
29
///////////////////////////////////////////////////////////////////////////////////////////////////
30

  
31
  private static int getRotatingQuat(ObjectShape s1, ObjectShape s2, Static4D[] quats)
32
    {
33
    return -1;
34
    }
35

  
36
///////////////////////////////////////////////////////////////////////////////////////////////////
37

  
38
  public static CutSolidInfo computeInfo(TwistyObjectControllable object, float[][] cutPlanes)
39
    {
40
    float[][] pos = object.getCubitPositions();
41
    Static3D[] faceAxis = object.getFaceAxis();
42
    float[] dist = object.getDist3D();
43
    int numCubits = pos.length;
44

  
45
    float[][] potentialVertices = FactoryShape.computePotentialVertices(cutPlanes);
46

  
47
    ObjectShape[] shapes = new ObjectShape[numCubits];
48
    for(int c=0; c<numCubits; c++)
49
      {
50
      shapes[c] = FactoryShape.createShape(cutPlanes,potentialVertices,pos[c],pos[c]);
51
      shapes[c].computeFaceOuter(pos[c],faceAxis,dist);
52
      }
53

  
54
    Static4D[] quats = object.getQuats();
55

  
56
    int[][] map = new int[numCubits][2];
57
    for(int c=0; c<numCubits; c++) map[c][0] = -1;
58

  
59
    int variant = 0;
60
    for(int c=0; c<numCubits; c++)
61
      if( map[c][0]<0 )
62
        {
63
        map[c][0] = variant++;
64
        ObjectShape shape1 = shapes[c];
65

  
66
        for(int d=c+1; d<numCubits; d++)
67
          {
68
          ObjectShape shape2 = shapes[d];
69
          int quat = getRotatingQuat(shape1,shape2,quats);
70

  
71
          if( quat>=0 )
72
            {
73
            map[d][0] = variant-1;
74
            map[d][1] = quat;
75
            }
76
          }
77
        }
78

  
79
    ObjectShape[] variantShapes = new ObjectShape[variant];
80
    for(int c=0; c<numCubits; c++)
81
      {
82
      int v = map[c][0];
83
      if( variantShapes[v]==null ) variantShapes[v] = shapes[c];
84
      }
85

  
86
    return new CutSolidInfo(variantShapes,map);
87
    }
88
  }
src/main/java/org/distorted/objectlib/helpers/ObjectShape.java
18 18

  
19 19
public class ObjectShape
20 20
  {
21
  private static final float[] mCanonical = new float[] {0.343f,0.509f,0.789f};
21 22
  private static final float[] mTmp1 = new float[4];
22 23
  private static final float[] mTmp2 = new float[4];
23 24

  
......
81 82
      int numFaces =mMultigonIndices.length;
82 83
      str.append("numFaces: ");
83 84
      str.append(numFaces);
84
      str.append("\n");
85
      str.append("\n  ");
85 86

  
86
      for(int[][] mMultigonIndex : mMultigonIndices)
87
      for(int f=0; f<numFaces; f++)
87 88
        {
88
        for(int[] multigonIndex : mMultigonIndex)
89
        int[][] multigonIndex = mMultigonIndices[f];
90

  
91
        for(int[] mulIndex : multigonIndex)
89 92
          {
90
          int len = multigonIndex.length;
93
          int len = mulIndex.length;
91 94
          str.append(" {");
92 95

  
93
          for(int i=0; i<len; i++)
96
          for(int v=0; v<len; v++)
94 97
            {
95
            str.append( i==0 ? " " : ", ");
96
            str.append(multigonIndex[i]);
98
            str.append( v==0 ? " " : ", ");
99
            str.append(mulIndex[v]);
97 100
            }
98 101
          str.append("},");
99 102
          }
100
        str.append("\n");
103

  
104
        if( mFaceIsOuter!=null ) str.append( mFaceIsOuter[f] ? " outer" : " inner");
105
        else                     str.append(" mFaceIsOuter is null");
106
        str.append("\n  ");
101 107
        }
102 108
      }
103 109
    else
104 110
      {
105 111
      int numFaces =mVertIndices.length;
106
      str.append("\nnumFaces: ");
112
      str.append("numFaces: ");
107 113
      str.append(numFaces);
108
      str.append("\n   ");
114
      str.append("\n  ");
109 115

  
110
      for(int[] vertIndex : mVertIndices)
116
      for(int f=0; f<numFaces; f++)
111 117
        {
118
        int[] vertIndex = mVertIndices[f];
119

  
112 120
        for(int index : vertIndex)
113 121
          {
114 122
          str.append(" ");
115 123
          str.append(index);
116 124
          }
117
        str.append("\n   ");
125

  
126
        if( mFaceIsOuter!=null ) str.append( mFaceIsOuter[f] ? " outer" : " inner");
127
        else                     str.append(" mFaceIsOuter is null");
128
        str.append("\n  ");
118 129
        }
119 130
      }
120 131

  
......
129 140
  public int[][] getVertIndices()        { return mVertIndices; }
130 141
  public int[][][] getMultigonIndices()  { return mMultigonIndices; }
131 142

  
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
// Return 1 if arr1>arr2, 0 if arr1==arr2, -1 if arr1<arr2.
145
// if arr1.length > arr2.length, then arr1>arr2.
146
// if arr1.length==arr2.lenght, then treat individual integers of arrays as digits in a 2^32-mal
147
// system and compare those two 2^32-mal numbers.
148

  
149
  private int compare(int[] arr1, int[] arr2)
150
    {
151
    int len1 = arr1.length;
152
    int len2 = arr2.length;
153

  
154
    if( len1>len2 ) return 1;
155
    if( len1<len2 ) return -1;
156

  
157
    for(int i=0; i<len1; i++)
158
      {
159
      int diff = arr1[i]-arr2[i];
160
      if( diff>0 ) return 1;
161
      if( diff<0 ) return -1;
162
      }
163

  
164
    return 0;
165
    }
166

  
167
///////////////////////////////////////////////////////////////////////////////////////////////////
168
// return the same array, but rotate it so that its smallest value is first.
169
// (the values in the array are guaranteed to not repeat)
170

  
171
  private int[] rotateSmallestValueToFirstIndex(int[] indices)
172
    {
173
    int smallest = Integer.MAX_VALUE;
174
    int smallestIndex = -1;
175
    int len = indices.length;
176

  
177
    for(int i=0; i<len; i++)
178
      if( indices[i]<smallest )
179
        {
180
        smallest = indices[i];
181
        smallestIndex = i;
182
        }
183

  
184
    int[] ret = new int[len];
185
    for(int i=0; i<len; i++) ret[i] = indices[(smallestIndex+i)%len];
186

  
187
    return ret;
188
    }
189

  
190
///////////////////////////////////////////////////////////////////////////////////////////////////
191
// Canonical form. The point: we want to be able to quickly see if two instances of ObjectShape are
192
// in fact the same shape. (the 'equals' function)
193
//
194
// Multigon not supported (rationale: this is only needed in TwistyCutSolid - i.e. for objects which
195
// are created by cutting a solid along a number of planes. This will never result in multigon shapes)
196
//
197
//   1. Sort the vertices from left to right according to the order they are on the mCanonical vector
198
//      (here first compute the 'auxiliary' and 'permutation' arrays so that we don't have to keep
199
//       rearranging the indices in the VertIndices multiarrays every time we swap two vertices)
200
//   2. Then, sort the indices on every every face by placing the lowest index first.
201
//   3. Then, sort the faces (and correspondingly the mFaceIsOuters).
202
//      Each face contains a list of indices (I1,I2,...,IN). Sort by those lists by treating each
203
//      integer in it as a digit in 2^32-mal number system and thus as if the whole list were a single
204
//      2^32-mal integer.
205

  
206
  public void toCanonicalForm()
207
    {
208
    int numVertices = mVertices.length;
209
    int[] permutation = new int[numVertices];
210
    float[] auxiliary = new float[numVertices];
211

  
212
    for(int v=0; v<numVertices; v++)
213
      {
214
      float[] vert = mVertices[v];
215
      auxiliary[v] = mCanonical[0]*vert[0] + mCanonical[1]*vert[1] + mCanonical[2]*vert[2];
216
      permutation[v] = v;
217
      }
218

  
219
    // insertion sort auxiliary[] and permutation[]
220
    int sortedAlready = 1;
221

  
222
    while( sortedAlready<numVertices )
223
      {
224
      float x = auxiliary[sortedAlready];
225
      int n = permutation[sortedAlready];
226
      int i = sortedAlready;
227

  
228
      while( i>0 && auxiliary[i-1]>x )
229
        {
230
        auxiliary[i]   = auxiliary[i-1];
231
        permutation[i] = permutation[i-1];
232
        i--;
233
        }
234
      auxiliary[i]  = x;
235
      permutation[i]= n;
236
      sortedAlready++;
237
      }
238

  
239
    // now 'permutation' is in a form which is slow to use when we rename mVerIndices. Change it to
240
    // another form where map[i]=j means 'index which used to be i must be changed to j'
241
    int[] perm = new int[numVertices];
242
    for(int i=0; i<numVertices; i++) perm[permutation[i]] = i;
243

  
244
    if( mFacesMultigon )
245
      {
246
      android.util.Log.e("D", "error in ObjectShape.toCanonicalForm: multigon unsupported!");
247
      }
248
    else
249
      {
250
      float[][] tmpVertices = new float[numVertices][];
251
      for(int i=0; i<numVertices; i++) tmpVertices[i] = mVertices[permutation[i]];
252
      for(int i=0; i<numVertices; i++) mVertices[i] = tmpVertices[i];
253

  
254
      int numFaces = mVertIndices.length;
255
      for(int f=0; f<numFaces; f++)
256
        {
257
        int[] indices = mVertIndices[f];
258
        int len = indices.length;
259
        for(int i=0; i<len; i++) indices[i] = perm[indices[i]];
260
        mVertIndices[f] = rotateSmallestValueToFirstIndex(indices);
261
        }
262

  
263
      // insertion sort mVertIndices and mFaceIsOuter
264
      sortedAlready = 1;
265

  
266
      while( sortedAlready<numFaces )
267
        {
268
        int[] x = mVertIndices[sortedAlready];
269
        boolean n = mFaceIsOuter[sortedAlready];
270
        int i = sortedAlready;
271

  
272
        while( i>0 && compare(mVertIndices[i-1],x)>0 )
273
          {
274
          mVertIndices[i] = mVertIndices[i-1];
275
          mFaceIsOuter[i] = mFaceIsOuter[i-1];
276
          i--;
277
          }
278
        mVertIndices[i] = x;
279
        mFaceIsOuter[i] = n;
280
        sortedAlready++;
281
        }
282
      }
283
    }
284

  
285
///////////////////////////////////////////////////////////////////////////////////////////////////
286
// both shapes already in canonical form!
287

  
288
  public boolean equals(ObjectShape shape)
289
    {
290
    int len1 = mFaceIsOuter.length;
291
    int len2 = shape.mFaceIsOuter.length;
292

  
293
    if( len1 != len2 ) return false;
294

  
295
    for(int f=0; f<len1; f++)
296
      if( mFaceIsOuter[f] != shape.mFaceIsOuter[f] ) return false;
297

  
298
    if( mFacesMultigon != shape.mFacesMultigon ) return false;
299

  
300
    if( mFacesMultigon )
301
      {
302
      int numIndices1 = mMultigonIndices.length;
303
      int numIndices2 = shape.mMultigonIndices.length;
304

  
305
      if( numIndices1 != numIndices2 ) return false;
306

  
307
      for(int i=0; i<numIndices1; i++)
308
        {
309
        int[][] indi1 = mMultigonIndices[i];
310
        int[][] indi2 = shape.mMultigonIndices[i];
311

  
312
        int ilen1 = indi1.length;
313
        int ilen2 = indi2.length;
314

  
315
        if( ilen1 != ilen2 ) return false;
316

  
317
        for(int j=0; j<ilen1; j++)
318
          {
319
          int[] ind1 = indi1[j];
320
          int[] ind2 = indi2[j];
321
          int l1     = ind1.length;
322
          int l2     = ind2.length;
323

  
324
          if( l1 != l2 ) return false;
325

  
326
          for(int k=0; k<l1; k++)
327
            if( ind1[k] != ind2[k] ) return false;
328
          }
329
        }
330
      }
331
    else
332
      {
333
      int numIndices1 = mVertIndices.length;
334
      int numIndices2 = shape.mVertIndices.length;
335

  
336
      if( numIndices1 != numIndices2 ) return false;
337

  
338
      for(int i=0; i<numIndices1; i++)
339
        {
340
        int[] ind1 = mVertIndices[i];
341
        int[] ind2 = shape.mVertIndices[i];
342
        int ilen1 = ind1.length;
343
        int ilen2 = ind2.length;
344

  
345
        if( ilen1 != ilen2 ) return false;
346

  
347
        for(int j=0; j<ilen1; j++)
348
            if( ind1[j] != ind2[j] ) return false;
349
        }
350
      }
351

  
352
    float MIN_ERR = 0.001f;
353
    int numv1 = mVertices.length;
354
    int numv2 = shape.mVertices.length;
355

  
356
    if( numv1 != numv2 ) return false;
357

  
358
    for(int v=0; v<numv1; v++)
359
      {
360
      float[] v1 = mVertices[v];
361
      float[] v2 = shape.mVertices[v];
362

  
363
      float dx = v1[0]-v2[0];
364
      float dy = v1[1]-v2[1];
365
      float dz = v1[2]-v2[2];
366

  
367
      if( dx*dx+dy*dy+dz*dz > MIN_ERR ) return false;
368
      }
369

  
370
    return true;
371
    }
372

  
373
///////////////////////////////////////////////////////////////////////////////////////////////////
374

  
375
  public ObjectShape rotate(Static4D quat)
376
    {
377
    float[] tmp = new float[4];
378
    int numVertices = mVertices.length;
379
    float[][] verts = new float[numVertices][];
380
    float qx = quat.get0();
381
    float qy = quat.get1();
382
    float qz = quat.get2();
383
    float qw = quat.get3();
384
    float[] q = new float[] {qx,qy,qz,qw};
385

  
386
    for(int v=0; v<numVertices; v++)
387
      {
388
      float[] vert = mVertices[v];
389
      QuatHelper.rotateVectorByQuat(tmp,vert[0],vert[1],vert[2],1,q);
390
      verts[v] = new float[] {tmp[0],tmp[1],tmp[2]};
391
      }
392

  
393
    int numOuter = mFaceIsOuter.length;
394
    boolean[] outer= new boolean[numOuter];
395
    for(int f=0; f<numOuter; f++) outer[f] = mFaceIsOuter[f];
396

  
397
    if( mFacesMultigon )
398
      {
399
      int numIndices = mMultigonIndices.length;
400
      int[][][] indices = new int[numIndices][][];
401

  
402
      for(int i=0; i<numIndices; i++)
403
        {
404
        int[][] indi = mMultigonIndices[i];
405
        int len = indi.length;
406
        indices[i] = new int[len][];
407

  
408
        for(int j=0; j<len; j++)
409
          {
410
          int[] ind = indi[j];
411
          int l     = ind.length;
412
          int[] t   = new int[l];
413
          for(int k=0; k<l; k++) t[k] = ind[k];
414
          indices[i][j] = t;
415
          }
416
        }
417

  
418
      ObjectShape ret = new ObjectShape(verts,indices);
419
      ret.setFaceOuter(outer);
420
      return ret;
421
      }
422
    else
423
      {
424
      int numIndices = mVertIndices.length;
425
      int[][] indices = new int[numIndices][];
426

  
427
      for(int i=0; i<numIndices; i++)
428
        {
429
        int[] ind = mVertIndices[i];
430
        int len = ind.length;
431
        int[] t = new int[len];
432
        for(int j=0; j<len; j++) t[j] = ind[j];
433
        indices[i] = t;
434
        }
435

  
436
      ObjectShape ret = new ObjectShape(verts,indices);
437
      ret.setFaceOuter(outer);
438
      return ret;
439
      }
440
    }
441

  
132 442
///////////////////////////////////////////////////////////////////////////////////////////////////
133 443

  
134 444
  private void computeNormalVector(float[] v0, float[] v1, float[] v2, float[] output)
......
168 478
    {
169 479
    final float MAX_ERROR_DIST = 0.001f;
170 480
    float fx = faceAxis.get0();
171
    float fy = faceAxis.get0();
172
    float fz = faceAxis.get0();
481
    float fy = faceAxis.get1();
482
    float fz = faceAxis.get2();
173 483
    float x = vertex[0]+pos[0];
174 484
    float y = vertex[1]+pos[1];
175 485
    float z = vertex[2]+pos[2];
src/main/java/org/distorted/objectlib/objects/TwistyCutSolid.java
13 13
import org.distorted.library.type.Static3D;
14 14
import org.distorted.library.type.Static4D;
15 15
import org.distorted.objectlib.helpers.FactoryCubit;
16
import org.distorted.objectlib.helpers.FactoryCutSolid;
17 16
import org.distorted.objectlib.helpers.FactoryShape;
18 17
import org.distorted.objectlib.helpers.ObjectFaceShape;
19 18
import org.distorted.objectlib.helpers.ObjectShape;
......
103 102
  private void prepareShapes()
104 103
    {
105 104
    if( mCutPlanes==null ) createCutPlanes();
106
    FactoryCutSolid.CutSolidInfo info = FactoryCutSolid.computeInfo(this,mCutPlanes);
107
    mShapes = info.getShapes();
108
    mCubitToVariantQuatMap = info.getVariantQuatMap();
105

  
106
    Static4D[] quats = getQuats();
107
    float[][] pos = getCubitPositions();
108
    Static3D[] faceAxis = getFaceAxis();
109
    float[] dist = getDist3D();
110

  
111
    float[][] potentialVertices = FactoryShape.computePotentialVertices(mCutPlanes);
112

  
113
    ObjectShape[] shapes = new ObjectShape[mNumCubits];
114
    for(int c=0; c<mNumCubits; c++)
115
      {
116
      shapes[c] = FactoryShape.createShape(mCutPlanes,potentialVertices,pos[c],pos[c]);
117
      shapes[c].computeFaceOuter(pos[c],faceAxis,dist);
118
      shapes[c].debug();
119
      shapes[c].toCanonicalForm();
120
      }
121

  
122
    mCubitToVariantQuatMap = new int[mNumCubits][2];
123
    for(int c=0; c<mNumCubits; c++) mCubitToVariantQuatMap[c][0] = -1;
124

  
125
    int variant = 0;
126
    for(int c=0; c<mNumCubits; c++)
127
      if( mCubitToVariantQuatMap[c][0]<0 )
128
        {
129
        mCubitToVariantQuatMap[c][0] = variant++;
130

  
131
        for(int q=0; q<mNumQuats; q++)
132
          {
133
          ObjectShape rotShape = shapes[c].rotate(quats[q]);
134
          rotShape.toCanonicalForm();
135

  
136
          for(int d=c+1; d<mNumCubits; d++)
137
            if( rotShape.equals(shapes[d]) )
138
              {
139
              mCubitToVariantQuatMap[d][0] = variant-1;
140
              mCubitToVariantQuatMap[d][1] = q;
141
              }
142
          }
143
        }
144

  
145
    mShapes = new ObjectShape[variant];
146
    for(int c=0; c<mNumCubits; c++)
147
      {
148
      int v = mCubitToVariantQuatMap[c][0];
149
      if( mShapes[v]==null ) mShapes[v] = shapes[c];
150
      }
151

  
152
    android.util.Log.e("D", "shape variants: "+variant);
153
    for(int v=0; v<variant; v++) mShapes[v].debug();
109 154
    }
110 155

  
111 156
///////////////////////////////////////////////////////////////////////////////////////////////////

Also available in: Unified diff