1 30 31 package com.jgoodies.animation; 32 33 import java.awt.Color ; 34 import java.util.Collections ; 35 import java.util.Iterator ; 36 import java.util.LinkedList ; 37 import java.util.List ; 38 import java.util.Random ; 39 40 49 public final class AnimationFunctions { 50 51 55 public static final AnimationFunction ONE = 56 constant(Integer.MAX_VALUE, new Float (1.0f)); 57 58 62 public static final AnimationFunction ZERO = 63 constant(Integer.MAX_VALUE, new Float (0.0f)); 64 65 66 private AnimationFunctions() { 67 } 69 70 71 82 public static AnimationFunction alphaColor( 83 AnimationFunction f, 84 Color baseColor) { 85 return new AlphaColorAnimationFunction(f, baseColor); 86 } 87 88 95 public static FloatFunction asFloat(AnimationFunction f) { 96 return new FloatFunction(f); 97 } 98 99 107 public static AnimationFunction concat( 108 AnimationFunction first, 109 AnimationFunction second) { 110 List sequence = new LinkedList (); 111 sequence.add(first); 112 sequence.add(second); 113 return new SequencedAnimationFunction(sequence); 114 } 115 116 124 public static AnimationFunction constant(long duration, Object value) { 125 return discrete(duration, new Object [] { value }); 126 } 127 128 137 public static AnimationFunction discrete( 138 long duration, 139 Object [] values) { 140 return discrete(duration, values, null); 141 } 142 143 153 public static AnimationFunction discrete( 154 long duration, 155 Object [] values, 156 float[] keyTimes) { 157 return new InterpolatedAnimationFunction( 158 duration, 159 values, 160 keyTimes, 161 InterpolatedAnimationFunction.MODE_DISCRETE); 162 } 163 164 173 public static AnimationFunction fromBy( 174 long duration, 175 float from, 176 float by) { 177 return fromTo(duration, from, from + by); 178 } 179 180 189 public static AnimationFunction fromTo( 190 long duration, 191 float from, 192 float to) { 193 return linear( 194 duration, 195 new Float [] { new Float (from), new Float (to)}); 196 } 197 198 207 public static AnimationFunction linear(long duration, Object [] values) { 208 return linear(duration, values, null); 209 } 210 211 221 public static AnimationFunction linear( 222 long duration, 223 Object [] values, 224 float[] keyTimes) { 225 return new InterpolatedAnimationFunction( 226 duration, 227 values, 228 keyTimes, 229 InterpolatedAnimationFunction.MODE_LINEAR); 230 } 231 232 233 247 public static AnimationFunction linearColors( 248 long duration, Color [] colors, float[] keyTimes) { 249 return new ColorFunction(duration, colors, keyTimes); 250 } 251 252 253 262 public static AnimationFunction random( 263 int min, 264 int max, 265 float changeProbability) { 266 return new RandomAnimationFunction(min, max, changeProbability); 267 } 268 269 277 public static AnimationFunction repeat( 278 AnimationFunction f, 279 long repeatTime) { 280 return new RepeatedAnimationFunction(f, repeatTime); 281 } 282 283 290 public static AnimationFunction reverse(AnimationFunction f) { 291 return new ReversedAnimationFunction(f); 292 } 293 294 295 297 private static class AlphaColorAnimationFunction 299 implements AnimationFunction { 300 private final Color baseColor; 301 private final AnimationFunction fAlpha; 302 303 private AlphaColorAnimationFunction( 304 AnimationFunction fAlpha, 305 Color baseColor) { 306 this.fAlpha = fAlpha; 307 this.baseColor = baseColor; 308 } 309 310 public long duration() { 311 return fAlpha.duration(); 312 } 313 314 public Object valueAt(long time) { 316 return new Color ( 317 baseColor.getRed(), 318 baseColor.getGreen(), 319 baseColor.getBlue(), 320 ((Float ) fAlpha.valueAt(time)).intValue()); 321 } 322 } 323 324 private static class ColorFunction extends AbstractAnimationFunction { 326 327 331 private final AnimationFunctions.FloatFunction redFunction; 332 333 337 private final AnimationFunctions.FloatFunction greenFunction; 338 339 343 private final AnimationFunctions.FloatFunction blueFunction; 344 345 349 private final AnimationFunctions.FloatFunction alphaFunction; 350 351 352 354 364 private ColorFunction(long duration, Color [] colors, float[] keyTimes) { 365 super(duration); 366 Float [] red = new Float [colors.length]; 367 Float [] green = new Float [colors.length]; 368 Float [] blue = new Float [colors.length]; 369 Float [] alpha = new Float [colors.length]; 370 371 for (int i = 0; i < colors.length; i++) { 372 red[i] = new Float (colors[i].getRed()); 373 green[i] = new Float (colors[i].getGreen()); 374 blue[i] = new Float (colors[i].getBlue()); 375 alpha[i] = new Float (colors[i].getAlpha()); 376 } 377 378 redFunction = AnimationFunctions.asFloat(AnimationFunctions.linear( 379 duration, red, keyTimes)); 380 greenFunction = AnimationFunctions.asFloat(AnimationFunctions.linear( 381 duration, green, keyTimes)); 382 blueFunction = AnimationFunctions.asFloat(AnimationFunctions.linear( 383 duration, blue, keyTimes)); 384 alphaFunction = AnimationFunctions.asFloat(AnimationFunctions.linear( 385 duration, alpha, keyTimes)); 386 } 387 388 389 391 401 public Object valueAt(long time) { 402 return colorValueAt(time); 403 } 404 405 413 private Color colorValueAt(long time) { 414 checkTimeRange(time); 415 return new Color ( 416 (int) redFunction.valueAt(time), 417 (int) greenFunction.valueAt(time), 418 (int) blueFunction.valueAt(time), 419 (int) alphaFunction.valueAt(time)); 420 } 421 422 } 423 424 427 public static class FloatFunction { 428 private final AnimationFunction f; 429 430 FloatFunction(AnimationFunction f) { 431 this.f = f; 432 } 433 434 public long duration() { 435 return f.duration(); 436 } 437 public float valueAt(long time) { 438 return ((Number ) f.valueAt(time)).floatValue(); 439 } 440 } 441 442 private static class InterpolatedAnimationFunction 444 extends AbstractAnimationFunction { 445 static final int MODE_DISCRETE = 1; 446 static final int MODE_LINEAR = 2; 447 private final float[] keyTimes; 448 private final int mode; 449 450 454 455 private final Object [] values; 456 457 private InterpolatedAnimationFunction( 458 long duration, 459 Object [] values, 460 float[] keyTimes, 461 int mode) { 462 super(duration); 463 this.values = values; 464 this.keyTimes = keyTimes; 465 this.mode = mode; 466 checkValidKeyTimes(values.length, keyTimes); 467 } 468 469 private void checkValidKeyTimes(int valuesLength, float[] theKeyTimes) { 470 if (theKeyTimes == null) 471 return; 472 473 if (valuesLength < 2 || valuesLength != theKeyTimes.length) 474 throw new IllegalArgumentException ("The values and key times arrays must be non-empty and must have equal length."); 475 476 for (int index = 0; index < theKeyTimes.length - 2; index++) { 477 if (theKeyTimes[index] >= theKeyTimes[index + 1]) 478 throw new IllegalArgumentException ("The key times must be increasing."); 479 } 480 } 481 482 private Object discreteValueAt(long time) { 483 return values[indexAt(time, values.length)]; 484 } 485 486 private int indexAt(long time, int intervalCount) { 487 long duration = duration(); 488 if (keyTimes == null) { 490 return (int) (time * intervalCount / duration); 491 } 492 for (int index = keyTimes.length - 1; index > 0; index--) { 493 if (time > duration * keyTimes[index]) 494 return index; 495 } 496 return 0; 497 } 498 499 508 private Object interpolateLinear( 509 Object value1, 510 Object value2, 511 long time, 512 long duration) { 513 float f1 = ((Number ) value1).floatValue(); 514 float f2 = ((Number ) value2).floatValue(); 515 float value = f1 + (f2 - f1) * time / duration; 516 return new Float (value); 517 } 518 519 private Object linearValueAt(long time) { 520 int segments = values.length - 1; 521 int beginIndex = indexAt(time, segments); 522 int endIndex = beginIndex + 1; 523 long lastTime = duration() - 1; 524 long beginTime = 525 keyTimes == null 526 ? beginIndex * lastTime / segments 527 : (long) (keyTimes[beginIndex] * lastTime); 528 long endTime = 529 keyTimes == null 530 ? endIndex * lastTime / segments 531 : (long) (keyTimes[endIndex] * lastTime); 532 533 return interpolateLinear( 534 values[beginIndex], 535 values[endIndex], 536 time - beginTime, 537 endTime - beginTime); 538 } 539 540 public Object valueAt(long time) { 541 checkTimeRange(time); 542 switch (mode) { 543 case MODE_DISCRETE : 544 return discreteValueAt(time); 545 546 case MODE_LINEAR : 547 return linearValueAt(time); 548 549 default : 550 throw new IllegalStateException ("Unsupported interpolation mode."); 551 } 552 } 553 } 554 555 private static class RandomAnimationFunction 557 implements AnimationFunction { 558 private final float changeProbability; 559 private final int max; 560 private final int min; 561 private final Random random; 562 563 private Object value; 564 565 private RandomAnimationFunction( 566 int min, 567 int max, 568 float changeProbability) { 569 this.random = new Random (); 570 this.min = min; 571 this.max = max; 572 this.changeProbability = changeProbability; 573 } 574 575 public long duration() { 576 return Integer.MAX_VALUE; 577 } 578 579 public Object valueAt(long time) { 580 if ((value == null) 581 || (random.nextFloat() < changeProbability)) { 582 value = new Integer (min + random.nextInt(max - min)); 583 } 584 return value; 585 } 586 } 587 588 private static class RepeatedAnimationFunction 590 extends AbstractAnimationFunction { 591 private final AnimationFunction f; 592 private final long simpleDuration; 593 594 private RepeatedAnimationFunction( 595 AnimationFunction f, 596 long repeatTime) { 597 super(repeatTime); 598 this.f = f; 599 this.simpleDuration = f.duration(); 600 } 601 602 public Object valueAt(long time) { 603 return f.valueAt(time % simpleDuration); 604 } 605 } 606 607 private static class ReversedAnimationFunction 609 extends AbstractAnimationFunction { 610 private final AnimationFunction f; 611 612 private ReversedAnimationFunction(AnimationFunction f) { 613 super(f.duration()); 614 this.f = f; 615 } 616 617 public Object valueAt(long time) { 618 return f.valueAt(duration() - time); 619 } 620 } 621 622 private static class SequencedAnimationFunction 624 implements AnimationFunction { 625 private final List functions; 626 627 private SequencedAnimationFunction(List functions) { 628 this.functions = Collections.unmodifiableList(functions); 629 if (this.functions.isEmpty()) 630 throw new IllegalArgumentException ("The list of functions must not be empty."); 631 } 632 633 public long duration() { 634 long cumulatedDuration = 0; 635 for (Iterator i = functions.iterator(); i.hasNext();) { 636 AnimationFunction f = (AnimationFunction) i.next(); 637 cumulatedDuration += f.duration(); 638 } 639 return cumulatedDuration; 640 } 641 642 public Object valueAt(long time) { 643 if (time < 0) 644 throw new IllegalArgumentException ("The time must be positive."); 645 646 long begin = 0; 647 long end; 648 for (Iterator i = functions.iterator(); i.hasNext();) { 649 AnimationFunction f = (AnimationFunction) i.next(); 650 end = begin + f.duration(); 651 if (time < end) 652 return f.valueAt(time - begin); 653 begin = end; 654 } 655 throw new IllegalArgumentException ("The time must be smaller than the total duration."); 656 } 657 } 658 659 } | Popular Tags |