Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8360047

Allow interpolation outside of range [0,1]

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Unresolved
    • Icon: P4 P4
    • jfx26
    • javafx
    • None
    • behavioral
    • minimal
    • Hide
      Third-party implementations of `Interpolatable` may work incorrectly for interpolation factors outside of [0,1]. However, no valid JavaFX program can currently produce such interpolation factors in animations (as this capability is only added with this enhancement). Therefore, no existing JavaFX program will be accidentally affected by this change; only new programs that specifically decide to use cubic Beziér functions with values outside of [0,1] must ensure that all interpolators behave correctly. In practice, this shouldn't be a problem as it is very unlikely that a third-party implementation would fail by throwing an exception. A GitHub search yielded no such example.
      Show
      Third-party implementations of `Interpolatable` may work incorrectly for interpolation factors outside of [0,1]. However, no valid JavaFX program can currently produce such interpolation factors in animations (as this capability is only added with this enhancement). Therefore, no existing JavaFX program will be accidentally affected by this change; only new programs that specifically decide to use cubic Beziér functions with values outside of [0,1] must ensure that all interpolators behave correctly. In practice, this shouldn't be a problem as it is very unlikely that a third-party implementation would fail by throwing an exception. A GitHub search yielded no such example.
    • Java API
    • JDK

      Summary

      Allow interpolation outside of range [0,1], and accept cubic Bézier functions with control points outside of range [0,1] on the Y axis (output progress).

      Problem

      JavaFX unnecessarily restricts interpolation in the following ways:

      • Interpolatable implementations often clamp intermediate values to the interpolation factor range [0,1].

      • SplineInterpolator doesn't accept Y coordinates outside of [0,1] for its control points. While this was probably done so that the computed interpolation factor doesn't exceed [0,1], the restriction goes far beyond that. For example, the following function is not representable, even though its values are all within the [0,1] range: <cubic-bezier-1.png>. The following function is also not representable, but would be very useful for bouncy animations: <cubic-bezier-2.png>.

      Solution

      Fortunately, there is no technical reason why JavaFX can't support the full range of animations that can be represented with a cubic Beziér interpolation function.

      1. The specification of Interpolatable is changed to require implementations to accept interpolation factors outside of [0,1].
      2. All implementations of Interpolatable now correctly return intermediate values outside of [0,1].
      3. SplineInterpolator accepts control points with any Y coordinate (it was never specified that it should reject Y coordinates outside of [0,1]).

      Specification

      --- a/modules/javafx.graphics/src/main/java/javafx/animation/Interpolatable.java
      +++ b/modules/javafx.graphics/src/main/java/javafx/animation/Interpolatable.java
      @@ -39,10 +39,10 @@
        *                 {@link #interpolate(Object, double)} method.</td>
        *         </tr>
        *         <tr><td style="vertical-align: top"><a id="linear" style="white-space: nowrap">linear</a></td>
      - *             <td>Two components are combined by linear interpolation such that {@code t = 0} produces
      - *                 the start value, {@code t = 1} produces the end value, and {@code 0 < t < 1} produces
      - *                 {@code (1 - t) * start + t * end}. This interpolation type is usually applicable for
      - *                 numeric components.</td>
      + *             <td>Two components are combined by linear interpolation such that the intermediate value is
      + *                 produced by computing {@code (1 - t) * start + t * end}. Note that this formula produces
      + *                 values less than {@code start} for {@code t < 0} and values greater than {@code end} for
      + *                 {@code t > 1}. This interpolation type is usually applicable for numeric components.</td>
        *         </tr>
        *         <tr><td style="vertical-align: top"><a id="discrete" style="white-space: nowrap">discrete</a></td>
        *             <td>If two components cannot be meaningfully combined, the intermediate component value
      @@ -70,8 +70,8 @@
      
           /**
            * Returns an intermediate value between the value of this {@code Interpolatable} and the specified
      -     * {@code endValue} using the linear interpolation factor {@code t}, ranging from 0 (inclusive)
      -     * to 1 (inclusive).
      +     * {@code endValue} using the linear interpolation factor {@code t}. The interpolation factor can
      +     * be any finite value.
            * <p>
            * The returned value might not be a new instance; the implementation might also return one of the
            * two existing instances if the intermediate value would be equal to one of the existing values.
      @@ -78,10 +78,8 @@
            * However, this is an optimization and applications should not assume any particular identity
            * of the returned value.
            *
      -     * @implSpec An implementation is not required to reject interpolation factors less than 0 or larger
      -     *           than 1, but this specification gives no meaning to values returned outside of this range.
      -     *           For example, an implementation might clamp the interpolation factor to [0..1], or it might
      -     *           continue the linear interpolation outside of this range.
      +     * @implSpec An implementation must accept any interpolation factor, but it can return a clamped
      +     *           intermediate value that falls within its value range.
            *
            * @param endValue the target value
            * @param t the interpolation factor
      --- a/modules/javafx.graphics/src/main/java/javafx/scene/paint/RadialGradient.java
      +++ b/modules/javafx.graphics/src/main/java/javafx/scene/paint/RadialGradient.java
      @@ -234,17 +234,21 @@
      
           /**
            * Creates a new instance of RadialGradient.
      +     *
            * @param focusAngle the angle in degrees from the center of the gradient
      -     * to the focus point to which the first color is mapped
      +     *                   to the focus point to which the first color is mapped
            * @param focusDistance the distance from the center of the gradient to the
      -     * focus point to which the first color is mapped
      +     *                      focus point to which the first color is mapped,
      +     *                      must be greater than or equal to zero
            * @param centerX the X coordinate of the center point of the gradient's circle
            * @param centerY the Y coordinate of the center point of the gradient's circle
      -     * @param radius the radius of the circle defining the extents of the color gradient
      +     * @param radius the radius of the circle defining the extents of the color gradient,
      +     *               must be greater than or equal to zero
            * @param proportional whether the coordinates and sizes are proportional
      -     * to the shape which this gradient fills
      +     *                     to the shape which this gradient fills
            * @param cycleMethod cycle method applied to the gradient
            * @param stops the gradient's color specification
      +     * @throws IllegalArgumentException if {@code focusDistance} or {@code radius} is negative
            */
           public RadialGradient(
                   @NamedArg("focusAngle") double focusAngle,
      @@ -255,6 +259,7 @@
                   @NamedArg(value="proportional", defaultValue="true") boolean proportional,
                   @NamedArg("cycleMethod") CycleMethod cycleMethod,
                   @NamedArg("stops") Stop... stops) {
      +        checkInvariants(radius, focusDistance);
               this.focusAngle = focusAngle;
               this.focusDistance = focusDistance;
               this.centerX = centerX;
      @@ -268,17 +273,21 @@
      
           /**
            * Creates a new instance of RadialGradient.
      +     *
            * @param focusAngle the angle in degrees from the center of the gradient
      -     * to the focus point to which the first color is mapped
      +     *                   to the focus point to which the first color is mapped
            * @param focusDistance the distance from the center of the gradient to the
      -     * focus point to which the first color is mapped
      +     *                      focus point to which the first color is mapped,
      +     *                      must be greater than or equal to zero
            * @param centerX the X coordinate of the center point of the gradient's circle
            * @param centerY the Y coordinate of the center point of the gradient's circle
      -     * @param radius the radius of the circle defining the extents of the color gradient
      +     * @param radius the radius of the circle defining the extents of the color gradient,
      +     *               must be greater than or equal to zero
            * @param proportional whether the coordinates and sizes are proportional
      -     * to the shape which this gradient fills
      +     *                     to the shape which this gradient fills
            * @param cycleMethod cycle method applied to the gradient
            * @param stops the gradient's color specification
      +     * @throws IllegalArgumentException if {@code focusDistance} or {@code radius} is negative
            */
           public RadialGradient(
                   @NamedArg("focusAngle") double focusAngle,

            mstrauss Michael Strauß
            mstrauss Michael Strauß
            Kevin Rushforth
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: