Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.animation; 027 028import javafx.util.Duration; 029 030import com.sun.scenario.animation.NumberTangentInterpolator; 031import com.sun.scenario.animation.SplineInterpolator; 032 033/** 034 * The abstract class defines several {@code interpolate} methods, which are 035 * used to calculate interpolated values. Various built-in implementations of 036 * this class are offered. Applications may choose to implement their own 037 * {@code Interpolator} to get custom interpolation behavior. 038 * <p> 039 * A custom {@code Interpolator} has to be defined in terms of a " 040 * {@link #curve(double) curve()}". 041 */ 042public abstract class Interpolator { 043 044 private static final double EPSILON = 1e-12; 045 046 /** 047 * The constructor of {@code Interpolator}. 048 */ 049 protected Interpolator() { 050 } 051 052 /** 053 * Built-in interpolator that provides discrete time interpolation. The 054 * return value of {@code interpolate()} is {@code endValue} only when the 055 * input {@code fraction} is 1.0, and {@code startValue} otherwise. 056 */ 057 public static final Interpolator DISCRETE = new Interpolator() { 058 @Override 059 protected double curve(double t) { 060 return (Math.abs(t - 1.0) < EPSILON) ? 1.0 : 0.0; 061 } 062 063 @Override 064 public String toString() { 065 return "Interpolator.DISCRETE"; 066 } 067 }; 068 069 /** 070 * Built-in interpolator that provides linear time interpolation. The return 071 * value of {@code interpolate()} is {@code startValue} + ({@code endValue} 072 * - {@code startValue}) * {@code fraction}. 073 */ 074 public static final Interpolator LINEAR = new Interpolator() { 075 @Override 076 protected double curve(double t) { 077 return t; 078 } 079 080 @Override 081 public String toString() { 082 return "Interpolator.LINEAR"; 083 } 084 }; 085 086 /* 087 * Easing is calculated with the following algorithm (taken from SMIL 3.0 088 * specs). The result is clamped because of possible rounding errors. 089 * 090 * double runRate = 1.0 / (1.0 - acceleration/2.0 - deceleration/2.0); if 091 * (fraction < acceleration) { double averageRunRate = runRate * (fraction / 092 * acceleration) / 2; fraction *= averageRunRate; } else if (fraction > (1.0 093 * - deceleration)) { // time spent in deceleration portion double tdec = 094 * fraction - (1.0 - deceleration); // proportion of tdec to total 095 * deceleration time double pdec = tdec / deceleration; fraction = runRate * 096 * (1.0 - ( acceleration / 2) - deceleration + tdec * (2 - pdec) / 2); } 097 * else { fraction = runRate * (fraction - (acceleration / 2)); } 098 */ 099 100 /** 101 * Built-in interpolator instance that provides ease in/out behavior. 102 * <p> 103 * An ease-both interpolator will make an animation start slow, then 104 * accelerate and slow down again towards the end, all in a smooth manner. 105 * <p> 106 * The implementation uses the algorithm for easing defined in SMIL 3.0 107 * with an acceleration and deceleration factor of 0.2, respectively. 108 */ 109 public static final Interpolator EASE_BOTH = new Interpolator() { 110 @Override 111 protected double curve(double t) { 112 // See the SMIL 3.1 specification for details on this calculation 113 // acceleration = 0.2, deceleration = 0.2 114 return Interpolator.clamp((t < 0.2) ? 3.125 * t * t 115 : (t > 0.8) ? -3.125 * t * t + 6.25 * t - 2.125 116 : 1.25 * t - 0.125); 117 } 118 119 @Override 120 public String toString() { 121 return "Interpolator.EASE_BOTH"; 122 } 123 }; 124 /** 125 * Built-in interpolator instance that provides ease in behavior. 126 * <p> 127 * An ease-in interpolator will make an animation start slow and then 128 * accelerate smoothly. 129 * <p> 130 * The implementation uses the algorithm for easing defined in SMIL 3.0 131 * with an acceleration factor of 0.2. 132 */ 133 public static final Interpolator EASE_IN = new Interpolator() { 134 private static final double S1 = 25.0 / 9.0; 135 private static final double S3 = 10.0 / 9.0; 136 private static final double S4 = 1.0 / 9.0; 137 138 @Override 139 protected double curve(double t) { 140 // See the SMIL 3.1 specification for details on this calculation 141 // acceleration = 0.2, deceleration = 0.0 142 return Interpolator.clamp((t < 0.2) ? S1 * t * t : S3 * t - S4); 143 } 144 145 @Override 146 public String toString() { 147 return "Interpolator.EASE_IN"; 148 } 149 }; 150 151 /** 152 * Built-in interpolator instance that provides ease out behavior. 153 * <p> 154 * An ease-out interpolator will make an animation slow down toward the 155 * end smoothly. 156 * <p> 157 * The implementation uses the algorithm for easing defined in SMIL 3.0 158 * with an deceleration factor of 0.2. 159 */ 160 public static final Interpolator EASE_OUT = new Interpolator() { 161 private static final double S1 = -25.0 / 9.0; 162 private static final double S2 = 50.0 / 9.0; 163 private static final double S3 = -16.0 / 9.0; 164 private static final double S4 = 10.0 / 9.0; 165 166 @Override 167 protected double curve(double t) { 168 // See the SMIL 3.1 specification for details on this calculation 169 // acceleration = 0.2, deceleration = 0.0 170 return Interpolator.clamp((t > 0.8) ? S1 * t * t + S2 * t + S3 : S4 171 * t); 172 } 173 174 @Override 175 public String toString() { 176 return "Interpolator.EASE_OUT"; 177 } 178 }; 179 180 /** 181 * Creates an {@code Interpolator}, which {@link #curve(double) curve()} is 182 * shaped using the spline control points defined by ({@code x1}, {@code y1} 183 * ) and ({@code x2}, {@code y2}). The anchor points of the spline are 184 * implicitly defined as ({@code 0.0}, {@code 0.0}) and ({@code 1.0}, 185 * {@code 1.0}). 186 * 187 * @param x1 188 * x coordinate of the first control point 189 * @param y1 190 * y coordinate of the first control point 191 * @param x2 192 * x coordinate of the second control point 193 * @param y2 194 * y coordinate of the second control point 195 * @return A spline interpolator 196 */ 197 public static Interpolator SPLINE(double x1, double y1, double x2, double y2) { 198 return new SplineInterpolator(x1, y1, x2, y2); 199 } 200 201 /** 202 * Create a tangent interpolator. A tangent interpolator allows to define 203 * the behavior of an animation curve very precisely by defining the 204 * tangents close to a key frame. 205 * 206 * A tangent interpolator defines the behavior to the left and to the right 207 * of a key frame, therefore it is only useful within a {@link Timeline}. 208 * If used in a {@link KeyFrame} after a KeyFrame that has different interpolator, 209 * it's treated as if the out-tangent of that KeyFrame was equal to the value in the KeyFrame. 210 * 211 * <p> 212 * <img src="doc-files/tangent_interpolator.png"/> 213 * 214 * <p> 215 * The parameters define the tangent of the animation curve for the in 216 * tangent (before a key frame) and out tangent (after a key frame). Each 217 * tangent is specified with a pair, the distance to the key frame and the 218 * value of the tangent at this moment. 219 * <p> 220 * The interpolation then follows a bezier curve, with 2 control points defined by the specified tangent and 221 * positioned at 1/3 of the duration before the second KeyFrame or after the first KeyFrame. See the picture above. 222 * 223 * @param t1 224 * The delta time of the in-tangent, relative to the KeyFrame 225 * @param v1 226 * The value of the in-tangent 227 * @param t2 228 * The delta time of the out-tangent, relative to the KeyFrame 229 * @param v2 230 * The value of the out-tangent 231 * @return the new tangent interpolator 232 */ 233 public static Interpolator TANGENT(Duration t1, double v1, Duration t2, 234 double v2) { 235 return NumberTangentInterpolator.create(v1, t1, v2, t2); 236 } 237 238 /** 239 * Creates a tangent interpolator, for which in-tangent and out-tangent are 240 * identical. This is especially useful for the first and the last key frame 241 * of a {@link Timeline}, because for these key frames only one tangent is 242 * used. 243 * 244 * @see #TANGENT(Duration, double, Duration, double) 245 * 246 * @param t 247 * The delta time of the tangent 248 * @param v 249 * The value of the tangent 250 * @return the new Tangent interpolator 251 */ 252 public static Interpolator TANGENT(Duration t, double v) { 253 return NumberTangentInterpolator.create(v, t); 254 } 255 256 /** 257 * This method takes two {@code Objects} along with a {@code fraction} 258 * between {@code 0.0} and {@code 1.0} and returns the interpolated value. 259 * <p> 260 * If both {@code Objects} implement {@code Number}, their values are 261 * interpolated. If {@code startValue} implements {@link Interpolatable} the 262 * calculation defined in {@link Interpolatable#interpolate(Object, double) 263 * interpolate()} is used. If neither of these conditions are met, a 264 * discrete interpolation is used, i.e. {@code endValue} is returned if and 265 * only if {@code fraction} is {@code 1.0}, otherwise {@code startValue} is 266 * returned. 267 * <p> 268 * Before calculating the interpolated value, the fraction is altered 269 * according to the function defined in {@link #curve(double) curve()}. 270 * 271 * @param startValue 272 * start value 273 * @param endValue 274 * end value 275 * @param fraction 276 * a value between 0.0 and 1.0 277 * @return interpolated value 278 */ 279 @SuppressWarnings({ "unchecked", "rawtypes" }) 280 public Object interpolate(Object startValue, Object endValue, 281 double fraction) { 282 if ((startValue instanceof Number) && (endValue instanceof Number)) { 283 final double start = ((Number) startValue).doubleValue(); 284 final double end = ((Number) endValue).doubleValue(); 285 final double val = start + (end - start) * curve(fraction); 286 if ((startValue instanceof Double) || (endValue instanceof Double)) { 287 return Double.valueOf(val); 288 } 289 if ((startValue instanceof Float) || (endValue instanceof Float)) { 290 return Float.valueOf((float) val); 291 } 292 if ((startValue instanceof Long) || (endValue instanceof Long)) { 293 return Long.valueOf(Math.round(val)); 294 } 295 return Integer.valueOf((int) Math.round(val)); 296 } else if ((startValue instanceof Interpolatable) && (endValue instanceof Interpolatable)) { 297 return ((Interpolatable) startValue).interpolate(endValue, 298 curve(fraction)); 299 } else { 300 // discrete 301 return (curve(fraction) == 1.0) ? endValue : startValue; 302 } 303 } 304 305 /** 306 * This method takes two {@code boolean} values along with a 307 * {@code fraction} between {@code 0.0} and {@code 1.0} and returns the 308 * interpolated value. 309 * <p> 310 * Before calculating the interpolated value, the fraction is altered 311 * according to the function defined in {@link #curve(double) curve()}. 312 * 313 * @param startValue 314 * the first data point 315 * @param endValue 316 * the second data point 317 * @param fraction 318 * the fraction in {@code [0.0...1.0]} 319 */ 320 public boolean interpolate(boolean startValue, boolean endValue, 321 double fraction) { 322 return (Math.abs(curve(fraction) - 1.0) < EPSILON) ? endValue 323 : startValue; 324 } 325 326 /** 327 * This method takes two {@code double} values along with a {@code fraction} 328 * between {@code 0.0} and {@code 1.0} and returns the interpolated value. 329 * <p> 330 * Before calculating the interpolated value, the fraction is altered 331 * according to the function defined in {@link #curve(double) curve()}. 332 * 333 * @param startValue 334 * the first data point 335 * @param endValue 336 * the second data point 337 * @param fraction 338 * the fraction in {@code [0.0...1.0]} 339 */ 340 public double interpolate(double startValue, double endValue, 341 double fraction) { 342 return startValue + (endValue - startValue) * curve(fraction); 343 } 344 345 /** 346 * This method takes two {@code int} values along with a {@code fraction} 347 * between {@code 0.0} and {@code 1.0} and returns the interpolated value. 348 * <p> 349 * Before calculating the interpolated value, the fraction is altered 350 * according to the function defined in {@link #curve(double) curve()}. 351 * 352 * @param startValue 353 * the first data point 354 * @param endValue 355 * the second data point 356 * @param fraction 357 * the fraction in {@code [0.0...1.0]} 358 */ 359 public int interpolate(int startValue, int endValue, double fraction) { 360 return startValue 361 + (int) Math.round((endValue - startValue) * curve(fraction)); 362 } 363 364 /** 365 * This method takes two {@code int} values along with a {@code fraction} 366 * between {@code 0.0} and {@code 1.0} and returns the interpolated value. 367 * <p> 368 * Before calculating the interpolated value, the fraction is altered 369 * according to the function defined in {@link #curve(double) curve()}. 370 * 371 * @param startValue 372 * the first data point 373 * @param endValue 374 * the second data point 375 * @param fraction 376 * the fraction in {@code [0.0...1.0]} 377 */ 378 public long interpolate(long startValue, long endValue, 379 double fraction) { 380 return startValue 381 + Math.round((endValue - startValue) * curve(fraction)); 382 } 383 384 private static double clamp(double t) { 385 return (t < 0.0) ? 0.0 : (t > 1.0) ? 1.0 : t; 386 } 387 388 /** 389 * Mapping from [0.0..1.0] to itself. 390 * 391 * @param t 392 * time, but normalized to the range [0.0..1.0], where 0.0 is the 393 * start of the current interval, while 1.0 is the end of the 394 * current interval. Usually a function that increases 395 * monotonically. 396 */ 397 protected abstract double curve(double t); 398 399}