/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* HierarchicalBCEngine.java
* Copyright (C) 2003 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui.graphvisualizer;
import weka.core.FastVector;
import weka.gui.graphvisualizer.GraphNode;
import weka.gui.graphvisualizer.GraphEdge;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JCheckBox;
import javax.swing.ButtonGroup;
import javax.swing.BorderFactory;
import javax.swing.JProgressBar;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
/**
* This class lays out the vertices of a graph in a
* hierarchy of vertical levels, with a number of nodes
* in each level. The number of levels is the depth of
* the deepest child reachable from some parent at level
* 0. It implements a layout technique as described by
* K. Sugiyama, S. Tagawa, and M. Toda. in "Methods for
* visual understanding of hierarchical systems", IEEE
* Transactions on Systems, Man and Cybernetics,
* SMC-11(2):109-125, Feb. 1981.
*
There have been a few modifications made, however.
* The crossings function is changed as it was non-linear
* in time complexity. Furthermore, we don't have any
* interconnection matrices for each level, instead we
* just have one big interconnection matrix for the
* whole graph and a int[][] array which stores the
* vertices present in each level.
*
* @author Ashraf M. Kibriya (amk14@cs.waikato.ac.nz)
* @version $Revision: 1.6 $ - 24 Apr 2003 - Initial version (Ashraf M. Kibriya)
*
*/
public class HierarchicalBCEngine implements GraphConstants, LayoutEngine {
/** FastVector containing nodes and edges */
protected FastVector m_nodes, m_edges;
/** FastVector containing listeners for
* layoutCompleteEvent generated by this
* LayoutEngine */
protected FastVector layoutCompleteListeners;
/** Interconnection matrix for the graph */
protected int graphMatrix[][];
/** Array containing the indices of nodes in each level.
* The nodeLevels.length is equal to the number of levels */
protected int nodeLevels[][];
/** The nodeWidth and nodeHeight */
protected int m_nodeWidth, m_nodeHeight;
/* The following radio buttons control the
way the layout is performed. If any
of the following is changed then we
need to perform a complete relayout
*/
protected JRadioButton m_jRbNaiveLayout;
protected JRadioButton m_jRbPriorityLayout;
protected JRadioButton m_jRbTopdown;
protected JRadioButton m_jRbBottomup;
/** controls edge concentration by concentrating multilple singular dummy
* child nodes into one plural dummy child node
*/
protected JCheckBox m_jCbEdgeConcentration;
/** The panel containing extra options,
* specific to this LayoutEngine, for
* greater control over layout of the graph */
protected JPanel m_controlsPanel;
/** The progress bar to show the progress
* of the layout process */
protected JProgressBar m_progress;
/** This tells the the LayoutGraph method if
* a completeReLayout should be performed
* when it is called. */
protected boolean m_completeReLayout=false;
/** This contains the original size of the nodes vector
* when it was passed in through the constructor, before
* adding all the dummy vertices */
private int origNodesSize;
/** Constructor - takes in FastVectors of nodes and edges, and the initial
* width and height of a node
*/
public HierarchicalBCEngine(FastVector nodes, FastVector edges, int nodeWidth,
int nodeHeight) {
m_nodes = nodes; m_edges = edges; m_nodeWidth = nodeWidth;
m_nodeHeight = nodeHeight;
makeGUIPanel(false);
}
/** Constructor - takes in FastVectors of nodes and edges, the initial width
* and height of a node, and a boolean value to indicate if the edges
* should be concentrated.
* @param nodes - FastVector containing all the nodes
* @param edges - FastVector containing all the edges
* @param nodeWidth - A node's allowed width
* @param nodeHeight - A node's allowed height
* @param edgeConcentration - True: if want to concentrate edges,
* False: otherwise
*/
public HierarchicalBCEngine(FastVector nodes, FastVector edges,
int nodeWidth, int nodeHeight, boolean edgeConcentration) {
m_nodes = nodes; m_edges = edges; m_nodeWidth = nodeWidth;
m_nodeHeight = nodeHeight;
makeGUIPanel(edgeConcentration);
}
/** SimpleConstructor
* If we want to instantiate the class first, and if information for
* nodes and edges is not available. However, we would have to manually
* provide all the information later on by calling setNodesEdges and
* setNodeSize methods
*/
public HierarchicalBCEngine() { }
/**
* This methods makes the gui extra controls panel "m_controlsPanel"
*/
protected void makeGUIPanel(boolean edgeConc) {
m_jRbNaiveLayout = new JRadioButton("Naive Layout");
m_jRbPriorityLayout = new JRadioButton("Priority Layout");
ButtonGroup bg = new ButtonGroup();
bg.add(m_jRbNaiveLayout);
bg.add(m_jRbPriorityLayout);
m_jRbPriorityLayout.setSelected(true);
ActionListener a = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
m_completeReLayout=true;
}
};
m_jRbTopdown = new JRadioButton("Top Down");
m_jRbBottomup = new JRadioButton("Bottom Up");
m_jRbTopdown.addActionListener(a);
m_jRbBottomup.addActionListener(a);
bg = new ButtonGroup();
bg.add(m_jRbTopdown);
bg.add(m_jRbBottomup);
m_jRbBottomup.setSelected(true);
m_jCbEdgeConcentration = new JCheckBox("With Edge Concentration", edgeConc);
m_jCbEdgeConcentration.setSelected(edgeConc);
m_jCbEdgeConcentration.addActionListener(a);
JPanel jp1 = new JPanel( new GridBagLayout() );
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.anchor = gbc.NORTHWEST;
gbc.weightx = 1;
gbc.fill = gbc.HORIZONTAL;
jp1.add(m_jRbNaiveLayout, gbc);
jp1.add(m_jRbPriorityLayout, gbc);
jp1.setBorder( BorderFactory.createTitledBorder("Layout Type") );
JPanel jp2 = new JPanel( new GridBagLayout() );
jp2.add(m_jRbTopdown, gbc);
jp2.add(m_jRbBottomup, gbc);
jp2.setBorder( BorderFactory.createTitledBorder("Layout Method") );
m_progress = new JProgressBar(0, 11);
m_progress.setBorderPainted(false);
m_progress.setStringPainted(true);
m_progress.setString("");
m_progress.setValue(0);
m_controlsPanel = new JPanel( new GridBagLayout() );
m_controlsPanel.add(jp1, gbc);
m_controlsPanel.add(jp2, gbc);
m_controlsPanel.add(m_jCbEdgeConcentration, gbc);
}
/** give access to set of graph nodes */
public FastVector getNodes() {
return m_nodes;
}
/** This method returns a handle to the extra
* controls panel, so that the visualizing
* class can add it to some of it's own
* gui panel.
*/
public JPanel getControlPanel() {
return m_controlsPanel;
}
/** Returns a handle to the progressBar
* of this LayoutEngine.
*/
public JProgressBar getProgressBar() {
return m_progress;
}
/** Sets the nodes and edges for this LayoutEngine.
* Must be used if the class created by simple
* HierarchicalBCEngine() constructor.
* @param nodes - FastVector containing all the nodes
* @param edges - FastVector containing all the edges
*/
public void setNodesEdges(FastVector nodes, FastVector edges) {
m_nodes = nodes; m_edges = edges;
}
/**
* Sets the size of a node. This method must be
* used if the class created by simple
* HierarchicalBCEngine() constructor.
* @param nodeWidth - A node's allowed width
* @param nodeHeight - A node's allowed height
*/
public void setNodeSize(int nodeWidth, int nodeHeight) {
m_nodeWidth = nodeWidth;
m_nodeHeight = nodeHeight;
}
/**
* Method to add a LayoutCompleteEventListener
* @param l - Listener to receive the LayoutCompleteEvent by this
* class.
*/
public void addLayoutCompleteEventListener(LayoutCompleteEventListener l) {
if(layoutCompleteListeners==null)
layoutCompleteListeners = new FastVector();
layoutCompleteListeners.addElement(l);
}
/**
* Method to remove a LayoutCompleteEventListener.
* @param e - The LayoutCompleteEventListener to remove.
*/
public void removeLayoutCompleteEventListener(LayoutCompleteEventListener e){
if(layoutCompleteListeners!=null) {
LayoutCompleteEventListener l;
for(int i=0; i The layout is performed in a separate thread and the progress
* bar of the class is updated for each of the steps as the process
* continues.
*/
public void layoutGraph() {
//cannot perform a layout if no description of nodes and/or edges is provided
if(m_nodes==null || m_edges==null)
return;
Thread th = new Thread() {
public void run() {
m_progress.setBorderPainted(true);
if(nodeLevels==null) {
makeProperHierarchy();
}
else if(m_completeReLayout==true) {
clearTemps_and_EdgesFromNodes(); makeProperHierarchy();
m_completeReLayout=false;
}
//minimizing crossings
if(m_jRbTopdown.isSelected()) {
int crossbefore=crossings(nodeLevels), crossafter=0, i=0;
do {
m_progress.setValue(i+4);
m_progress.setString("Minimizing Crossings: Pass"+(i+1));
if(i!=0)
crossbefore = crossafter;
nodeLevels = minimizeCrossings(false, nodeLevels);
crossafter = crossings(nodeLevels);
i++;
}
while(crossafternodesLevel[j])
min = nodesLevel[j];
}
//if the shallowest child of a parent has a depth greater than 1
// and it is not a lone parent with no children
if(min!=65536 && min>1)
nodesLevel[i]=min-1;
}
}
//System.out.println("");
int maxLevel=0;
for(int i=0; imaxLevel)
maxLevel = nodesLevel[i];
//System.out.println( ((GraphNode)m_nodes.elementAt(i)).ID+" "+i+">"+
// nodesLevel[i]);
}
int levelCounts[] = new int[maxLevel+1];
for(int i=0; i"+levelCounts[nodesLevel[i]]);
nodeLevels[nodesLevel[i]][levelsCounter[nodesLevel[i]]++] = i;
}
m_progress.setValue(3);
m_progress.setString("Removing gaps by adding dummy vertices");
//*Making a proper Hierarchy by putting in dummy vertices to close all gaps
if(m_jCbEdgeConcentration.isSelected())
removeGapsWithEdgeConcentration(nodesLevel);
else
removeGaps(nodesLevel);
//After assigning levels and adding dummy vertices
//System.out.print("\n\t");
//for(int i=0; i0)
if(nodesLevel[i]>nodesLevel[n]+1) {
int tempMatrix[][] =
new int[graphMatrix.length+(nodesLevel[i]-nodesLevel[n]-1)]
[graphMatrix.length+(nodesLevel[i]-nodesLevel[n]-1)];
int level = nodesLevel[n]+1;
copyMatrix(graphMatrix, tempMatrix);
String s1 = new String("S"+tempCnt++);
m_nodes.addElement(new GraphNode(s1, s1, SINGULAR_DUMMY)); //true));
int temp3 [] = new int[nodeLevels[level].length+1];
//for(int j=0; jlen)
tempMatrix[k][k-1]=-1*tempMatrix[n][i];
}
//temp[lastTempNodeCreated][targetNode]=temp[origNode][targetNode]
tempMatrix[k][i]=tempMatrix[n][i];
//System.out.println("k "+((GraphNode)m_nodes.elementAt(k)).ID+
// " i "+((GraphNode)m_nodes.elementAt(i)).ID+
// " n "+((GraphNode)m_nodes.elementAt(n)).ID+
// " len "+((GraphNode)m_nodes.elementAt(len)).ID );
//temp[origNode][firstTempNodecreated] = temp[origNode][targetNode]
tempMatrix[n][len] = tempMatrix[n][i];
//temp[firstTempNodeCreated][origNode] for reverse tracing
tempMatrix[len][n] = -1*tempMatrix[n][i];
//temp[targetNode][lastTempNodecreated] for reverse tracing
tempMatrix[i][k] = -1*tempMatrix[n][i];
//temp[lastTempNodeCreated][secondlastNode] for reverse tracing
//but only do this if more than 1 temp nodes are created
if(k>len)
tempMatrix[k][k-1] = -1*tempMatrix[n][i];
//temp[origNode][targetNode] = 0 unlinking as they have been
// linked by a chain of temporary nodes now.
tempMatrix[n][i] = 0;
tempMatrix[i][n] = 0;
graphMatrix = tempMatrix;
}
else {
//****Even if there is no gap just add a reference for the
//****parent to the child for reverse tracing, useful if the
//****there is a reversed edge from parent to child and therefore
//****visualizer would know to highlight this edge when
//****highlighting the child.
graphMatrix[i][n]=-1*graphMatrix[n][i];
}
}
}
//Interconnection matrices at each level, 1 to n-1 after minimizing edges
//printMatrices(nodeLevels);
}
/**
* This method removes gaps from the graph. It tries to minimise the number
* of edges by concentrating multiple dummy nodes from the same parent and
* on the same vertical level into one. It takes as an argument of int[]
* of length m_nodes.size() containing the level of each
* node.
*/
private void removeGapsWithEdgeConcentration(int nodesLevel[]) {
final int temp = m_nodes.size(), temp2=graphMatrix[0].length;
int tempCnt=1;
for(int n=0; n0)
if(nodesLevel[i]>nodesLevel[n]+1) {
//System.out.println("Processing node "+
// ((GraphNode)m_nodes.elementAt(n)).ID+
// " for "+((GraphNode)m_nodes.elementAt(i)).ID);
int tempLevel=nodesLevel[n];
boolean tempNodePresent=false;
int k=temp;
int tempnode = n;
while(tempLevel < nodesLevel[i]-1 ) {
tempNodePresent=false;
for(; k0) {
//System.out.println("tempnode will be true");
tempNodePresent = true; break;
}
}
if(tempNodePresent) {
tempnode=k; k=k+1;
tempLevel++;
}
else {
if(tempnode!=n)
tempnode=k-1;
//System.out.println("breaking from loop");
break;
}
}
if(((GraphNode)m_nodes.elementAt(tempnode)).nodeType==SINGULAR_DUMMY)
((GraphNode)m_nodes.elementAt(tempnode)).nodeType=PLURAL_DUMMY;
if(tempNodePresent) {
//Link the last known temp node to target
graphMatrix[tempnode][i] = graphMatrix[n][i];
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(tempnode)).ID+
// ", "+((GraphNode)nodes.elementAt(n)).ID);
/////matrix[lastknowntempnode][source]=-original_val
/////graphMatrix[tempnode][n] = -graphMatrix[n][i];
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(i)).ID+
// ", "+
// ((GraphNode)nodes.elementAt(tempnode)).ID);
//and matrix[target][lastknowntempnode]=-original_val
//for reverse tracing
graphMatrix[i][tempnode] = -graphMatrix[n][i];
//unlink source from the target
graphMatrix[n][i] = 0;
graphMatrix[i][n] = 0;
continue;
}
int len = graphMatrix.length;
int tempMatrix[][] =
new int[graphMatrix.length+(nodesLevel[i]-nodesLevel[tempnode]-1)]
[graphMatrix.length+(nodesLevel[i]-nodesLevel[tempnode]-1)];
int level = nodesLevel[tempnode]+1;
copyMatrix(graphMatrix, tempMatrix);
String s1 = new String("S"+tempCnt++);
//System.out.println("Adding dummy "+s1);
m_nodes.addElement(new GraphNode(s1, s1, SINGULAR_DUMMY));
int temp3 [] = new int[nodeLevels[level].length+1];
System.arraycopy(nodeLevels[level], 0, temp3,
0, nodeLevels[level].length);
temp3[temp3.length-1] = m_nodes.size()-1;
nodeLevels[level] = temp3;
temp3 = new int[m_nodes.size()+1];
System.arraycopy(nodesLevel, 0, temp3, 0, nodesLevel.length);
temp3[m_nodes.size()-1] = level;
nodesLevel = temp3;
level++;
//nodeLevels[level++].addElement(new Integer(m_nodes.size()-1));
//System.out.println("len:"+len+"("+
// ((GraphNode)m_nodes.elementAt(len)).ID+"),"+
// nodesLevel[i]+","+nodesLevel[tempnode]);
int m;
for(m=len; mlen) {
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(m)).ID+
// ", "+((GraphNode)nodes.elementAt(m-1)).ID);
tempMatrix[m][m-1]=-1*tempMatrix[n][i];
}
}
//System.out.println("m "+((GraphNode)m_nodes.elementAt(m)).ID+
// " i "+((GraphNode)m_nodes.elementAt(i)).ID+
// " tempnode "+((GraphNode)m_nodes.elementAt(tempnode)).ID+
// " len "+((GraphNode)m_nodes.elementAt(len)).ID );
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(m)).ID+", "+
// ((GraphNode)nodes.elementAt(i)).ID);
//temp[lastTempNodeCreated][targetNode]=temp[origNode][targetNode]
tempMatrix[m][i]=tempMatrix[n][i];
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(tempnode)).ID+", "+
// ((GraphNode)nodes.elementAt(len)).ID);
//temp[origNode][firstTempNodecreated] = temp[origNode][targetNode]
tempMatrix[tempnode][len] = tempMatrix[n][i];
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(len)).ID+", "+
// ((GraphNode)nodes.elementAt(tempnode)).ID);
//temp[firstTempNodeCreated][origNode] for reverse tracing
tempMatrix[len][tempnode] = -1*tempMatrix[n][i];
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(i)).ID+", "+
// ((GraphNode)nodes.elementAt(m)).ID);
//temp[targetNode][lastTempNodecreated] for reverse tracing
tempMatrix[i][m] = -1*tempMatrix[n][i];
if(m>len) {
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(m)).ID+
// ", "+((GraphNode)nodes.elementAt(m-1)).ID);
//temp[lastTempNodeCreated][secondlastNode] for reverse tracing
//but only do this if more than 1 temp nodes are created
tempMatrix[m][m-1] = -1*tempMatrix[n][i];
}
//temp[origNode][targetNode] = 0 unlinking as they have been
tempMatrix[n][i] = 0;
//linked by a chain of temporary nodes now.
tempMatrix[i][n] = 0;
graphMatrix = tempMatrix;
}
else {
//System.out.println("modifying "+
// ((GraphNode)nodes.elementAt(i)).ID+", "+
// ((GraphNode)nodes.elementAt(n)).ID);
//****Even if there is no gap just add a reference for the
//****parent to the child for reverse tracing, useful if the
//****there is a reversed edge from parent to child and therefore
//****visualizer would know to highlight this edge when
//****highlighting the child.
graphMatrix[i][n]=-1*graphMatrix[n][i];
}
}
}
}
/**
* Returns the index of an element in a level.
* Must never be called with the wrong element and
* the wrong level, will throw an exception otherwise.
* It takes as agrument the index of the element (in the m_nodes vector)
* and the level it is supposed to be in (as each level contains the indices
* of the nodes present in that level).
*/
private int indexOfElementInLevel(int element, int level[]) throws Exception {
int idx;
for(int i=0; i=levels[i+1].length) {
int k1=0, k2=0, k3=0;
GraphNode n = (GraphNode) m_nodes.elementAt(levels[i][uidx]);
//Deactivating and counting crossings for all edges ending in it
//coming from bottom left
if(lastOcrnce[levels[i][uidx]]!=null) {
MyListNode temp = new MyListNode(-1); temp.next = upper.first;
try {
do {
temp = temp.next;
if(levels[i][uidx]==temp.n) {
k1 = k1+1;
k3 = k3+k2;
//System.out.println("Removing from upper: "+temp.n);
upper.remove(temp);
}
else
k2 = k2+1;
} while(temp!=lastOcrnce[levels[i][uidx]]);
}
catch(NullPointerException ex) {
System.out.println("levels[i][uidx]: "+levels[i][uidx]+
" which is: "+((GraphNode)m_nodes.elementAt(levels[i][uidx])).ID+
" temp: "+temp+
" upper.first: "+upper.first);
ex.printStackTrace();
System.exit(-1);}
lastOcrnce[levels[i][uidx]]=null;
sum = sum + k1*lower.size() + k3;
}
//Activating all the edges going out towards the bottom
//and bottom right
for(int k=0; k0)
try {
if( indexOfElementInLevel(n.edges[k][0], levels[i+1]) >= uidx) {
edgeOcrnce[n.edges[k][0]]=1;
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
for(int k=0; k lidx) {
edgeOcrnce[n.edges[k][0]]=1;
}
}
catch(Exception ex) {
ex.printStackTrace();
}
}
for(int k=0; k=graphMatrix.length)
return;
else if(j>=graphMatrix[i].length)
return;
if(graphMatrix[i][j]<=0)
assignLevels(levels, depth, i, ++j);
else if(graphMatrix[i][j]==DIRECTED || graphMatrix[i][j]==DOUBLE) {
if(depth+1>levels[j]) {
levels[j]=depth+1;
assignLevels(levels, depth+1, j, 0);
}
assignLevels(levels, depth, i, ++j);
}
}
/**
* This method minimizes the number of edge crossings using the BaryCenter
* heuristics given by Sugiyama et al. 1981
* This method processes the graph topdown if reversed is false,
* otherwise it does bottomup.
*/
private int[][] minimizeCrossings(boolean reversed, int nodeLevels[][]) {
//Minimizing crossings using Sugiyama's method
if(reversed==false) {
for(int times=0; times<1; times++) {
int tempLevels[][] = new int[nodeLevels.length][];
//System.out.println("---------------------------------");
//System.out.println("Crossings before PHaseID: "+
// crossings(nodeLevels));
copy2DArray(nodeLevels, tempLevels);
for(int i=0; i=0; i--) //Up
phaseIU(i, tempLevels);
if(crossings(tempLevels)=0; i--) { //Up
phaseIIU(i, tempLevels);
}
if(crossings(tempLevels)=0; i--) //Up
phaseIU(i, tempLevels);
if(crossings(tempLevels)=0; i--) { //Up
phaseIIU(i, tempLevels);
}
if(crossings(tempLevels)=0; k--)
phaseIU(k, levels);
//System.out.println("Crossings temp:"+crossings(tempLevels)+
// " graph:"+crossings(levels));
//if(crossings(tempLevels)=0; k--)
phaseIU(k, levels);
if(crossings(levels)<=crossings(tempLevels)) {
//System.out.println("Crossings temp: "+crossings(tempLevels)+
// " Crossings levels: "+crossings(levels));
copy2DArray(levels, tempLevels); } //printMatrices(levels);
else {
copy2DArray(tempLevels, levels);
levels[lindex][i+1] = node1;
levels[lindex][i] = node2;
}
//System.out.println("Crossings after PhaseIU of PhaseIIU, in "+
// "iteration "+i+" of "+(rowBC.length-1)+" at "
// +lindex+", levels: "+crossings(levels)+
// " temp: "+crossings(tempLevels));
//tempLevels = new int[levels.length][];
//copy2DArray(levels, tempLevels);
for(int k=0; k0) {
sum++;
try {
rowBC[i] =
rowBC[i]+indexOfElementInLevel(n.edges[j][0], levels[lindex+1])+1;
}
catch(Exception ex) { return null; }
}
}
if(rowBC[i]!=0)
rowBC[i] = rowBC[i]/sum;
}
return rowBC;
}
/**
* See Sugiyama et al. 1981 (full reference give at top)
*/
protected float [] calcColBC(final int lindex, final int levels[][]) {
float colBC[] = new float[levels[lindex+1].length];
GraphNode n;
for(int i=0; i BC[j]) {
hold=BC[i];
BC[i]=BC[j];
BC[j]=hold;
lhold = level[i];
level[i] = level[j];
level[j] = lhold;
switches++;
}//endif
}//endfor
}while(switches>0 || gap>1);
}
*/
/**
* This methods sorts the vertices in level[] according to their
* barycenters in BC[], using insertion sort. It, however, doesn't touch the
* vertices with barycenter equal to zero.
*/
//Both level and BC have elements in the same order
protected static void isort(int level[], float BC[]) {
float temp;
int temp2;
for(int i=0; i-1 && (tempmaxStringWidth)
maxStringWidth=strWidth;
}
if(m_nodeSize0)
n++;
return n;
}
protected int lConnectivity(int lindex, int eindex) {
int n=0;
for(int i=0; i0)
n++;
return n;
}
protected int uBCenter(int lindex, int eindex, int horPositions[]) {
int sum=0;
for(int i=0; i0)
sum = sum + (horPositions[nodeLevels[lindex-1][i]]);
if(sum!=0) { // To avoid 0/0
//System.out.println("uBC Result: "+sum+"/"+
// uConnectivity(lindex,eindex)+
// " = "+(sum/uConnectivity(lindex,eindex)) );
sum = sum/uConnectivity(lindex,eindex);
}
return sum;
}
protected int lBCenter(int lindex, int eindex, int horPositions[]) {
int sum=0;
for(int i=0; i0)
sum = sum + (horPositions[nodeLevels[lindex+1][i]]);
if(sum!=0) // To avoid 0/0
sum = sum/lConnectivity(lindex, eindex); //lConectivity;
return sum;
}
private void tempMethod(int horPositions[]) {
int minPosition = horPositions[0];
for(int i=0; i"+horPositions[i]);
}
}
//int nodeHeight = m_nodeHeight*2; //m_fm.getHeight()*2;
for(int i=0, temp=0; imaxCount)
maxCount=count;
}
//fireLayoutCompleteEvent( new LayoutCompleteEvent(this) );
int priorities[], BC[];
//System.out.println("********Going from 2 to n********");
for(int i=1; i=0; i--) {
priorities = new int[nodeLevels[i].length];
BC = new int[nodeLevels[i].length];
for(int j=0; j"+horPositions[i]);
}
}
//int nodeHeight = m_nodeHeight*2; //m_fm.getHeight()*2;
for(int i=0, temp=0; i-1 && priorities[descOrder[j]] horPositions[level[j]] )
leftCount++;
else if( horPositions[level[descOrder[i]]] < horPositions[level[j]] )
rightCount++;
}
leftNodes = new int[leftCount];
rightNodes = new int[rightCount];
for(int j=0, l=0, r=0; j horPositions[level[j]] )
leftNodes[l++]=j;
else if( horPositions[level[descOrder[i]]] < horPositions[level[j]] )
rightNodes[r++]=j;
//****Moving left
while(Math.abs(horPositions[level[descOrder[i]]]-1
-bCenters[descOrder[i]]) <
Math.abs(horPositions[level[descOrder[i]]]-bCenters[descOrder[i]]) ) {
//****Checking if it can be moved to left
int temp = horPositions[level[descOrder[i]]];
boolean cantMove=false;
for(int j=leftNodes.length-1; j>=0; j--) {
if(temp-horPositions[level[leftNodes[j]]] > 1)
break;
else if(priorities[descOrder[i]]<=priorities[leftNodes[j]])
{ cantMove=true; break; }
else
temp = horPositions[level[leftNodes[j]]];
}
//if(horPositions[level[descOrder[i]]]-1==
// horPositions[level[leftNodes[j]]])
// cantMove = true;
if(cantMove)
break;
temp = horPositions[level[descOrder[i]]]-1;
//****moving other vertices to left
for(int j=leftNodes.length-1; j>=0; j--) {
if(temp==horPositions[level[leftNodes[j]]]) {
//System.out.println("Moving "+
// ((Node)m_nodes.elementAt(level[leftNodes[j]])).ID+" from "
// +horPositions[level[leftNodes[j]]]+" to "
// +(horPositions[level[leftNodes[j]]]-1) );
horPositions[level[leftNodes[j]]] =
temp = horPositions[level[leftNodes[j]]]-1;
}
}
//System.out.println("Moving main "+
// ((GraphNode)m_nodes.elementAt(level[descOrder[i]])).ID+" from "
// +horPositions[level[descOrder[i]]]+" to "
// +(horPositions[level[descOrder[i]]]-1));
horPositions[level[descOrder[i]]]=horPositions[level[descOrder[i]]]-1;
}
//****Moving right
while(Math.abs(horPositions[level[descOrder[i]]]+1
-bCenters[descOrder[i]]) <
Math.abs(horPositions[level[descOrder[i]]]-bCenters[descOrder[i]]) ) {
//****checking if the vertex can be moved
int temp = horPositions[level[descOrder[i]]];
boolean cantMove=false;
for(int j=0; j 1)
break;
else if(priorities[descOrder[i]]<=priorities[rightNodes[j]])
{ cantMove=true; break; }
else
temp = horPositions[level[rightNodes[j]]];
}
//if(horPositions[level[descOrder[i]]]-1==
// horPositions[level[leftNodes[j]]])
// cantMove = true;
if(cantMove)
break;
temp = horPositions[level[descOrder[i]]]+1;
//****moving other vertices to left
for(int j=0; j