Project

General

Profile

« Previous | Next » 

Revision 69061d6e

Added by Leszek Koltunski almost 2 years ago

fixes for the generic Mirror mechanism.

View differences:

src/main/java/org/distorted/objectlib/helpers/FactoryMirror.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.helpers;
11

  
12
import org.distorted.library.type.Static3D;
13

  
14
///////////////////////////////////////////////////////////////////////////////////////////////////
15
// 1. for every potentialVertex, if it is on the same side of every plane present as the
16
//    'internalPoint', it must be one of the vertices of the ObjectShape. Remember which planes it
17
//    belongs to and add it to the list of vertices.
18
// 2. Having complete list of vertices and a bitmap of which planes each vertex belongs to, for each
19
//    plane:
20
//    a) assemble the list of vertices that belong to this plane
21
//    b) compute their center of mass and using this as a pivot, arrange the list into CCW order
22
//    c) out of the vertices and the CCW'd indices, construct an ObjectShape.
23

  
24
public class FactoryMirror
25
  {
26
  public static ObjectShape createShape(float[][] cutPlanes, float[][] potentialVertices, float[] position, float[] internalPoint)
27
    {
28
    int numV = potentialVertices.length;
29
    float[][] tmp = new float[numV][];
30
    int numVertices = 0;
31

  
32
    android.util.Log.e("d","numPotential="+numV+" internal: "+internalPoint[0]+" "+internalPoint[1]+" "+internalPoint[2]);
33

  
34
    for( float[] vert : potentialVertices )
35
      {
36
      boolean ok = true;
37

  
38
      for(float[] cutPlane : cutPlanes)
39
        {
40
        if( isOnDifferentSides(internalPoint, vert, cutPlane) )
41
          {
42
          ok = false;
43
          break;
44
          }
45
        }
46

  
47
      if( ok )
48
        {
49
        android.util.Log.d("d","adding vert "+vert[0]+" "+vert[1]+" "+vert[2]);
50
        tmp[numVertices] = vert;
51
        numVertices++;
52
        }
53
      }
54

  
55
    float[][] vertices = new float[numVertices][];
56

  
57
    for(int v=0; v<numVertices; v++)
58
      {
59
      float[] t = tmp[v];
60
      vertices[v] = new float[] { t[0],t[1],t[2] };
61
      }
62

  
63
    android.util.Log.d("d","added "+numVertices+" verts");
64

  
65
    int numP = cutPlanes.length;
66
    int[] numVerticesOnPlane = new int[numP];
67
    int[][] verticesOnPlane = new int[numP][numVertices];
68

  
69
    for(int p=0; p<numP; p++)
70
      {
71
      float[] plane = cutPlanes[p];
72

  
73
      for(int v=0; v<numVertices; v++)
74
        {
75
        float[] vert = vertices[v];
76

  
77
        if( vertexOnPlane(vert,plane) )
78
          {
79
          verticesOnPlane[p][numVerticesOnPlane[p]] = v;
80
          numVerticesOnPlane[p]++;
81
          }
82
        }
83
      }
84

  
85
    int numFaces = 0;
86
    for(int p=0; p<numP; p++)
87
      if( numVerticesOnPlane[p]>=3 ) numFaces++;
88

  
89
    int[][] indices = new int[numFaces][];
90
    int index = 0;
91

  
92
    for(int p=0; p<numP; p++ )
93
      if( numVerticesOnPlane[p]>=3 )
94
        {
95
        float[] center = computeCenterOfMass(vertices,numVerticesOnPlane[p],verticesOnPlane[p]);
96
        indices[index] = arrangeCCW(center,cutPlanes[p],vertices,numVerticesOnPlane[p],verticesOnPlane[p]);
97
        index++;
98
        }
99

  
100
    for( float[] v: vertices )
101
      {
102
      v[0] -= position[0];
103
      v[1] -= position[1];
104
      v[2] -= position[2];
105
      }
106

  
107
    return new ObjectShape(vertices,indices);
108
    }
109

  
110
///////////////////////////////////////////////////////////////////////////////////////////////////
111
// return arithmetic average of the vertices.
112

  
113
  private static float[] computeCenterOfMass(float[][] vertices, int num, int[] indices)
114
    {
115
    float[] ret = new float[3];
116

  
117
    for( int i : indices )
118
      {
119
      float[] v = vertices[i];
120

  
121
      ret[0] += v[0];
122
      ret[1] += v[1];
123
      ret[2] += v[2];
124
      }
125

  
126
    ret[0] /= num;
127
    ret[1] /= num;
128
    ret[2] /= num;
129

  
130
    return ret;
131
    }
132

  
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134
// Return true iff 'vertex' lies in the plane 'plane'
135

  
136
  private static boolean vertexOnPlane(float[] vertex, float[] plane)
137
    {
138
    final float MAXERROR = 0.01f;
139
    float d = vertex[0]*plane[0] + vertex[1]*plane[1] + vertex[2]*plane[2] - plane[3];
140
    return (d>=-MAXERROR && d<=MAXERROR);
141
    }
142

  
143
///////////////////////////////////////////////////////////////////////////////////////////////////
144
// return true iff points p0 and p1 are on different sides of plane 'plane'. [ i.e. every way from
145
// p0 to p1, always has to pass through at least one point from 'plane' ]
146

  
147
  private static boolean isOnDifferentSides(float[] p0, float[] p1, float[] plane)
148
    {
149
    final float MAXERROR = 0.01f;
150

  
151
    float d0 = p0[0]*plane[0] + p0[1]*plane[1] + p0[2]*plane[2] - plane[3];
152
    float d1 = p1[0]*plane[0] + p1[1]*plane[1] + p1[2]*plane[2] - plane[3];
153

  
154
    if( d0>=-MAXERROR && d0<=MAXERROR ) return false;
155
    if( d0>MAXERROR ) return d1<-MAXERROR;
156
    return d1>MAXERROR;
157
    }
158

  
159
///////////////////////////////////////////////////////////////////////////////////////////////////
160
// return indices 'indices', but cut to only 'num' of them [original 'indices' array can be longer]
161
// and arranged so that the 'vertices' those indices are indices for are in counter-clockwise order
162
// [starting from an arbitrary one]. center is their center of mass.
163
//
164
// a) for every vertex, compute the angle the vector from 'center' to this vertex forms with an
165
//    arbitrary line [for example the vector from center to the first vertex]
166
// b) sort the vertices by this angle [ascending]
167

  
168
  private static int[] arrangeCCW(float[] center, float[] plane, float[][] vertices, int num, int[] indices)
169
    {
170
    float[] angles = new float[num];
171

  
172
    int j= indices[0];
173
    float vx = vertices[j][0] - center[0];
174
    float vy = vertices[j][1] - center[1];
175
    float vz = vertices[j][2] - center[2];
176

  
177
    float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
178

  
179
    vx /= len;
180
    vy /= len;
181
    vz /= len;
182

  
183
    for(int i=0; i<num; i++)
184
      {
185
      int index = indices[i];
186
      float[] v = vertices[index];
187

  
188
      float wx = v[0]-center[0];
189
      float wy = v[1]-center[1];
190
      float wz = v[2]-center[2];
191

  
192
      float l = (float)Math.sqrt(wx*wx + wy*wy + wz*wz);
193

  
194
      wx /= l;
195
      wy /= l;
196
      wz /= l;
197

  
198
      angles[i] = computeAngle(plane,vx,vy,vz,wx,wy,wz);
199
      }
200

  
201
    int[] ret = new int[num];
202
    for(int i=0; i<num; i++) ret[i] = indices[i];
203

  
204
    bubbleSort(angles,ret,num);
205

  
206
    return ret;
207
    }
208

  
209
///////////////////////////////////////////////////////////////////////////////////////////////////
210
// strange version of bubbleSort where we sort array 'arr2' according to values of different array
211
// 'arr1'.
212

  
213
  private static void bubbleSort(float[] arr1, int[] arr2, int n)
214
    {
215
    int i, j, temp;
216
    boolean swapped;
217
    float tmp;
218

  
219
    for( i=0; i<n-1; i++ )
220
      {
221
      swapped = false;
222

  
223
      for( j=0; j<n-i-1; j++ )
224
        {
225
        if( arr1[j] > arr1[j+1] )
226
          {
227
          tmp      = arr1[j];
228
          arr1[j]  = arr1[j+1];
229
          arr1[j+1]= tmp;
230

  
231
          temp     = arr2[j];
232
          arr2[j]  = arr2[j+1];
233
          arr2[j+1]= temp;
234

  
235
          swapped  = true;
236
          }
237
        }
238

  
239
      if( !swapped ) break;
240
      }
241
    }
242

  
243
///////////////////////////////////////////////////////////////////////////////////////////////////
244
// given a plane with normal vector 'normal', and two in-plane vectors p=(px,py,pz) and
245
// r=(rx,ry,rz) [in-plane, i.e. cross(p,r) is parallel to 'normal' ] compute the angle between p and r.
246
//
247
// the angle belongs to <0,2PI) and goes from p to r counter-clockwise (according to the 'normal' -
248
// i.e. look at the situation so that the normal points at you and track the angle from p to r)
249
//
250
// vectors p and r are guaranteed to be normalized.
251
//
252
// 1. compute scalar product of p and r
253
// 2. result is the cosine of the 'smaller' angle between the two
254
// 3. a = compute arc cos of this
255
// 4. return a or (2PI-a), depending on if cross(p,r) agrees in direction with the normal, or not.
256

  
257
  private static float computeAngle(float[] normal, float px, float py, float pz, float rx, float ry, float rz)
258
    {
259
    float s = px*rx + py*ry + pz*rz;
260
    float a = (float) Math.acos(s);
261
    float[] cross = crossProduct(px,py,pz,rx,ry,rz);
262
    float scalar = cross[0]*normal[0] + cross[1]*normal[1] + cross[2]*normal[2];
263

  
264
    return scalar>0 ? a : (float)(2*Math.PI - a);
265
    }
266

  
267
///////////////////////////////////////////////////////////////////////////////////////////////////
268

  
269
  private static float[] crossProduct(float a1, float a2, float a3, float b1, float b2, float b3)
270
    {
271
    float[] ret = new float[3];
272

  
273
    ret[0] = a2*b3 - a3*b2;
274
    ret[1] = a3*b1 - a1*b3;
275
    ret[2] = a1*b2 - a2*b1;
276

  
277
    return ret;
278
    }
279

  
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281
// if normals to planes p1,p2,p3 are linearly independent, than those planes intersect in one point.
282
// Return this point. Otherwise, return null.
283

  
284
  private static float[] computeCommonPoint(float[] p1, float[] p2, float[] p3)
285
    {
286
    float MAXERROR = 0.01f;
287
    float det = determinant(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],p3[0],p3[1],p3[2]);
288

  
289
    if( det>=-MAXERROR && det<=MAXERROR ) return null;
290

  
291
    float deX = determinant(p1[3],p1[1],p1[2],p2[3],p2[1],p2[2],p3[3],p3[1],p3[2]);
292
    float deY = determinant(p1[0],p1[3],p1[2],p2[0],p2[3],p2[2],p3[0],p3[3],p3[2]);
293
    float deZ = determinant(p1[0],p1[1],p1[3],p2[0],p2[1],p2[3],p3[0],p3[1],p3[3]);
294

  
295
    return new float[] { deX/det, deY/det, deZ/det };
296
    }
297

  
298
///////////////////////////////////////////////////////////////////////////////////////////////////
299
// a1 a2 a3 a1 a2
300
// b1 b2 b3 b1 b2
301
// c1 c2 c3 c1 c2
302

  
303
  private static float determinant(float a1, float a2, float a3,
304
                                   float b1, float b2, float b3,
305
                                   float c1, float c2, float c3 )
306
    {
307
    float det = 0;
308

  
309
    det += a1*b2*c3;
310
    det += a2*b3*c1;
311
    det += a3*b1*c2;
312
    det -= a3*b2*c1;
313
    det -= a1*b3*c2;
314
    det -= a2*b1*c3;
315

  
316
    return det;
317
    }
318

  
319
///////////////////////////////////////////////////////////////////////////////////////////////////
320

  
321
  private static boolean isDifferent(float[][] table, int num, float[] vert)
322
    {
323
    float MAXERROR = 0.01f;
324

  
325
    for( int i=0; i<num; i++ )
326
      {
327
      float[] t = table[i];
328
      float dx = t[0]-vert[0];
329
      float dy = t[1]-vert[1];
330
      float dz = t[2]-vert[2];
331
      float dist = dx*dx + dy*dy + dz*dz;
332

  
333
      if( dist>=-MAXERROR && dist<=MAXERROR ) return false;
334
      }
335

  
336
    return true;
337
    }
338

  
339
///////////////////////////////////////////////////////////////////////////////////////////////////
340

  
341
  public static float[][] computePotentialVertices(float[][] cutPlanes)
342
    {
343
    int numPlanes = cutPlanes.length;
344
    int numRet = numPlanes*(numPlanes-1)*(numPlanes-2)/6;
345
    float[][] ret = new float[numRet][];
346
    int index = 0;
347

  
348
    for(int i=0; i<numPlanes; i++)
349
      for(int j=i+1; j<numPlanes; j++)
350
        for(int k=j+1; k<numPlanes; k++)
351
          {
352
          float[] vert = computeCommonPoint(cutPlanes[i],cutPlanes[j],cutPlanes[k]);
353

  
354
          if( vert!=null && isDifferent(ret,index,vert) )
355
            {
356
            ret[index] = vert;
357
            index++;
358
            }
359
          }
360

  
361
    if( index<numRet )
362
      {
363
      float[][] ret2 = new float[index][];
364
      for(int i=0; i<index; i++) ret2[i] = ret[i];
365
      return ret2;
366
      }
367

  
368
    return ret;
369
    }
370

  
371
///////////////////////////////////////////////////////////////////////////////////////////////////
372
// does the (x,y,z) point belong to the face defined by (faceAxis,dist) ?
373

  
374
  private static boolean isInFaces(Static3D[] faceAxis, float[] dist3D, float x, float y, float z)
375
    {
376
    final float MAXERR = 0.01f;
377
    int numA = faceAxis.length;
378

  
379
    for(int a=0; a<numA; a++)
380
      {
381
      Static3D ax = faceAxis[a];
382
      float dist = x*ax.get0() + y*ax.get1() + z*ax.get2();
383
      float diff = dist-dist3D[a];
384
      if( diff>-MAXERR && diff<MAXERR ) return true;
385
      }
386

  
387
    return false;
388
    }
389

  
390
///////////////////////////////////////////////////////////////////////////////////////////////////
391
// return a table of indices.length ints.
392
// Nth int is 0 if the face defined by indices[N] is an external one; 1 otherwise.
393

  
394
  public static int[] produceBandIndices(float[][] vertices, int[][] indices, Static3D[] faceAxis, float[] dist3D )
395
    {
396
    int numF = indices.length;
397
    int[] ret = new int[numF];
398
    float x,y,z;
399

  
400
    for(int f=0; f<numF; f++)
401
      {
402
      int[] faceI = indices[f];
403
      x = y = z = 0;
404

  
405
      for(int i : faceI)
406
        {
407
        float[] vertex = vertices[i];
408
        x += vertex[0];
409
        y += vertex[1];
410
        z += vertex[2];
411
        }
412

  
413
      int numV = faceI.length;
414
      x /= numV;
415
      y /= numV;
416
      z /= numV;
417

  
418
      ret[f] = isInFaces(faceAxis,dist3D, x,y,z) ? 0 : 1;
419
      }
420

  
421
    return ret;
422
    }
423

  
424
///////////////////////////////////////////////////////////////////////////////////////////////////
425
// how many faces does the point 'vert' belong to? (i.e. 3-->corner, 2-->edge, 1--> face point,
426
// 0 --> internal
427

  
428
  private static int numberInFaces(float[] vert, Static3D[] faceAxis, float[] dist3D)
429
    {
430
    final float MAXERR = 0.01f;
431
    int numA = faceAxis.length;
432
    int ret = 0;
433
    float x = vert[0];
434
    float y = vert[1];
435
    float z = vert[2];
436

  
437
    for(int a=0; a<numA; a++)
438
      {
439
      Static3D ax = faceAxis[a];
440
      float dist = x*ax.get0() + y*ax.get1() + z*ax.get2();
441
      float diff = dist-dist3D[a];
442
      if( diff>-MAXERR && diff<MAXERR ) ret++;
443
      }
444

  
445
    return ret;
446
    }
447

  
448
///////////////////////////////////////////////////////////////////////////////////////////////////
449
// return a table of vertices.length ints.
450
// Nth int is 0 if vertices[N] lies in a corner or edge of the shape; -1 otherwise.
451

  
452
  public static int[] computeVertexEffectsIndices(float[][] vertices, Static3D[] faceAxis, float[] dist3D)
453
    {
454
    int numV = vertices.length;
455
    int[] ret = new int[numV];
456

  
457
    for(int v=0; v<numV; v++)
458
      {
459
      float[] vert = vertices[v];
460
      ret[v] = numberInFaces(vert,faceAxis,dist3D)>=2 ? 0 : -1;
461
      }
462

  
463
    return ret;
464
    }
465
  }
src/main/java/org/distorted/objectlib/helpers/FactoryShape.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Magic Cube.                                                              //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.objectlib.helpers;
11

  
12
import org.distorted.library.type.Static3D;
13

  
14
///////////////////////////////////////////////////////////////////////////////////////////////////
15

  
16
public class FactoryShape
17
  {
18
  private static final float MAXERROR = 0.0001f;
19

  
20
///////////////////////////////////////////////////////////////////////////////////////////////////
21
// return arithmetic average of the vertices.
22

  
23
  private static float[] computeCenterOfMass(float[][] vertices, int num, int[] indices)
24
    {
25
    float[] ret = new float[3];
26

  
27
    for( int i=0; i<num; i++ )
28
      {
29
      int ind = indices[i];
30
      float[] v = vertices[ind];
31

  
32
      ret[0] += v[0];
33
      ret[1] += v[1];
34
      ret[2] += v[2];
35
      }
36

  
37
    ret[0] /= num;
38
    ret[1] /= num;
39
    ret[2] /= num;
40

  
41
    return ret;
42
    }
43

  
44
///////////////////////////////////////////////////////////////////////////////////////////////////
45
// Return true iff 'vertex' lies in the plane 'plane'
46

  
47
  private static boolean vertexOnPlane(float[] vertex, float[] plane)
48
    {
49
    float d = vertex[0]*plane[0] + vertex[1]*plane[1] + vertex[2]*plane[2] - plane[3];
50
    return (d>=-MAXERROR && d<=MAXERROR);
51
    }
52

  
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54
// return true iff points p0 and p1 are on different sides of plane 'plane'. [ i.e. every way from
55
// p0 to p1, always has to pass through at least one point from 'plane' ]
56

  
57
  private static boolean isOnDifferentSides(float[] p0, float[] p1, float[] plane)
58
    {
59
    float d0 = p0[0]*plane[0] + p0[1]*plane[1] + p0[2]*plane[2] - plane[3];
60
    float d1 = p1[0]*plane[0] + p1[1]*plane[1] + p1[2]*plane[2] - plane[3];
61

  
62
    if( d0>=-MAXERROR && d0<=MAXERROR ) return false;
63
    if( d0>MAXERROR ) return d1<-MAXERROR;
64
    return d1>MAXERROR;
65
    }
66

  
67
///////////////////////////////////////////////////////////////////////////////////////////////////
68
// return indices 'indices', but cut to only 'num' of them [original 'indices' array can be longer]
69
// and arranged so that the 'vertices' those indices are indices for are in counter-clockwise order
70
// [starting from an arbitrary one]. center is their center of mass.
71
//
72
// a) for every vertex, compute the angle the vector from 'center' to this vertex forms with an
73
//    arbitrary line [for example the vector from center to the first vertex]
74
// b) sort the vertices by this angle [ascending]
75

  
76
  private static int[] arrangeCCW(float[] plane, float[][] vertices, int num, int[] indices)
77
    {
78
    float[] angles = new float[num];
79
    float[] center = computeCenterOfMass(vertices,num,indices);
80

  
81
    int j= indices[0];
82
    float vx = vertices[j][0] - center[0];
83
    float vy = vertices[j][1] - center[1];
84
    float vz = vertices[j][2] - center[2];
85

  
86
    float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
87

  
88
    vx /= len;
89
    vy /= len;
90
    vz /= len;
91

  
92
    for(int i=0; i<num; i++)
93
      {
94
      int index = indices[i];
95
      float[] v = vertices[index];
96

  
97
      float wx = v[0]-center[0];
98
      float wy = v[1]-center[1];
99
      float wz = v[2]-center[2];
100

  
101
      float l = (float)Math.sqrt(wx*wx + wy*wy + wz*wz);
102

  
103
      wx /= l;
104
      wy /= l;
105
      wz /= l;
106

  
107
      angles[i] = computeAngle(plane,vx,vy,vz,wx,wy,wz);
108
      }
109

  
110
    int[] ret = new int[num];
111
    for(int i=0; i<num; i++) ret[i] = indices[i];
112

  
113
    bubbleSort(angles,ret,num);
114

  
115
    return ret;
116
    }
117

  
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119
// strange version of bubbleSort where we sort array 'arr2' according to values of different array
120
// 'arr1'.
121

  
122
  private static void bubbleSort(float[] arr1, int[] arr2, int n)
123
    {
124
    int i, j, temp;
125
    boolean swapped;
126
    float tmp;
127

  
128
    for( i=0; i<n-1; i++ )
129
      {
130
      swapped = false;
131

  
132
      for( j=0; j<n-i-1; j++ )
133
        {
134
        if( arr1[j] > arr1[j+1] )
135
          {
136
          tmp      = arr1[j];
137
          arr1[j]  = arr1[j+1];
138
          arr1[j+1]= tmp;
139

  
140
          temp     = arr2[j];
141
          arr2[j]  = arr2[j+1];
142
          arr2[j+1]= temp;
143

  
144
          swapped  = true;
145
          }
146
        }
147

  
148
      if( !swapped ) break;
149
      }
150
    }
151

  
152
///////////////////////////////////////////////////////////////////////////////////////////////////
153
// given a plane with normal vector 'normal', and two in-plane vectors p=(px,py,pz) and
154
// r=(rx,ry,rz) [in-plane, i.e. cross(p,r) is parallel to 'normal' ] compute the angle between p and r.
155
//
156
// the angle belongs to <0,2PI) and goes from p to r counter-clockwise (according to the 'normal' -
157
// i.e. look at the situation so that the normal points at you and track the angle from p to r)
158
//
159
// vectors p and r are guaranteed to be normalized.
160
//
161
// 1. compute scalar product of p and r
162
// 2. result is the cosine of the 'smaller' angle between the two
163
// 3. a = compute arc cos of this
164
// 4. return a or (2PI-a), depending on if cross(p,r) agrees in direction with the normal, or not.
165

  
166
  private static float computeAngle(float[] normal, float px, float py, float pz, float rx, float ry, float rz)
167
    {
168
    float s = px*rx + py*ry + pz*rz;
169

  
170
    if( s> 1 ) s=1;
171
    if( s<-1 ) s=-1;
172

  
173
    float a = (float) Math.acos(s);
174
    float[] cross = crossProduct(px,py,pz,rx,ry,rz);
175
    float scalar = cross[0]*normal[0] + cross[1]*normal[1] + cross[2]*normal[2];
176

  
177
    return scalar>=0 ? a : (float)(2*Math.PI - a);
178
    }
179

  
180
///////////////////////////////////////////////////////////////////////////////////////////////////
181

  
182
  private static float[] crossProduct(float a1, float a2, float a3, float b1, float b2, float b3)
183
    {
184
    float[] ret = new float[3];
185

  
186
    ret[0] = a2*b3 - a3*b2;
187
    ret[1] = a3*b1 - a1*b3;
188
    ret[2] = a1*b2 - a2*b1;
189

  
190
    return ret;
191
    }
192

  
193
///////////////////////////////////////////////////////////////////////////////////////////////////
194
// if normals to planes p1,p2,p3 are linearly independent, than those planes intersect in one point.
195
// Return this point. Otherwise, return null.
196

  
197
  private static float[] computeCommonPoint(float[] p1, float[] p2, float[] p3)
198
    {
199
    float det = determinant(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],p3[0],p3[1],p3[2]);
200

  
201
    if( det>=-MAXERROR && det<=MAXERROR ) return null;
202

  
203
    float deX = determinant(p1[3],p1[1],p1[2],p2[3],p2[1],p2[2],p3[3],p3[1],p3[2]);
204
    float deY = determinant(p1[0],p1[3],p1[2],p2[0],p2[3],p2[2],p3[0],p3[3],p3[2]);
205
    float deZ = determinant(p1[0],p1[1],p1[3],p2[0],p2[1],p2[3],p3[0],p3[1],p3[3]);
206

  
207
    return new float[] { deX/det, deY/det, deZ/det };
208
    }
209

  
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211
// a1 a2 a3 a1 a2
212
// b1 b2 b3 b1 b2
213
// c1 c2 c3 c1 c2
214

  
215
  private static float determinant(float a1, float a2, float a3,
216
                                   float b1, float b2, float b3,
217
                                   float c1, float c2, float c3 )
218
    {
219
    float det = 0;
220

  
221
    det += a1*b2*c3;
222
    det += a2*b3*c1;
223
    det += a3*b1*c2;
224
    det -= a3*b2*c1;
225
    det -= a1*b3*c2;
226
    det -= a2*b1*c3;
227

  
228
    return det;
229
    }
230

  
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232
// how many faces does the point (x,y,z) belong to? (i.e. 3-->corner, 2-->edge, 1--> face point,
233
// 0 --> internal
234

  
235
  private static int numberInFaces(Static3D[] faceAxis, float[] dist3D, float x, float y, float z)
236
    {
237
    int numA = faceAxis.length;
238
    int ret = 0;
239

  
240
    for(int a=0; a<numA; a++)
241
      {
242
      Static3D ax = faceAxis[a];
243
      float dist = x*ax.get0() + y*ax.get1() + z*ax.get2();
244
      float diff = dist-dist3D[a];
245
      if( diff>-MAXERROR && diff<MAXERROR ) ret++;
246
      }
247

  
248
    return ret;
249
    }
250

  
251
///////////////////////////////////////////////////////////////////////////////////////////////////
252
// does the (x,y,z) point belong to any of the faces defined by (faceAxis,dist) ?
253

  
254
  private static boolean isInFaces(Static3D[] faceAxis, float[] dist3D, float x, float y, float z)
255
    {
256
    int numA = faceAxis.length;
257

  
258
    for(int a=0; a<numA; a++)
259
      {
260
      Static3D ax = faceAxis[a];
261
      float dist = x*ax.get0() + y*ax.get1() + z*ax.get2();
262
      float diff = dist-dist3D[a];
263
      if( diff>-MAXERROR && diff<MAXERROR ) return true;
264
      }
265

  
266
    return false;
267
    }
268

  
269
///////////////////////////////////////////////////////////////////////////////////////////////////
270

  
271
  private static boolean isDifferent(float[][] table, int num, float[] vert)
272
    {
273
    for( int i=0; i<num; i++ )
274
      {
275
      float[] t = table[i];
276
      float dx = t[0]-vert[0];
277
      float dy = t[1]-vert[1];
278
      float dz = t[2]-vert[2];
279
      float dist = dx*dx + dy*dy + dz*dz;
280

  
281
      if( dist>=-MAXERROR && dist<=MAXERROR ) return false;
282
      }
283

  
284
    return true;
285
    }
286

  
287
///////////////////////////////////////////////////////////////////////////////////////////////////
288
// PUBLIC API
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

  
291
  public static float[][] computePotentialVertices(float[][] cutPlanes)
292
    {
293
    int numPlanes = cutPlanes.length;
294
    int numRet = numPlanes*(numPlanes-1)*(numPlanes-2)/6;
295
    float[][] ret = new float[numRet][];
296
    int index = 0;
297

  
298
    for(int i=0; i<numPlanes; i++)
299
      for(int j=i+1; j<numPlanes; j++)
300
        for(int k=j+1; k<numPlanes; k++)
301
          {
302
          float[] vert = computeCommonPoint(cutPlanes[i],cutPlanes[j],cutPlanes[k]);
303

  
304
          if( vert!=null && isDifferent(ret,index,vert) )
305
            {
306
            ret[index] = vert;
307
            index++;
308
            }
309
          }
310

  
311
    if( index<numRet )
312
      {
313
      float[][] ret2 = new float[index][];
314
      for(int i=0; i<index; i++) ret2[i] = ret[i];
315
      return ret2;
316
      }
317

  
318
    return ret;
319
    }
320

  
321
///////////////////////////////////////////////////////////////////////////////////////////////////
322
// return a table of indices.length ints.
323
// Nth int is 0 if the face defined by indices[N] is an external one; 1 otherwise.
324

  
325
  public static int[] produceBandIndices(float[][] vertices, float[] position, int[][] indices, Static3D[] faceAxis, float[] dist3D )
326
    {
327
    int numF = indices.length;
328
    int[] ret = new int[numF];
329
    float x,y,z;
330

  
331
    for(int f=0; f<numF; f++)
332
      {
333
      int[] faceI = indices[f];
334
      x = y = z = 0;
335

  
336
      for(int i : faceI)
337
        {
338
        float[] vertex = vertices[i];
339
        x += vertex[0];
340
        y += vertex[1];
341
        z += vertex[2];
342
        }
343

  
344
      int numV = faceI.length;
345
      x /= numV;
346
      y /= numV;
347
      z /= numV;
348

  
349
      x += position[0];
350
      y += position[1];
351
      z += position[2];
352

  
353
      ret[f] = isInFaces(faceAxis,dist3D, x,y,z) ? 0 : 1;
354
      }
355

  
356
    return ret;
357
    }
358

  
359
///////////////////////////////////////////////////////////////////////////////////////////////////
360
// return a table of vertices.length ints.
361
// Nth int is 0 if vertices[N] lies in a corner or edge of the shape; -1 otherwise.
362

  
363
  public static int[] computeVertexEffectsIndices(float[][] vertices, float[] position, Static3D[] faceAxis, float[] dist3D)
364
    {
365
    int numV = vertices.length;
366
    int[] ret = new int[numV];
367

  
368
    for(int v=0; v<numV; v++)
369
      {
370
      float[] vert = vertices[v];
371

  
372
      float x = vert[0] + position[0];
373
      float y = vert[1] + position[1];
374
      float z = vert[2] + position[2];
375

  
376
      ret[v] = numberInFaces(faceAxis,dist3D,x,y,z)>=2 ? 0 : -1;
377
      }
378

  
379
    return ret;
380
    }
381

  
382
///////////////////////////////////////////////////////////////////////////////////////////////////
383
// 1. for every potentialVertex, if it is on the same side of every plane present as the
384
//    'internalPoint', it must be one of the vertices of the ObjectShape. Remember which planes it
385
//    belongs to and add it to the list of vertices.
386
// 2. Having complete list of vertices and a bitmap of which planes each vertex belongs to, for each
387
//    plane:
388
//    a) assemble the list of vertices that belong to this plane
389
//    b) compute their center of mass and using this as a pivot, arrange the list into CCW order
390
//    c) out of the vertices and the CCW'd indices, construct an ObjectShape.
391

  
392
  public static ObjectShape createShape(float[][] cutPlanes, float[][] potentialVertices, float[] position, float[] internalPoint)
393
    {
394
    int numV = potentialVertices.length;
395
    float[][] tmp = new float[numV][];
396
    int numVertices = 0;
397

  
398
    for( float[] vert : potentialVertices )
399
      {
400
      boolean ok = true;
401

  
402
      for(float[] plane : cutPlanes)
403
        {
404
        if( isOnDifferentSides(internalPoint, vert, plane) )
405
          {
406
          ok = false;
407
          break;
408
          }
409
        }
410

  
411
      if( ok )
412
        {
413
        tmp[numVertices] = vert;
414
        numVertices++;
415
        }
416
      }
417

  
418
    float[][] vertices = new float[numVertices][];
419

  
420
    for(int v=0; v<numVertices; v++)
421
      {
422
      float[] t = tmp[v];
423
      vertices[v] = new float[] { t[0],t[1],t[2] };
424
      }
425

  
426
    int numP = cutPlanes.length;
427
    int[] numVerticesOnPlane = new int[numP];
428
    int[][] verticesOnPlane = new int[numP][numVertices];
429

  
430
    for(int p=0; p<numP; p++)
431
      {
432
      float[] plane = cutPlanes[p];
433

  
434
      for(int v=0; v<numVertices; v++)
435
        {
436
        float[] vert = vertices[v];
437

  
438
        if( vertexOnPlane(vert,plane) )
439
          {
440
          verticesOnPlane[p][numVerticesOnPlane[p]] = v;
441
          numVerticesOnPlane[p]++;
442
          }
443
        }
444
      }
445

  
446
    int numFaces = 0;
447
    for(int p=0; p<numP; p++)
448
      if( numVerticesOnPlane[p]>=3 ) numFaces++;
449

  
450
    int[][] indices = new int[numFaces][];
451
    int index = 0;
452

  
453
    for(int p=0; p<numP; p++ )
454
      if( numVerticesOnPlane[p]>=3 )
455
        {
456
        indices[index] = arrangeCCW(cutPlanes[p],vertices,numVerticesOnPlane[p],verticesOnPlane[p]);
457
        index++;
458
        }
459

  
460
    for( float[] v: vertices )
461
      {
462
      v[0] -= position[0];
463
      v[1] -= position[1];
464
      v[2] -= position[2];
465
      }
466

  
467
    return new ObjectShape(vertices,indices);
468
    }
469
  }
src/main/java/org/distorted/objectlib/objects/TwistyMirrorSkewb.java
15 15
import org.distorted.library.type.Static3D;
16 16
import org.distorted.library.type.Static4D;
17 17
import org.distorted.objectlib.helpers.FactoryCubit;
18
import org.distorted.objectlib.helpers.FactoryMirror;
18
import org.distorted.objectlib.helpers.FactoryShape;
19 19
import org.distorted.objectlib.helpers.ObjectFaceShape;
20 20
import org.distorted.objectlib.helpers.ObjectShape;
21 21
import org.distorted.objectlib.helpers.ObjectVertexEffects;
......
41 41
         };
42 42

  
43 43
  private static final int[] FACE_COLORS = new int[] { COLOR_WHITE };
44
  private static final float[] MIRROR_VEC = {0,0,0};//{ 0.10f, 0.25f, 0.40f };
44
  private static final float[] MIRROR_VEC = { 0.10f, 0.15f, 0.20f };
45 45

  
46 46
  private int[][] mEdges;
47 47
  private int[][] mBasicAngle;
......
64 64
  @Override
65 65
  public int getInternalColor()
66 66
    {
67
    return 0xff222222;
67
    return 0xff333333;
68 68
    }
69 69

  
70 70
///////////////////////////////////////////////////////////////////////////////////////////////////
......
185 185

  
186 186
///////////////////////////////////////////////////////////////////////////////////////////////////
187 187

  
188
  public float[][] getCubitPositions(int[] numLayers)
188
  private float[][] getPositions()
189 189
    {
190 190
    if( mPositions==null )
191 191
      {
192
      final float COR = 1;
193
      final float CEN = 1;
192
      final float COR = 1.0f;
193
      final float CEN = 1.0f;
194 194
      final float X = MIRROR_VEC[0];
195 195
      final float Y = MIRROR_VEC[1];
196 196
      final float Z = MIRROR_VEC[2];
197 197

  
198 198
      mPositions = new float[8+6][];
199 199

  
200
      mPositions[0] = new float[]{ COR-X,  COR-Y,  COR-Z };
201
      mPositions[1] = new float[]{ COR-X,  COR-Y, -COR-Z };
202
      mPositions[2] = new float[]{ COR-X, -COR-Y,  COR-Z };
203
      mPositions[3] = new float[]{ COR-X, -COR-Y, -COR-Z };
204
      mPositions[4] = new float[]{-COR-X,  COR-Y,  COR-Z };
205
      mPositions[5] = new float[]{-COR-X,  COR-Y, -COR-Z };
206
      mPositions[6] = new float[]{-COR-X, -COR-Y,  COR-Z };
207
      mPositions[7] = new float[]{-COR-X, -COR-Y, -COR-Z };
208

  
209
      mPositions[ 8] = new float[]{    -X,    -Y, CEN-Z };
210
      mPositions[ 9] = new float[]{    -X,    -Y,-CEN-Z };
211
      mPositions[10] = new float[]{    -X, CEN-Y,    -Z };
212
      mPositions[11] = new float[]{    -X,-CEN-Y,    -Z };
213
      mPositions[12] = new float[]{ CEN-X,    -Y,    -Z };
214
      mPositions[13] = new float[]{-CEN-X,    -Y,    -Z };
200
      mPositions[0] = new float[]{ COR+X,  COR+Y,  COR+Z };
201
      mPositions[1] = new float[]{ COR+X,  COR+Y, -COR+Z };
202
      mPositions[2] = new float[]{ COR+X, -COR+Y,  COR+Z };
203
      mPositions[3] = new float[]{ COR+X, -COR+Y, -COR+Z };
204
      mPositions[4] = new float[]{-COR+X,  COR+Y,  COR+Z };
205
      mPositions[5] = new float[]{-COR+X,  COR+Y, -COR+Z };
206
      mPositions[6] = new float[]{-COR+X, -COR+Y,  COR+Z };
207
      mPositions[7] = new float[]{-COR+X, -COR+Y, -COR+Z };
208

  
209
      mPositions[ 8] = new float[]{     X,     Y, CEN+Z };
210
      mPositions[ 9] = new float[]{     X,     Y,-CEN+Z };
211
      mPositions[10] = new float[]{     X, CEN+Y,     Z };
212
      mPositions[11] = new float[]{     X,-CEN+Y,     Z };
213
      mPositions[12] = new float[]{ CEN+X,     Y,     Z };
214
      mPositions[13] = new float[]{-CEN+X,     Y,     Z };
215 215
      }
216 216

  
217 217
    return mPositions;
218 218
    }
219 219

  
220

  
221
///////////////////////////////////////////////////////////////////////////////////////////////////
222

  
223
  public float[][] getCubitPositions(int[] numLayers)
224
    {
225
    return getPositions();
226
    }
227

  
220 228
///////////////////////////////////////////////////////////////////////////////////////////////////
221 229

  
222 230
  public Static4D getCubitQuats(int cubit, int[] numLayers)
......
250 258

  
251 259
  private float[] internalPoint(int variant)
252 260
    {
253
    int[] numLayers = getNumLayers();
254
    float[][] pos = getCubitPositions(numLayers);
261
    float[][] pos = getPositions();
255 262
    float[] position = pos[variant];
256 263
    float[][] center = computeVertexEffectCenter(variant);
257 264
    float[] cent = center[0];
......
277 284
      int numV = getNumCubitVariants(numLayers);
278 285
      mShapes = new ObjectShape[numV];
279 286
      createCutPlanes();
280
      mPotentialVertices = FactoryMirror.computePotentialVertices(mCutPlanes);
287
      mPotentialVertices = FactoryShape.computePotentialVertices(mCutPlanes);
281 288
      }
282 289

  
283 290
    if( mShapes[variant]==null )
284 291
      {
285
      int[] numLayers = getNumLayers();
286
      float[][] pos = getCubitPositions(numLayers);
292
      float[][] pos = getPositions();
287 293
      float[] point = internalPoint(variant);
288
      mShapes[variant] = FactoryMirror.createShape(mCutPlanes,mPotentialVertices,pos[variant],point);
294
      mShapes[variant] = FactoryShape.createShape(mCutPlanes,mPotentialVertices,pos[variant],point);
289 295
      }
290 296

  
291 297
    return mShapes[variant];
......
298 304
    ObjectShape shape = getObjectShape(variant);
299 305
    int[][] ind    = shape.getVertIndices();
300 306
    float[][] vert = shape.getVertices();
301
    int[] indices  = FactoryMirror.produceBandIndices(vert,ind, getFaceAxis(), getDist() );
307
    float[][] pos  = getPositions();
308
    int[] indices  = FactoryShape.produceBandIndices(vert, pos[variant], ind, getFaceAxis(), getDist() );
302 309

  
303 310
    if( variant<8 )
304 311
      {
305 312
      int N = 5;
306
      int E1= 3;
307
      int E2= 1;
308
      float height = isInIconMode() ? 0.001f : 0.30f;
309
      float[][] bands = { {height,35,0.16f,0.7f,N,E1,E1}, {0.1f, 35,1.00f,0.0f,3,1,E2} };
313
      int E = 2;
314
      float height = isInIconMode() ? 0.001f : 0.04f;
315
      float[][] bands = { {height,35,0.16f,0.7f,N,E,E}, {0.001f, 35,1.00f,0.0f,N,E,E} };
310 316
      return new ObjectFaceShape(bands,indices,null);
311 317
      }
312 318
    else
313 319
      {
314 320
      int N = 5;
315
      int E = 2;
316
      float height = isInIconMode() ? 0.001f : 0.30f;
317
      float[][] bands = { {height,35,SQ2/8,0.9f,N,E,E}, {0.1f,35,1,0.0f,3,0,0} };
321
      int E = 1;
322
      float height = isInIconMode() ? 0.001f : 0.05f;
323
      float[][] bands = { {height,35,SQ2/8,0.9f,N,E,E}, {0.001f,35,1,0.0f,3,0,0} };
318 324
      return new ObjectFaceShape(bands,indices,null);
319 325
      }
320 326
    }
......
353 359
    ObjectShape shape  = getObjectShape(variant);
354 360
    float[][] vertices = shape.getVertices();
355 361
    float[][] centers  = computeVertexEffectCenter(variant);
356
    int[] indices      = FactoryMirror.computeVertexEffectsIndices(vertices,getFaceAxis(), getDist() );
357
    float[][] corners  = variant<8 ? new float[][]{{0.04f, 0.20f}} : new float[][]{{0.03f, 0.15f}};
362
    float[][] pos      = getPositions();
363
    int[] indices      = FactoryShape.computeVertexEffectsIndices(vertices, pos[variant], getFaceAxis(), getDist() );
364
    float[][] corners  = variant<8 ? new float[][]{{0.00f, 0.20f}} : new float[][]{{0.00f, 0.15f}};
358 365

  
359 366
    return FactoryCubit.generateVertexEffect(vertices,corners,indices,centers,indices);
360 367
    }

Also available in: Unified diff