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 }