001 /*
002 * $Id: Star2D.java 3239 2009-02-01 20:35:49Z rah003 $
003 *
004 * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy).
005 *
006 * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle,
007 * Santa Clara, California 95054, U.S.A. All rights reserved.
008 *
009 * Copyright (c) 2006 Romain Guy <romain.guy@mac.com>
010 * All rights reserved.
011 *
012 * Redistribution and use in source and binary forms, with or without
013 * modification, are permitted provided that the following conditions
014 * are met:
015 * 1. Redistributions of source code must retain the above copyright
016 * notice, this list of conditions and the following disclaimer.
017 * 2. Redistributions in binary form must reproduce the above copyright
018 * notice, this list of conditions and the following disclaimer in the
019 * documentation and/or other materials provided with the distribution.
020 * 3. The name of the author may not be used to endorse or promote products
021 * derived from this software without specific prior written permission.
022 *
023 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
024 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
025 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
026 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
028 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
029 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
030 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
032 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033 */
034
035 package org.jdesktop.swingx.geom;
036
037 import java.awt.Rectangle;
038 import java.awt.Shape;
039 import java.awt.geom.AffineTransform;
040 import java.awt.geom.GeneralPath;
041 import java.awt.geom.PathIterator;
042 import java.awt.geom.Point2D;
043 import java.awt.geom.Rectangle2D;
044
045 /**
046 * <p>This class provides a star shape. A star is defined by two radii and a
047 * number of branches. Each branch spans between the two radii. The inner
048 * radius is the distance between the center of the star and the origin of the
049 * branches. The outer radius is the distance between the center of the star
050 * and the tips of the branches.</p>
051 *
052 * @author Romain Guy <romain.guy@mac.com>
053 */
054
055 public class Star2D implements Shape {
056 private Shape starShape;
057 private double x;
058 private double y;
059 private double innerRadius;
060 private double outerRadius;
061 private int branchesCount;
062
063 /**
064 * <p>Creates a new star whose center is located at the specified
065 * <code>x</code> and <code>y</code> coordinates. The number of branches
066 * and their length can be specified.</p>
067 *
068 * @param x the location of the star center
069 * @param y the location of the star center
070 * @param innerRadius the distance between the center of the star and the
071 * origin of the branches
072 * @param outerRadius the distance between the center of the star and the
073 * tip of the branches
074 * @param branchesCount the number of branches in this star; must be >= 3
075 * @throws IllegalArgumentException if <code>branchesCount<code> is < 3 or
076 * if <code>innerRadius</code> is >= <code>outerRadius</code>
077 */
078 public Star2D(double x, double y,
079 double innerRadius, double outerRadius,
080 int branchesCount) {
081 if (branchesCount < 3) {
082 throw new IllegalArgumentException("The number of branches must" +
083 " be >= 3.");
084 } else if (innerRadius >= outerRadius) {
085 throw new IllegalArgumentException("The inner radius must be < " +
086 "outer radius.");
087 }
088
089 this.x = x;
090 this.y = y;
091 this.innerRadius = innerRadius;
092 this.outerRadius = outerRadius;
093 this.branchesCount = branchesCount;
094
095 starShape = generateStar(x, y, innerRadius, outerRadius, branchesCount);
096 }
097
098 private static Shape generateStar(double x, double y,
099 double innerRadius, double outerRadius,
100 int branchesCount) {
101 GeneralPath path = new GeneralPath();
102
103 double outerAngleIncrement = 2 * Math.PI / branchesCount;
104
105 double outerAngle = branchesCount % 2 == 0 ? 0.0 : -(Math.PI / 2.0);
106 double innerAngle = (outerAngleIncrement / 2.0) + outerAngle;
107
108 float x1 = (float) (Math.cos(outerAngle) * outerRadius + x);
109 float y1 = (float) (Math.sin(outerAngle) * outerRadius + y);
110
111 float x2 = (float) (Math.cos(innerAngle) * innerRadius + x);
112 float y2 = (float) (Math.sin(innerAngle) * innerRadius + y);
113
114 path.moveTo(x1, y1);
115 path.lineTo(x2, y2);
116
117 outerAngle += outerAngleIncrement;
118 innerAngle += outerAngleIncrement;
119
120 for (int i = 1; i < branchesCount; i++) {
121 x1 = (float) (Math.cos(outerAngle) * outerRadius + x);
122 y1 = (float) (Math.sin(outerAngle) * outerRadius + y);
123
124 path.lineTo(x1, y1);
125
126 x2 = (float) (Math.cos(innerAngle) * innerRadius + x);
127 y2 = (float) (Math.sin(innerAngle) * innerRadius + y);
128
129 path.lineTo(x2, y2);
130
131 outerAngle += outerAngleIncrement;
132 innerAngle += outerAngleIncrement;
133 }
134
135 path.closePath();
136 return path;
137 }
138
139 /**
140 * <p>Sets the inner radius of the star, that is the distance between its
141 * center and the origin of the branches. The inner radius must always be
142 * lower than the outer radius.</p>
143 *
144 * @param innerRadius the distance between the center of the star and the
145 * origin of the branches
146 * @throws IllegalArgumentException if the inner radius is >= outer radius
147 */
148 public void setInnerRadius(double innerRadius) {
149 if (innerRadius >= outerRadius) {
150 throw new IllegalArgumentException("The inner radius must be <" +
151 " outer radius.");
152 }
153
154 this.innerRadius = innerRadius;
155 starShape = generateStar(getX(), getY(), innerRadius, getOuterRadius(),
156 getBranchesCount());
157 }
158
159 /**
160 * <p>Sets location of the center of the star.</p>
161 *
162 * @param x the x location of the center of the star
163 */
164 public void setX(double x) {
165 this.x = x;
166 starShape = generateStar(x, getY(), getInnerRadius(), getOuterRadius(),
167 getBranchesCount());
168 }
169
170 /**
171 * <p>Sets the location of the center of the star.</p>
172 *
173 * @param y the x location of the center of the star
174 */
175 public void setY(double y) {
176 this.y = y;
177 starShape = generateStar(getX(), y, getInnerRadius(), getOuterRadius(),
178 getBranchesCount());
179 }
180
181 /**
182 * <p>Sets the outer radius of the star, that is the distance between its
183 * center and the tips of the branches. The outer radius must always be
184 * greater than the inner radius.</p>
185 *
186 * @param outerRadius the distance between the center of the star and the
187 * tips of the branches
188 * @throws IllegalArgumentException if the inner radius is >= outer radius
189 */
190 public void setOuterRadius(double outerRadius) {
191 if (innerRadius >= outerRadius) {
192 throw new IllegalArgumentException("The outer radius must be > " +
193 "inner radius.");
194 }
195
196 this.outerRadius = outerRadius;
197 starShape = generateStar(getX(), getY(), getInnerRadius(), outerRadius,
198 getBranchesCount());
199 }
200
201 /**
202 * <p>Sets the number branches of the star. A star must always have at least
203 * 3 branches.</p>
204 *
205 * @param branchesCount the number of branches
206 * @throws IllegalArgumentException if <code>branchesCount</code> is <=2
207 */
208 public void setBranchesCount(int branchesCount) {
209 if (branchesCount <= 2) {
210 throw new IllegalArgumentException("The number of branches must" +
211 " be >= 3.");
212 }
213
214 this.branchesCount = branchesCount;
215 starShape = generateStar(getX(), getY(), getInnerRadius(),
216 getOuterRadius(), branchesCount);
217 }
218
219 /**
220 * <p>Returns the location of the center of star.</p>
221 *
222 * @return the x coordinate of the center of the star
223 */
224 public double getX() {
225 return x;
226 }
227
228 /**
229 * <p>Returns the location of the center of star.</p>
230 *
231 * @return the y coordinate of the center of the star
232 */
233 public double getY() {
234 return y;
235 }
236
237 /**
238 * <p>Returns the distance between the center of the star and the origin
239 * of the branches.</p>
240 *
241 * @return the inner radius of the star
242 */
243 public double getInnerRadius() {
244 return innerRadius;
245 }
246
247 /**
248 * <p>Returns the distance between the center of the star and the tips
249 * of the branches.</p>
250 *
251 * @return the outer radius of the star
252 */
253 public double getOuterRadius() {
254 return outerRadius;
255 }
256
257 /**
258 * <p>Returns the number of branches of the star.</p>
259 *
260 * @return the number of branches, always >= 3
261 */
262 public int getBranchesCount() {
263 return branchesCount;
264 }
265
266 /**
267 * {@inheritDoc}
268 */
269 public Rectangle getBounds() {
270 return starShape.getBounds();
271 }
272
273 /**
274 * {@inheritDoc}
275 */
276 public Rectangle2D getBounds2D() {
277 return starShape.getBounds2D();
278 }
279
280 /**
281 * {@inheritDoc}
282 */
283 public boolean contains(double x, double y) {
284 return starShape.contains(x, y);
285 }
286
287 /**
288 * {@inheritDoc}
289 */
290 public boolean contains(Point2D p) {
291 return starShape.contains(p);
292 }
293
294 /**
295 * {@inheritDoc}
296 */
297 public boolean intersects(double x, double y, double w, double h) {
298 return starShape.intersects(x, y, w, h);
299 }
300
301 /**
302 * {@inheritDoc}
303 */
304 public boolean intersects(Rectangle2D r) {
305 return starShape.intersects(r);
306 }
307
308 /**
309 * {@inheritDoc}
310 */
311 public boolean contains(double x, double y, double w, double h) {
312 return starShape.contains(x, y, w, h);
313 }
314
315 /**
316 * {@inheritDoc}
317 */
318 public boolean contains(Rectangle2D r) {
319 return starShape.contains(r);
320 }
321
322 /**
323 * {@inheritDoc}
324 */
325 public PathIterator getPathIterator(AffineTransform at) {
326 return starShape.getPathIterator(at);
327 }
328
329 /**
330 * {@inheritDoc}
331 */
332 public PathIterator getPathIterator(AffineTransform at, double flatness) {
333 return starShape.getPathIterator(at, flatness);
334 }
335 }