/* Research Project: Graphical Database for Category Theory J. Bradbury, Dr. R. Rosebrugh, I. Rutherford Mount Allison University 2001 File: Spring.java (author: Shawn Lorae Stutzman, Auburn University, 12/12/96) Description: Class to implement Kamada and Kawai's spring algorithm with modifications). */ //import statements import java.lang.*; public class Spring { private static DRect rect; private static double xmax,xmin,ymax,ymin; private static int orderedList[]; // this is used to enable a quick lookup // of nodes' array values (which might // differ from their index values) private static int N; // nodes in graph; will be set in compute function private static int EDGES; // edges in graph; set in compute function private static long D[][]; //the graphical distances between all pairs private static double K[][]; // spring strengths private static double Ko; // spring constant private static double L[][]; // ideal spring lengths private static double epsilon; private static double delta[]; private static int MAX_TIMES_REPOSITIONED = 10;// constant to limit number // of times thru "inner" loop private static int numTimesRepositioned = 0; // counts number of times // thru "inner" loop private static int NUM_TIMES_MOVED[]; // counts number of times each // vertex has been selected to // move private static int HY_SIZE = 10; // these variables control the E private static int HY_PERCENTAGE = 5;// stopping condition and how it private static double E,E_HY[]; // keeps track of its information private static int COUNTER = 0; private static Node mv = null; // the node chosen to move at each iteration private static double partial_x,partial_y,partial_xx, partial_xy,partial_yx,partial_yy; private static boolean connected; public String compute(Graph G, GraphUpdate update) { double tempValue,maxValue,maxDel; int maxTimes = 0; int mvi,i; Node v,u; rect = update.windowRect(); Initialize(G); // if graph not entirely contained in drawing area, change drawing area? // change graph?? (want to make sure that graph is inside the drawing // area before starting....) For now (with the "non-bouncing // moving-function" used), this doesn't need to be enforced) // Also check to make sure that graph is connected, or else we need to // exit here for(i=0;i maxDel) maxDel = delta[enum(G.getIndexFromNode(v))]; if (NUM_TIMES_MOVED[enum(G.getIndexFromNode(v))] > maxTimes) maxTimes = NUM_TIMES_MOVED[enum(G.getIndexFromNode(v))]; } mv = G.firstNode(); mvi = enum(G.getIndexFromNode(mv)); maxValue = 0; for (v = mv; v !=null; v = G.nextNode(v)) { if (maxTimes != 0) tempValue = TempFunction (delta[enum(G.getIndexFromNode(v))]/maxDel, 1 - NUM_TIMES_MOVED[enum(G.getIndexFromNode(v))]/maxTimes); else // the first time, base the decision only upon the delta tempValue = delta[enum(G.getIndexFromNode(v))]/maxDel; if (tempValue > maxValue) { mv = v; mvi = enum(G.getIndexFromNode(mv)); maxValue = tempValue; } } // see if any stopping conditions are met if (delta[mvi] < epsilon) { //System.out.println("Quitting because of epsilon"); break; } if (COUNTER > HY_SIZE) if (E_HY[COUNTER%HY_SIZE] * HY_PERCENTAGE/100.0 > (E = findE(G))) { //System.out.println("Quitting because of history"); break; } // can't quit yet, so put the E in the history array and get ready to // find a new position for vertex 'mv' E_HY[COUNTER%HY_SIZE] = E; numTimesRepositioned = 0; while ( (delta[mvi] > epsilon) && (numTimesRepositioned < MAX_TIMES_REPOSITIONED) ) { //MoveToNewPosition(G); // this function simulates elastic collision // instead of hitting & sticking //MoveToNewPosition1(G); // this function "hits and sticks" MoveToNewPosition2(G); // this function doesn't care delta[mvi] = Math.sqrt(findDelta2(G,mv)); numTimesRepositioned++; }//end "inner" while NUM_TIMES_MOVED[mvi]++; //if redraw is on ??? update.update(false); // if the cool stop button (that isn't implemented) has been pressed // redraw // break; }//end "outer" while return null; }//end main compute function private static void Initialize(Graph G) { Node v,u; int i; N = G.numberOfNodes(); makeOrderedList(G); NUM_TIMES_MOVED = new int[N]; for (i=0;i xmax) xfrac = (xmax - xpos)/dx; else xfrac = 1; if (ypos + dy < ymin) yfrac = (ypos - ymin)/dy; else if (ypos + dy > ymax) yfrac = (ymax - ypos)/dy; else yfrac = 1; double x = xpos+dx; double y = ypos+dy; if (xfrac < yfrac) { xpos += dx * xfrac; dx *= (xfrac - 1); ypos += dy * xfrac; dy *= (1 - xfrac); } else if (yfrac < xfrac) { ypos += dy * yfrac; dy *= (yfrac - 1); xpos += dx * yfrac; dx *= (1 - yfrac); } else { xpos += dx; dx = 0; ypos += dy; dy = 0; } }//end while mv.setPosition(xpos,ypos); } private static void MoveToNewPosition1(Graph G) { double A,B,C,D,E,F,dx,dy; double xpos,ypos,xfrac,yfrac; xpos = mv.getPosition().x; ypos = mv.getPosition().y; int mvi = enum(G.getIndexFromNode(mv)); findPartials(G,mv); A = partial_xx; B = partial_xy; C = -(partial_x); D = partial_yx; E = partial_yy; F = -(partial_y); dy = (A*F-C*D)/(A*E-B*D); dx = (C*E-B*F)/(A*E-B*D); if (xpos + dx < xmin) xfrac = (xpos - xmin)/dx; else if (xpos + dx > xmax) xfrac = (xmax - xpos)/dx; else xfrac = 1; if (ypos + dy < ymin) yfrac = (ypos - ymin)/dy; else if (ypos + dy > ymax) yfrac = (ymax - ypos)/dy; else yfrac = 1; if (xfrac < yfrac) { yfrac = xfrac; } else if (yfrac < xfrac) { xfrac = yfrac; } double x = xpos+dx; double y = ypos+dy; xpos += dx*xfrac; dx = 0; ypos += dy*yfrac; dy = 0; mv.setPosition(xpos,ypos); } private static void MoveToNewPosition2(Graph G) { double A,B,C,D,E,F,dx,dy; double xpos,ypos,xfrac,yfrac; xpos = mv.getPosition().x; ypos = mv.getPosition().y; int mvi = enum(G.getIndexFromNode(mv)); findPartials(G,mv); A = partial_xx; B = partial_xy; C = -(partial_x); D = partial_yx; E = partial_yy; F = -(partial_y); dy = (A*F-C*D)/(A*E-B*D); dx = (C*E-B*F)/(A*E-B*D); mv.setPosition(xpos+dx,ypos+dy); } private static void CheckPositions(Graph G) { Node v,u; int vi,ui; double rand; boolean OK = false; while(!OK) { OK = true; for (v = G.firstNode(); v != null; v = G.nextNode(v)) for (u = G.nextNode(v); u != null; u = G.nextNode(u)) if ((v.getPosition().x == u.getPosition().x) && (v.getPosition().y == u.getPosition().y)) { vi = enum(G.getIndexFromNode(v)); ui = enum(G.getIndexFromNode(u)); rand = (1.4*Math.random() - 1) * L[vi][ui]; u.setPosition(u.getPosition().x + rand , u.getPosition().y); rand = (1.4*Math.random() - 1) * L[vi][ui]; u.setPosition(u.getPosition().x , u.getPosition().y + rand); OK = false; } } } }//end class KK