/* * 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