Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / ColonetGUI / Colonet.java @ 107

History | View | Annotate | Download (23.5 KB)

1 32 gtress
//
2
//  Colonet.java
3
//
4
5
import javax.swing.*;
6
import java.awt.*;
7
import java.awt.image.*;
8
import java.awt.event.*;
9
import java.net.*;
10
import java.io.*;
11
import java.util.Random;
12
import java.applet.*;
13
14
public class Colonet extends JApplet implements ActionListener, MouseListener, Runnable {
15
16
        final int CANVAS_SIZE = 500;  //don't make this too large, or the applet will be slow.
17
        final int BUFFER = 50;
18
        final int RADIUS = 30;
19
20
        // Connection
21
        JTextField txtHost;
22
        JTextField txtPort;
23
        JButton btnConnect;
24
        JButton btnGraph;
25
        JLabel lblConnectionStatus;
26 76 gtress
        JTextArea txtMatrix;
27 32 gtress
        JTextArea txtInfo;
28
        JPanel panelConnect;
29
        JPanel panelServerInterface;
30
31
        // Stats
32
        JLabel lblBattery;
33
        JLabel lblTokenPasses;
34
        JLabel lblHastToken;
35
        JPanel panelStats;
36
37
        // South
38
        JPanel panelSouth;
39
        JTextArea log;
40
        JScrollPane spLog;
41
42
        // Control
43
        JPanel panelControl;
44
        JTabbedPane tabPaneControl;
45
        JPanel panelRobotControl;
46
        JPanel panelRobotDirection;
47
        JPanel panelRobotCommands;
48
        JButton btnF, btnB, btnL, btnR, btnActivate;
49 67 gtress
        JComboBox cmbRobotNum;
50 32 gtress
51
        // Task Manager
52
        JPanel panelTaskManager;
53
        JScrollPane spTaskManager;
54
        JPanel panelTaskManagerControls;
55
        JPanel panelTaskManagerControlsPriority;
56
        DefaultListModel taskListModel;
57
        JList taskList;
58
        JButton btnAddTask;
59
        JButton btnRemoveTask;
60
        JButton btnMoveTaskUp;
61
        JButton btnMoveTaskDown;
62
63
        // Graphics
64
        JPanel panel;
65
        GraphicsConfiguration gc;
66
        volatile BufferedImage image;
67
        volatile Graphics2D canvas;
68
        int cx, cy;
69
70
        Socket socket;
71
        OutputStreamWriter out;                        //TODO: add a BufferedWriter
72 76 gtress
        DataUpdater dataUpdater;
73 32 gtress
74
        Font botFont;
75
        Random random = new Random();
76
        volatile int tokenLoc;  //the token is currently here
77
        volatile int numBots;
78
        volatile int selectedBot;  //the user has selected this bot
79
        volatile Rectangle[] botRect;  //contains boundary shapes around bots for click detection
80
81
        Thread drawThread;
82 76 gtress
        Simulator simulator;
83 32 gtress
        SelectionIndicator indicator;
84
        PacketMonitor packetMonitor;
85 35 gtress
        ColonetServerInterface csi;
86 32 gtress
87
88
        public void init () {
89
                // set the default look and feel
90
        String laf = UIManager.getSystemLookAndFeelClassName();
91
        try {
92
            UIManager.setLookAndFeel(laf);
93
        } catch (UnsupportedLookAndFeelException exc) {
94
            System.err.println ("Warning: UnsupportedLookAndFeel: " + laf);
95
        } catch (Exception exc) {
96
            System.err.println ("Error loading " + laf + ": " + exc);
97
        }
98
                // We should invoke and wait to avoid browser display difficulties
99
                Runnable r = new Runnable() {
100
                        public void run() {
101
                                createAndShowGUI();
102
                        }
103
                };
104
                try {
105
                        SwingUtilities.invokeAndWait(r);
106
                } catch (InterruptedException e) {
107
                        //Not really sure why we would be in this situation
108
                        System.out.println(e);
109
                } catch (java.lang.reflect.InvocationTargetException e) {
110
                        //This should never happen. Seriously.
111
                        System.out.println(e);
112
                }
113
        }
114
115
        public void destroy () {
116
                try { drawThread.interrupt(); } catch (Exception e) { }
117
                try { indicator.interrupt(); } catch (Exception e) { }
118
                try { packetMonitor.interrupt(); } catch (Exception e) { }
119
        }
120
121
        private synchronized void createAndShowGUI () {
122
                // init graphical elements
123
                panel = new JPanel(false);  //set automatic double-buffering to false. we are doing it manually.
124
125
                // Connection area
126 76 gtress
                txtMatrix = new JTextArea("- 9 3 - 1\n- - - 5 -\n4 - - - 2\n- - - - -\n1 - - 3 -");
127
                txtMatrix.setBorder(BorderFactory.createTitledBorder("Input Matrix"));
128 32 gtress
                txtInfo = new JTextArea();
129
                txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
130
                txtInfo.setEditable(false);
131
                btnGraph = new JButton("Run");
132
                txtHost = new JTextField("roboclub1.frc.ri.cmu.edu");
133
                txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
134
                txtPort = new JTextField("10123");
135
                txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
136
                btnConnect = new JButton("Connect");
137
                lblConnectionStatus = new JLabel("Status: Offline");
138
                panelConnect = new JPanel();
139
                panelConnect.setLayout(new GridLayout(6,1));
140
                panelConnect.add(lblConnectionStatus);
141
                panelConnect.add(txtHost);
142
                panelConnect.add(txtPort);
143
                panelConnect.add(btnConnect);
144
                panelConnect.add(txtInfo);
145
                panelConnect.add(btnGraph);
146
                panelServerInterface = new JPanel();
147
                panelServerInterface.setLayout(new GridLayout(2,1));
148
                panelServerInterface.add(panelConnect);
149 76 gtress
                panelServerInterface.add(txtMatrix);
150 32 gtress
151
                // Status Elements
152
                lblTokenPasses = new JLabel();
153
                lblBattery = new JLabel("???");
154
                panelStats = new JPanel();
155
                panelStats.setLayout(new GridLayout(4,2));
156
                panelStats.add(new JLabel("Token Passes / sec          "));
157
                panelStats.add(lblTokenPasses);
158
                panelStats.add(new JLabel("Battery     "));
159
                panelStats.add(lblBattery);
160
                panelStats.add(new JLabel("Token Passes / sec     "));
161
                panelStats.add(lblTokenPasses);
162
163 72 gtress
                //TODO: add panelStats somewhere?
164 32 gtress
165
                // Robot direction panel
166
                panelRobotDirection = new JPanel();
167
                btnF = new JButton("^");
168
                btnB = new JButton("v");
169
                btnL = new JButton("<");
170
                btnR = new JButton(">");
171
                btnActivate = new JButton("o");
172
                panelRobotDirection = new JPanel();
173
                panelRobotDirection.setLayout(new GridLayout(3,3));
174
                panelRobotDirection.add(new JLabel(""));
175
                panelRobotDirection.add(btnF);
176
                panelRobotDirection.add(new JLabel(""));
177
                panelRobotDirection.add(btnL);
178
                panelRobotDirection.add(btnActivate);
179
                panelRobotDirection.add(btnR);
180
                panelRobotDirection.add(new JLabel(""));
181
                panelRobotDirection.add(btnB);
182
                panelRobotDirection.add(new JLabel(""));
183
184
                // Robot Control and Commands
185
                panelRobotCommands = new JPanel();
186
                panelRobotCommands.setLayout(new FlowLayout());
187 67 gtress
                cmbRobotNum = new JComboBox();
188
                panelRobotCommands.add(cmbRobotNum);
189 32 gtress
                panelRobotCommands.add(new JLabel("Commands go here"));
190
                panelRobotControl = new JPanel();
191
                panelRobotControl.setLayout(new GridLayout(2,1));
192
                panelRobotControl.add(panelRobotDirection);
193
                panelRobotControl.add(panelRobotCommands);
194
195
                // Task Manager
196
                panelTaskManager = new JPanel();
197
                panelTaskManager.setLayout(new BorderLayout());
198
                taskListModel = new DefaultListModel();
199
                taskListModel.addElement("Map the Environment");
200
                taskListModel.addElement("Clean Up Chemical Spill");
201
                taskListModel.addElement("Grow Plants");
202
                taskListModel.addElement("Save the Cheerleader");
203
                taskListModel.addElement("Save the World");
204
                taskList = new JList(taskListModel);
205
                taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
206
                taskList.setSelectedIndex(0);
207
                spTaskManager = new JScrollPane(taskList);
208
                panelTaskManagerControls = new JPanel();
209
                panelTaskManagerControls.setLayout(new GridLayout(1,3));
210
                panelTaskManagerControlsPriority = new JPanel();
211
                panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
212
                btnAddTask = new JButton("Add...");
213
                btnRemoveTask = new JButton("Remove");
214
                btnMoveTaskUp = new JButton("^");
215
                btnMoveTaskDown = new JButton("v");
216
                panelTaskManagerControlsPriority.add(btnMoveTaskUp);
217
                panelTaskManagerControlsPriority.add(btnMoveTaskDown);
218
                panelTaskManagerControls.add(btnAddTask);
219
                panelTaskManagerControls.add(btnRemoveTask);
220
                panelTaskManagerControls.add(panelTaskManagerControlsPriority);
221
                panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
222
                panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
223
                panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
224
225
                // Message log
226
                log = new JTextArea();
227
                spLog = new JScrollPane(log,
228
                        ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
229
                        ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
230
                spLog.setBorder(BorderFactory.createTitledBorder("Log"));
231
                spLog.setPreferredSize(new Dimension(0, 150));
232
                log.setEditable(false);
233
234
                // Main control mechanism
235
                panelControl = new JPanel();
236
                panelControl.setLayout(new GridLayout(1,1));
237
                tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
238
                tabPaneControl.setPreferredSize(new Dimension(300, 0));
239
                tabPaneControl.addTab("Connection", panelServerInterface);
240
                tabPaneControl.addTab("Robots", panelRobotControl);
241
                tabPaneControl.addTab("Tasks", panelTaskManager);
242
                panelControl.add(tabPaneControl);
243
244
                // Set up elements in the south
245
                panelSouth = new JPanel();
246
                panelSouth.setLayout(new GridLayout(1,2));
247
                panelSouth.add(spLog);
248
249
                this.getContentPane().setLayout(new BorderLayout());
250
                this.getContentPane().add(panel, BorderLayout.CENTER);
251
                this.getContentPane().add(panelSouth, BorderLayout.SOUTH);
252
                this.getContentPane().add(panelControl, BorderLayout.EAST);
253
                this.setVisible(true);
254
255 72 gtress
                /* Add all listeners here */
256
                // Task Management
257 32 gtress
                btnAddTask.addActionListener(this);
258
                btnRemoveTask.addActionListener(this);
259
                btnMoveTaskUp.addActionListener(this);
260
                btnMoveTaskDown.addActionListener(this);
261 72 gtress
                // Robot Control
262
                btnF.addActionListener(this);
263
                btnB.addActionListener(this);
264
                btnL.addActionListener(this);
265
                btnR.addActionListener(this);
266
                btnActivate.addActionListener(this);
267
                // Other
268 32 gtress
                btnGraph.addActionListener(this);
269
                btnConnect.addActionListener(this);
270
                panel.addMouseListener(this);
271
272
273
                // Get the graphics configuration of the screen to create a buffer
274
                gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
275
                        .getDefaultScreenDevice().getDefaultConfiguration();
276
                image = gc.createCompatibleImage(CANVAS_SIZE,CANVAS_SIZE);
277
                canvas = image.createGraphics();
278
                canvas.setStroke(new BasicStroke(2));  //set pen width
279
280
                // Calculate center of canvas
281
                cx = image.getWidth() / 2;
282
                cy = image.getHeight() / 2;
283
284
                botFont = new Font("Arial", Font.PLAIN, 30);
285
                tokenLoc = 0;
286
                numBots = 0;
287
                selectedBot = 0;
288
289
                // Set up dependent threads
290
                indicator = new SelectionIndicator(canvas);
291
                indicator.setRadius(RADIUS+3, 15);  //a tad more than the bot radius
292
                packetMonitor = new PacketMonitor();
293 76 gtress
                simulator = new Simulator();
294 35 gtress
295 76 gtress
                csi = new ColonetServerInterface(log, txtMatrix);
296 32 gtress
297
        }
298
299 35 gtress
        public synchronized void paint (Graphics g) {
300 32 gtress
                /*        First, redraw the graphical components in the applet.
301
                        This paint method overrides the built-in paint of the
302
                        JApplet, and we don't want to deal with redrawing the
303
                        components manually. Fuck that shit. */
304
                super.paint(g);
305
306
                // Place the buffered image on the screen, inside the panel
307
                panel.getGraphics().drawImage(image, 0, 0, Color.WHITE, this);
308
309
        }
310
311 35 gtress
        public synchronized void update (Graphics g) {
312 32 gtress
                paint(g);
313
        }
314
315 35 gtress
        public void actionPerformed (ActionEvent e) {
316 32 gtress
                Object source = e.getSource();
317
                if (source == btnGraph) {
318
                        btnGraph.setEnabled(false);
319
                        lblConnectionStatus.setText("Simulating");
320
321
                        //Start dependent threads
322
                        drawThread = new Thread(this, "drawThread");
323
                        drawThread.start();
324
                        indicator.start();
325
                        packetMonitor.start();
326 76 gtress
                        simulator.start();
327 32 gtress
                } else if (source == btnConnect) {
328
                        doSocket();
329 76 gtress
                        dataUpdater = new DataUpdater();
330
                        dataUpdater.start();
331 32 gtress
                } else if (source == btnRemoveTask) {
332
                        try {
333
                                taskListModel.remove(taskList.getSelectedIndex());
334
                        } catch (ArrayIndexOutOfBoundsException ex) {
335
                        }
336 72 gtress
337
                // Robot controls
338
                } else if (source == btnF) {
339
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
340
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
341
                } else if (source == btnB) {
342
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
343
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
344
                } else if (source == btnL) {
345
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
346
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
347
                } else if (source == btnR) {
348
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", ColonetServerInterface.GLOBAL_DEST);
349
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", ColonetServerInterface.GLOBAL_DEST);
350
                } else if (source == btnActivate) {
351
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 0", ColonetServerInterface.GLOBAL_DEST);
352
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 0", ColonetServerInterface.GLOBAL_DEST);
353 107 gtress
354
355
                // Queue Management
356
                } else if (source == btnAddTask) {
357
                        String description = JOptionPane.showInputDialog("Description of new task");
358
                        String data = JOptionPane.showInputDialog("Command and data for new task");
359
                        csi.sendQueueAdd(0, data, description);
360
                } else if (source == btnRemoveTask) {
361
                        csi.sendQueueRemove(0);
362
                } else if (source == btnMoveTaskUp) {
363
                        csi.sendQueueReorder(0, 1);
364
                } else if (source == btnMoveTaskDown) {
365
366
367 32 gtress
                }
368
        }
369
370 35 gtress
        private void randomize () {
371 32 gtress
                Random r = new Random();
372
                StringBuilder s = new StringBuilder();
373
374
                int count = r.nextInt(8) + 1;
375 35 gtress
                for (int i = 0; i < count; i++) {
376
                        for (int j = 0; j < count; j++) {
377 32 gtress
                                if (r.nextBoolean())
378
                                        s.append("" + (r.nextInt(16) + 1));
379
                                else
380
                                        s.append("-");
381
                                if (j != count-1)
382
                                        s.append(" ");
383
                        }
384
                        if (i != count-1) s.append("\n");
385
                }
386
387 76 gtress
                txtMatrix.setText(s.toString());
388 32 gtress
        }
389
390 35 gtress
        private void doSocket () {
391
                csi.connect(txtHost.getText(), txtPort.getText());
392 32 gtress
        }
393
394 35 gtress
        public void drawRobot (int id, int x, int y) {
395 32 gtress
                //save the bot in memory, so we can tell if we click on it later
396
                botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
397
398
                //draw the bot on the canvas
399
                canvas.setColor(Color.BLACK);
400
                canvas.drawOval(x-RADIUS, y-RADIUS, RADIUS*2, RADIUS*2);
401
402
                //draw the label
403
                canvas.setFont(botFont);
404
                canvas.drawString("" + id, x-10, y+10);
405
        }
406
407 35 gtress
        public void drawConnection (int start, int end, int radius, Color color) {
408 32 gtress
                final int ARROW_LENGTH = 18;
409
410
                double angle = 2.0 * Math.PI / numBots;
411
                int startx, starty, endx, endy;
412
                startx = cx - (int)(radius * Math.cos(start * angle));
413
                starty = cy - (int)(radius * Math.sin(start * angle));
414
                endx = cx - (int)(radius * Math.cos(end * angle));
415
                endy = cy - (int)(radius * Math.sin(end * angle));
416
                canvas.setColor(color);
417
                canvas.drawLine(startx, starty, endx, endy);
418
419
                //create arrow
420
                if (color.equals(Color.BLACK)) return;
421
                int big_dy = starty - endy;
422
                int big_dx = endx - startx;
423
                double theta = 0;
424
                if (big_dx == 0 && starty > endy) //pointing up
425
                        theta = Math.PI/2;
426
                else if (big_dx == 0 && starty < endy) //pointing down
427
                        theta = 3*Math.PI/2;
428
                else if (big_dy == 0 && startx > endx) //pointing left
429
                        theta = Math.PI;
430
                else if (big_dy == 0 && startx < endx) //pointing right
431
                        theta = 0;
432
                else
433
                        theta = Math.atan(1.0 * big_dy / big_dx);
434
435
                //create ploygon
436
                Polygon poly = new Polygon();
437
                int dx_arrow = Math.abs((int)(ARROW_LENGTH * Math.cos(theta)));
438
                int dy_arrow = Math.abs((int)(ARROW_LENGTH * Math.sin(theta)));
439
                int dy_half = (int)(ARROW_LENGTH/2 * Math.cos(theta));
440
                int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
441
                int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
442
                int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
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 35 gtress
        public void run () {
450
                while (true) {
451 32 gtress
                        step();
452
                        repaint();
453 35 gtress
                        try {
454
                                Thread.sleep(90);
455
                        } catch (InterruptedException e) {
456
                                return;
457
                        }
458 32 gtress
                }
459
        }
460
461 35 gtress
        public void step () {
462 32 gtress
                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 76 gtress
                String [] rows = txtMatrix.getText().split("\n");
473 32 gtress
                numBots = rows.length;
474
                String [][] entries = new String[numBots][numBots];
475
                valid = true;
476 35 gtress
                for (int i = 0; i < numBots; i++) {
477 32 gtress
                        entries[i] = rows[i].split(" ");
478
                        if (entries[i].length != rows.length) valid = false;
479
                }
480
481 35 gtress
                if (valid) {
482 38 gtress
                        this.showStatus("Running");
483 32 gtress
484
                        // draw robots and find which one is seleced
485
                        double angle = 2.0 * Math.PI / numBots;
486
                        canvas.setColor(Color.BLACK);
487
                        botRect = new Rectangle[numBots];
488
                        int x, y;
489
                        if (selectedBot >= numBots) selectedBot = 0;
490 35 gtress
                        for (int i = 0; i < numBots; i++) {
491 32 gtress
                                x = cx - (int)(BIGRADIUS * Math.cos(i * angle));
492
                                y = cy - (int)(BIGRADIUS * Math.sin(i * angle));
493
                                drawRobot(i, x, y);
494
                                if (i == selectedBot) indicator.setCenter(x, y);
495
                        }
496
497
                        // draw token marker
498
                        int tokenx, tokeny;
499
                        int tokenNum = tokenLoc;
500
                        tokenx = cx - (int)(BIGRADIUS * Math.cos(tokenNum * angle));
501
                        tokeny = cy - (int)(BIGRADIUS * Math.sin(tokenNum * angle));
502
                        canvas.setColor(Color.RED);
503
                        canvas.drawOval(tokenx-TOKENRADIUS, tokeny-TOKENRADIUS, 2*TOKENRADIUS, 2*TOKENRADIUS);
504
505
                        // create an inner circle along which the connections are made.
506
                        // let the diameter of this circle be 2*RADIUS less than the outerDiameter.
507
                        // see what connections exist
508 35 gtress
                        for (int row = 0; row < numBots; row++) {
509
                                for(int col = 0; col < numBots; col++) {
510
                                        if (!entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) {
511
                                                //TODO: Make a standard gray
512 32 gtress
                                                drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200));
513 38 gtress
                                        } else if (!entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) {
514 32 gtress
                                                drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
515
                                        }
516
                                }
517
                        }
518
519
                        // draw the selection indicator
520
                        indicator.draw();
521
522 35 gtress
                } else {// if matrix is not valid
523 32 gtress
                        this.showStatus("Error: Invalid matrix");
524
                }
525
526
        }
527
528
        /*        At this point, moveToken is only called by the simulator.
529
        *        In the future, it can be rewritten to account for non-standard
530
        *        token passing or deleted if the information can be retrieved
531
        *        directly from the Colonet server instead.
532
        */
533 35 gtress
        public void moveToken () {
534
                try {
535
                        tokenLoc = (tokenLoc+1)%numBots;
536
                } catch (ArithmeticException e) {  // in case numRobots is zero
537
                }
538 32 gtress
539
                packetMonitor.addTokenPass();
540
        }
541
542
        //
543
        // MouseEvent methods
544
        //
545
        public void mouseExited(MouseEvent e) {}
546
        public void mouseEntered(MouseEvent e) {}
547
        public void mouseReleased(MouseEvent e) {}
548
        public void mouseClicked(MouseEvent e) {}
549 35 gtress
        public void mousePressed(MouseEvent e) {
550 32 gtress
                try {
551 35 gtress
                        for (int i = 0; i < numBots; i++) {
552 32 gtress
                                if (botRect[i].contains(e.getPoint()))
553
                                        selectedBot = i;
554
                        }
555
                } catch (Exception ex) {
556
                        System.out.println(e);
557
                }
558
559
        }
560
561
        /*
562
        *        SelectionIndicator thread.
563
        *        Graphical representation of the selection marker
564
        *
565
        *        step() and draw() are synchronized methods. step() is private and
566
        *        used to update the position of the crosshairs. draw() is called
567
        *        externally and should only run if all calculations in step() have
568
        *        been completed.
569
        */
570 35 gtress
        private class SelectionIndicator extends Thread {
571 32 gtress
572
                final int INDICATOR_DELAY = 100;
573
                final double DTHETA = 0.3;    //larger values make the marker rotate faster
574
                Graphics2D g;   //canvas to draw on
575
                boolean running;
576
577
                int sx, sy;                //center
578
                int r, dr;                //radius and width of marker
579
                double theta;   //current angle
580
581
                volatile Polygon poly1, poly2, poly3, poly4;
582
583
                int px1, py1;
584
                int rx1, ry1;
585
                int px2, py2;
586
                int rx2, ry2;
587
                int px3, py3;
588
                int rx3, ry3;
589
                int px4, py4;
590
                int rx4, ry4;
591
592
                int steps;
593
594 35 gtress
                public SelectionIndicator (Graphics2D g) {
595 32 gtress
                        super("SelectionIndicator");
596
                        this.g = g;
597
                        running = false;
598
                        steps = 0;
599
600
                        theta = 0;
601
                        rx1 = 0; ry1 = 0;
602
                        px1 = 0; py1 = 0;
603
                        rx2 = 0; ry2 = 0;
604
                        px2 = 0; py2 = 0;
605
                        rx3 = 0; ry3 = 0;
606
                        px3 = 0; py3 = 0;
607
                        rx4 = 0; ry4 = 0;
608
                        px4 = 0; py4 = 0;
609
                }
610
611 35 gtress
                public synchronized void setCenter (int sx, int sy) {
612 32 gtress
                        if (sx == this.sx && sy == this.sy) return;
613
                        this.sx = sx;
614
                        this.sy = sy;
615
                        steps = 0;
616
                }
617
618 35 gtress
                public synchronized void setRadius (int r, int dr) {
619 32 gtress
                        this.r = r;
620
                        this.dr = dr;
621
                        steps = 0;
622
                }
623
624 35 gtress
                public void run () {
625 32 gtress
                        running = true;
626 35 gtress
                        while (running) {
627 32 gtress
                                step();
628 35 gtress
                                try {
629
                                        Thread.sleep(INDICATOR_DELAY);
630
                                } catch (InterruptedException e) {
631
                                        running = false;
632
                                        return;
633
                                }
634 32 gtress
                        }
635
                }
636
637 35 gtress
                private synchronized void step () {
638 32 gtress
                        Polygon poly1_new = new Polygon();
639
                        Polygon poly2_new = new Polygon();
640
                        Polygon poly3_new = new Polygon();
641
                        Polygon poly4_new = new Polygon();
642
643
                        //the step
644
                        theta = (theta + DTHETA/Math.PI) % (Math.PI);
645
646
                        //the calculation
647
                        //let p be the point of the pointy thing toward the center
648
                        //let r be the point at the opposite side
649
650
                        //recalculate radius, if it will look cool, lolz
651
                        int newr = r;
652 38 gtress
                        if (steps < 100)
653 107 gtress
                        newr = (int)( r + 200/(steps+1) );
654 32 gtress
655
                        //precompute values for dx and dy
656
                        int dx_inner = (int)(newr * Math.cos(theta));
657
                        int dy_inner = (int)(newr * Math.sin(theta));
658
                        int dx_outer = (int)((newr+dr) * Math.cos(theta));
659
                        int dy_outer = (int)((newr+dr) * Math.sin(theta));
660
661
                        //calculate polygon constants
662
                        int dy_poly = (int)(dr/2 * Math.cos(theta));
663
                        int dx_poly = (int)(dr/2 * Math.sin(theta));
664
665
                        //determine critical points
666 35 gtress
                        //kansas city shuffle!
667 32 gtress
                        px1 = sx + dx_inner;
668
                        py1 = sy - dy_inner;
669
                        rx1 = sx + dx_outer;
670
                        ry1 = sy - dy_outer;
671
                        px2 = sx - dx_inner;
672
                        py2 = sy + dy_inner;
673
                        rx2 = sx - dx_outer;
674
                        ry2 = sy + dy_outer;
675
                        px3 = sx - dy_inner;
676
                        py3 = sy - dx_inner;
677
                        rx3 = sx - dy_outer;
678
                        ry3 = sy - dx_outer;
679
                        px4 = sx + dy_inner;
680
                        py4 = sy + dx_inner;
681
                        rx4 = sx + dy_outer;
682
                        ry4 = sy + dx_outer;
683
684
                        //create polygons
685
                        poly1_new.addPoint(px1, py1);
686
                        poly1_new.addPoint(rx1+dx_poly, ry1+dy_poly);
687
                        poly1_new.addPoint(rx1-dx_poly, ry1-dy_poly);
688
                        poly2_new.addPoint(px2, py2);
689
                        poly2_new.addPoint(rx2+dx_poly, ry2+dy_poly);
690
                        poly2_new.addPoint(rx2-dx_poly, ry2-dy_poly);
691
                        poly3_new.addPoint(px3, py3);
692
                        poly3_new.addPoint(rx3-dy_poly, ry3+dx_poly);
693
                        poly3_new.addPoint(rx3+dy_poly, ry3-dx_poly);
694
                        poly4_new.addPoint(px4, py4);
695
                        poly4_new.addPoint(rx4-dy_poly, ry4+dx_poly);
696
                        poly4_new.addPoint(rx4+dy_poly, ry4-dx_poly);
697
698
                        //reassign updated polygons
699
                        poly1 = poly1_new;
700
                        poly2 = poly2_new;
701
                        poly3 = poly3_new;
702
                        poly4 = poly4_new;
703
704
                        if (steps < 300) steps++;
705
                }
706
707 35 gtress
                public synchronized void draw () {
708 32 gtress
                        if (!running) return;
709
                        g.setColor(Color.GRAY);
710
                        //draw polygons
711
                        g.fillPolygon(poly1);
712
                        g.fillPolygon(poly2);
713
                        g.fillPolygon(poly3);
714
                        g.fillPolygon(poly4);
715
                }
716
717
        }
718
719
        /*
720
        *        Simulator thread.
721
        *
722
        */
723 35 gtress
        private class Simulator extends Thread {
724 32 gtress
                final int SIMULATOR_DELAY = 300;
725
                boolean running;
726
727 35 gtress
                public Simulator () {
728 32 gtress
                        super("Simulator");
729
                        running = false;
730
                }
731
732 35 gtress
                public void run () {
733 32 gtress
                        running = true;
734 35 gtress
                        while (running) {
735 32 gtress
                                step();
736 35 gtress
                                try {
737
                                        Thread.sleep(SIMULATOR_DELAY);
738
                                } catch (InterruptedException e) {
739
                                        running = false;
740
                                        return;
741
                                }
742 32 gtress
                        }
743
                }
744
745 35 gtress
                private void step () {
746 32 gtress
                        // simulate passing the token
747
                        moveToken();
748
                }
749
750
        }
751
752
        /*
753
        *        PacketMonitor thread.
754
        *
755
        *        Currently, this counts the rate of token passes but will eventually
756
        *        be modified to keep more important statistics.
757
        */
758 35 gtress
        private class PacketMonitor extends Thread {
759 32 gtress
                final int PACKETMONITOR_DELAY = 1000;
760
761
                boolean running;
762
                int tokenPasses;
763
764 35 gtress
                public PacketMonitor () {
765 32 gtress
                        super("PacketMonitor");
766
                        running = false;
767
                        tokenPasses = 0;
768
                }
769
770 35 gtress
                public void run () {
771 32 gtress
                        running = true;
772 35 gtress
                        while (running) {
773 32 gtress
                                displayTokenPasses();
774 35 gtress
                                try {
775
                                        Thread.sleep(PACKETMONITOR_DELAY);
776
                                } catch (InterruptedException e) {
777
                                        running = false;
778
                                        return;
779
                                }
780 32 gtress
                        }
781
                }
782
783 35 gtress
                public synchronized void addTokenPass () {
784 32 gtress
                        tokenPasses++;
785
                }
786
787 35 gtress
                public synchronized void displayTokenPasses () {
788 32 gtress
                        lblTokenPasses.setText("" + tokenPasses);
789
                        tokenPasses = 0;
790
                }
791
792
        }
793
794
        /*
795 67 gtress
        *        DataUpdater thread.
796 76 gtress
        *   The purpose of this thread is to request data from the server at regular intervals.
797 32 gtress
        *
798
        */
799 67 gtress
        class DataUpdater extends Thread {
800 76 gtress
                final int DATAUPDATER_DELAY = 1100;
801 32 gtress
802 67 gtress
                public DataUpdater () {
803
                        super("Colonet DataUpdater");
804 32 gtress
                }
805
806 35 gtress
                public void run () {
807 32 gtress
                        String line;
808 35 gtress
                        while (true) {
809 32 gtress
                                try {
810 76 gtress
                                        //request more data
811
                                        if (csi.isReady())
812 107 gtress
                                                csi.sendSensorDataRequest();
813 67 gtress
                                        Thread.sleep(DATAUPDATER_DELAY);
814 32 gtress
                                } catch (InterruptedException e) {
815
                                        return;
816 39 gtress
                                }
817 32 gtress
                        }
818
                }
819
820
        }
821
822
}