/* * $Id$ * * Dual-licensed under LGPL (Sun and Romain Guy) and BSD (Romain Guy). * * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * Copyright (c) 2006 Romain Guy <romain.guy@mac.com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.jdesktop.swingx.geom; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; /** * <p>This class provides a star shape. A star is defined by two radii and a * number of branches. Each branch spans between the two radii. The inner * radius is the distance between the center of the star and the origin of the * branches. The outer radius is the distance between the center of the star * and the tips of the branches.</p> * * @author Romain Guy <romain.guy@mac.com> */ public class Star2D implements Shape { private Shape starShape; private double x; private double y; private double innerRadius; private double outerRadius; private int branchesCount; /** * <p>Creates a new star whose center is located at the specified * <code>x</code> and <code>y</code> coordinates. The number of branches * and their length can be specified.</p> * * @param x the location of the star center * @param y the location of the star center * @param innerRadius the distance between the center of the star and the * origin of the branches * @param outerRadius the distance between the center of the star and the * tip of the branches * @param branchesCount the number of branches in this star; must be >= 3 * @throws IllegalArgumentException if <code>branchesCount<code> is < 3 or * if <code>innerRadius</code> is >= <code>outerRadius</code> */ public Star2D(double x, double y, double innerRadius, double outerRadius, int branchesCount) { if (branchesCount < 3) { throw new IllegalArgumentException("The number of branches must" + " be >= 3."); } else if (innerRadius >= outerRadius) { throw new IllegalArgumentException("The inner radius must be < " + "outer radius."); } this.x = x; this.y = y; this.innerRadius = innerRadius; this.outerRadius = outerRadius; this.branchesCount = branchesCount; starShape = generateStar(x, y, innerRadius, outerRadius, branchesCount); } private static Shape generateStar(double x, double y, double innerRadius, double outerRadius, int branchesCount) { GeneralPath path = new GeneralPath(); double outerAngleIncrement = 2 * Math.PI / branchesCount; double outerAngle = branchesCount % 2 == 0 ? 0.0 : -(Math.PI / 2.0); double innerAngle = (outerAngleIncrement / 2.0) + outerAngle; float x1 = (float) (Math.cos(outerAngle) * outerRadius + x); float y1 = (float) (Math.sin(outerAngle) * outerRadius + y); float x2 = (float) (Math.cos(innerAngle) * innerRadius + x); float y2 = (float) (Math.sin(innerAngle) * innerRadius + y); path.moveTo(x1, y1); path.lineTo(x2, y2); outerAngle += outerAngleIncrement; innerAngle += outerAngleIncrement; for (int i = 1; i < branchesCount; i++) { x1 = (float) (Math.cos(outerAngle) * outerRadius + x); y1 = (float) (Math.sin(outerAngle) * outerRadius + y); path.lineTo(x1, y1); x2 = (float) (Math.cos(innerAngle) * innerRadius + x); y2 = (float) (Math.sin(innerAngle) * innerRadius + y); path.lineTo(x2, y2); outerAngle += outerAngleIncrement; innerAngle += outerAngleIncrement; } path.closePath(); return path; } /** * <p>Sets the inner radius of the star, that is the distance between its * center and the origin of the branches. The inner radius must always be * lower than the outer radius.</p> * * @param innerRadius the distance between the center of the star and the * origin of the branches * @throws IllegalArgumentException if the inner radius is >= outer radius */ public void setInnerRadius(double innerRadius) { if (innerRadius >= outerRadius) { throw new IllegalArgumentException("The inner radius must be <" + " outer radius."); } this.innerRadius = innerRadius; starShape = generateStar(getX(), getY(), innerRadius, getOuterRadius(), getBranchesCount()); } /** * <p>Sets location of the center of the star.</p> * * @param x the x location of the center of the star */ public void setX(double x) { this.x = x; starShape = generateStar(x, getY(), getInnerRadius(), getOuterRadius(), getBranchesCount()); } /** * <p>Sets the location of the center of the star.</p> * * @param y the x location of the center of the star */ public void setY(double y) { this.y = y; starShape = generateStar(getX(), y, getInnerRadius(), getOuterRadius(), getBranchesCount()); } /** * <p>Sets the outer radius of the star, that is the distance between its * center and the tips of the branches. The outer radius must always be * greater than the inner radius.</p> * * @param outerRadius the distance between the center of the star and the * tips of the branches * @throws IllegalArgumentException if the inner radius is >= outer radius */ public void setOuterRadius(double outerRadius) { if (innerRadius >= outerRadius) { throw new IllegalArgumentException("The outer radius must be > " + "inner radius."); } this.outerRadius = outerRadius; starShape = generateStar(getX(), getY(), getInnerRadius(), outerRadius, getBranchesCount()); } /** * <p>Sets the number branches of the star. A star must always have at least * 3 branches.</p> * * @param branchesCount the number of branches * @throws IllegalArgumentException if <code>branchesCount</code> is <=2 */ public void setBranchesCount(int branchesCount) { if (branchesCount <= 2) { throw new IllegalArgumentException("The number of branches must" + " be >= 3."); } this.branchesCount = branchesCount; starShape = generateStar(getX(), getY(), getInnerRadius(), getOuterRadius(), branchesCount); } /** * <p>Returns the location of the center of star.</p> * * @return the x coordinate of the center of the star */ public double getX() { return x; } /** * <p>Returns the location of the center of star.</p> * * @return the y coordinate of the center of the star */ public double getY() { return y; } /** * <p>Returns the distance between the center of the star and the origin * of the branches.</p> * * @return the inner radius of the star */ public double getInnerRadius() { return innerRadius; } /** * <p>Returns the distance between the center of the star and the tips * of the branches.</p> * * @return the outer radius of the star */ public double getOuterRadius() { return outerRadius; } /** * <p>Returns the number of branches of the star.</p> * * @return the number of branches, always >= 3 */ public int getBranchesCount() { return branchesCount; } /** * {@inheritDoc} */ @Override public Rectangle getBounds() { return starShape.getBounds(); } /** * {@inheritDoc} */ @Override public Rectangle2D getBounds2D() { return starShape.getBounds2D(); } /** * {@inheritDoc} */ @Override public boolean contains(double x, double y) { return starShape.contains(x, y); } /** * {@inheritDoc} */ @Override public boolean contains(Point2D p) { return starShape.contains(p); } /** * {@inheritDoc} */ @Override public boolean intersects(double x, double y, double w, double h) { return starShape.intersects(x, y, w, h); } /** * {@inheritDoc} */ @Override public boolean intersects(Rectangle2D r) { return starShape.intersects(r); } /** * {@inheritDoc} */ @Override public boolean contains(double x, double y, double w, double h) { return starShape.contains(x, y, w, h); } /** * {@inheritDoc} */ @Override public boolean contains(Rectangle2D r) { return starShape.contains(r); } /** * {@inheritDoc} */ @Override public PathIterator getPathIterator(AffineTransform at) { return starShape.getPathIterator(at); } /** * {@inheritDoc} */ @Override public PathIterator getPathIterator(AffineTransform at, double flatness) { return starShape.getPathIterator(at, flatness); } }