Project

General

Profile

Revision 427

Began adding functionality for clicking on robots in webcam view.

View differences:

trunk/code/projects/colonet/ColonetGUI/Colonet.java
10 10
import java.awt.event.*;
11 11
import java.net.*;
12 12
import java.io.*;
13
import java.util.Random;
13
import java.util.*;
14 14

  
15 15

  
16 16
/**
......
22 22
*/
23 23
public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener, Runnable {
24 24

  
25
	// Used for the robot graph
25
	// Used for images
26 26
	final int CANVAS_SIZE = 500;  //the applet may be slow if the canvas gets too large
27 27
	final int BUFFER = 50;
28 28
	final int RADIUS = 30;
......
42 42
	JTextArea txtInfo; 
43 43
	JPanel panelConnect;
44 44
	JPanel panelServerInterface;
45
	Socket socket;					
46
	OutputStreamWriter out;
47
	DataUpdater dataUpdater;  
45 48
	
46 49
	// South
47 50
	JPanel panelSouth;
......
62 65
	JPanel panelBattery;
63 66
	VectorController vectorController;
64 67
	BufferedImage imageVectorControl;
68
	JButton btnAssignID;
65 69
	JButton btnCommand_StopTask;
66 70
	JButton btnCommand_ResumeTask;
67 71
	JButton btnCommand_ChargeNow;
......
81 85
	JButton btnUpdateTasks;
82 86
	TaskAddWindow taskAddWindow;
83 87
	
84
	//Webcam and Graph
88
	//Webcam
85 89
	WebcamPanel panelWebcam;
86 90
	GraphicsPanel panelGraph;
87 91
	GraphicsConfiguration gc;
......
90 94
	int cx, cy;
91 95
	JTabbedPane tabPaneMain;
92 96
	
93
	
94
	Socket socket;					
95
	OutputStreamWriter out;
96
	DataUpdater dataUpdater;  
97
	
98 97
	Font botFont;
99
	volatile int tokenLoc;  //the token is currently here
100 98
	volatile int numBots;
101
	volatile int selectedBot;  //the user has selected this bot
102
	volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
99
	volatile int selectedBot;  //the user has selected this bot graphically
100
	volatile java.util.List <RobotIcon> robotIcons;  //contains boundary shapes around bots for click detection
103 101
	volatile int[] xbeeID;
104 102
	
105 103
	Thread drawThread;
......
109 107

  
110 108
	
111 109
	public void init () {
112
		// set the default look and feel - choose one
110
		// Set the default look and feel - choose one
113 111
        //String laf = UIManager.getSystemLookAndFeelClassName();
114 112
		String laf = UIManager.getCrossPlatformLookAndFeelClassName();
115 113
		//String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
......
160 158
		cx = image.getWidth() / 2;
161 159
		cy = image.getHeight() / 2;
162 160
		
161
		// Set up robots
163 162
		botFont = new Font("Arial", Font.PLAIN, 14);
164
		tokenLoc = 0;
165 163
		numBots = 0;
166 164
		selectedBot = 0;
165
		robotIcons = new ArrayList <RobotIcon> ();
167 166
		
168 167
		// Connection area
169 168
		txtMatrix = new JTextArea();
......
217 216
		panelRobotCommands.setLayout(new GridLayout(5,2));
218 217
		cmbRobotNum = new JComboBox();
219 218
		// Battery subset
220
		lblBattery = new JLabel();
221 219
		batteryIcon = new BatteryIcon(25);
222
		//batteryIcon = new BatteryIcon(50, lblBattery.getMaximumSize().height, lblBattery.getMaximumSize().height);
223 220
		lblBattery = new JLabel(batteryIcon);
221
		btnAssignID = new JButton("Assign ID");
224 222
		btnCommand_StopTask = new JButton("Stop Current Task");
225 223
		btnCommand_ResumeTask = new JButton("Resume Current Task");
226 224
		btnCommand_ChargeNow = new JButton("Recharge Now");
......
229 227
		panelRobotCommands.add(cmbRobotNum);
230 228
		panelRobotCommands.add(new JLabel("Battery Level: "));
231 229
		panelRobotCommands.add(lblBattery);
232
		panelRobotCommands.add(btnCommand_StopTask);
233
		panelRobotCommands.add(btnCommand_ResumeTask);
234
		panelRobotCommands.add(btnCommand_ChargeNow);
235
		panelRobotCommands.add(btnCommand_StopCharging);
230
		panelRobotCommands.add(btnAssignID);
231
		panelRobotCommands.add(new JLabel(""));  //make the items line up properly
232
		//panelRobotCommands.add(btnCommand_StopTask);
233
		//panelRobotCommands.add(btnCommand_ResumeTask);
234
		//panelRobotCommands.add(btnCommand_ChargeNow);
235
		//panelRobotCommands.add(btnCommand_StopCharging);
236 236
		panelRobotControl = new JPanel();
237 237
		panelRobotControl.setLayout(new GridLayout(2,1));
238 238
		panelRobotControl.add(panelRobotDirection);
......
317 317
		btnActivate.addActionListener(this);
318 318
		btnActivate.addKeyListener(this);
319 319
		cmbRobotNum.addKeyListener(this);
320
		vectorController.addMouseMotionListener(this);
321
		vectorController.addMouseListener(this);
322 320
		btnCommand_StopTask.addActionListener(this);
323 321
		btnCommand_ResumeTask.addActionListener(this);
324 322
		btnCommand_ChargeNow.addActionListener(this);
......
326 324
		// Other
327 325
		btnConnect.addActionListener(this);
328 326
		btnGetXBeeIDs.addActionListener(this);
329
		panelGraph.addMouseListener(this);
330
		this.addMouseMotionListener(this);	
327
		btnAssignID.addActionListener(this);
328
		panelWebcam.addMouseListener(this);	
331 329
				
332 330
		// Set up animation threads
333 331
		indicator = new SelectionIndicator(canvas);
......
340 338
			This paint method overrides the built-in paint of the 
341 339
			JApplet, and we don't want to deal with redrawing the
342 340
			components manually. Fuck that shit. */
343
		step();
344 341
		super.paint(g);
345 342
	}
346 343
	
......
348 345
		paint(g);
349 346
	}
350 347
	
351
	public void drawRobot (int id, int x, int y) {
352
		//save the bot in memory, so we can tell if we click on it later
353
		botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
354
	
355
		//draw the bot on the canvas
356
		canvas.setColor(Color.BLACK);
357
		canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2);
358
		
359
		//draw the label
360
		canvas.setFont(botFont);
361
		try {
362
			canvas.drawString("" + xbeeID[id], x-20, y+2);
363
		} catch (Exception e) {
364
			canvas.drawString("???", x-22, y+2);
365
		}
366
	}
367
	
368
	public void drawConnection (int start, int end, int radius, Color color) {
369
		final int ARROW_LENGTH = 18;
370
	
371
		double angle = 2.0 * Math.PI / numBots;
372
		int startx, starty, endx, endy;
373
		startx = cx - (int)(radius * Math.cos(start * angle));
374
		starty = cy - (int)(radius * Math.sin(start * angle));
375
		endx = cx - (int)(radius * Math.cos(end * angle));
376
		endy = cy - (int)(radius * Math.sin(end * angle));
377
		canvas.setColor(color);
378
		canvas.drawLine(startx, starty, endx, endy);
379
		
380
		//create arrow
381
		if (color.equals(Color.BLACK)) return;
382
		int big_dy = starty - endy;
383
		int big_dx = endx - startx;
384
		double theta = 0;
385
		if (big_dx == 0 && starty > endy) //pointing up
386
			theta = Math.PI/2;
387
		else if (big_dx == 0 && starty < endy) //pointing down 
388
			theta = 3*Math.PI/2;
389
		else if (big_dy == 0 && startx > endx) //pointing left
390
			theta = Math.PI;
391
		else if (big_dy == 0 && startx < endx) //pointing right
392
			theta = 0;
393
		else
394
			theta = Math.atan(1.0 * big_dy / big_dx);
395
		
396
		//create ploygon
397
		Polygon poly = new Polygon();
398
		int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta)));
399
		int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta)));
400
		int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta));
401
		int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
402
		int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
403
		int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
404
		poly.addPoint(endx, endy);
405
		poly.addPoint(rx - dx_half, ry - dy_half);
406
		poly.addPoint(rx + dx_half, ry + dy_half);
407
		canvas.fillPolygon(poly);
408
	}
409
	
410 348
	public void run () {
411 349
		while (true) {
412 350
			repaint();
......
417 355
			}
418 356
		}
419 357
	}
420
	
421
	private void step () {
422
		final int DIAMETER = image.getWidth() - 2*BUFFER;
423
		final int BIGRADIUS = DIAMETER / 2;
424
		final int TOKENRADIUS = 40;
425
		boolean valid;
426
	
427
		// clear image
428
		canvas.setColor(Color.WHITE);
429
		canvas.fillRect(0, 0, image.getWidth(), image.getHeight());
430 358
		
431
		// parse the matrix, to see what robots exist
432
		String [] rows = txtMatrix.getText().split("\n");
433
		numBots = rows.length;
434
		String [][] entries = new String[numBots][numBots];
435
		valid = true;
436
		for (int i = 0; i < numBots; i++) {
437
			entries[i] = rows[i].split(" ");
438
			if (entries[i].length != rows.length) valid = false;
439
		}
440
		
441
		if (valid) {
442
			this.showStatus("Running");
443
			
444
			// draw robots and find which one is seleced
445
			double angle = 2.0 * Math.PI / numBots;
446
			canvas.setColor(Color.BLACK);
447
			botRect = new Rectangle[numBots];
448
			int x, y;
449
			if (selectedBot >= numBots) selectedBot = 0;
450
			for (int i = 0; i < numBots; i++) {
451
				x = cx - (int)(BIGRADIUS * Math.cos(i * angle));
452
				y = cy - (int)(BIGRADIUS * Math.sin(i * angle));
453
				drawRobot(i, x, y);
454
				if (i == selectedBot) indicator.setCenter(x, y);
455
			}
456
			
457
			// draw token marker
458
			int tokenx, tokeny;
459
			int tokenNum = tokenLoc;
460
			tokenx = cx - (int)(BIGRADIUS * Math.cos(tokenNum * angle));
461
			tokeny = cy - (int)(BIGRADIUS * Math.sin(tokenNum * angle));
462
			canvas.setColor(Color.RED);
463
			canvas.drawOval(tokenx-TOKENRADIUS, tokeny-TOKENRADIUS, 2*TOKENRADIUS, 2*TOKENRADIUS);
464
			
465
			// create an inner circle along which the connections are made.
466
			// let the diameter of this circle be 2*RADIUS less than the outerDiameter.
467
			// see what connections exist
468
			for (int row = 0; row < numBots; row++) {
469
				for(int col = 0; col < numBots; col++) {
470
					if (!entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) {
471
						//TODO: Make a standard gray
472
						drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200));
473
					} else if (!entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) {
474
						drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
475
					}
476
				}
477
			}
478
			
479
			// draw the selection indicator
480
			indicator.draw();
481
			
482
		} else {  // if matrix is not valid
483
			this.showStatus("Error: Invalid matrix");
484
		}
485
	
486
	}
487
	
488 359
	/** 
489 360
	* Gets the JTextArea used for storing the activity log. This method returns a reference to the 
490 361
	* JTextArea that stores the log. The log can contain any activity that is revelant to the use
......
647 518
	public void mouseEntered(MouseEvent e) {
648 519
	}
649 520
	public void mouseReleased(MouseEvent e) {
650
		vectorController.notifyMouseEvent(e, true);
651 521
	}
652 522
	public void mouseClicked(MouseEvent e) {
653
		vectorController.notifyMouseEvent(e, false);
654 523
	}
655 524
	public void mousePressed(MouseEvent e) {
656
		try {
657
			for (int i = 0; i < numBots; i++) {
658
				if (botRect[i].contains(e.getPoint())) {
659
					selectedBot = i;
660
					cmbRobotNum.setSelectedIndex(i+1);
661
				}
662
			}
663
		} catch (Exception ex) {
664
		}
525
		System.out.println(e);
665 526
	}
666 527
	public void mouseDragged(MouseEvent e) {
667
		vectorController.notifyMouseEvent(e, false);
668 528
	}
669 529
	public void mouseMoved(MouseEvent e) {
670 530
	}
......
703 563
	public void actionPerformed (ActionEvent e) {
704 564
		Object source = e.getSource();
705 565
		
706
		//Connection
566
		// General Actions
707 567
		if (source == btnConnect) {
708 568
			connect();
709 569
		} else if (source == btnGetXBeeIDs) {
710 570
			csi.sendXBeeIDRequest();
571
		} else if (source == btnAssignID) {
572
		    String message;
573
			
711 574
		}
712 575
		
713 576
		// Robot Movement Controls
......
983 846
		int BORDER = 16;  // this is arbitrary. it makes the image look nice inside a border.
984 847
		int BOT_RADIUS = 40;
985 848
		volatile BufferedImage img;
986
		volatile Point [] points;
987 849
	
988 850
		public WebcamPanel () {
989 851
			super();
......
995 857
				img = null;
996 858
				img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
997 859
			}
998
			System.gc();
999 860
			img = newimg;
1000 861
		}
1001 862
		
1002 863
		public synchronized void setPoints (Point [] newpoints) {
1003
			this.points = newpoints;
864
			// test code -- need to remove later
865
			if (newpoints == null) {
866
				Point [] p = new Point [3];
867
				p[0] = new Point(100,150);
868
				p[1] = new Point(200,200);
869
				p[2] = new Point(400,300);
870
				setPoints(p);
871
				return;
872
			}
873
			
874
			for (int i = 0; i < newpoints.length; i++) {
875
				Point p = newpoints[i];
876
				boolean found = false;
877
				for (int j = 0; j < robotIcons.size(); j++) {
878
					RobotIcon r = robotIcons.get(i);
879
					if (r.isClose(p.x, p.y)) {
880
						r.move(p.x, p.y);
881
						found = true;
882
					}
883
				}
884
				if (!found) {
885
					RobotIcon r = new RobotIcon(p.x, p.y);
886
					robotIcons.add(r);
887
					System.out.println("Added " + r);
888
				}
889
			}
890
			
1004 891
		}
1005 892
		
1006 893
		public synchronized void paint (Graphics g) {
......
1021 908
						);
1022 909
						
1023 910
			// Draw Identifiers
1024
			if (points == null)
911
			if (robotIcons == null)
1025 912
				return;
1026
			g.setColor(Color.RED);
1027 913
			((Graphics2D)g).setStroke(new BasicStroke(2));
1028
			for (int i = 0; i < points.length; i++) {
1029
				g.drawOval(points[i].x - BOT_RADIUS, points[i].y - BOT_RADIUS, 2*BOT_RADIUS, 2*BOT_RADIUS);
914
			for (int i = 0; i < robotIcons.size(); i++) {
915
				RobotIcon r = robotIcons.get(i);
916
				g.setColor(r.color);
917
				g.drawOval(r.x, r.y, 2*r.RADIUS, 2*r.RADIUS);
918
				System.out.println("Painted: " + r);
1030 919
			}
1031 920
			
1032 921
		}
......
1074 963
					Thread.sleep(WEBCAMLOADER_DELAY);
1075 964
					if (image != null) 
1076 965
						image.flush();
1077
					System.gc();
1078 966
					image = ImageIO.read(imagePath);
1079 967
					// The MediaTracker waitForID pauses the thread until the image is loaded.
1080 968
					// We don't want to display a half-downloaded image.
......
1083 971
					mt.removeImage(image);
1084 972
					// Save
1085 973
					panelWebcam.setImage(image);
1086
					parseLocations(locationsPath.toURL());
974
					//parseLocations(locationsPath.toURL());
975
					panelWebcam.setPoints(null);  //temporary simulation code
1087 976
				} catch (InterruptedException e) {
1088 977
					return;
1089 978
				} catch (java.security.AccessControlException e) {
......
1132 1021
			
1133 1022
		}
1134 1023
	}
1024
	
1025
	/*
1026
	*  RobotIcon class
1027
	*  Provides a means for graphically representing and keeping track of webcam bots.
1028
	*/
1029
	class RobotIcon {
1030
		public final int RADIUS = 30;
1031
		public final int CLOSE = 40;
1032
		
1033
		public int x, y;
1034
		public int id;
1035
		public Color color;
1036
		
1037
		public RobotIcon (int x, int y) {
1038
			this.id = -1;
1039
			this.color = Color.RED;
1040
			this.x = x;
1041
			this.y = y;
1042
		}
1043
		
1044
		public void move (int newX, int newY) {
1045
			this.x = newX;
1046
			this.y = newY;
1047
		}
1048
		
1049
		public boolean isClose (int nx, int ny) {
1050
			int dist = (int) Point.distance(this.x, this.y, nx, ny);
1051
			return (dist < CLOSE);
1052
		}
1053
		
1054
		public String toString () {
1055
			String s = "RobotIcon at (" + x + "," + y + "), id " + id;
1056
			return s;
1057
		}
1058
		
1059
	}
1135 1060

  
1136 1061
	
1137 1062
	/*
1138 1063
	*	VectorController class
1139 1064
	*	Manages robot motion control graphically
1140 1065
	*/
1141
	class VectorController extends GraphicsPanel {
1066
	class VectorController extends GraphicsPanel implements MouseListener, MouseMotionListener {
1142 1067
		int x, y, cx, cy;
1143 1068
		int width, height;
1144 1069
		int side;
......
1155 1080
				side = width;
1156 1081
			else
1157 1082
				side = height;
1083
			this.addMouseListener(this);
1084
			this.addMouseMotionListener(this);
1158 1085
		}
1159 1086
		
1160 1087
		public void setPoint (int x, int y) {
......
1180 1107
				vectorController.sendToServer();
1181 1108
		}
1182 1109
		
1110
		public void mouseExited(MouseEvent e) {
1111
		}
1112
		public void mouseEntered(MouseEvent e) {
1113
		}
1114
		public void mouseReleased(MouseEvent e) {
1115
			this.notifyMouseEvent(e, true);
1116
		}
1117
		public void mouseClicked(MouseEvent e) {
1118
			this.notifyMouseEvent(e, false);
1119
		}
1120
		public void mousePressed(MouseEvent e) {
1121
		}
1122
		public void mouseDragged(MouseEvent e) {
1123
			vectorController.notifyMouseEvent(e, false);
1124
		}
1125
		public void mouseMoved(MouseEvent e) {
1126
		}
1127
		
1183 1128
		public int getSpeed () {
1184 1129
			int dx = x - cx;
1185 1130
			int dy = y - cy;
......
1293 1238
		JScrollPane spAvailableTasks;
1294 1239
		JTextArea txtDescription;
1295 1240
		JTextField txtParameters;
1296
		MouseListener mouseListener;
1297 1241
		
1298 1242
		public TaskAddWindow () {
1299 1243
			super("Add a Task");
......
1393 1337
	
1394 1338
	}
1395 1339
	
1340
	/*
1341
	*  BatteryIcon class
1342
	*  Graphical representation of battery level
1343
	*/
1396 1344
	class BatteryIcon implements Icon {
1397 1345
		private int width;
1398 1346
	    private int height;
......
1483 1431
	}
1484 1432

  
1485 1433

  
1434

  
1486 1435
}

Also available in: Unified diff