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