/*
* @(#)AffineTransformList.java
*
* Last Modified: 9/01/02
*/
import java.awt.geom.*;
import java.util.*;
import java.util.*;
/**
* Linked list implementation of the List interface containing AffineTransforms. Implements all
* optional list operations, but only permits AffineTransform
insertion. In addition to implementing the List interface,
* the AffineTransformList class extends the uniformly named methods within LinkedList to
* get, remove and insert an element at the
* beginning and end of the list. These operations allow AffineTransformLists to be
* used as a stack, queue, or double-ended queue (deque).
*
* The primary purpose of the class is for the development of getTransformStep,
* which returns the AffineTransform
found passing a double index. The double index transforms
* into an intermidiary AffineTransform
developed from the list of AffineTransforms.
*
* The iterators returned by the this class's iterator and
* listIterator methods are fail-fast: if the list is
* structurally modified at any time after the iterator is created, in any way
* except through the Iterator's own remove or add methods,
* the iterator will throw a ConcurrentModificationException. Thus,
* in the face of concurrent modification, the iterator fails quickly and
* cleanly, rather than risking arbitrary, non-deterministic behavior at an
* undetermined time in the future.
*
* @author Corey Sanders
* @version 1.4 9/01/02
* @see java.util.LinkedList
* @see java.awt.geom.AffineTransform
*/
public class AffineTransformList extends LinkedList {
/**
* Constructs an empty list.
*/
public AffineTransformList() {
super();
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list.
*/
public AffineTransformList(Collection c) {
super(c);
}
/**
* Appends the given AffineTransform
to the end of this list.
*
* @param a the AffineTransform
to be inserted at the end of this list.
* @return true (as per the general contract of
* Collection.add).
*/
public boolean add(AffineTransform a) {
return super.add(a);
}
/**
* Inserts the specified AffineTransform
at the specified position in this list.
* Shifts the AffineTransform
currently at that position (if any) and any
* subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted.
* @param element AffineTransform
to be inserted.
*
* @throws IndexOutOfBoundsException if the specified index is out of
* range (index < 0 || index > size()).
*/
public void add(int index, AffineTransform element) {
super.add(index, element);
}
/**
* Inserts the given AffineTransform
at the beginning of this list.
*
* @param a the AffineTransform
to be inserted at the beginning of this list.
*/
public void addFirst(AffineTransform a) {
super.addFirst(a);
}
/**
* Appends the given AffineTransform
to the end of this list. (Identical in
* function to the add method; included only for consistency.)
*
* @param a the AffineTransform
to be inserted at the end of this list.
*/
public void addLast(AffineTransform a) {
super.addFirst(a);
}
/**
* Replaces the AffineTransform
at the specified position in this list with the
* specified AffineTransform
.
*
* @param index index of element to replace.
* @param element AffineTransform
to be stored at the specified position.
* @return the AffineTransform
previously at the specified position.
* @throws IndexOutOfBoundsException if the specified index is out of
* range (index < 0 || index >= size()).
*/
public AffineTransform set(int index, AffineTransform element) {
return (AffineTransform)super.set(index, element);
}
/**
* Finds the appropriate AffineTransform
given a double step. The double step
* refers to inbetween two AffineTransform
s, defined by integer indices. The AffineTransform
* returns that takes the step and finds the AffineTransform that fits at that given point
* between the two integer indices.
*
*@param step double step referring to inbetween two indices of the AffineTransformList.
*@return AffineTransform
that represents the transform for the double step between
* two AffineTransform
s.
*@throws IndexOutOfBoundsException if the specified step is out of
* range (step < 0 || step >= size()).
*/
public AffineTransform getTransformStep(double step) throws IndexOutOfBoundsException{
if (step > (size()-1)) {
throw new IndexOutOfBoundsException();
}
AffineTransform previous = (AffineTransform)get((int)Math.floor(step));
AffineTransform next = (AffineTransform)get((int)Math.ceil(step));
double previousWeight = 1.0 - (step - Math.floor(step));
double nextWeight = step - Math.floor(step);
double m00, m01, m02,
m10, m11, m12;
// Matrix entries according to : {[m00, m01, m02]
// [m10, m11, m12]}
m00 = (previous.getScaleX() * previousWeight) + (next.getScaleX() * nextWeight);
m11 = (previous.getScaleY() * previousWeight) + (next.getScaleY() * nextWeight);
m01 = (previous.getShearX() * previousWeight) + (next.getShearX() * nextWeight);
m10 = (previous.getShearY() * previousWeight) + (next.getShearY() * nextWeight);
m02 = (previous.getTranslateX() * previousWeight) + (next.getTranslateX() * nextWeight);
m12 = (previous.getTranslateY() * previousWeight) + (next.getTranslateY() * nextWeight);
return new AffineTransform(m00, m10, m01, m11, m02, m12);
}
/**
* Finds the appropriate AffineTransform
given a double step and two AffineTrasforms. The double step
* refers to a number between 1 and 0. The AffineTransform
* returned takes the step and finds the AffineTransform that fits at that given point
* between the two integer indices, 0 returns AffineTransform
a and 1 returns AffineTrasform
b.
*
*@param a AffineTransform that is returned at step 0.
*@param b AffineTransform that is returned at step 1.
*@param step double step referring to inbetween two indices of the AffineTransformList.
*@return AffineTransform
that represents the transform for the double step between
* two AffineTransform
s a and b.
*@throws IndexOutOfBoundsException if the specified step is out of
* range (step < 0 || step >= size()).
*/
public static AffineTransform getTransformStep(AffineTransform a, AffineTransform b, double step) {
if (step > 1 || step < 0)
return null;
double previousWeight = 1.0 - (step);
double nextWeight = step;
double m00, m01, m02,
m10, m11, m12;
m00 = (a.getScaleX() * previousWeight) + (b.getScaleX() * nextWeight);
m11 = (a.getScaleY() * previousWeight) + (b.getScaleY() * nextWeight);
m01 = (a.getShearX() * previousWeight) + (b.getShearX() * nextWeight);
m10 = (a.getShearY() * previousWeight) + (b.getShearY() * nextWeight);
m02 = (a.getTranslateX() * previousWeight) + (b.getTranslateX() * nextWeight);
m12 = (a.getTranslateY() * previousWeight) + (b.getTranslateY() * nextWeight);
return new AffineTransform(m00, m10, m01, m11, m02, m12);
}
}