1/*
2 * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package java.awt;
27
28import java.awt.geom.AffineTransform;
29import java.awt.geom.Point2D;
30import java.awt.geom.Rectangle2D;
31import java.awt.image.ColorModel;
32import java.beans.ConstructorProperties;
33
34/**
35 * The {@code RadialGradientPaint} class provides a way to fill a shape with
36 * a circular radial color gradient pattern. The user may specify 2 or more
37 * gradient colors, and this paint will provide an interpolation between
38 * each color.
39 * <p>
40 * The user must specify the circle controlling the gradient pattern,
41 * which is described by a center point and a radius.  The user can also
42 * specify a separate focus point within that circle, which controls the
43 * location of the first color of the gradient.  By default the focus is
44 * set to be the center of the circle.
45 * <p>
46 * This paint will map the first color of the gradient to the focus point,
47 * and the last color to the perimeter of the circle, interpolating
48 * smoothly for any in-between colors specified by the user.  Any line drawn
49 * from the focus point to the circumference will thus span all the gradient
50 * colors.
51 * <p>
52 * Specifying a focus point outside of the radius of the circle will cause
53 * the rings of the gradient pattern to be centered on the point just inside
54 * the edge of the circle in the direction of the focus point.
55 * The rendering will internally use this modified location as if it were
56 * the specified focus point.
57 * <p>
58 * The user must provide an array of floats specifying how to distribute the
59 * colors along the gradient.  These values should range from 0.0 to 1.0 and
60 * act like keyframes along the gradient (they mark where the gradient should
61 * be exactly a particular color).
62 * <p>
63 * In the event that the user does not set the first keyframe value equal
64 * to 0 and/or the last keyframe value equal to 1, keyframes will be created
65 * at these positions and the first and last colors will be replicated there.
66 * So, if a user specifies the following arrays to construct a gradient:<br>
67 * <pre>
68 *     {Color.BLUE, Color.RED}, {.3f, .7f}
69 * </pre>
70 * this will be converted to a gradient with the following keyframes:<br>
71 * <pre>
72 *     {Color.BLUE, Color.BLUE, Color.RED, Color.RED}, {0f, .3f, .7f, 1f}
73 * </pre>
74 *
75 * <p>
76 * The user may also select what action the {@code RadialGradientPaint} object
77 * takes when it is filling the space outside the circle's radius by
78 * setting {@code CycleMethod} to either {@code REFLECTION} or {@code REPEAT}.
79 * The gradient color proportions are equal for any particular line drawn
80 * from the focus point. The following figure shows that the distance AB
81 * is equal to the distance BC, and the distance AD is equal to the distance DE.
82 * <p style="text-align:center">
83 * <img src = "doc-files/RadialGradientPaint-3.png" alt="image showing the
84 * distance AB=BC, and AD=DE">
85 * <p>
86 * If the gradient and graphics rendering transforms are uniformly scaled and
87 * the user sets the focus so that it coincides with the center of the circle,
88 * the gradient color proportions are equal for any line drawn from the center.
89 * The following figure shows the distances AB, BC, AD, and DE. They are all equal.
90 * <p style="text-align:center">
91 * <img src = "doc-files/RadialGradientPaint-4.png" alt="image showing the
92 * distance of AB, BC, AD, and DE are all equal">
93 * <p>
94 * Note that some minor variations in distances may occur due to sampling at
95 * the granularity of a pixel.
96 * If no cycle method is specified, {@code NO_CYCLE} will be chosen by
97 * default, which means the last keyframe color will be used to fill the
98 * remaining area.
99 * <p>
100 * The colorSpace parameter allows the user to specify in which colorspace
101 * the interpolation should be performed, default sRGB or linearized RGB.
102 *
103 * <p>
104 * The following code demonstrates typical usage of
105 * {@code RadialGradientPaint}, where the center and focus points are
106 * the same:
107 * <pre>
108 *     Point2D center = new Point2D.Float(50, 50);
109 *     float radius = 25;
110 *     float[] dist = {0.0f, 0.2f, 1.0f};
111 *     Color[] colors = {Color.RED, Color.WHITE, Color.BLUE};
112 *     RadialGradientPaint p =
113 *         new RadialGradientPaint(center, radius, dist, colors);
114 * </pre>
115 *
116 * <p>
117 * This image demonstrates the example code above, with default
118 * (centered) focus for each of the three cycle methods:
119 * <p style="text-align:center">
120 * <img src = "doc-files/RadialGradientPaint-1.png" alt="image showing the
121 * output of the sameple code">
122 * <p>
123 * It is also possible to specify a non-centered focus point, as
124 * in the following code:
125 * <pre>
126 *     Point2D center = new Point2D.Float(50, 50);
127 *     float radius = 25;
128 *     Point2D focus = new Point2D.Float(40, 40);
129 *     float[] dist = {0.0f, 0.2f, 1.0f};
130 *     Color[] colors = {Color.RED, Color.WHITE, Color.BLUE};
131 *     RadialGradientPaint p =
132 *         new RadialGradientPaint(center, radius, focus,
133 *                                 dist, colors,
134 *                                 CycleMethod.NO_CYCLE);
135 * </pre>
136 *
137 * <p>
138 * This image demonstrates the previous example code, with non-centered
139 * focus for each of the three cycle methods:
140 * <p style="text-align:center">
141 * <img src = "doc-files/RadialGradientPaint-2.png" alt="image showing the
142 * output of the sample code">
143 *
144 * @see java.awt.Paint
145 * @see java.awt.Graphics2D#setPaint
146 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
147 * @since 1.6
148 */
149public final class RadialGradientPaint extends MultipleGradientPaint {
150
151    /** Focus point which defines the 0% gradient stop X coordinate. */
152    private final Point2D focus;
153
154    /** Center of the circle defining the 100% gradient stop X coordinate. */
155    private final Point2D center;
156
157    /** Radius of the outermost circle defining the 100% gradient stop. */
158    private final float radius;
159
160    /**
161     * Constructs a {@code RadialGradientPaint} with a default
162     * {@code NO_CYCLE} repeating method and {@code SRGB} color space,
163     * using the center as the focus point.
164     *
165     * @param cx the X coordinate in user space of the center point of the
166     *           circle defining the gradient.  The last color of the
167     *           gradient is mapped to the perimeter of this circle.
168     * @param cy the Y coordinate in user space of the center point of the
169     *           circle defining the gradient.  The last color of the
170     *           gradient is mapped to the perimeter of this circle.
171     * @param radius the radius of the circle defining the extents of the
172     *               color gradient
173     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
174     *                  distribution of colors along the gradient
175     * @param colors array of colors to use in the gradient.  The first color
176     *               is used at the focus point, the last color around the
177     *               perimeter of the circle.
178     *
179     * @throws NullPointerException
180     * if {@code fractions} array is null,
181     * or {@code colors} array is null
182     * @throws IllegalArgumentException
183     * if {@code radius} is non-positive,
184     * or {@code fractions.length != colors.length},
185     * or {@code colors} is less than 2 in size,
186     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
187     * or the {@code fractions} are not provided in strictly increasing order
188     */
189    public RadialGradientPaint(float cx, float cy, float radius,
190                               float[] fractions, Color[] colors)
191    {
192        this(cx, cy,
193             radius,
194             cx, cy,
195             fractions,
196             colors,
197             CycleMethod.NO_CYCLE);
198    }
199
200    /**
201     * Constructs a {@code RadialGradientPaint} with a default
202     * {@code NO_CYCLE} repeating method and {@code SRGB} color space,
203     * using the center as the focus point.
204     *
205     * @param center the center point, in user space, of the circle defining
206     *               the gradient
207     * @param radius the radius of the circle defining the extents of the
208     *               color gradient
209     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
210     *                  distribution of colors along the gradient
211     * @param colors array of colors to use in the gradient.  The first color
212     *               is used at the focus point, the last color around the
213     *               perimeter of the circle.
214     *
215     * @throws NullPointerException
216     * if {@code center} point is null,
217     * or {@code fractions} array is null,
218     * or {@code colors} array is null
219     * @throws IllegalArgumentException
220     * if {@code radius} is non-positive,
221     * or {@code fractions.length != colors.length},
222     * or {@code colors} is less than 2 in size,
223     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
224     * or the {@code fractions} are not provided in strictly increasing order
225     */
226    public RadialGradientPaint(Point2D center, float radius,
227                               float[] fractions, Color[] colors)
228    {
229        this(center,
230             radius,
231             center,
232             fractions,
233             colors,
234             CycleMethod.NO_CYCLE);
235    }
236
237    /**
238     * Constructs a {@code RadialGradientPaint} with a default
239     * {@code SRGB} color space, using the center as the focus point.
240     *
241     * @param cx the X coordinate in user space of the center point of the
242     *           circle defining the gradient.  The last color of the
243     *           gradient is mapped to the perimeter of this circle.
244     * @param cy the Y coordinate in user space of the center point of the
245     *           circle defining the gradient.  The last color of the
246     *           gradient is mapped to the perimeter of this circle.
247     * @param radius the radius of the circle defining the extents of the
248     *               color gradient
249     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
250     *                  distribution of colors along the gradient
251     * @param colors array of colors to use in the gradient.  The first color
252     *               is used at the focus point, the last color around the
253     *               perimeter of the circle.
254     * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
255     *                    or {@code REPEAT}
256     *
257     * @throws NullPointerException
258     * if {@code fractions} array is null,
259     * or {@code colors} array is null,
260     * or {@code cycleMethod} is null
261     * @throws IllegalArgumentException
262     * if {@code radius} is non-positive,
263     * or {@code fractions.length != colors.length},
264     * or {@code colors} is less than 2 in size,
265     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
266     * or the {@code fractions} are not provided in strictly increasing order
267     */
268    public RadialGradientPaint(float cx, float cy, float radius,
269                               float[] fractions, Color[] colors,
270                               CycleMethod cycleMethod)
271    {
272        this(cx, cy,
273             radius,
274             cx, cy,
275             fractions,
276             colors,
277             cycleMethod);
278    }
279
280    /**
281     * Constructs a {@code RadialGradientPaint} with a default
282     * {@code SRGB} color space, using the center as the focus point.
283     *
284     * @param center the center point, in user space, of the circle defining
285     *               the gradient
286     * @param radius the radius of the circle defining the extents of the
287     *               color gradient
288     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
289     *                  distribution of colors along the gradient
290     * @param colors array of colors to use in the gradient.  The first color
291     *               is used at the focus point, the last color around the
292     *               perimeter of the circle.
293     * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
294     *                    or {@code REPEAT}
295     *
296     * @throws NullPointerException
297     * if {@code center} point is null,
298     * or {@code fractions} array is null,
299     * or {@code colors} array is null,
300     * or {@code cycleMethod} is null
301     * @throws IllegalArgumentException
302     * if {@code radius} is non-positive,
303     * or {@code fractions.length != colors.length},
304     * or {@code colors} is less than 2 in size,
305     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
306     * or the {@code fractions} are not provided in strictly increasing order
307     */
308    public RadialGradientPaint(Point2D center, float radius,
309                               float[] fractions, Color[] colors,
310                               CycleMethod cycleMethod)
311    {
312        this(center,
313             radius,
314             center,
315             fractions,
316             colors,
317             cycleMethod);
318    }
319
320    /**
321     * Constructs a {@code RadialGradientPaint} with a default
322     * {@code SRGB} color space.
323     *
324     * @param cx the X coordinate in user space of the center point of the
325     *           circle defining the gradient.  The last color of the
326     *           gradient is mapped to the perimeter of this circle.
327     * @param cy the Y coordinate in user space of the center point of the
328     *           circle defining the gradient.  The last color of the
329     *           gradient is mapped to the perimeter of this circle.
330     * @param radius the radius of the circle defining the extents of the
331     *               color gradient
332     * @param fx the X coordinate of the point in user space to which the
333     *           first color is mapped
334     * @param fy the Y coordinate of the point in user space to which the
335     *           first color is mapped
336     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
337     *                  distribution of colors along the gradient
338     * @param colors array of colors to use in the gradient.  The first color
339     *               is used at the focus point, the last color around the
340     *               perimeter of the circle.
341     * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
342     *                    or {@code REPEAT}
343     *
344     * @throws NullPointerException
345     * if {@code fractions} array is null,
346     * or {@code colors} array is null,
347     * or {@code cycleMethod} is null
348     * @throws IllegalArgumentException
349     * if {@code radius} is non-positive,
350     * or {@code fractions.length != colors.length},
351     * or {@code colors} is less than 2 in size,
352     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
353     * or the {@code fractions} are not provided in strictly increasing order
354     */
355    public RadialGradientPaint(float cx, float cy, float radius,
356                               float fx, float fy,
357                               float[] fractions, Color[] colors,
358                               CycleMethod cycleMethod)
359    {
360        this(new Point2D.Float(cx, cy),
361             radius,
362             new Point2D.Float(fx, fy),
363             fractions,
364             colors,
365             cycleMethod);
366    }
367
368    /**
369     * Constructs a {@code RadialGradientPaint} with a default
370     * {@code SRGB} color space.
371     *
372     * @param center the center point, in user space, of the circle defining
373     *               the gradient.  The last color of the gradient is mapped
374     *               to the perimeter of this circle.
375     * @param radius the radius of the circle defining the extents of the color
376     *               gradient
377     * @param focus the point in user space to which the first color is mapped
378     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
379     *                  distribution of colors along the gradient
380     * @param colors array of colors to use in the gradient. The first color
381     *               is used at the focus point, the last color around the
382     *               perimeter of the circle.
383     * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
384     *                    or {@code REPEAT}
385     *
386     * @throws NullPointerException
387     * if one of the points is null,
388     * or {@code fractions} array is null,
389     * or {@code colors} array is null,
390     * or {@code cycleMethod} is null
391     * @throws IllegalArgumentException
392     * if {@code radius} is non-positive,
393     * or {@code fractions.length != colors.length},
394     * or {@code colors} is less than 2 in size,
395     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
396     * or the {@code fractions} are not provided in strictly increasing order
397     */
398    public RadialGradientPaint(Point2D center, float radius,
399                               Point2D focus,
400                               float[] fractions, Color[] colors,
401                               CycleMethod cycleMethod)
402    {
403        this(center,
404             radius,
405             focus,
406             fractions,
407             colors,
408             cycleMethod,
409             ColorSpaceType.SRGB,
410             new AffineTransform());
411    }
412
413    /**
414     * Constructs a {@code RadialGradientPaint}.
415     *
416     * @param center the center point in user space of the circle defining the
417     *               gradient.  The last color of the gradient is mapped to
418     *               the perimeter of this circle.
419     * @param radius the radius of the circle defining the extents of the
420     *               color gradient
421     * @param focus the point in user space to which the first color is mapped
422     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
423     *                  distribution of colors along the gradient
424     * @param colors array of colors to use in the gradient.  The first color
425     *               is used at the focus point, the last color around the
426     *               perimeter of the circle.
427     * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
428     *                    or {@code REPEAT}
429     * @param colorSpace which color space to use for interpolation,
430     *                   either {@code SRGB} or {@code LINEAR_RGB}
431     * @param gradientTransform transform to apply to the gradient
432     *
433     * @throws NullPointerException
434     * if one of the points is null,
435     * or {@code fractions} array is null,
436     * or {@code colors} array is null,
437     * or {@code cycleMethod} is null,
438     * or {@code colorSpace} is null,
439     * or {@code gradientTransform} is null
440     * @throws IllegalArgumentException
441     * if {@code radius} is non-positive,
442     * or {@code fractions.length != colors.length},
443     * or {@code colors} is less than 2 in size,
444     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
445     * or the {@code fractions} are not provided in strictly increasing order
446     */
447    @ConstructorProperties({ "centerPoint", "radius", "focusPoint", "fractions", "colors", "cycleMethod", "colorSpace", "transform" })
448    public RadialGradientPaint(Point2D center,
449                               float radius,
450                               Point2D focus,
451                               float[] fractions, Color[] colors,
452                               CycleMethod cycleMethod,
453                               ColorSpaceType colorSpace,
454                               AffineTransform gradientTransform)
455    {
456        super(fractions, colors, cycleMethod, colorSpace, gradientTransform);
457
458        // check input arguments
459        if (center == null) {
460            throw new NullPointerException("Center point must be non-null");
461        }
462
463        if (focus == null) {
464            throw new NullPointerException("Focus point must be non-null");
465        }
466
467        if (radius <= 0) {
468            throw new IllegalArgumentException("Radius must be greater " +
469                                               "than zero");
470        }
471
472        // copy parameters
473        this.center = new Point2D.Double(center.getX(), center.getY());
474        this.focus = new Point2D.Double(focus.getX(), focus.getY());
475        this.radius = radius;
476    }
477
478    /**
479     * Constructs a {@code RadialGradientPaint} with a default
480     * {@code SRGB} color space.
481     * The gradient circle of the {@code RadialGradientPaint} is defined
482     * by the given bounding box.
483     * <p>
484     * This constructor is a more convenient way to express the
485     * following (equivalent) code:<br>
486     *
487     * <pre>
488     *     double gw = gradientBounds.getWidth();
489     *     double gh = gradientBounds.getHeight();
490     *     double cx = gradientBounds.getCenterX();
491     *     double cy = gradientBounds.getCenterY();
492     *     Point2D center = new Point2D.Double(cx, cy);
493     *
494     *     AffineTransform gradientTransform = new AffineTransform();
495     *     gradientTransform.translate(cx, cy);
496     *     gradientTransform.scale(gw / 2, gh / 2);
497     *     gradientTransform.translate(-cx, -cy);
498     *
499     *     RadialGradientPaint gp =
500     *         new RadialGradientPaint(center, 1.0f, center,
501     *                                 fractions, colors,
502     *                                 cycleMethod,
503     *                                 ColorSpaceType.SRGB,
504     *                                 gradientTransform);
505     * </pre>
506     *
507     * @param gradientBounds the bounding box, in user space, of the circle
508     *                       defining the outermost extent of the gradient
509     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
510     *                  distribution of colors along the gradient
511     * @param colors array of colors to use in the gradient.  The first color
512     *               is used at the focus point, the last color around the
513     *               perimeter of the circle.
514     * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
515     *                    or {@code REPEAT}
516     *
517     * @throws NullPointerException
518     * if {@code gradientBounds} is null,
519     * or {@code fractions} array is null,
520     * or {@code colors} array is null,
521     * or {@code cycleMethod} is null
522     * @throws IllegalArgumentException
523     * if {@code gradientBounds} is empty,
524     * or {@code fractions.length != colors.length},
525     * or {@code colors} is less than 2 in size,
526     * or a {@code fractions} value is less than 0.0 or greater than 1.0,
527     * or the {@code fractions} are not provided in strictly increasing order
528     */
529    public RadialGradientPaint(Rectangle2D gradientBounds,
530                               float[] fractions, Color[] colors,
531                               CycleMethod cycleMethod)
532    {
533        // gradient center/focal point is the center of the bounding box,
534        // radius is set to 1.0, and then we set a scale transform
535        // to achieve an elliptical gradient defined by the bounding box
536        this(new Point2D.Double(gradientBounds.getCenterX(),
537                                gradientBounds.getCenterY()),
538             1.0f,
539             new Point2D.Double(gradientBounds.getCenterX(),
540                                gradientBounds.getCenterY()),
541             fractions,
542             colors,
543             cycleMethod,
544             ColorSpaceType.SRGB,
545             createGradientTransform(gradientBounds));
546
547        if (gradientBounds.isEmpty()) {
548            throw new IllegalArgumentException("Gradient bounds must be " +
549                                               "non-empty");
550        }
551    }
552
553    private static AffineTransform createGradientTransform(Rectangle2D r) {
554        double cx = r.getCenterX();
555        double cy = r.getCenterY();
556        AffineTransform xform = AffineTransform.getTranslateInstance(cx, cy);
557        xform.scale(r.getWidth()/2, r.getHeight()/2);
558        xform.translate(-cx, -cy);
559        return xform;
560    }
561
562    /**
563     * Creates and returns a {@link PaintContext} used to
564     * generate a circular radial color gradient pattern.
565     * See the description of the {@link Paint#createContext createContext} method
566     * for information on null parameter handling.
567     *
568     * @param cm the preferred {@link ColorModel} which represents the most convenient
569     *           format for the caller to receive the pixel data, or {@code null}
570     *           if there is no preference.
571     * @param deviceBounds the device space bounding box
572     *                     of the graphics primitive being rendered.
573     * @param userBounds the user space bounding box
574     *                   of the graphics primitive being rendered.
575     * @param transform the {@link AffineTransform} from user
576     *              space into device space.
577     * @param hints the set of hints that the context object can use to
578     *              choose between rendering alternatives.
579     * @return the {@code PaintContext} for
580     *         generating color patterns.
581     * @see Paint
582     * @see PaintContext
583     * @see ColorModel
584     * @see Rectangle
585     * @see Rectangle2D
586     * @see AffineTransform
587     * @see RenderingHints
588     */
589    public PaintContext createContext(ColorModel cm,
590                                      Rectangle deviceBounds,
591                                      Rectangle2D userBounds,
592                                      AffineTransform transform,
593                                      RenderingHints hints)
594    {
595        // avoid modifying the user's transform...
596        transform = new AffineTransform(transform);
597        // incorporate the gradient transform
598        transform.concatenate(gradientTransform);
599
600        return new RadialGradientPaintContext(this, cm,
601                                              deviceBounds, userBounds,
602                                              transform, hints,
603                                              (float)center.getX(),
604                                              (float)center.getY(),
605                                              radius,
606                                              (float)focus.getX(),
607                                              (float)focus.getY(),
608                                              fractions, colors,
609                                              cycleMethod, colorSpace);
610    }
611
612    /**
613     * Returns a copy of the center point of the radial gradient.
614     *
615     * @return a {@code Point2D} object that is a copy of the center point
616     */
617    public Point2D getCenterPoint() {
618        return new Point2D.Double(center.getX(), center.getY());
619    }
620
621    /**
622     * Returns a copy of the focus point of the radial gradient.
623     * Note that if the focus point specified when the radial gradient
624     * was constructed lies outside of the radius of the circle, this
625     * method will still return the original focus point even though
626     * the rendering may center the rings of color on a different
627     * point that lies inside the radius.
628     *
629     * @return a {@code Point2D} object that is a copy of the focus point
630     */
631    public Point2D getFocusPoint() {
632        return new Point2D.Double(focus.getX(), focus.getY());
633    }
634
635    /**
636     * Returns the radius of the circle defining the radial gradient.
637     *
638     * @return the radius of the circle defining the radial gradient
639     */
640    public float getRadius() {
641        return radius;
642    }
643}
644