/*
* @(#)SquaresTransition2D.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.geom.Rectangle2D;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
import com.bric.geom.RectangularTransform;
/** In this transition the current frame splits off into several
* tiles that calmly "explode" towards the viewer, revealing the
* next frame underneath. Here are playback samples:
* <p><table summary="Sample Animations of SquaresTransition2D" cellspacing="50" border="0"><tr>
* <td align="center">
* <img src="https://javagraphics.java.net/resources/transition/SquaresTransition2D/Squares(10x10).gif" alt="Squares (10x10)">
* <p>Squares (10x10)
* </td>
* <td align="center">
* <img src="https://javagraphics.java.net/resources/transition/SquaresTransition2D/Squares(20x20).gif" alt="Squares (20x20)">
* <p>Squares (20x20)
* </td>
* <td align="center">
* <img src="https://javagraphics.java.net/resources/transition/SquaresTransition2D/Squares(30x30).gif" alt="Squares (30x30)">
* <p>Squares (30x30)
* </td>
* </tr></table>
*
*/
public class SquaresTransition2D 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 SquaresTransition2D(10, 10),
new SquaresTransition2D(30, 30),
new SquaresTransition2D(20, 20),
};
}
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;
double d1 = i1.transform.getDeterminant();
double d2 = i2.transform.getDeterminant();
if(d1<d2) {
return -1;
}
return 1;
}
};
float[][] accels;
float[][] delays;
float progressMax = 1;
/** Creates a new squares transition with 10 rows and columns. */
public SquaresTransition2D() {
this(10,10);
}
/** Creates a new squares transition.
*
* @param columns the number of columns
* @param rows the number of rows
*/
public SquaresTransition2D(int columns,int rows) {
delays = new float[columns][rows];
accels = new float[columns][rows];
Random random = new Random();
for(int x = 0; x<columns; x++) {
for(int y = 0; y<rows; y++) {
float offset = (y-rows/2)*(y-rows/2)+(x-columns/2)*(x-columns/2);
offset = offset/(rows*rows/4+columns*columns/4);
//float offset = ((float)(y+x))/((float)(rows+columns));
delays[x][y] = .3f*offset+.1f*random.nextFloat();
accels[x][y] = (.5f+.8f*random.nextFloat());
}
}
progressMax = findMax(0,2);
}
protected float findMax(float t0,float t1) {
if(t1-t0<.0001) return Math.max(t0,t1);
Rectangle2D r = new Rectangle2D.Float(0,0,100,100);
float mid = t0/2f+t1/2f;
Transition2DInstruction[] instrA = getInstructions(t0,new Dimension(100,100));
Transition2DInstruction[] instrB = getInstructions(mid,new Dimension(100,100));
Transition2DInstruction[] instrC = getInstructions(t1,new Dimension(100,100));
boolean validA = false;
boolean validB = false;
boolean validC = false;
for(int a = 1; a<instrA.length; a++) {
if(r.intersects((Rectangle2D)((ImageInstruction)instrA[a]).clipping)) {
validA = true;
}
if(r.intersects((Rectangle2D)((ImageInstruction)instrB[a]).clipping)) {
validB = true;
}
if(r.intersects((Rectangle2D)((ImageInstruction)instrC[a]).clipping)) {
validC = true;
}
}
if(validA && validC)
return Math.max(t0,t1);
if(validA) {
if(validB) {
return findMax(mid,t1);
} else {
return findMax(t0,mid);
}
} else {
throw new RuntimeException();
}
}
@Override
public Transition2DInstruction[] getInstructions(float progress,
Dimension size) {
progress = progress*progressMax;
int columns = accels.length;
int rows = accels[0].length;
ImageInstruction[] instr = new ImageInstruction[columns*rows+1];
instr[0] = new ImageInstruction(false);
float columnWidth = ((float)size.width)/((float)columns);
float rowHeight = ((float)size.height)/((float)rows);
int ctr = 0;
for(int x = 0; x<columns; x++) {
for(int y = 0; y<rows; y++) {
float delay = delays[x][y];
float accel = accels[x][y];
float t = progress-delay;
if(t<0)
t = 0;
float z = 1+120*accel*t*t;
Rectangle2D r = new Rectangle2D.Float(x*columnWidth,y*rowHeight,columnWidth,rowHeight);
RectangularTransform transform = new RectangularTransform();
float centerX = size.width/2;
float centerY = size.height/2;
transform.translate(centerX,centerY);
transform.scale(z,z);
double dx = centerX-r.getCenterX();
double dy = centerY-r.getCenterY();
transform.translate(-centerX-10*t*dx*progress,-centerY-10*t*dy*progress);
Rectangle2D clip = transform.transform(r);
instr[1+(ctr++)] = new ImageInstruction(true,transform.createAffineTransform(),clip);
}
}
Arrays.sort(instr,comparator);
return instr;
}
@Override
public String toString() {
return "Squares ("+delays[0].length+"x"+delays.length+")";
}
}