001 package edu.nrao.sss.geom; 002 003 import java.awt.Rectangle; 004 import java.awt.Shape; 005 import java.awt.geom.AffineTransform; 006 import java.awt.geom.Ellipse2D; 007 import java.awt.geom.PathIterator; 008 import java.awt.geom.Point2D; 009 import java.awt.geom.Rectangle2D; 010 011 /** 012 * A circle described by a central point and radial length. 013 * This circle class fits in with java's {@link java.awt.geom 2D} package. 014 * <p> 015 * <b>Version Info:</b> 016 * <table style="margin-left:2em"> 017 * <tr><td>$Revision: 797 $</td></tr> 018 * <tr><td>$Date: 2007-08-08 16:48:50 -0600 (Wed, 08 Aug 2007) $</td></tr> 019 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 020 * </table></p> 021 * 022 * @author David M. Harland 023 * @since 2007-08-07 024 */ 025 public class Circle 026 implements Shape, Cloneable 027 { 028 private Point2D center; 029 private double radius; 030 private Ellipse2D ellipse; 031 032 /** 033 * Creates a new circle, centered at the origin, with the given radius. 034 * 035 * @param radius the radius of this circle. The units are arbitrary, 036 * but are often taken to be pixels. 037 */ 038 public Circle(double radius) 039 { 040 this(new Point2D.Double(), radius); 041 } 042 043 /** 044 * Creates a new circle with the given center and radius. 045 * 046 * @param center the center of this circle. 047 * 048 * @param radius the radius of this circle. The units are arbitrary, 049 * but are often taken to be pixels. If this value 050 * is infinite, negative, or not a number, the radius 051 * will be set to one. 052 */ 053 public Circle(Point2D center, double radius) 054 { 055 this.center = (center == null) ? new Point2D.Double() 056 : (Point2D)center.clone(); 057 058 this.radius = radiusIsValid(radius) ? radius : 1.0; 059 060 ellipse = new Ellipse2D.Double(); 061 062 updateEllipse(); 063 } 064 065 /** Updates the ellipse delegate to match this circle. */ 066 private void updateEllipse() 067 { 068 double diameter = 2.0 * radius; 069 070 ellipse.setFrame(center.getX() - radius, 071 center.getY() - radius, diameter, diameter); 072 } 073 074 //============================================================================ 075 // 076 //============================================================================ 077 078 /** Returns <i>true</i> if newRadius is non-negative and finite. */ 079 private boolean radiusIsValid(double newRadius) 080 { 081 return (newRadius >= 0.0) && !Double.isInfinite(newRadius) 082 && !Double.isNaN(newRadius); 083 } 084 085 /** 086 * Sets the radius of this circle. 087 * If {@code newRadius} is negative, infinite, or not a number, an 088 * <tt>IllegalArgumentException</tt> is thrown. 089 * 090 * @param newRadius the new radius of this circle. 091 */ 092 public void setRadius(double newRadius) 093 { 094 if (radiusIsValid(newRadius)) 095 { 096 radius = newRadius; 097 } 098 else 099 { 100 throw new IllegalArgumentException( 101 "Tried to set radius to " + newRadius + 102 ". Radius must be a finite non-negative number."); 103 } 104 } 105 106 /** 107 * Returns the radius of this circle. 108 * The units are arbitrary, but are often taken to be pixels. 109 * @return the radius of this circle. 110 */ 111 public double getRadius() { return radius; } 112 113 /** 114 * Returns the diameter of this circle. 115 * The units are arbitrary, but are often taken to be pixels. 116 * @return the diameter of this circle. 117 */ 118 public double getDiameter() { return 2.0 * radius; } 119 120 /** 121 * Sets the center of this circle to be coincident with {@code newCenter}. 122 * Note that this circle will <i>not</i> hold a reference to 123 * {@code newCenter}, so changes made to it after calling this method 124 * will not be reflected herein. 125 * <p> 126 * If {@code newCenter} is <i>null</i>, the center of this circle will 127 * not be altered.</p> 128 * 129 * @param newCenter the new center of this circle. 130 */ 131 public void setCenter(Point2D newCenter) 132 { 133 if (newCenter != null) 134 center.setLocation(newCenter.getX(), newCenter.getY()); 135 } 136 137 /** 138 * Returns a copy of the center of this circle. 139 * @return a copy of the center of this circle. 140 */ 141 public Point2D getCenter() 142 { 143 return (Point2D)center.clone(); 144 } 145 146 //============================================================================ 147 // IMPLEMENTATION OF Shape INTERFACE 148 //============================================================================ 149 150 public boolean contains(double x, double y) 151 { 152 return ellipse.contains(x, y); 153 } 154 155 public boolean contains(double x, double y, double w, double h) 156 { 157 return ellipse.contains(x, y, w, h); 158 } 159 160 public boolean contains(Point2D p) 161 { 162 return ellipse.contains(p); 163 } 164 165 public boolean contains(Rectangle2D r) 166 { 167 return ellipse.contains(r); 168 } 169 170 public Rectangle getBounds() 171 { 172 return ellipse.getBounds(); 173 } 174 175 public Rectangle2D getBounds2D() 176 { 177 return ellipse.getBounds2D(); 178 } 179 180 public PathIterator getPathIterator(AffineTransform at) 181 { 182 return ellipse.getPathIterator(at); 183 } 184 185 public PathIterator getPathIterator(AffineTransform at, double flatness) 186 { 187 return ellipse.getPathIterator(at, flatness); 188 } 189 190 public boolean intersects(double x, double y, double w, double h) 191 { 192 return ellipse.intersects(x, y, w, h); 193 } 194 195 /** {@inheritDoc} */ 196 public boolean intersects(Rectangle2D r) 197 { 198 return ellipse.intersects(r); 199 } 200 201 //============================================================================ 202 // 203 //============================================================================ 204 205 /** 206 * Creates a copy of this circle. 207 * If anything goes wrong during the cloning process 208 * a runtime exception is thrown. 209 */ 210 @Override 211 public Circle clone() 212 { 213 Circle clone = null; 214 215 try 216 { 217 clone = (Circle)super.clone(); 218 219 clone.center = (Point2D)this.center.clone(); 220 221 clone.ellipse = (Ellipse2D)this.ellipse.clone(); 222 } 223 catch (CloneNotSupportedException ex) 224 { 225 throw new RuntimeException(ex); 226 } 227 228 return clone; 229 } 230 }