/*
* @(#)FlurryTransition2D.java
*
* $Date: 2014-06-06 20:04:49 +0200 (P, 06 jún. 2014) $
*
* Copyright (c) 2011 by Jeremy Wood.
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* Jeremy Wood. For details see accompanying license terms.
*
* This software is probably, but not necessarily, discussed here:
* https://javagraphics.java.net/
*
* That site should also contain the most recent official version
* of this software. (See the SVN repository for more details.)
*/
package com.bric.image.transition;
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
import java.util.Vector;
import com.bric.geom.ShapeBounds;
import com.bric.geom.TransformUtils;
/** In this transition one image breaks into several smaller tiles
* and then is whisked away as if by a wind. Or, seen backwards, a flurry of incoming tiles assemble into
* the incoming image.
* <p>Here are playback samples:
* <p><table summary="Sample Animations of FlurryTransition2D" cellspacing="50" border="0"><tr>
* <td align="center">
* <img src="https://javagraphics.java.net/resources/transition/FlurryTransition2D/FlurryIn.gif" alt="Flurry In">
* <p>Flurry In
* </td>
* <td align="center">
* <img src="https://javagraphics.java.net/resources/transition/FlurryTransition2D/FlurryOut.gif" alt="Flurry Out">
* <p>Flurry Out
* </td>
* </tr></table>
*/
public class FlurryTransition2D extends Transition2D {
/** This public static method is used by the
* {@link com.bric.image.transition.Transition2DDemoHelper}
* class to create sample animations of this transition.
* @return the transitions that should be used to demonstrate this
* transition.
*/
public static Transition[] getDemoTransitions() {
return new Transition[] {
new FlurryTransition2D(IN),
new FlurryTransition2D(OUT)
};
}
int type = OUT;
Comparator<ImageInstruction> comparator = new Comparator<ImageInstruction>() {
public int compare(ImageInstruction i1, ImageInstruction i2) {
if(i1.isFirstFrame && i2.isFirstFrame==false)
return 1;
if(i2.isFirstFrame && i1.isFirstFrame==false)
return -1;
Rectangle2D r1 = ShapeBounds.getBounds(i1.clipping);
Rectangle2D r2 = ShapeBounds.getBounds(i2.clipping);
double area1 = r1.getWidth()*r1.getHeight();
double area2 = r2.getWidth()*r2.getHeight();
if(area1<area2) {
return -1;
}
return 1;
}
};
/** Creates a new flurry transition that moves out.
*/
public FlurryTransition2D() {
this(OUT);
}
/** Creates a new flurry transition
*
* @param type must be OUT or IN
*/
public FlurryTransition2D(int type) {
if(!(type==OUT || type==IN)) {
throw new IllegalArgumentException("This transition must use OUT or IN.");
}
this.type = type;
}
@Override
public Transition2DInstruction[] getInstructions(float progress,
Dimension size) {
if(type==IN) {
progress = 1-progress;
}
progress = progress*.78f;
Vector<Rectangle2D> v1 = new Vector<Rectangle2D>();
float yHeight = 200f/10f;
float xWidth = 200f/10f;
for(float y = 0; y<200; y+=yHeight) {
for(float x = 0; x<200; x+=xWidth) {
Rectangle2D r = new Rectangle2D.Double(x,y,xWidth,yHeight);
v1.add(r);
}
}
progress = (float)Math.pow(progress, 1);
ImageInstruction[] instr = new ImageInstruction[v1.size()+1];
instr[0] = new ImageInstruction(false);
Random random = new Random();
for(int a = 0; a<v1.size(); a++) {
Rectangle2D r = v1.get(a);
random.setSeed(a);
Shape clipping = r;
Point2D center = new Point2D.Double(r.getCenterX()-200f/2f,r.getCenterY()-200f/2f);
float k = (float)(Math.sqrt(center.getX()*center.getX()+center.getY()*center.getY())/Math.sqrt(200f*200f/4+200f*200f/4));
k = (1-progress)*k+progress;
float scaleProgress = (float)Math.pow(2*progress*k,.02+4*random.nextFloat());
AffineTransform transform = new AffineTransform();
transform.translate(200f/2,200f/2);
transform.scale(1+2*scaleProgress,1+2*scaleProgress);
transform.rotate(progress);
transform.translate(-200f/2,-200f/2);
Point2D p1 = new Point2D.Double(r.getCenterX(),r.getCenterY());
Point2D p2 = new Point2D.Double();
Point2D p3 = new Point2D.Double();
transform.transform(p1,p2);
double dx = -(p1.getX()-p2.getX());
double dy = -(p1.getY()-p2.getY());
transform.setToIdentity();
transform.concatenate(TransformUtils.createAffineTransform(
0,0,
0,200,
200,0,
0,0,
0,size.height,
size.width,0
));
transform.scale( 1+Math.abs(dx)/15f, 1+Math.abs(dy)/15f );
transform.rotate(progress);
transform.translate(dx,dy);
clipping = transform.createTransformedShape(clipping);
p1.setLocation(r.getX(),r.getY());
p2.setLocation(r.getX()+r.getWidth(),r.getY());
p3.setLocation(r.getX(),r.getY()+r.getHeight());
transform.transform(p1, p1);
transform.transform(p2, p2);
transform.transform(p3, p3);
transform = TransformUtils.createAffineTransform(
r.getX()*size.width/200f, r.getY()*size.height/200f,
(r.getX()+r.getWidth())*size.width/200f, r.getY()*size.height/200f,
r.getX()*size.width/200f, (r.getY()+r.getHeight())*size.height/200f,
p1.getX(), p1.getY(),
p2.getX(), p2.getY(),
p3.getX(), p3.getY()
);
instr[a+1] = new ImageInstruction(true,transform,clipping);
}
Arrays.sort(instr,comparator);
if(type==IN) {
for(int a = 0; a<instr.length; a++) {
instr[a].isFirstFrame = !instr[a].isFirstFrame;
}
}
return instr;
}
@Override
public String toString() {
if(type==OUT) {
return "Flurry Out";
} else {
return "Flurry In";
}
}
}