001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.ext.awt;
020:
021: import java.awt.Color;
022: import java.awt.PaintContext;
023: import java.awt.Rectangle;
024: import java.awt.RenderingHints;
025: import java.awt.geom.AffineTransform;
026: import java.awt.geom.NoninvertibleTransformException;
027: import java.awt.geom.Point2D;
028: import java.awt.geom.Rectangle2D;
029: import java.awt.image.ColorModel;
030:
031: /**
032: * <p>
033: * This class provides a way to fill a shape with a circular radial color
034: * gradient pattern. The user may specify 2 or more gradient colors, and this
035: * paint will provide an interpolation between each color.
036: * <p>
037: *
038: * The user must provide an array of floats specifying how to distribute the
039: * colors along the gradient. These values should range from 0.0 to 1.0 and
040: * act like keyframes along the gradient (they mark where the gradient should
041: * be exactly a particular color).
042: *
043: * <p>
044: * This paint will map the first color of the gradient to a focus point within
045: * the circle, and the last color to the perimeter of the circle, interpolating
046: * smoothly for any inbetween colors specified by the user. Any line drawn
047: * from the focus point to the circumference will span the all the gradient
048: * colors. By default the focus is set to be the center of the circle.
049: *
050: * <p>
051: * Specifying a focus point outside of the circle's radius will result in the
052: * focus being set to the intersection point of the focus-center line and the
053: * perimenter of the circle.
054: * <p>
055: *
056: * Specifying a cycle method allows the user to control the painting behavior
057: * outside of the bounds of the circle's radius. See LinearGradientPaint for
058: * more details.
059: *
060: * <p>
061: * The following code demonstrates typical usage of RadialGradientPaint:
062: * <p>
063: * <code>
064: * Point2D center = new Point2D.Float(0, 0);<br>
065: * float radius = 20;
066: * float[] dist = {0.0, 0.2, 1.0};<br>
067: * Color[] colors = {Color.red, Color.white, Color.blue};<br>
068: * RadialGradientPaint p = new RadialGradientPaint(center, radius,
069: * dist, colors);
070: * </code>
071: *
072: * <p> In the event that the user does not set the first keyframe value equal
073: * to 0 and the last keyframe value equal to 1, keyframes will be created at
074: * these positions and the first and last colors will be replicated there.
075: * So, if a user specifies the following arrays to construct a gradient:<br>
076: * {Color.blue, Color.red}, {.3, .7}<br>
077: * this will be converted to a gradient with the following keyframes:
078: * {Color.blue, Color.blue, Color.red, Color.red}, {0, .3, .7, 1}
079: *
080: *
081: * <p>
082: * <img src = "radial.jpg">
083: * <p>
084: * This image demonstrates a radial gradient with NO_CYCLE and default focus.
085: * <p>
086: *
087: * <img src = "radial2.jpg">
088: * <p>
089: * This image demonstrates a radial gradient with NO_CYCLE and non-centered
090: * focus.
091: * <p>
092: *
093: * <img src = "radial3.jpg">
094: * <p>
095: * This image demonstrates a radial gradient with REFLECT and non-centered
096: * focus.
097: *
098: * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
099: * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
100: * @version $Id: RadialGradientPaint.java 479573 2006-11-27 10:13:36Z dvholten $
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: }
|