/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * SVGTreeBranchDrawer.java * Copyright Remco Bouckaert remco@cs.auckland.ac.nz (C) 2011 */ package viz.graphics; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Stroke; /** This class takes care of drawing a single tree out of a tree set in SVG * into a StringBuffer */ public class SVGTreeDrawer extends TreeDrawer { StringBuffer m_buf; public SVGTreeDrawer(StringBuffer buf) { m_buf = buf; } public int m_branchStyle = 0; private void draw(int nX1, int nY1, int nX2, int nY2, float fWidth) { m_buf.append("<path " + "fill='none' " + "stroke='rgb(" +m_color.getRed()+ "," + m_color.getGreen() +"," + m_color.getBlue()+")' " + "stroke-width='"+ fWidth+"' " + "opacity='" + m_fAlpha + "' " + " d='"); m_buf.append("M"+nX1+" "+nY1+"L"+nX2+" "+nY2); m_buf.append("'/>\n"); } private void draw(int nX1, int nY1, int nX2, int nY2) { m_buf.append("M"+nX1+" "+nY1+"L"+nX2+" "+nY2); } private void drawarc(int nX1, int nY1, int nX2, int nY2) { m_buf.append("M"+nX1+" "+nY1+"A"+(nX2-nX1)+","+(nY2-nY1) + " 0 0,0 " +nX2+","+nY2); } /** * draw block tree using array representation of a tree. Adds jitter if * required **/ @Override void drawBlockTree(float[] nX, float[] nY, int [] color, Graphics2D g, float fScaleX, float fScaleY) { if (nX == null || nY == null) { return; } float fLineWidth = ((BasicStroke)g.getStroke()).getLineWidth(); float fAlpha = ((AlphaComposite)g.getComposite()).getAlpha(); int nRed = (color[0] >> 16) & 0xFF;//g.getColor().getRed(); int nGreen = (color[0] >> 8) & 0xFF;//g.getColor().getGreen(); int nBlue = (color[0] >> 0) & 0xFF;//g.getColor().getBlue(); m_buf.append("<path " + "fill='none' " + "stroke='rgb(" + nRed + "," + nGreen +"," + nBlue +")' " + "stroke-width='"+ fLineWidth+"' " + "opacity='" + fAlpha + "' " + " d='"); if (m_nJitter <= 0) { for (int i = 0; i < nX.length - 1; i+=4) { if (m_bRootAtTop) { draw((int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY), (int) (nX[i] * fScaleX), (int) (nY[i+1] * fScaleY)); draw((int) (nX[i] * fScaleX), (int) (nY[i+1] * fScaleY), (int) (nX[i + 3] * fScaleX), (int) (nY[i + 1] * fScaleY)); draw((int) (nX[i+3] * fScaleX), (int) (nY[i+2] * fScaleY), (int) (nX[i + 3] * fScaleX), (int) (nY[i + 3] * fScaleY)); } else { draw((int) (nY[i] * fScaleX), (int) (nX[i] * fScaleY), (int) (nY[i + 1] * fScaleX), (int) (nX[i] * fScaleY)); draw((int) (nY[i+1] * fScaleX), (int) (nX[i] * fScaleY), (int) (nY[i + 1] * fScaleX), (int) (nX[i + 3] * fScaleY)); draw((int) (nY[i+2] * fScaleX), (int) (nX[i+3] * fScaleY), (int) (nY[i + 3] * fScaleX), (int) (nX[i + 3] * fScaleY)); } } /* for (int i = 0; i < nX.length - 1; i++) { if (i % 4 != 3) { draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY)); } } */ } else { int[] nXJ = new int[nX.length]; for (int i = 0; i < nX.length; i++) { nXJ[i] = (int) (nX[i] * fScaleX) + m_random.nextInt(m_nJitter); } for (int i = 0; i < nX.length - 1; i++) { if (i % 4 != 3) { draw( nXJ[i], (int) (nY[i] * fScaleY), nXJ[i + 1], (int) (nY[i + 1] * fScaleY)); } } } m_buf.append("'/>\n"); } /** draw block tree with variable line widths, where line width represents some information in the metadata **/ @Override void drawBlockTree(float[] nX, float[] nY, float[]fLineWidth, float [] fTopLineWidth, int [] color, Graphics2D g, float fScaleX, float fScaleY) { if (nX == null || nY == null) { return; } if (m_nJitter <= 0) { for (int i = 0; i < nX.length - 2; i++) { if (i % 4 != 3) { if (i % 4 == 0 || i % 4 == 2) { float fWidth = fLineWidth[i] * LINE_WIDTH_SCALE; float fTopWidth = fTopLineWidth[i] * LINE_WIDTH_SCALE; Stroke stroke = new BasicStroke(fWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); ((Graphics2D) g).setStroke(stroke); if (m_bViewBlockTree) { if (i % 4 == 0) { draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fTopWidth/2.0f), fWidth); } else { // i % 4 == 2 draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fTopWidth/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f), fWidth); } } else { if (i % 4 == 0) { float fTopWidth2 = fTopLineWidth[i+2] * LINE_WIDTH_SCALE; if (nY[i+1] < nY[i+2]) { draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX)-1, (int) (((nY[i+1] + nY[i+2])/2.0) * fScaleY - (fTopWidth+fTopWidth2)/2.0f), fWidth); } else { draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX)-1, (int) (((nY[i+1] + nY[i+2])/2.0) * fScaleY - (fTopWidth-fTopWidth2)/2.0f), fWidth); } } else { // i % 4 == 2 float fTopWidth2 = fTopLineWidth[i-2] * LINE_WIDTH_SCALE; if (nY[i-1] < nY[i]) { draw( (int) (nX[i] * fScaleX)-1, (int) (((nY[i] +nY[i-1])/2.0)* fScaleY - (fTopWidth-fTopWidth2)/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f), fWidth); } else { draw( (int) (nX[i] * fScaleX)-1, (int) (((nY[i] +nY[i-1])/2.0)* fScaleY - (fTopWidth+fTopWidth2)/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f), fWidth); } } } } else if (i % 4 == 1 && m_bViewBlockTree) { Stroke stroke = new BasicStroke(m_nTreeWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); ((Graphics2D) g).setStroke(stroke); draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY), m_nTreeWidth); } } } } else { int[] nXJ = new int[nX.length]; for (int i = 0; i < nX.length; i++) { nXJ[i] = (int) (nX[i] * fScaleX) + m_random.nextInt(m_nJitter); } for (int i = 0; i < nX.length - 1; i++) { if (i % 4 != 3) { draw( nXJ[i], (int) (nY[i] * fScaleY), nXJ[i + 1], (int) (nY[i + 1] * fScaleY), m_nTreeWidth); } if (i % 4 == 0 || i % 4 == 2) { float fWidth = fLineWidth[i] * LINE_WIDTH_SCALE; Stroke stroke = new BasicStroke(fWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); ((Graphics2D) g).setStroke(stroke); draw( nXJ[i], (int) (nY[i] * fScaleY - fWidth/2.0f), nXJ[i + 1], (int) (nY[i + 1] * fScaleY - fWidth/2.0f), fWidth); } else if (i % 4 == 1) { Stroke stroke = new BasicStroke(m_nTreeWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL); ((Graphics2D) g).setStroke(stroke); draw( nXJ[i], (int) (nY[i] * fScaleY), nXJ[i + 1], (int) (nY[i + 1] * fScaleY), m_nTreeWidth); } } } } /** * draw triangle tree using array representation of a tree. Adds jitter * if required **/ @Override void drawTriangleTree(float[] nX, float[] nY, int [] color, Graphics2D g, float fScaleX, float fScaleY) { if (nX == null || nY == null) { return; } float fLineWidth = ((BasicStroke)g.getStroke()).getLineWidth(); float fAlpha = ((AlphaComposite)g.getComposite()).getAlpha(); // Color color = g.getColor(); int nRed = (color[0] >> 16) & 0xFF;//g.getColor().getRed(); int nGreen = (color[0] >> 8) & 0xFF;//g.getColor().getGreen(); int nBlue = (color[0] >> 0) & 0xFF;//g.getColor().getBlue(); m_buf.append("<path " + "fill='none' " + "stroke='rgb(" + nRed + "," + nGreen +"," + nBlue +")' " + "stroke-width='"+ fLineWidth+"' " + "opacity='" + fAlpha + "' " + " d='"); // ignore jitter for triangle trees if (m_bRootAtTop) { for (int i = 0; i < nX.length - 4; i++) { float fWidth = 0; float fTopWidth = 0; float fTopWidth2 = 0; if (i % 4 != 3) { if (i % 4 == 0 || i % 4 == 2) { if (m_branchStyle == 2) { if (i % 4 == 0) { if (nX[i+1] < nX[i+2]) { drawarc( (int) (nX[i] * fScaleX - fWidth/2.0f), (int) (nY[i] * fScaleY), (int) (((nX[i+1] + nX[i+2])/2.0) * fScaleX - (fTopWidth+fTopWidth2)/2.0f), (int) (nY[i + 1] * fScaleY)-1); } else { drawarc( (int) (nX[i] * fScaleX - fWidth/2.0f), (int) (nY[i] * fScaleY), (int) (((nX[i+1] + nX[i+2])/2.0) * fScaleX - (fTopWidth-fTopWidth2)/2.0f), (int) (nY[i + 1] * fScaleY)-1); } } else { // i % 4 == 2 if (nX[i-1] < nX[i]) { drawarc( (int) (((nX[i] +nX[i-1])/2.0)* fScaleX - (fTopWidth-fTopWidth2)/2.0f), (int) (nY[i] * fScaleY)-1, (int) (nX[i + 1] * fScaleX - fWidth/2.0f), (int) (nY[i + 1] * fScaleY)-1); } else { drawarc( (int) (((nX[i] +nX[i-1])/2.0)* fScaleX - (fTopWidth+fTopWidth2)/2.0f), (int) (nY[i] * fScaleY)-1, (int) (nX[i + 1] * fScaleX - fWidth/2.0f), (int) (nY[i + 1] * fScaleY)-1); } } } else { if (i % 4 == 0) { if (nX[i+1] < nX[i+2]) { draw( (int) (nX[i] * fScaleX - fWidth/2.0f), (int) (nY[i] * fScaleY), (int) (((nX[i+1] + nX[i+2])/2.0) * fScaleX - (fTopWidth+fTopWidth2)/2.0f), (int) (nY[i + 1] * fScaleY)-1); } else { draw( (int) (nX[i] * fScaleX - fWidth/2.0f), (int) (nY[i] * fScaleY), (int) (((nX[i+1] + nX[i+2])/2.0) * fScaleX - (fTopWidth-fTopWidth2)/2.0f), (int) (nY[i + 1] * fScaleY)-1); } } else { // i % 4 == 2 if (nX[i-1] < nX[i]) { draw( (int) (((nX[i] +nX[i-1])/2.0)* fScaleX - (fTopWidth-fTopWidth2)/2.0f), (int) (nY[i] * fScaleY)-1, (int) (nX[i + 1] * fScaleX - fWidth/2.0f), (int) (nY[i + 1] * fScaleY)-1); } else { draw( (int) (((nX[i] +nX[i-1])/2.0)* fScaleX - (fTopWidth+fTopWidth2)/2.0f), (int) (nY[i] * fScaleY)-1, (int) (nX[i + 1] * fScaleX - fWidth/2.0f), (int) (nY[i + 1] * fScaleY)-1); } } } } } } } else { for (int i = 0; i < nX.length - 4; i++) { float fWidth = 0; float fTopWidth = 0; float fTopWidth2 = 0; if (i % 4 != 3) { if (i % 4 == 0 || i % 4 == 2) { if (m_branchStyle == 2) { if (i % 4 == 0) { if (nY[i+1] < nY[i+2]) { drawarc( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX)-1, (int) (((nY[i+1] + nY[i+2])/2.0) * fScaleY - (fTopWidth+fTopWidth2)/2.0f)); } else { drawarc( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX)-1, (int) (((nY[i+1] + nY[i+2])/2.0) * fScaleY - (fTopWidth-fTopWidth2)/2.0f)); } } else { // i % 4 == 2 if (nY[i-1] < nY[i]) { drawarc( (int) (nX[i] * fScaleX)-1, (int) (((nY[i] +nY[i-1])/2.0)* fScaleY - (fTopWidth-fTopWidth2)/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f)); } else { drawarc( (int) (nX[i] * fScaleX)-1, (int) (((nY[i] +nY[i-1])/2.0)* fScaleY - (fTopWidth+fTopWidth2)/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f)); } } } else { if (i % 4 == 0) { if (nY[i+1] < nY[i+2]) { draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX)-1, (int) (((nY[i+1] + nY[i+2])/2.0) * fScaleY - (fTopWidth+fTopWidth2)/2.0f)); } else { draw( (int) (nX[i] * fScaleX), (int) (nY[i] * fScaleY - fWidth/2.0f), (int) (nX[i + 1] * fScaleX)-1, (int) (((nY[i+1] + nY[i+2])/2.0) * fScaleY - (fTopWidth-fTopWidth2)/2.0f)); } } else { // i % 4 == 2 if (nY[i-1] < nY[i]) { draw( (int) (nX[i] * fScaleX)-1, (int) (((nY[i] +nY[i-1])/2.0)* fScaleY - (fTopWidth-fTopWidth2)/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f)); } else { draw( (int) (nX[i] * fScaleX)-1, (int) (((nY[i] +nY[i-1])/2.0)* fScaleY - (fTopWidth+fTopWidth2)/2.0f), (int) (nX[i + 1] * fScaleX), (int) (nY[i + 1] * fScaleY - fWidth/2.0f)); } } } } } } } m_buf.append("'/>\n"); } Color m_color; float m_fAlpha; } // class BranchDrawer