Package graphStructure

Source Code of graphStructure.Graph

package graphStructure;

import java.util.*;
import java.awt.*;
import java.io.*;
import java.awt.geom.*;

import dataStructure.DoublyLinkedList;
import graphStructure.mementos.*;

/**
* This class represents the model of the graph object, that stores all the data
* that makes up the structure of the graph, and methods to perform operations
* on this data such as saving to and loading from a file, adding nodes or edges
* etc...
*
* @author Jon Harris
*/
public class Graph
{
  private String    label;
  private Vector    nodes;
  private boolean drawSelected;
  private Color drawColor;
  private String filePath;
  private DoublyLinkedList mementos;
  private MementoGrouper currentMemento;
  private boolean showCoords;
  private boolean showLabels;
  private boolean trackUndos;
  private boolean hasChangedSinceLastSave;
  private boolean hasChangedSinceLastDraw;
  private boolean logChangedSinceLastDraw;
  private Vector logEntries;
  private LogEntry currentLogEntry;
  private Graph parent;
  private boolean drawGrid;
  private int gridRows;
  private int gridCols;
  private int gridColWidth;
  private int gridRowHeight;

  /**
   * Constructor for class Graph.
   */
  public Graph()
  {
    label = "";
    nodes = new Vector();
    drawColor = null;
    drawSelected = true;
    filePath = "";
    mementos = new DoublyLinkedList();
    currentMemento = null;
    trackUndos = true;
    hasChangedSinceLastSave = false;
    hasChangedSinceLastDraw = true;
    showCoords = false;
    showLabels = true;
    logEntries = new Vector();
    currentLogEntry = null;
    parent = null;
    drawGrid = false;
    gridRows = -1;
    gridCols = -1;
  }

  /**
   * Constructor for class Graph that assigns a label to the Graph.
   *
   * @param String aLabel: The label to assign to the Graph.
   */
  public Graph(String aLabel)
  {
    this();
    label = aLabel;
  }

  /**
   * Constructor for class Graph that assigns a label to the Graph and
   * provides the initial node set for the Graph.
   *
   * @param String aLabel: The label to assign to the Graph.
   * @param Vector initialNodes: A Vector containing the initial Nodes for the Graph.
   */
  public Graph(String aLabel, Vector initialNodes)
  {
    this();
    label = aLabel;
    nodes = initialNodes;
  }

  public Graph(Graph aGraph)
  {
    parent = aGraph;
    label = new String(aGraph.label);
    drawSelected = aGraph.drawSelected;
    trackUndos = aGraph.trackUndos;
    hasChangedSinceLastSave = aGraph.hasChangedSinceLastSave;
    hasChangedSinceLastDraw = true;
    if ( aGraph.drawColor == null )
    {
      drawColor = null;
    }
    else
    {
      drawColor = new Color(aGraph.drawColor.getRGB());
    }
    filePath = new String(aGraph.filePath);
    nodes = new Vector();
    mementos = new DoublyLinkedList();
    currentMemento = null;
    showCoords = aGraph.showCoords;
    showLabels = aGraph.showLabels;
    logEntries = new Vector();
    currentLogEntry = null;
  }

  public String getShowString()
  {
    if ( showCoords )
    {
      return "Show Coordinates";
    }
    else
    {
      if ( showLabels )
      {
        return "Show Labels";
      }
      else
      {
        return "Show Nothing";
      }
    }
  }
 
  public void shareMementos(Graph aGraph) { mementos = aGraph.mementos; }

  public void setTrackUndos(boolean tu) { trackUndos = tu; initUndo(); }

  private void initUndo()
  {
    mementos = new DoublyLinkedList();
    currentMemento = null;
  }
 
  public boolean getTrackUndos() { return trackUndos; }

  public void setDrawSelected(boolean draw) { drawSelected = draw; }

  public boolean getDrawSelected() { return drawSelected; }

  public void setDrawColor(Color aColor) { drawColor = aColor; }

  public Color getDrawColor() { return drawColor; }

  public void setShowCoords(boolean c)
  {
    showCoords = c;
    hasChangedSinceLastDraw = true;
  }

  public boolean getShowCoords() { return showCoords; }

  public void setShowLabels(boolean l)
  {
    showLabels = l;
    hasChangedSinceLastDraw = true;
  }

  public boolean getShowLabels() { return showLabels; }

  public String getFilePath() { return filePath; }

  public String getFileName()
  {
    if ( filePath.indexOf('\\') == -1 )
    {
      return filePath.substring( 0, filePath.lastIndexOf('.') );
    }
    else
    {
      return filePath.substring( filePath.lastIndexOf('\\')+1, filePath.lastIndexOf('.') );
    }
  }

  public void setFilePath(String fp) { filePath = fp; }

  public boolean hasChangedSinceLastSave() { return hasChangedSinceLastSave; }

  public boolean hasChangedSinceLastDraw() { return hasChangedSinceLastDraw; }

  public boolean logChangedSinceLastDraw() { return logChangedSinceLastDraw; }

  public void markForRepaint() { hasChangedSinceLastDraw = true; }

  private int getRowHeight(int numRows, int height)
  {
    return height / (numRows-1);
  }
 
  private int getColWidth(int numCols, int width)
  {
    return width / (numCols-1);
  }
 
  public void setGrid(int numRows, int rowHeight, int numCols, int colWidth,
                      boolean addMemento)
  {
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(GridSizeMemento.createGridSizeMemento(this));
    }
    gridRows = numRows;
    gridRowHeight = rowHeight;
    gridCols = numCols;
    gridColWidth = colWidth;
  }
 
  public void setGridArea(int numRows, int height, int numCols, int width,
                          boolean addMemento)
  {
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(GridSizeMemento.createGridSizeMemento(this));
    }
    if ( numRows <= 1 )
    {
      numRows = 2;
    }
    gridRows = numRows;
    gridRowHeight = getRowHeight(numRows, height);
    if ( numCols <= 1 )
    {
      numCols = 2;
    }
    gridCols = numCols;
    gridColWidth = getColWidth(numCols, width);
  }
 
  public int getGridRows() { return gridRows; }
 
  public int getGridCols() { return gridCols; }
 
  public int getGridColWidth() { return gridColWidth; }
 
  public int getGridRowHeight() { return gridRowHeight; }
 
  public void setDrawGrid(boolean draw) { drawGrid = draw; }

  public boolean getDrawGrid() { return drawGrid && gridRows >= 2 && gridCols >= 2; }
 
  public int getGridHeight() { return (gridRows-1)*gridRowHeight; }
 
  public int getGridWidth() { return (gridCols-1)*gridColWidth; }
 
  public void drawGrid(Graphics2D g2, int xOffset, int yOffset)
  {
    int x = 0 + xOffset;
    int y = 0 + yOffset;
    g2.setColor(Color.gray);
    for ( int i=0; i<gridRows; i++ )
    {
      y = i*gridRowHeight + yOffset;
      g2.drawLine(xOffset, y, gridColWidth*(gridCols-1) + xOffset, y);
    }
    for ( int i=0; i<gridCols; i++ )
    {
      x = i*gridColWidth + xOffset;
      g2.drawLine(x, yOffset, x, gridRowHeight*(gridRows-1) + yOffset);
    }
  }
 
  public Location getClosestGridLocation(Location location)
  {
    int row = (int)Math.round(location.doubleY() / gridRowHeight);
    int col = (int)Math.round(location.doubleX() / gridColWidth);
    if ( row > gridRows-1 )
    {
      row = gridRows-1;
    }
    if ( col > gridCols-1 )
    {
      col = gridCols-1;
    }
    return new Location( col*gridColWidth, row*gridRowHeight);
  }
 
  public boolean isOnGrid(Location location)
  {
    return location.intX() % gridColWidth == 0 &&
           location.intY() % gridRowHeight == 0;
  }
 
  public void newMemento(String title)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( trackUndos )
    {
      if ( currentMemento != null )
      {
        mementos.enqueueAfterCurrent(currentMemento);
      }     
      currentMemento = new MementoGrouper(title);
    }
  }

  public void renameMemento(String title)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( trackUndos )
    {
      currentMemento.setTitle(title);
    }
  }

  public void doneMemento()
  {
    if ( trackUndos )
    {
      if ( currentMemento != null )
      {
        currentMemento.removeUselessMementos();
        if ( currentMemento.size() > 0 )
        {
          mementos.enqueueAfterCurrent(currentMemento);
        }
        currentMemento = null;
      }
    }
  }

  public void undoMemento()
  {
    if ( currentMemento != null )
    {
      currentMemento.apply(this);
    }
  }
 
  public void abortMemento()
  {
    if ( trackUndos )
    {
      currentMemento = null;
    }
  }

  public boolean hasMoreUndos()
  {
    return mementos.getCurrent() != null;
  }

  public void undo()
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( trackUndos )
    {
      if ( mementos.getCurrent() != null )
      {
        ((MementoGrouper)mementos.getCurrent()).apply(this);
        mementos.toPrev();
      }
      else
      {
        mementos.toHead();
      }
    }
  }

  public MementoGrouper peekUndo()
  {
    return (MementoGrouper)mementos.getCurrent();
  }

  public boolean hasMoreRedos()
  {
    return mementos.hasNext();
  }

  public void redo()
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( trackUndos )
    {
      if ( mementos.hasNext() )
      {
        mementos.toNext();
        ((MementoGrouper)mementos.getCurrent()).apply(this);
      }
      else
      {
        mementos.toTail();
      }
    }
  }

  public MementoGrouper peekRedo()
  {
    if ( mementos.hasNext() )
    {
      mementos.toNext();
      MementoGrouper mg = (MementoGrouper)mementos.getCurrent();
      mementos.toPrev();
      return mg;
    }
    else
    {
      return null;
    }
  }
 
  public String getLogString()
  {
    String returnString = "";
    for ( int i=0; i<logEntries.size(); i++ )
    {
      returnString+= "Log Entry " + (i+1) +
                     "---------------------" +
                     ((LogEntry)logEntries.elementAt(i)).infoString() +
                     "---------------------\n\n";
    }
    return returnString;
  }
 
  public Vector getLogEntries() { return logEntries; }
 
  public LogEntry startLogEntry(String operationName)
  {
    if ( parent != null )
    {
      LogEntry newEntry = new LogEntry(operationName, this, System.currentTimeMillis());
      parent.startLogEntry(newEntry);
      return newEntry;
    }
    else
    {
      LogEntry newEntry = new LogEntry(operationName, this, System.currentTimeMillis());
      if ( currentLogEntry == null )
      {
        logEntries.addElement(newEntry);
      }
      else
      {
        currentLogEntry.addSubEntry(newEntry);
      }
      currentLogEntry = newEntry;
      return newEntry;
    }
  }
 
  private void startLogEntry(LogEntry logEntry)
  {
    if ( parent != null )
    {
      parent.startLogEntry(logEntry);
    }
    else
    {
      if ( currentLogEntry == null )
      {
        logEntries.addElement(logEntry);
      }
      else
      {
        currentLogEntry.addSubEntry(logEntry);
      }
      currentLogEntry = logEntry;
    }
  }
 
  public void stopLogEntry(LogEntry logEntry)
  {
    if ( parent != null )
    {
      parent.stopLogEntry(logEntry);
      return;
    }
    else
    {
      logChangedSinceLastDraw = true;
    }
    logEntry.updateTimeTaken(System.currentTimeMillis());
    currentLogEntry = logEntry.getParentEntry();
  }
 
  public Rectangle2D.Double getBounds()
  {
    return getBounds( 0, 0 );
  }

  public Rectangle2D.Double getBounds( int xAdd, int yAdd )
  {
    return getBounds( nodes, xAdd, yAdd );
  }

  public Rectangle2D.Double getBounds( Vector someNodes )
  {
    return getBounds( someNodes, 0, 0 );
  }

  public Rectangle2D.Double getBounds( Vector someNodes, int xAdd, int yAdd )
  {
    double minX = 0;
    double minY = 0;
    double maxX = 0;
    double maxY = 0;
    if ( !someNodes.isEmpty() )
    {
      Location aLocation = ((Node)someNodes.firstElement()).getLocation();
      maxX = minX = aLocation.doubleX();
      maxY = minY = aLocation.doubleY();

      for ( int i=1; i<someNodes.size(); i++ )
      {
        aLocation = ((Node)someNodes.elementAt(i)).getLocation();
        if ( aLocation.doubleX() < minX )
        {
          minX = aLocation.doubleX();
        }
        else if ( aLocation.doubleX() > maxX )
        {
          maxX = aLocation.doubleX();
        }
        if ( aLocation.doubleY() < minY )
        {
          minY = aLocation.doubleY();
        }
        else if ( aLocation.doubleY() > maxY )
        {
          maxY = aLocation.doubleY();
        }
      }

      Vector edges = getCurvedEdges(someNodes);

      Rectangle2D rect;
      for ( int i=0; i<edges.size(); i++ )
      {
        //aLocation = ((Edge)edges.elementAt(i)).getCenterLocation();

        rect = ((Edge)edges.elementAt(i)).getQuadCurve().getBounds2D();

        if ( rect.getMinX() < minX )
        {
          minX = rect.getMinX();
        }
        if ( rect.getMaxX() > maxX )
        {
          maxX = rect.getMaxX();
        }
        if ( rect.getMinY() < minY )
        {
          minY = rect.getMinY();
        }
        if ( rect.getMaxY() > maxY )
        {
          maxY = rect.getMaxY();
        }
      }
    }
    return new Rectangle2D.Double( minX, minY,
                                   maxX - minX + xAdd,
                                   maxY - minY + yAdd );
  }

  public Location getCenterPointLocation()
  {
    Node currentNode;
    int xAcc = 0;
    int yAcc = 0;

    if ( nodes.size() > 0 )
    {
      for ( int i=0; i<nodes.size(); i++ )
      {
        currentNode = (Node)nodes.elementAt(i);
        xAcc+= currentNode.getX();
        yAcc+= currentNode.getY();
      }
      return new Location(xAcc/nodes.size(), yAcc/nodes.size());
    }
    else
    {
      return new Location(0, 0);
    }
  }

  public static Node partitionAroundMedianX(Vector pNodes, Vector lesser, Vector greater)
  {
    Node mNode = getMedianXNode(pNodes);
    Node currentNode;

    if ( pNodes.size() > 1 )
    {
      if ( pNodes.size() %2 == 1 )
      {
        lesser.ensureCapacity(pNodes.size()/2);
        greater.ensureCapacity(pNodes.size()/2);
        lesser.removeAllElements();
        greater.removeAllElements();
      }
      else
      {
        lesser.ensureCapacity(pNodes.size()/2);
        greater.ensureCapacity(pNodes.size()/2-1);
        lesser.removeAllElements();
        greater.removeAllElements();
      }

      for ( int i=0; i<pNodes.size(); i++ )
      {
        currentNode = (Node)pNodes.elementAt(i);
        if ( currentNode.getX() < mNode.getX() )
        {
          lesser.addElement(currentNode);
        }
        else if ( currentNode.getX() > mNode.getX() )
        {
          greater.addElement(currentNode);
        }
      }

      for ( int i=0; i<pNodes.size(); i++ )
      {
        currentNode = (Node)pNodes.elementAt(i);
        if ( currentNode != mNode && currentNode.getX() == mNode.getX() )
        {
          if ( lesser.size() < pNodes.size()/2 )
          {
            lesser.addElement(currentNode);
          }
          else
          {
            greater.addElement(currentNode);
          }
        }
      }
    }
    return mNode;
  }

  public Node getMedianXNode()
  {
    return getMedianXNode(nodes);
  }

  public static Node getMedianXNode(Vector sNodes)
  {
    if ( sNodes.size() > 0 )
    {
      Node mNodes[] = new Node[sNodes.size()];
      sNodes.toArray(mNodes);
      return quickSelectX(mNodes, mNodes.length/2);
    }
    return null;
  }

  private static Node quickSelectX(Node mNodes[], int k)
  {
    if ( mNodes.length == 1 )
    {
      return mNodes[0];
    }
    Node medianNode = getMedianOfMediansXNode(mNodes);
    int lesserCount= 0, equalCount = 0, greaterCount = 0;
    for ( int i=0; i<mNodes.length; i++ )
    {
      if ( mNodes[i].getX() < medianNode.getX() )
      {
        lesserCount++;
      }
      else if ( mNodes[i].getX() > medianNode.getX() )
      {
        greaterCount++;
      }
    }
    Node lesserNodes[] = new Node[lesserCount];
    Node equalNodes[] = new Node[mNodes.length-lesserCount-greaterCount];
    Node greaterNodes[] = new Node[greaterCount];
    lesserCount = equalCount = greaterCount = 0;
    for ( int i=0; i<mNodes.length; i++ )
    {
      if ( mNodes[i].getX() < medianNode.getX() )
      {
        lesserNodes[lesserCount++] = mNodes[i];
      }
      else if ( mNodes[i].getX() > medianNode.getX() )
      {
        greaterNodes[greaterCount++] = mNodes[i];
      }
      else
      {
        equalNodes[equalCount++] = mNodes[i];
      }
    }
    if ( k < lesserNodes.length )
    {
      return quickSelectX(lesserNodes, k);
    }
    else if ( k < lesserNodes.length + equalNodes.length )
    {
      return medianNode;
    }
    else
    {
      return quickSelectX(greaterNodes, k - lesserNodes.length - equalNodes.length);
    }
  }

  public static Node getMedianOfMediansXNode(Node mNodes[])
  {
    do
    {
      mNodes = findMediansX(mNodes);
    }
    while ( mNodes.length != 1 );
    return mNodes[0];
  }

  private static Node[] findMediansX(Node mNodes[])
  {
    Node medians[];
    int leftOver = mNodes.length % 5;
    Node temp[] = new Node[5];
    Node currentNode, switcherNode;
    int i = 0, j = 0, m = 0;
    if ( leftOver == 0 )
    {
      medians = new Node[mNodes.length/5];
    }
    else
    {
      medians = new Node[mNodes.length/5+1];
    }
    for ( i=0, m=0; i<mNodes.length; i++ )
    {
      if ( i > 0 && i % 5 == 0 )
      {
        medians[m++] = temp[2];
      }

      currentNode = mNodes[i];
      switcherNode = null;

      for ( j=0; j<i%5; j++ )
      {
        if ( temp[j].getX() > currentNode.getX() )
        {
          switcherNode = temp[j];
          break;
        }
      }
      temp[j] = currentNode;
      if ( switcherNode != null )
      {
        for ( ; j<i%5; j++ )
        {
          currentNode = temp[j+1];
          temp[j+1] = switcherNode;
          switcherNode = currentNode;
        }
      }

    }
    if ( leftOver != 0 )
    {
      medians[m] = temp[leftOver/2];
    }
    else
    {
      medians[m] = temp[2];
    }
    return medians;
  }

  public static Node partitionAroundMedianY(Vector pNodes, Vector lesser, Vector greater)
  {
    Node mNode = getMedianYNode(pNodes);
    Node currentNode;

    if ( pNodes.size() > 1 )
    {
      if ( pNodes.size() %2 == 1 )
      {
        lesser.ensureCapacity(pNodes.size()/2);
        greater.ensureCapacity(pNodes.size()/2);
        lesser.removeAllElements();
        greater.removeAllElements();
      }
      else
      {
        lesser.ensureCapacity(pNodes.size()/2);
        greater.ensureCapacity(pNodes.size()/2-1);
        lesser.removeAllElements();
        greater.removeAllElements();
      }

      for ( int i=0; i<pNodes.size(); i++ )
      {
        currentNode = (Node)pNodes.elementAt(i);
        if ( currentNode.getY() < mNode.getY() )
        {
          lesser.addElement(currentNode);
        }
        else if ( currentNode.getY() > mNode.getY() )
        {
          greater.addElement(currentNode);
        }
      }

      for ( int i=0; i<pNodes.size(); i++ )
      {
        currentNode = (Node)pNodes.elementAt(i);
        if ( currentNode != mNode && currentNode.getY() == mNode.getY() )
        {
          if ( lesser.size() < pNodes.size()/2 )
          {
            lesser.addElement(currentNode);
          }
          else
          {
            greater.addElement(currentNode);
          }
        }
      }
    }
    return mNode;
  }

  public Node getMedianYNode()
  {
    return getMedianYNode(nodes);
  }

  public static Node getMedianYNode(Vector sNodes)
  {
    if ( sNodes.size() > 0 )
    {
      Node mNodes[] = new Node[sNodes.size()];
      sNodes.toArray(mNodes);
      return quickSelectY(mNodes, mNodes.length/2);
    }
    return null;
  }

  private static Node quickSelectY(Node mNodes[], int k)
  {
    if ( mNodes.length == 1 )
    {
      return mNodes[0];
    }
    Node medianNode = getMedianOfMediansYNode(mNodes);
    int lesserCount= 0, equalCount = 0, greaterCount = 0;
    for ( int i=0; i<mNodes.length; i++ )
    {
      if ( mNodes[i].getY() < medianNode.getY() )
      {
        lesserCount++;
      }
      else if ( mNodes[i].getY() > medianNode.getY() )
      {
        greaterCount++;
      }
    }
    Node lesserNodes[] = new Node[lesserCount];
    Node equalNodes[] = new Node[mNodes.length-lesserCount-greaterCount];
    Node greaterNodes[] = new Node[greaterCount];
    lesserCount = equalCount = greaterCount = 0;
    for ( int i=0; i<mNodes.length; i++ )
    {
      if ( mNodes[i].getY() < medianNode.getY() )
      {
        lesserNodes[lesserCount++] = mNodes[i];
      }
      else if ( mNodes[i].getY() > medianNode.getY() )
      {
        greaterNodes[greaterCount++] = mNodes[i];
      }
      else
      {
        equalNodes[equalCount++] = mNodes[i];
      }
    }
    if ( k < lesserNodes.length )
    {
      return quickSelectY(lesserNodes, k);
    }
    else if ( k < lesserNodes.length + equalNodes.length )
    {
      return medianNode;
    }
    else
    {
      return quickSelectY(greaterNodes, k - lesserNodes.length - equalNodes.length);
    }
  }

  public static Node getMedianOfMediansYNode(Node mNodes[])
  {
    do
    {
      mNodes = findMediansY(mNodes);
    }
    while ( mNodes.length != 1 );
    return mNodes[0];
  }

  private static Node[] findMediansY(Node mNodes[])
  {
    Node medians[];
    int leftOver = mNodes.length % 5;
    Node temp[] = new Node[5];
    Node currentNode, switcherNode;
    int i = 0, j = 0, m = 0;
    if ( leftOver == 0 )
    {
      medians = new Node[mNodes.length/5];
    }
    else
    {
      medians = new Node[mNodes.length/5+1];
    }
    for ( i=0, m=0; i<mNodes.length; i++ )
    {
      if ( i > 0 && i % 5 == 0 )
      {
        medians[m++] = temp[2];
      }

      currentNode = mNodes[i];
      switcherNode = null;

      for ( j=0; j<i%5; j++ )
      {
        if ( temp[j].getY() > currentNode.getY() )
        {
          switcherNode = temp[j];
          break;
        }
      }
      temp[j] = currentNode;
      if ( switcherNode != null )
      {
        for ( ; j<i%5; j++ )
        {
          currentNode = temp[j+1];
          temp[j+1] = switcherNode;
          switcherNode = currentNode;
        }
      }

    }
    if ( leftOver != 0 )
    {
      medians[m] = temp[leftOver/2];
    }
    else
    {
      medians[m] = temp[2];
    }
    return medians;
  }
 
  public Graph copy()
  {
    return copyNodes(nodes);
  }
 
  /**
   * Returns a copy of the graph, maintaining the order of edges at each node. 
   * @param multiLevel - If true, nodes and edges will set their
   * copy field to the value of the copy field of the node or edge they are copying.
   * @return The copy of the graph
   */
  public Graph copy( boolean keepReferences )
  {
    return copyNodes(nodes, keepReferences);
  }


  public Graph copyNodes(Vector nodeVector)
  {
    return copyNodes( nodeVector, false );
  }

  // copies all nodes in the nodeVector and ALL of their edges.
  public Graph copyNodes( Vector nodeVector, boolean keepReferences )
  {
    Graph newGraph = new Graph(this);
    Vector incidentEdges;
    Node newNode, currentNode;
    Edge newEdge, currentEdge;
    Vector sourceEdges = getEdges(nodeVector);
    // Vectors to maintain original copy references of nodes and edges of input graph.
    // These references are borrowed to allow dual access between copy and source.
    Vector copyNodes = new Vector(nodes.size());
    Vector copyEdges = new Vector(sourceEdges.size());
   
    for ( int i=0; i<nodeVector.size(); i++ )
    {
      currentNode = (Node)nodeVector.elementAt(i);
      copyNodes.addElement(currentNode.getCopy());
      newNode = new Node(currentNode);
      newNode.setCopy(currentNode);
      currentNode.setCopy(newNode);
      newGraph.addNode(newNode);
    }

    for ( int i=0; i<sourceEdges.size(); i++ )
    {
      currentEdge = (Edge)sourceEdges.elementAt(i);
      copyEdges.addElement(currentEdge.getCopy());
      if ( currentEdge.getDirectedSourceNode() != null )
      {
        newEdge = new Edge( currentEdge, currentEdge.getDirectedSourceNode().getCopy(),
            currentEdge.getStartNode().getCopy(), currentEdge.getEndNode().getCopy() );
      }
      else
      {
        newEdge = new Edge( currentEdge, null,
            currentEdge.getStartNode().getCopy(), currentEdge.getEndNode().getCopy() );
      }
      newEdge.setCopy(currentEdge);
      currentEdge.setCopy(newEdge);
    }

    for ( int i=0; i<nodeVector.size(); i++ )
    {
      currentNode = (Node)nodeVector.elementAt(i);
      incidentEdges = currentNode.incidentEdges();
      for ( int j=0; j<incidentEdges.size(); j++ )
      {
        currentEdge = (Edge)incidentEdges.elementAt(j);
        currentNode.getCopy().addIncidentEdgeNoCheck(currentEdge.getCopy());
      }
    }

    for ( int i=0; i<nodeVector.size(); i++ )
    {
      currentNode = (Node)nodeVector.elementAt(i);
      if ( !keepReferences )
      {
        currentNode.getCopy().setCopy(null);
      }
      currentNode.setCopy((Node)copyNodes.elementAt(i));
    }

    for ( int i=0; i<sourceEdges.size(); i++ )
    {
      currentEdge = (Edge)sourceEdges.elementAt(i);
      if ( !keepReferences )
      {
        currentEdge.getCopy().setCopy(null);
      }
      currentEdge.setCopy((Edge)copyEdges.elementAt(i));
    }
    return newGraph;
  }

  public Graph copyNode(Node aNode)
  {
    return copyNode( aNode, false , false );
  }

  public Graph copyNode( Node aNode, boolean keepCopyReferences )
  {
    return copyNode( aNode, keepCopyReferences , false );
  }

  public Graph copyNode(Node aNode, boolean keepCopyReferences,
                        boolean updateCopyReferences)
  {
    Graph newGraph = new Graph(this);
    Node newNode = new Node(aNode);
    if ( updateCopyReferences )
    {
      newNode.setCopy(aNode.getCopy());
    }
    else
    {
      newNode.setCopy(aNode);
    }
    newGraph.addNode(newNode);
    if ( !keepCopyReferences )
    {
      newNode.setCopy(null);
    }
    return newGraph;
  }

  // copies all of the edges in the vector and any related nodes.
 
  public Graph copyEdges( Vector edges )
  {
    return copyEdges( edges, false );
  }

  public Graph copyEdges( Vector edges, boolean keepCopyReferences )
  {
    Graph newGraph = new Graph(this);
    Node newNode, currentNode;
    Edge newEdge, currentEdge;
    Vector sourceNodes = new Vector(2*edges.size());
    Vector copyNodes;
    Vector newEdges;

    for ( int j=0; j<edges.size(); j++ )
    {
      currentEdge = (Edge)edges.elementAt(j);
      currentEdge.setIsAdded(false);
      ((Node)currentEdge.getStartNode()).setIsAdded(false);
      ((Node)currentEdge.getEndNode()).setIsAdded(false);
    }

    for ( int j=0; j<edges.size(); j++ )
    {
      currentEdge = (Edge)edges.elementAt(j);
      if ( !((Node)currentEdge.getStartNode()).isAdded() )
      {
        ((Node)currentEdge.getStartNode()).setIsAdded(true);
        sourceNodes.addElement(currentEdge.getStartNode());
      }
      if ( !((Node)currentEdge.getEndNode()).isAdded() )
      {
        ((Node)currentEdge.getEndNode()).setIsAdded(true);
        sourceNodes.addElement(currentEdge.getEndNode());
      }
    }

    copyNodes = new Vector(sourceNodes.size());
    for ( int i=0; i<sourceNodes.size(); i++ )
    {
      currentNode = (Node)sourceNodes.elementAt(i);
      newNode = new Node(currentNode);
      newNode.setCopy(currentNode);
      copyNodes.addElement(currentNode.getCopy());
      currentNode.setCopy(newNode);
      newGraph.addNode(newNode);
    }

    for ( int j=0; j<edges.size(); j++ )
    {
      currentEdge = (Edge)edges.elementAt(j);
      if ( !currentEdge.isAdded() )
      {
        currentEdge.setIsAdded(true);
        if ( currentEdge.getDirectedSourceNode() != null )
        {
          newEdge = new Edge( currentEdge, currentEdge.getDirectedSourceNode().getCopy(),
              currentEdge.getStartNode().getCopy(), currentEdge.getEndNode().getCopy() );
        }
        else
        {
          newEdge = new Edge( currentEdge, null,
              currentEdge.getStartNode().getCopy(), currentEdge.getEndNode().getCopy() );
        }
        newEdge.setCopy(currentEdge);
        currentEdge.getStartNode().getCopy().addIncidentEdgeNoCheck(newEdge);
        currentEdge.getEndNode().getCopy().addIncidentEdgeNoCheck(newEdge);
      }
    }

    for ( int i=0; i<sourceNodes.size(); i++ )
    {
      currentNode = (Node)sourceNodes.elementAt(i);
      if ( !keepCopyReferences )
      {
        currentNode.getCopy().setCopy(null);
      }
      currentNode.setCopy((Node)copyNodes.elementAt(i));
      currentNode.setIsAdded(false);
    }

    newEdges = newGraph.getEdges();
    for ( int j=0; j<newEdges.size(); j++ )
    {
      currentEdge = (Edge)edges.elementAt(j);
      newEdge = (Edge)newEdges.elementAt(j);
      if ( !keepCopyReferences )
      {
        newEdge.setCopy(null);
      }
      currentEdge.setIsAdded(false);
    }
    return newGraph;
  }

  public void resetCopyData()
  {
    Node aNode;
    Edge anEdge;
    Enumeration enumEdges, enumNodes;
    enumNodes = nodes.elements();
    while ( enumNodes.hasMoreElements() )
    {
      aNode = (Node)enumNodes.nextElement();
      aNode.setCopy(null);
      enumEdges = aNode.incidentEdges().elements();
      while ( enumEdges.hasMoreElements() )
      {
        anEdge = (Edge)enumEdges.nextElement();
        anEdge.setCopy(null);
      }
    }
  }

  /**
   * Returns the label of this Graph
   *
   * @return String: The label of this Graph.
   */
  public String getLabel() { return label; }

  /**
   * Returns the Nodes contained within this Graph.
   *
   * @return Vector: A Vector containing the Nodes of this Graph.
   */
  public Vector getNodes() { return nodes; }

  public Node getNodeAt(int index)
  {
    if ( nodes.isEmpty() || index < 0 || index > nodes.size()-1 )
    {
      return null;
    }
    else
    {
      return (Node)nodes.elementAt(index);
    }
  }

  public int getNumNodes() { return nodes.size(); }

  /**
   * Sets the label of this Graph.
   *
   * @param String newLabel: The new label for this Graph.
   */
  public void setLabel(String newLabel) { label = newLabel; }

  public boolean edgeNumbersAreInSync()
  {
    return getNumEdges() == getEdges().size();
  }

  public void makeAllEdgesStraight()
  {
    Vector edges = getEdges();
    Edge anEdge;
    for ( int i=0; i<edges.size(); i++ )
    {
      anEdge = (Edge)edges.elementAt(i);
      if ( anEdge.isCurved() )
      {
        anEdge.makeStraight();
      }
    }
  }

  public int getNumEdges()
  {
    return getNumEdges(nodes);
  }

  public int getNumEdges(Vector nodeVector)
  {
    int numEdges = 0;
    Enumeration allNodes = nodeVector.elements();
    while(allNodes.hasMoreElements())
    {
      numEdges+= ((Node)allNodes.nextElement()).getNumEdges();
    }
    return numEdges/2;
  }

  public int getNumGeneratedEdges()
  {
    int numGenerated = 0;
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      if ( ((Edge)edges.elementAt(i)).isGenerated() )
      {
        numGenerated++;
      }
    }
    return numGenerated;
  }

  public int getNumCurvedEdges()
  {
    int numCurved = 0;
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      if ( ((Edge)edges.elementAt(i)).isCurved() )
      {
        numCurved++;
      }
    }
    return numCurved;
  }

  /**
   * Returns all of the Edges of this Graph as retrieved by asking
   * all of the Nodes in this Graph for their adjacent Edges.
   *
   * @return Vector: A Vector containing the Edges of this Graph.
   */
  public Vector getEdges()
  {
    return getEdges(nodes);
  }

  // get all edges incident to the nodes in the vector
 
  public Vector getEdges(Vector nodeVector)
  {
    return getEdges(nodeVector, false);
  }

  public Vector getCurvedEdges(Vector nodeVector)
  {
    return getEdges(nodeVector, true);
  }

  private Vector getEdges(Vector nodeVector, boolean onlyCurved)
  {
    Vector edges;
    Enumeration allNodes;
    Enumeration someEdges;
    Edge anEdge;
    int numEdges = getNumEdges(nodeVector);
    edges = new Vector(numEdges);

    allNodes = nodeVector.elements();
    while(allNodes.hasMoreElements())
    {
      someEdges = ((Node)allNodes.nextElement()).incidentEdges().elements();
      while(someEdges.hasMoreElements())
      {
        ((Edge)someEdges.nextElement()).setIsAdded(false);
      }
    }

    allNodes = nodeVector.elements();
    while(allNodes.hasMoreElements())
    {
      someEdges = ((Node)allNodes.nextElement()).incidentEdges().elements();
      while(someEdges.hasMoreElements())
      {
        anEdge = (Edge)someEdges.nextElement();
        if ( !anEdge.isAdded() )
        {
          if ( !onlyCurved || anEdge.isCurved() )
          {
            edges.addElement(anEdge);
          }
          anEdge.setIsAdded(true);
        }
      }
    }

    allNodes = nodeVector.elements();
    while(allNodes.hasMoreElements())
    {
      someEdges = ((Node)allNodes.nextElement()).incidentEdges().elements();
      while(someEdges.hasMoreElements())
      {
        ((Edge)someEdges.nextElement()).setIsAdded(false);
      }
    }
    return edges;
  }

  public Node[] getRandomTriangularFace()
  {
    Node triangleNodes[] = new Node[3];
    triangleNodes[0] = (Node)nodes.firstElement();
    Edge tempEdge = (Edge)triangleNodes[0].incidentEdges().firstElement();
    triangleNodes[1] = (Node)tempEdge.otherEndFrom(triangleNodes[0]);
    triangleNodes[2] = (Node)tempEdge.getNextInOrderFrom(triangleNodes[0]).otherEndFrom(triangleNodes[0]);
    if ( triangleNodes[2] ==
         tempEdge.getPreviousInOrderFrom(triangleNodes[1]).otherEndFrom(triangleNodes[1]) )
    {
      return triangleNodes;
    }
    else
    {
      return null;
    }
  }

  /**
   * Returns a String representation of this Graph including it's label,
   * number of Nodes, and number of Edges.
   *
   * @return String: A String representation of this Graph.
   */
  public String toString()
  {
    return(label + "(" + nodes.size() + " nodes, " + getNumEdges() + " edges)");
  }

  public void printAll()
  {
    for ( int i=0; i<nodes.size(); i++ )
    {
      ((Node)nodes.elementAt(i)).printAll();
    }
  }

  /**
   * Adds the given Node to the Nodes contained within this Graph.
   *
   * @param Node aNode: The Node to add to this Graph.
   */
  public void addNode(Node aNode)
  {
    addNode(aNode, true);
  }

  public void addNode(Node aNode, boolean addMemento)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    nodes.addElement(aNode);
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(NodeMemento.createCreateMemento(aNode));
    }
  }

  public Node createNode(Location aPoint)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    Node newNode = new Node(aPoint);
    nodes.addElement(newNode);
    if ( currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(NodeMemento.createCreateMemento(newNode));
    }
    return newNode;
  }

  public void translateNode(Node aNode, int dx, int dy, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    boolean memento = currentMemento != null && trackUndos && createMemento;
    if ( memento )
    {
      currentMemento.addMemento(NodeMovementMemento.createMoveMemento(aNode));
    }
    aNode.translate(dx, dy);
    Edge anEdge;
    Vector edges = aNode.incidentEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      anEdge = (Edge)edges.elementAt(i);
      if ( memento )
      {
        currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
      }
      anEdge.update();
    }
  }

  public void relocateNode(NodeInterface aNode, Location aLocation, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    boolean memento = currentMemento != null && trackUndos && createMemento;
    if ( memento )
    {
      currentMemento.addMemento(NodeMovementMemento.createMoveMemento(aNode));
    }
    aNode.setLocation(aLocation);
  }

  public void translateNodes( Vector someNodes, int dx, int dy, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    translate(someNodes, dx, dy, createMemento);
  }
 
  private void translate( Vector someNodes, int dx, int dy, boolean createMemento )
  {
    Node aNode;
    boolean memento = currentMemento != null && trackUndos && createMemento;
    for ( int i=0; i<someNodes.size(); i++ )
    {
      aNode = (Node)someNodes.elementAt(i);
      if ( memento )
      {
        currentMemento.addMemento(NodeMovementMemento.createMoveMemento(aNode));
      }
      aNode.translate(dx, dy);
    }
    Vector edges = getEdges(nodes);
    Edge anEdge;
    for ( int i=0; i<edges.size(); i++ )
    {
      anEdge = (Edge)edges.elementAt(i);
      if ( memento )
      {
        currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
      }
      anEdge.update();
    }
  }

  public void relocateEdge( Edge anEdge, Location newLocation, boolean createMemento )
  {
    if ( currentMemento != null && trackUndos && createMemento )
    {
      currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
    }
    anEdge.setCenterLocation(newLocation);
  }
 
  public void curveEdge( Edge anEdge, int dx, int dy, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( currentMemento != null && trackUndos && createMemento )
    {
      currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
    }
    anEdge.makeCurved();
    anEdge.translate(dx, dy);
  }

  public void orthogonalizeEdge( Edge anEdge, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( currentMemento != null && trackUndos && createMemento )
    {
      currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
    }
    anEdge.makeOrthogonal();
  }
 
  public void straightenEdge( EdgeInterface anEdge, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( currentMemento != null && trackUndos && createMemento )
    {
      currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
    }
    anEdge.makeStraight();
  }

  public void straightenEdges(boolean createMemento)
  {
    straightenEdges(getEdges(), createMemento);
  }
 
  public void straightenEdges(Vector edges, boolean createMemento)
  {
    for ( int i=0; i<edges.size(); i++ )
    {
      straightenEdge((Edge)edges.elementAt(i), createMemento);
    }
  }
 
  public void updateEdge( EdgeInterface anEdge, boolean createMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( currentMemento != null && trackUndos && createMemento )
    {
      currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
    }
    anEdge.update();
  }
 
  public void updateEdges(Vector edges, boolean createMemento)
  {
    for ( int i=0; i<edges.size(); i++ )
    {
      updateEdge((Edge)edges.elementAt(i), createMemento);
    }
  }
 
  public void refreshEdgeCurves()
  {
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      ((Edge)edges.elementAt(i)).update();
    }
  }

  public void updateEdgeCurveAngles()
  {
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      ((Edge)edges.elementAt(i)).initCurveAngles();
    }
  }

 
  public void refreshOrthogonalEdges(Vector edges)
  {
    Edge anEdge;
    Location location;
    for ( int i=0; i<edges.size(); i++ )
    { 
      anEdge = (Edge)edges.elementAt(i);
      if ( anEdge.isOrthogonal() )
      { 
        location = anEdge.getOrthogonalLocation();
        if ( location == null )
        {
          anEdge.setCenterLocation(anEdge.getNormalLocation());
        }
        else
       
          anEdge.setCenterLocation(location);
        }
      }
      else
      {
        anEdge.update();
      }
    }
  }
 
  public void changeNodeLabel ( NodeInterface aNode, String label, boolean createMemento )
  {
    if ( !label.equals(aNode.getLabel()) )
    {
      hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
      if ( currentMemento != null && trackUndos && createMemento )
      {
        currentMemento.addMemento(NodeLabelMemento.createLabelMemento(aNode));
      }
      aNode.setLabel( label );
    }
  }

  public void changeNodeDrawX ( NodeInterface aNode, boolean drawX, boolean createMemento )
  {
    if ( drawX != aNode.getDrawX() )
    {
      hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
      if ( currentMemento != null && trackUndos && createMemento )
      {
        currentMemento.addMemento(NodeDrawXMemento.createDrawXMemento(aNode));
      }
      aNode.setDrawX(drawX);
    }
  }

  public void changeNodeColor ( NodeInterface aNode, Color aColor, boolean createMemento )
  {
    if ( !aColor.equals( aNode.getColor() ) )
    {
      hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
      if ( currentMemento != null && trackUndos && createMemento )
      {
        currentMemento.addMemento(NodeColorMemento.createColorMemento(aNode));
      }
      aNode.setColor( aColor );
    }
  }

  public void changeEdgeColor ( EdgeInterface anEdge, Color aColor, boolean createMemento )
  {
    if ( !aColor.equals( anEdge.getColor() ) )
    {
      hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
      if ( currentMemento != null && trackUndos && createMemento )
      {
        currentMemento.addMemento(EdgeColorMemento.createColorMemento(anEdge));
      }
      anEdge.setColor( aColor );
    }
  }

  public void changeEdgeDirection( EdgeInterface anEdge, NodeInterface sourceNode, boolean createMemento )
  {
    if ( (sourceNode != null && !sourceNode.equals( anEdge.getDirectedSourceNode() )) ||
         (sourceNode == null && anEdge.getDirectedSourceNode() != null) )
    {
      hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
      if ( currentMemento != null && trackUndos && createMemento &&
           ((sourceNode != null && !sourceNode.equals(anEdge.getDirectedSourceNode())) ||
            (sourceNode == null && anEdge.getDirectedSourceNode() != null)) )
      {
        currentMemento.addMemento(EdgeDirectionMemento.createDirectionMemento(anEdge));
      }
      anEdge.setDirectedFrom( sourceNode );
    }
  }

  public boolean isTriangle(Node sourceNode, Edge firstEdge, Edge secondEdge)
  {
    Node firstNode = (Node)firstEdge.otherEndFrom(sourceNode);
    Node secondNode = (Node)secondEdge.otherEndFrom(sourceNode);
    return firstEdge.getPreviousInOrderFrom(firstNode).otherEndFrom(firstNode) == secondNode;
  }

  public boolean isInQuadrilateral(Edge anEdge)
  {
    Node firstNode = (Node)anEdge.getStartNode();
    Node secondNode = (Node)anEdge.otherEndFrom(firstNode);
    return ( anEdge.getNextInOrderFrom(firstNode).otherEndFrom(firstNode) ==
             anEdge.getPreviousInOrderFrom(secondNode).otherEndFrom(secondNode) &&
             anEdge.getPreviousInOrderFrom(firstNode).otherEndFrom(firstNode) ==
             anEdge.getNextInOrderFrom(secondNode).otherEndFrom(secondNode) );
  }

  public void flip(Edge anEdge)
  {
    Node firstNode = (Node)anEdge.getStartNode();
    Node secondNode = (Node)anEdge.getEndNode();
    Node newFirstNode = (Node)((Edge)anEdge.getPreviousInOrderFrom(firstNode)).otherEndFrom(firstNode);
    Node newSecondNode = (Node)((Edge)anEdge.getNextInOrderFrom(firstNode)).otherEndFrom(firstNode);
    Edge newFirstPrevEdge = (Edge)anEdge.getNextInOrderFrom(secondNode);
    Edge newSecondPrevEdge = (Edge)anEdge.getNextInOrderFrom(firstNode);
    // It is assumed that edges being flipped are NOT directed...
    Edge newEdge = new Edge(anEdge, null, newFirstNode, newSecondNode );

    deleteEdge(anEdge);
    addEdge(newEdge, newFirstPrevEdge, newSecondPrevEdge);
  }

  public void addEdge( EdgeInterface newEdge, EdgeInterface startPrevEdge,
                       EdgeInterface endPrevEdge )
  {
    addEdge( newEdge, startPrevEdge, endPrevEdge, true );
  }

  public void addEdge( EdgeInterface newEdge, EdgeInterface startPrevEdge,
                       EdgeInterface endPrevEdge, boolean addMemento )
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    NodeInterface startNode = newEdge.getStartNode();
    NodeInterface endNode = newEdge.getEndNode();
    startNode.addEdgeBetween( newEdge,
                              startPrevEdge,
                              startPrevEdge.getNextInOrderFrom(startNode) );
    endNode.addEdgeBetween( newEdge,
                            endPrevEdge,
                            endPrevEdge.getNextInOrderFrom(endNode) );
    if ( addMemento && currentMemento != null && trackUndos )
    {
      Edge a, b, c;
      if ( newEdge instanceof EdgeExtender )
      {
        a = ((EdgeExtender)newEdge).getRef();
      }
      else
      {
        a = (Edge)newEdge;
      }
      if ( startPrevEdge instanceof EdgeExtender )
      {
        b = ((EdgeExtender)startPrevEdge).getRef();
      }
      else
      {
        b = (Edge)startPrevEdge;
      }
      if ( endPrevEdge instanceof EdgeExtender )
      {
        c = ((EdgeExtender)endPrevEdge).getRef();
      }
      else
      {
        c = (Edge)endPrevEdge;
      }
      currentMemento.addMemento(EdgeBetweenMemento.createCreateMemento(a, b, c));
    }
  }

  private void addEdge(Node start, Node end, boolean addMemento )
  {
    // First make the edge
    Edge anEdge = new Edge(start, end);
    // Now tell the nodes about the edge
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( start.addIncidentEdge(anEdge) && end.addIncidentEdge(anEdge) &&
         addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(EdgeBetweenMemento.createCreateMemento(anEdge,
        (Edge)anEdge.getPreviousInOrderFrom(start),
        (Edge)anEdge.getPreviousInOrderFrom(end)));
    }
    if ( !edgeNumbersAreInSync() )
    {
      System.out.println("error2: " + anEdge);
    }
  }

  public void addEdge(Node start, Node end)
  {
    addEdge(start, end, true);
  }

  public void addEdgeNoCheck(Edge anEdge)
  {
    addEdgeNoCheck(anEdge, true);
  }

  public void addEdgeNoCheck(Edge anEdge, boolean addMemento)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    anEdge.getStartNode().addIncidentEdgeNoCheck(anEdge);
    anEdge.getEndNode().addIncidentEdgeNoCheck(anEdge);
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(EdgeBetweenMemento.createCreateMemento(anEdge,
        (Edge)anEdge.getPreviousInOrderFrom(anEdge.getStartNode()),
        (Edge)anEdge.getPreviousInOrderFrom(anEdge.getEndNode())));
    }
  }


  public void addEdgeNoCheck(NodeInterface aNode, EdgeInterface anEdge)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    aNode.addIncidentEdgeNoCheck(anEdge);
  }

  public void addEdgeNoCheck(Node start, Node end)
  {
    addEdgeNoCheck(start, end, true);
  }

  public void addEdgeNoCheck(Node start, Node end, boolean addMemento)
  {
    hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
    Edge anEdge = new Edge(start, end);
    start.addIncidentEdgeNoCheck(anEdge);
    end.addIncidentEdgeNoCheck(anEdge);
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(EdgeBetweenMemento.createCreateMemento(anEdge,
        (Edge)anEdge.getPreviousInOrderFrom(start),
        (Edge)anEdge.getPreviousInOrderFrom(end)));
    }
    if ( !edgeNumbersAreInSync() )
    {
      System.out.println("error4: " + anEdge);
    }
  }

  public void addGeneratedEdgeNoCheck(Node start, Node end)
  {
    addGeneratedEdgeNoCheck(start, end, true);
  }

  public void addGeneratedEdgeNoCheck(Node start, Node end, boolean addMemento)
  {
    hasChangedSinceLastSave = true;
      hasChangedSinceLastDraw = true;
    Edge anEdge = new Edge(start, end);
    anEdge.setIsGenerated(true);
    start.addIncidentEdgeNoCheck(anEdge);
    end.addIncidentEdgeNoCheck(anEdge);
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(EdgeBetweenMemento.createCreateMemento(anEdge,
        (Edge)anEdge.getPreviousInOrderFrom(start),
        (Edge)anEdge.getPreviousInOrderFrom(end)));
    }
  }

  /**
   * Adds the given Edge to the Graph by searching the Nodes for
   * ones with the given labels and creates a new Edge
   * using the Nodes found within the Graph.
   *
   * @param String startLabel: The label of the first end Node of the new Edge to add.
   * @param String endLabel: The label of the second end Node of the new Edge to add.
   */
  public void addEdge(String startLabel, String endLabel)
  {
    Node start, end;
    start = nodeNamed(startLabel);
    end = nodeNamed(endLabel);
    if ((start != null) && (end != null))
      addEdge(start, end);
  }

  /**
   * Removes the given Edge from this Graph by telling the end
   * Nodes of the Edge to delete the Edge from their incident
   * Edge list.
   *
   * @param Edge anEdge: The Edge to remove from this Graph.
   */
  public void deleteEdge(Edge anEdge)
  {
    deleteEdge(anEdge, true);
  }

  public void deleteEdge(Edge anEdge, boolean createMemento)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( createMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(EdgeBetweenMemento.createDeleteMemento(anEdge,
        (Edge)anEdge.getPreviousInOrderFrom(anEdge.getStartNode()),
        (Edge)anEdge.getPreviousInOrderFrom(anEdge.getEndNode())));
    }
    anEdge.getStartNode().deleteIncidentEdge(anEdge);
    anEdge.getEndNode().deleteIncidentEdge(anEdge);
  }

  /**
   * Removes the given Node from this Graph, deleting any Edges
   * incident to it.
   *
   * @param Node aNode: The Node to remove from this Graph.
   */
  public void deleteNode(Node aNode)
  {
    deleteNode(aNode, true);
  }

  public void deleteNode(Node aNode, boolean addMemento)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    Enumeration someEdges = aNode.incidentEdgesInReverse().elements();
    while(someEdges.hasMoreElements())
    {
      Edge anEdge = (Edge)someEdges.nextElement();
      deleteEdge(anEdge, addMemento);
    }
    nodes.removeElement(aNode);
    if ( addMemento && currentMemento != null && trackUndos )
    {
      currentMemento.addMemento(NodeMemento.createDeleteMemento(aNode));
    }
  }

  public void makeGeneratedEdgePermanent(Edge anEdge)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    if ( anEdge.isGenerated() )
    {
      anEdge.setIsGenerated(false);
      if ( currentMemento != null && trackUndos )
      {
        currentMemento.addMemento(EdgeMemento.createPreserveGeneratedMemento(anEdge));
      }
    }
  }

  public void makeGeneratedEdgesPermanent()
  {
    Enumeration enumEdges = getEdges().elements();
    while ( enumEdges.hasMoreElements() )
    {
      makeGeneratedEdgePermanent((Edge)enumEdges.nextElement());
    }
  }

  public void deleteGeneratedEdges()
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    Enumeration enumNodes = nodes.elements();
    Node currentNode;
    Vector edges;
    Edge currentEdge;
    while ( enumNodes.hasMoreElements() )
    {
      currentNode = (Node)enumNodes.nextElement();
      edges = currentNode.incidentEdges();
      for ( int i=0; i<edges.size(); i++ )
      {
        currentEdge = (Edge)edges.elementAt(i);
        if ( currentEdge.isGenerated() )
        {
          deleteEdge(currentEdge);
        }
      }
    }
  }

  public void removeEdgeDirections()
  {
    removeEdgeDirections(true);
  }

  public void removeEdgeDirections(boolean createMemento)
  {
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      changeEdgeDirection((Edge)edges.elementAt(i), null, createMemento);
    }
  }

  public void clearNodeLabels()
  {
    clearNodeLabels(true);
  }

  public void clearNodeLabels(boolean createMemento)
  {
    for ( int i=0; i<nodes.size(); i++ )
    {
      changeNodeLabel((Node)nodes.elementAt(i), "", createMemento);
    }
  }

  /**
   * Returns the Node with the given Label, or Null if none exists.
   *
   * @param String aLabel: The label of the Node to retrieve.
   * @return Node: The Node with label matching the given label.
   */
  public Node nodeNamed(String aLabel)
  {
    for (int i=0; i<nodes.size(); i++)
    {
      Node aNode = (Node)nodes.elementAt(i);
      if (aNode.getLabel().equals(aLabel))
        return aNode;
    }
    return null;
  }

  /**
   * Returns the Node at the given location, or Null if none exists.
   *
   * @param Point p: The Point representing the location of the Node to retrieve.
   * @return Node: The Node with location matching the given location.
   */
  public Node nodeAt(Point p)
  {
    return nodeAt(new Location(p));
  }

  public Node nodeAt(Location p)
  {
    for (int i=0; i<nodes.size(); i++)
    {
      Node aNode = (Node)nodes.elementAt(i);
      int distance = (p.intX() - aNode.getLocation().intX()) * (p.intX() - aNode.getLocation().intX()) +
                     (p.intY() - aNode.getLocation().intY()) * (p.intY() - aNode.getLocation().intY());
      if (distance <= (Node.RADIUS * Node.RADIUS))
        return aNode;
    }
    return null;
  }

  /**
   * Returns the Edge whose midpoint is at (or very close to) the given location,
   * or Null if none exists.
   *
   * @param Point p: The Point representing the location of the Edge to retrieve.
   * @return Edge: The Edge with location matching the given location.
   */
  public Edge edgeAt(Location p)
  {
    Vector edges = getEdges();
    int midPointX, midPointY;
    for (int i=0; i<edges.size(); i++)
    {
      Edge anEdge = (Edge)edges.elementAt(i);
      midPointX = anEdge.getCenterLocation().intX();
      midPointY = anEdge.getCenterLocation().intY();
      int distance = (p.intX() - midPointX) * (p.intX() - midPointX) +
                     (p.intY() - midPointY) * (p.intY() - midPointY);
      if ( distance <= (Node.RADIUS * Node.RADIUS) )
      {
        return anEdge;
      }
    }
    return null;
  }

  public Vector getNodesInRectangle( Rectangle2D.Double rect )
  {
    Vector nodesToReturn = new Vector();
    Node aNode;
    for ( int i=0; i<nodes.size(); i++ )
    {
      aNode = (Node)nodes.elementAt(i);
      if ( rect.contains( aNode.getX(), aNode.getY() ) )
      {
        nodesToReturn.addElement(aNode);
      }
    }
    return nodesToReturn;
  }

  public Vector getEdgesInRectangle( Rectangle2D.Double rect )
  {
    Vector edgesToReturn = new Vector();
    Vector edges = getEdges();
    Edge anEdge;
    for ( int i=0; i<edges.size(); i++ )
    {
      anEdge = (Edge)edges.elementAt(i);
      if ( rect.contains( anEdge.getCenterLocation().intX(),
                          anEdge.getCenterLocation().intY() ) )
      {
        edgesToReturn.addElement(anEdge);
      }
    }
    return edgesToReturn;
  }

  /**
   * Returns the Edge that passes through the given location,
   * or Null if none exists.
   *
   * @param Point p: The Point that the Edge to retrieve must pass through.
   * @return Edge: The Edge passing through the given location.
   */
  /*public Edge edgeContainingPoint(Point p)
  {
    Vector edges = getEdges();
    Edge anEdge;
    double distance = 0;
    for (int i=0; i<edges.size(); i++)
    {
      anEdge = (Edge)edges.elementAt(i);
      distance = Line2D.ptLineDist(anEdge.getStartNode().getLocation().intX(),
                                   anEdge.getStartNode().getLocation().intY(),
                                   anEdge.getEndNode().getLocation().intX(),
                                   anEdge.getEndNode().getLocation().intY(),
                                   p.x,
                                   p.y);
      if (distance == 0)
        return anEdge;
    }
    return null;
  }*/

  /**
   * Returns all of the Nodes in this Graph that have been selected.
   *
   * @return Vector: A Vector containing all of the selected Nodes of this Graph.
   */
  public Vector selectedNodes()
  {
    Vector selected = new Vector();
    Enumeration allNodes = nodes.elements();
    Node aNode;
    while(allNodes.hasMoreElements())
    {
      aNode = (Node)allNodes.nextElement();
      if (aNode.isSelected())
        selected.addElement(aNode);
    }
    return selected;
  }

  /**
   * Returns all of the Edges in this Graph that have been selected.
   *
   * @return Vector: A Vector containing all of the selected Edges of this Graph.
   */
  public Vector selectedEdges()
  {
    Vector selected = new Vector();
    Enumeration allEdges = getEdges().elements();
    Edge anEdge;
    while(allEdges.hasMoreElements())
    {
      anEdge = (Edge)allEdges.nextElement();
      if (anEdge.isSelected())
        selected.addElement(anEdge);
    }
    return selected;
  }

  public void unselectAll()
  {
    hasChangedSinceLastDraw = true;
    Enumeration highlightedEdges = selectedEdges().elements();
    while (highlightedEdges.hasMoreElements())
    {
      ((Edge)highlightedEdges.nextElement()).setSelected(false);
    }
    Enumeration highlightedNodes = selectedNodes().elements();
    while (highlightedNodes.hasMoreElements())
    {
      ((Node)highlightedNodes.nextElement()).setSelected(false);
    }
  }

  public void deleteSelected()
  {
    hasChangedSinceLastDraw = true;
    Enumeration highlightedEdges = selectedEdges().elements();
    while (highlightedEdges.hasMoreElements())
    {
      deleteEdge((Edge)highlightedEdges.nextElement());
    }
    Enumeration highlightedNodes = selectedNodes().elements();
    while (highlightedNodes.hasMoreElements())
    {
      deleteNode((Node)highlightedNodes.nextElement());
    }
  }

  public void toggleEdgeSelection(Edge anEdge)
  {
    hasChangedSinceLastDraw = true;
    anEdge.toggleSelected();
  }

  public void toggleNodeSelection(Node aNode)
  {
    hasChangedSinceLastDraw = true;
    aNode.toggleSelected();
  }

  public void selectNodes(Vector sNodes)
  {
    hasChangedSinceLastDraw = true;
    for ( int i=0; i<sNodes.size(); i++ )
    {
      ((Node)sNodes.elementAt(i)).setSelected(true);
    }
  }

  public void selectEdges(Vector sEdges)
  {
    hasChangedSinceLastDraw = true;
    for ( int i=0; i<sEdges.size(); i++ )
    {
      ((Edge)sEdges.elementAt(i)).setSelected(true);
    }
  }

  public void deleteAll()
  {
    hasChangedSinceLastDraw = true;
    Enumeration nodeEnum = new Vector(nodes).elements();
    while (nodeEnum.hasMoreElements())
    {
      deleteNode((Node)nodeEnum.nextElement());
    }
  }

  public void resetColors(boolean createMemento)
  {
    hasChangedSinceLastDraw = true;
    Node aNode;
    for ( int i=0; i<nodes.size(); i++ )
    {
      aNode = (Node)nodes.elementAt(i);
      changeNodeColor(aNode, Node.DEFAULT_COLOR, createMemento);
      changeNodeDrawX(aNode, false, createMemento);
      //aNode.setLabel("");
    }
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      changeEdgeColor((Edge)edges.elementAt(i), Edge.DEFAULT_COLOR, createMemento);
    }
  }

  /**
   * Draws this Graph using the default Colors
   *
   * @param Graphics aPen: The Graphics object to use to draw this Graph.
   */
  public void draw(Graphics2D g2)
  {
    draw(g2, 0, 0);
  }

  public void draw(Graphics2D g2, int xOffset, int yOffset)
  {
    hasChangedSinceLastDraw = false;
    logChangedSinceLastDraw = false;
    Vector edges = getEdges();
    // Draw the edges first
    for (int i=0; i<edges.size(); i++)
    {
      ((Edge)edges.elementAt(i)).draw(g2, xOffset, yOffset,
                                      drawSelected);
    }
    // Draw the nodes now
    for (int i=0; i<nodes.size(); i++)
    {
      ((Node)nodes.elementAt(i)).draw(g2, xOffset, yOffset,
                                      drawSelected, showCoords, showLabels);
    }
  }

  public void rotate(Location pivotPoint, double angle, boolean createMemento)
  {
    boolean memento = currentMemento != null && trackUndos && createMemento;
   
    Node currentNode;
    for ( int i=0; i<nodes.size(); i++ )
    {
      currentNode = (Node)nodes.elementAt(i);
      if ( memento )
      {
        currentMemento.addMemento(NodeMovementMemento.createMoveMemento(currentNode));
      }
      currentNode.rotate(pivotPoint, angle);
    }
    Vector edges = getEdges();
    Edge anEdge;
    for ( int i=0; i<edges.size(); i++ )
    {
      anEdge = (Edge)edges.elementAt(i);
      if ( memento )
      {
        currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
      }
      anEdge.rotate(pivotPoint, angle);
      anEdge.update();
    }
  }

  public void translate(int dx, int dy, boolean createMemento)
  {
    hasChangedSinceLastSave = true;
    hasChangedSinceLastDraw = true;
    translate(nodes, dx, dy, createMemento);
  }

  /**
   * Save this Graph to the File that is provided as a Parameter. The label,
   * size, number of Nodes and number of Edges is outputted and the saveTo
   * method of each Node and Edge in the Graph is called.
   *
   * @param PrintWriter aFile: The file to save to that is open/ready for output.
   */
  public void saveTo(PrintWriter aFile)
  {
    aFile.println(label);
    aFile.println(gridRows);
    aFile.println(gridRowHeight);
    aFile.println(gridCols);
    aFile.println(gridColWidth);
    // Output the nodes
    aFile.println(nodes.size());
    enumerateNodeAndEdgeIndices();
    for (int i=0; i<nodes.size(); i++)
    {
      ((Node)nodes.elementAt(i)).saveTo(aFile);
    }
    // Output the edges
    Vector edges = getEdges();
    aFile.println(edges.size());
    for (int i=0; i<edges.size(); i++)
    {
      ((Edge)edges.elementAt(i)).saveTo(aFile);
    }
    hasChangedSinceLastSave = false;
  }

  /**
   * Load this Graph from the File that is provided as a Parameter. The label
   * and scale are read in, and each Node and Edge stored in the file is loaded
   * by calling its loadFrom method.<br>
   * <br>
   * Note that after the Nodes and Edges are loaded, it is necessary to go through
   * the Graph and connected the Nodes and Edges properly.
   *
   * @param BufferedReader aFile: The file to load from that is open/ready for input.
   */
  public static Graph loadFrom(BufferedReader aFile) throws IOException
  {
    Node aNode;
    int numNodes,numEdges;
    // Read the label from the file and make the graph
    Graph aGraph = new Graph(aFile.readLine());
    aGraph.gridRows = Integer.valueOf(aFile.readLine()).intValue();
    aGraph.gridRowHeight = Integer.valueOf(aFile.readLine()).intValue();
    aGraph.gridCols = Integer.valueOf(aFile.readLine()).intValue();
    aGraph.gridColWidth = Integer.valueOf(aFile.readLine()).intValue();
    // Get the nodes and edges
    numNodes = Integer.valueOf(aFile.readLine()).intValue();
    Vector allEdgeIndices = new Vector();
    for (int i=0; i<numNodes; i++)
    {
      aGraph.addNode(Node.loadFrom(aFile, allEdgeIndices));
    }
    // Now connect them with new edges
    numEdges = Integer.valueOf(aFile.readLine()).intValue();
    Vector edges = new Vector(numEdges);
    for (int i=0; i<numEdges; i++)
    {
      edges.addElement( Edge.loadFrom(aFile, aGraph.nodes) );
    }

    Vector edgeIndices;
    for (int i=0; i<numNodes; i++)
    {
      aNode = (Node)aGraph.nodes.elementAt(i);
      edgeIndices = (Vector)allEdgeIndices.elementAt(i);
      for ( int j=0; j<edgeIndices.size(); j++ )
      {
        aNode.addIncidentEdgeNoCheck(
          (Edge)edges.elementAt( ((Integer)edgeIndices.elementAt(j)).intValue()-1 ) );
      }
    }

    return (aGraph);
  }

  public boolean hasNodes()
  {
    return nodes.size() != 0;
  }

  public void enumerateNodeAndEdgeIndices()
  {
    for ( int i=0; i<nodes.size(); i++ )
    {
      ((Node)nodes.elementAt(i)).setIndex(i+1);
    }
    Vector edges = getEdges();
    for ( int i=0; i<edges.size(); i++ )
    {
      ((Edge)edges.elementAt(i)).setIndex(i+1);
    }
  }

  public EdgeInterface[] sortEdges()
  {
    return sortEdges(getEdges());
  }

  public EdgeInterface[] sortEdges(Vector edges)
  {
    int count[] = new int[nodes.size()];
    EdgeInterface sortedEdges[] = new EdgeInterface[edges.size()];
    EdgeInterface sortedEdges2[] = new EdgeInterface[edges.size()];
    int i=0;
    for ( i=0; i<nodes.size(); i++ )
    {
      count[i] = 0;
      ((Node)nodes.elementAt(i)).setIndex(i+1);
    }
    for ( i=0; i<edges.size(); i++ )
    {
      count[((EdgeInterface)edges.elementAt(i)).getHigherIndex()-1]++;
    }
    for ( i=1; i<nodes.size(); i++ )
    {
      count[i]+=count[i-1];
    }
    for ( i=edges.size()-1; i>=0; i-- )
    {
      sortedEdges[count[((EdgeInterface)edges.elementAt(i)).getHigherIndex()-1]-1] = (EdgeInterface)edges.elementAt(i);
      count[((EdgeInterface)edges.elementAt(i)).getHigherIndex()-1]--;
    }

    for ( i=0; i<nodes.size(); i++ )
    {
      count[i] = 0;
    }
    for ( i=0; i<edges.size(); i++ )
    {
      count[sortedEdges[i].getLowerIndex()-1]++;
    }
    for ( i=1; i<nodes.size(); i++ )
    {
      count[i]+=count[i-1];
    }
    for ( i=edges.size()-1; i>=0; i-- )
    {
      sortedEdges2[count[sortedEdges[i].getLowerIndex()-1]-1] = sortedEdges[i];
      count[sortedEdges[i].getLowerIndex()-1]--;
    }
    return sortedEdges2;
  }

  public void deleteAllEdges()
  {
    // This is for embed...
    Vector edges = getEdges();
    Edge edge;
    for ( int i=0; i<edges.size(); i++ )
    {
      edge = (Edge)edges.elementAt(i);
      if ( currentMemento != null && trackUndos )
      {
        currentMemento.addMemento(EdgeBetweenMemento.createChangeMemento(edge));
      }
    }

    Node node;
    for ( int i=0; i<nodes.size(); i++ )
    {
      node = (Node)nodes.elementAt(i);
      if ( currentMemento != null && trackUndos )
      {
        currentMemento.addMemento(NodeChangeMemento.createChangeMemento(node));
      }
      node.resetIncidentEdges();
    }
  }

  public boolean checkForDuplicateEdges()
  {
    EdgeInterface sortedEdges[] = sortEdges();
    for ( int i=0; i<sortedEdges.length-1; i++ )
    {
      if ( sortedEdges[i].equals(sortedEdges[i+1]) )
      {
        return true;
      }
    }
    return false;
  }

  public void scaleTo(Rectangle2D.Double newBounds, boolean createMemento )
  {
    boolean memento = currentMemento != null && trackUndos && createMemento;
    if ( !nodes.isEmpty() )
    {
      Rectangle2D.Double oldBounds = getBounds();
      double xFactor = newBounds.getWidth() / oldBounds.getWidth();
      double yFactor = newBounds.getHeight() / oldBounds.getHeight();
      Node currentNode;

      for ( int i=0; i<nodes.size(); i++ )
      {
        currentNode = (Node)nodes.elementAt(i);
        if ( memento )
        {
          currentMemento.addMemento(NodeMovementMemento.createMoveMemento(currentNode));
        }
        currentNode.scaleBy( oldBounds.getMinX(), oldBounds.getMinY() , xFactor, yFactor);
      }
      Vector edges = getEdges();
      Edge anEdge;
      for ( int i=0; i<edges.size(); i++ )
      {
        anEdge = (Edge)edges.elementAt(i);
        if ( memento )
        {
          currentMemento.addMemento(EdgeMovementMemento.createMoveMemento(anEdge));
        }
        anEdge.scaleBy( oldBounds.getMinX(), oldBounds.getMinY() , xFactor, yFactor);
      }
    }
  }

  public Vector createNodeExtenders(Class NodeExtenderClass)
  {
    Vector newVector = new Vector(nodes.size());
    Node currentNode;
    NodeExtender currentNodeExtender;
    for ( int i=0; i<nodes.size(); i++ )
    {
      currentNode = (Node)nodes.elementAt(i);
      try
      {
        currentNodeExtender = (NodeExtender)NodeExtenderClass.newInstance();
        currentNode.setExtender(currentNodeExtender);
        currentNodeExtender.setRef(currentNode);
        newVector.addElement(currentNodeExtender);
      }
      catch (Exception e) { e.printStackTrace(); }
    }
    return newVector;
  }

  public Vector createEdgeExtenders(Class EdgeExtenderClass)
  {
    Vector edges = getEdges();
    Vector newVector = new Vector(edges.size());
    Edge currentEdge;
    EdgeExtender currentEdgeExtender;
    for ( int i=0; i<edges.size(); i++ )
    {
      currentEdge = (Edge)edges.elementAt(i);
      try
      {
        currentEdgeExtender = (EdgeExtender)EdgeExtenderClass.newInstance();
        currentEdge.setExtender(currentEdgeExtender);
        currentEdgeExtender.setRef(currentEdge);
        newVector.addElement(currentEdgeExtender);
      }
      catch (Exception e) { e.printStackTrace(); }
    }
    return newVector;
  }

  public Vector getNodeExtenders()
  {
    Vector newVector = new Vector(nodes.size());
    Node currentNode;
    NodeExtender currentNodeExtender;
    for ( int i=0; i<nodes.size(); i++ )
    {
      currentNode = (Node)nodes.elementAt(i);
      currentNodeExtender = currentNode.getExtender();
      if ( currentNodeExtender != null )
      {
        newVector.addElement(currentNodeExtender);
      }
    }
    return newVector;
  }

  public Vector getEdgeExtenders()
  {
    Vector edges = getEdges();
    Vector newVector = new Vector(edges.size());
    Edge currentEdge;
    EdgeExtender currentEdgeExtender;
    for ( int i=0; i<edges.size(); i++ )
    {
      currentEdge = (Edge)edges.elementAt(i);
      currentEdgeExtender = currentEdge.getExtender();
      if ( currentEdgeExtender != null )
      {
        newVector.addElement(currentEdgeExtender);
      }
    }
    return newVector;
  }

  public Vector getEdgeExtenders(Vector nodeVector)
  {
    Vector edges = getEdges(nodeVector);
    Vector newVector = new Vector(edges.size());
    Edge currentEdge;
    EdgeExtender currentEdgeExtender;
    for ( int i=0; i<edges.size(); i++ )
    {
      currentEdge = (Edge)edges.elementAt(i);
      currentEdgeExtender = currentEdge.getExtender();
      if ( currentEdgeExtender != null )
      {
        newVector.addElement(currentEdgeExtender);
      }
    }
    return newVector;
  }
 
  public void permuteNodeOrder()
  {
    java.util.Random rand = new java.util.Random();
    Object temp;
    int j;
    for ( int i=0; i<nodes.size(); i++ )
    {
      j = rand.nextInt(nodes.size());
      temp = nodes.elementAt(i);
      nodes.setElementAt(nodes.elementAt(j), i);
      nodes.setElementAt(temp, j);   
    }
  }
}
TOP

Related Classes of graphStructure.Graph

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.