繁体   English   中英

如何通过JUNG2绘制相同的边缘名称

[英]How to draw same edge name by JUNG2

我正在做JUNG2的绘制网络拓扑项目,现在发现JUNG2无法在不同的顶点绘制相同的边缘(名称)。 并报告如下:

Exception in thread "main" java.lang.IllegalArgumentException: edge GigabitEthernet0/3<--->GigabitEthernet0/0/0/0 already exists in this graph with endpoints <HKBR1, HKBR3> and cannot be added with endpoints <HKBR2, HKBR4>
at edu.uci.ics.jung.graph.AbstractGraph.getValidatedEndpoints(AbstractGraph.java:93)
at edu.uci.ics.jung.graph.SparseMultigraph.addEdge(SparseMultigraph.java:123)
at edu.uci.ics.jung.graph.AbstractGraph.addEdge(AbstractGraph.java:60)
at pkg.DrawnTopology.DrawnTopology(DrawnTopology.java:45)
at pkg.ReadLine.main(ReadLine.java:85)

我已将所有边和顶点存储到二维数组中。 二维数组数据从不同的文件中学习,因此数据是动态的。 由于网络拓扑可能具有相同的边缘名称,那么如何解决呢?

问题显然缺乏细节,但从描述和错误信息中,人们可能会猜到这里有什么问题:

您的图形可以定义为Graph<V, String>

它可能是Graph的子类,顶点类型无关紧要。 关键点是边缘类型是String

并且您正尝试向图表添加边缘,如下所示:

g.addEdge("edge0", v0, v1);
g.addEdge("edge0", v2, v3);

这将导致错误,因为边缘"edge0"存在两次。 (这是有道理的。否则:当你向图表询问"edge0"的端点时会发生什么?它应该返回v0,v1还是v2,v3 ?它只是模糊不清)。

(注意,这不仅是边缘类型为String时的情况。对于任何边缘类型都会发生,只要两条边彼此equal )。

这里一个简单的解决方案是引入一个包装String的专用Edge类:

class Edge
{
    private final String name;

    Edge(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return name;
    }
}

这个类没有equals方法重写。 因此,即使字符串相等,这种类型的两个对象也不会相等:

Edge e0 = new Edge("edge0");
Edge e1 = new Edge("edge0");
System.out.println(e0.equals(e1)); // prints "false"

然后,边标签可以简单地是这些边的toString表示,它返回原始字符串。

一个例子:

import javax.swing.JFrame;

import org.apache.commons.collections15.Transformer;

import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.visualization.VisualizationViewer;

class Edge
{
    private final String name;

    Edge(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return name;
    }
}

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

        class EdgeLabelTransformer implements Transformer<Edge, String>
        {
            @Override
            public String transform(Edge edge)
            {
                return edge.toString();
            }
        }
        vv.getRenderContext().setEdgeLabelTransformer(
            new EdgeLabelTransformer());

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

    public static Graph<String, Edge> getGraph()
    {
        Graph<String, Edge> g = new DirectedSparseGraph<String, Edge>();
        g.addVertex("v0");
        g.addVertex("v1");
        g.addEdge(new Edge("e0"), "v0", "v1");
        g.addEdge(new Edge("e0"), "v1", "v0");
        return g;
    }
}

旁注:对于某些应用程序,也可以将边缘的顶点存储在Edge类中。 然后你可以实现equalshashCode方法,它允许你在两个边具有相同的顶点时将它们视为相等。

从技术上讲,边缘名称必须是唯一的,但您可以操纵图表中显示的内容。 为了获得边的唯一名称,我使用以下模式来表示边的名称:fromVertex_edgeName_toVertex。

然后,您需要一个EdgeLabelTransformer

private class EdgeLabelTransformer<V> implements Transformer<V, String> {

    @Override
    public String transform(V v) {
        return v.toString().substring(v.toString().indexOf("_") + 1, v.toString().lastIndexOf("_"));
    }
}

这个变换器实际上告诉VisualViewer要显示什么。 因此,在我的情况下,它只显示中间部分,这导致您可以在图形中具有多个具有相同显示名称的边。

像这样添加变换器:

visualViewer.getRenderContext().setEdgeLabelTransformer(new EdgeLabelTransformer<String>());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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