package edu.princeton.cs.algs4.growingtree.framework; /* * @(#)DisplayChangeAnimation.java * * Last Modified: 9/01/02 */ import java.util.*; import java.awt.*; import java.awt.geom.*; /** * * The Animation object that defines the Rotation of a BSTTree. Two constructors exist, * one setting the animator and animation color Schemes, one setting those to defaults.

* * The object restores all values changed in the given nodes, however, if the object * is never allowed to finish, the restoring of values becomes impossible. On any exception occuring * elsewhere, the object may not restore the conditions correctly. * * @author Corey Sanders * @version 1.4 9/01/02 */ public class DisplayChangeAnimation

extends AbstractAnimation { /** * The Default step size used in the animation (16). */ public final static int DEFAULT_STEP = 16; /** * Constant that defines the starting location. */ private final int START = 0; /** * Constant the defines the final moving location. */ private final int MOVE = 1; /** * Private doubles used to hold the current and previous location steps. */ private double currentLocation = 0.0; /** * The previous location of the animation. */ private double previousLocation; /** * The moving nodes for the display change. */ private MovingBSTTreeAnimation

movingTreeNodes; /** * The int defining the change in display. */ private int displayChange; /** * The linked list containing all of the right null links nodes */ private LinkedList> rightNullNodes; /** * The linked list containing all of the left null links nodes */ private LinkedList> leftNullNodes; /** * Color Scheme used as the original. */ private NodeSettings nodeOriginalScheme; /** * Color Scheme used for the original scheme of the key. */ private KeySettings keyOriginalScheme; /** * BSTTreeHead which is the head of the tree whose display is chaning. */ private GrowingTreeHead

head; /** * The constructor which initiates the status and sets the color Schemes to default. Also sets * starting command to Animation.PLAY, and sets the step time to the default. * * @param head the BSTTreeHead head of the tree whose display is changing. * @param displayChange the new kind of display, according to BSTTreeHead.SECT_DISPLAY or BSTTreeHead.BINARY_DISPLAY */ public DisplayChangeAnimation(GrowingTreeHead

head, int displayChange) { this(head, displayChange, null, null, Animation.PLAY, DEFAULT_STEP); } /** * The constructor which initiates the status and prepares the color schemes. * * @param head the BSTTreeHead head of the tree whose display is changing. * @param displayChange the new kind of display, according to BSTTreeHead.SECT_DISPLAY or BSTTreeHead.BINARY_DISPLAY * @param NodeOriginalAnimationScheme original scheme for the root. * @param KeyOriginalScheme original scheme for the key. * @param startingCmd the Animation command that should start. * @param stepTime the time for each step of the Animation. Sets the initial value. */ public DisplayChangeAnimation(GrowingTreeHead

head, int displayChange, NodeSettings NodeOriginalScheme, KeySettings KeyOriginalScheme, String startingCmd, int stepTime) { super(); // Set defaults if no color schemes exist if (NodeOriginalScheme == null) { NodeOriginalScheme = new NodeSettings(); } if (KeyOriginalScheme == null) { KeyOriginalScheme = new KeySettings(); } setNodeOriginalScheme((NodeSettings)NodeOriginalScheme.clone()); setKeyOriginalScheme((KeySettings)KeyOriginalScheme.clone()); setLeftNullNodes(new LinkedList>()); setRightNullNodes(new LinkedList>()); // Sets the root and child nodes setHead(head); setDisplayChange(displayChange); setMovingTreeNodes(new MovingBSTTreeAnimation

(getNodeOriginalScheme(), getKeyOriginalScheme())); setStartingCommand(startingCmd); setStepTime(stepTime); } /************************/ /* Accessor methods */ /************************/ /** * Gets the displayChange for the display change animation. * * @return displayChange integer defined in BSTTreeHead. */ public int getDisplayChange() { return displayChange; } /** * Gets the right null link nodes. * * @return LinkedList for the right null link nodes. */ private LinkedList> getRightNullNodes() { return rightNullNodes; } /** * Gets the left null link nodes. * * @return LinkedList for the left null link nodes. */ private LinkedList> getLeftNullNodes() { return leftNullNodes; } /** * Gets the head for the tree whose display is changing. * * @return BSTTreeHead for the entire tree display change. */ private GrowingTreeHead

getHead() { return head; } /** * Gets the MovingBSTTreeAnimation for the tree whose display is changing. * * @return MovingBSTTreeAnimation for the entire tree display change. */ public MovingBSTTreeAnimation

getMovingTreeNodes() { return movingTreeNodes; } /** * Gets the NodeSettings for the original node scheme for the rotation. * * @return NodeSettings for the original node scheme. */ public NodeSettings getNodeOriginalScheme() { return nodeOriginalScheme; } /** * Gets the KeySettings for the original scheme of the key. * * @return KeySettings for the original key scheme. */ public KeySettings getKeyOriginalScheme() { return keyOriginalScheme; } /************************/ /* Mutator methods */ /************************/ /** * Sets the displayChange for the animation. * * @param displayChange the int defined within BSTTreeHead (SECT_DISPLAY or BINARY_DISPLAY). */ public void setDisplayChange(int displayChange) { this.displayChange = displayChange; } /** * Sets the right null link nodes. * * @param LinkedList for the right null link nodes. */ private void setRightNullNodes(LinkedList> rightNullNodes) { this.rightNullNodes = rightNullNodes; } /** * Sets the left null link nodes. * * @param leftNullNodes LinkedList for the left null link nodes. */ private void setLeftNullNodes(LinkedList> leftNullNodes) { this.leftNullNodes = leftNullNodes; } /** * Sets the head for the tree whose display is changing. * * @param head BSTTreeHead for the display change. */ private void setHead(GrowingTreeHead

head) { this.head = head; } /** * Sets the MovingBSTTreeAnimation for the tree whose display is changing. * * @param movingTreeNodes MovingBSTTreeAnimation for the entire tree display change. */ public void setMovingTreeNodes(MovingBSTTreeAnimation

movingTreeNodes) { this.movingTreeNodes = movingTreeNodes; } /** * Sets the NodeSettings for the original scheme for the rotation. * * @param scheme NodeSettings for the original scheme. */ public void setNodeOriginalScheme(NodeSettings scheme) { nodeOriginalScheme = scheme; } /** * Sets the KeySettings for the original scheme of the key during rotation. * * @param scheme KeySettings for the original of the key. */ public void setKeyOriginalScheme(KeySettings scheme) { keyOriginalScheme = scheme; } /*****************************/ /* Entire Animators Mutators */ /*****************************/ /** * Creates the moving nodes corresponding to the entire tree. */ private void createFinalTreeMovingNodes() { // Intialize //finalTreeMovingNodes = new MovingBSTTreeAnimation(); // Top node GrowingTreeNode

topNode = (GrowingTreeNode

)getHead().getChild(); if (topNode == null) return; MovingBSTTree

topMovingNode = new MovingBSTTree

(topNode); if (topNode.isAnimateDrawing()) { // Add grandchild to descendant animation getMovingTreeNodes().add(topMovingNode, topNode); topMovingNode.setMovePosition(MovingBSTTree.FOLLOW_NODE); // Set listeners getMovingTreeNodes().addAnimationListener(topNode); (topNode).addAnimator(getMovingTreeNodes()); } // Add all children MovingBSTTree

left = addTreeNode((GrowingTreeNode

)topNode.getLeftNodeInternal(), getMovingTreeNodes(), MovingBSTTree.FOLLOW_NODE, topMovingNode); MovingBSTTree

right = addTreeNode((GrowingTreeNode

)topNode.getRightNodeInternal(), getMovingTreeNodes(), MovingBSTTree.FOLLOW_NODE, topMovingNode); if (left != null) { topMovingNode.setLeftTree(left); } else { getLeftNullNodes().add(topMovingNode); } if (right != null) { topMovingNode.setRightTree(right); } else { getRightNullNodes().add(topMovingNode); } } /** * Adds all children nodes to the animator list, setting the Moving node as its parent. The move position * defines the moving of the new node. * * @param node the node which the MovingBSTTree made imitates. * @param animator the MovingBSTTreeAnimation to which the new MovingBSTTree node is added. * @param movePostion the moving position of the new MovingBSTTree. * @return MovingBSTTree the new tree moving node. */ private MovingBSTTree

addTreeNode(GrowingTreeNode

node, MovingBSTTreeAnimation

animator, int movePosition, MovingBSTTree

parent) { if (node.isEmpty()) return null; // Create new MovingBSTTree MovingBSTTree

movingNode = new MovingBSTTree

(node, parent); if (node.isAnimateDrawing()) { // Sets the move position movingNode.setMovePosition(movePosition); // Adds the animator to the MovingBSTTreeAnimation animator.add(movingNode, node); // Adds the listener to the animation and the animation to the node. animator.addAnimationListener(node); node.addAnimator(animator); MovingBSTTree

left = addTreeNode((GrowingTreeNode

)node.getLeftNodeInternal(), animator, MovingBSTTree.FOLLOW_NODE, movingNode); MovingBSTTree

right = addTreeNode((GrowingTreeNode

)node.getRightNodeInternal(), animator, MovingBSTTree.FOLLOW_NODE, movingNode); // Recursively goes through children if (left != null) { movingNode.setLeftTree(left); } else { getLeftNullNodes().add(movingNode); } if (right != null) { movingNode.setRightTree(right); } else { getRightNullNodes().add(movingNode); } } movingNode.setCurrentTransform(movingNode.getStartTransform()); return movingNode; } /** * Draws the animation of the next step, using the status of the animation (Animation.PLAY, Animation.PAUSE and so forth). * After completing the drawing, the Animation sends an AnimationEvent to all its listeners, indicating * any information that the listerners may wish to use.

* The starting status used for the animation is the one previously defined. * * @param g2 Graphics2D to which the graphics are drawn. */ public void drawAnimation(Graphics2D g2) { drawAnimation(g2, getStartingCommand()); } /** * Draws the animation of the next step, using the status of the animation (Animation.PLAY, Animation.PAUSE and so forth). * After completing the drawing, the Animation sends an AnimationEvent to all its listeners, indicating * any information that the listerners may wish to use. * * BSTTreeHead calls: *

* Other Animation Objects used: * * * @param g2 the graphics to which the animation step should be drawn. * @param startingStatus sent to the animators */ public void drawAnimation(Graphics2D g2, String startingStatus) { setStartingCommand(startingStatus); // Sets the animation step size. getMovingTreeNodes().setStepSize(getStepSize()); // Sets the animation step size. //getMovingTreeNodes().setStep(getStep()); getMovingTreeNodes().setStep(false); // FINISH status (set from outside) if (getStatus().equals(Animation.FINISH)) { // Actual rotation getHead().setDisplay(getDisplayChange()); } // BEGIN status if (getStatus().equals(Animation.BEGIN)) { currentLocation = 0.0; previousLocation = 0.0; // Create the final moving nodes createFinalTreeMovingNodes(); //getMovingTreeNodes().drawAnimation(g2, startingStatus); //getMovingTreeNodes().setAnimationScheme(getNodeOriginalScheme(), getKeyOriginalScheme()); // Actual display change getHead().setDisplay(getDisplayChange()); // REDRAW message messageAction(Animation.REDRAW); if (displayChange == GrowingTreeHead.BINARY_DISPLAY) { for(int i=0; i)getLeftNullNodes().get(i)).getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault,0)); } for(int i=0; i)getRightNullNodes().get(i)).getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault,0)); } } getMovingTreeNodes().drawAnimation(g2, startingStatus); animationAction(); setStatus(startingStatus); return; } String action = Animation.PLAY; if (getStatus().equals(Animation.PLAY)) { action = Animation.PLAY; previousLocation = currentLocation; if(getStep()) { // Skip middle animation steps. currentLocation = Math.ceil(currentLocation) + getStepSize(); } else { // Normal step currentLocation += getStepSize(); } } // REWIND status if (getStatus().equals(Animation.REWIND)) { action = Animation.REWIND; previousLocation = currentLocation; if(getStep()) { // Skip middle animation steps. currentLocation = Math.floor(currentLocation)-getStepSize(); } else { // Normal step currentLocation -= getStepSize(); } } // Beginning of Animation if (currentLocation <= 0) { setStatus(Animation.PAUSE); currentLocation = 0; } // PAUSE status if (getStatus().equals(Animation.PAUSE)) { action = Animation.PAUSE; } // STOP status if (getStatus().equals(Animation.STOP)) { messageAction(Animation.STOP); // Nothing happens // Call listeners animationAction(); return; } messageAction(action); float decreasingFromOne = .6F - ((float)currentLocation) ; float increasingToOne = ((float)currentLocation); if (increasingToOne > 1) { increasingToOne = 1; } if (increasingToOne < 0) { increasingToOne = 0; } if (decreasingFromOne < 0) { decreasingFromOne = 0; } //Moving if (currentLocation < MOVE) { getMovingTreeNodes().setStatus(action); getMovingTreeNodes().makeAnimation(g2, action); if (displayChange == GrowingTreeHead.BINARY_DISPLAY) { for(int i=0; i)getLeftNullNodes().get(i)).getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne)); } for(int i=0; i)getRightNullNodes().get(i)).getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, increasingToOne)); } } else { for(int i=0; i)getLeftNullNodes().get(i)).getSettings().setLeftLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, decreasingFromOne)); ((MovingBSTTree

)getLeftNullNodes().get(i)).drawFollowNode(g2, currentLocation, true); } for(int i=0; i)getRightNullNodes().get(i)).getSettings().setRightLinkComposite((Composite)AlphaComposite.getInstance(NodeSettings.nodeRuleDefault, decreasingFromOne)); ((MovingBSTTree

)getRightNullNodes().get(i)).drawFollowNode(g2, currentLocation, true); } } getMovingTreeNodes().drawAnimation(g2, action); } // Animation is completed if (currentLocation >= MOVE) { // Set step, to finish the animation getMovingTreeNodes().setStep(true); // Draw getMovingTreeNodes().makeAnimation(g2, Animation.PLAY); getMovingTreeNodes().drawAnimation(g2, Animation.PLAY); // Set own status to FINISH setStatus(Animation.FINISH); } // FINISH status if (getStatus().equals(Animation.FINISH)) { // Completion messages messageAction(Animation.FINISH); // Set all status to FINISH getMovingTreeNodes().setStatus(Animation.FINISH); getMovingTreeNodes().makeAnimation(g2, startingStatus); // Draw getMovingTreeNodes().drawAnimation(g2, startingStatus); } // Call listeners animationAction(); } }