www.pudn.com > 19832002.rar > GraphAlgorithm.java
import java.awt.*;
/**
* GraphAlgorithm.java
* Dijkstra×î¶Ì·¾¶Ëã·¨ÑÝʾ
* @author: Carla Laffra
* @date: March, 1996
*
* Applet for explaining graph algorithms.
* It currently only explains Dijkstra's shortest path algorithm,
* but it can easily be extended to handle more algorithms.
*
* Copyright 1996, Carla Laffra, all rights reserved
*/
public class GraphAlgorithm extends java.applet.Applet {
GraphCanvas graphcanvas = new GraphCanvas(this);
Options options = new Options(this);
Documentation documentation = new Documentation();
public void init() {
setLayout(new BorderLayout(10, 10));
add("Center", graphcanvas);
add("North", documentation);
add("East", options);
}
public Insets insets() {
return new Insets(10, 10, 10, 10);
}
public void lock() {
graphcanvas.lock();
options.lock();
}
public void unlock() {
graphcanvas.unlock();
options.unlock();
}
}
class Options extends Panel {
// set of options at the right of the screen
Button b1 = new Button("clear");
Button b2 = new Button("run");
Button b3 = new Button("step");
Button b4 = new Button("reset");
Button b5 = new Button("example");
Button b6 = new Button("exit");
GraphAlgorithm parent;
boolean Locked=false;
Options(GraphAlgorithm myparent) {
parent = myparent;
setLayout(new GridLayout(6, 1, 0, 10));
add(b1);
add(b2);
add(b3);
add(b4);
add(b5);
add(b6);
}
public boolean action(Event evt, Object arg) {
if (evt.target instanceof Button) {
if (((String)arg).equals("step")) {
if (!Locked) {
b3.setLabel("next step");
parent.graphcanvas.stepalg();
}
else parent.documentation.doctext.showline("locked");
}
if (((String)arg).equals("next step"))
parent.graphcanvas.nextstep();
if (((String)arg).equals("reset")) {
parent.graphcanvas.reset();
b3.setLabel("step");
parent.documentation.doctext.showline("all items");
}
if (((String)arg).equals("clear")) {
parent.graphcanvas.clear();
b3.setLabel("step");
parent.documentation.doctext.showline("all items");
}
if (((String)arg).equals("run")) {
if (!Locked)
parent.graphcanvas.runalg();
else parent.documentation.doctext.showline("locked");
}
if (((String)arg).equals("example")) {
if (!Locked)
parent.graphcanvas.showexample();
else parent.documentation.doctext.showline("locked");
}
if (((String)arg).equals("exit")) {
System.exit(0);
}
}
return true;
}
public void lock() {
Locked=true;
}
public void unlock() {
Locked=false;
b3.setLabel("step");
}
}
class Documentation extends Panel {
// Documentation on top of the screen
DocOptions docopt = new DocOptions(this);
DocText doctext = new DocText();
Documentation() {
setLayout(new BorderLayout(10, 10));
add("West", docopt);
add("Center", doctext);
}
}
class DocOptions extends Panel {
Choice doc = new Choice();
Documentation parent;
DocOptions(Documentation myparent) {
setLayout(new GridLayout(2, 1, 5, 0));
parent = myparent;
add(new Label("DOCUMENTATION:"));
doc.addItem("draw nodes");
doc.addItem("remove nodes");
doc.addItem("move nodes");
doc.addItem("the startnode");
doc.addItem("draw arrows");
doc.addItem("change weights");
doc.addItem("remove arrows");
doc.addItem("clear / reset");
doc.addItem("run algorithm");
doc.addItem("step through");
doc.addItem("example");
doc.addItem("exit");
doc.addItem("all items");
add(doc);
}
public boolean action(Event evt, Object arg) {
if (evt.target instanceof Choice) {
String str=new String(doc.getSelectedItem());
parent.doctext.showline(str);
}
return true;
}
}
class DocText extends TextArea {
final String drawnodes = new String("DRAWING NODES:\n"+
"Draw a node by clicking the mouse.\n\n");
final String rmvnodes = new String("REMOVE NODES:\n"+
"To remove a node press and click on the node.\n"+
"You can not remove the startnode.\n"+
"Select another startnode, then you can remove the node.\n\n");
final String mvnodes = new String("MOVING NODES\n"+
"To move a node press , click on the node,\nand drag it to"+
" its new position.\n\n");
final String startnode = new String("STARTNODE:\n"+
"The startnode is blue, other nodes are grey.\n"+
"The first node you draw on the screen will be the startnode.\n"+
"To select another startnode press , click on the startnode,\n"+
"and drag the mouse to another node.\n"+
"To delete the startnode, first select another startnode, and then"+
"\nremove the node the usual way.\n\n");
final String drawarrows = new String("DRAWING ARROWS:\n"+
"To draw an arrow click mouse in a node,"+
"and drag it to another node.\n\n");
final String weight = new String("CHANGING WEIGHTS:\n"+
"To change the weight of an arrow, click on the arrowhead and drag\n"+
"it along the arrow.\n\n");
final String rmvarrows = new String("REMOVE ARROWS:\n"+
"To remove an arrow, change its weight to 0.\n\n");
final String clrreset = new String(" BUTTON: "+
"Remove the current graph from the screen.\n"+
" BUTTON: "+
"Remove the results of the algorithm from the graph,\n"+
" and unlock screen.\n\n");
final String runalg = new String(" BUTTON: "+
"Run the algorithm on the graph, there will be a time\n" +
"delay of +/- 1 second between steps.\n"+
"To run the algorithm slower, use .\n");
final String step = new String(" BUTTON: " +
"An opportunity to step through the algorithm.\n");
final String example = new String(" BUTTON: "+
"Displays a graph on the screen for you.\n"+
"You can then use or \n");
final String exitbutton = new String(" BUTTON: " +
"Only works if applet is run with appletviewer.\n");
final String toclose = new String("ERROR: "+
"This position is to close to another node/arrow.\n");
final String done = new String("Algorithm has finished, " +
"follow orange arrows from startnode to any node "+
"to get\nthe shortest path to " +
"the node. The length of the path is written in the node.\n" +
"press to reset the graph, and unlock the screen.");
final String some = new String("Algorithm has finished, " +
"follow orange arrows from startnode to any node "+
"to get\nthe shortest path to " +
"the node. The length of the path is written in the node.\n" +
"There are no paths from the startnode to any gray node.\n" +
"press to reset the graph, and unlock the screen.");
final String none = new String("Algorithm has finished, " +
"there are no nodes reachable from the start node.\n"+
"press to reset the graph, and unlock the screen.");
final String maxnodes = new String("ERROR: "+
"Maximum number of nodes reached!\n\n");
final String info = new String("DOCUMENTATION:\n"+
"You can scroll through the documentation or get documentation\n"+
"on a specific "+
"item by selecting the item on the left.\nSelecting "+
"brings you back "+
" to the scrolling text.\n\n");
final String locked = new String("ERROR: "+
"Keyboard/mouse locked for this action.\n"+
"Either press or .\n");
final String doc = info + drawnodes + rmvnodes + mvnodes +
startnode + drawarrows + weight + rmvarrows +
clrreset + runalg + step + example + exitbutton;
DocText() {
super(5, 2);
setText(doc);
}
public void showline(String str) {
if (str.equals("draw nodes")) setText(drawnodes);
else if (str.equals("remove nodes")) setText(rmvnodes);
else if (str.equals("move nodes")) setText(mvnodes);
else if (str.equals("the startnode")) setText(startnode);
else if (str.equals("draw arrows")) setText(drawarrows);
else if (str.equals("change weights")) setText(weight);
else if (str.equals("remove arrows")) setText(rmvarrows);
else if (str.equals("clear / reset")) setText(clrreset);
else if (str.equals("run algorithm")) setText(runalg);
else if (str.equals("step through")) setText(step);
else if (str.equals("example")) setText(example);
else if (str.equals("exit")) setText(exitbutton);
else if (str.equals("all items")) setText(doc);
else if (str.equals("toclose")) setText(toclose);
else if (str.equals("done")) setText(done);
else if (str.equals("locked")) setText(locked);
else if (str.equals("maxnodes")) setText(maxnodes);
else if (str.equals("none")) setText(none);
else if (str.equals("some")) setText(some);
else setText(str);
}
}
class GraphCanvas extends Canvas implements Runnable {
// drawing area for the graph
final int MAXNODES = 20;
final int MAX = MAXNODES+1;
final int NODESIZE = 26;
final int NODERADIX = 13;
final int DIJKSTRA = 1;
// basic graph information
Point node[] = new Point[MAX]; // node
int weight[][] = new int[MAX][MAX]; // weight of arrow
Point arrow[][] = new Point[MAX][MAX]; // current position of arrowhead
Point startp[][] = new Point[MAX][MAX]; // start and
Point endp[][] = new Point[MAX][MAX]; // endpoint of arrow
float dir_x[][] = new float[MAX][MAX]; // direction of arrow
float dir_y[][] = new float[MAX][MAX]; // direction of arrow
// graph information while running algorithm
boolean algedge[][] = new boolean[MAX][MAX];
int dist[] = new int[MAX];
int finaldist[] = new int[MAX];
Color colornode[] = new Color[MAX];
boolean changed[] = new boolean[MAX]; // indicates distance change during algorithm
int numchanged =0;
int neighbours=0;
int step=0;
// information used by the algorithm to find the next
// node with minimum distance
int mindist, minnode, minstart, minend;
int numnodes=0; // number of nodes
int emptyspots=0; // empty spots in array node[] (due to node deletion)
int startgraph=0; // start of graph
int hitnode; // mouse clicked on or close to this node
int node1, node2; // numbers of nodes involved in current action
Point thispoint=new Point(0,0); // current mouseposition
Point oldpoint=new Point(0, 0); // previous position of node being moved
// current action
boolean newarrow = false;
boolean movearrow = false;
boolean movestart = false;
boolean deletenode = false;
boolean movenode = false;
boolean performalg = false;
boolean clicked = false;
// fonts
Font roman= new Font("TimesRoman", Font.BOLD, 12);
Font helvetica= new Font("Helvetica", Font.BOLD, 15);
FontMetrics fmetrics = getFontMetrics(roman);
int h = (int)fmetrics.getHeight()/3;
// for double buffering
private Image offScreenImage;
private Graphics offScreenGraphics;
private Dimension offScreenSize;
// for run option
Thread algrthm;
// current algorithm, (in case more algorithms are added)
int algorithm;
// algorithm information to be displayed in documetation panel
String showstring = new String("");
boolean stepthrough=false;
// locking the screen while running the algorithm
boolean Locked = false;
GraphAlgorithm parent;
GraphCanvas(GraphAlgorithm myparent) {
parent = myparent;
init();
algorithm=DIJKSTRA;
setBackground(Color.white);
}
public void lock() {
// lock screen while running an algorithm
Locked=true;
}
public void unlock() {
Locked=false;
}
public void start() {
if (algrthm != null) algrthm.resume();
}
public void init() {
for (int i=0;i0)
arrowupdate(i, j, weight[i][j]);
repaint();
}
public boolean mouseDown(Event evt, int x, int y) {
if (Locked)
parent.documentation.doctext.showline("locked");
else {
clicked = true;
if (evt.shiftDown()) {
// move a node
if (nodehit(x, y, NODESIZE)) {
oldpoint = node[hitnode];
node1 = hitnode;
movenode=true;
}
}
else if (evt.controlDown()) {
// delete a node
if (nodehit(x, y, NODESIZE)) {
node1 = hitnode;
if (startgraph==node1) {
movestart=true;
thispoint = new Point(x,y);
colornode[startgraph]=Color.gray;
}
else
deletenode= true;
}
}
else if (arrowhit(x, y, 5)) {
// change weihgt of an edge
movearrow = true;
repaint();
}
else if (nodehit(x, y, NODESIZE)) {
// draw a new arrow
if (!newarrow) {
newarrow = true;
thispoint = new Point(x, y);
node1 = hitnode;
}
}
else if ( !nodehit(x, y, 50) && !arrowhit(x, y, 50) ) {
// draw new node
if (emptyspots==0) {
// take the next available spot in the array
if (numnodes < MAXNODES)
node[numnodes++]=new Point(x, y);
else parent.documentation.doctext.showline("maxnodes");
}
else {
// take an empty spot in the array (from previously deleted node)
int i;
for (i=0;i0) {
arrowupdate(i, node1, weight[i][node1]);
}
if (weight[node1][i]>0) {
arrowupdate(node1, i, weight[node1][i]);
}
}
repaint();
}
else if (movestart || newarrow) {
thispoint = new Point(x, y);
repaint();
}
else if (movearrow) {
changeweight(x, y);
repaint();
}
}
return true;
}
public boolean mouseUp(Event evt, int x, int y) {
if ( (!Locked) && clicked ) {
if (movenode) {
// move the node if the new position is not to close to
// another node or outside of the panel
node[node1]=new Point(0, 0);
if ( nodehit(x, y, 50) || (x<0) || (x>this.size().width) ||
(y<0) || (y>this.size().height) ) {
node[node1]=oldpoint;
parent.documentation.doctext.showline("toclose");
}
else node[node1]=new Point(x, y);
for (int i=0;i0)
arrowupdate(i, node1, weight[i][node1]);
if (weight[node1][i]>0)
arrowupdate(node1, i, weight[node1][i]);
}
movenode=false;
}
else if (deletenode) {
nodedelete();
deletenode=false;
}
else if (newarrow) {
newarrow = false;
if (nodehit(x, y, NODESIZE)) {
node2=hitnode;
if (node1!=node2) {
arrowupdate(node1, node2, 50);
if (weight[node2][node1]>0) {
arrowupdate(node2, node1, weight[node2][node1]);
}
parent.documentation.doctext.showline("change weights");
}
else System.out.println("zelfde");
}
}
else if (movearrow) {
movearrow = false;
if (weight[node1][node2]>0)
changeweight(x, y);
}
else if (movestart) {
// if new position is a node, this node becomes the startnode
if (nodehit(x, y, NODESIZE))
startgraph=hitnode;
colornode[startgraph]=Color.blue;
movestart=false;
}
repaint();
}
return true;
}
public boolean nodehit(int x, int y, int dist) {
// checks if you hit a node with your mouseclick
for (int i=0; i0 ) &&
(Math.pow(x-arrow[i][j].x, 2) +
Math.pow(y-arrow[i][j].y, 2) < Math.pow(dist, 2) ) ) {
node1 = i;
node2 = j;
return true;
}
}
return false;
}
public void nodedelete() {
// delete a node and the arrows coming into/outof the node
node[node1]=new Point(-100, -100);
for (int j=0;j
Math.abs(endp[node1][node2].y-startp[node1][node2].y) ) {
follow_x = true;
}
// find the new position of the arrowhead, and calculate
// the corresponding weight
if (follow_x) {
int hbound = Math.max(startp[node1][node2].x,
endp[node1][node2].x)-Math.abs(diff_x);
int lbound = Math.min(startp[node1][node2].x,
endp[node1][node2].x)+Math.abs(diff_x);
// arrow must stay between the nodes
if (xhbound) { arrow[node1][node2].x=hbound; }
else arrow[node1][node2].x=x;
arrow[node1][node2].y=
(arrow[node1][node2].x-startp[node1][node2].x) *
(endp[node1][node2].y-startp[node1][node2].y)/
(endp[node1][node2].x-startp[node1][node2].x) +
startp[node1][node2].y;
// new weight
weight[node1][node2]=
Math.abs(arrow[node1][node2].x-startp[node1][node2].x-diff_x)*
100/(hbound-lbound);
}
// do the same if you follow y
else {
int hbound = Math.max(startp[node1][node2].y,
endp[node1][node2].y)-Math.abs(diff_y);
int lbound = Math.min(startp[node1][node2].y,
endp[node1][node2].y)+Math.abs(diff_y);
if (yhbound) { arrow[node1][node2].y=hbound; }
else arrow[node1][node2].y=y;
arrow[node1][node2].x=
(arrow[node1][node2].y-startp[node1][node2].y) *
(endp[node1][node2].x-startp[node1][node2].x)/
(endp[node1][node2].y-startp[node1][node2].y) +
startp[node1][node2].x;
weight[node1][node2]=
Math.abs(arrow[node1][node2].y-startp[node1][node2].y-diff_y)*
100/(hbound-lbound);
}
}
public void arrowupdate(int p1, int p2, int w) {
// make a new arrow from node p1 to p2 with weight w, or change
// the weight of the existing arrow to w, calculate the resulting
// position of the arrowhead
int dx, dy;
float l;
weight[p1][p2]=w;
// direction line between p1 and p2
dx = node[p2].x-node[p1].x;
dy = node[p2].y-node[p1].y;
// distance between p1 and p2
l = (float)( Math.sqrt((float)(dx*dx + dy*dy)));
dir_x[p1][p2]=dx/l;
dir_y[p1][p2]=dy/l;
// calculate the start and endpoints of the arrow,
// adjust startpoints if there also is an arrow from p2 to p1
if (weight[p2][p1]>0) {
startp[p1][p2] = new Point((int)(node[p1].x-5*dir_y[p1][p2]),
(int)(node[p1].y+5*dir_x[p1][p2]));
endp[p1][p2] = new Point((int)(node[p2].x-5*dir_y[p1][p2]),
(int)(node[p2].y+5*dir_x[p1][p2]));
}
else {
startp[p1][p2] = new Point(node[p1].x, node[p1].y);
endp[p1][p2] = new Point(node[p2].x, node[p2].y);
}
// range for arrowhead is not all the way to the start/endpoints
int diff_x = (int)(Math.abs(20*dir_x[p1][p2]));
int diff_y = (int)(Math.abs(20*dir_y[p1][p2]));
// calculate new x-position arrowhead
if (startp[p1][p2].x>endp[p1][p2].x) {
arrow[p1][p2] = new Point(endp[p1][p2].x + diff_x +
(Math.abs(endp[p1][p2].x-startp[p1][p2].x) - 2*diff_x )*
(100-w)/100 , 0);
}
else {
arrow[p1][p2] = new Point(startp[p1][p2].x + diff_x +
(Math.abs(endp[p1][p2].x-startp[p1][p2].x) - 2*diff_x )*
w/100, 0);
}
// calculate new y-position arrowhead
if (startp[p1][p2].y>endp[p1][p2].y) {
arrow[p1][p2].y=endp[p1][p2].y + diff_y +
(Math.abs(endp[p1][p2].y-startp[p1][p2].y) - 2*diff_y )*
(100-w)/100;
}
else {
arrow[p1][p2].y=startp[p1][p2].y + diff_y +
(Math.abs(endp[p1][p2].y-startp[p1][p2].y) - 2*diff_y )*
w/100;
}
}
public String intToString(int i) {
char c=(char)((int)'a'+i);
return ""+c;
}
public final synchronized void update(Graphics g) {
// prepare new image offscreen
Dimension d=size();
if ((offScreenImage == null) || (d.width != offScreenSize.width) ||
(d.height != offScreenSize.height)) {
offScreenImage = createImage(d.width, d.height);
offScreenSize = d;
offScreenGraphics = offScreenImage.getGraphics();
}
offScreenGraphics.setColor(Color.white);
offScreenGraphics.fillRect(0, 0, d.width, d.height);
paint(offScreenGraphics);
g.drawImage(offScreenImage, 0, 0, null);
}
public void drawarrow(Graphics g, int i, int j) {
// draw arrow between node i and node j
int x1, x2, x3, y1, y2, y3;
// calculate arrowhead
x1= (int)(arrow[i][j].x - 3*dir_x[i][j] + 6*dir_y[i][j]);
x2= (int)(arrow[i][j].x - 3*dir_x[i][j] - 6*dir_y[i][j]);
x3= (int)(arrow[i][j].x + 6*dir_x[i][j]);
y1= (int)(arrow[i][j].y - 3*dir_y[i][j] - 6*dir_x[i][j]);
y2= (int)(arrow[i][j].y - 3*dir_y[i][j] + 6*dir_x[i][j]);
y3= (int)(arrow[i][j].y + 6*dir_y[i][j]);
int arrowhead_x[] = { x1, x2, x3, x1 };
int arrowhead_y[] = { y1, y2, y3, y1 };
// if edge already chosen by algorithm change color
if (algedge[i][j]) g.setColor(Color.orange);
// draw arrow
g.drawLine(startp[i][j].x, startp[i][j].y, endp[i][j].x, endp[i][j].y);
g.fillPolygon(arrowhead_x, arrowhead_y, 4);
// write weight of arrow at an appropriate position
int dx = (int)(Math.abs(7*dir_y[i][j]));
int dy = (int)(Math.abs(7*dir_x[i][j]));
String str = new String("" + weight[i][j]);
g.setColor(Color.black);
if ((startp[i][j].x>endp[i][j].x) && (startp[i][j].y>=endp[i][j].y))
g.drawString( str, arrow[i][j].x + dx, arrow[i][j].y - dy);
if ((startp[i][j].x>=endp[i][j].x) && (startp[i][j].yendp[i][j].y))
g.drawString( str, arrow[i][j].x + dx,
arrow[i][j].y + fmetrics.getHeight() );
}
public void detailsDijkstra(Graphics g, int i, int j) {
// check arrow between node i and node j is amongst the arrows to
// choose from during this step of the algorithm
// check if node j has the next minimal distance to the startnode
if ( (finaldist[i]!=-1) && (finaldist[j]==-1) ) {
g.setColor(Color.red);
if ( (dist[j]==-1) || (dist[j]>=(dist[i]+weight[i][j])) ) {
if ( (dist[i]+weight[i][j])0) && (dist[i]!=-1) ) {
String str = new String(""+dist[i]);
g.drawString(str, node[i].x - (int)fmetrics.stringWidth(str)/2 -1,
node[i].y + h);
// string to distance to nodes on the documentation panel
if (finaldist[i]==-1) {
neighbours++;
if (neighbours!=1)
showstring = showstring + ", ";
showstring = showstring + intToString(i) +"=" + dist[i];
}
}
showstring = showstring + ". ";
if ( (step>1) && (numchanged>0) ) {
if (numchanged>1)
showstring = showstring + "Notice that the distances to ";
else showstring = showstring + "Notice that the distance to ";
for (int i=0; i1)
showstring = showstring + "have changed!\n";
else showstring = showstring + "has changed!\n";
}
else showstring = showstring + " ";
if (neighbours>1) {
// if there where more canditates explain why this node is taken
showstring = showstring + "Node " + intToString(minend) +
" has the minimum distance.\n";
//check if there are other paths to minend.
int newpaths=0;
for (int i=0; i0) && (weight[i][minend]>0) && ( finaldist[i] == -1 ) )
newpaths++;
if (newpaths>0)
showstring = showstring + "Any other path to " + intToString(minend) +
" visits another red node, and will be longer than " + mindist + ".\n";
else showstring = showstring +
"There are no other arrows coming in to "+
intToString(minend) + ".\n";
}
else {
boolean morenodes=false;
for (int i=0; i0 ) && ( finaldist[i] == -1 ) && ( weight[i][minend]>0 ) )
morenodes=true;
boolean bridge=false;
for (int i=0; i0 ) && ( finaldist[i] == -1 ) && ( weight[minend][i]>0 ) )
bridge=true;
if ( morenodes && bridge )
showstring = showstring + "Since this node forms a 'bridge' to "+
"the remaining nodes,\nall other paths to this node will be longer.\n";
else if ( morenodes && (!bridge) )
showstring = showstring + "Remaining gray nodes are not reachable.\n";
else showstring = showstring + "There are no other arrows coming in to "+
intToString(minend) + ".\n";
}
showstring = showstring + "Node " + intToString(minend) +
" will be colored orange to indicate " + mindist +
" is the length of the shortest path to " + intToString(minend) +".";
parent.documentation.doctext.showline(showstring);
}
public void detailsalg(Graphics g, int i, int j) {
// more algorithms can be added later
if (algorithm==DIJKSTRA)
detailsDijkstra(g, i, j);
}
public void endstepalg(Graphics g) {
// more algorithms can be added later
if (algorithm==DIJKSTRA)
endstepDijkstra(g);
if ( ( performalg ) && (mindist==0) ) {
if (algrthm != null) algrthm.stop();
int nreachable = 0;
for (int i=0; i 0)
nreachable++;
if (nreachable == 0)
parent.documentation.doctext.showline("none");
else if (nreachable< (numnodes-emptyspots-1))
parent.documentation.doctext.showline("some");
else
parent.documentation.doctext.showline("done");
}
}
public void paint(Graphics g) {
mindist=0;
minnode=MAXNODES;
minstart=MAXNODES;
minend=MAXNODES;
for(int i=0; i0) {
// if algorithm is running then perform next step for this arrow
if (performalg)
detailsalg(g, i, j);
drawarrow(g, i, j);
}
// if arrowhead has been dragged to 0, draw it anyway, so the user
// will have the option to make it positive again
if (movearrow && weight[node1][node2]==0) {
drawarrow(g, node1, node2);
g.drawLine(startp[node1][node2].x, startp[node1][node2].y,
endp[node1][node2].x, endp[node1][node2].y);
}
// draw the nodes
for (int i=0; i0) {
g.setColor(colornode[i]);
g.fillOval(node[i].x-NODERADIX, node[i].y-NODERADIX,
NODESIZE, NODESIZE);
}
// reflect the startnode being moved
g.setColor(Color.blue);
if (movestart)
g.fillOval(thispoint.x-NODERADIX, thispoint.y-NODERADIX,
NODESIZE, NODESIZE);
g.setColor(Color.black);
// finish this step of the algorithm
if (performalg) endstepalg(g);
// draw black circles around nodes, write their names to the screen
g.setFont(helvetica);
for (int i=0; i0) {
g.setColor(Color.black);
g.drawOval(node[i].x-NODERADIX, node[i].y-NODERADIX,
NODESIZE, NODESIZE);
g.setColor(Color.blue);
g.drawString(intToString(i), node[i].x-14, node[i].y-14);
}
}
}