//package wpm; import java.awt.*; import java.applet.Applet; public class BeanTree extends Applet { static TreeCanvas TreeDisplay; static BeanTreeControls controls; public void init() { setLayout( new BorderLayout() ); resize(300, 300); TreeDisplay = new TreeCanvas(10, 10, 400, 400); add( "Center", TreeDisplay ); add("North", controls = new BeanTreeControls(TreeDisplay)); TreeDisplay.Tree = new TreeClass(); TreeDisplay.controls = controls; TreeDisplay.Tree.SubRoot = new Branch(null, false); TreeDisplay.Tree.Root = new Branch(TreeDisplay.Tree.SubRoot, false); TreeDisplay.edgewidth = 10; TreeDisplay.needsUpdating = false; TreeDisplay.highlightedBranch = null; TreeDisplay.Tree.exists = false; repaint(); } public void start() { controls.enable(); } public void stop() { controls.disable(); } public static void main(String args[]) { com.metrowerks.AppletFrame.startApplet("BeanTree", "BeanTree", args); } } /** ======================================================================== */ class TreeCanvas extends Canvas { TreeClass Tree; int x_max, y_max; int edgewidth; Branch highlightedBranch, branchFrom; int xFrom, yFrom, xTo, yTo; boolean needsUpdating; String treeDescription; BeanTreeControls controls; private int lastleft; private int taxspacing; private Branch foundBranch; public TreeCanvas( int x_max, int y_max, int x_size, int y_size ) { this.x_max = x_max; this.y_max = y_max; resize( x_size, y_size ); repaint(); } /*_________________________________________________*/ private void WriteTreeDescription(Branch N) { if (N.left!=null) { treeDescription+='('; WriteTreeDescription(N.left); treeDescription+=','; WriteTreeDescription(N.right); treeDescription+=')'; } else { treeDescription+='*'; } } public String Describe() { treeDescription=""; WriteTreeDescription(Tree.Root); treeDescription+=';'; return treeDescription; } /*_________________________________________________*/ private void CalcInternalLocs(Branch N) { if (N.left != null) //internal { CalcInternalLocs(N.left); CalcInternalLocs(N.right); N.y = (-N.left.x + N.right.x+N.left.y + N.right.y) / 2; N.x =(N.left.x + N.right.x - N.left.y + N.right.y) / 2; } } /*_________________________________________________*/ private void CalcTerminalLocs(Branch N) { if (N.left == null) //terminal { lastleft+= taxspacing; N.y = 90; N.x = lastleft; } else { CalcTerminalLocs(N.left); CalcTerminalLocs(N.right); } } /*_________________________________________________*/ private void CalcBranchPolys(Branch N) { if (N.left != null) //terminal { CalcBranchPolys(N.left); CalcBranchPolys(N.right); N.branchPoly.npoints=0; N.branchPoly.addPoint(N.x, N.y); N.branchPoly.addPoint(N.x+edgewidth/2, N.y-edgewidth/2); N.branchPoly.addPoint(N.x+edgewidth, N.y); N.branchPoly.addPoint(N.ancestor.x+edgewidth, N.ancestor.y); N.branchPoly.addPoint(N.ancestor.x, N.ancestor.y); N.branchPoly.npoints=5; } else { N.branchPoly.npoints=0; N.branchPoly.addPoint(N.x, N.y); N.branchPoly.addPoint(N.x+edgewidth, N.y); N.branchPoly.addPoint(N.ancestor.x+edgewidth, N.ancestor.y); N.branchPoly.addPoint(N.ancestor.x, N.ancestor.y); N.branchPoly.npoints=4; } } /*_________________________________________________*/ private void calcBranches() { lastleft = 0; taxspacing = (bounds().width - 10) / Tree.numTaxa; CalcTerminalLocs(Tree.Root); CalcInternalLocs(Tree.Root); Tree.SubRoot.y = (Tree.Root.y)+20; Tree.SubRoot.x = (Tree.Root.x)-20; CalcBranchPolys(Tree.Root); } /*_________________________________________________*/ private void drawBranch(Graphics g, Branch N) { g.setColor(N.color); g.fillPolygon(N.branchPoly); if (N.left != null) drawBranch(g, N.left); if (N.right != null) drawBranch(g, N.right); } /*_________________________________________________*/ public void drawTree(Graphics g) { if (Tree.exists) { calcBranches(); drawBranch(g, Tree.Root); } } /*_________________________________________________*/ public void paint(Graphics g) { drawTree(g); needsUpdating = false; } /*_________________________________________________*/ public void InvertBranch(Graphics g, Branch N) { // N.color=Color.white; highlightedBranch=N; g.setColor(Color.white); g.fillPolygon(N.branchPoly); // needsUpdating=true; } /*_________________________________________________*/ public void RevertBranch(Graphics g, Branch N) { // N.color=Color.black; highlightedBranch=null; g.setColor(Color.black); g.fillPolygon(N.branchPoly); // needsUpdating=true; } /*_________________________________________________*/ private void ScanBranches(Branch N, int x, int y) { if (foundBranch==null) { if (N.branchPoly.inside(x, y)) foundBranch = N; if (N.left != null) //terminal { ScanBranches(N.left, x, y); ScanBranches(N.right, x, y); } } } /*_________________________________________________*/ public Branch FindBranch(int x, int y) { foundBranch=null; ScanBranches(Tree.Root, x, y); return foundBranch; } /*_________________________________________________*/ public void ScanTouch(Graphics g, int x, int y) { Branch branchFound=FindBranch( x, y); if (branchFound!=null) { branchFrom=branchFound; xFrom=x; yFrom=y; xTo=x; yTo=y; g.setXORMode(Color.gray); g.setColor(Color.black); g.drawLine(xFrom,yFrom,xTo,yTo); } } /*_________________________________________________*/ public void ScanFlash(Graphics g, int x, int y) { Branch branchFound=FindBranch( x, y); if (highlightedBranch != null) {if (branchFound==null) RevertBranch(g, highlightedBranch); else if (branchFound!=highlightedBranch) { RevertBranch(g, highlightedBranch); InvertBranch(g, branchFound); } } else if (branchFound!=null) InvertBranch(g, branchFound); } /*_________________________________________________*/ public void ScanDrop(Graphics g, int x, int y) { Branch branchTo=FindBranch( x, y); if (branchTo != null) {if (branchFrom==branchTo) { } else { Tree.MoveBranch(branchFrom, branchTo); controls.RedescribeTree(); } }; needsUpdating=true; branchFrom = null; } /*_________________________________________________*/ public boolean mouseMove(Event e, int x, int y) { Graphics g = getGraphics(); ScanFlash(g, x, y); return true; } /*_________________________________________________*/ public boolean mouseDown(Event e, int x, int y) { Graphics g = getGraphics(); ScanTouch(g, x, y); if (needsUpdating) repaint(); return true; } /*_________________________________________________*/ public boolean mouseDrag(Event e, int x, int y) { if (branchFrom!=null) { Graphics g = getGraphics(); g.setColor(Color.black); g.setXORMode(Color.gray); g.drawLine(xFrom,yFrom,xTo,yTo); xTo=x; yTo=y; g.drawLine(xFrom,yFrom,xTo,yTo); } return true; } /*_________________________________________________*/ public boolean mouseUp(Event e, int x, int y) { Graphics g = getGraphics(); if (branchFrom!=null) { ScanDrop( g, x, y); repaint(); } branchFrom=null; g.setXORMode(g.getColor()); return true; } } /** ======================================================================== */ public class TreeClass { Branch Root, SubRoot; int numTaxa; boolean exists; private int stringloc; /** ________________ read tree ________________ */ private void ParseTreeDescription(String TreeDescription, Branch Ancestor) { if (TreeDescription.charAt(stringloc) == '(') { stringloc++; Ancestor.sprout(); ParseTreeDescription(TreeDescription, Ancestor.left); stringloc++; //skip comma ParseTreeDescription(TreeDescription, Ancestor.right); stringloc++; //skip parensu } else { stringloc++; //skip tt name numTaxa++; } } public void ReadTree(String TreeDescription) { stringloc=0; numTaxa=0; ParseTreeDescription(TreeDescription, Root); exists=true; } /** ______________________________________________ */ private boolean DescendantOf(Branch branchD, Branch branchA) { return false; } private boolean NodeSlantsRight(Branch N) { if (N.ancestor.right==N) return true; else return false; } private Branch Sister(Branch N) { if (N.ancestor.right==N) return N.ancestor.left; else return N.ancestor.right; } /** ______________________________________________ */ public void MoveBranch(Branch branchFrom, Branch branchTo) { Branch sideN,C, G, F, H, NCAnc; boolean fromancslantRight, fromslantRight, toslantRight, NCslantRight, fromroot, toroot; if ((branchFrom.ancestor.ancestor == branchTo) & (branchTo == Root)) { branchFrom = Sister(branchFrom); branchTo = Sister(branchFrom.ancestor); } if ((branchFrom.ancestor == Root) & (branchTo.ancestor.ancestor == Root)) { sideN = branchFrom; branchFrom = branchTo; branchTo = sideN; } fromroot = false; toroot = false; fromslantRight = NodeSlantsRight(branchFrom); fromancslantRight = NodeSlantsRight(branchFrom.ancestor); toslantRight = NodeSlantsRight(branchTo); G = Sister(branchFrom); H = branchFrom.ancestor.ancestor; C = branchTo.ancestor; F = branchFrom.ancestor; if (F == Root) fromroot = true; else if (branchTo == Root ) toroot = true; if (fromslantRight == toslantRight) { sideN = F.left; F.left = F.right; F.right = sideN; } G.ancestor = H; F.ancestor = C; branchTo.ancestor = F; if (fromancslantRight) H.right = G; else H.left = G; if (toslantRight) { F.right = branchTo; C.right = F; } else { F.left = branchTo; C.left = F; } sideN = Sister(G); if (fromroot) { sideN = Root; Root = G; G = sideN; } if (toroot) { sideN = Root; Root = F; F = sideN; } if (!NodeSlantsRight(Root)) { SubRoot.right = Root; } } } /** ======================================================================== */ public class Branch { Branch left, right, ancestor; int x; int y; Polygon branchPoly; Color color; Branch(Branch Ancestor, boolean isFirstDescendant) { this.ancestor = Ancestor; this.color=Color.black; branchPoly= new Polygon(); branchPoly.xpoints = new int[5]; branchPoly.ypoints = new int[5]; branchPoly.npoints=5; } public boolean sprout() { this.left = new Branch(this, true); this.right = new Branch(this, false); return true; } } class BeanTreeControls extends Panel { TextField tf; TreeCanvas TreeDisplay; public BeanTreeControls(TreeCanvas TreeDisplay) { this.TreeDisplay = TreeDisplay; add(tf = new TextField("(((*,*),(*,*)),(((*,*),*),*));", 40)); add(new Button("Show")); } public boolean action(Event ev, Object arg) { if (ev.target instanceof Button) { /* destroy current tree if present */ /*Display.startApplet("BeanTree.html", "BeanTree.html", args);*/ TreeDisplay.treeDescription=tf.getText(); TreeDisplay.Tree.ReadTree(TreeDisplay.treeDescription); TreeDisplay.repaint(); return true; } return false; } public void RedescribeTree() { TreeDisplay.treeDescription = TreeDisplay.Describe(); tf.setText(TreeDisplay.treeDescription); repaint(); } }