// // TreePrinter.java // MetaEvolve // // Version 1 // // Created by Brian Risk of Geneffects on March 15, 2004. // Last Modified on March 19, 2004. // www.geneffects.com // import java.io.*; import java.awt.*; import java.awt.image.*; import javax.imageio.*; import javax.swing.tree.*; public class TreeVisualizer { private int side = 512; //the height and width of the image private double circleDiminishFactor = 0.875; private double branchStartWidth = 16.0; private double branchDiminshFactor = 0.6666; private TreeBranchRenderer tbr = null; private TreeNodeRenderer tnr = null; private Color bkgndColor = Color.white; private Color arenaColor = Color.black; private Color branchColor = Color.white; private Color nodeColor = Color.red; private boolean renderNodes = true; private int ignorePastLevel = -1; //if set to less than 0, all levels are drawn public TreeVisualizer() {} //TreeNode is an interface found under java.swing.tree.* public BufferedImage renderTree(TreeNode tn) { BufferedImage bufferedImage = new BufferedImage(side, side, BufferedImage.TYPE_INT_RGB); // Create a graphics contents on the buffered image Graphics2D g2d = bufferedImage.createGraphics(); // Making the graphic object draw anti-aliased shapes g2d.addRenderingHints(new RenderingHints( RenderingHints.KEY_ANTIALIASING , RenderingHints.VALUE_ANTIALIAS_ON )); g2d.setColor(bkgndColor); g2d.fillRect(0,0,side, side); g2d.setColor(arenaColor); g2d.fillOval(0,0,side,side); g2d.setColor(branchColor); drawBranches(g2d, tn, 0, 0.0, 2.0 * Math.PI); if (renderNodes) { g2d.setColor(nodeColor); drawNodes(g2d, tn, 0, 0.0, 2.0 * Math.PI); } g2d.dispose(); return bufferedImage; } public void writeImageFile(RenderedImage ri, File f) { try { ImageIO.write(ri, "png", f); } catch (IOException e) { e.printStackTrace(); } } private Point drawBranches(Graphics2D g, TreeNode tn, int level, double start, double finish) { double span = finish - start; double middle = start + (span / 2.0); Point middlePoint = radToCart(getR(level), middle, side / 2, side / 2); Stroke strokeSize = getStroke(level); if (!tn.isLeaf()) { if (ignorePastLevel >= 0) { if (ignorePastLevel < level + 1) { return middlePoint; } } double subSection = span / (double) tn.getChildCount(); double s1 = start; double s2 = start + subSection; for (int i = 0; i < tn.getChildCount(); i++) { TreeNode tn2 = tn.getChildAt(i); Point connectPoint = drawBranches(g, tn2, level + 1, s1, s2); g.setStroke(strokeSize); if (tbr != null) { Color nc = tbr.getBranchColor(tn, level); if (nc != null) { g.setColor(nc); } } g.drawLine((int)middlePoint.getX(), (int)middlePoint.getY(), (int)connectPoint.getX(), (int)connectPoint.getY()); s1 += subSection; s2 += subSection; } } return middlePoint; } private void drawNodes(Graphics2D g, TreeNode tn, int level, double start, double finish) { double span = finish - start; double middle = start + (span / 2.0); Point middlePoint = radToCart(getR(level), middle, side / 2, side / 2); double x = middlePoint.getX(); double y = middlePoint.getY(); g.setStroke(new BasicStroke(0)); double r = branchStartWidth * Math.pow(branchDiminshFactor, level) ; if ((int) (2 * r) > 0) { if (tnr != null) { Color nc = tnr.getNodeColor(tn, level); if (nc != null) { g.setColor(nc); } } g.fillOval((int) (x - r), (int) (y - r), (int) (2 * r), (int) (2 * r)); } if (!tn.isLeaf()) { if (ignorePastLevel >= 0) { if (ignorePastLevel < level + 1) { return; } } double subSection = span / (double) tn.getChildCount(); double s1 = start; double s2 = start + subSection; for (int i = 0; i < tn.getChildCount(); i++) { TreeNode tn2 = tn.getChildAt(i); drawNodes(g, tn2, level + 1, s1, s2); s1 += subSection; s2 += subSection; } } } private Stroke getStroke(int level) { return new BasicStroke((float) (branchStartWidth * Math.pow(branchDiminshFactor, level)), BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER); } //x and y are the origin, the pixel location of the center of the coordinate system private Point radToCart(double r, double theta, int x, int y) { theta += Math.PI / 2.0; int nx = (int) (r * Math.cos(theta)) + x; int ny = (int) (r * Math.sin(theta)) + y; return new Point(nx, ny); } private double getR(int level) { double r = (double) (side / 2) - ((double) (side / 2) * Math.pow(circleDiminishFactor, level)); return r; } //mutating and accessing methods public void setSide(int s) {side = s;} public int getSide() {return side;} public void setCircleDiminishFactor(double c) {circleDiminishFactor = c;} public double getCircleDiminishFactor() {return circleDiminishFactor;} public void setBranchStartWidth(double b) {branchStartWidth = b;} public double getBranchStartWidth() {return branchStartWidth;} public void setBranchDiminishFactor(double s) {branchDiminshFactor = s;} public double getBranchDiminshFactor() {return branchDiminshFactor;} public void setBkgndColor(Color c) {bkgndColor = c;} public Color getBkgndColor() {return bkgndColor;} public void setArenaColor(Color c) {arenaColor = c;} public Color getArenaColor() {return arenaColor;} public void setBranchColor(Color c) {branchColor = c;} public Color getBranchColor() {return branchColor;} public void setNodeColor(Color c) {nodeColor = c;} public Color getNodeColor() {return nodeColor;} public void setTreeBranchRenderer(TreeBranchRenderer ntbr) {tbr = ntbr;} public TreeBranchRenderer getTreeBranchRenderer() {return tbr;} public void setTreeNodeRenderer(TreeNodeRenderer ntnr) {tnr = ntnr;} public TreeNodeRenderer getTreeNodeRenderer() {return tnr;} public void setRenderNodes(boolean r) {renderNodes = r;} public boolean getRenderNodes() {return renderNodes;} public void setIgnorePastLevel(int i) {ignorePastLevel = i;} public int getIgnorePastLevel() {return ignorePastLevel;} }