edgerenderer.java

来自「用applet实现很多应用小程序」· Java 代码 · 共 523 行 · 第 1/2 页

JAVA
523
字号
package prefuse.render;

import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import prefuse.Constants;
import prefuse.util.ColorLib;
import prefuse.util.GraphicsLib;
import prefuse.util.StrokeLib;
import prefuse.visual.EdgeItem;
import prefuse.visual.VisualItem;


/**
 * <p>Renderer that draws edges as lines connecting nodes. Both
 * straight and curved lines are supported. Curved lines are drawn using
 * cubic Bezier curves. Subclasses can override the
 * {@link #getCurveControlPoints(EdgeItem, Point2D[], double, double, double, double)}
 * method to provide custom control point assignment for such curves.</p>
 * 
 * <p>This class also supports arrows for directed edges. See the
 * {@link #setArrowType(int)} method for more.</p>
 * 
 * @version 1.0
 * @author <a href="http://jheer.org">jeffrey heer</a>
 */
public class EdgeRenderer extends AbstractShapeRenderer {
    
    public static final String EDGE_TYPE = "edgeType";
    
    protected static final double HALF_PI = Math.PI / 2;
    
    protected Line2D       m_line  = new Line2D.Float();
    protected CubicCurve2D m_cubic = new CubicCurve2D.Float();

    protected int     m_edgeType  = Constants.EDGE_TYPE_LINE;
    protected int     m_xAlign1   = Constants.CENTER;
    protected int     m_yAlign1   = Constants.CENTER;
    protected int     m_xAlign2   = Constants.CENTER;
    protected int     m_yAlign2   = Constants.CENTER;
    protected double  m_width     = 1;
    protected float   m_curWidth  = 1;
    protected Point2D m_tmpPoints[]  = new Point2D[2];
    protected Point2D m_ctrlPoints[] = new Point2D[2];
    protected Point2D m_isctPoints[] = new Point2D[2];
    
    // arrow head handling
    protected int     m_edgeArrow   = Constants.EDGE_ARROW_FORWARD;
    protected int     m_arrowWidth  = 8;
    protected int     m_arrowHeight = 12;
    protected Polygon m_arrowHead   = updateArrowHead(
                                        m_arrowWidth, m_arrowHeight);
    protected AffineTransform m_arrowTrans = new AffineTransform();
    protected Shape   m_curArrow;

    /**
     * Create a new EdgeRenderer.
     */
    public EdgeRenderer() {
        m_tmpPoints[0]  = new Point2D.Float();
        m_tmpPoints[1]  = new Point2D.Float();
        m_ctrlPoints[0] = new Point2D.Float();
        m_ctrlPoints[1] = new Point2D.Float();      
        m_isctPoints[0] = new Point2D.Float();
        m_isctPoints[1] = new Point2D.Float();      
    }

    /**
     * Create a new EdgeRenderer with the given edge type.
     * @param edgeType the edge type, one of
     * {@link prefuse.Constants#EDGE_TYPE_LINE} or
     * {@link prefuse.Constants#EDGE_TYPE_CURVE}.
     */
    public EdgeRenderer(int edgeType) {
        this(edgeType, Constants.EDGE_ARROW_FORWARD);
    }
    
    /**
     * Create a new EdgeRenderer with the given edge and arrow types.
     * @param edgeType the edge type, one of
     * {@link prefuse.Constants#EDGE_TYPE_LINE} or
     * {@link prefuse.Constants#EDGE_TYPE_CURVE}.
     * @param arrowType the arrow type, one of
     * {@link prefuse.Constants#EDGE_ARROW_FORWARD},
     * {@link prefuse.Constants#EDGE_ARROW_REVERSE}, or
     * {@link prefuse.Constants#EDGE_ARROW_NONE}.
     * @see #setArrowType(int)
     */
    public EdgeRenderer(int edgeType, int arrowType) {
        this();
        setEdgeType(edgeType);
        setArrowType(arrowType);
    }
    
    /**
     * @see prefuse.render.AbstractShapeRenderer#getRenderType(prefuse.visual.VisualItem)
     */
    public int getRenderType(VisualItem item) {
        return RENDER_TYPE_DRAW;
    }
    
    /**
     * @see prefuse.render.AbstractShapeRenderer#getRawShape(prefuse.visual.VisualItem)
     */
    protected Shape getRawShape(VisualItem item) {
        EdgeItem   edge = (EdgeItem)item;
        VisualItem item1 = edge.getSourceItem();
        VisualItem item2 = edge.getTargetItem();
        
        int type = m_edgeType;
        
        getAlignedPoint(m_tmpPoints[0], item1.getBounds(),
                        m_xAlign1, m_yAlign1);
        getAlignedPoint(m_tmpPoints[1], item2.getBounds(),
                        m_xAlign2, m_yAlign2);
        m_curWidth = (float)(m_width * getLineWidth(item));
        
        // create the arrow head, if needed
        EdgeItem e = (EdgeItem)item;
        if ( e.isDirected() && m_edgeArrow != Constants.EDGE_ARROW_NONE ) {
            // get starting and ending edge endpoints
            boolean forward = (m_edgeArrow == Constants.EDGE_ARROW_FORWARD);
            Point2D start = null, end = null;
            start = m_tmpPoints[forward?0:1];
            end   = m_tmpPoints[forward?1:0];
            
            // compute the intersection with the target bounding box
            VisualItem dest = forward ? e.getTargetItem() : e.getSourceItem();
            int i = GraphicsLib.intersectLineRectangle(start, end,
                    dest.getBounds(), m_isctPoints);
            if ( i > 0 ) end = m_isctPoints[0];
            
            // create the arrow head shape
            AffineTransform at = getArrowTrans(start, end, m_curWidth);
            m_curArrow = at.createTransformedShape(m_arrowHead);
            
            // update the endpoints for the edge shape
            // need to bias this by arrow head size
            Point2D lineEnd = m_tmpPoints[forward?1:0]; 
            lineEnd.setLocation(0, -m_arrowHeight);
            at.transform(lineEnd, lineEnd);
        } else {
            m_curArrow = null;
        }
        
        // create the edge shape
        Shape shape = null;
        double n1x = m_tmpPoints[0].getX();
        double n1y = m_tmpPoints[0].getY();
        double n2x = m_tmpPoints[1].getX();
        double n2y = m_tmpPoints[1].getY();
        switch ( type ) {
            case Constants.EDGE_TYPE_LINE:          
                m_line.setLine(n1x, n1y, n2x, n2y);
                shape = m_line;
                break;
            case Constants.EDGE_TYPE_CURVE:
                getCurveControlPoints(edge, m_ctrlPoints,n1x,n1y,n2x,n2y);
                m_cubic.setCurve(n1x, n1y,
                                m_ctrlPoints[0].getX(), m_ctrlPoints[0].getY(),
                                m_ctrlPoints[1].getX(), m_ctrlPoints[1].getY(),
                                n2x, n2y);
                shape = m_cubic;
                break;
            default:
                throw new IllegalStateException("Unknown edge type");
        }
        
        // return the edge shape
        return shape;
    }

    /**
     * @see prefuse.render.Renderer#render(java.awt.Graphics2D, prefuse.visual.VisualItem)
     */
    public void render(Graphics2D g, VisualItem item) {
        // render the edge line
        super.render(g, item);
        // render the edge arrow head, if appropriate
        if ( m_curArrow != null ) {
            g.setPaint(ColorLib.getColor(item.getFillColor()));
            g.fill(m_curArrow);
        }
    }

    /**
     * Returns an affine transformation that maps the arrowhead shape
     * to the position and orientation specified by the provided
     * line segment end points.
     */
    protected AffineTransform getArrowTrans(Point2D p1, Point2D p2, 
                                            double width)
    {
        m_arrowTrans.setToTranslation(p2.getX(), p2.getY());
        m_arrowTrans.rotate(-HALF_PI + 
            Math.atan2(p2.getY()-p1.getY(), p2.getX()-p1.getX()));
        if ( width > 1 ) {
            double scalar = width/4;
            m_arrowTrans.scale(scalar, scalar);
        }
        return m_arrowTrans;
    }
    
    /**
     * Update the dimensions of the arrow head, creating a new
     * arrow head if necessary. The return value is also set
     * as the member variable <code>m_arrowHead</code>
     * @param w the width of the untransformed arrow head base, in pixels
     * @param h the height of the untransformed arrow head, in pixels
     * @return the untransformed arrow head shape
     */
    protected Polygon updateArrowHead(int w, int h) {
        if ( m_arrowHead == null ) {
            m_arrowHead = new Polygon();
        } else {
            m_arrowHead.reset();
        }
        m_arrowHead.addPoint(0, 0);
        m_arrowHead.addPoint(-w/2, -h);
        m_arrowHead.addPoint( w/2, -h);
        m_arrowHead.addPoint(0, 0);
        return m_arrowHead;
    }
        
    

    /**
     * @see prefuse.render.AbstractShapeRenderer#getTransform(prefuse.visual.VisualItem)
     */
    protected AffineTransform getTransform(VisualItem item) {
        return null;
    }
    
    /**
     * @see prefuse.render.Renderer#locatePoint(java.awt.geom.Point2D, prefuse.visual.VisualItem)
     */
    public boolean locatePoint(Point2D p, VisualItem item) {
        Shape s = getShape(item);
        if ( s == null ) {
            return false;
        } else {
            double width = Math.max(2, getLineWidth(item));
            double halfWidth = width/2.0;
            return s.intersects(p.getX()-halfWidth,
                                p.getY()-halfWidth,
                                width,width);
        }
    }
    
    /**
     * @see prefuse.render.Renderer#setBounds(prefuse.visual.VisualItem)
     */
    public void setBounds(VisualItem item) {
        if ( !m_manageBounds ) return;
        Shape shape = getShape(item);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?