我正在做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)
我已将所有边和顶点存储到二维数组中。二维数组数据从不同的文件中学习,因此数据是动态的。由于网络拓扑可能具有相同的边缘名称,那么如何解决呢?
答案 0 :(得分:3)
问题显然缺乏细节,但从描述和错误信息中,人们可能会猜到这里有什么问题:
您的图表可能被定义为Graph<V, String>
。
它可能是Graph
的子类,顶点类型无关紧要。关键点是边缘类型是String
)
您正试图像这样在图表中添加边缘:
g.addEdge("edge0", v0, v1);
g.addEdge("edge0", v2, v3);
这会导致错误,因为边"edge0"
存在两次。 (这是有道理的。否则:当您向图表询问"edge0"
的终点时会发生什么?它应该返回v0,v1
还是v2,v3
?它只是模棱两可的。)
(请注意,这不仅仅是边缘类型为String
的情况。任何边缘类型都会发生这种情况,只要两条边是equal
到彼此)。
这里的一个简单解决方案是引入一个包装字符串的专用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
类中。然后,您可以实现equals
和hashCode
方法,允许您在两个边具有相同顶点时将它们视为相等。
答案 1 :(得分:0)
从技术上讲,边缘名称必须是唯一的,但您可以操纵图表中显示的内容。为了获得边的唯一名称,我使用以下模式来表示边的名称: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>());