/* * Author: tdanford * Date: Jan 4, 2009 */ package org.seqcode.viz.paintable; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; public class DirectedTagPainter extends AbstractPaintable { private Color color; private String label; private boolean direction; public DirectedTagPainter() { color = Color.blue; direction = true; label = null; } public DirectedTagPainter(Color c) { this(); color = c; } public DirectedTagPainter(Color c, boolean dir) { this(c); direction = dir; } public DirectedTagPainter(boolean dir) { this(Color.blue, dir); } public void setFillColor(Color c) { color = c; } public void setLabel(String l) { label = l; } public void setDirection(boolean dir) { direction = dir; } /** * Some experimental code for painting arbitrary arrows from point-to-point. * */ public void paintArrow(Graphics2D g2, Point p1, Point p2, int thickness) { int dx = p2.x - p1.x; int dy = p2.y - p1.y; double dx2 = (double)(dx * dx); double dy2 = (double)(dy * dy); int dist = (int)Math.round(Math.sqrt(dx2 + dy2)); double rot = 0.0; if(dx == 0 && dy == 0) { rot = 0.0; } else { if(dy < 0) { rot = Math.acos((double)dx / (double)dist); } else { rot = 2.0 * Math.PI - Math.acos((double)dx / (double)dist); } } g2.translate(p1.x, p1.y); g2.rotate(-rot); paintItem(g2, 0, -thickness/2, dist, +thickness/2); g2.rotate(rot); g2.translate(-p1.x, -p1.y); } public void paintItem(Graphics g, int x1, int y1, int x2, int y2) { paintTag((Graphics2D)g, x1, y1, x2, y2); } public void paintTag(Graphics2D g2, int x1, int y1, int x2, int y2) { Font font = g2.getFont(); Stroke stroke = g2.getStroke(); int thickness = 3; g2.setStroke(new BasicStroke((float)thickness)); int w = x2-x1, h = y2-y1; int h2 = h/2, h3 = h/3; int w4 = w/4; int arrowDepth = Math.min(h, w); // width of the "head" of the arrow int ya = y1+thickness; // ya is the y of the top of the arrow base. int yb = y2-thickness; // yb is the y of the bottom of the arrow base int yc = y1+h2; // yc is the y of the middle (the point) of the arrow. int xb = direction ? x1 : x2; // xb is the beginning of the base. int xc = direction ? x2 : x1; // xc is the x of the point of the arrow head. // xa is the x of where the arrow base meets the head int xa = direction ? xc - arrowDepth : xc + arrowDepth; int bw = w-arrowDepth+1; // width of the "base" of the arrow int bh = h-(thickness*2); // height of the "base" of the arrow int[] hx = new int[] { xa, xc, xa }; // coordinates (hx and hy) for the arrow head. int[] hy = new int[] { ya, yc, yb }; g2.setColor(color); g2.fillPolygon(hx, hy, 3); // fills in the head of the arrow g2.fillRect((direction ? xb : xa), ya, bw, bh); // fills in the base of the arrow g2.setColor(Color.black); g2.drawLine(xb, ya, xa, ya); // draws the top line of the arrow body g2.drawLine(xb, ya, xb, yb); // draws the back line of the arrow body g2.drawLine(xb, yb, xa, yb); // draws the bottom line of the arrow body // outlines the arrow head. g2.drawLine(xa, ya, xa, ya); g2.drawLine(xa, ya, xc, yc); g2.drawLine(xa, yb, xa, yb); g2.drawLine(xa, yb, xc, yc); g2.setStroke(stroke); if(label != null) { int fontSize = font.getSize(); String fontFamily = font.getFamily(); int fontStyle = font.getStyle(); FontMetrics metrics = g2.getFontMetrics(); int lblWidth = metrics.charsWidth(label.toCharArray(), 0, label.length()); int lblHeight = metrics.getAscent() + metrics.getDescent(); while(fontSize > 7 && (lblWidth >= bw || lblHeight >= bh)) { fontSize -= 1; Font newFont = new Font(fontFamily, fontStyle, fontSize); g2.setFont(newFont); metrics = g2.getFontMetrics(); lblWidth = metrics.charsWidth(label.toCharArray(), 0, label.length()); lblHeight = metrics.getAscent() + metrics.getDescent(); } if(lblWidth <= bw && lblHeight <= bh) { if(direction) { g2.drawString(label, xb+bw-lblWidth, ya+bh-metrics.getDescent()); } else { g2.drawString(label, xa+2, ya+bh-metrics.getDescent()); } } } g2.setFont(font); } }