001/* 002 * $Id: Star2D.java 3863 2010-10-26 02:53:32Z kschaefe $ 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 035package org.jdesktop.swingx.geom; 036 037import java.awt.Rectangle; 038import java.awt.Shape; 039import java.awt.geom.AffineTransform; 040import java.awt.geom.GeneralPath; 041import java.awt.geom.PathIterator; 042import java.awt.geom.Point2D; 043import 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 055public 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 @Override 270 public Rectangle getBounds() { 271 return starShape.getBounds(); 272 } 273 274 /** 275 * {@inheritDoc} 276 */ 277 @Override 278 public Rectangle2D getBounds2D() { 279 return starShape.getBounds2D(); 280 } 281 282 /** 283 * {@inheritDoc} 284 */ 285 @Override 286 public boolean contains(double x, double y) { 287 return starShape.contains(x, y); 288 } 289 290 /** 291 * {@inheritDoc} 292 */ 293 @Override 294 public boolean contains(Point2D p) { 295 return starShape.contains(p); 296 } 297 298 /** 299 * {@inheritDoc} 300 */ 301 @Override 302 public boolean intersects(double x, double y, double w, double h) { 303 return starShape.intersects(x, y, w, h); 304 } 305 306 /** 307 * {@inheritDoc} 308 */ 309 @Override 310 public boolean intersects(Rectangle2D r) { 311 return starShape.intersects(r); 312 } 313 314 /** 315 * {@inheritDoc} 316 */ 317 @Override 318 public boolean contains(double x, double y, double w, double h) { 319 return starShape.contains(x, y, w, h); 320 } 321 322 /** 323 * {@inheritDoc} 324 */ 325 @Override 326 public boolean contains(Rectangle2D r) { 327 return starShape.contains(r); 328 } 329 330 /** 331 * {@inheritDoc} 332 */ 333 @Override 334 public PathIterator getPathIterator(AffineTransform at) { 335 return starShape.getPathIterator(at); 336 } 337 338 /** 339 * {@inheritDoc} 340 */ 341 @Override 342 public PathIterator getPathIterator(AffineTransform at, double flatness) { 343 return starShape.getPathIterator(at, flatness); 344 } 345}