Package com.mxgraph.analysis

Source Code of com.mxgraph.analysis.mxGraphGenerator

/**
* Copyright (c) 2012, JGraph Ltd
*/
package com.mxgraph.analysis;

import java.util.ArrayList;

import com.mxgraph.costfunction.mxCostFunction;
import com.mxgraph.costfunction.mxDoubleValCostFunction;
import com.mxgraph.generatorfunction.mxGeneratorFunction;
import com.mxgraph.generatorfunction.mxGeneratorRandomFunction;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.view.mxCellState;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraphView;

/**
* @author Mate
*
*/
public class mxGraphGenerator
{
  // cost function class that implements mxICostFunction
  //  private mxGeneratorFunction generatorFunction = new mxGeneratorRandomFunction(0,1,2);
  //  private mxGeneratorFunction generatorFunction = new mxGeneratorConstFunction(1.5);
  //  private mxGeneratorFunction generatorFunction = new mxGeneratorRandomIntFunction(0, 20);
  private mxGeneratorFunction generatorFunction = null;

  private mxCostFunction costFunction = null;

  public mxGraphGenerator(mxGeneratorFunction generatorFunction, mxCostFunction costFunction)
  {
    if (generatorFunction != null)
    {
      this.generatorFunction = generatorFunction;
    }

    if (costFunction != null)
    {
      this.costFunction = costFunction;
    }
    else
    {
      this.costFunction = new mxDoubleValCostFunction();
    }
  };

  /**
   * @param aGraph
   * @param numVertexes
   * @return a null graph
   */
  public void getNullGraph(mxAnalysisGraph aGraph, int numVertices)
  {
    if (numVertices < 0)
    {
      throw new IllegalArgumentException();
    }
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();

    for (int i = 0; i < numVertices; i++)
    {
      graph.insertVertex(parent, null, new Integer(i).toString(), i * 50, 0, 25, 25);
    }
  };

  /**
   * @param aGraph
   * @param numVertices number of vertices
   * @return A complete graph that has <b>numVertices</b> number of vertices
   */
  public void getCompleteGraph(mxAnalysisGraph aGraph, int numVertices)
  {
    if (numVertices < 0)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), i * 50, 0, 25, 25);
    }

    for (int i = 0; i < numVertices; i++)
    {
      Object vertex1 = vertices[i];

      for (int j = 0; j < numVertices; j++)
      {
        Object vertex2 = vertices[j];

        if (vertex1 != vertex2 && !mxGraphStructure.areConnected(aGraph, vertex1, vertex2))
        {
          graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertex1, vertex2);
        }
      }
    }
  };

  /**
   * @param aGraph
   * @param numRows - number of rows in the grid graph
   * @param numColumns - number of columns in the grid graph
   * @return Returns a <b>numColumns</b> x <b>numRows</b> grid graph
   */
  public void getGridGraph(mxAnalysisGraph aGraph, int numColumns, int numRows)
  {
    if (numColumns < 0 || numRows < 0)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    int numVertices = numColumns * numRows;
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    int vertexCount = 0;

    for (int j = 0; j < numRows; j++)
    {
      for (int i = 0; i < numColumns; i++)
      {
        Object currVertex = vertices[vertexCount];

        if (i > 0)
        {
          // connect with previous x
          graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[vertexCount - 1], currVertex);
        }

        if (j > 0)
        {
          //connect with previous y
          graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[vertexCount - numColumns], currVertex);
        }

        vertexCount++;
      }
    }
  };

  /**
   * Sets the physical spacing between vertices in a grid graph. This works for now only for a graph generated with mxGraphCreator.getGridGraph() only after creating the graph
   * @param aGraph
   * @param xSpacing - horizontal spacing between vertices
   * @param ySpacing - vertical spacing between vertices
   * @param numRows - number of rows in the grid graph
   * @param numColumns - number of columns in the grid graph
   */
  public void setGridGraphSpacing(mxAnalysisGraph aGraph, double xSpacing, double ySpacing, int numColumns, int numRows)
  {
    mxGraph graph = aGraph.getGraph();

    if (xSpacing < 0 || ySpacing < 0 || numColumns < 1 || numRows < 1)
    {
      throw new IllegalArgumentException();
    }

    Object parent = graph.getDefaultParent();
    Object[] vertices = aGraph.getChildVertices(parent);
    mxIGraphModel model = graph.getModel();

    for (int i = 0; i < numRows; i++)
    {
      for (int j = 0; j < numColumns; j++)
      {
        Object currVertex = vertices[i * numColumns + j];
        mxGeometry geometry = model.getGeometry(currVertex);
        geometry.setX(j * xSpacing);
        geometry.setY(i * ySpacing);
      }
    }
  };

  /**
   * @param aGraph
   * @param numVerticesGroup1 number of vertices in group 1
   * @param numVerticesGroup2 number of vertices in group 2
   * @return a bipartite graph with group 1 containing <b>numVerticesGroup1</b> vertices and group 2 containing <b>numVerticesGroup2</b>
   */
  public void getBipartiteGraph(mxAnalysisGraph aGraph, int numVerticesGroup1, int numVerticesGroup2)
  {
    if (numVerticesGroup1 < 0 || numVerticesGroup2 < 0)
    {
      throw new IllegalArgumentException();
    }

    int numVertices = numVerticesGroup1 + numVerticesGroup2;
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    for (int i = 0; i < numVerticesGroup1; i++)
    {
      Object currVertex = vertices[i];
      Object destVertex = vertices[getRandomInt(numVerticesGroup1, numVertices - 1)];
      graph.insertEdge(parent, null, getNewEdgeValue(aGraph), currVertex, destVertex);
    }

    for (int j = 0; j < numVerticesGroup2; j++)
    {
      Object currVertex = vertices[numVerticesGroup1 + j];
      int edgeNum = aGraph.getOpposites(aGraph.getEdges(currVertex, null, true, true, false, true), currVertex, true, true).length;

      if (edgeNum == 0)
      {
        Object destVertex = vertices[getRandomInt(0, numVerticesGroup1 - 1)];
        graph.insertEdge(parent, null, getNewEdgeValue(aGraph), currVertex, destVertex);
      }
    }
  };

  /**
   * Sets the physical spacing between vertices in a bipartite graph. This works for now only for a graph generated with mxGraphCreator.getBipartiteGraph()
   * only after creating the graph
   * @param aGraph
   * @param numVerticesGroup1 - number of vertices in group 1
   * @param numVerticesGroup2 - number of vertices in group 2
   * @param vertexSpacing - vertical spacing between vertices in the same group
   * @param groupSpacing - spacing between groups
   */
  public void setBipartiteGraphSpacing(mxAnalysisGraph aGraph, int numVerticesGroup1, int numVerticesGroup2, double vertexSpacing,
      double groupSpacing)
  {
    if (numVerticesGroup1 < 0 || numVerticesGroup2 < 0)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    double group1StartY = 0;
    double group2StartY = 0;
    Object parent = graph.getDefaultParent();
    mxIGraphModel model = graph.getModel();

    if (numVerticesGroup1 < numVerticesGroup2)
    {
      double centerYtimes2 = (numVerticesGroup2 * vertexSpacing);
      group1StartY = (centerYtimes2 - (numVerticesGroup1 * vertexSpacing)) / 2;
    }
    else
    {
      double centerYtimes2 = (numVerticesGroup1 * vertexSpacing);
      group2StartY = (centerYtimes2 - (numVerticesGroup2 * vertexSpacing)) / 2;
    }

    Object[] vertices = aGraph.getChildVertices(parent);

    // position vertexes for group 1
    for (int i = 0; i < numVerticesGroup1; i++)
    {
      Object currVertex = vertices[i];
      mxGeometry geometry = model.getGeometry(currVertex);
      geometry.setX(0);
      geometry.setY(group1StartY + i * vertexSpacing);
    }

    // position vertexes for group 2
    for (int i = numVerticesGroup1; i < numVerticesGroup1 + numVerticesGroup2; i++)
    {
      Object currVertex = vertices[i];
      mxGeometry geometry = model.getGeometry(currVertex);
      geometry.setX(groupSpacing);
      geometry.setY(group2StartY + (i - numVerticesGroup1) * vertexSpacing);
    }
  };

  /**
   * @param aGraph
   * @param numVerticesGroup1 number of vertices in group 1
   * @param numVerticesGroup2 number of vertices in group 2
   * @return a bipartite graph with group 1 containing <b>numVerticesGroup1</b> vertices and group 2 containing <b>numVerticesGroup2</b>
   */
  public void getCompleteBipartiteGraph(mxAnalysisGraph aGraph, int numVerticesGroup1, int numVerticesGroup2)
  {
    if (numVerticesGroup1 < 0 || numVerticesGroup2 < 0)
    {
      throw new IllegalArgumentException();
    }

    int numVertices = numVerticesGroup1 + numVerticesGroup2;
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    for (int i = 0; i < numVerticesGroup1; i++)
    {
      for (int j = numVerticesGroup1; j < numVertices; j++)
      {
        Object currVertex = vertices[i];
        Object destVertex = vertices[j];
        graph.insertEdge(parent, null, getNewEdgeValue(aGraph), currVertex, destVertex);
      }
    }
  };

  /**
   * @param aGraph
   * @param xDim
   * @param yDim
   * @return a knight graph of size <b>xDim</b> x <b>yDim</b>
   * Note that the minimum size is 3x3
   */
  public void getKnightGraph(mxAnalysisGraph aGraph, int xDim, int yDim)
  {
    if (xDim < 3 || yDim < 3)
    {
      throw new IllegalArgumentException();
    }

    int numVertices = xDim * yDim;
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    //now we set up the starting conditions
    int[] currCoords = new int[2];

    //the main loop
    for (int i = 0; i < (xDim * yDim); i++)
    {
      currCoords = getVertexGridCoords(xDim, yDim, i);
      Object[] neighborMoves = getKnightMoveVertexes(aGraph, xDim, yDim, currCoords[0], currCoords[1]);

      for (int j = 0; j < neighborMoves.length; j++)
      {
        // connect current with the possible move that has minimum number of its (possible moves)
        if (!mxGraphStructure.areConnected(aGraph, vertices[i], neighborMoves[j]))
        {
          graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[i], neighborMoves[j]);
        }
        // that vertex becomes the current vertex and we repeat until no possible moves
      }
    }
  };

  /**
   * @param aGraph
   * @param xDim x dimension of chess-board, size starts from 1
   * @param yDim y dimension of chess-board, size starts from 1
   * @param xCoord x coordinate on the chess-board, coordinate starts from 1
   * @param yCoord y coordinate on the chess-board, coordinate starts from 1
   * @return a list of ALL vertexes which would be valid moves from the current position, regardless if they were visited or not
   * Note that both dimensions and both coordinates must be positive
   */
  public Object[] getKnightMoveVertexes(mxAnalysisGraph aGraph, int xDim, int yDim, int xCoord, int yCoord)
  {
    if (xCoord > xDim || yCoord > yDim || xDim < 1 || yDim < 1 || xCoord < 1 || yCoord < 1)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object[] vertices = aGraph.getChildVertices(graph.getDefaultParent());

    //check all possible 8 locations

    //location 1
    int currX = xCoord + 1;
    int currY = yCoord - 2;
    ArrayList<Object> possibleMoves = new ArrayList<Object>();
    // check if in bounds
    Object currVertex;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 2
    currX = xCoord + 2;
    currY = yCoord - 1;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 3
    currX = xCoord + 2;
    currY = yCoord + 1;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 4
    currX = xCoord + 1;
    currY = yCoord + 2;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 5
    currX = xCoord - 1;
    currY = yCoord + 2;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 6
    currX = xCoord - 2;
    currY = yCoord + 1;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 7
    currX = xCoord - 2;
    currY = yCoord - 1;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 8
    currX = xCoord - 1;
    currY = yCoord - 2;

    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    return possibleMoves.toArray();
  };

  /**
   * use this only with the grid graph, and various chess-board graphs, because of vertex ordering
   * @param xDim x dimension of chess-board, size starts from 1
   * @param yDim y dimension of chess-board, size starts from 1
   * @param value value of the vertex that needs coordinates returned
   * @return int[x,y] where x and y are the coordinates in the grid or chess-board
   * Note that both dimensions must be positive
   */
  public int[] getVertexGridCoords(int xDim, int yDim, int value)
  {
    if (value > ((yDim * xDim) - 1) || xDim < 0 || yDim < 0 || value < 0)
    {
      throw new IllegalArgumentException();
    }

    int yCoord = (int) Math.floor(value / xDim);
    int xCoord = (value - yCoord * xDim) + 1;
    yCoord += 1;

    int[] coords = new int[2];
    coords[0] = xCoord;
    coords[1] = yCoord;
    return coords;
  };

  /**
   * use this only with the grid graph and various chess-board graphs, because of vertex ordering
   * @param vertices
   * @param xDim x dimension of chess-board, size starts from 1
   * @param yDim y dimension of chess-board, size starts from 1
   * @param xCoord x coordinate on the chess-board, coordinate starts from 1
   * @param yCoord y coordinate on the chess-board, coordinate starts from 1
   * @return vertex on the desired coordinates.
   * Note that both dimensions and both coordinates must be positive
   */
  private Object getVertexFromGrid(Object[] vertices, int xDim, int yDim, int xCoord, int yCoord)
  {
    if (xCoord > xDim || yCoord > yDim || xDim < 1 || yDim < 1 || xCoord < 1 || yCoord < 1)
    {
      throw new IllegalArgumentException();
    }

    int value = (yCoord - 1) * xDim + xCoord - 1;

    return vertices[value];
  };

  /**
   * @param xDim
   * @param yDim
   * @param weights
   * Return a king graph of size <b>xDim</b> x <b>yDim</b>
   * Note that the minimum size is 4x4
   */
  public void getKingGraph(mxAnalysisGraph aGraph, int xDim, int yDim)
  {
    if (xDim < 2 || yDim < 2)
    {
      throw new IllegalArgumentException();
    }

    int numVertices = xDim * yDim;
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    //now we set up the starting conditions
    int[] currCoords = new int[2];

    //the main loop
    for (int i = 0; i < (xDim * yDim); i++)
    {
      currCoords = getVertexGridCoords(xDim, yDim, i);
      Object[] neighborMoves = getKingMoveVertexes(aGraph, xDim, yDim, currCoords[0], currCoords[1]);

      for (int j = 0; j < neighborMoves.length; j++)
      {
        // connect current with the possible move that has minimum number of its (possible moves)
        if (!mxGraphStructure.areConnected(aGraph, vertices[i], neighborMoves[j]))
        {
          graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[i], neighborMoves[j]);
        }
        // that vertex becomes the current vertex and we repeat until no possible moves
      }
    }
  };

  /**
   * @param aGraph
   * @param xDim x dimension of the chessboard
   * @param yDim y dimension of the chessboard
   * @param xCoord the current x position of the king
   * @param yCoord the current y position of the king
   * @return list of all possible moves of a king from the specified position
   * Note that both dimensions and both coordinates must be positive
   */
  public Object[] getKingMoveVertexes(mxAnalysisGraph aGraph, int xDim, int yDim, int xCoord, int yCoord)
  {
    if (xDim < 0 || yDim < 0 || xCoord < 0 || yCoord < 0)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object[] vertices = aGraph.getChildVertices(graph.getDefaultParent());

    //check all possible 8 locations

    //location 1
    int currX = xCoord + 1;
    int currY = yCoord - 1;
    ArrayList<Object> possibleMoves = new ArrayList<Object>();
    // check if in bounds
    Object currVertex;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 2
    currX = xCoord + 1;
    currY = yCoord;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 3
    currX = xCoord + 1;
    currY = yCoord + 1;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 4
    currX = xCoord;
    currY = yCoord + 1;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 5
    currX = xCoord - 1;
    currY = yCoord + 1;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 6
    currX = xCoord - 1;
    currY = yCoord;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 7
    currX = xCoord - 1;
    currY = yCoord + 1;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    //location 8
    currX = xCoord;
    currY = yCoord - 1;
    // check if in bounds
    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      currVertex = getVertexFromGrid(vertices, xDim, yDim, currX, currY);
      possibleMoves.add(currVertex);
    }

    return possibleMoves.toArray();
  };

  /**
   * @param aGraph
   * Returns a Petersen graph
   */
  public void getPetersenGraph(mxAnalysisGraph aGraph)
  {
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[10];
   
    for (int i = 0; i < 10; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[0], vertices[2]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[0], vertices[8]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[0], vertices[9]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[1], vertices[2]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[1], vertices[5]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[1], vertices[7]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[2], vertices[4]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[3], vertices[4]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[3], vertices[7]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[3], vertices[9]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[4], vertices[6]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[5], vertices[6]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[5], vertices[9]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[6], vertices[8]);
    graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[7], vertices[8]);
  };

  /**
   * @param aGraph
   * @param numVertices
   * Returns a path graph
   */
  public void getPathGraph(mxAnalysisGraph aGraph, int numVertices)
  {
    if (numVertices < 0)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    for (int i = 0; i < numVertices - 1; i++)
    {
      graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[i], vertices[i + 1]);
    }
  };

  /**
   * Sets the physical spacing between vertices in a path graph. This works for now only for a graph generated with mxGraphCreator.getPathGraph()
   * only after creating the graph
   * @param aGraph
   * @param spacing
   */
  public void setPathGraphSpacing(mxAnalysisGraph aGraph, double spacing)
  {
    if (spacing < 0)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = aGraph.getChildVertices(parent);
    mxIGraphModel model = graph.getModel();

    for (int i = 0; i < vertices.length; i++)
    {
      Object currVertex = vertices[i];

      mxGeometry geometry = model.getGeometry(currVertex);
      geometry.setX(0);
      geometry.setY(i * spacing);
    }
  };

  /**
   * @param aGraph
   * @param numVertices
   * Returns a star graph
   * Note that minimum vertex number is 4
   */
  public void getStarGraph(mxAnalysisGraph aGraph, int numVertices)
  {
    if (numVertices < 4)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    int numVertexesInPerimeter = numVertices - 1;

    for (int i = 0; i < numVertexesInPerimeter; i++)
    {
      graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[numVertexesInPerimeter], vertices[i]);
    }
  };

  /**
   * Sets the physical size of a star graph. This works for now only for a graph generated with mxGraphCreator.getStarGraph() and getWheelGraph()
   * @param aGraph
   * @param graphSize
   */
  public void setStarGraphLayout(mxAnalysisGraph aGraph, double graphSize)
  {
    if (graphSize < 4)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = aGraph.getChildVertices(parent);
    mxIGraphModel model = graph.getModel();
    int vertexNum = vertices.length;
    double centerX = graphSize / 2f;
    double centerY = centerX;

    int numVertexesInPerimeter = vertexNum - 1;

    //create the circle
    for (int i = 0; i < numVertexesInPerimeter; i++)
    {
      //calc the position
      double x = 0;
      double y = 0;
      double currRatio = ((double) i / (double) numVertexesInPerimeter);
      currRatio = currRatio * 2;
      currRatio = currRatio * (double) Math.PI;
      x = Math.round(centerX + Math.round(graphSize * Math.sin(currRatio) / 2));
      y = Math.round(centerY - Math.round(graphSize * Math.cos(currRatio) / 2));
      Object currVertex = vertices[i];
      mxGeometry geometry = model.getGeometry(currVertex);
      geometry.setX(x);
      geometry.setY(y);
    }

    mxGeometry geometry = model.getGeometry(vertices[vertexNum - 1]);
    geometry.setX(centerX);
    geometry.setY(centerY);
  };

  /**
   * @param aGraph
   * @param numVertices
   * Returns a wheel graph. Note that numVertices has to be at least 4.
   */
  public void getWheelGraph(mxAnalysisGraph aGraph, int numVertices)
  {
    if (numVertices < 4)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numVertices];
   
    for (int i = 0; i < numVertices; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    int numVerticesInPerimeter = numVertices - 1;

    for (int i = 0; i < numVerticesInPerimeter; i++)
    {
      graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[numVerticesInPerimeter], vertices[i]);

      if (i < numVerticesInPerimeter - 1)
      {
        graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[i], vertices[i + 1]);
      }
      else
      {
        graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertices[i], vertices[0]);
      }
    }
  };

  /**
   * @param aGraph
   * @param numBranches number of branches (minimum >= 2)
   * @param branchSize number of vertices in a single branch (minimum >= 2)
   * Returns a friendship windmill graph (aka Dutch windmill)
   */
  public void getFriendshipWindmillGraph(mxAnalysisGraph aGraph, int numBranches, int branchSize)
  {
    if (numBranches < 2 || branchSize < 2)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    int numVertices = numBranches * branchSize + 1;
    Object[] vertices = new Object[numVertices];
    int vertexCount = 0;

    for (int i = 0; i < numBranches; i++)
    {
      for (int j = 0; j < branchSize; j++)
      {
        vertices[vertexCount] = graph.insertVertex(parent, null, new Integer(vertexCount).toString(), 0, 0, 25, 25);
        vertexCount++;
      }
    }

    vertices[numVertices - 1] = graph.insertVertex(parent, null, new Integer(numVertices - 1).toString(), 0, 0, 25, 25);

    //make the connections
    for (int i = 0; i < numBranches; i++)
    {
      Object oldVertex = vertices[numVertices - 1];

      for (int j = 0; j < branchSize; j++)
      {
        Object currVertex = vertices[i * (branchSize) + j];
        graph.insertEdge(parent, null, getNewEdgeValue(aGraph), oldVertex, currVertex);
        oldVertex = currVertex;
      }

      Object currVertex = vertices[numVertices - 1];
      graph.insertEdge(parent, null, getNewEdgeValue(aGraph), oldVertex, currVertex);
    }
  };

  /**
   * @param aGraph
   * @param numBranches - number of branches (minimum >= 2)
   * @param branchSize - number of vertices in a single branch (minimum >= 2)
   * Returns a windmill graph
   */
  public void getWindmillGraph(mxAnalysisGraph aGraph, int numBranches, int branchSize)
  {
    if (numBranches < 2 || branchSize < 2)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    int numVertices = numBranches * branchSize + 1;
    Object[] vertices = new Object[numVertices];
   
    int vertexCount = 0;

    for (int i = 0; i < numBranches; i++)
    {
      for (int j = 0; j < branchSize; j++)
      {
        vertices[vertexCount] = graph.insertVertex(parent, null, new Integer(vertexCount).toString(), 0, 0, 25, 25);
        vertexCount++;
      }
    }

    vertices[numVertices - 1] = graph.insertVertex(parent, null, new Integer(numVertices - 1).toString(), 0, 0, 25, 25);
    Object centerVertex = vertices[numVertices - 1];

    //make the connections
    for (int i = 0; i < numBranches; i++)
    {
      for (int j = 0; j < branchSize; j++)
      {
        Object vertex1 = vertices[i * (branchSize) + j];
        if (!mxGraphStructure.areConnected(aGraph, centerVertex, vertex1))
        {
          graph.insertEdge(parent, null, getNewEdgeValue(aGraph), centerVertex, vertex1);
        }

        for (int k = 0; k < branchSize; k++)
        {
          Object vertex2 = vertices[i * (branchSize) + k];

          if (j != k && !mxGraphStructure.areConnected(aGraph, vertex1, vertex2))
          {
            graph.insertEdge(parent, null, getNewEdgeValue(aGraph), vertex1, vertex2);
          }
        }
      }
    }
  };

  //NOTE the inside code is delicate, so please change it only if you know what you're doing
  /**
   * Sets the layout of a windmill graph. Use this method only for graphs generated with mxGraphGenerator.getWindmillGraph() and getFriendshitWindmillGraph()
   * @param aGraph
   * @param numBranches
   * @param numVerticesInBranch
   * @param graphSize
   */
  public void setWindmillGraphLayout(mxAnalysisGraph aGraph, int numBranches, int numVerticesInBranch, double graphSize)
  {
    if (graphSize < 0 || numBranches < 2 || numVerticesInBranch < 1)
    {
      throw new IllegalArgumentException();
    }

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = aGraph.getChildVertices(parent);
    mxIGraphModel model = graph.getModel();
    int vertexNum = vertices.length;
    double centerX = graphSize / 2f;
    double centerY = centerX;
    boolean isBranchSizeEven = ((numVerticesInBranch) % 2 == 0);
    int middleIndex = (int) Math.ceil(numVerticesInBranch / 2f);

    //create the circle
    for (int i = 0; i < numBranches; i++)
    {
      for (int j = 0; j < numVerticesInBranch; j++)
      {
        double currSize = this.getRingSize(j + 1, numVerticesInBranch, graphSize);

        //calc the position
        double x = 0;
        double y = 0;
        int numVertexesInPerimeter = 0;
        double currRatio = 0;
        numVertexesInPerimeter = numBranches;

        // need to detect the 2 middle vertices for even sized branches
        if (isBranchSizeEven && j == middleIndex - 1)
        {
          //full size
          currRatio = ((double) i - (0.0005f * graphSize / Math.pow(numVerticesInBranch, 1))) / (double) numVertexesInPerimeter;
        }
        else if (isBranchSizeEven && j == middleIndex)
        {
          currRatio = ((double) i + (0.0005f * graphSize / Math.pow(numVerticesInBranch, 1))) / (double) numVertexesInPerimeter;
        }
        else if (!isBranchSizeEven && currSize == graphSize)
        {
          currRatio = ((double) i / (double) numVertexesInPerimeter);
        }
        else
        {
          if (j + 1 < middleIndex)
          {
            //before middle
            currRatio = ((double) (i - 1f / Math.pow(currSize, 0.25) + 0.00000000000015f * Math.pow(currSize, 4)) / (double) numVertexesInPerimeter);
          }
          else
          {
            //after middle
            currRatio = ((double) (i + 1f / Math.pow(currSize, 0.25) - 0.00000000000015f * Math.pow(currSize, 4)) / (double) numVertexesInPerimeter);
          }
        }

        currRatio = currRatio * 2;
        currRatio = currRatio * (double) Math.PI;
        x = Math.round(centerX + Math.round(currSize * Math.sin(currRatio) / 2));
        y = Math.round(centerY - Math.round(currSize * Math.cos(currRatio) / 2));
        //shoot
        int currIndex = i * (numVerticesInBranch) + j;
        Object currVertex = vertices[currIndex];
        mxGeometry geometry = model.getGeometry(currVertex);
        geometry.setX(x);
        geometry.setY(y);
      }
    }

    //the center vertex is the last one
    Object currVertex = vertices[vertexNum - 1];
    mxGeometry geometry = model.getGeometry(currVertex);
    geometry.setX(centerX);
    geometry.setY(centerY);
  };

  /**
   * A helper function that calculates the ring size for a windmill graph, based on the index of a vertex in a brach and branch size. - for internal use
   * @param currVertex - starting from 1
   * @param branchSize - starting from 1
   * @param fullSize
   * @return ring size
   */
  private double getRingSize(int currIndex, int branchSize, double fullSize)
  {
    if (currIndex < 1 || currIndex > branchSize || branchSize < 1 || fullSize < 0)
    {
      throw new IllegalArgumentException();
    }

    int middleIndex = 0;
    boolean isBranchSizeEven = ((branchSize) % 2 == 0);

    middleIndex = (int) Math.ceil(branchSize / 2f);

    if (currIndex == middleIndex || (isBranchSizeEven && currIndex == middleIndex + 1))
    {
      //full size
      return fullSize;
    }
    else if (currIndex >= middleIndex)
    {
      //after middle
      currIndex = branchSize - currIndex + 1;
    }
    return (((float) Math.pow(currIndex, 0.75) / (float) Math.pow(middleIndex, 0.75)) * fullSize);
  };

  /**
   * Generates a random graph
   * @param aGraph
   * @param numNodes number of vertexes
   * @param numEdges number of edges (may be inaccurate if <b>forceConnected</b> is set to true
   * @param allowSelfLoops if true, there will be a chance that self loops will be generated too
   * @param allowMultipleEdges if true, there will be a chance that multiple edges will be generated (multiple edges between the same two vertices)
   * @param forceConnected if true the resulting graph will be always connected, but this may alter <b>numEdges</b>
   */
  public void getSimpleRandomGraph(mxAnalysisGraph aGraph, int numNodes, int numEdges, boolean allowSelfLoops,
      boolean allowMultipleEdges, boolean forceConnected)
  {
    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    Object[] vertices = new Object[numNodes];
   
    for (int i = 0; i < numNodes; i++)
    {
      vertices[i] = graph.insertVertex(parent, null, new Integer(i).toString(), 0, 0, 25, 25);
    }

    for (int i = 0; i < numEdges; i++)
    {
      boolean goodPair = true;
      Object startVertex;
      Object endVertex;

      do
      {
        goodPair = true;
        startVertex = vertices[(int) Math.round(Math.random() * (vertices.length - 1))];
        endVertex = vertices[(int) Math.round(Math.random() * (vertices.length - 1))];

        if (!allowSelfLoops && startVertex.equals(endVertex))
        {
          goodPair = false;
        }
        else if (!allowMultipleEdges && mxGraphStructure.areConnected(aGraph, startVertex, endVertex))
        {
          goodPair = false;
        }
      }
      while (!goodPair);

      graph.insertEdge(parent, null, getNewEdgeValue(aGraph), startVertex, endVertex);
    }

    if (forceConnected)
    {
      mxGraphStructure.makeConnected(aGraph);
    }
  };

  /**
   * Generates a random tree graph
   * @param aGraph
   * @param vertexCount
   */
  public void getSimpleRandomTree(mxAnalysisGraph aGraph, int vertexCount)
  {
    int edgeCount = (int) Math.round(vertexCount * 2);
    this.getSimpleRandomGraph(aGraph, vertexCount, edgeCount, false, false, true);

    //still need to remove surplus edges
    Object[] vertices = aGraph.getChildVertices(aGraph.getGraph().getDefaultParent());

    try
    {
      oneSpanningTree(aGraph, true, true);
    }
    catch (StructuralException e)
    {
      System.out.println(e);
    }

    try
    {
      mxGraphStructure.makeTreeDirected(aGraph, vertices[(int) Math.round(Math.random() * (vertices.length - 1))]);
    }
    catch (StructuralException e)
    {
      System.out.println(e);
    }
  };

  /**
   * Creates a new edge value based on graph properties in mxAnalysisGraph. Used mostly when creating new edges during graph generation.
   * @param aGraph
   * @return
   */
  public Double getNewEdgeValue(mxAnalysisGraph aGraph)
  {
    if (getGeneratorFunction() != null)
    {
      mxGraph graph = aGraph.getGraph();
      return getGeneratorFunction().getCost(graph.getView().getState(graph.getDefaultParent()));
    }
    else
    {
      return null;
    }
  };

  /**
   * @param graph
   * @param weighted if true, the edges will be weighted, otherwise all will have default value (1.0)
   * @param minWeight minimum edge weight if weighted
   * @param maxWeight maximum edge weight if weighted
   * @return a generator function
   */
  public static mxGeneratorFunction getGeneratorFunction(mxGraph graph, boolean weighted, double minWeight, double maxWeight)
  {
    if (weighted)
    {
      return new mxGeneratorRandomFunction(minWeight, maxWeight, 2);
    }
    else
    {
      return null;
    }
  };

  public mxGeneratorFunction getGeneratorFunction()
  {
    return this.generatorFunction;
  };

  /**
   * @param minValue
   * @param maxValue
   * @return a random integer in the interval [minValue, maxValue]
   */
  public int getRandomInt(int minValue, int maxValue)
  {
    if (minValue == maxValue)
      return minValue;
    if (minValue > maxValue)
    {
      int tmp = maxValue;
      maxValue = minValue;
      minValue = tmp;
    }

    int currValue = 0;
    currValue = minValue + (int) Math.round((Math.random() * (maxValue - minValue)));
    return currValue;
  };

  /**
   * @param graph
   * @param forceConnected if true, an unconnected graph is made connected
   * @param forceSimple if true, a non-simple graph is made simple
   * Calculates one spanning tree of graph, which doesn't have to be but can be minimal
   * (this is faster than minimal spanning tree, so if you need any spanning tree, use this one)
   * Self loops and multiple edges are automatically removed!
   * Also, unconnected graphs are made connected!
   * @throws StructuralException the graph has to be simple (no self-loops and no multiple edges)
   */
  public void oneSpanningTree(mxAnalysisGraph aGraph, boolean forceConnected, boolean forceSimple) throws StructuralException
  {
    mxGraph graph = aGraph.getGraph();

    boolean isSimple = mxGraphStructure.isSimple(aGraph);
    boolean isConnected = mxGraphStructure.isConnected(aGraph);

    if (!isSimple)
    {
      if (forceSimple)
      {
        mxGraphStructure.makeSimple(aGraph);
      }
      else
      {
        throw new StructuralException("Graph is not simple.");
      }
    }

    if (!isConnected)
    {
      if (forceConnected)
      {
        mxGraphStructure.makeConnected(aGraph);
      }
      else
      {
        throw new StructuralException("Graph is not connected.");
      }
    }

    Object[] edges = aGraph.getChildEdges(graph.getDefaultParent());
    int edgeCount = edges.length;

    for (int i = 0; i < edgeCount; i++)
    {
      Object currEdge = edges[i];
      graph.removeCells(new Object[] { currEdge });

      if (!mxGraphStructure.isConnected(aGraph))
      {
        graph.addCell(currEdge);
      }
    }
  };

  //TODO make a double check to avoid unnecessary cases of throwing an exception (if the algorithm can't work out a solution, try a mirrored strategy)
  /**
   * @param aGraph
   * @param xDim x dimension of the chessboard
   * @param yDim y dimension of the chessboard
   * @param startVertexValue vertex where the tour will start
   * @throws StructuralException not all size combinations are allowed, see wikipedia for a more detailed explanation
   * Returns a Knight's Tour graph
   */
  public void getKnightTour(mxAnalysisGraph aGraph, int xDim, int yDim, int startVertexValue) throws StructuralException
  {
    if (xDim < 5 || yDim < 5)
    {
      throw new IllegalArgumentException();
    }

    ArrayList<Object> resultPath = new ArrayList<Object>();
    int vertexNum = xDim * yDim;

    mxGraph graph = aGraph.getGraph();
    Object parent = graph.getDefaultParent();
    int vertexCount = 0;

    for (int i = 0; i < vertexNum; i++)
    {
      graph.insertVertex(parent, null, new Integer(vertexCount).toString(), 0, 0, 25, 25);
      vertexCount++;
    }

    // we have the board set up
    Object[] vertices = aGraph.getChildVertices(parent);

    //now we set up the starting conditions
    int currValue = startVertexValue;
    int[] currCoords = new int[2];
    Object oldMove = vertices[startVertexValue];
    currCoords = getVertexGridCoords(xDim, yDim, startVertexValue);
    resultPath.add(oldMove);
    Object nextMove = getNextKnightMove(aGraph, xDim, yDim, currCoords[0], currCoords[1], resultPath);
    mxCostFunction costFunction = aGraph.getGenerator().getCostFunction();
    mxGraphView view = graph.getView();
   
    //the main loop
    while (nextMove != null)
    {
      // connect current with the possible move that has minimum number of its (possible moves)
      graph.insertEdge(parent, null, null, oldMove, nextMove);
      resultPath.add(nextMove);
      // that vertex becomes the current vertex and we repeat until no possible moves
     
      currValue = (int) costFunction.getCost(new mxCellState(view, nextMove, null));
      currCoords = getVertexGridCoords(xDim, yDim, currValue);
      oldMove = nextMove;
      nextMove = getNextKnightMove(aGraph, xDim, yDim, currCoords[0], currCoords[1], resultPath);
    }

    if (resultPath.size() < vertexNum)
    {
      //the mirrored strategy should go here, instead of the exception
      //and the exception would be thrown only if the mirrored fails too
      throw new StructuralException("Could not generate a correct Knight tour with size " + xDim + " x " + yDim + ".");
    }
  };

  /**
   * Helper function for Knights Tour - for internal use
   * @param aGraph
   * @param xDim
   * @param yDim
   * @param xCoord
   * @param yCoord
   * @param resultPath
   * @return
   */
  private Object getNextKnightMove(mxAnalysisGraph aGraph, int xDim, int yDim, int xCoord, int yCoord, ArrayList<Object> resultPath)
  {
    Object[] possibleMoves = getKnightMoveVertexes(aGraph, xDim, yDim, xCoord, yCoord);
    //get the position with minimum possible moves
    int minMoveNum = 9;
    float biggestDistance = 0;
    Object currVertex = null;
    mxCostFunction costFunction = aGraph.getGenerator().getCostFunction();
    mxGraphView view = aGraph.getGraph().getView();
   
    for (int i = 0; i < possibleMoves.length; i++)
    {
      int currValue = (int) costFunction.getCost(new mxCellState(view, possibleMoves[i], null));
      int[] currCoords = getVertexGridCoords(xDim, yDim, currValue);
      int currMoveNum = getPossibleKnightMoveCount(aGraph, xDim, yDim, currCoords[0], currCoords[1]);
      float currDistance = getDistanceFromGridCenter(xDim, yDim, currValue);

      if ((currMoveNum < minMoveNum || (currMoveNum == minMoveNum && currDistance > biggestDistance))
          && !resultPath.contains(possibleMoves[i]))
      {
        biggestDistance = currDistance;
        minMoveNum = currMoveNum;
        currVertex = possibleMoves[i];
      }
    }
    return currVertex;
  };

  /**
   * Helper function for Knights Tour - for internal use
   * @param aGraph
   * @param xDim
   * @param yDim
   * @param xCoord
   * @param yCoord
   * @return
   */
  private int getPossibleKnightMoveCount(mxAnalysisGraph aGraph, int xDim, int yDim, int xCoord, int yCoord)
  {
    //check all possible 8 locations

    //location 1
    int currX = xCoord + 1;
    int currY = yCoord - 2;
    int possibleMoveCount = 0;
    Object parent = aGraph.getGraph().getDefaultParent();
    Object[] vertices = aGraph.getChildVertices(parent);

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 2
    currX = xCoord + 2;
    currY = yCoord - 1;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 3
    currX = xCoord + 2;
    currY = yCoord + 1;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 4
    currX = xCoord + 1;
    currY = yCoord + 2;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 5
    currX = xCoord - 1;
    currY = yCoord + 2;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 6
    currX = xCoord - 2;
    currY = yCoord + 1;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 7
    currX = xCoord - 2;
    currY = yCoord - 1;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    //location 8
    currX = xCoord - 1;
    currY = yCoord - 2;

    if (currX > 0 && currX <= xDim && currY > 0 && currY <= yDim)
    {
      if (aGraph.getEdges(getVertexFromGrid(vertices, xDim, yDim, currX, currY), parent, false, true).length == 0)
      {
        possibleMoveCount++;
      }
    }

    return possibleMoveCount;
  };

  /**
   * Helper function for Knights Tour - for internal use
   * @param xDim
   * @param yDim
   * @param currValue
   * @return
   */
  private float getDistanceFromGridCenter(int xDim, int yDim, int currValue)
  {
    float centerX = (xDim + 1) / 2f;
    float centerY = (yDim + 1) / 2f;
    int[] currCoords = getVertexGridCoords(xDim, yDim, currValue);
    float x = Math.abs(centerX - currCoords[0]);
    float y = Math.abs(centerY - currCoords[1]);

    return (float) Math.sqrt(x * x + y * y);
  }

  public mxCostFunction getCostFunction()
  {
    return costFunction;
  }

  public void setCostFunction(mxCostFunction costFunction)
  {
    this.costFunction = costFunction;
  };
};
TOP

Related Classes of com.mxgraph.analysis.mxGraphGenerator

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.