edu.uci.ics.jung.visualization.renderers.BasicEdgeRenderer.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.visualization.renderers.BasicEdgeRenderer.java

Source

/*
 * Copyright (c) 2005, The JUNG Authors
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either "license.txt"
 * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 *
 * Created on Aug 23, 2005
 */
package edu.uci.ics.jung.visualization.renderers;

import com.google.common.graph.EndpointPair;
import com.google.common.graph.Network;
import edu.uci.ics.jung.layout.model.Point;
import edu.uci.ics.jung.visualization.MultiLayerTransformer.Layer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationModel;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import edu.uci.ics.jung.visualization.decorators.ParallelEdgeShapeFunction;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
import edu.uci.ics.jung.visualization.util.Context;
import edu.uci.ics.jung.visualization.util.EdgeIndexFunction;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.function.Predicate;

public class BasicEdgeRenderer<N, E> implements Renderer.Edge<N, E> {

    protected EdgeArrowRenderingSupport<N, E> edgeArrowRenderingSupport = new BasicEdgeArrowRenderingSupport<N, E>();

    @Override
    public void paintEdge(RenderContext<N, E> renderContext, VisualizationModel<N, E> visualizationModel, E e) {
        GraphicsDecorator g2d = renderContext.getGraphicsContext();
        if (!renderContext.getEdgeIncludePredicate().test(e)) {
            return;
        }

        // don't draw edge if either incident node is not drawn
        EndpointPair<N> endpoints = visualizationModel.getNetwork().incidentNodes(e);
        N u = endpoints.nodeU();
        N v = endpoints.nodeV();
        Predicate<N> nodeIncludePredicate = renderContext.getNodeIncludePredicate();
        if (!nodeIncludePredicate.test(u) || !nodeIncludePredicate.test(v)) {
            return;
        }

        Stroke new_stroke = renderContext.edgeStrokeFunction().apply(e);
        Stroke old_stroke = g2d.getStroke();
        if (new_stroke != null) {
            g2d.setStroke(new_stroke);
        }

        drawSimpleEdge(renderContext, visualizationModel, e);

        // restore paint and stroke
        if (new_stroke != null) {
            g2d.setStroke(old_stroke);
        }
    }

    protected Shape prepareFinalEdgeShape(RenderContext<N, E> renderContext,
            VisualizationModel<N, E> visualizationModel, E e, int[] coords, boolean[] loop) {
        EndpointPair<N> endpoints = visualizationModel.getNetwork().incidentNodes(e);
        N v1 = endpoints.nodeU();
        N v2 = endpoints.nodeV();

        Point p1 = visualizationModel.getLayoutModel().apply(v1);
        Point p2 = visualizationModel.getLayoutModel().apply(v2);
        Point2D p2d1 = renderContext.getMultiLayerTransformer().transform(Layer.LAYOUT,
                new Point2D.Double(p1.x, p1.y));
        Point2D p2d2 = renderContext.getMultiLayerTransformer().transform(Layer.LAYOUT,
                new Point2D.Double(p2.x, p2.y));
        float x1 = (float) p2d1.getX();
        float y1 = (float) p2d1.getY();
        float x2 = (float) p2d2.getX();
        float y2 = (float) p2d2.getY();
        coords[0] = (int) x1;
        coords[1] = (int) y1;
        coords[2] = (int) x2;
        coords[3] = (int) y2;

        boolean isLoop = loop[0] = v1.equals(v2);
        Shape s2 = renderContext.getNodeShapeFunction().apply(v2);
        Shape edgeShape = renderContext.getEdgeShapeFunction()
                .apply(Context.getInstance(visualizationModel.getNetwork(), e));

        AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1);

        if (isLoop) {
            // this is a self-loop. scale it is larger than the node
            // it decorates and translate it so that its nadir is
            // at the center of the node.
            Rectangle2D s2Bounds = s2.getBounds2D();
            xform.scale(s2Bounds.getWidth(), s2Bounds.getHeight());
            xform.translate(0, -edgeShape.getBounds2D().getWidth() / 2);
        } else if (renderContext.getEdgeShapeFunction() instanceof EdgeShape.Orthogonal) {
            float dx = x2 - x1;
            float dy = y2 - y1;
            int index = 0;
            if (renderContext.getEdgeShapeFunction() instanceof ParallelEdgeShapeFunction) {
                @SuppressWarnings("unchecked")
                EdgeIndexFunction<N, E> peif = ((ParallelEdgeShapeFunction<N, E>) renderContext
                        .getEdgeShapeFunction()).getEdgeIndexFunction();
                index = peif.getIndex(Context.getInstance(visualizationModel.getNetwork(), e));
                index *= 20;
            }
            GeneralPath gp = new GeneralPath();
            gp.moveTo(0, 0); // the xform will do the translation to x1,y1
            if (x1 > x2) {
                if (y1 > y2) {
                    gp.lineTo(0, index);
                    gp.lineTo(dx - index, index);
                    gp.lineTo(dx - index, dy);
                    gp.lineTo(dx, dy);
                } else {
                    gp.lineTo(0, -index);
                    gp.lineTo(dx - index, -index);
                    gp.lineTo(dx - index, dy);
                    gp.lineTo(dx, dy);
                }

            } else {
                if (y1 > y2) {
                    gp.lineTo(0, index);
                    gp.lineTo(dx + index, index);
                    gp.lineTo(dx + index, dy);
                    gp.lineTo(dx, dy);

                } else {
                    gp.lineTo(0, -index);
                    gp.lineTo(dx + index, -index);
                    gp.lineTo(dx + index, dy);
                    gp.lineTo(dx, dy);
                }
            }

            edgeShape = gp;

        } else {
            // this is a normal edge. Rotate it to the angle between
            // node endpoints, then scale it to the distance between
            // the nodes
            float dx = x2 - x1;
            float dy = y2 - y1;
            float thetaRadians = (float) Math.atan2(dy, dx);
            xform.rotate(thetaRadians);
            float dist = (float) Math.sqrt(dx * dx + dy * dy);
            xform.scale(dist, 1.0);
        }

        edgeShape = xform.createTransformedShape(edgeShape);

        return edgeShape;
    }

    /**
     * Draws the edge <code>e</code>, whose endpoints are at <code>(x1,y1)</code> and <code>(x2,y2)
     * </code>, on the graphics context <code>g</code>. The <code>Shape</code> provided by the <code>
     * EdgeShapeFunction</code> instance is scaled in the x-direction so that its width is equal to
     * the distance between <code>(x1,y1)</code> and <code>(x2,y2)</code>.
     *
     * @param e the edge to be drawn
     */
    protected void drawSimpleEdge(RenderContext<N, E> renderContext, VisualizationModel<N, E> visualizationModel,
            E e) {

        int[] coords = new int[4];
        boolean[] loop = new boolean[1];
        Shape edgeShape = prepareFinalEdgeShape(renderContext, visualizationModel, e, coords, loop);

        int x1 = coords[0];
        int y1 = coords[1];
        int x2 = coords[2];
        int y2 = coords[3];
        boolean isLoop = loop[0];

        GraphicsDecorator g = renderContext.getGraphicsContext();
        Network<N, E> network = visualizationModel.getNetwork();

        Paint oldPaint = g.getPaint();

        // get Paints for filling and drawing
        // (filling is done first so that drawing and label use same Paint)
        Paint fill_paint = renderContext.getEdgeFillPaintFunction().apply(e);
        if (fill_paint != null) {
            g.setPaint(fill_paint);
            g.fill(edgeShape);
        }
        Paint draw_paint = renderContext.getEdgeDrawPaintFunction().apply(e);
        if (draw_paint != null) {
            g.setPaint(draw_paint);
            g.draw(edgeShape);
        }

        float scalex = (float) g.getTransform().getScaleX();
        float scaley = (float) g.getTransform().getScaleY();
        // see if arrows are too small to bother drawing
        if (scalex < .3 || scaley < .3) {
            return;
        }

        if (renderContext.renderEdgeArrow()) {

            Stroke new_stroke = renderContext.getEdgeArrowStrokeFunction().apply(e);
            Stroke old_stroke = g.getStroke();
            if (new_stroke != null) {
                g.setStroke(new_stroke);
            }

            Shape destNodeShape = renderContext.getNodeShapeFunction().apply(network.incidentNodes(e).nodeV());

            AffineTransform xf = AffineTransform.getTranslateInstance(x2, y2);
            destNodeShape = xf.createTransformedShape(destNodeShape);

            AffineTransform at = edgeArrowRenderingSupport.getArrowTransform(renderContext, edgeShape,
                    destNodeShape);
            if (at == null) {
                return;
            }
            Shape arrow = renderContext.getEdgeArrow();
            arrow = at.createTransformedShape(arrow);
            g.setPaint(renderContext.getArrowFillPaintFunction().apply(e));
            g.fill(arrow);
            g.setPaint(renderContext.getArrowDrawPaintFunction().apply(e));
            g.draw(arrow);

            if (!network.isDirected()) {
                Shape nodeShape = renderContext.getNodeShapeFunction().apply(network.incidentNodes(e).nodeU());
                xf = AffineTransform.getTranslateInstance(x1, y1);
                nodeShape = xf.createTransformedShape(nodeShape);
                at = edgeArrowRenderingSupport.getReverseArrowTransform(renderContext, edgeShape, nodeShape,
                        !isLoop);
                if (at == null) {
                    return;
                }
                arrow = renderContext.getEdgeArrow();
                arrow = at.createTransformedShape(arrow);
                g.setPaint(renderContext.getArrowFillPaintFunction().apply(e));
                g.fill(arrow);
                g.setPaint(renderContext.getArrowDrawPaintFunction().apply(e));
                g.draw(arrow);
            }
            // restore paint and stroke
            if (new_stroke != null) {
                g.setStroke(old_stroke);
            }
        }

        // restore old paint
        g.setPaint(oldPaint);
    }

    public EdgeArrowRenderingSupport<N, E> getEdgeArrowRenderingSupport() {
        return edgeArrowRenderingSupport;
    }

    public void setEdgeArrowRenderingSupport(EdgeArrowRenderingSupport<N, E> edgeArrowRenderingSupport) {
        this.edgeArrowRenderingSupport = edgeArrowRenderingSupport;
    }
}