edu.uci.ics.jung.visualization.renderers.BasicEdgeRenderer Maven / Gradle / Ivy
/*
* 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 implements Renderer.Edge {
protected EdgeArrowRenderingSupport edgeArrowRenderingSupport =
new BasicEdgeArrowRenderingSupport();
@Override
public void paintEdge(
RenderContext renderContext, VisualizationModel 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 endpoints = visualizationModel.getNetwork().incidentNodes(e);
N u = endpoints.nodeU();
N v = endpoints.nodeV();
Predicate 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 renderContext,
VisualizationModel visualizationModel,
E e,
int[] coords,
boolean[] loop) {
EndpointPair 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 peif =
((ParallelEdgeShapeFunction) 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 e
, whose endpoints are at (x1,y1)
and (x2,y2)
*
, on the graphics context g
. The Shape
provided by the
* EdgeShapeFunction
instance is scaled in the x-direction so that its width is equal to
* the distance between (x1,y1)
and (x2,y2)
.
*
* @param e the edge to be drawn
*/
protected void drawSimpleEdge(
RenderContext renderContext, VisualizationModel 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 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 getEdgeArrowRenderingSupport() {
return edgeArrowRenderingSupport;
}
public void setEdgeArrowRenderingSupport(
EdgeArrowRenderingSupport edgeArrowRenderingSupport) {
this.edgeArrowRenderingSupport = edgeArrowRenderingSupport;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy