java - 如何在jung中对顶点进行分组?

标签 java graph jung jung2

我开始和JUNG一起学习图建模。 我其实有两个问题: 1. 有什么方法可以将一些顶点分组吗?比如在它们周围画一个框? 2. JUNG支持没有源顶点的边吗?如果这是一条普通边:a -> b。我想说->b

感谢您的帮助

最佳答案

您可以使用 VisualizationViewer#addPreRenderPaintableVisualizationViewer 中注册 Paintable。该可绘制对象将在绘制其他任何内容之前(即在绘制顶点或边之前)被调用。在此可绘制对象中,您可以计算要分组的顶点的边界框,然后将其简单地绘制为矩形。

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;
    }
}

注意:根据您确定应对哪些顶点进行分组的方式以及布局,可能会有更优雅或更高效的解决方案。但这应该是通用的,甚至可以使用动态布局或顶点集。

<小时/>

关于“没有顶点的边”的问题:不支持这样的边。首先,因为您必须在调用Graph#addEdge(...)时指定两个顶点。除此之外,这里的关键问题是如何确定这条边的方向。当然,人们可以考虑“解决方法”。例如,插入一些特殊的顶点,这些顶点被声明为“虚拟”顶点并从渲染中排除(因此,它们的存在只是为了成为此类边的“一个(不可见)端点”。但这会很麻烦。

我的 Crystal 球说,其目的是表明顶点具有“更远的边”,其端点根本不相关。 如果是这种情况,您可以只画一些线来指示这些边缘。这可以大致如下完成(但这只是一个草图,并且不应该被视为深刻的建议!肯定有“更好”的解决方案!)

    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);
        }
    });

关于java - 如何在jung中对顶点进行分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22936187/

相关文章:

java - 如何在使用camera2 api预览之前缓冲和延迟视频几秒钟

java - 无法加载bean : type:org. apache.struts2.views.gxp.inject.InjectedObjectContainer

algorithm - NP-完全图优化 : minimal node selection?

java - 是否可以在执行另一个 java 应用程序期间创建 java applet

java - 如何使用 JUNG 的注释系统注释我的图表?

java - 在 JUNG 2.0 Java 框架中使用 EditingModalGraphMouse 插件自定义鼠标菜单

java - 将字符串解释为打包的二进制数据,Python 与 Java

java - 在android中使用JSON将字符串编码为UTF-8

python - NetworkX:如何将节点坐标分配为属性?

algorithm - 从固定节点以最小成本到达节点的方法数