/* * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package java.awt; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.ColorModel; import java.beans.ConstructorProperties; /** * The {@code RadialGradientPaint} class provides a way to fill a shape with * a circular radial color gradient pattern. The user may specify 2 or more * gradient colors, and this paint will provide an interpolation between * each color. *
* The user must specify the circle controlling the gradient pattern, * which is described by a center point and a radius. The user can also * specify a separate focus point within that circle, which controls the * location of the first color of the gradient. By default the focus is * set to be the center of the circle. *
* This paint will map the first color of the gradient to the focus point, * and the last color to the perimeter of the circle, interpolating * smoothly for any in-between colors specified by the user. Any line drawn * from the focus point to the circumference will thus span all the gradient * colors. *
* Specifying a focus point outside of the radius of the circle will cause * the rings of the gradient pattern to be centered on the point just inside * the edge of the circle in the direction of the focus point. * The rendering will internally use this modified location as if it were * the specified focus point. *
* The user must provide an array of floats specifying how to distribute the * colors along the gradient. These values should range from 0.0 to 1.0 and * act like keyframes along the gradient (they mark where the gradient should * be exactly a particular color). *
* In the event that the user does not set the first keyframe value equal
* to 0 and/or the last keyframe value equal to 1, keyframes will be created
* at these positions and the first and last colors will be replicated there.
* So, if a user specifies the following arrays to construct a gradient:
*
* {Color.BLUE, Color.RED}, {.3f, .7f}
*
* this will be converted to a gradient with the following keyframes:
* {Color.BLUE, Color.BLUE, Color.RED, Color.RED}, {0f, .3f, .7f, 1f}
*
*
* * The user may also select what action the {@code RadialGradientPaint} object * takes when it is filling the space outside the circle's radius by * setting {@code CycleMethod} to either {@code REFLECTION} or {@code REPEAT}. * The gradient color proportions are equal for any particular line drawn * from the focus point. The following figure shows that the distance AB * is equal to the distance BC, and the distance AD is equal to the distance DE. *
*
* * The colorSpace parameter allows the user to specify in which colorspace * the interpolation should be performed, default sRGB or linearized RGB. * *
* The following code demonstrates typical usage of * {@code RadialGradientPaint}, where the center and focus points are * the same: *
*
* Point2D center = new Point2D.Float(50, 50);
* float radius = 25;
* float[] dist = {0.0f, 0.2f, 1.0f};
* Color[] colors = {Color.RED, Color.WHITE, Color.BLUE};
* RadialGradientPaint p =
* new RadialGradientPaint(center, radius, dist, colors);
*
*
* * This image demonstrates the example code above, with default * (centered) focus for each of the three cycle methods: *
*
* * It is also possible to specify a non-centered focus point, as * in the following code: *
*
* Point2D center = new Point2D.Float(50, 50);
* float radius = 25;
* Point2D focus = new Point2D.Float(40, 40);
* float[] dist = {0.0f, 0.2f, 1.0f};
* Color[] colors = {Color.RED, Color.WHITE, Color.BLUE};
* RadialGradientPaint p =
* new RadialGradientPaint(center, radius, focus,
* dist, colors,
* CycleMethod.NO_CYCLE);
*
*
* * This image demonstrates the previous example code, with non-centered * focus for each of the three cycle methods: *
*
*
* This constructor is a more convenient way to express the
* following (equivalent) code:
*
*
* double gw = gradientBounds.getWidth();
* double gh = gradientBounds.getHeight();
* double cx = gradientBounds.getCenterX();
* double cy = gradientBounds.getCenterY();
* Point2D center = new Point2D.Double(cx, cy);
*
* AffineTransform gradientTransform = new AffineTransform();
* gradientTransform.translate(cx, cy);
* gradientTransform.scale(gw / 2, gh / 2);
* gradientTransform.translate(-cx, -cy);
*
* RadialGradientPaint gp =
* new RadialGradientPaint(center, 1.0f, center,
* fractions, colors,
* cycleMethod,
* ColorSpaceType.SRGB,
* gradientTransform);
*
*
* @param gradientBounds the bounding box, in user space, of the circle
* defining the outermost extent of the gradient
* @param fractions numbers ranging from 0.0 to 1.0 specifying the
* distribution of colors along the gradient
* @param colors array of colors to use in the gradient. The first color
* is used at the focus point, the last color around the
* perimeter of the circle.
* @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
* or {@code REPEAT}
*
* @throws NullPointerException
* if {@code gradientBounds} is null,
* or {@code fractions} array is null,
* or {@code colors} array is null,
* or {@code cycleMethod} is null
* @throws IllegalArgumentException
* if {@code gradientBounds} is empty,
* or {@code fractions.length != colors.length},
* or {@code colors} is less than 2 in size,
* or a {@code fractions} value is less than 0.0 or greater than 1.0,
* or the {@code fractions} are not provided in strictly increasing order
*/
public RadialGradientPaint(Rectangle2D gradientBounds,
float[] fractions, Color[] colors,
CycleMethod cycleMethod)
{
// gradient center/focal point is the center of the bounding box,
// radius is set to 1.0, and then we set a scale transform
// to achieve an elliptical gradient defined by the bounding box
this(new Point2D.Double(gradientBounds.getCenterX(),
gradientBounds.getCenterY()),
1.0f,
new Point2D.Double(gradientBounds.getCenterX(),
gradientBounds.getCenterY()),
fractions,
colors,
cycleMethod,
ColorSpaceType.SRGB,
createGradientTransform(gradientBounds));
if (gradientBounds.isEmpty()) {
throw new IllegalArgumentException("Gradient bounds must be " +
"non-empty");
}
}
private static AffineTransform createGradientTransform(Rectangle2D r) {
double cx = r.getCenterX();
double cy = r.getCenterY();
AffineTransform xform = AffineTransform.getTranslateInstance(cx, cy);
xform.scale(r.getWidth()/2, r.getHeight()/2);
xform.translate(-cx, -cy);
return xform;
}
/**
* Creates and returns a {@link PaintContext} used to
* generate a circular radial color gradient pattern.
* See the description of the {@link Paint#createContext createContext} method
* for information on null parameter handling.
*
* @param cm the preferred {@link ColorModel} which represents the most convenient
* format for the caller to receive the pixel data, or {@code null}
* if there is no preference.
* @param deviceBounds the device space bounding box
* of the graphics primitive being rendered.
* @param userBounds the user space bounding box
* of the graphics primitive being rendered.
* @param transform the {@link AffineTransform} from user
* space into device space.
* @param hints the set of hints that the context object can use to
* choose between rendering alternatives.
* @return the {@code PaintContext} for
* generating color patterns.
* @see Paint
* @see PaintContext
* @see ColorModel
* @see Rectangle
* @see Rectangle2D
* @see AffineTransform
* @see RenderingHints
*/
public PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform transform,
RenderingHints hints)
{
// avoid modifying the user's transform...
transform = new AffineTransform(transform);
// incorporate the gradient transform
transform.concatenate(gradientTransform);
return new RadialGradientPaintContext(this, cm,
deviceBounds, userBounds,
transform, hints,
(float)center.getX(),
(float)center.getY(),
radius,
(float)focus.getX(),
(float)focus.getY(),
fractions, colors,
cycleMethod, colorSpace);
}
/**
* Returns a copy of the center point of the radial gradient.
*
* @return a {@code Point2D} object that is a copy of the center point
*/
public Point2D getCenterPoint() {
return new Point2D.Double(center.getX(), center.getY());
}
/**
* Returns a copy of the focus point of the radial gradient.
* Note that if the focus point specified when the radial gradient
* was constructed lies outside of the radius of the circle, this
* method will still return the original focus point even though
* the rendering may center the rings of color on a different
* point that lies inside the radius.
*
* @return a {@code Point2D} object that is a copy of the focus point
*/
public Point2D getFocusPoint() {
return new Point2D.Double(focus.getX(), focus.getY());
}
/**
* Returns the radius of the circle defining the radial gradient.
*
* @return the radius of the circle defining the radial gradient
*/
public float getRadius() {
return radius;
}
}