package edu.princeton.cs.algs4.growingtree.framework; /* * @(#)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 { private LinkedList list; /** * Constructs an empty list. */ public AffineTransformList() { list = new LinkedList(); } /** * 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) { list = new LinkedList(c); } /** * Gets the number of elements in this list. */ public int size() { return list.size(); } /** * Gets the element at index in this list. */ public AffineTransform get(int index) { return list.get(index); } /** * 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 list.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) { list.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) { list.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) { list.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 list.set(index, element); } /** * Finds the appropriate AffineTransform given a double step. The double step * refers to inbetween two AffineTransforms, 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 AffineTransforms. *@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(); step = size() - 1; } 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 AffineTransforms 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); } }