Project

General

Profile

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

distorted-objectlib / src / main / java / org / distorted / objectlib / bandaged / BandagedObjectMegaminx.java @ 7e8750c9

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.bandaged;
11

    
12
import static org.distorted.objectlib.main.TwistyObject.SQ5;
13
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.C2;
14
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.COS54;
15
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.LEN;
16
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
17

    
18
import org.distorted.library.main.DistortedScreen;
19
import org.distorted.library.mesh.MeshBase;
20
import org.distorted.library.type.Static3D;
21
import org.distorted.objectlib.main.TwistyObject;
22
import org.distorted.objectlib.metadata.Metadata;
23
import org.distorted.objectlib.objects.TwistyBandagedMegaminx;
24
import org.distorted.objectlib.shape.ShapeDodecahedron;
25
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
26

    
27
///////////////////////////////////////////////////////////////////////////////////////////////////
28

    
29
public class BandagedObjectMegaminx extends BandagedObject
30
{
31
  public static final float MEGA_D = 0.04f;
32

    
33
  public static final float SIN18 = (SQ5-1)/4;
34
  public static final float COS18 = (float)(0.25f*Math.sqrt(10.0f+2.0f*SQ5));
35

    
36
  private static final int NUM_CORNERS = 20;
37
  private static final int NUM_CENTERS = 12;
38
  private static final int NUM_EDGES   = 30;
39

    
40
///////////////////////////////////////////////////////////////////////////////////////////////////
41

    
42
  private float[][] getCuts(int[] numLayers)
43
    {
44
    int numL = numLayers[0];
45
    int distL = numL;
46
    boolean megaminx = isMegaminx(numL);
47
    float dist = megaminx ? 0.5f-MEGA_D : 0.5f;
48
    if( (numL%2)==0 ) numL++;
49

    
50
    float[][] ret = new float[6][numL-1];
51
    float D = distL*TouchControlDodecahedron.DIST3D;
52
    float X = 2*D/(2+SIN18);  // height of the 'upper' part of a dodecahedron, i.e. put it on a table,
53
                              // its height is then 2D, it has one 'lower' part of height X, one
54
                              // 'middle' part of height Y and one upper part of height X again.
55
    int num = (numL-1)/2;
56
    float G = X*dist/num;     // height of one Layer
57

    
58
    for(int i=0; i<num; i++)
59
      {
60
      float cut = -D + (i+0.85f)*G;  // 0.85? not fully correct; attempt to make it
61
                                     // easier to rotate the outer layers
62
      int j = 2*num-1-i;
63
      ret[0][i] =  cut;
64
      ret[0][j] = -cut;
65
      ret[1][i] =  cut;
66
      ret[1][j] = -cut;
67
      ret[2][i] =  cut;
68
      ret[2][j] = -cut;
69
      ret[3][i] =  cut;
70
      ret[3][j] = -cut;
71
      ret[4][i] =  cut;
72
      ret[4][j] = -cut;
73
      ret[5][i] =  cut;
74
      ret[5][j] = -cut;
75
      }
76

    
77
    return ret;
78
    }
79

    
80
///////////////////////////////////////////////////////////////////////////////////////////////////
81
// The pair (distance,angle) defines a point P in R^2 in polar coordinate system. Let V be the vector
82
// from the center of the coordinate system to P.
83
// Let P' be the point defined by polar (distance,angle+PI/2). Let Lh be the half-line starting at
84
// P' and going in the direction of V.
85
// Return true iff point 'point' lies on the left of Lh, i.e. when we rotate (using the center of
86
// the coordinate system as the center of rotation) 'point' and Lh in such a way that Lh points
87
// directly upwards, is 'point' on the left or the right of it?
88

    
89
  private boolean isOnTheLeft(float[] point, float distance, float angle)
90
    {
91
    float sin = (float)Math.sin(angle);
92
    float cos = (float)Math.cos(angle);
93

    
94
    float vx = point[0] + sin*distance;
95
    float vy = point[1] - cos*distance;
96

    
97
    return vx*sin < vy*cos;
98
    }
99

    
100
///////////////////////////////////////////////////////////////////////////////////////////////////
101
// return angle (in radians) that the line connecting the center C of the pentagonal face and the
102
// first vertex of the pentagon makes with a vertical line coming upwards from the center C.
103

    
104
  private float returnAngle(int face)
105
    {
106
    switch(face)
107
      {
108
      case  0:
109
      case  2:
110
      case  6:
111
      case  7: return 0.0f;
112
      case  1:
113
      case  3:
114
      case  4:
115
      case  5: return (float)(36*Math.PI/180);
116
      case  9:
117
      case 10: return (float)(54*Math.PI/180);
118
      case  8:
119
      case 11: return (float)(18*Math.PI/180);
120
      }
121

    
122
    return 0.0f;
123
    }
124

    
125
///////////////////////////////////////////////////////////////////////////////////////////////////
126
// i.e. one with a center - as opposed to 'kilominx'
127

    
128
  static boolean isMegaminx(int size)
129
    {
130
    return (size%2)==1;
131
    }
132

    
133
///////////////////////////////////////////////////////////////////////////////////////////////////
134

    
135
  static int numCubitsPerCornerMega(int numLayers)
136
    {
137
    return 3*((numLayers-1)/2)*((numLayers-3)/2) + 1;
138
    }
139

    
140
///////////////////////////////////////////////////////////////////////////////////////////////////
141

    
142
  static int numCubitsPerEdgeMega(int numLayers)
143
    {
144
    return numLayers-2;
145
    }
146

    
147
///////////////////////////////////////////////////////////////////////////////////////////////////
148

    
149
  static int numCubitsPerCornerKilo(int numLayers)
150
    {
151
    return 3*((numLayers-3)/2)*((numLayers-5)/2) + (numLayers<5 ? 0:1);
152
    }
153

    
154
///////////////////////////////////////////////////////////////////////////////////////////////////
155

    
156
  static int numCubitsPerEdgeKilo(int numLayers)
157
    {
158
    return numLayers<5 ? 0 : 2*(numLayers-4);
159
    }
160

    
161
///////////////////////////////////////////////////////////////////////////////////////////////////
162

    
163
  public static int numCubits(int size)
164
    {
165
    if( isMegaminx(size) )
166
      {
167
      int numCubitsPerCorner = numCubitsPerCornerMega(size);
168
      int numCubitsPerEdge   = numCubitsPerEdgeMega(size);
169
      return NUM_CORNERS*numCubitsPerCorner+NUM_EDGES*numCubitsPerEdge+NUM_CENTERS;
170
      }
171
    else
172
      {
173
      size++;
174

    
175
      if(size==3) return NUM_CORNERS;
176

    
177
      int numCubitsPerCorner = numCubitsPerCornerKilo(size);
178
      int numCubitsPerEdge   = numCubitsPerEdgeKilo(size);
179
      int numCubitsPerCenter = 5;
180
      return NUM_CORNERS*numCubitsPerCorner+NUM_EDGES*numCubitsPerEdge+NUM_CENTERS*numCubitsPerCenter;
181
      }
182
    }
183

    
184
///////////////////////////////////////////////////////////////////////////////////////////////////
185

    
186
  public static boolean isAdjacent(int size, float dx, float dy, float dz)
187
    {
188
    float len = dx*dx + dy*dy + dz*dz;
189
    float MAXERR = 0.01f;
190

    
191
    switch(size)
192
      {
193
      case 2: float x2_0 = 2.01f;
194
              return len<=x2_0*x2_0;
195

    
196
      case 3: float x3_0 = 1.51f*(SIN54/COS54);
197
              return len<=x3_0*x3_0;
198

    
199
      case 4: float x4_0 = 1.0f;
200
              float x4_1 = 2.00f;
201
              float x4_2 = 2.00f*(1+SIN18);
202
              float d4_0 = len-x4_0*x4_0;
203
              float d4_1 = len-x4_1*x4_1;
204
              float d4_2 = len-x4_2*x4_2;
205

    
206
              return ( (d4_0<MAXERR && d4_0>-MAXERR) ||
207
                       (d4_1<MAXERR && d4_1>-MAXERR) ||
208
                       (d4_2<MAXERR && d4_2>-MAXERR)  );
209

    
210
      case 5: float x5_0 = 2.5f*(0.5f-MEGA_D);
211
              float x5_1 = 2.5f*(0.5f+MEGA_D);
212
              float x5_2 = x5_0*COS18;
213
              float x5_3 = x5_1 + x5_0*SIN18;
214
              float x5_4 = 2.5f*SIN54/COS54 - x5_2;
215
              float d5_0 = len-x5_0*x5_0;
216
              float d5_1 = len-x5_1*x5_1;
217
              float d5_2 = len-x5_2*x5_2;
218
              float d5_3 = len-x5_3*x5_3;
219
              float d5_4 = len-x5_4*x5_4;
220

    
221
              return ( (d5_0<MAXERR && d5_0>-MAXERR) ||
222
                       (d5_1<MAXERR && d5_1>-MAXERR) ||
223
                       (d5_2<MAXERR && d5_2>-MAXERR) ||
224
                       (d5_3<MAXERR && d5_3>-MAXERR) ||
225
                       (d5_4<MAXERR && d5_4>-MAXERR)  );
226
      }
227

    
228
    return false;
229
    }
230

    
231
///////////////////////////////////////////////////////////////////////////////////////////////////
232

    
233
  float[][] getRotAxis()
234
    {
235
    return new float[][]
236
      {
237
         {    C2/LEN, SIN54/LEN,    0      },
238
         {   -C2/LEN, SIN54/LEN,    0      },
239
         { 0        ,    C2/LEN, SIN54/LEN },
240
         { 0        ,   -C2/LEN, SIN54/LEN },
241
         { SIN54/LEN,    0     ,    C2/LEN },
242
         { SIN54/LEN,    0     ,   -C2/LEN }
243
      };
244
    }
245

    
246
///////////////////////////////////////////////////////////////////////////////////////////////////
247

    
248
  float[][][] getPositions()
249
    {
250
    FactoryBandagedMegaminx factory = FactoryBandagedMegaminx.getInstance();
251
    return factory.getPositions(mSize);
252
    }
253

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

    
256
  float getDist2D()
257
    {
258
    return (SIN54/COS54)/2;
259
    }
260

    
261
///////////////////////////////////////////////////////////////////////////////////////////////////
262

    
263
  int[] getColors()
264
    {
265
    return ShapeDodecahedron.FACE_COLORS;
266
    }
267

    
268

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

    
271
  boolean isAdjacent(float x1, float y1, float z1, float x2, float y2, float z2 )
272
    {
273
    float dx = x1-x2;
274
    float dy = y1-y2;
275
    float dz = z1-z2;
276

    
277
    return isAdjacent(mSize[0],dx,dy,dz);
278
    }
279

    
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281

    
282
  MeshBase createMesh(float[] pos, boolean round)
283
    {
284
    FactoryBandagedMegaminx factory = FactoryBandagedMegaminx.getInstance();
285
    return factory.createMesh(pos,mSize,false,round);
286
    }
287

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

    
291
  public BandagedObjectMegaminx(DistortedScreen screen, int minSize, int maxSize)
292
    {
293
    super(screen,minSize,maxSize);
294
    }
295

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

    
298
  public float getScreenRatio()
299
    {
300
    return 0.3f;
301
    }
302

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

    
305
  public float[] getDist3D()
306
    {
307
    float d = (float)Math.sqrt(0.625f+0.275f*SQ5);
308
    return new float[] {d,d,d,d,d,d,d,d,d,d,d,d};
309
    }
310

    
311
///////////////////////////////////////////////////////////////////////////////////////////////////
312

    
313
  public Static3D[] getFaceAxis()
314
    {
315
    return TouchControlDodecahedron.FACE_AXIS;
316
    }
317

    
318
///////////////////////////////////////////////////////////////////////////////////////////////////
319

    
320
  public boolean tryChangeObject(int x, int y, int z)
321
    {
322
    if( mSize[0]!=x && x>=mMinSize && x<=mMaxSize )
323
      {
324
      mSize[0] = x;
325
      mSize[1] = x;
326
      mSize[2] = x;
327
      mSize[3] = x;
328
      mSize[4] = x;
329
      mSize[5] = x;
330

    
331
      mMax = x;
332
      mNumCubits = numCubits(x);
333
      mCuts = getCuts(mSize);
334
      return true;
335
      }
336
    else if( mCuts==null )
337
      {
338
      mMax = 2;
339
      mNumCubits = numCubits(mMax);
340
      mCuts = getCuts(mSize);
341
      return true;
342
      }
343
    return false;
344
    }
345

    
346
///////////////////////////////////////////////////////////////////////////////////////////////////
347

    
348
  public int computeProjectionAngle()
349
    {
350
    return 60;
351
    }
352

    
353
///////////////////////////////////////////////////////////////////////////////////////////////////
354

    
355
  public boolean isInsideFace(int face, float[] p)
356
    {
357
    float angle = returnAngle(face);
358
    float A = (float)(Math.PI/5);
359

    
360
    for(int i=0; i<5; i++)
361
      {
362
      if( isOnTheLeft(p, mDist2D, (9-2*i)*A-angle) ) return false;
363
      }
364

    
365
    return true;
366
    }
367

    
368
///////////////////////////////////////////////////////////////////////////////////////////////////
369

    
370
  private int[] createLayers(int val)
371
    {
372
    int[] ret = new int[6];
373
    for(int i=0; i<6; i++) ret[i] = val;
374
    return ret;
375
    }
376

    
377
///////////////////////////////////////////////////////////////////////////////////////////////////
378

    
379
  public TwistyObject createObject(int mode, float size)
380
    {
381
    int param=-1;
382
    int[] numLayers = null;
383

    
384
    switch(mSize[0])
385
      {
386
      case 2: param = TwistyBandagedMegaminx.KILOMINX3; numLayers = createLayers(3); break;
387
      case 3: param = TwistyBandagedMegaminx.MEGAMINX3; numLayers = createLayers(3); break;
388
      case 4: param = TwistyBandagedMegaminx.KILOMINX5; numLayers = createLayers(5); break;
389
      case 5: param = TwistyBandagedMegaminx.MEGAMINX5; numLayers = createLayers(5); break;
390
      }
391

    
392
    float[][] pos = getCubitPositions();
393
    Metadata meta = new Metadata( null, numLayers,param,pos,0);
394
    return new TwistyBandagedMegaminx( mode, ShapeDodecahedron.DEFAULT_ROT, new Static3D(0,0,0), size, meta, null );
395
    }
396
}
(5-5/15)