blob: 8ed8e781c7090cbd865e944e439c4d7ea482db08 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.draw2d.graph;
/**
* Some utility methods for graphs.
*
* @author Eric Bordeau
* @since 2.1.2
*/
class GraphUtilities {
static Subgraph getCommonAncestor(Node left, Node right) {
Subgraph parent;
if (right instanceof Subgraph)
parent = (Subgraph) right;
else
parent = right.getParent();
while (parent != null) {
if (parent.isNested(left))
return parent;
parent = parent.getParent();
}
return null;
}
/**
* Returns <code>true</code> if the given graph contains at least one cycle.
*
* @param graph
* the graph to test
* @return whether the graph is cyclic
*/
public static boolean isCyclic(DirectedGraph graph) {
return isCyclic(new NodeList(graph.nodes));
}
/**
* Recursively removes leaf nodes from the list until there are no nodes
* remaining (acyclic) or there are no leaf nodes but the list is not empty
* (cyclic), then returns the result.
*
* @param nodes
* the list of nodes to test
* @return whether the graph is cyclic
*/
public static boolean isCyclic(NodeList nodes) {
if (nodes.isEmpty())
return false;
int size = nodes.size();
// remove all the leaf nodes from the graph
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.getNode(i);
if (node.outgoing == null || node.outgoing.isEmpty()) { // this is a
// leaf node
nodes.remove(node);
for (int j = 0; j < node.incoming.size(); j++) {
Edge e = node.incoming.getEdge(j);
e.source.outgoing.remove(e);
}
}
}
// if no nodes were removed, that means there are no leaf nodes and the
// graph is cyclic
if (nodes.size() == size)
return true;
// leaf nodes were removed, so recursively call this method with the new
// list
return isCyclic(nodes);
}
/**
* Counts the number of edge crossings in a DirectedGraph
*
* @param graph
* the graph whose crossed edges are counted
* @return the number of edge crossings in the graph
*/
public static int numberOfCrossingsInGraph(DirectedGraph graph) {
int crossings = 0;
for (int i = 0; i < graph.ranks.size(); i++) {
Rank rank = graph.ranks.getRank(i);
crossings += numberOfCrossingsInRank(rank);
}
return crossings;
}
/**
* Counts the number of edge crossings in a Rank
*
* @param rank
* the rank whose crossed edges are counted
* @return the number of edge crossings in the rank
*/
public static int numberOfCrossingsInRank(Rank rank) {
int crossings = 0;
for (int i = 0; i < rank.size() - 1; i++) {
Node currentNode = rank.getNode(i);
Node nextNode;
for (int j = i + 1; j < rank.size(); j++) {
nextNode = rank.getNode(j);
EdgeList currentOutgoing = currentNode.outgoing;
EdgeList nextOutgoing = nextNode.outgoing;
for (int k = 0; k < currentOutgoing.size(); k++) {
Edge currentEdge = currentOutgoing.getEdge(k);
for (int l = 0; l < nextOutgoing.size(); l++) {
if (nextOutgoing.getEdge(l).getIndexForRank(
currentNode.rank + 1) < currentEdge
.getIndexForRank(currentNode.rank + 1))
crossings++;
}
}
}
}
return crossings;
}
private static NodeList search(Node node, NodeList list) {
if (node.flag)
return list;
node.flag = true;
list.add(node);
for (int i = 0; i < node.outgoing.size(); i++)
search(node.outgoing.getEdge(i).target, list);
return list;
}
/**
* Returns <code>true</code> if adding an edge between the 2 given nodes
* will introduce a cycle in the containing graph.
*
* @param source
* the potential source node
* @param target
* the potential target node
* @return whether an edge between the 2 given nodes will introduce a cycle
*/
public static boolean willCauseCycle(Node source, Node target) {
NodeList nodes = search(target, new NodeList());
nodes.resetFlags();
return nodes.contains(source);
}
static boolean isConstrained(Node left, Node right) {
Subgraph common = left.getParent();
while (common != null && !common.isNested(right)) {
left = left.getParent();
common = left.getParent();
}
while (right.getParent() != common)
right = right.getParent();
return (left.rowOrder != -1 && right.rowOrder != -1)
&& left.rowOrder != right.rowOrder;
}
}