Project

General

Profile

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

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

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.COS54;
14
import static org.distorted.objectlib.touchcontrol.TouchControlDodecahedron.SIN54;
15

    
16
import org.distorted.library.main.DistortedScreen;
17
import org.distorted.library.mesh.MeshBase;
18
import org.distorted.library.type.Static3D;
19
import org.distorted.objectlib.main.InitData;
20
import org.distorted.objectlib.main.TwistyObject;
21
import org.distorted.objectlib.shape.ShapeDodecahedron;
22
import org.distorted.objectlib.touchcontrol.TouchControlDodecahedron;
23

    
24
///////////////////////////////////////////////////////////////////////////////////////////////////
25

    
26
public class BandagedObjectMegaminx extends BandagedObject
27
{
28
  public static final float MEGA_D = 0.04f;
29

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

    
33
  private static final int NUM_CORNERS = 20;
34
  private static final int NUM_CENTERS = 12;
35
  private static final int NUM_EDGES   = 30;
36

    
37
///////////////////////////////////////////////////////////////////////////////////////////////////
38
// The pair (distance,angle) defines a point P in R^2 in polar coordinate system. Let V be the vector
39
// from the center of the coordinate system to P.
40
// Let P' be the point defined by polar (distance,angle+PI/2). Let Lh be the half-line starting at
41
// P' and going in the direction of V.
42
// Return true iff point 'point' lies on the left of Lh, i.e. when we rotate (using the center of
43
// the coordinate system as the center of rotation) 'point' and Lh in such a way that Lh points
44
// directly upwards, is 'point' on the left or the right of it?
45

    
46
  private boolean isOnTheLeft(float[] point, float distance, float angle)
47
    {
48
    float sin = (float)Math.sin(angle);
49
    float cos = (float)Math.cos(angle);
50

    
51
    float vx = point[0] + sin*distance;
52
    float vy = point[1] - cos*distance;
53

    
54
    return vx*sin < vy*cos;
55
    }
56

    
57
///////////////////////////////////////////////////////////////////////////////////////////////////
58
// return angle (in radians) that the line connecting the center C of the pentagonal face and the
59
// first vertex of the pentagon makes with a vertical line coming upwards from the center C.
60

    
61
  private float returnAngle(int face)
62
    {
63
    switch(face)
64
      {
65
      case  0:
66
      case  2:
67
      case  6:
68
      case  7: return 0.0f;
69
      case  1:
70
      case  3:
71
      case  4:
72
      case  5: return (float)(36*Math.PI/180);
73
      case  9:
74
      case 10: return (float)(54*Math.PI/180);
75
      case  8:
76
      case 11: return (float)(18*Math.PI/180);
77
      }
78

    
79
    return 0.0f;
80
    }
81

    
82
///////////////////////////////////////////////////////////////////////////////////////////////////
83
// i.e. one with a center - as opposed to 'kilominx'
84

    
85
  static boolean isMegaminx(int size)
86
    {
87
    return (size%2)==1;
88
    }
89

    
90
///////////////////////////////////////////////////////////////////////////////////////////////////
91

    
92
  static int numCubitsPerCornerMega(int numLayers)
93
    {
94
    return 3*((numLayers-1)/2)*((numLayers-3)/2) + 1;
95
    }
96

    
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

    
99
  static int numCubitsPerEdgeMega(int numLayers)
100
    {
101
    return numLayers-2;
102
    }
103

    
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

    
106
  static int numCubitsPerCornerKilo(int numLayers)
107
    {
108
    return 3*((numLayers-3)/2)*((numLayers-5)/2) + (numLayers<5 ? 0:1);
109
    }
110

    
111
///////////////////////////////////////////////////////////////////////////////////////////////////
112

    
113
  static int numCubitsPerEdgeKilo(int numLayers)
114
    {
115
    return numLayers<5 ? 0 : 2*(numLayers-4);
116
    }
117

    
118
///////////////////////////////////////////////////////////////////////////////////////////////////
119

    
120
  public static int numCubits(int size)
121
    {
122
    if( isMegaminx(size) )
123
      {
124
      int numCubitsPerCorner = numCubitsPerCornerMega(size);
125
      int numCubitsPerEdge   = numCubitsPerEdgeMega(size);
126
      return NUM_CORNERS*numCubitsPerCorner+NUM_EDGES*numCubitsPerEdge+NUM_CENTERS;
127
      }
128
    else
129
      {
130
      size++;
131

    
132
      if(size==3) return NUM_CORNERS;
133

    
134
      int numCubitsPerCorner = numCubitsPerCornerKilo(size);
135
      int numCubitsPerEdge   = numCubitsPerEdgeKilo(size);
136
      int numCubitsPerCenter = 5;
137
      return NUM_CORNERS*numCubitsPerCorner+NUM_EDGES*numCubitsPerEdge+NUM_CENTERS*numCubitsPerCenter;
138
      }
139
    }
140

    
141
///////////////////////////////////////////////////////////////////////////////////////////////////
142

    
143
  float[][][] getPositions()
144
    {
145
    FactoryBandagedMegaminx factory = FactoryBandagedMegaminx.getInstance();
146
    return factory.getPositions(mSize);
147
    }
148

    
149
///////////////////////////////////////////////////////////////////////////////////////////////////
150

    
151
  float getDist2D()
152
    {
153
    return (SIN54/COS54)/2;
154
    }
155

    
156
///////////////////////////////////////////////////////////////////////////////////////////////////
157

    
158
  int[] getColors()
159
    {
160
    return ShapeDodecahedron.FACE_COLORS;
161
    }
162

    
163
///////////////////////////////////////////////////////////////////////////////////////////////////
164

    
165
  boolean isAdjacent(float dx, float dy, float dz)
166
    {
167
    float len = dx*dx + dy*dy + dz*dz;
168
    float MAXERR = 0.01f;
169

    
170
    switch(mSize[0])
171
      {
172
      case 2: float x2_0 = 3.01f;
173
              return len<=x2_0*x2_0;
174

    
175
      case 3: float x3_0 = 1.51f*(SIN54/COS54);
176
              return len<=x3_0*x3_0;
177

    
178
      case 4: float x4_0 = 1.25f;
179
              float x4_1 = 2.50f;
180
              float x4_2 = 2.50f*(1+SIN18);
181
              float d4_0 = len-x4_0*x4_0;
182
              float d4_1 = len-x4_1*x4_1;
183
              float d4_2 = len-x4_2*x4_2;
184

    
185
              return ( (d4_0<MAXERR && d4_0>-MAXERR) ||
186
                       (d4_1<MAXERR && d4_1>-MAXERR) ||
187
                       (d4_2<MAXERR && d4_2>-MAXERR)  );
188

    
189
      case 5: float x5_0 = 2.5f*(0.5f-MEGA_D);
190
              float x5_1 = 2.5f*(0.5f+MEGA_D);
191
              float x5_2 = 2.5f*(0.5f-MEGA_D)*COS18;
192
              float x5_3 = x5_1 + 2.5f*(0.5f-MEGA_D)*SIN18;
193
              float x5_4 = 2.5f*SIN54 - x5_2;
194
              float d5_0 = len-x5_0*x5_0;
195
              float d5_1 = len-x5_1*x5_1;
196
              float d5_2 = len-x5_2*x5_2;
197
              float d5_3 = len-x5_3*x5_3;
198
              float d5_4 = len-x5_4*x5_4;
199

    
200
              return ( (d5_0<MAXERR && d5_0>-MAXERR) ||
201
                       (d5_1<MAXERR && d5_1>-MAXERR) ||
202
                       (d5_2<MAXERR && d5_2>-MAXERR) ||
203
                       (d5_3<MAXERR && d5_3>-MAXERR) ||
204
                       (d5_4<MAXERR && d5_4>-MAXERR)  );
205
      }
206

    
207
    return false;
208
    }
209

    
210
///////////////////////////////////////////////////////////////////////////////////////////////////
211

    
212
  MeshBase createMesh(float[] pos, boolean round)
213
    {
214
    FactoryBandagedMegaminx factory = FactoryBandagedMegaminx.getInstance();
215
    return factory.createMesh(pos,mSize,false,round);
216
    }
217

    
218
///////////////////////////////////////////////////////////////////////////////////////////////////
219
// PUBLIC API
220

    
221
  public BandagedObjectMegaminx(DistortedScreen screen)
222
    {
223
    super(screen,6);
224
    }
225

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

    
228
  public float getScreenRatio()
229
    {
230
    return 0.2f;
231
    }
232

    
233
///////////////////////////////////////////////////////////////////////////////////////////////////
234

    
235
  public float[] getDist3D()
236
    {
237
    float d = (float)Math.sqrt(0.625f+0.275f*SQ5);
238
    return new float[] {d,d,d,d,d,d,d,d,d,d,d,d};
239
    }
240

    
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

    
243
  public Static3D[] getFaceAxis()
244
    {
245
    return TouchControlDodecahedron.FACE_AXIS;
246
    }
247

    
248
///////////////////////////////////////////////////////////////////////////////////////////////////
249

    
250
  public boolean tryChangeObject(int x, int y, int z)
251
    {
252
    if( mSize[0]!=x )
253
      {
254
      mSize[0] = x;
255
      mSize[1] = x;
256
      mSize[2] = x;
257
      mSize[3] = x;
258

    
259
      mMax = x;
260
      mNumCubits = numCubits(x);
261
      return true;
262
      }
263

    
264
    return false;
265
    }
266

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

    
269
  public int computeProjectionAngle()
270
    {
271
    return 60;
272
    }
273

    
274
///////////////////////////////////////////////////////////////////////////////////////////////////
275

    
276
  public boolean isInsideFace(int face, float[] p)
277
    {
278
    float angle = returnAngle(face);
279
    float A = (float)(Math.PI/5);
280

    
281
    for(int i=0; i<5; i++)
282
      {
283
      if( isOnTheLeft(p, mDist2D, (9-2*i)*A-angle) ) return false;
284
      }
285

    
286
    return true;
287
    }
288

    
289
///////////////////////////////////////////////////////////////////////////////////////////////////
290

    
291
  public TwistyObject createObject(int mode, float size)
292
    {
293
    float[][] pos = getCubitPositions();
294
    InitData data = new InitData( mSize,pos);
295
    return null;//new TwistyBandagedMegaminx( TwistyObject.MESH_NICE, mode, ShapeDodecahedron.DEFAULT_ROT, new Static3D(0,0,0), size, data, null );
296
    }
297
}
(5-5/11)