redo with new anti-GLucose
[SugarCubes.git] / Model.pde
1 /**
2 * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
3 *
4 * //\\ //\\ //\\ //\\
5 * ///\\\ ///\\\ ///\\\ ///\\\
6 * \\\/// \\\/// \\\/// \\\///
7 * \\// \\// \\// \\//
8 *
9 * EXPERTS ONLY!! EXPERTS ONLY!!
10 *
11 * Contains the model definitions for the cube structures.
12 */
13
14 /**
15 * Top-level model of the entire sculpture. This contains a list of
16 * every cube on the sculpture, which forms a hierarchy of faces, strips
17 * and points.
18 */
19 public static class Model extends LXModel {
20
21 public final List<Tower> towers;
22 public final List<Cube> cubes;
23 public final List<Face> faces;
24 public final List<Strip> strips;
25
26 private final Cube[] _cubes;
27
28 public Model(List<Tower> towerList, Cube[] cubeArr) {
29 super(new Fixture(cubeArr));
30 Fixture fixture = (Fixture) this.fixtures.get(0);
31
32 _cubes = cubeArr;
33
34 // Make unmodifiable accessors to the model data
35 List<Cube> cubeList = new ArrayList<Cube>();
36 List<Face> faceList = new ArrayList<Face>();
37 List<Strip> stripList = new ArrayList<Strip>();
38 for (Cube cube : _cubes) {
39 if (cube != null) {
40 cubeList.add(cube);
41 for (Face face : cube.faces) {
42 faceList.add(face);
43 for (Strip strip : face.strips) {
44 stripList.add(strip);
45 }
46 }
47 }
48 }
49
50 this.towers = Collections.unmodifiableList(towerList);
51 this.cubes = Collections.unmodifiableList(cubeList);
52 this.faces = Collections.unmodifiableList(faceList);
53 this.strips = Collections.unmodifiableList(stripList);
54 }
55
56 private static class Fixture extends LXAbstractFixture {
57
58 private Fixture(Cube[] cubeArr) {
59 for (Cube cube : cubeArr) {
60 if (cube != null) {
61 for (LXPoint point : cube.points) {
62 this.points.add(point);
63 }
64 }
65 }
66 }
67 }
68
69 /**
70 * TODO(mcslee): figure out better solution
71 *
72 * @param index
73 * @return
74 */
75 public Cube getCubeByRawIndex(int index) {
76 return _cubes[index];
77 }
78 }
79
80 /**
81 * Model of a set of cubes stacked in a tower
82 */
83 public static class Tower extends LXModel {
84 /**
85 * Immutable list of cubes
86 */
87 public final List<Cube> cubes;
88
89 /**
90 * Immutable list of faces
91 */
92 public final List<Face> faces;
93
94 /**
95 * Immutable list of strips
96 */
97 public final List<Strip> strips;
98
99 /**
100 * Constructs a tower model from these cubes
101 *
102 * @param cubes Array of cubes
103 */
104 public Tower(List<Cube> cubes) {
105 super(cubes.toArray(new Cube[] {}));
106
107 List<Cube> cubeList = new ArrayList<Cube>();
108 List<Face> faceList = new ArrayList<Face>();
109 List<Strip> stripList = new ArrayList<Strip>();
110
111 for (Cube cube : cubes) {
112 cubeList.add(cube);
113 for (Face face : cube.faces) {
114 faceList.add(face);
115 for (Strip strip : face.strips) {
116 stripList.add(strip);
117 }
118 }
119 }
120 this.cubes = Collections.unmodifiableList(cubeList);
121 this.faces = Collections.unmodifiableList(faceList);
122 this.strips = Collections.unmodifiableList(stripList);
123 }
124 }
125
126 /**
127 * Model of a single cube, which has an orientation and position on the
128 * car. The position is specified in x,y,z coordinates with rotation. The
129 * x axis is left->right, y is bottom->top, and z is front->back.
130 *
131 * A cube's x,y,z position is specified as the left, bottom, front corner.
132 *
133 * Dimensions are all specified in real-world inches.
134 */
135 public static class Cube extends LXModel {
136
137 public final static int FACES_PER_CUBE = 4;
138 public static final int POINTS_PER_STRIP = 16;
139
140 public final static int STRIPS_PER_CUBE = FACES_PER_CUBE*Face.STRIPS_PER_FACE;
141 public final static int POINTS_PER_CUBE = STRIPS_PER_CUBE*POINTS_PER_STRIP;
142 public final static int POINTS_PER_FACE = Face.STRIPS_PER_FACE*POINTS_PER_STRIP;
143
144 public final static float EDGE_HEIGHT = 21.75f;
145 public final static float EDGE_WIDTH = 24.625f;
146 public final static float CHANNEL_WIDTH = 1.5f;
147
148 public final static Face.Metrics FACE_METRICS = new Face.Metrics(
149 new Strip.Metrics(EDGE_WIDTH, POINTS_PER_STRIP),
150 new Strip.Metrics(EDGE_HEIGHT, POINTS_PER_STRIP)
151 );
152
153 /**
154 * Immutable list of all cube faces
155 */
156 public final List<Face> faces;
157
158 /**
159 * Immutable list of all strips
160 */
161 public final List<Strip> strips;
162
163 /**
164 * Front left corner x coordinate
165 */
166 public final float x;
167
168 /**
169 * Front left corner y coordinate
170 */
171 public final float y;
172
173 /**
174 * Front left corner z coordinate
175 */
176 public final float z;
177
178 /**
179 * Rotation about the x-axis
180 */
181 public final float rx;
182
183 /**
184 * Rotation about the y-axis
185 */
186 public final float ry;
187
188 /**
189 * Rotation about the z-axis
190 */
191 public final float rz;
192
193 public Cube(double x, double y, double z, double rx, double ry, double rz) {
194 this((float) x, (float) y, (float) z, (float) rx, (float) ry, (float) rz);
195 }
196
197 public Cube(float x, float y, float z, float rx, float ry, float rz) {
198 super(new Fixture(x, y, z, rx, ry, rz));
199 Fixture fixture = (Fixture) this.fixtures.get(0);
200
201 while (rx < 0) rx += 360;
202 while (ry < 0) ry += 360;
203 while (rz < 0) rz += 360;
204 rx = rx % 360;
205 ry = ry % 360;
206 rz = rz % 360;
207
208 this.x = x;
209 this.y = y;
210 this.z = z;
211 this.rx = rx;
212 this.ry = ry;
213 this.rz = rz;
214
215 this.faces = Collections.unmodifiableList(fixture.faces);
216 this.strips = Collections.unmodifiableList(fixture.strips);
217 }
218
219 private static class Fixture extends LXAbstractFixture {
220
221 private final List<Face> faces = new ArrayList<Face>();
222 private final List<Strip> strips = new ArrayList<Strip>();
223
224 private Fixture(float x, float y, float z, float rx, float ry, float rz) {
225 LXTransform t = new LXTransform();
226 t.translate(x, y, z);
227 t.rotateX(rx * PI / 180.);
228 t.rotateY(ry * PI / 180.);
229 t.rotateZ(rz * PI / 180.);
230
231 for (int i = 0; i < FACES_PER_CUBE; i++) {
232 Face face = new Face(FACE_METRICS, (ry + 90*i) % 360, t);
233 this.faces.add(face);
234 for (Strip s : face.strips) {
235 this.strips.add(s);
236 }
237 for (LXPoint p : face.points) {
238 this.points.add(p);
239 }
240 t.translate(EDGE_WIDTH, 0, 0);
241 t.rotateY(HALF_PI);
242 }
243 }
244 }
245 }
246
247 /**
248 * A face is a component of a cube. It is comprised of four strips forming
249 * the lights on this side of a cube. A whole cube is formed by four faces.
250 */
251 public static class Face extends LXModel {
252
253 public final static int STRIPS_PER_FACE = 4;
254
255 public static class Metrics {
256 final Strip.Metrics horizontal;
257 final Strip.Metrics vertical;
258
259 public Metrics(Strip.Metrics horizontal, Strip.Metrics vertical) {
260 this.horizontal = horizontal;
261 this.vertical = vertical;
262 }
263 }
264
265 /**
266 * Immutable list of strips
267 */
268 public final List<Strip> strips;
269
270 /**
271 * Rotation of the face about the y-axis
272 */
273 public final float ry;
274
275 Face(Metrics metrics, float ry, LXTransform transform) {
276 super(new Fixture(metrics, ry, transform));
277 Fixture fixture = (Fixture) this.fixtures.get(0);
278 this.ry = ry;
279 this.strips = Collections.unmodifiableList(fixture.strips);
280 }
281
282 private static class Fixture extends LXAbstractFixture {
283
284 private final List<Strip> strips = new ArrayList<Strip>();
285
286 private Fixture(Metrics metrics, float ry, LXTransform transform) {
287 transform.push();
288 transform.translate(0, metrics.vertical.length, 0);
289 for (int i = 0; i < STRIPS_PER_FACE; i++) {
290 boolean isHorizontal = (i % 2 == 0);
291 Strip.Metrics stripMetrics = isHorizontal ? metrics.horizontal : metrics.vertical;
292 Strip strip = new Strip(stripMetrics, ry, transform, isHorizontal);
293 this.strips.add(strip);
294 transform.translate(isHorizontal ? metrics.horizontal.length : metrics.vertical.length, 0, 0);
295 transform.rotateZ(HALF_PI);
296 for (LXPoint p : strip.points) {
297 this.points.add(p);
298 }
299 }
300 transform.pop();
301 }
302 }
303 }
304
305 /**
306 * A strip is a linear run of points along a single edge of one cube.
307 */
308 public static class Strip extends LXModel {
309
310 public static final float POINT_SPACING = 18.625f / 15.f;
311
312 public static class Metrics {
313
314 public final float length;
315 public final int numPoints;
316
317 public Metrics(float length, int numPoints) {
318 this.length = length;
319 this.numPoints = numPoints;
320 }
321 }
322
323 public final Metrics metrics;
324
325 /**
326 * Whether this is a horizontal strip
327 */
328 public final boolean isHorizontal;
329
330 /**
331 * Rotation about the y axis
332 */
333 public final float ry;
334
335 public Object obj1 = null, obj2 = null;
336
337 Strip(Metrics metrics, float ry, List<LXPoint> points, boolean isHorizontal) {
338 super(points);
339 this.isHorizontal = isHorizontal;
340 this.metrics = metrics;
341 this.ry = ry;
342 }
343
344 Strip(Metrics metrics, float ry, LXTransform transform, boolean isHorizontal) {
345 super(new Fixture(metrics, ry, transform));
346 this.metrics = metrics;
347 this.isHorizontal = isHorizontal;
348 this.ry = ry;
349 }
350
351 private static class Fixture extends LXAbstractFixture {
352 private Fixture(Metrics metrics, float ry, LXTransform transform) {
353 float offset = (metrics.length - (metrics.numPoints - 1) * POINT_SPACING) / 2.f;
354 transform.push();
355 transform.translate(offset, -Cube.CHANNEL_WIDTH/2.f, 0);
356 for (int i = 0; i < metrics.numPoints; i++) {
357 LXPoint point = new LXPoint(transform.x(), transform.y(), transform.z());
358 this.points.add(point);
359 transform.translate(POINT_SPACING, 0, 0);
360 }
361 transform.pop();
362 }
363 }
364 }
365