View Javadoc
1   package org.newdawn.slick.geom;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.newdawn.slick.util.FastTrig;
7   
8   import javax.annotation.Nonnull;
9   
10  /**
11   * An ellipse meeting the <code>Shape</code> contract. The ellipse is actually an approximation using 
12   * a series of points generated around the contour of the ellipse.
13   * 
14   * @author Mark
15   */
16  public class Ellipse extends Shape {
17      /**
18       * 
19       */
20      private static final long serialVersionUID = 1L;
21  
22      /**
23       * Default number of segments to draw this ellipse with
24       */
25      static final int DEFAULT_SEGMENT_COUNT = 50;
26      
27      /**
28       * The number of segments for graphical representation.
29       */
30      private final int segmentCount;
31      /**
32       * horizontal radius
33       */
34      private float radius1;
35      /**
36       * vertical radius
37       */
38      private float radius2;
39  
40      /**
41       * Creates a new Ellipse object.
42       *
43       * @param centerPointX x coordinate of the center of the ellipse
44       * @param centerPointY y coordinate of the center of the ellipse
45       * @param radius1 horizontal radius
46       * @param radius2 vertical radius
47       */
48      public Ellipse(float centerPointX, float centerPointY, float radius1, float radius2) {
49          this(centerPointX, centerPointY, radius1, radius2, DEFAULT_SEGMENT_COUNT);
50      }
51  
52      /**
53       * Creates a new Ellipse object.
54       *
55       * @param centerPointX x coordinate of the center of the ellipse
56       * @param centerPointY y coordinate of the center of the ellipse
57       * @param radius1 horizontal radius
58       * @param radius2 vertical radius
59       * @param segmentCount how fine to make the ellipse.
60       */
61      Ellipse(float centerPointX, float centerPointY, float radius1, float radius2, int segmentCount) {
62          this.x = centerPointX - radius1;
63          this.y = centerPointY - radius2;
64          this.radius1 = radius1;
65          this.radius2 = radius2;
66          this.segmentCount = segmentCount;
67          checkPoints();
68      }
69  
70      /**
71       * Change the shape of this Ellipse
72       * 
73       * @param radius1 horizontal radius
74       * @param radius2 vertical radius
75       */
76      void setRadii(float radius1, float radius2) {
77          setRadius1(radius1);
78          setRadius2(radius2);
79      }
80  
81      /**
82       * Get the horizontal radius of the ellipse
83       * 
84       * @return The horizontal radius of the ellipse
85       */
86      public float getRadius1() {
87          return radius1;
88      }
89  
90      /**
91       * Set the horizontal radius of the ellipse
92       * 
93       * @param radius1 The horizontal radius to set
94       */
95      void setRadius1(float radius1) {
96          if (radius1 != this.radius1) {
97              this.radius1 = radius1;
98              pointsDirty = true;
99          }
100     }
101 
102     /**
103      * Get the vertical radius of the ellipse
104      * 
105      * @return The vertical radius of the ellipse
106      */
107     public float getRadius2() {
108         return radius2;
109     }
110 
111     /**
112      * Set the vertical radius of the ellipse
113      * 
114      * @param radius2 The vertical radius to set
115      */
116     void setRadius2(float radius2) {
117         if (radius2 != this.radius2) {
118             this.radius2 = radius2;
119             pointsDirty = true;
120         }
121     }
122 
123     /**
124      * Generate the points to outline this ellipse.
125      *
126      */
127     protected void createPoints() {
128         final List<Float> tempPoints = new ArrayList<>();
129 
130         maxX = -Float.MIN_VALUE;
131         maxY = -Float.MIN_VALUE;
132         minX = Float.MAX_VALUE;
133         minY = Float.MAX_VALUE;
134 
135         float start = 0;
136         float end = 359;
137         
138         float cx = x + radius1;
139         float cy = y + radius2;
140         
141         int step = 360 / segmentCount;
142         
143         for (float a=start;a<=end+step;a+=step) {
144             float ang = a;
145             if (ang > end) {
146                 ang = end;
147             }
148             float newX = (float) (cx + (FastTrig.cos(Math.toRadians(ang)) * radius1));
149             float newY = (float) (cy + (FastTrig.sin(Math.toRadians(ang)) * radius2));
150 
151             if(newX > maxX) {
152                 maxX = newX;
153             }
154             if(newY > maxY) {
155                 maxY = newY;
156             }
157             if(newX < minX) {
158                 minX = newX;
159             }
160             if(newY < minY) {
161                 minY = newY;
162             }
163             
164             tempPoints.add(newX);
165             tempPoints.add(newY);
166         }
167         points = new float[tempPoints.size()];
168         for(int i=0;i<points.length;i++) {
169             points[i] = tempPoints.get(i);
170         }
171     }
172 
173     /**
174      * @see org.newdawn.slick.geom.Shape#transform(org.newdawn.slick.geom.Transform)
175      */
176     @Nonnull
177     public Shape transform(@Nonnull Transform transform) {
178         checkPoints();
179         
180         Polygon resultPolygon = new Polygon();
181         
182         float result[] = new float[points.length];
183         transform.transform(points, 0, result, 0, points.length / 2);
184         resultPolygon.points = result;
185         resultPolygon.checkPoints();
186 
187         return resultPolygon;
188     }
189 
190     /**
191      * @see org.newdawn.slick.geom.Shape#findCenter()
192      */
193     protected void findCenter() {
194         center = new float[2];
195         center[0] = x + radius1;
196         center[1] = y + radius2;
197     }
198 
199     /**
200      * @see org.newdawn.slick.geom.Shape#calculateRadius()
201      */
202     protected void calculateRadius() {
203         boundingCircleRadius = (radius1 > radius2) ? radius1 : radius2;
204     }
205 }