001    package physics3d;
002    
003    
004    import java.util.ArrayList;
005    import java.util.Collections;
006    import java.util.List;
007    
008    /**
009     * Shape is a immutable class that describes the bounding area, and 3d shape of a GameObject
010     *
011     *@specfield bound : PhysicsShape               // the bounds of the shape, centered at the origin
012     *@specified parts : set                                // the parts that make up the Shape, centered at the origin
013     */
014    
015    /*
016     * Abstraction Function
017     * AF(r) = a Shape, s, such that
018     * s.bound = r. bound
019     * s.parts = r.parts
020     */
021    
022    /*
023     * Rep Invariant
024     * bound, parts != null
025     * bound bounds parts
026     */
027    
028    public class Shape {
029            //fields
030            private final PhysicsShape bound;
031            private final List<PhysicsShape> parts;
032            
033            //static shapes
034            private static Shape ball;
035            private static Shape cirBumper;
036            private static Shape squBumper;
037            private static Shape triBumper;
038            private static Shape flipper;
039            
040            //constructors
041            private Shape(PhysicsShape bound, PhysicsShape part) {
042                    this.bound = bound;
043                    parts = new ArrayList<PhysicsShape>();
044                    parts.add(part);
045                    //checkRep();
046            }
047            
048            private Shape(PhysicsShape bound, List<PhysicsShape> parts) {
049                    this.bound = bound;
050                    this.parts = parts;
051                    //checkRep();
052            }
053            
054            //factory methods
055            /**
056             * @return the standard Ball's shape 
057             */
058            public static Shape getBallShape() {
059                    if (ball == null) {
060                            PhysicsShape boundSphere = new Sphere(Vect3.ZERO, 0.25);
061                            PhysicsShape sphere = new Sphere(Vect3.ZERO, 0.25);
062                            ball = new Shape(boundSphere, sphere);
063                    }
064                    return ball;
065            }
066            
067            /**
068             * @return the standard SquareBumper's shape  
069             */
070            public static Shape getSqBumperShape() {
071                    if (squBumper == null) {
072                            Double s = 0.5;
073                            
074                            //bounding sphere
075                            PhysicsShape boundSphere = new Sphere(Vect3.ZERO, Math.sqrt(3) * s);
076                            
077                            //parts
078                            //vertices of cube
079                            Vect3 a = new Vect3(-s, -s, -s);
080                            Vect3 b = new Vect3(s, -s, -s);
081                            Vect3 c = new Vect3(s, -s, s);
082                            Vect3 d = new Vect3(-s, -s, s);
083                            Vect3 e = new Vect3(-s, s, -s);
084                            Vect3 f = new Vect3(-s, s, s);
085                            Vect3 g = new Vect3(s, s, s);
086                            Vect3 h = new Vect3(s, s, -s);
087                            
088                            //points at the vertices
089                            PhysicsShape pa = new Sphere(a, 0);
090                            PhysicsShape pb = new Sphere(b, 0);
091                            PhysicsShape pc = new Sphere(c, 0);
092                            PhysicsShape pd = new Sphere(d, 0);
093                            PhysicsShape pe = new Sphere(e, 0);
094                            PhysicsShape pf = new Sphere(f, 0);
095                            PhysicsShape pg = new Sphere(g, 0);
096                            PhysicsShape ph = new Sphere(h, 0);
097                            
098                            //edges
099                            PhysicsShape e1 = new LateralCylinder(0, a, b);
100                            PhysicsShape e2 = new LateralCylinder(0, b, c);
101                            PhysicsShape e3 = new LateralCylinder(0, c, d);
102                            PhysicsShape e4 = new LateralCylinder(0, d, a);
103                            
104                            PhysicsShape e5 = new LateralCylinder(0, e, f);
105                            PhysicsShape e6 = new LateralCylinder(0, f, g);
106                            PhysicsShape e7 = new LateralCylinder(0, g, h);
107                            PhysicsShape e8 = new LateralCylinder(0, h, e);
108                            
109                            PhysicsShape e9 = new LateralCylinder(0, a, e);
110                            PhysicsShape e10 = new LateralCylinder(0, b, h);
111                            PhysicsShape e11 = new LateralCylinder(0, c, g);
112                            PhysicsShape e12 = new LateralCylinder(0, d, f);
113                            
114                            //faces of cube
115                            //top faces
116                            PhysicsShape top = new PlanePolygon(makeList(a, b, c, d));
117                            
118                            //bottom faces
119                            PhysicsShape bottom = new PlanePolygon(makeList(e, f, g, h));
120                            
121                            //front faces
122                            PhysicsShape front = new PlanePolygon(makeList(a, e, h, b));
123                            
124                            //back faces
125                            PhysicsShape back = new PlanePolygon(makeList(d, c, g, f));
126                            
127                            //left faces
128                            PhysicsShape left = new PlanePolygon(makeList(a, d, f, e));
129                            
130                            //right faces
131                            PhysicsShape right = new PlanePolygon(makeList(c, b, h, g));
132                            
133                            //put parts in list
134                            List<PhysicsShape> partsList = new ArrayList<PhysicsShape>();
135                            
136                            //vertices
137                            partsList.add(pa);
138                            partsList.add(pb);
139                            partsList.add(pc);
140                            partsList.add(pd);
141                            partsList.add(pe);
142                            partsList.add(pf);
143                            partsList.add(pg);
144                            partsList.add(ph);
145                            
146                            //edges
147                            partsList.add(e1);
148                            partsList.add(e2);
149                            partsList.add(e3);
150                            partsList.add(e4);
151                            partsList.add(e5);
152                            partsList.add(e6);
153                            partsList.add(e7);
154                            partsList.add(e8);
155                            partsList.add(e9);
156                            partsList.add(e10);
157                            partsList.add(e11);
158                            partsList.add(e12);
159                            
160                            //faces
161                            partsList.add(top);
162                            partsList.add(bottom);
163                            partsList.add(front);
164                            partsList.add(back);
165                            partsList.add(left);
166                            partsList.add(right);
167                            
168                            //creates the Shape
169                            squBumper = new Shape(boundSphere, partsList);
170                    }
171                    return squBumper;
172            }
173            
174            /**
175             * @return the standard TriangleBumper's shape
176             */
177            public static Shape getTriBumperShape() {
178                    if (triBumper == null) {
179                            Double s = 0.5;
180    
181                            //bounding sphere
182                            PhysicsShape boundSphere = new Sphere(Vect3.ZERO, Math.sqrt(3) * s);
183    
184                            //parts
185                            //vertices
186                            Vect3 a = new Vect3(-s, -s, -s);
187                            Vect3 b = new Vect3(s, -s, -s);
188                            Vect3 c = new Vect3(s, -s, s);
189                            Vect3 d = new Vect3(-s, -s, s);
190                            Vect3 e = new Vect3(-s, s, -s);
191                            Vect3 f = new Vect3(-s, s, s);
192                            
193                            //corner points
194                            PhysicsShape pa = new Sphere(a, 0);
195                            PhysicsShape pb = new Sphere(b, 0);
196                            PhysicsShape pc = new Sphere(c, 0);
197                            PhysicsShape pd = new Sphere(d, 0);
198                            PhysicsShape pe = new Sphere(e, 0);
199                            PhysicsShape pf = new Sphere(f, 0);
200                            
201                            //edges
202                            PhysicsShape e1 = new LateralCylinder(0, a, b);
203                            PhysicsShape e2 = new LateralCylinder(0, b, c);
204                            PhysicsShape e3 = new LateralCylinder(0, c, d);
205                            PhysicsShape e4 = new LateralCylinder(0, d, a);
206                            
207                            PhysicsShape e5 = new LateralCylinder(0, e, b);
208                            PhysicsShape e6 = new LateralCylinder(0, c, f);
209                            
210                            PhysicsShape e7 = new LateralCylinder(0, a, e);
211                            PhysicsShape e8 = new LateralCylinder(0, d, f);
212                            PhysicsShape e9 = new LateralCylinder(0, e, f);
213                            
214                            //faces
215                            //front and back triangles
216                            PhysicsShape front = new PlanePolygon(makeList(a, e, b));
217                            PhysicsShape back = new PlanePolygon(makeList(f, c, d));
218                            
219                            //bottom quad
220                            PhysicsShape top = new PlanePolygon(makeList(a, b, c, d));
221                            
222                            //side quad
223                            PhysicsShape side = new PlanePolygon(makeList(e, a, d, f));
224                            
225                            //slanted quad
226                            PhysicsShape bottom = new PlanePolygon(makeList(e, f, c, b));
227                            
228                            //put parts in list
229                            List<PhysicsShape> partsList =  new ArrayList<PhysicsShape>();
230                            
231                            //adding vertices
232                            partsList.add(pa);
233                            partsList.add(pb);
234                            partsList.add(pc);
235                            partsList.add(pd);
236                            partsList.add(pe);
237                            partsList.add(pf);
238                            
239                            //adding edges
240                            partsList.add(e1);
241                            partsList.add(e2);
242                            partsList.add(e3);
243                            partsList.add(e4);
244                            partsList.add(e5);
245                            partsList.add(e6);
246                            partsList.add(e7);
247                            partsList.add(e8);
248                            partsList.add(e9);
249                            
250                            //adding faces
251                            partsList.add(front);
252                            partsList.add(back);
253                            partsList.add(bottom);
254                            partsList.add(side);
255                            partsList.add(top);
256                            
257                            //creates the Shape
258                            triBumper = new Shape(boundSphere, partsList);
259                    }
260                    return triBumper;
261            }
262            
263            /**
264             * @return the CircleBumper's standard shape
265             */
266            public static Shape getCirBumperShape() {
267                    if (cirBumper == null) {
268                            Double s = 0.5;
269    
270                            //bounding sphere
271                            PhysicsShape boundSphere = new Sphere(Vect3.ZERO, Math.sqrt(3) * s);
272    
273                            //parts
274                            //front circle
275                            Vect3 fv = new Vect3(0, 0, -s);
276                            PhysicsShape frontCircle = new PlaneCircle(fv, Vect3.Z_HAT.neg(), s);
277                            //back circle
278                            Vect3 bv = new Vect3(0, 0, s);
279                            PhysicsShape backCircle = new PlaneCircle(bv, Vect3.Z_HAT, s);
280                            //cylinder
281                            PhysicsShape cylinder = new LateralCylinder(s, bv, fv);
282                            
283                            //toruses
284                            PhysicsShape frontTorus = new Torus(fv, Vect3.Z_HAT, s, 0);
285                            PhysicsShape backTorus = new Torus(bv, Vect3.Z_HAT.neg(), s, 0);
286                            
287                            //put parts in list
288                            List<PhysicsShape> partsList = new ArrayList<PhysicsShape>();
289                            partsList.add(frontCircle);
290                            partsList.add(backCircle);
291                            partsList.add(cylinder);
292                            partsList.add(frontTorus);
293                            partsList.add(backTorus);
294                            
295                            //creates the Shape
296                            cirBumper = new Shape(boundSphere, partsList);
297                    }
298                    return cirBumper;
299            }
300            
301            /**
302             * @return the Shape of an Absorber
303             */
304            public static Shape getAbsorberShape(int height, int width, int depth) {
305                    double w2 = width/2.0;
306                    double h2 = height/2.0;
307                    double d2 = depth/2.0;
308                    
309                    //bounding sphere
310                    PhysicsShape boundSphere = new Sphere(Vect3.ZERO, Math.sqrt(w2*w2 + h2*h2 + d2*d2));
311                    
312                    Vect3 a = new Vect3(-w2, -h2, -d2);
313                    Vect3 b = new Vect3(w2, -h2, -d2);
314                    Vect3 c = new Vect3(w2, -h2, d2);
315                    Vect3 d = new Vect3(-w2, -h2, d2);
316                    Vect3 e = new Vect3(-w2, h2, -d2);
317                    Vect3 f = new Vect3(-w2, h2, d2);
318                    Vect3 g = new Vect3(w2, h2, d2);
319                    Vect3 h = new Vect3(w2, h2, -d2);
320                    
321                    //points at the vertices
322                    PhysicsShape pa = new Sphere(a, 0);
323                    PhysicsShape pb = new Sphere(b, 0);
324                    PhysicsShape pc = new Sphere(c, 0);
325                    PhysicsShape pd = new Sphere(d, 0);
326                    PhysicsShape pe = new Sphere(e, 0);
327                    PhysicsShape pf = new Sphere(f, 0);
328                    PhysicsShape pg = new Sphere(g, 0);
329                    PhysicsShape ph = new Sphere(h, 0);
330                    
331                    //edges
332                    PhysicsShape e1 = new LateralCylinder(0, a, b);
333                    PhysicsShape e2 = new LateralCylinder(0, b, c);
334                    PhysicsShape e3 = new LateralCylinder(0, c, d);
335                    PhysicsShape e4 = new LateralCylinder(0, d, a);
336                    
337                    PhysicsShape e5 = new LateralCylinder(0, e, f);
338                    PhysicsShape e6 = new LateralCylinder(0, f, g);
339                    PhysicsShape e7 = new LateralCylinder(0, g, h);
340                    PhysicsShape e8 = new LateralCylinder(0, h, e);
341                    
342                    PhysicsShape e9 = new LateralCylinder(0, a, e);
343                    PhysicsShape e10 = new LateralCylinder(0, b, h);
344                    PhysicsShape e11 = new LateralCylinder(0, c, g);
345                    PhysicsShape e12 = new LateralCylinder(0, d, f);
346                    
347            //faces of cube
348                    //top faces
349                    PhysicsShape top = new PlanePolygon(makeList(a, b, c, d));
350                    
351                    //bottom faces
352                    PhysicsShape bottom = new PlanePolygon(makeList(e, f, g, h));
353                    
354                    //front faces
355                    PhysicsShape front = new PlanePolygon(makeList(a, e, h, b));
356                    
357                    //back faces
358                    PhysicsShape back = new PlanePolygon(makeList(d, c, g, f));
359                    
360                    //left faces
361                    PhysicsShape left = new PlanePolygon(makeList(a, d, f, e));
362                    
363                    //right faces
364                    PhysicsShape right = new PlanePolygon(makeList(c, b, h, g));
365                    
366                    //put parts in list
367                    List<PhysicsShape> partsList = new ArrayList<PhysicsShape>();
368                    //adding vertices
369                    partsList.add(pa);
370                    partsList.add(pb);
371                    partsList.add(pc);
372                    partsList.add(pd);
373                    partsList.add(pe);
374                    partsList.add(pf);
375                    partsList.add(pg);
376                    partsList.add(ph);
377                    
378                    //adding edges
379                    partsList.add(e1);
380                    partsList.add(e2);
381                    partsList.add(e3);
382                    partsList.add(e4);
383                    partsList.add(e5);
384                    partsList.add(e6);
385                    partsList.add(e7);
386                    partsList.add(e8);
387                    partsList.add(e9);
388                    partsList.add(e10);
389                    partsList.add(e11);
390                    partsList.add(e12);
391                    
392                    //adding faces
393                    partsList.add(top);
394                    partsList.add(bottom);
395                    partsList.add(front);
396                    partsList.add(back);
397                    partsList.add(left);
398                    partsList.add(right);
399                    
400                    return new Shape(boundSphere, partsList);
401            }
402            
403            
404            
405            /**
406             * @return the Shape of a Flipper
407             */
408            public static Shape getFlipperShape() {
409                    if (flipper == null) {
410                            //radius of corner spheres 
411                            double r = GameConstants.FLIPPER_RADIUS_FRACTION;
412                            double l = .5;
413                                    
414                            //bounding sphere... oversized for now. 
415                            PhysicsShape boundSphere = new Sphere(Vect3.ZERO, l * 3);
416                            
417                            //parts
418                            //four "corner" vertices
419                            Vect3 a = new Vect3(0, 0, 1-.5);
420                            Vect3 b = new Vect3(0, 0, .5-1);
421                            Vect3 c = new Vect3(0, 2 * (1-r), 1-.5);
422                            Vect3 d = new Vect3(0, 2 * (1-r), .5-1);
423                            
424                            PhysicsShape topCyl = new LateralCylinder(r, a, b);
425                            PhysicsShape botCyl = new LateralCylinder(r, c, d);
426                            
427                            PhysicsShape aCir = new PlaneCircle(a, Vect3.Z_HAT, r); 
428                            PhysicsShape bCir = new PlaneCircle(b, Vect3.Z_HAT.neg(), r);
429                            PhysicsShape cCir = new PlaneCircle(c, Vect3.Z_HAT, r); 
430                            PhysicsShape dCir = new PlaneCircle(d, Vect3.Z_HAT.neg(), r);
431                            
432                            //side planes
433                            //vertices
434                            Vect3 ap1 = new Vect3(r, a.y(), a.z());
435                            Vect3 bp1 = new Vect3(r, b.y(), b.z());
436                            Vect3 cp1 = new Vect3(r, c.y(), c.z());
437                            Vect3 dp1 = new Vect3(r, d.y(), d.z());
438                            
439                            PhysicsShape plane1 = new PlanePolygon(makeList(ap1, bp1, dp1, cp1));
440                            
441                            Vect3 ap2 = new Vect3(-r, a.y(), a.z());
442                            Vect3 bp2 = new Vect3(-r, b.y(), b.z());
443                            Vect3 cp2 = new Vect3(-r, c.y(), c.z());
444                            Vect3 dp2 = new Vect3(-r, d.y(), d.z());
445                            
446                            PhysicsShape plane2 = new PlanePolygon(makeList(ap2, cp2, dp2, bp2));
447                            
448                            //front plane
449                            PhysicsShape plane3 = new PlanePolygon(makeList(ap1, ap2, cp2, cp1));
450                            PhysicsShape plane4 = new PlanePolygon(makeList(bp1, bp2, dp2, dp1));
451                            
452                            List<PhysicsShape> partsList = new ArrayList<PhysicsShape>();
453                            partsList.add(aCir);
454                            partsList.add(bCir);
455                            partsList.add(cCir);
456                            partsList.add(dCir);
457                            
458                            partsList.add(topCyl);
459                            partsList.add(botCyl); 
460                            
461                            partsList.add(plane1);
462                            partsList.add(plane2);
463                            partsList.add(plane3);
464                            partsList.add(plane4); 
465                            
466    /*                      
467                            //four spheres
468                            PhysicsShape s1 = new Sphere(a, r);
469                            PhysicsShape s2 = new Sphere(b, r);
470                            PhysicsShape s3 = new Sphere(c, r);
471                            PhysicsShape s4 = new Sphere(d, r);
472                            
473                            //4 cylinders
474                            PhysicsShape aCyl = new LateralCylinder(r, a, b);
475                            PhysicsShape bCyl = new LateralCylinder(r, b, d);
476                            PhysicsShape cCyl = new LateralCylinder(r, d, c);
477                            PhysicsShape dCyl = new LateralCylinder(r, c, a);
478                            
479                            //side planes
480                            //vertices
481                            Vect3 ap1 = new Vect3(r, a.y(), a.z());
482                            Vect3 bp1 = new Vect3(r, b.y(), b.z());
483                            Vect3 cp1 = new Vect3(r, c.y(), c.z());
484                            Vect3 dp1 = new Vect3(r, d.y(), d.z());
485                            
486                            PhysicsShape plane1 = new PlanePolygon(makeList(ap1, bp1, cp1, dp1));
487                            
488                            Vect3 ap2 = new Vect3(-r, a.y(), a.z());
489                            Vect3 bp2 = new Vect3(-r, b.y(), b.z());
490                            Vect3 cp2 = new Vect3(-r, c.y(), c.z());
491                            Vect3 dp2 = new Vect3(-r, d.y(), d.z());
492                            
493                            PhysicsShape plane2 = new PlanePolygon(makeList(cp2, ap2, bp2, dp2));
494            */              
495                            //put parts in List
496            //              List<PhysicsShape> partsList = new ArrayList<PhysicsShape>();
497    /*                      partsList.add(s1);
498                            partsList.add(s2);
499                            partsList.add(s3);
500                            partsList.add(s4); 
501                            partsList.add(aCyl);
502                            partsList.add(bCyl);
503                            partsList.add(cCyl);
504                            partsList.add(dCyl); 
505                            partsList.add(plane1);
506                            partsList.add(plane2); 
507            */
508                            
509                            flipper = new Shape(boundSphere, partsList);
510                    }
511                    return flipper;
512            }
513            
514            /**
515             * @return the Shape for a wall given length and width
516             */
517            public static Shape getWallShape(int length, int width) {               
518                    // corners
519                    Vect3 a = new Vect3(-width/2.0, -length/2.0, 0);
520                    Vect3 b = new Vect3(width/2.0, -length/2.0, 0);
521                    Vect3 c = new Vect3(width/2.0, length/2.0, 0);
522                    Vect3 d = new Vect3(-width/2.0, length/2.0, 0);
523                    
524                    
525                    //planes
526                    PhysicsShape plane1 = new PlanePolygon(makeList(a, b, c, d));
527                    
528                    
529                    //parts list
530                    List<PhysicsShape> partsList = new ArrayList<PhysicsShape>();
531                    partsList.add(plane1);
532                    
533                    return new Shape(plane1, plane1);
534            }
535            
536            //helper method that takes three Vect3s and puts them into a List
537            private static List<Vect3> makeList(Vect3 v1, Vect3 v2, Vect3 v3) {
538                    List<Vect3> vList = new ArrayList<Vect3>();
539                    vList.add(v1);
540                    vList.add(v2);
541                    vList.add(v3);
542                    return Collections.unmodifiableList(vList);
543            }
544            
545            private static List<Vect3> makeList(Vect3 v1, Vect3 v2, Vect3 v3, Vect3 v4) {
546                    List<Vect3> vList = new ArrayList<Vect3>();
547                    vList.add(v1);
548                    vList.add(v2);
549                    vList.add(v3);
550                    vList.add(v4);
551                    return Collections.unmodifiableList(vList);
552            }
553            
554            /**
555             * @return the bound of this object
556             */
557            public PhysicsShape getBound() {
558                    return this.bound;
559            }
560            
561            /**
562             * @returns the parts of this object
563             */
564            public List<PhysicsShape> getParts() {
565                    return Collections.unmodifiableList(parts);
566            }
567            
568            private void checkRep() {}
569    }