Project

General

Profile

Revision 30

Added by Greg Tress over 16 years ago

got rid of old files

View differences:

trunk/code/projects/colonet/ColonetGUI/index.html
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3

  
4
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
5
<head>
6
	<title>Colony Control Applet - Carnegie Mellon Robotics Club</title>
7
	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
8
	<link rel="stylesheet" type="text/css" href="colonetstyle.css" />
9
</head>
10

  
11
<body>
12

  
13
<div class="top">
14
	<h1>Colonet: Robot Graph</h1>
15
	<p>Carnegie Mellon Robotics Club: Colony Project</p>
16
	<img src="http://roboclub8.frc.ri.cmu.edu/mainwiki/roboclublogo.png" height="125px" width="110px" alt="RoboClub Logo" />
17
</div>
18

  
19
<div class="app">
20
	<p>
21
	<object
22
		classid = "java:Colonet.class"
23
		type = "application/x-java-applet"
24
		width = "800"
25
		height = "700"
26
		align = "bottom"
27
		codebase = "http://roboclub1.frc.ri.cmu.edu/gui/" 
28
		name = "Colonet"
29
		title = "Colonet" >
30
		<param name = "code" value = "Colonet.class" />
31
	</object>
32
	<br />
33
	Requires Java 5.
34
	<br />
35
	<a href="Colonet.java">Source Code</a>
36
	<br />
37
	<br />
38
	</p>
39
</div>
40

  
41
<div class="bottom">
42
	<p><b>Colony Project Home page:</b><br />
43
	<a href="http://www.robotcolony.org/">www.robotcolony.org</a></p>
44
	
45
	<p><b>Validator:</b><br />
46
	<a href="http://validator.w3.org/check?uri=referer">
47
	<img src="http://www.w3.org/Icons/valid-xhtml10-blue"
48
		 alt="Valid XHTML 1.0 Transitional"
49
		 height="31"
50
		 width="88" 
51
		 border="0"
52
		 />
53
	</a>
54
	<a href="http://jigsaw.w3.org/css-validator/validator?uri=http://roboclub1.frc.ri.cmu.edu/ColonetGUI/colonetstyle.css">
55
  	<img style="border:0;width:88px;height:31px"
56
       src="http://www.w3.org/Icons/valid-css-blue" 
57
       alt="Valid CSS!" />
58
	</a><br />
59
	</p>
60
	
61
</div>
62

  
63

  
64

  
65
</body>
66
</html>
trunk/code/projects/colonet/ColonetGUI/index_simple.html
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3

  
4
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
5
<head>
6
	<title>Colony Control Applet - Carnegie Mellon Robotics Club</title>
7
	<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
8
	<link rel="stylesheet" type="text/css" href="colonetstyle.css" />
9
</head>
10

  
11
<body>
12

  
13
<div class="top">
14
	<h1>Colonet</h1>
15
	<p>Carnegie Mellon Robotics Club: Colony Project</p>
16
	<img src="http://roboclub8.frc.ri.cmu.edu/mainwiki/roboclublogo.png" height="125px" width="110px" />
17
</div>
18

  
19
<div class="app">
20
	<p>
21
	<object
22
		classid = "java:SimpleColonet.class"
23
		type = "application/x-java-applet"
24
		width = "900"
25
		height = "600"
26
		align = "bottom"
27
		codebase = "http://roboclub1.frc.ri.cmu.edu/gui/" 
28
		name = "SimpleColonet"
29
		title = "SimpleColonet" >
30
		<param name = "code" value = "SimpleColonet.class" />
31
	</object>
32
	<br />
33
	</p>
34
</div>
35

  
36
<div class="bottom">
37
	<p><b>Colony Project Home page:</b><br />
38
	<a href="http://www.robotcolony.org/">www.robotcolony.org</a></p>
39
	
40
	<p><b>Colonet Developers:</b><br />
41
	Gregory Tress, Eugene Edward Marinelli III, Jason Knichel, Suresh Nidhiry</p>
42
	
43
	<p><b>Validator:</b><br />
44
	<a href="http://validator.w3.org/check?uri=referer">
45
	<img src="http://www.w3.org/Icons/valid-xhtml10-blue"
46
		 alt="Valid XHTML 1.0 Transitional"
47
		 height="31"
48
		 width="88" 
49
		 border="0"
50
		 />
51
	</a>
52
	<a href="http://jigsaw.w3.org/css-validator/validator?uri=http://roboclub1.frc.ri.cmu.edu/ColonetGUI/colonetstyle.css">
53
  	<img style="border:0;width:88px;height:31px"
54
       src="http://www.w3.org/Icons/valid-css-blue" 
55
       alt="Valid CSS!" />
56
	</a><br />
57
	</p>
58
	
59
</div>
60

  
61

  
62

  
63
</body>
64
</html>
trunk/code/projects/colonet/ColonetGUI/copy.sh
1
#! /bin/bash
2

  
3
sudo cp * /var/www/gui/
trunk/code/projects/colonet/ColonetGUI/BotGraph.java
1
/* 
2
	BotGraph.java
3
	Colony Project
4
	Gregory Tress 
5
*/
6

  
7
import javax.swing.*;
8
import java.awt.*;
9
import java.awt.image.*;
10
import java.awt.event.*;
11
import java.net.*;
12
import java.io.*;
13
import java.util.Random;
14

  
15
public class BotGraph extends JApplet implements ActionListener, MouseListener, Runnable
16
{
17

  
18
	final int CANVAS_SIZE = 550;  //don't make this too large, or the applet will be slow.
19
	final int BUFFER = 50;
20
	final int RADIUS = 30;
21

  
22
	JTextField txtHost;				
23
	JTextField txtPort;				
24
	JButton btnConnect;	
25
	JButton btnGraph;
26
	JButton btnRandomize;
27
	JLabel lblNumRobots;
28
	JLabel lblHasToken;
29
	JLabel lblTokenPasses;
30
	JLabel lblConnectionStatus;
31
	JTextArea txtInput;  //sample matrix is entered in this area
32
	JTextArea txtInfo; 
33
	JPanel panel;
34
	JPanel panelConnect;
35
	JPanel panelControl;
36
	JPanel panelStats;
37
	
38
	GraphicsConfiguration gc;
39
	volatile BufferedImage image;
40
	volatile Graphics2D canvas;
41
	int cx, cy;
42
	
43
	Socket socket;					
44
	OutputStreamWriter out;			//TODO: add a BufferedWriter
45
	DataListener datalistener;  
46
	
47
	Font botFont;
48
	Random random = new Random();
49
	volatile int tokenLoc;  //the token is currently here
50
	volatile int numBots;
51
	volatile int selectedBot;  //the user has selected this bot
52
	volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
53
	
54
	Thread drawThread;
55
	SelectionIndicator indicator;
56
	Simulator simulator;
57
	PacketMonitor packetMonitor;
58
	
59
	public void init ()
60
	{
61
		// We should invoke and wait to avoid browser display difficulties
62
		Runnable r = new Runnable() {
63
			public void run() {
64
				createAndShowGUI();
65
			}
66
		};
67
		try {
68
			SwingUtilities.invokeAndWait(r);
69
		} catch (InterruptedException e) {
70
			//Not really sure why we would be in this situation
71
			System.out.println(e);
72
		} catch (java.lang.reflect.InvocationTargetException e) {
73
			//This should never happen. Seriously.
74
			System.out.println(e);
75
		}
76
	}
77
	
78
	public void destroy ()
79
	{
80
		drawThread.interrupt();
81
		indicator.interrupt();
82
		simulator.interrupt();
83
		packetMonitor.interrupt();
84
	}
85

  
86
	private synchronized void createAndShowGUI ()
87
	{
88
		// init graphical elements
89
		panel = new JPanel(false);  //set automatic double-buffering to false. we are doing it manually.
90
		
91
		// Set up connection area
92
		txtHost = new JTextField("roboclub1.frc.ri.cmu.edu");
93
		txtPort = new JTextField("10123");
94
		btnConnect = new JButton("Connect");
95
		lblConnectionStatus = new JLabel("Status: Offline");
96
		panelConnect = new JPanel();
97
		panelConnect.setLayout(new GridLayout(2,3));
98
		panelConnect.add(new JLabel("Host"));
99
		panelConnect.add(new JLabel("Port"));
100
		panelConnect.add(lblConnectionStatus);
101
		panelConnect.add(txtHost);
102
		panelConnect.add(txtPort);
103
		panelConnect.add(btnConnect);
104
		panelConnect.setBorder(BorderFactory.createTitledBorder("Connection"));
105
		
106
		// Set up elements in the east
107
		panelControl = new JPanel();
108
		panelControl.setLayout(new GridLayout(5,1));
109
		lblNumRobots = new JLabel();
110
		lblHasToken = new JLabel();
111
		lblTokenPasses = new JLabel();
112
		panelStats = new JPanel();
113
		panelStats.setLayout(new GridLayout(3,2));
114
		panelStats.add(new JLabel("Number of Bots  "));
115
		panelStats.add(lblNumRobots);
116
		panelStats.add(new JLabel("Token At  "));
117
		panelStats.add(lblHasToken);
118
		panelStats.add(new JLabel("Token Passes / sec     "));
119
		panelStats.add(lblTokenPasses);
120
		txtInput = new JTextArea("- 9 3 - 1\n- - - 5 -\n4 - - - 2\n- - - - -\n1 - - 3 -");
121
		txtInput.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
122
		txtInfo = new JTextArea();
123
		txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
124
		txtInfo.setEditable(false);
125
		btnGraph = new JButton("Run");
126
		btnRandomize = new JButton("Randomize");
127
		panelControl.add(panelStats);
128
		panelControl.add(txtInput);
129
		panelControl.add(txtInfo);
130
		panelControl.add(btnRandomize);
131
		panelControl.add(btnGraph);
132
		
133
		
134
		this.getContentPane().setLayout(new BorderLayout());
135
		this.getContentPane().add(panelConnect, BorderLayout.NORTH);
136
		this.getContentPane().add(panelControl, BorderLayout.EAST);
137
		this.getContentPane().add(panel, BorderLayout.CENTER);
138
		this.setVisible(true);
139
		
140
		btnGraph.addActionListener(this);
141
		btnRandomize.addActionListener(this);
142
		btnConnect.addActionListener(this);
143
		panel.addMouseListener(this);
144
		
145
		
146
		// Get the graphics configuration of the screen to create a buffer
147
		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
148
			.getDefaultScreenDevice().getDefaultConfiguration();
149
		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
150
		canvas = image.createGraphics();
151
		canvas.setStroke(new BasicStroke(2));  //set pen width
152
		
153
		// Calculate center of canvas
154
		cx = image.getWidth() / 2;
155
		cy = image.getHeight() / 2;
156
		
157
		botFont = new Font("Arial", Font.PLAIN, 30);
158
		tokenLoc = 0;
159
		numBots = 0;
160
		selectedBot = 0;
161
		
162
		// Set up dependent threads
163
		indicator = new SelectionIndicator(canvas);
164
		indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
165
		simulator = new Simulator();
166
		packetMonitor = new PacketMonitor();
167
		datalistener = new DataListener();
168
	
169
	}
170
	
171
	public synchronized void paint (Graphics g)
172
	{
173
		/*	First, redraw the graphical components in the applet. 
174
			This paint method overrides the built-in paint of the 
175
			JApplet, and we don't want to deal with redrawing the
176
			components manually. Fuck that shit. */
177
		super.paint(g);
178
		
179
		// Place the buffered image on the screen, inside the panel
180
		panel.getGraphics().drawImage(image, 0, 0, Color.WHITE, this);
181
		
182
	}
183
	
184
	public synchronized void update (Graphics g)
185
	{
186
		paint(g);
187
	}
188
	
189
	public void actionPerformed (ActionEvent e)
190
	{
191
		Object source = e.getSource();
192
		if (source == btnGraph)
193
		{
194
			btnGraph.setEnabled(false);
195
			lblConnectionStatus.setText("Status: Simulation mode => running");
196
			
197
			//Start dependent threads
198
			drawThread = new Thread(this, "drawThread");
199
			drawThread.start();
200
			indicator.start();
201
			simulator.start();
202
			packetMonitor.start();
203
		}
204
		else if (source == btnConnect)
205
		{
206
			doSocket();
207
		}
208
		else if (source == btnRandomize)
209
		{
210
			randomize();
211
		}
212
	}
213
	
214
	private void randomize ()
215
	{
216
		Random r = new Random();
217
		StringBuilder s = new StringBuilder();
218
		
219
		int count = r.nextInt(8) + 1;
220
		for (int i = 0; i < count; i++)
221
		{
222
			for (int j = 0; j < count; j++)
223
			{
224
				if (r.nextBoolean())	
225
					s.append("" + (r.nextInt(16) + 1));
226
				else 
227
					s.append("-");
228
				if (j != count-1)
229
					s.append(" ");
230
			}
231
			if (i != count-1) s.append("\n");
232
		}
233
		
234
		txtInput.setText(s.toString());
235
	}
236
	
237
	private void doSocket ()
238
	{
239
		//make sure hostname and port are valid
240
		if (txtHost.getText().equals("") || txtPort.getText().equals("")) {
241
			err("Please enter a hostname and port.");
242
			return;
243
		}
244
		int port = 0;
245
		try {
246
			port = Integer.parseInt(txtPort.getText());
247
		} catch (Exception e) {
248
			err("Invalid port");
249
			return;
250
		}
251
		
252
		//make sure we aren't already connected. if so, disconnect first.
253
		if (socket != null && socket.isConnected()) {
254
			try {
255
				out.close();
256
				socket.close();
257
			} catch (IOException e) {}
258
		}
259
		
260
		try {
261
			socket = new Socket(txtHost.getText(), port);
262
		} catch (UnknownHostException e) {
263
			err("Unknown Host Exception");
264
			return;
265
		} catch (IOException e) {
266
			err("IO Exception\n\n" + e);
267
			return;
268
		} catch (java.security.AccessControlException e) {
269
			err("Permission denied by java.security.AccessControlException.\n\nYou may only connect to the server from which this applet was loaded.");
270
			return;
271
		}
272
		if (socket == null || !socket.isConnected()) {
273
			err("Connection failed. Try connecting again.");
274
			return;
275
		}
276
		msg("Connected to " + txtHost.getText() + " on port " + port + "\n");
277
		lblConnectionStatus.setText("Status: ONLINE");
278
		try {
279
			out = new OutputStreamWriter(socket.getOutputStream());
280
		} catch (IOException e) {
281
			warn("Could not get OutputStream from socket connection.");
282
		}
283
	
284
	}
285
	
286
	public void drawRobot (int id, int x, int y) 
287
	{
288
		//save the bot in memory, so we can tell if we click on it later
289
		botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
290
	
291
		//draw the bot on the canvas
292
		canvas.setColor(Color.BLACK);
293
		canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2);
294
		
295
		//draw the label
296
		canvas.setFont(botFont);
297
		canvas.drawString("" + id, x-10, y+10);
298
	}
299
	
300
	public void drawConnection (int start, int end, int radius, Color color)
301
	{
302
		final int ARROW_LENGTH = 18;
303
	
304
		double angle = 2.0 * Math.PI / numBots;
305
		int startx, starty, endx, endy;
306
		startx = cx - (int)(radius * Math.cos(start * angle));
307
		starty = cy - (int)(radius * Math.sin(start * angle));
308
		endx = cx - (int)(radius * Math.cos(end * angle));
309
		endy = cy - (int)(radius * Math.sin(end * angle));
310
		canvas.setColor(color);
311
		canvas.drawLine(startx, starty, endx, endy);
312
		
313
		//create arrow
314
		if (color.equals(Color.BLACK)) return;
315
		int big_dy = starty - endy;
316
		int big_dx = endx - startx;
317
		double theta = 0;
318
		if (big_dx == 0 && starty > endy) //pointing up
319
			theta = Math.PI/2;
320
		else if (big_dx == 0 && starty < endy) //pointing down 
321
			theta = 3*Math.PI/2;
322
		else if (big_dy == 0 && startx > endx) //pointing left
323
			theta = Math.PI;
324
		else if (big_dy == 0 && startx < endx) //pointing right
325
			theta = 0;
326
		else
327
			theta = Math.atan(1.0 * big_dy / big_dx);
328
		
329
		//create ploygon
330
		Polygon poly = new Polygon();
331
		int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta)));
332
		int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta)));
333
		int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta));
334
		int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
335
		int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
336
		int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
337
		//System.out.println("" + start + "->" + end + " : dx=" + big_dx + ",dy=" + big_dy + ",dy_arrow=" + dy_arrow + ",dx_arrow=" + dx_arrow + ",theta=" + theta + ",endx=" + endx + ",endy=" + endy + ",rx=" + rx + ",ry=" + ry);
338
		poly.addPoint(endx, endy);
339
		poly.addPoint(rx - dx_half, ry - dy_half);
340
		poly.addPoint(rx + dx_half, ry + dy_half);
341
		canvas.fillPolygon(poly);
342
	}
343
	
344
	public void run ()
345
	{
346
		while (true)
347
		{
348
			step();
349
			repaint();
350
			try { Thread.sleep(90); }
351
				catch (InterruptedException e) { return; }
352
		}
353
	}
354
	
355
	public void step () 
356
	{
357
		final int DIAMETER = image.getWidth() - 2*BUFFER;
358
		final int BIGRADIUS = DIAMETER / 2;
359
		final int TOKENRADIUS = 40;
360
		boolean valid;
361
	
362
		// clear image
363
		canvas.setColor(Color.WHITE);
364
		canvas.fillRect(0, 0, image.getWidth(), image.getHeight());
365
		
366
		// parse the matrix, to see what robots exist
367
		String [] rows = txtInput.getText().split("\n");
368
		numBots = rows.length;
369
		String [][] entries = new String[numBots][numBots];
370
		valid = true;
371
		for (int i = 0; i < numBots; i++) 
372
		{
373
			entries[i] = rows[i].split(" ");
374
			if (entries[i].length != rows.length) valid = false;
375
		}
376
		
377
		if (valid)
378
		{
379
			lblNumRobots.setText("" + numBots);
380
			lblHasToken.setText("" + tokenLoc);
381
			this.showStatus("Matrix OK");
382
			
383
			// draw outer ring
384
			//canvas.setColor(Color.GREEN);
385
			//canvas.drawOval(BUFFER, BUFFER, DIAMETER, DIAMETER);
386
			
387
			// draw robots and find which one is seleced
388
			double angle = 2.0 * Math.PI / numBots;
389
			canvas.setColor(Color.BLACK);
390
			botRect = new Rectangle[numBots];
391
			int x, y;
392
			if (selectedBot >= numBots) selectedBot = 0;
393
			for (int i = 0; i < numBots; i++)
394
			{
395
				x = cx - (int)(BIGRADIUS * Math.cos(i * angle));
396
				y = cy - (int)(BIGRADIUS * Math.sin(i * angle));
397
				drawRobot(i, x, y);
398
				if (i == selectedBot) indicator.setCenter(x, y);
399
			}
400
			
401
			// draw token marker
402
			int tokenx, tokeny;
403
			int tokenNum = tokenLoc;
404
			tokenx = cx - (int)(BIGRADIUS * Math.cos(tokenNum * angle));
405
			tokeny = cy - (int)(BIGRADIUS * Math.sin(tokenNum * angle));
406
			canvas.setColor(Color.RED);
407
			canvas.drawOval(tokenx-TOKENRADIUS, tokeny-TOKENRADIUS, 2*TOKENRADIUS, 2*TOKENRADIUS);
408
			
409
			// create an inner circle along which the connections are made.
410
			// let the diameter of this circle be 2*RADIUS less than the outerDiameter.
411
			// see what connections exist
412
			for (int row = 0; row < numBots; row++)
413
			{
414
				for(int col = 0; col < numBots; col++)
415
				{
416
					if (! entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) //one-way
417
					{
418
						//drawConnection(row, col, BIGRADIUS-RADIUS, Color.GRAY);
419
						drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200));
420
					}
421
					else if (! entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) //two-way
422
					{
423
						drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
424
					}
425
				}
426
			}
427
			
428
			// draw the selection indicator
429
			indicator.draw();
430
			txtInfo.setText("Bot " + selectedBot + " is selected.\n");
431
			txtInfo.append("Battery: ???\n");
432
			txtInfo.append("Packet statistics: ???");
433
			
434
		}
435
		else // if matrix is not valid
436
		{
437
			this.showStatus("Error: Invalid matrix");
438
		}
439
	
440
	}
441
	
442
	/*	At this point, moveToken is only called by the simulator.
443
	*	In the future, it can be rewritten to account for non-standard
444
	*	token passing or deleted if the information can be retrieved
445
	*	directly from the Colonet server instead.
446
	*/
447
	public void moveToken ()
448
	{
449
		try { tokenLoc = (tokenLoc+1)%numBots; }
450
			catch (ArithmeticException e) { }  // in case numRobots is zero
451
		
452
		packetMonitor.addTokenPass();
453
	}
454
	
455
	//
456
	// MouseEvent methods
457
	//
458
	public void mouseExited(MouseEvent e) {}
459
	public void mouseEntered(MouseEvent e) {}
460
	public void mouseReleased(MouseEvent e) {}
461
	public void mouseClicked(MouseEvent e) {}
462
	public void mousePressed(MouseEvent e)
463
	{
464
		try {
465
			for (int i = 0; i < numBots; i++)
466
			{
467
				if (botRect[i].contains(e.getPoint()))
468
					selectedBot = i;
469
			}
470
		} catch (Exception ex) {
471
			System.out.println(e);
472
		}
473
	
474
	}
475
	
476
	private void msg (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);}
477
	private void warn (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.WARNING_MESSAGE);}
478
	private void err (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.ERROR_MESSAGE);}
479
	
480
	
481
	/*
482
	*	SelectionIndicator thread.
483
	*	Graphical representation of the selection marker
484
	*
485
	*	step() and draw() are synchronized methods. step() is private and 
486
	*	used to update the position of the crosshairs. draw() is called 
487
	*	externally and should only run if all calculations in step() have
488
	*	been completed.
489
	*/
490
	private class SelectionIndicator extends Thread
491
	{
492
	
493
		final int INDICATOR_DELAY = 100;
494
		final double DTHETA = 0.3;    //larger values make the marker rotate faster
495
		Graphics2D g;   //canvas to draw on
496
		boolean running;
497
		
498
		int sx, sy;		//center
499
		int r, dr;		//radius and width of marker
500
		double theta;   //current angle
501
		
502
		volatile Polygon poly1, poly2, poly3, poly4;
503
		
504
		int px1, py1;
505
		int rx1, ry1;
506
		int px2, py2;
507
		int rx2, ry2;
508
		int px3, py3;
509
		int rx3, ry3;
510
		int px4, py4;
511
		int rx4, ry4;
512
		
513
		int steps;
514
	
515
		public SelectionIndicator (Graphics2D g)
516
		{
517
			super("SelectionIndicator");
518
			this.g = g;
519
			running = false;
520
			steps = 0;
521
			
522
			theta = 0;
523
			rx1 = 0; ry1 = 0;
524
			px1 = 0; py1 = 0;
525
			rx2 = 0; ry2 = 0;
526
			px2 = 0; py2 = 0;
527
			rx3 = 0; ry3 = 0;
528
			px3 = 0; py3 = 0;
529
			rx4 = 0; ry4 = 0;
530
			px4 = 0; py4 = 0;
531
		}
532
		
533
		public synchronized void setCenter (int sx, int sy)
534
		{
535
			if (sx == this.sx && sy == this.sy) return;
536
			this.sx = sx;
537
			this.sy = sy;
538
			steps = 0;
539
		}
540
		
541
		public synchronized void setRadius (int r, int dr)
542
		{
543
			this.r = r;
544
			this.dr = dr;
545
			steps = 0;
546
		}
547
		
548
		public void run ()
549
		{
550
			running = true;
551
			while (running)
552
			{
553
				step();
554
				try { Thread.sleep(INDICATOR_DELAY); }
555
					catch (InterruptedException e) {  running = false; return; }
556
			}
557
		}
558
		
559
		private synchronized void step ()
560
		{
561
			Polygon poly1_new = new Polygon();
562
			Polygon poly2_new = new Polygon();
563
			Polygon poly3_new = new Polygon();
564
			Polygon poly4_new = new Polygon();
565
		
566
			//the step
567
			theta = (theta + DTHETA/Math.PI) % (Math.PI);
568
			
569
			//the calculation
570
			//let p be the point of the pointy thing toward the center
571
			//let r be the point at the opposite side
572
			
573
			//recalculate radius, if it will look cool, lolz
574
			int newr = r;
575
			if (steps < 100) newr = (int)( r + 200/(steps+1) );
576
			
577
			//precompute values for dx and dy
578
			int dx_inner = (int)(newr * Math.cos(theta));
579
			int dy_inner = (int)(newr * Math.sin(theta));
580
			int dx_outer = (int)((newr+dr) * Math.cos(theta));
581
			int dy_outer = (int)((newr+dr) * Math.sin(theta));
582
			
583
			//calculate polygon constants
584
			int dy_poly = (int)(dr/2 * Math.cos(theta));
585
			int dx_poly = (int)(dr/2 * Math.sin(theta));
586
			
587
			//determine critical points
588
			px1 = sx + dx_inner;
589
			py1 = sy - dy_inner;
590
			rx1 = sx + dx_outer;
591
			ry1 = sy - dy_outer;
592
			px2 = sx - dx_inner;
593
			py2 = sy + dy_inner;
594
			rx2 = sx - dx_outer;
595
			ry2 = sy + dy_outer;
596
			px3 = sx - dy_inner;
597
			py3 = sy - dx_inner;
598
			rx3 = sx - dy_outer;
599
			ry3 = sy - dx_outer;
600
			px4 = sx + dy_inner;
601
			py4 = sy + dx_inner;
602
			rx4 = sx + dy_outer;
603
			ry4 = sy + dx_outer;
604
			
605
			//create polygons
606
			poly1_new.addPoint(px1, py1);
607
			poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly);
608
			poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly);
609
			poly2_new.addPoint(px2, py2);
610
			poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly);
611
			poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly);
612
			poly3_new.addPoint(px3, py3);
613
			poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly);
614
			poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly);
615
			poly4_new.addPoint(px4, py4);
616
			poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly);
617
			poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly);
618
			
619
			//reassign updated polygons
620
			poly1 = poly1_new;
621
			poly2 = poly2_new;
622
			poly3 = poly3_new;
623
			poly4 = poly4_new;
624
		
625
			if (steps < 300) steps++;
626
		}
627
		
628
		public synchronized void draw ()
629
		{
630
			if (!running) return;
631
			g.setColor(Color.GRAY);
632
			//draw polygons
633
			g.fillPolygon(poly1);
634
			g.fillPolygon(poly2);
635
			g.fillPolygon(poly3);
636
			g.fillPolygon(poly4);
637
		}
638
	
639
	
640
	}
641
	
642
	/*
643
	*	Simulator thread.
644
	*
645
	*/
646
	private class Simulator extends Thread
647
	{
648
		final int SIMULATOR_DELAY = 300;
649
	
650
		boolean running;
651
	
652
		public Simulator ()
653
		{
654
			super("Simulator");
655
			running = false;
656
		}
657
		
658
		public void run ()
659
		{
660
			running = true;
661
			while (running)
662
			{
663
				step();
664
				try { Thread.sleep(SIMULATOR_DELAY); }
665
					catch (InterruptedException e) { running = false; return; }
666
			}
667
		}
668
		
669
		private void step ()
670
		{
671
			// simulate passing the token
672
			moveToken();
673
		
674
		}
675
	
676
	}
677
	
678
	/*
679
	*	PacketMonitor thread.
680
	*
681
	*	Currently, this counts the rate of token passes but will eventually 
682
	*	be modified to keep more important statistics.
683
	*/
684
	private class PacketMonitor extends Thread
685
	{
686
		final int PACKETMONITOR_DELAY = 1000;
687
	
688
		boolean running;
689
		int tokenPasses;
690
	
691
		public PacketMonitor ()
692
		{
693
			super("PacketMonitor");
694
			running = false;
695
			tokenPasses = 0;
696
		}
697
		
698
		public void run ()
699
		{
700
			running = true;
701
			while (running)
702
			{
703
				displayTokenPasses();
704
				try { Thread.sleep(PACKETMONITOR_DELAY); }
705
					catch (InterruptedException e) { running = false; return; }
706
			}
707
		}
708
		
709
		public synchronized void addTokenPass ()
710
		{
711
			tokenPasses++;
712
		}
713
		
714
		public synchronized void displayTokenPasses ()
715
		{
716
			lblTokenPasses.setText("" + tokenPasses);
717
			tokenPasses = 0;
718
		}
719
	
720
	}
721
	
722
	/*
723
	*	DataListener thread.
724
	*
725
	*/
726
	class DataListener extends Thread
727
	{
728
		final int DATALISTENER_DELAY = 1000;
729
		BufferedReader reader;
730
		
731
		public DataListener ()
732
		{
733
			super("Colonet DataListener");
734
		}
735
		
736
		public void run ()
737
		{
738
			String line;
739
			try {
740
				reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
741
			} catch (IOException e) {
742
				warn("Could not open input stream from socket.\nTry relooding the applet.");
743
			}
744
			while (true)
745
			{
746
				try {
747
					if (reader.ready())
748
					{
749
						line = reader.readLine();
750
						if (line != null)
751
						{
752
							msg("Incoming data: [" + line + "]");
753
						}
754
					}
755
					Thread.sleep(DATALISTENER_DELAY);
756
				} catch (InterruptedException e) {
757
					return;
758
				} catch (IOException e) {
759
					warn("IOException while reading incoming data.");
760
				}
761
			}
762
		}
763

  
764
	}
765

  
766
	
767
	/*
768
	*	Matrix class
769
	*	holds current sensor matrix data
770
	*/
771
	
772
	/*
773
	private class Matrix
774
	{
775
		int [][] grid;
776
	
777
		public Matrix ()
778
		{
779
			grid = new int[1][1];
780
		}
781
		
782
		public String toString ()
783
		{
784
			StringBuilder s = new StringBuilder();
785
			for (int j = 0; j < grid.length; j++)
786
			{
787
				for (int i = 0; i < grid[0].length; i++)
788
					s.append(grid[i][j]);
789
				if (j < grid.length-1) s.append("\n");
790
			}
791
			return s.toString();
792
		}
793
	
794
	}
795
	*/
796
	
797
	
798
	
799
}
800

  
trunk/code/projects/colonet/ColonetGUI/Colonet.java
1
/* 
2
	BotGraph.java
3
	Colony Project
4
	Gregory Tress 
5
*/
6

  
7
import javax.swing.*;
8
import java.awt.*;
9
import java.awt.image.*;
10
import java.awt.event.*;
11
import java.net.*;
12
import java.io.*;
13
import java.util.Random;
14

  
15
public class Colonet extends JApplet implements ActionListener, MouseListener, Runnable
16
{
17

  
18
	final int CANVAS_SIZE = 500;  //don't make this too large, or the applet will be slow.
19
	final int BUFFER = 50;
20
	final int RADIUS = 30;
21

  
22
	// Connection
23
	JTextField txtHost;				
24
	JTextField txtPort;				
25
	JButton btnConnect;	
26
	JButton btnGraph;
27
	JLabel lblConnectionStatus;
28
	JTextArea txtInput;
29
	JTextArea txtInfo; 
30
	JPanel panelConnect;
31
	JPanel panelServerInterface;
32
	
33
	// Stats
34
	JLabel lblBattery;
35
	JLabel lblTokenPasses;
36
	JLabel lblHastToken;
37
	JPanel panelStats;
38
	
39
	// South
40
	JPanel panelSouth;
41
	JTextArea log;
42
	JScrollPane spLog;
43
	
44
	// Control
45
	JPanel panelControl;
46
	JTabbedPane tabPaneControl;
47
	JPanel panelRobotControl;
48
	JPanel panelRobotDirection;
49
	JPanel panelRobotCommands;
50
	JButton btnF, btnB, btnL, btnR, btnActivate;
51
	
52
	// Task Manager
53
	JPanel panelTaskManager;
54
	JScrollPane spTaskManager;
55
	JPanel panelTaskManagerControls;
56
	JPanel panelTaskManagerControlsPriority;
57
	DefaultListModel taskListModel;
58
	JList taskList;
59
	JButton btnAddTask;
60
	JButton btnRemoveTask;
61
	JButton btnMoveTaskUp;
62
	JButton btnMoveTaskDown;
63
	
64
	// Graphics
65
	JPanel panel;
66
	GraphicsConfiguration gc;
67
	volatile BufferedImage image;
68
	volatile Graphics2D canvas;
69
	int cx, cy;
70
	
71
	Socket socket;					
72
	OutputStreamWriter out;			//TODO: add a BufferedWriter
73
	DataListener datalistener;  
74
	
75
	Font botFont;
76
	Random random = new Random();
77
	volatile int tokenLoc;  //the token is currently here
78
	volatile int numBots;
79
	volatile int selectedBot;  //the user has selected this bot
80
	volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
81
	
82
	Thread drawThread;
83
	SelectionIndicator indicator;
84
	PacketMonitor packetMonitor;
85
	
86
	public void init ()
87
	{
88
		// We should invoke and wait to avoid browser display difficulties
89
		Runnable r = new Runnable() {
90
			public void run() {
91
				createAndShowGUI();
92
			}
93
		};
94
		try {
95
			SwingUtilities.invokeAndWait(r);
96
		} catch (InterruptedException e) {
97
			//Not really sure why we would be in this situation
98
			System.out.println(e);
99
		} catch (java.lang.reflect.InvocationTargetException e) {
100
			//This should never happen. Seriously.
101
			System.out.println(e);
102
		}
103
	}
104
	
105
	public void destroy ()
106
	{
107
		try { drawThread.interrupt(); } catch (Exception e) { }
108
		try { indicator.interrupt(); } catch (Exception e) { }
109
		try { packetMonitor.interrupt(); } catch (Exception e) { }
110
	}
111

  
112
	private synchronized void createAndShowGUI ()
113
	{
114
		// init graphical elements
115
		panel = new JPanel(false);  //set automatic double-buffering to false. we are doing it manually.
116
		
117
		// Connection area
118
		txtInput = new JTextArea("- 9 3 - 1\n- - - 5 -\n4 - - - 2\n- - - - -\n1 - - 3 -");
119
		txtInput.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
120
		txtInfo = new JTextArea();
121
		txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
122
		txtInfo.setEditable(false);
123
		btnGraph = new JButton("Run");
124
		txtHost = new JTextField("roboclub1.frc.ri.cmu.edu");
125
		txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
126
		txtPort = new JTextField("10123");
127
		txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
128
		btnConnect = new JButton("Connect");
129
		lblConnectionStatus = new JLabel("Status: Offline");
130
		panelConnect = new JPanel();
131
		panelConnect.setLayout(new GridLayout(6,1));
132
		panelConnect.add(lblConnectionStatus);
133
		panelConnect.add(txtHost);
134
		panelConnect.add(txtPort);
135
		panelConnect.add(btnConnect);
136
		panelConnect.add(txtInfo);
137
		panelConnect.add(btnGraph);
138
		panelServerInterface = new JPanel();
139
		panelServerInterface.setLayout(new GridLayout(2,1));
140
		panelServerInterface.add(panelConnect);
141
		panelServerInterface.add(txtInput);
142
				
143
		// Status Elements
144
		lblTokenPasses = new JLabel();
145
		lblBattery = new JLabel("???");
146
		panelStats = new JPanel();
147
		panelStats.setLayout(new GridLayout(4,2));
148
		panelStats.add(new JLabel("Token Passes / sec          "));
149
		panelStats.add(lblTokenPasses);
150
		panelStats.add(new JLabel("Battery     "));
151
		panelStats.add(lblBattery);
152
		panelStats.add(new JLabel("Token Passes / sec     "));
153
		panelStats.add(lblTokenPasses);
154
		
155
		//TODO: add panelStats somewhere!
156

  
157
		// Robot direction panel
158
		panelRobotDirection = new JPanel();
159
		btnF = new JButton("^");
160
		btnB = new JButton("v");
161
		btnL = new JButton("<");
162
		btnR = new JButton(">");
163
		btnActivate = new JButton("o");
164
		panelRobotDirection = new JPanel();
165
		panelRobotDirection.setLayout(new GridLayout(3,3));
166
		panelRobotDirection.add(new JLabel(""));
167
		panelRobotDirection.add(btnF);
168
		panelRobotDirection.add(new JLabel(""));
169
		panelRobotDirection.add(btnL);
170
		panelRobotDirection.add(btnActivate);
171
		panelRobotDirection.add(btnR);
172
		panelRobotDirection.add(new JLabel(""));
173
		panelRobotDirection.add(btnB);
174
		panelRobotDirection.add(new JLabel(""));
175
		
176
		// Robot Control and Commands
177
		panelRobotCommands = new JPanel();
178
		panelRobotCommands.setLayout(new FlowLayout());
179
		panelRobotCommands.add(new JLabel("Commands go here"));
180
		panelRobotControl = new JPanel();
181
		panelRobotControl.setLayout(new GridLayout(2,1));
182
		panelRobotControl.add(panelRobotDirection);
183
		panelRobotControl.add(panelRobotCommands);
184
		
185
		// Task Manager
186
		panelTaskManager = new JPanel();
187
		panelTaskManager.setLayout(new BorderLayout());
188
		taskListModel = new DefaultListModel();
189
		taskListModel.addElement("Map the Environment");
190
		taskListModel.addElement("Clean Up Chemical Spill");
191
		taskListModel.addElement("Grow Plants");
192
		taskListModel.addElement("Save the Cheerleader");
193
		taskListModel.addElement("Save the World");
194
		taskList = new JList(taskListModel);
195
		taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
196
		taskList.setSelectedIndex(0);
197
		spTaskManager = new JScrollPane(taskList);
198
		panelTaskManagerControls = new JPanel();
199
		panelTaskManagerControls.setLayout(new GridLayout(1,3));
200
		panelTaskManagerControlsPriority = new JPanel();
201
		panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
202
		btnAddTask = new JButton("Add...");
203
		btnRemoveTask = new JButton("Remove");
204
		btnMoveTaskUp = new JButton("^");
205
		btnMoveTaskDown = new JButton("v");
206
		panelTaskManagerControlsPriority.add(btnMoveTaskUp);
207
		panelTaskManagerControlsPriority.add(btnMoveTaskDown);
208
		panelTaskManagerControls.add(btnAddTask);
209
		panelTaskManagerControls.add(btnRemoveTask);
210
		panelTaskManagerControls.add(panelTaskManagerControlsPriority);
211
		panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
212
		panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
213
		panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
214
		
215
		// Message log
216
		log = new JTextArea();
217
		spLog = new JScrollPane(log,
218
			ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, 
219
			ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
220
		spLog.setBorder(BorderFactory.createTitledBorder("Log"));
221
		spLog.setPreferredSize(new Dimension(0, 150));
222
		log.setEditable(false);
223
		
224
		// Main control mechanism
225
		panelControl = new JPanel();
226
		panelControl.setLayout(new GridLayout(1,1));
227
		tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
228
		tabPaneControl.setPreferredSize(new Dimension(300, 0));
229
		tabPaneControl.addTab("Connection", panelServerInterface);
230
		tabPaneControl.addTab("Robots", panelRobotControl);
231
		tabPaneControl.addTab("Tasks", panelTaskManager);
232
		panelControl.add(tabPaneControl);
233
		
234
		// Set up elements in the south
235
		panelSouth = new JPanel();
236
		panelSouth.setLayout(new GridLayout(1,2));
237
		panelSouth.add(spLog);
238

  
239
		this.getContentPane().setLayout(new BorderLayout());
240
		this.getContentPane().add(panel, BorderLayout.CENTER);
241
		this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
242
		this.getContentPane().add(panelControl, BorderLayout.EAST);
243
		this.setVisible(true);
244
		
245
		btnAddTask.addActionListener(this);
246
		btnRemoveTask.addActionListener(this);
247
		btnMoveTaskUp.addActionListener(this);
248
		btnMoveTaskDown.addActionListener(this);
249
		btnGraph.addActionListener(this);
250
		btnConnect.addActionListener(this);
251
		panel.addMouseListener(this);
252
		
253
		
254
		// Get the graphics configuration of the screen to create a buffer
255
		gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
256
			.getDefaultScreenDevice().getDefaultConfiguration();
257
		image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
258
		canvas = image.createGraphics();
259
		canvas.setStroke(new BasicStroke(2));  //set pen width
260
		
261
		// Calculate center of canvas
262
		cx = image.getWidth() / 2;
263
		cy = image.getHeight() / 2;
264
		
265
		botFont = new Font("Arial", Font.PLAIN, 30);
266
		tokenLoc = 0;
267
		numBots = 0;
268
		selectedBot = 0;
269
		
270
		// Set up dependent threads
271
		indicator = new SelectionIndicator(canvas);
272
		indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
273
		packetMonitor = new PacketMonitor();
274
		datalistener = new DataListener();
275
	
276
	}
277
	
278
	public synchronized void paint (Graphics g)
279
	{
280
		/*	First, redraw the graphical components in the applet. 
281
			This paint method overrides the built-in paint of the 
282
			JApplet, and we don't want to deal with redrawing the
283
			components manually. Fuck that shit. */
284
		super.paint(g);
285
		
286
		// Place the buffered image on the screen, inside the panel
287
		panel.getGraphics().drawImage(image, 0, 0, Color.WHITE, this);
288
		
289
	}
290
	
291
	public synchronized void update (Graphics g)
292
	{
293
		paint(g);
294
	}
295
	
296
	public void actionPerformed (ActionEvent e)
297
	{
298
		Object source = e.getSource();
299
		if (source == btnGraph) {
300
			btnGraph.setEnabled(false);
301
			lblConnectionStatus.setText("Simulating");
302
			
303
			//Start dependent threads
304
			drawThread = new Thread(this, "drawThread");
305
			drawThread.start();
306
			indicator.start();
307
			packetMonitor.start();
308
		} else if (source == btnConnect) {
309
			doSocket();
310
		} else if (source == btnRemoveTask) {
311
			try {
312
				taskListModel.remove(taskList.getSelectedIndex());
313
			} catch (ArrayIndexOutOfBoundsException ex) {
314
			}
315
		}
316
	}
317
	
318
	private void randomize ()
319
	{
320
		Random r = new Random();
321
		StringBuilder s = new StringBuilder();
322
		
323
		int count = r.nextInt(8) + 1;
324
		for (int i = 0; i < count; i++)
325
		{
326
			for (int j = 0; j < count; j++)
327
			{
328
				if (r.nextBoolean())	
329
					s.append("" + (r.nextInt(16) + 1));
330
				else 
331
					s.append("-");
332
				if (j != count-1)
333
					s.append(" ");
334
			}
335
			if (i != count-1) s.append("\n");
336
		}
337
		
338
		txtInput.setText(s.toString());
339
	}
340
	
341
	private void doSocket ()
342
	{
343
		//make sure hostname and port are valid
344
		if (txtHost.getText().equals("") || txtPort.getText().equals("")) {
345
			err("Please enter a hostname and port.");
346
			return;
347
		}
348
		int port = 0;
349
		try {
350
			port = Integer.parseInt(txtPort.getText());
351
		} catch (Exception e) {
352
			err("Invalid port");
353
			return;
354
		}
355
		
356
		//make sure we aren't already connected. if so, disconnect first.
357
		if (socket != null && socket.isConnected()) {
358
			try {
359
				out.close();
360
				socket.close();
361
			} catch (IOException e) {}
362
		}
363
		
364
		try {
365
			socket = new Socket(txtHost.getText(), port);
366
		} catch (UnknownHostException e) {
367
			err("Unknown Host Exception");
368
			return;
369
		} catch (IOException e) {
370
			err("IO Exception\n\n" + e);
371
			return;
372
		} catch (java.security.AccessControlException e) {
373
			err("Permission denied by java.security.AccessControlException."
374
			+"\n\nYou may only connect to the server from which this applet was loaded.");
375
			return;
376
		}
377
		if (socket == null || !socket.isConnected()) {
378
			err("Connection failed. Try connecting again.");
379
			return;
380
		}
381
		msg("Connected to " + txtHost.getText() + " on port " + port + "\n");
382
		lblConnectionStatus.setText("Online");
383
		try {
384
			out = new OutputStreamWriter(socket.getOutputStream());
385
		} catch (IOException e) {
386
			warn("Could not get OutputStream from socket connection.");
387
		}
388
	
389
	}
390
	
391
	public void drawRobot (int id, int x, int y) 
392
	{
393
		//save the bot in memory, so we can tell if we click on it later
394
		botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
395
	
396
		//draw the bot on the canvas
397
		canvas.setColor(Color.BLACK);
398
		canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2);
399
		
400
		//draw the label
401
		canvas.setFont(botFont);
402
		canvas.drawString("" + id, x-10, y+10);
403
	}
404
	
405
	public void drawConnection (int start, int end, int radius, Color color)
406
	{
407
		final int ARROW_LENGTH = 18;
408
	
409
		double angle = 2.0 * Math.PI / numBots;
410
		int startx, starty, endx, endy;
411
		startx = cx - (int)(radius * Math.cos(start * angle));
412
		starty = cy - (int)(radius * Math.sin(start * angle));
413
		endx = cx - (int)(radius * Math.cos(end * angle));
414
		endy = cy - (int)(radius * Math.sin(end * angle));
415
		canvas.setColor(color);
416
		canvas.drawLine(startx, starty, endx, endy);
417
		
418
		//create arrow
419
		if (color.equals(Color.BLACK)) return;
420
		int big_dy = starty - endy;
421
		int big_dx = endx - startx;
422
		double theta = 0;
423
		if (big_dx == 0 && starty > endy) //pointing up
424
			theta = Math.PI/2;
425
		else if (big_dx == 0 && starty < endy) //pointing down 
426
			theta = 3*Math.PI/2;
427
		else if (big_dy == 0 && startx > endx) //pointing left
428
			theta = Math.PI;
429
		else if (big_dy == 0 && startx < endx) //pointing right
430
			theta = 0;
431
		else
432
			theta = Math.atan(1.0 * big_dy / big_dx);
433
		
434
		//create ploygon
435
		Polygon poly = new Polygon();
436
		int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta)));
437
		int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta)));
438
		int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta));
439
		int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
440
		int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
441
		int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
442
		//System.out.println("" + start + "->" + end + " : dx=" + big_dx + ",dy=" + big_dy + ",dy_arrow=" + dy_arrow + ",dx_arrow=" + dx_arrow + ",theta=" + theta + ",endx=" + endx + ",endy=" + endy + ",rx=" + rx + ",ry=" + ry);
443
		poly.addPoint(endx, endy);
444
		poly.addPoint(rx - dx_half, ry - dy_half);
445
		poly.addPoint(rx + dx_half, ry + dy_half);
446
		canvas.fillPolygon(poly);
447
	}
448
	
449
	public void run ()
450
	{
451
		while (true)
452
		{
453
			step();
454
			repaint();
455
			try { Thread.sleep(90); }
456
				catch (InterruptedException e) { return; }
457
		}
458
	}
459
	
460
	public void step () 
461
	{
462
		final int DIAMETER = image.getWidth() - 2*BUFFER;
463
		final int BIGRADIUS = DIAMETER / 2;
464
		final int TOKENRADIUS = 40;
465
		boolean valid;
466
	
467
		// clear image
468
		canvas.setColor(Color.WHITE);
469
		canvas.fillRect(0, 0, image.getWidth(), image.getHeight());
470
		
471
		// parse the matrix, to see what robots exist
472
		String [] rows = txtInput.getText().split("\n");
473
		numBots = rows.length;
474
		String [][] entries = new String[numBots][numBots];
475
		valid = true;
476
		for (int i = 0; i < numBots; i++) 
477
		{
478
			entries[i] = rows[i].split(" ");
479
			if (entries[i].length != rows.length) valid = false;
480
		}
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff