/*
* This file is part of JGAP.
*
* JGAP offers a dual license model containing the LGPL as well as the MPL.
*
* For licensing information please see the file license.txt included with JGAP
* or have a look at the top of class org.jgap.Chromosome which representatively
* includes the JGAP license policy applicable for any file delivered with JGAP.
*/
package org.jgap.util.tree;
//
// 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 {
/** String containing the CVS revision. Read out via reflection!*/
private final static String CVS_REVISION = "$Revision: 1.2 $";
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;
}
}