001: /*
002:
003: Copyright 2001-2003 The Apache Software Foundation
004:
005: Licensed under the Apache License, Version 2.0 (the "License");
006: you may not use this file except in compliance with the License.
007: You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016:
017: */
018: package com.xoetrope.batik.ext.awt;
019:
020: import java.awt.Color;
021: import java.awt.PaintContext;
022: import java.awt.Rectangle;
023: import java.awt.RenderingHints;
024: import java.awt.geom.AffineTransform;
025: import java.awt.geom.NoninvertibleTransformException;
026: import java.awt.geom.Point2D;
027: import java.awt.geom.Rectangle2D;
028: import java.awt.image.ColorModel;
029:
030: /**
031: * <p>
032: * This class provides a way to fill a shape with a circular radial color
033: * gradient pattern. The user may specify 2 or more gradient colors, and this
034: * paint will provide an interpolation between each color.
035: * <p>
036: *
037: * The user must provide an array of floats specifying how to distribute the
038: * colors along the gradient. These values should range from 0.0 to 1.0 and
039: * act like keyframes along the gradient (they mark where the gradient should
040: * be exactly a particular color).
041: *
042: * <p>
043: * This paint will map the first color of the gradient to a focus point within
044: * the circle, and the last color to the perimeter of the circle, interpolating
045: * smoothly for any inbetween colors specified by the user. Any line drawn
046: * from the focus point to the circumference will span the all the gradient
047: * colors. By default the focus is set to be the center of the circle.
048: *
049: * <p>
050: * Specifying a focus point outside of the circle's radius will result in the
051: * focus being set to the intersection point of the focus-center line and the
052: * perimenter of the circle.
053: * <p>
054: *
055: * Specifying a cycle method allows the user to control the painting behavior
056: * outside of the bounds of the circle's radius. See LinearGradientPaint for
057: * more details.
058: *
059: * <p>
060: * The following code demonstrates typical usage of RadialGradientPaint:
061: * <p>
062: * <code>
063: * Point2D center = new Point2D.Float(0, 0);<br>
064: * float radius = 20;
065: * float[] dist = {0.0, 0.2, 1.0};<br>
066: * Color[] colors = {Color.red, Color.white, Color.blue};<br>
067: * RadialGradientPaint p = new RadialGradientPaint(center, radius,
068: * dist, colors);
069: * </code>
070: *
071: * <p> In the event that the user does not set the first keyframe value equal
072: * to 0 and the last keyframe value equal to 1, keyframes will be created at
073: * these positions and the first and last colors will be replicated there.
074: * So, if a user specifies the following arrays to construct a gradient:<br>
075: * {Color.blue, Color.red}, {.3, .7}<br>
076: * this will be converted to a gradient with the following keyframes:
077: * {Color.blue, Color.blue, Color.red, Color.red}, {0, .3, .7, 1}
078: *
079: *
080: * <p>
081: * <img src = "radial.jpg">
082: * <p>
083: * This image demonstrates a radial gradient with NO_CYCLE and default focus.
084: * <p>
085: *
086: * <img src = "radial2.jpg">
087: * <p>
088: * This image demonstrates a radial gradient with NO_CYCLE and non-centered
089: * focus.
090: * <p>
091: *
092: * <img src = "radial3.jpg">
093: * <p>
094: * This image demonstrates a radial gradient with REFLECT and non-centered
095: * focus.
096: *
097: * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
098: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
099: * @version $Id: RadialGradientPaint.java,v 1.2 2006/08/31 09:28:47 val Exp $
100: *
101: */
102:
103: public final class RadialGradientPaint extends MultipleGradientPaint {
104:
105: /** Focus point which defines the 0% gradient stop x coordinate. */
106: private Point2D focus;
107:
108: /** Center of the circle defining the 100% gradient stop x coordinate. */
109: private Point2D center;
110:
111: /** Radius of the outermost circle defining the 100% gradient stop. */
112: private float radius;
113:
114: /**
115: * <p>
116: *
117: * Constructs a <code>RadialGradientPaint</code>, using the center as the
118: * focus point.
119: *
120: * @param cx the x coordinate in user space of the center point of the
121: * circle defining the gradient. The last color of the gradient is mapped
122: * to the perimeter of this circle
123: *
124: * @param cy the y coordinate in user space of the center point of the
125: * circle defining the gradient. The last color of the gradient is mapped
126: * to the perimeter of this circle
127: *
128: * @param radius the radius of the circle defining the extents of the
129: * color gradient
130: *
131: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
132: * distribution of colors along the gradient
133: *
134: * @param colors array of colors to use in the gradient. The first color
135: * is used at the focus point, the last color around the perimeter of the
136: * circle.
137: *
138: *
139: * @throws IllegalArgumentException
140: * if fractions.length != colors.length, or if colors is less
141: * than 2 in size, or if radius < 0
142: *
143: *
144: */
145: public RadialGradientPaint(float cx, float cy, float radius,
146: float[] fractions, Color[] colors) {
147: this (cx, cy, radius, cx, cy, fractions, colors);
148: }
149:
150: /**
151: * <p>
152: *
153: * Constructs a <code>RadialGradientPaint</code>, using the center as the
154: * focus point.
155: *
156: * @param center the center point, in user space, of the circle defining
157: * the gradient
158: *
159: * @param radius the radius of the circle defining the extents of the
160: * color gradient
161: *
162: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
163: * distribution of colors along the gradient
164: *
165: * @param colors array of colors to use in the gradient. The first color
166: * is used at the focus point, the last color around the perimeter of the
167: * circle.
168: *
169: * @throws NullPointerException if center point is null
170: *
171: * @throws IllegalArgumentException
172: * if fractions.length != colors.length, or if colors is less
173: * than 2 in size, or if radius < 0
174: *
175: *
176: */
177: public RadialGradientPaint(Point2D center, float radius,
178: float[] fractions, Color[] colors) {
179: this (center, radius, center, fractions, colors);
180: }
181:
182: /**
183: * <p>
184: *
185: * Constructs a <code>RadialGradientPaint</code>.
186: *
187: * @param cx the x coordinate in user space of the center point of the
188: * circle defining the gradient. The last color of the gradient is mapped
189: * to the perimeter of this circle
190: *
191: * @param cy the y coordinate in user space of the center point of the
192: * circle defining the gradient. The last color of the gradient is mapped
193: * to the perimeter of this circle
194: *
195: * @param radius the radius of the circle defining the extents of the
196: * color gradient
197: *
198: * @param fx the x coordinate of the point in user space to which the
199: * first color is mapped
200: *
201: * @param fy the y coordinate of the point in user space to which the
202: * first color is mapped
203: *
204: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
205: * distribution of colors along the gradient
206: *
207: * @param colors array of colors to use in the gradient. The first color
208: * is used at the focus point, the last color around the perimeter of the
209: * circle.
210: *
211: * @throws IllegalArgumentException
212: * if fractions.length != colors.length, or if colors is less
213: * than 2 in size, or if radius < 0
214: *
215: *
216: */
217: public RadialGradientPaint(float cx, float cy, float radius,
218: float fx, float fy, float[] fractions, Color[] colors) {
219: this (new Point2D.Float(cx, cy), radius, new Point2D.Float(fx,
220: fy), fractions, colors, NO_CYCLE, SRGB);
221: }
222:
223: /**
224: * <p>
225: *
226: * Constructs a <code>RadialGradientPaint</code>.
227: *
228: * @param center the center point, in user space, of the circle defining
229: * the gradient. The last color of the gradient is mapped to the perimeter
230: * of this circle
231: *
232: * @param radius the radius of the circle defining the extents of the color
233: * gradient
234: *
235: * @param focus the point, in user space, to which the first color is
236: * mapped
237: *
238: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
239: * distribution of colors along the gradient
240: *
241: * @param colors array of colors to use in the gradient. The first color
242: * is used at the focus point, the last color around the perimeter of the
243: * circle.
244: *
245: * @throws NullPointerException if one of the points is null
246: *
247: * @throws IllegalArgumentException
248: * if fractions.length != colors.length, or if colors is less
249: * than 2 in size, or if radius < 0
250: *
251: */
252: public RadialGradientPaint(Point2D center, float radius,
253: Point2D focus, float[] fractions, Color[] colors) {
254: this (center, radius, focus, fractions, colors, NO_CYCLE, SRGB);
255: }
256:
257: /**
258: * <p>
259: *
260: * Constructs a <code>RadialGradientPaint</code>.
261: *
262: * @param center the center point in user space of the circle defining the
263: * gradient. The last color of the gradient is mapped to the perimeter of
264: * this circle
265: *
266: * @param radius the radius of the circle defining the extents of the color
267: * gradient
268: *
269: * @param focus the point in user space to which the first color is mapped
270: *
271: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
272: * distribution of colors along the gradient
273: *
274: * @param colors array of colors to use in the gradient. The first color is
275: * used at the focus point, the last color around the perimeter of the
276: * circle.
277: *
278: * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
279: *
280: * @param colorSpace which colorspace to use for interpolation,
281: * either SRGB or LINEAR_RGB
282: *
283: * @throws NullPointerException if one of the points is null
284: *
285: * @throws IllegalArgumentException
286: * if fractions.length != colors.length, or if colors is less
287: * than 2 in size, or if radius < 0
288: *
289: */
290: public RadialGradientPaint(Point2D center, float radius,
291: Point2D focus, float[] fractions, Color[] colors,
292: CycleMethodEnum cycleMethod, ColorSpaceEnum colorSpace) {
293: this (center, radius, focus, fractions, colors, cycleMethod,
294: colorSpace, new AffineTransform());
295: }
296:
297: /**
298: * <p>
299: *
300: * Constructs a <code>RadialGradientPaint</code>.
301: *
302: * @param center the center point in user space of the circle defining the
303: * gradient. The last color of the gradient is mapped to the perimeter of
304: * this circle
305: *
306: * @param radius the radius of the circle defining the extents of the color
307: * gradient.
308: *
309: * @param focus the point in user space to which the first color is mapped
310: *
311: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
312: * distribution of colors along the gradient
313: *
314: * @param colors array of colors to use in the gradient. The first color is
315: * used at the focus point, the last color around the perimeter of the
316: * circle.
317: *
318: * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
319: *
320: * @param colorSpace which colorspace to use for interpolation,
321: * either SRGB or LINEAR_RGB
322: *
323: * @param gradientTransform transform to apply to the gradient
324: *
325: * @throws NullPointerException if one of the points is null,
326: * or gradientTransform is null
327: *
328: * @throws IllegalArgumentException
329: * if fractions.length != colors.length, or if colors is less
330: * than 2 in size, or if radius < 0
331: *
332: */
333: public RadialGradientPaint(Point2D center, float radius,
334: Point2D focus, float[] fractions, Color[] colors,
335: CycleMethodEnum cycleMethod, ColorSpaceEnum colorSpace,
336: AffineTransform gradientTransform) {
337: super (fractions, colors, cycleMethod, colorSpace,
338: gradientTransform);
339:
340: // Check input arguments
341: if (center == null) {
342: throw new NullPointerException(
343: "Center point should not be null.");
344: }
345:
346: if (focus == null) {
347: throw new NullPointerException(
348: "Focus point should not be null.");
349: }
350:
351: if (radius <= 0) {
352: throw new IllegalArgumentException(
353: "radius should be greater than zero");
354: }
355:
356: //copy parameters
357: this .center = (Point2D) center.clone();
358: this .focus = (Point2D) focus.clone();
359: this .radius = radius;
360: }
361:
362: /**
363: * <p>
364: *
365: * Constructs a <code>RadialGradientPaint</code>, the gradient circle is
366: * defined by a bounding box.
367: *
368: * @param gradientBounds the bounding box, in user space, of the circle
369: * defining outermost extent of the gradient.
370: *
371: * @param fractions numbers ranging from 0.0 to 1.0 specifying the
372: * distribution of colors along the gradient
373: *
374: * @param colors array of colors to use in the gradient. The first color
375: * is used at the focus point, the last color around the perimeter of the
376: * circle.
377: *
378: * @throws NullPointerException if the gradientBounds is null
379: *
380: * @throws IllegalArgumentException
381: * if fractions.length != colors.length, or if colors is less
382: * than 2 in size, or if radius < 0
383: *
384: */
385: public RadialGradientPaint(Rectangle2D gradientBounds,
386: float[] fractions, Color[] colors) {
387:
388: //calculate center point and radius based on bounding box coordinates.
389: this ((float) gradientBounds.getX()
390: + ((float) gradientBounds.getWidth() / 2),
391:
392: (float) gradientBounds.getY()
393: + ((float) gradientBounds.getWidth() / 2),
394:
395: (float) gradientBounds.getWidth() / 2, fractions, colors);
396: }
397:
398: /** <p>
399: * Creates and returns a PaintContext used to generate the color pattern,
400: * for use by the internal rendering engine.
401: *
402: * @param cm {@link ColorModel} that receives
403: * the <code>Paint</code> data. This is used only as a hint.
404: *
405: * @param deviceBounds the device space bounding box of the
406: * graphics primitive being rendered
407: *
408: * @param userBounds the user space bounding box of the
409: * graphics primitive being rendered
410: *
411: * @param transform the {@link AffineTransform} from user
412: * space into device space
413: *
414: * @param hints the hints that the context object uses to choose
415: * between rendering alternatives
416: *
417: * @return the {@link PaintContext} that generates color patterns.
418: *
419: * @throws IllegalArgumentException if the transform is not invertible
420: *
421: * @see PaintContext
422: */
423: public PaintContext createContext(ColorModel cm,
424: Rectangle deviceBounds, Rectangle2D userBounds,
425: AffineTransform transform, RenderingHints hints) {
426: // Can't modify the transform passed in...
427: transform = new AffineTransform(transform);
428: // incorporate the gradient transform
429: transform.concatenate(gradientTransform);
430:
431: try {
432: return new RadialGradientPaintContext(cm, deviceBounds,
433: userBounds, transform, hints,
434: (float) center.getX(), (float) center.getY(),
435: radius, (float) focus.getX(), (float) focus.getY(),
436: fractions, colors, cycleMethod, colorSpace);
437: }
438:
439: catch (NoninvertibleTransformException e) {
440: throw new IllegalArgumentException("transform should be "
441: + "invertible");
442: }
443: }
444:
445: /**
446: * Returns a copy of the center point of the radial gradient.
447: * @return a {@link Point2D} object that is a copy of the center point
448: */
449: public Point2D getCenterPoint() {
450: return new Point2D.Double(center.getX(), center.getY());
451: }
452:
453: /** Returns a copy of the end point of the gradient axis.
454: * @return a {@link Point2D} object that is a copy of the focus point
455: */
456: public Point2D getFocusPoint() {
457: return new Point2D.Double(focus.getX(), focus.getY());
458: }
459:
460: /** Returns the radius of the circle defining the radial gradient.
461: * @return the radius of the circle defining the radial gradient
462: */
463: public float getRadius() {
464: return radius;
465: }
466:
467: }
|