642 lines
15 KiB
Java
642 lines
15 KiB
Java
//******************************************************************************
|
|
//
|
|
// File: Wedge.java
|
|
// Package: edu.rit.draw.item
|
|
// Unit: Class edu.rit.draw.item.Wedge
|
|
//
|
|
// This Java source file is copyright (C) 2013 by Alan Kaminsky. All rights
|
|
// reserved. For further information, contact the author, Alan Kaminsky, at
|
|
// ark@cs.rit.edu.
|
|
//
|
|
// This Java source file is part of the Parallel Java 2 Library ("PJ2"). PJ2 is
|
|
// free software; you can redistribute it and/or modify it under the terms of
|
|
// the GNU General Public License as published by the Free Software Foundation;
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// PJ2 is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
//
|
|
// A copy of the GNU General Public License is provided in the file gpl.txt. You
|
|
// may also obtain a copy of the GNU General Public License on the World Wide
|
|
// Web at http://www.gnu.org/licenses/gpl.html.
|
|
//
|
|
//******************************************************************************
|
|
|
|
package edu.rit.draw.item;
|
|
|
|
import edu.rit.draw.Drawing;
|
|
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Shape;
|
|
|
|
import java.awt.geom.Arc2D;
|
|
|
|
import java.io.Externalizable;
|
|
import java.io.IOException;
|
|
import java.io.ObjectInput;
|
|
import java.io.ObjectOutput;
|
|
|
|
/**
|
|
* Class Wedge provides a {@linkplain DrawingItem} that is a circular wedge. The
|
|
* wedge has an outline consisting of two rays from the wedge's center point
|
|
* joined by a circular arc. The wedge has a filled interior. The wedge is
|
|
* defined by the following attributes:
|
|
* <UL>
|
|
* <P><LI>
|
|
* <TT>center()</TT> -- The wedge's center point. The default is (0,0).
|
|
* <P><LI>
|
|
* <TT>radius()</TT> -- The wedge's radius. The default is 1.
|
|
* <P><LI>
|
|
* <TT>start()</TT> -- The wedge's starting angle in radians. This is the angle
|
|
* from the positive X axis to the wedge's starting point. The default is 0.
|
|
* <P><LI>
|
|
* <TT>extent()</TT> -- The wedge's angular extent in radians. This is the angle
|
|
* from the wedge's starting point to the wedge's ending point. The default is
|
|
* π/2.
|
|
* </UL>
|
|
* <P>
|
|
* Angles increase from the positive X axis towards the positive Y axis. Since
|
|
* the positive X axis points to the right and the positive Y axis points down,
|
|
* angles increase in the clockwise direction. (This is the opposite of the
|
|
* usual mathematical convention, where the positive Y axis points upwards.)
|
|
* <P>
|
|
* The static <TT>defaultCenter()</TT>, <TT>defaultRadius()</TT>,
|
|
* <TT>defaultStart()</TT>, and <TT>defaultExtent()</TT> methods are provided to
|
|
* set the default center point, radius, starting angle, and angular extent. If
|
|
* the center point, radius, starting angle, or angular extent is not specified,
|
|
* the current default center point, radius, starting angle, or angular extent
|
|
* is used.
|
|
*
|
|
* @author Alan Kaminsky
|
|
* @version 07-Jun-2013
|
|
*/
|
|
public class Wedge
|
|
extends ShapeItem
|
|
implements Externalizable
|
|
{
|
|
|
|
// Exported constants.
|
|
|
|
/**
|
|
* The normal center point: (0,0).
|
|
*/
|
|
public static final Point NORMAL_CENTER = new Point (0, 0);
|
|
|
|
/**
|
|
* The normal radius: 1.
|
|
*/
|
|
public static final double NORMAL_RADIUS = 1.0;
|
|
|
|
/**
|
|
* The normal starting angle: 0.
|
|
*/
|
|
public static final double NORMAL_START = 0.0;
|
|
|
|
/**
|
|
* The normal angular extent: π/2.
|
|
*/
|
|
public static final double NORMAL_EXTENT = Math.PI / 2.0;
|
|
|
|
// Hidden data members.
|
|
|
|
private static final long serialVersionUID = -3194574426240421069L;
|
|
|
|
private static final double DEGREES_PER_RADIAN = 180.0 / Math.PI;
|
|
private static final double A_PI_2 = Math.PI / 2.0;
|
|
private static final double A_PI = Math.PI;
|
|
private static final double A_3_PI_2 = 3.0 * Math.PI / 2.0;
|
|
private static final double A_2_PI = 2.0 * Math.PI;
|
|
private static final double A_5_PI_2 = 5.0 * Math.PI / 2.0;
|
|
private static final double A_3_PI = 3.0 * Math.PI;
|
|
private static final double A_7_PI_2 = 7.0 * Math.PI / 2.0;
|
|
|
|
// Attributes.
|
|
Point myCenter = theDefaultCenter;
|
|
double myRadius = theDefaultRadius;
|
|
double myStart = theDefaultStart;
|
|
double myExtent = theDefaultExtent;
|
|
|
|
// The default attributes.
|
|
static Point theDefaultCenter = NORMAL_CENTER;
|
|
static double theDefaultRadius = NORMAL_RADIUS;
|
|
static double theDefaultStart = NORMAL_START;
|
|
static double theDefaultExtent = NORMAL_EXTENT;
|
|
|
|
// For computing the bounding box.
|
|
Point myNw;
|
|
Point mySe;
|
|
Size mySize;
|
|
|
|
// Exported constructors.
|
|
|
|
/**
|
|
* Construct a new wedge. The default center point, radius, starting angle,
|
|
* and angular extent are used.
|
|
*/
|
|
public Wedge()
|
|
{
|
|
super();
|
|
}
|
|
|
|
/**
|
|
* Construct a new wedge with the same center point, radius, starting angle,
|
|
* and angular extent as the given wedge.
|
|
*
|
|
* @param theWedge Wedge.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if <TT>theWedge</TT> is null.
|
|
*/
|
|
public Wedge
|
|
(Wedge theWedge)
|
|
{
|
|
super (theWedge);
|
|
myCenter = theWedge.myCenter;
|
|
myRadius = theWedge.myRadius;
|
|
myStart = theWedge.myStart;
|
|
myExtent = theWedge.myExtent;
|
|
}
|
|
|
|
// Exported operations.
|
|
|
|
/**
|
|
* Returns the default center point.
|
|
*
|
|
* @return Default center point.
|
|
*/
|
|
public static Point defaultCenter()
|
|
{
|
|
return theDefaultCenter;
|
|
}
|
|
|
|
/**
|
|
* Set the default center point. Before calling this method the first time,
|
|
* the default center point is (0,0).
|
|
*
|
|
* @param theCenter Default center point.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if <TT>theCenter</TT> is null.
|
|
*/
|
|
public static void defaultCenter
|
|
(Point theCenter)
|
|
{
|
|
if (theCenter == null) throw new NullPointerException();
|
|
theDefaultCenter = theCenter;
|
|
}
|
|
|
|
/**
|
|
* Returns the default radius.
|
|
*
|
|
* @return Default radius.
|
|
*/
|
|
public static double defaultRadius()
|
|
{
|
|
return theDefaultRadius;
|
|
}
|
|
|
|
/**
|
|
* Set the default radius. Before calling this method the first time, the
|
|
* default radius is 1.
|
|
*
|
|
* @param theRadius Default radius.
|
|
*
|
|
* @exception IllegalArgumentException
|
|
* (unchecked exception) Thrown if <TT>theRadius</TT> <= 0.
|
|
*/
|
|
public static void defaultRadius
|
|
(double theRadius)
|
|
{
|
|
if (theRadius <= 0.0) throw new IllegalArgumentException();
|
|
theDefaultRadius = theRadius;
|
|
}
|
|
|
|
/**
|
|
* Returns the default starting angle.
|
|
*
|
|
* @return Default starting angle (radians).
|
|
*/
|
|
public static double defaultStart()
|
|
{
|
|
return theDefaultStart;
|
|
}
|
|
|
|
/**
|
|
* Set the default starting angle. Before calling this method the first
|
|
* time, the default starting angle is 0.
|
|
*
|
|
* @param theStart Default starting angle (radians).
|
|
*/
|
|
public static void defaultStart
|
|
(double theStart)
|
|
{
|
|
theDefaultStart = theStart;
|
|
}
|
|
|
|
/**
|
|
* Returns the default angular extent.
|
|
*
|
|
* @return Default angular extent (radians).
|
|
*/
|
|
public static double defaultExtent()
|
|
{
|
|
return theDefaultExtent;
|
|
}
|
|
|
|
/**
|
|
* Set the default angular extent. Before calling this method the first
|
|
* time, the default angular extent is π/2.
|
|
*
|
|
* @param theExtent Default angular extent (radians).
|
|
*/
|
|
public static void defaultExtent
|
|
(double theExtent)
|
|
{
|
|
theDefaultExtent = theExtent;
|
|
}
|
|
|
|
/**
|
|
* Returns the size of this drawing item's bounding box.
|
|
*
|
|
* @return Size.
|
|
*/
|
|
public Size size()
|
|
{
|
|
computeBoundingBox();
|
|
return mySize;
|
|
}
|
|
|
|
/**
|
|
* Returns the width of this drawing item's bounding box.
|
|
*
|
|
* @return Width.
|
|
*/
|
|
public double width()
|
|
{
|
|
computeBoundingBox();
|
|
return mySize.width;
|
|
}
|
|
|
|
/**
|
|
* Returns the height of this drawing item's bounding box.
|
|
*
|
|
* @return Height.
|
|
*/
|
|
public double height()
|
|
{
|
|
computeBoundingBox();
|
|
return mySize.height;
|
|
}
|
|
|
|
/**
|
|
* Returns the northwest corner point of this drawing item's bounding box.
|
|
*
|
|
* @return Northwest corner point.
|
|
*/
|
|
public Point nw()
|
|
{
|
|
computeBoundingBox();
|
|
return myNw;
|
|
}
|
|
|
|
/**
|
|
* Set this wedge's outline.
|
|
*
|
|
* @param theOutline Outline, or <TT>Outline.NONE</TT>.
|
|
*
|
|
* @return This wedge.
|
|
*/
|
|
public Wedge outline
|
|
(Outline theOutline)
|
|
{
|
|
doOutline (theOutline);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set this wedge's fill paint.
|
|
*
|
|
* @param theFill Fill paint, or <TT>Fill.NONE</TT>.
|
|
*
|
|
* @return This wedge.
|
|
*/
|
|
public Wedge fill
|
|
(Fill theFill)
|
|
{
|
|
doFill (theFill);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Returns this wedge's center point.
|
|
*
|
|
* @return Center point.
|
|
*/
|
|
public Point center()
|
|
{
|
|
return myCenter;
|
|
}
|
|
|
|
/**
|
|
* Set this wedge's center point.
|
|
*
|
|
* @param theCenter Center point.
|
|
*
|
|
* @return This wedge.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if <TT>theCenter</TT> is null.
|
|
*/
|
|
public Wedge center
|
|
(Point theCenter)
|
|
{
|
|
if (theCenter == null) throw new NullPointerException();
|
|
myCenter = theCenter;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Returns this wedge's radius.
|
|
*
|
|
* @return Radius.
|
|
*/
|
|
public double radius()
|
|
{
|
|
return myRadius;
|
|
}
|
|
|
|
/**
|
|
* Set this wedge's radius.
|
|
*
|
|
* @param theRadius Radius.
|
|
*
|
|
* @return This wedge.
|
|
*
|
|
* @exception IllegalArgumentException
|
|
* (unchecked exception) Thrown if <TT>theRadius</TT> <= 0.
|
|
*/
|
|
public Wedge radius
|
|
(double theRadius)
|
|
{
|
|
if (theRadius <= 0.0) throw new IllegalArgumentException();
|
|
myRadius = theRadius;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Returns this wedge's starting angle.
|
|
*
|
|
* @return Starting angle (radians).
|
|
*/
|
|
public double start()
|
|
{
|
|
return myStart;
|
|
}
|
|
|
|
/**
|
|
* Set this wedge's starting angle.
|
|
*
|
|
* @param theStart Starting angle (radians).
|
|
*
|
|
* @return This wedge.
|
|
*/
|
|
public Wedge start
|
|
(double theStart)
|
|
{
|
|
myStart = theStart;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Returns this wedge's angular extent.
|
|
*
|
|
* @return Angular extent (radians).
|
|
*/
|
|
public double extent()
|
|
{
|
|
return myExtent;
|
|
}
|
|
|
|
/**
|
|
* Set this wedge's angular extent.
|
|
*
|
|
* @param theExtent Angular extent (radians).
|
|
*
|
|
* @return This wedge.
|
|
*/
|
|
public Wedge extent
|
|
(double theExtent)
|
|
{
|
|
myExtent = theExtent;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add this wedge to the end of the default drawing's sequence of drawing
|
|
* items.
|
|
*
|
|
* @return This wedge.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if there is no default drawing.
|
|
*
|
|
* @see Drawing#defaultDrawing()
|
|
*/
|
|
public Wedge add()
|
|
{
|
|
doAdd (Drawing.defaultDrawing());
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add this wedge to the end of the given drawing's sequence of drawing
|
|
* items.
|
|
*
|
|
* @param theDrawing Drawing.
|
|
*
|
|
* @return This wedge.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if <TT>theDrawing</TT> is null.
|
|
*/
|
|
public Wedge add
|
|
(Drawing theDrawing)
|
|
{
|
|
doAdd (theDrawing);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add this wedge to the beginning of the default drawing's sequence of
|
|
* drawing items.
|
|
*
|
|
* @return This wedge.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if there is no default drawing.
|
|
*
|
|
* @see Drawing#defaultDrawing()
|
|
*/
|
|
public Wedge addFirst()
|
|
{
|
|
doAddFirst (Drawing.defaultDrawing());
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add this wedge to the beginning of the given drawing's sequence of
|
|
* drawing items.
|
|
*
|
|
* @param theDrawing Drawing.
|
|
*
|
|
* @return This wedge.
|
|
*
|
|
* @exception NullPointerException
|
|
* (unchecked exception) Thrown if <TT>theDrawing</TT> is null.
|
|
*/
|
|
public Wedge addFirst
|
|
(Drawing theDrawing)
|
|
{
|
|
doAddFirst (theDrawing);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Write this wedge to the given object output stream.
|
|
*
|
|
* @param out Object output stream.
|
|
*
|
|
* @exception IOException
|
|
* Thrown if an I/O error occurred.
|
|
*/
|
|
public void writeExternal
|
|
(ObjectOutput out)
|
|
throws IOException
|
|
{
|
|
super.writeExternal (out);
|
|
out.writeObject (myCenter);
|
|
out.writeDouble (myRadius);
|
|
out.writeDouble (myStart);
|
|
out.writeDouble (myExtent);
|
|
}
|
|
|
|
/**
|
|
* Read this wedge from the given object input stream.
|
|
*
|
|
* @param in Object input stream.
|
|
*
|
|
* @exception IOException
|
|
* Thrown if an I/O error occurred.
|
|
* @exception ClassNotFoundException
|
|
* Thrown if any class needed to deserialize this line cannot be found.
|
|
*/
|
|
public void readExternal
|
|
(ObjectInput in)
|
|
throws IOException, ClassNotFoundException
|
|
{
|
|
super.readExternal (in);
|
|
myCenter = (Point) in.readObject();
|
|
myRadius = in.readDouble();
|
|
myStart = in.readDouble();
|
|
myExtent = in.readDouble();
|
|
}
|
|
|
|
// Hidden operations.
|
|
|
|
/**
|
|
* Compute this wedge's bounding box. The results are stored in
|
|
* myNw, mySe, and mySize.
|
|
*/
|
|
private void computeBoundingBox()
|
|
{
|
|
if (myNw == null)
|
|
{
|
|
double extent, start1, start2, sx, sy, ex, ey, x1, y1, x2, y2;
|
|
|
|
// Make the angular extent positive if necessary.
|
|
if (myExtent >= 0.0)
|
|
{
|
|
extent = myExtent;
|
|
start1 = myStart;
|
|
}
|
|
else
|
|
{
|
|
extent = - myExtent;
|
|
start1 = myStart - extent;
|
|
}
|
|
|
|
// Compute starting angle (mod 2 pi).
|
|
start2 = Math.abs (start1);
|
|
start2 = start2 - Math.floor (start2 / A_2_PI) * A_2_PI;
|
|
if (start1 < 0.0) start2 = A_2_PI - start2;
|
|
|
|
// Compute starting point.
|
|
sx = myCenter.x() + myRadius * Math.cos (start2);
|
|
sy = myCenter.y() + myRadius * Math.sin (start2);
|
|
|
|
// Compute ending point.
|
|
ex = myCenter.x() + myRadius * Math.cos (start2 + extent);
|
|
ey = myCenter.y() + myRadius * Math.sin (start2 + extent);
|
|
|
|
// Compute initial bounding box from starting and ending points.
|
|
x1 = Math.min (sx, ex);
|
|
y1 = Math.min (sy, ey);
|
|
x2 = Math.max (sx, ex);
|
|
y2 = Math.max (sy, ey);
|
|
|
|
// Adjust bounding box if wedge crosses the positive X axis.
|
|
if (start2 < A_2_PI && start2 + extent > A_2_PI)
|
|
{
|
|
x2 = myCenter.x() + myRadius;
|
|
}
|
|
|
|
// Adjust bounding box if wedge crosses the positive Y axis.
|
|
if
|
|
((start2 < A_PI_2 && start2 + extent > A_PI_2) ||
|
|
(start2 < A_5_PI_2 && start2 + extent > A_5_PI_2))
|
|
{
|
|
y2 = myCenter.y() + myRadius;
|
|
}
|
|
|
|
// Adjust bounding box if wedge crosses the negative X axis.
|
|
if
|
|
((start2 < A_PI && start2 + extent > A_PI) ||
|
|
(start2 < A_3_PI && start2 + extent > A_3_PI))
|
|
{
|
|
x1 = myCenter.x() - myRadius;
|
|
}
|
|
|
|
// Adjust bounding box if wedge crosses the negative Y axis.
|
|
if
|
|
((start2 < A_3_PI_2 && start2 + extent > A_3_PI_2) ||
|
|
(start2 < A_7_PI_2 && start2 + extent > A_7_PI_2))
|
|
{
|
|
y1 = myCenter.y() - myRadius;
|
|
}
|
|
|
|
// Compute final bounding box.
|
|
myNw = new Point (x1, y1);
|
|
mySe = new Point (x2, y2);
|
|
mySize = mySe.difference (myNw);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compute this wedge's shape from its attributes.
|
|
*/
|
|
Shape getShape()
|
|
{
|
|
return
|
|
new Arc2D.Double
|
|
(/*x */ myCenter.x() - myRadius,
|
|
/*y */ myCenter.y() - myRadius,
|
|
/*w */ 2 * myRadius,
|
|
/*h */ 2 * myRadius,
|
|
/*start */ -myStart * DEGREES_PER_RADIAN,
|
|
/*extent*/ -myExtent * DEGREES_PER_RADIAN,
|
|
/*type */ Arc2D.PIE);
|
|
}
|
|
|
|
}
|