package edu.princeton.cs.algs4.growingtree.framework; import java.awt.AlphaComposite; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.text.NumberFormat; public class SwapBSTAnimation

extends AbstractAnimation { private GrowingTreeNode

nodeA; private GrowingTreeNode

nodeB; private NodeSettings nodeAOrig; private NodeSettings nodeBOrig; private double currentLocation; private final double LOCATION_MAX = 10; public SwapBSTAnimation(GrowingTreeNode

nodeA, GrowingTreeNode

nodeB, int stepTime) { this.nodeA = nodeA; this.nodeB = nodeB; nodeAOrig = (NodeSettings) nodeA.getSettings().clone(); nodeBOrig = (NodeSettings) nodeB.getSettings().clone(); this.setStepTime(stepTime); setStartingCommand(AbstractAnimation.PLAY); } public void drawAnimation(Graphics2D g2, String startingStatus) { setStartingCommand(startingStatus); if (getStatus().equals(Animation.BEGIN)) { currentLocation = 0; animationAction(); messageAction(Animation.BEGIN + " Swapping of "+nodeA.getKey().toString() + " and " + nodeB.getKey().toString()); // set starting status setStatus(getStartingCommand()); return; } if (getStatus().equals(Animation.STEP)) { setStatus(getStartingCommand()); } if (getStatus().equals(Animation.PLAY)) { messageAction(Animation.PLAY); //previousLocation = currentLocation; if(getStep()) { // Skip middle animation steps. currentLocation = Math.ceil(currentLocation) + getStepSize(); } else { // Normal step currentLocation += getStepSize(); } // Completed Animation if (currentLocation >= LOCATION_MAX) { setStatus(Animation.FINISH); drawAnimation(g2, getStartingCommand()); return; } } // PAUSE status if (getStatus().equals(Animation.PAUSE)) { messageAction(Animation.PAUSE); return; } // STOP status if (getStatus().equals(Animation.STOP)) { messageAction(Animation.STOP); return; } // FINISH status if (getStatus().equals(Animation.FINISH)) { NumberFormat nf = NumberFormat.getNumberInstance(); nf.setMaximumFractionDigits(3); messageAction(Animation.FINISH); animationAction(); KeyType tempKey = nodeA.getKey(); Object tempVal = nodeA.getValue(); nodeA.setNode(nodeB.getKey(), nodeB.getValue()); nodeB.setNode(tempKey, tempVal); nodeA.setSettings(nodeAOrig); nodeB.setSettings(nodeBOrig); return; } nodeA.getSettings().setScheme(NodeSettings.ERASE); nodeB.getSettings().setScheme(NodeSettings.ERASE); nodeA.drawNode(); nodeB.drawNode(); // Draw just the node without links. AffineTransform transA = getTransformStep(nodeA, nodeB, currentLocation/LOCATION_MAX); AffineTransform transB = getTransformStep(nodeB, nodeA, currentLocation/LOCATION_MAX); nodeA.setSettings(nodeAOrig); nodeB.setSettings(nodeBOrig); nodeA.drawNode(g2, transA); nodeB.drawNode(g2, transB); // Call listeners animationAction(); } public AffineTransform getTransformStep(GrowingTreeNode

from, GrowingTreeNode

to, double step) throws IndexOutOfBoundsException{ //if (step > (size()-1)) { //throw new IndexOutOfBoundsException(); // step = size() - 1; //} AffineTransform previous = from.getCurrentTransform(); //(AffineTransform)get((int)Math.floor(step)); AffineTransform next = to.getCurrentTransform();//(AffineTransform)get((int)Math.ceil(step)); double previousWeight = 1.0 - step; double nextWeight = 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); } }