简体   繁体   中英

How can I group Vertices in jung?

I began to learn Graph modeling with JUNG. I actually have two questions: 1. Is there any way I can group some vertices? Like draw a box around them? 2. Do JUNG support edges without a source vertex? If this is a normal edge: a -> b. I want to say -> b

thank you for your help

You can use VisualizationViewer#addPreRenderPaintable to register a Paintable in your VisualizationViewer . This paintable will be invoked before anything else is painted (ie before the vertices or the edges are painted). In this paintable, you can compute the bounding box of the vertices that you want to group, and simply paint this as a rectangle.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.Arrays;
import java.util.List;

import javax.swing.JFrame;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.Layer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractModalGraphMouse;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;

public class JUNGVertexStuffTest 
{
    public static void main(String[] args) 
    {
        JFrame jf = new JFrame();
        final Graph<String, String> g = getGraph();
        final VisualizationViewer<String, String> vv = 
            new VisualizationViewer<String, String>(
                new FRLayout<String, String>(g));

        final AbstractModalGraphMouse graphMouse = 
            new DefaultModalGraphMouse<String,String>();
        vv.setGraphMouse(graphMouse);

        List<String> verticesInBox = Arrays.asList("v0", "v1");
        addVertexGroupPainter(vv, verticesInBox);

        jf.getContentPane().add(vv);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.pack();
        jf.setVisible(true);
    }

    private static <V> void addVertexGroupPainter(
        final VisualizationViewer<V, ?> vv, final Iterable<V> verticesInBox)
    {
        vv.addPreRenderPaintable(new VisualizationViewer.Paintable()
        {
            @Override
            public boolean useTransform()
            {
                return true;
            }

            @Override
            public void paint(Graphics gr)
            {
                Graphics2D g = (Graphics2D)gr;

                Layout<V, ?> layout = vv.getGraphLayout();
                AffineTransform transform = 
                    vv.getRenderContext().
                       getMultiLayerTransformer().
                       getTransformer(Layer.LAYOUT).
                       getTransform();
                Rectangle2D boundingBox = 
                    computeBoundingBox(verticesInBox, layout, transform);

                double d = 20;
                Shape rect = new RoundRectangle2D.Double(
                    boundingBox.getMinX()-d, 
                    boundingBox.getMinY()-d,
                    boundingBox.getWidth()+d+d,
                    boundingBox.getHeight()+d+d, d, d);
                g.setColor(new Color(255,200,200));
                g.fill(rect);
                g.setColor(Color.BLACK);
                g.draw(rect);

            }
        });
    }


    private static <V> Rectangle2D computeBoundingBox(
        Iterable<V> vertices, Layout<V, ?> layout, AffineTransform at)
    {
        double minX = Double.MAX_VALUE;
        double minY = Double.MAX_VALUE;
        double maxX = -Double.MAX_VALUE;
        double maxY = -Double.MAX_VALUE;
        for (V vertex : vertices)
        {
            Point2D location = layout.transform(vertex);
            at.transform(location, location);
            minX = Math.min(minX, location.getX());
            minY = Math.min(minY, location.getY());
            maxX = Math.max(maxX, location.getX());
            maxY = Math.max(maxY, location.getY());
        }
        return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
    }


    public static Graph<String, String> getGraph() 
    {
        Graph<String, String> g = new DirectedSparseGraph<String, String>();
        g.addVertex("v0");
        g.addVertex("v1");
        g.addVertex("v2");
        g.addVertex("v3");
        g.addVertex("v4");
        g.addEdge("e0", "v0", "v1");
        g.addEdge("e1", "v1", "v2");
        g.addEdge("e2", "v2", "v3");
        g.addEdge("e3", "v3", "v4");
        g.addEdge("e4", "v4", "v0");
        g.addEdge("e5", "v1", "v3");
        g.addEdge("e6", "v2", "v4");
        return g;
    }
}

NOTE : Depending on how you determine which vertices should be grouped, and depending on the layout, there may be more elegant or efficient solutions. But this one should be generic, and even work with dynamic layouts or vertex sets.


Concerning the question about "edges without vertices": Such edges are not supported. First of all, because you have to specify two vertices when calling Graph#addEdge(...) . Apart from that, the crucial question here is how the direction of this edge should be determined. Of course one could consider "workarounds". For example, insert some special vertices that are declared as "dummy" vertices and excluded from rendering (and thus, only exist in order to be "one (invisible) endpoint" of such an edge. But this would be a hassle.

My crystal ball says that the intention is to indicate that a vertex has "further edges", whose endpoints are simply not relevant. IF this is the case, you could just paint some lines indicating these edges. This could roughly be done as follows (but this is only a sketch, and should not be considered as a profound recommendataion! There are certainly "better" solutions for this!)

    final Renderer.Vertex<String, String> originalVertexRenderer = 
        vv.getRenderer().getVertexRenderer();
    vv.getRenderer().setVertexRenderer(new Renderer.Vertex<String, String>()
    {
        @Override
        public void paintVertex(RenderContext<String, String> rc,
            Layout<String, String> layout, String vertex)
        {
            if (vertex.equals("v4"))
            {
                Point2D p = layout.transform(vertex);
                Line2D pseudoEdge = new Line2D.Double(
                    p.getX(), p.getY(), p.getX() + 100, p.getY() + 100); 
                rc.getGraphicsContext().draw(pseudoEdge);
            }
            originalVertexRenderer.paintVertex(rc, layout, vertex);
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM