Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / colonet / client / Colonet.java @ 590

History | View | Annotate | Download (39 KB)

1

    
2
import javax.swing.*;
3
import javax.swing.event.*;
4
import javax.imageio.*;
5
import java.awt.*;
6
import java.awt.image.*;
7
import java.awt.event.*;
8
import java.net.*;
9
import java.io.*;
10
import java.util.*;
11

    
12
/**
13
* The Colonet Graphical User Interface Applet for use locally and over an internet connection.
14
* @author Gregory Tress
15
*
16
* To generate javadoc on this file or other java files, use javadoc *.java -d doc, where doc
17
* is the name of the folder into which the files should be written.
18
*/
19
public class Colonet extends JApplet implements ActionListener, MouseInputListener, KeyListener, Runnable {
20

    
21
        // Used for painting
22
        final int BUFFER = 50;
23
        final int RADIUS = 30;
24

    
25
        // Used for the robot controller
26
        final int VECTOR_CONTROLLER_HEIGHT = 190;
27
        final int VECTOR_CONTROLLER_WIDTH = 320;
28

    
29
        // Connection
30
        JTextField txtHost;
31
        JTextField txtPort;
32
        JButton btnConnect;
33
        JButton btnGetXBeeIDs;
34
        JLabel lblConnectionStatus;
35
        JTextArea txtInfo;
36
        JPanel panelConnect;
37
        JPanel panelServerInterface;
38
        Socket socket;
39
        DataUpdater dataUpdater;
40

    
41
        // Control
42
        JPanel panelControl;
43
        JTabbedPane tabPaneControl;
44
        JPanel panelRobotControl;
45
        JPanel panelRobotDirection;
46
        JPanel panelRobotDirectionButtons;
47
        JPanel panelRobotCommands;
48
        JButton btnF, btnB, btnL, btnR, btnActivate;
49
        JComboBox cmbRobotNum;
50
        JLabel lblBattery;
51
        JLabel lblSelected;
52
        BatteryIcon batteryIcon;
53
        JPanel panelBattery;
54
        VectorController vectorController;
55
        BufferedImage imageVectorControl;
56
        JButton btnAssignID;
57
        boolean setWaypoint;
58
        int setWaypointID;
59
        JButton btnCommand_MoveTo;
60
        JButton btnCommand_MoveAll;
61
        JButton btnCommand_StopTask;
62
        JButton btnCommand_ResumeTask;
63
        JButton btnCommand_ChargeNow;
64
        JButton btnCommand_StopCharging;
65

    
66
        // Task Manager
67
        JPanel panelTaskManager;
68
        JScrollPane spTaskManager;
69
        JPanel panelTaskManagerControls;
70
        JPanel panelTaskManagerControlsPriority;
71
        DefaultListModel taskListModel;
72
        JList taskList;
73
        JButton btnAddTask;
74
        JButton btnRemoveTask;
75
        JButton btnMoveTaskUp;
76
        JButton btnMoveTaskDown;
77
        JButton btnUpdateTasks;
78
        TaskAddWindow taskAddWindow;
79

    
80
        // Webcam
81
        WebcamPanel panelWebcam;
82
        GraphicsConfiguration gc;
83
        JTabbedPane tabPaneMain;
84
        WebcamLoader webcamLoader;
85
        
86
        // Robots
87
        volatile int selectedBot;         //the user has selected this bot graphically
88
        volatile java.util.Map <Integer, RobotIcon> robotIcons;         //contains boundary shapes around bots for click detection
89
        volatile int[] xbeeID;
90

    
91
        Colonet self = this;
92
        volatile ColonetServerInterface csi;
93
        Thread paintThread;
94

    
95
        public void init () {
96
                // Set the default look and feel - choose one
97
                String laf = UIManager.getSystemLookAndFeelClassName();
98
                //String laf = UIManager.getCrossPlatformLookAndFeelClassName();
99
                //String laf = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
100
                try {
101
                        UIManager.setLookAndFeel(laf);
102
                } catch (UnsupportedLookAndFeelException exc) {
103
                        System.err.println ("Warning: UnsupportedLookAndFeel: " + laf);
104
                } catch (Exception exc) {
105
                        System.err.println ("Error loading " + laf + ": " + exc);
106
                }
107

    
108
                // We should invoke and wait to avoid browser display difficulties
109
                Runnable r = new Runnable() {
110
                        public void run() {
111
                                createAndShowGUI();
112
                        }
113
                };
114

    
115
                try {
116
                        SwingUtilities.invokeAndWait(r);
117
                } catch (InterruptedException e) {
118
                        //Not really sure why we would be in this situation
119
                        System.out.println("InterruptedException in init: " + e);
120
                } catch (java.lang.reflect.InvocationTargetException e) {
121
                        //This could happen for various reasons if there is a problem in createAndShowGUI
122
                        e.printStackTrace();
123
                }
124
        }
125

    
126
        public void destroy () {
127
            if (csi != null) {
128
                    csi.disconnect();
129
                }
130
        }
131

    
132
        private synchronized void createAndShowGUI () {
133
                paintThread = new Thread(this, "PaintThread");
134
                paintThread.start();
135
                
136
                // Webcam
137
                gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
138
                panelWebcam = new WebcamPanel();
139
                tabPaneMain = new JTabbedPane();
140
                tabPaneMain.setFont(new Font("arial", Font.PLAIN, 16));
141
                tabPaneMain.add(panelWebcam, "Webcam");
142

    
143
                // Robots
144
                selectedBot = -1;
145
                robotIcons = new HashMap <Integer, RobotIcon> ();
146

    
147
                // Connection area
148
                txtInfo = new JTextArea();
149
                txtInfo.setBorder(BorderFactory.createTitledBorder("Info"));
150
                txtHost = new JTextField(this.getDocumentBase().getHost());
151
                txtHost.setBorder(BorderFactory.createTitledBorder("Host"));
152
                txtPort = new JTextField("10123");
153
                txtPort.setBorder(BorderFactory.createTitledBorder("Port"));
154
                btnConnect = new JButton("Connect");
155
                btnConnect.setFont(new Font("arial", Font.BOLD, 16));
156
                btnGetXBeeIDs = new JButton("Get XBee IDs");
157
                getRootPane().setDefaultButton(btnConnect);
158
                lblConnectionStatus = new JLabel("Status: Offline");
159
                panelConnect = new JPanel();
160
                panelConnect.setLayout(new GridLayout(6,1));
161
                panelConnect.add(lblConnectionStatus);
162
                panelConnect.add(txtHost);
163
                panelConnect.add(txtPort);
164
                panelConnect.add(btnConnect);
165
                //panelConnect.add(btnGetXBeeIDs);
166
                panelServerInterface = new JPanel();
167
                panelServerInterface.setLayout(new GridLayout(2,1));
168
                panelServerInterface.add(panelConnect);
169
                panelServerInterface.add(txtInfo);
170

    
171
                // Robot direction panel
172
                panelRobotDirection = new JPanel();
173
                panelRobotDirectionButtons = new JPanel();
174

    
175
                Font f = new Font(null, Font.PLAIN, 18);
176
                btnF = new JButton("\u2191");
177
                btnF.setFont(f);
178
                btnB = new JButton("\u2193");
179
                btnB.setFont(f);
180
                btnL = new JButton("\u2190");
181
                btnL.setFont(f);
182
                btnR = new JButton("\u2192");
183
                btnR.setFont(f);
184
                btnActivate = new JButton("\u25A0");
185
                btnActivate.setFont(new Font(null, Font.BOLD, 36));
186

    
187
                panelRobotDirectionButtons.setLayout(new GridLayout(1,5));
188
                panelRobotDirectionButtons.add(btnActivate);
189
                panelRobotDirectionButtons.add(btnF);
190
                panelRobotDirectionButtons.add(btnB);
191
                panelRobotDirectionButtons.add(btnL);
192
                panelRobotDirectionButtons.add(btnR);
193

    
194
                imageVectorControl = gc.createCompatibleImage(VECTOR_CONTROLLER_WIDTH, VECTOR_CONTROLLER_HEIGHT);
195
                vectorController = new VectorController(imageVectorControl);
196
                panelRobotDirection.setLayout(new BorderLayout());
197
                panelRobotDirection.add(vectorController, BorderLayout.CENTER);
198
                panelRobotDirection.add(panelRobotDirectionButtons, BorderLayout.SOUTH);
199

    
200
                // Robot Control and Commands
201
                panelRobotCommands = new JPanel();
202
                panelRobotCommands.setLayout(new GridLayout(5,2));
203
                cmbRobotNum = new JComboBox();
204
                // Battery subset
205
                batteryIcon = new BatteryIcon(0);
206
                lblBattery = new JLabel(batteryIcon);
207
                lblSelected = new JLabel("None");
208
                // Command subset
209
                setWaypoint = false;
210
                setWaypointID = -1;
211
                btnAssignID = new JButton("Assign ID");
212
                btnCommand_MoveTo = new JButton("Move to ...");
213
                btnCommand_MoveAll = new JButton("Move all ...");
214
                btnCommand_StopTask = new JButton("Stop Current Task");
215
                btnCommand_ResumeTask = new JButton("Resume Current Task");
216
                btnCommand_ChargeNow = new JButton("Recharge Now");
217
                btnCommand_StopCharging = new JButton("Stop Recharging");
218
                panelRobotCommands.add(new JLabel("Select Robot to Control: "));
219
                panelRobotCommands.add(cmbRobotNum);
220
                panelRobotCommands.add(new JLabel("Battery Level: "));
221
                panelRobotCommands.add(lblBattery);
222
                panelRobotCommands.add(new JLabel("Selected Icon: "));
223
                panelRobotCommands.add(lblSelected);
224
                panelRobotCommands.add(btnAssignID);
225
                panelRobotCommands.add(new JLabel(""));
226
                panelRobotCommands.add(btnCommand_MoveTo);
227
                panelRobotCommands.add(btnCommand_MoveAll);
228
                //panelRobotCommands.add(btnCommand_StopTask);
229
                //panelRobotCommands.add(btnCommand_ResumeTask);
230
                //panelRobotCommands.add(btnCommand_ChargeNow);
231
                //panelRobotCommands.add(btnCommand_StopCharging);
232
                panelRobotControl = new JPanel();
233
                panelRobotControl.setLayout(new GridLayout(2,1));
234
                panelRobotControl.add(panelRobotDirection);
235
                panelRobotControl.add(panelRobotCommands);
236

    
237

    
238
                // Task Manager
239
                panelTaskManager = new JPanel();
240
                panelTaskManager.setLayout(new BorderLayout());
241
                taskListModel = new DefaultListModel();
242
                taskList = new JList(taskListModel);
243
                taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
244
                taskList.setSelectedIndex(0);
245
                spTaskManager = new JScrollPane(taskList);
246
                panelTaskManagerControls = new JPanel();
247
                panelTaskManagerControls.setLayout(new GridLayout(1,4));
248
                panelTaskManagerControlsPriority = new JPanel();
249
                panelTaskManagerControlsPriority.setLayout(new GridLayout(1,2));
250
                btnAddTask = new JButton("Add...");
251
                btnRemoveTask = new JButton("Remove");
252
                btnMoveTaskUp = new JButton("^");
253
                btnMoveTaskDown = new JButton("v");
254
                btnUpdateTasks = new JButton("Update");
255
                panelTaskManagerControlsPriority.add(btnMoveTaskUp);
256
                panelTaskManagerControlsPriority.add(btnMoveTaskDown);
257
                panelTaskManagerControls.add(btnAddTask);
258
                panelTaskManagerControls.add(btnRemoveTask);
259
                panelTaskManagerControls.add(btnUpdateTasks);
260
                panelTaskManagerControls.add(panelTaskManagerControlsPriority);
261
                panelTaskManager.add(spTaskManager, BorderLayout.CENTER);
262
                panelTaskManager.add(panelTaskManagerControls, BorderLayout.SOUTH);
263
                panelTaskManager.add(new JLabel("Current Task Queue"), BorderLayout.NORTH);
264
                taskAddWindow = new TaskAddWindow();
265

    
266
                // Main control mechanism
267
                panelControl = new JPanel();
268
                panelControl.setLayout(new GridLayout(1,1));
269
                tabPaneControl = new JTabbedPane(JTabbedPane.TOP);
270
                tabPaneControl.setFont(new Font("arial", Font.PLAIN, 16));
271
                tabPaneControl.setPreferredSize(new Dimension(VECTOR_CONTROLLER_WIDTH, 0));
272
                tabPaneControl.addTab("Connection", panelServerInterface);
273
                tabPaneControl.addTab("Robots", panelRobotControl);
274
                //tabPaneControl.addTab("Tasks", panelTaskManager);
275
                panelControl.add(tabPaneControl);
276

    
277

    
278
                // Put all elements in the ContentPane
279
                this.getContentPane().setLayout(new BorderLayout());
280
                this.getContentPane().add(tabPaneMain, BorderLayout.CENTER);
281
                this.getContentPane().add(panelControl, BorderLayout.EAST);
282
                this.setVisible(true);
283
                
284
                // Disable components before connecting
285
                btnConnect.setText("Connect");
286
        lblConnectionStatus.setText("Status: Disconnected");
287
        btnF.setEnabled(false);
288
        btnB.setEnabled(false);
289
        btnL.setEnabled(false);
290
        btnR.setEnabled(false);
291
        btnActivate.setEnabled(false);
292
        cmbRobotNum.setEnabled(false);
293
        btnAssignID.setEnabled(false);
294
        btnCommand_MoveTo.setEnabled(false);
295
        btnCommand_MoveAll.setEnabled(false);
296

    
297
                /* Add all listeners here */
298
                // Task Management
299
                btnAddTask.addActionListener(this);
300
                btnRemoveTask.addActionListener(this);
301
                btnMoveTaskUp.addActionListener(this);
302
                btnMoveTaskDown.addActionListener(this);
303
                btnUpdateTasks.addActionListener(this);
304
                // Robot Control
305
                btnF.addActionListener(this);
306
                btnB.addActionListener(this);
307
                btnL.addActionListener(this);
308
                btnR.addActionListener(this);
309
                btnF.addKeyListener(this);
310
                btnB.addKeyListener(this);
311
                btnL.addKeyListener(this);
312
                btnR.addKeyListener(this);
313
                btnActivate.addActionListener(this);
314
                btnActivate.addKeyListener(this);
315
                cmbRobotNum.addKeyListener(this);
316
                btnCommand_MoveTo.addActionListener(this);
317
                btnCommand_MoveAll.addActionListener(this);
318
                btnCommand_StopTask.addActionListener(this);
319
                btnCommand_ResumeTask.addActionListener(this);
320
                btnCommand_ChargeNow.addActionListener(this);
321
                btnCommand_StopCharging.addActionListener(this);
322
                // Other
323
                btnConnect.addActionListener(this);
324
                btnGetXBeeIDs.addActionListener(this);
325
                btnAssignID.addActionListener(this);
326
                panelWebcam.addMouseListener(this);
327
        }
328

    
329
        public void paint (Graphics g) {
330
                super.paint(g);
331
        }
332

    
333
        public void update (Graphics g) {
334
                paint(g);
335
        }
336
        
337
        public void run () {
338
                final int PAINT_DELAY = 300;
339
                while (true) {
340
                        try {
341
                                Thread.sleep(PAINT_DELAY);
342
                        } catch (Exception e) {
343
                                System.out.println(e);
344
                                return;
345
                        }
346
                        repaint();
347
                }
348
        }
349

    
350
        /**
351
        * Gets the JTextArea used for displaying debugging information. 
352
        *
353
        * @return the JTextArea where debugging information can be displayed.
354
        */
355
        public JTextArea getInfoPanel () {
356
                return txtInfo;
357
        }
358

    
359
        /**
360
        * Parses a String containing BOM matrix information.
361
        * The ColonetServerInterface receives lines of the BOM matrix.        (For encoding
362
        * information, see the ColonetServerInterface documentation.)         The entire matrix is passed
363
        * to the client when requested. This method takes a string of the form
364
        * "[command code] [command code] [number of robots] [data0] [data1] ..."
365
        * with tokens separated by spaces and containing no brackets.
366
        * The [command code]s are predefined values identifying this String as a BOM data
367
        * String, [number of robots] is an integer, and the values that follow are
368
        * the sensor readings of the robots in order, starting with robot 0.        Only [number of robots]^2
369
        * data entries will be read.        The matrix values are saved locally until the next String is parsed.
370
        *
371
        *
372
        * @param line the String containing BOM matrix information.
373
        * @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots]^2 data entries in the String
374
        */
375
        public void parseMatrix (String line) {
376
                txtInfo.setText("");
377
                String [] str = line.split(" ");
378
                int num = Integer.parseInt(str[2]);
379
                for (int i = 0; i < num; i++) {
380
                        for (int j = 0; j < num; j++) {
381
                                String next = str[3 + i*num + j];
382
                                if (next.equals("-1")) {
383
                                        txtInfo.append("-");
384
                                } else {
385
                                        txtInfo.append(next);
386
                                }
387

    
388
                                if (j < num - 1) {
389
                                        txtInfo.append(" ");
390
                                }
391
                        }
392

    
393
                        if (i < num - 1) {
394
                                txtInfo.append("\n");
395
                        }
396
                }
397
                repaint();
398
        }
399

    
400
        public void connect () {
401
        if (csi != null)
402
                return;
403
        csi = new ColonetServerInterface(self);
404
        csi.connect(txtHost.getText(), txtPort.getText());
405
        if (!csi.isReady()) {
406
                csi = null;
407
                return;
408
        }
409
        webcamLoader = new WebcamLoader(self);
410
        dataUpdater = new DataUpdater();
411
        dataUpdater.start();
412
        webcamLoader.start();
413
        Runnable r = new Runnable() {
414
                public void run () {
415
                        btnConnect.setText("Disconnect");
416
                        lblConnectionStatus.setText("Status: Connected");
417
                btnF.setEnabled(true);
418
                btnB.setEnabled(true);
419
                btnL.setEnabled(true);
420
                btnR.setEnabled(true);
421
                btnActivate.setEnabled(true);
422
                cmbRobotNum.setEnabled(true);
423
                btnAssignID.setEnabled(true);
424
                btnCommand_MoveTo.setEnabled(true);
425
                btnCommand_MoveAll.setEnabled(true);
426
                    }
427
                };
428
                SwingUtilities.invokeLater(r);
429
        }
430

    
431
        public void disconnect () {
432
        try {
433
            dataUpdater.interrupt();
434
        } catch (Exception e) {
435
        }
436
        csi = null;
437
                Runnable r = new Runnable() {
438
                public void run () {
439
                        btnConnect.setText("Connect");
440
                    lblConnectionStatus.setText("Status: Disconnected");
441
                btnF.setEnabled(false);
442
                btnB.setEnabled(false);
443
                btnL.setEnabled(false);
444
                btnR.setEnabled(false);
445
                btnActivate.setEnabled(false);
446
                cmbRobotNum.setEnabled(false);
447
                btnAssignID.setEnabled(false);
448
                btnCommand_MoveTo.setEnabled(false);
449
                btnCommand_MoveAll.setEnabled(false);
450
                    }
451
                };
452
                SwingUtilities.invokeLater(r);
453
        }
454

    
455
        /**
456
        * Parses a String containing a task queue update.
457
        * Format is currently not specified.
458
        * This method currently does nothing.
459
        *
460
        * @param line the String containing task queue update information.
461
        */
462
        public void parseQueue (String line) {
463

    
464
        }
465

    
466
        /**
467
        * Parses a String containing XBee ID values.
468
        * The ColonetServerInterface receives Strings of XBee information.        (For encoding
469
        * information, see the ColonetServerInterface documentation.)         This method takes
470
        * a string of the form "[command code] [command code] [number of robots] [id0] [id1] ..."
471
        * with tokens separated by spaces and containing no brackets.
472
        * The [command code]s are predefined values identifying this String as an XBee
473
        * ID String, [number of robots] is an integer, and the values that follow are
474
        * the IDs of the robots in order, starting with robot 0.        Only [number of robots]
475
        * will be read.         The ID values are saved locally until the next String is parsed.
476
        * The purpose of having this list is to ensure that robots are properly identified for control purposes.
477
        * This keeps robot identification consistent between sessions and prevents arbitrary assignment.
478
        *
479
        * @param line the String containing XBee ID information.
480
        * @throws ArrayIndexOutOfBoundsException if there are fewer than [number of robots] IDs in the String
481
        * @see ColonetServerInterface#sendXBeeIDRequest()
482
        */
483
        public void parseXBeeIDs (String line) {
484
                String [] str = line.split(" ");
485
                int num = Integer.parseInt(str[2]);
486
                xbeeID = new int[num];
487
                for (int i = 0; i < num; i++) {
488
                        xbeeID[i] = Integer.parseInt(str[i+3]);
489
                }
490

    
491
                //update the list of robots to control
492
                //but save the old value first
493
                Object oldSelection = cmbRobotNum.getSelectedItem();
494
                cmbRobotNum.removeAllItems();
495
                cmbRobotNum.addItem(new String("         All         "));
496
                for (int i = 0; i < num; i++) {
497
                        cmbRobotNum.addItem(new String("" + xbeeID[i]));
498
                }
499
                cmbRobotNum.setSelectedItem(oldSelection);
500
                repaint();
501
        }
502

    
503
        /**
504
        * Parses a String containing battery information.
505
        * The ColonetServerInterface receives Strings of battery information.         (For encoding
506
        * information, see the ColonetServerInterface documentation.)         This method takes
507
        * a string of the form "[command code] [command code] [robot ID] [value]"
508
        * with tokens separated by spaces and containing no brackets.
509
        * The [command code]s are predefined values identifying this String as a battery
510
        * information String, [robot ID] is an integer, and [value] is a battery measurement.
511
        * This updates the batery information for a single robot.
512
        *
513
        *
514
        * @param line the String containing battery information.
515
        * @see ColonetServerInterface#sendBatteryRequest(int)
516
        */
517
        public void parseBattery (String line) {
518
                String [] str = line.split(" ");
519
                int botNum = Integer.parseInt(str[2]);
520
                int level = Integer.parseInt(str[3]);
521

    
522
                System.out.println("Got battery update:" + line);
523
                RobotIcon r = robotIcons.get(botNum);
524
                if (r != null) {
525
                    r.battery = level;
526
                }
527
                repaint();
528
        }
529

    
530
        /**
531
        * Parses a String containing visual robot position information along with
532
        * canonical ID assignments.
533
        */
534
        public void parsePositions (String line) {
535
                String [] str = line.split(" ");
536
                java.util.Map <Integer, RobotIcon> newMap = new HashMap <Integer, RobotIcon> ();
537

    
538
                for (int i = 2; i < str.length; i+=3) {
539
                        int id = Integer.parseInt(str[i]);
540
                        int x = Integer.parseInt(str[i+1]);
541
                        int y = Integer.parseInt(str[i+2]);
542
                        RobotIcon newIcon = new RobotIcon(id, x, y);
543
                        if (newIcon.id >= 0) {
544
                                newIcon.color = Color.GREEN;
545
                        }
546
                        newMap.put(id, newIcon);
547
                }
548
                robotIcons = newMap;
549
                repaint();
550
        }
551

    
552
        //
553
        // MouseListener methods
554
        //
555
        public void mousePressed(MouseEvent e) {
556
                //Start a new Thread to handle the MouseEvent
557
                (new MouseHandler(e)).start();
558
                repaint();
559
        }
560
        public void mouseExited(MouseEvent e) {
561
        }
562
        public void mouseEntered(MouseEvent e) {
563
        }
564
        public void mouseReleased(MouseEvent e) {
565
        }
566
        public void mouseClicked(MouseEvent e) {
567
        }
568
        public void mouseDragged(MouseEvent e) {
569
        }
570
        public void mouseMoved(MouseEvent e) {
571
        }
572

    
573
        //
574
        // KeyListener methods
575
        //
576
        public void keyPressed (KeyEvent e) {
577
                //Start a new Thread to handle the KeyEvent
578
                (new KeyHandler(e)).start();
579
                repaint();
580
        }
581
        public void keyReleased (KeyEvent e) {
582
        }
583
        public void keyTyped (KeyEvent e) {
584
        }
585

    
586
        //
587
        // ActionListener method
588
        //
589
        public void actionPerformed (ActionEvent e) {
590
                // Start a new Thread to handle the ActionEvent
591
                (new ActionHandler(e)).start();
592
                repaint();
593
        }
594

    
595
        class MouseHandler extends Thread {
596
                MouseEvent e;
597

    
598
                public MouseHandler (MouseEvent event) {
599
                        super("MouseHandler");
600
                        this.e = event;
601
                }
602

    
603
                public void run () {
604
                        Point pt = panelWebcam.convertClick(e);
605

    
606
                        // If we are selecting a waypoint (destination) for a specific bot
607
                        if (setWaypoint && setWaypointID >= 0) {
608
                                setWaypoint = false;
609
                                panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
610
                                if (selectedBot < 0) {
611
                                        return;
612
                                }
613
                                
614
                                RobotIcon r = robotIcons.get(selectedBot);
615
                                if (r != null) {
616
                                        r.destx = pt.x;
617
                                        r.desty = pt.y;
618
                                        if (csi != null) {
619
                                                csi.sendAbsoluteMove(r.id, r.destx, r.desty);
620
                                        }
621
                                }
622

    
623
                                return;
624
                        }
625

    
626
                        // Right-click also means we are moving a robot
627
                        if (e.getButton() == MouseEvent.BUTTON2 || e.getButton() == MouseEvent.BUTTON3) {
628
                                if (selectedBot < 0) {
629
                                        return;
630
                                }
631

    
632
                                RobotIcon r = robotIcons.get(selectedBot);
633
                                if (r != null) {
634
                                        r.destx = pt.x;
635
                                        r.desty = pt.y;
636
                                        if (csi != null) {
637
                                                csi.sendAbsoluteMove(r.id, r.destx, r.desty);
638
                                        }
639
                                }
640

    
641
                                return;
642
                        }
643

    
644
                        // If we are setting all waypoints
645
                        if (setWaypoint) {
646
                                setWaypoint = false;
647
                                panelWebcam.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
648
                                Iterator <Map.Entry<Integer,RobotIcon>> it = robotIcons.entrySet().iterator();
649
                                while (it.hasNext()) {
650
                                        RobotIcon r = it.next().getValue();
651
                                        r.destx = pt.x;
652
                                        r.desty = pt.y;
653
                                }
654
                                
655
                                return;
656
                        }
657

    
658
                        // Otherwise, we are selecting a bot, or doing nothing
659
                        Iterator <Map.Entry<Integer,RobotIcon>> it = robotIcons.entrySet().iterator();
660
                        while (it.hasNext()) {
661
                                RobotIcon r = it.next().getValue();
662
                                if (r.contains(pt.x, pt.y)) {
663
                                        selectedBot = r.id;
664
                                        lblSelected.setText("" + r.id);
665
                                        // Try to select the clicked bot, if its XBee ID is detected.
666
                                        for (int j = 1; j < cmbRobotNum.getItemCount(); j++) {
667
                                                if (Integer.parseInt(cmbRobotNum.getItemAt(j).toString()) == selectedBot) {
668
                                                        cmbRobotNum.setSelectedIndex(j);
669
                                                }
670
                                        }
671
                                        return;
672
                                }
673
                        }
674

    
675
                }
676
        }
677

    
678
        class KeyHandler extends Thread {
679
                KeyEvent e;
680

    
681
                public KeyHandler (KeyEvent event) {
682
                        super("KeyHandler");
683
                        this.e = event;
684
                }
685

    
686
                public void run () {
687
                        int code = e.getKeyCode();
688
                        if (code == KeyEvent.VK_UP) {
689
                                vectorController.setMaxForward();
690
                                vectorController.sendToServer();
691
                        } else if (code == KeyEvent.VK_DOWN) {
692
                                vectorController.setMaxReverse();
693
                                vectorController.sendToServer();
694
                        } else if (code == KeyEvent.VK_LEFT) {
695
                                vectorController.setMaxLeft();
696
                                vectorController.sendToServer();
697
                        } else if (code == KeyEvent.VK_RIGHT) {
698
                                vectorController.setMaxRight();
699
                                vectorController.sendToServer();
700
                        } else if (code == KeyEvent.VK_S) {
701
                                vectorController.setZero();
702
                                vectorController.sendToServer();
703
                        }
704
                }
705
        }
706

    
707
        class ActionHandler extends Thread {
708
                ActionEvent e;
709

    
710
                public ActionHandler (ActionEvent event) {
711
                        super("ActionHandler");
712
                        this.e = event;
713
                }
714

    
715
                public void run () {
716
                        Object source = e.getSource();
717

    
718
                        // General Actions
719
                        if (source == btnConnect) {
720
                                if (csi == null) {
721
                                        connect();
722
                                } else {
723
                                        disconnect();
724
                                }
725
                        } else if (source == btnGetXBeeIDs) {
726
                                csi.sendXBeeIDRequest();
727
                        } else if (source == btnAssignID) {
728
                                String message;
729
                                if (selectedBot < 0) {
730
                                        message = "That robot is unidentified. Please specify its ID.";
731
                                } else {
732
                                        message = "That robot has ID " + selectedBot + ". You may reassign it now.";
733
                                }
734
                                String result = JOptionPane.showInputDialog(self, message, "Robot Identification", JOptionPane.QUESTION_MESSAGE);
735
                                if (result == null) {
736
                                        return;
737
                                }
738
                                int newID = -1;
739
                                try {
740
                                        newID = Integer.parseInt(result);
741
                                } catch (Exception ex) {
742
                                        csi.warn("Invalid ID.");
743
                                        return;
744
                                }
745
                                // Assign new ID and update display
746
                                if (csi != null) {
747
                                        csi.sendIDAssignment(selectedBot, newID);
748
                                }
749
                                selectedBot = newID;
750
                                lblSelected.setText("" + newID);
751
                        } else if (source == btnF) { // Robot Movement Controls
752
                                vectorController.setMaxForward();
753
                                vectorController.sendToServer();
754
                        } else if (source == btnB) {
755
                                vectorController.setMaxReverse();
756
                                vectorController.sendToServer();
757
                        } else if (source == btnL) {
758
                                vectorController.setMaxLeft();
759
                                vectorController.sendToServer();
760
                        } else if (source == btnR) {
761
                                vectorController.setMaxRight();
762
                                vectorController.sendToServer();
763
                        } else if (source == btnActivate) {
764
                                vectorController.setZero();
765
                                vectorController.sendToServer();
766
                        } else if (source == btnCommand_MoveTo) { // Robot Commands (non-movement)
767
                                if (selectedBot < 0) {
768
                                        return;
769
                                }
770
                                panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
771
                                setWaypoint = true;
772
                                setWaypointID = selectedBot;
773
                        } else if (source == btnCommand_MoveAll) {
774
                                panelWebcam.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
775
                                setWaypoint = true;
776
                                setWaypointID = -1;
777
                        } else if (source == btnCommand_StopTask) {
778

    
779
                        } else if (source == btnCommand_ResumeTask) {
780

    
781
                        } else if (source == btnCommand_ChargeNow) {
782

    
783
                        } else if (source == btnCommand_StopCharging) {
784

    
785
                        } else if (source == btnAddTask) { // Queue Management
786
                                taskAddWindow.prompt();
787
                        } else if (source == btnRemoveTask) {
788
                                if (taskList.getSelectedIndex() >= 0) {
789
                                        csi.sendQueueRemove(taskList.getSelectedIndex());
790
                                }
791
                                csi.sendQueueUpdate();
792
                        } else if (source == btnMoveTaskUp) {
793
                                csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() - 1);
794
                                csi.sendQueueUpdate();
795
                        } else if (source == btnMoveTaskDown) {
796
                                csi.sendQueueReorder(taskList.getSelectedIndex(), taskList.getSelectedIndex() + 1);
797
                                csi.sendQueueUpdate();
798
                        } else if (source == btnUpdateTasks) {
799
                                csi.sendQueueUpdate();
800
                        }
801

    
802
                }
803
        }
804

    
805
        /*
806
        * DataUpdater thread.
807
        *                The purpose of this thread is to request data from the server at regular intervals.
808
        *
809
        */
810
        class DataUpdater extends Thread {
811
                final int DATAUPDATER_DELAY = 500;
812
                public DataUpdater () {
813
                        super("Colonet DataUpdater");
814
                }
815

    
816
                public void run () {
817
                        String line;
818
                        while (true) {
819
                                try {
820
                                        //request more data
821
                                        if (csi != null && csi.isReady()) {
822
                                                csi.sendPositionRequest();
823
                                                csi.sendXBeeIDRequest();
824
                                                Iterator <Map.Entry<Integer,RobotIcon>> it = robotIcons.entrySet().iterator();
825
                                    while (it.hasNext()) {
826
                                            RobotIcon r = it.next().getValue();
827
                                            if (r.id >= 0) {
828
                                                        csi.sendBatteryRequest(r.id);
829
                                                }
830
                                                }
831
                                        }
832
                                        Thread.sleep(DATAUPDATER_DELAY);
833
                                } catch (InterruptedException e) {
834
                                        return;
835
                                }
836
                        }
837
                }
838
        }
839

    
840
        /*
841
        * GraphicsPanel class
842
        * An extension of JPanel, designed for holding an image that will be repainted regularly.
843
        */
844
        class GraphicsPanel extends JPanel {
845
                protected Image img;
846

    
847
                public GraphicsPanel (Image img) {
848
                        this(img, true);
849
                }
850

    
851
                public GraphicsPanel (Image img, boolean isDoubleBuffered) {
852
                        super(isDoubleBuffered);
853
                        this.img = img;
854
                }
855

    
856
                public void paint (Graphics g) {
857
                        // Place the buffered image on the screen, inside the panel
858
                        g.drawImage(img, 0, 0, Color.WHITE, this);
859
                }
860
        }
861

    
862
        /*
863
        * WebcamPanel class
864
        * Enables more efficient image handling in a component-controlled environment
865
        */
866
        class WebcamPanel extends JPanel {
867
                final int BORDER = 16;        // this is arbitrary. it makes the image look nice inside a border.
868
                final int BATTERY_WIDTH = 50;
869
                final int BATTERY_HEIGHT = 10;
870
                volatile BufferedImage img;
871
                BufferedImage buffer;
872

    
873
                public WebcamPanel () {
874
                        super(true);
875
                }
876

    
877
                public synchronized void setImage (BufferedImage newimg) {
878
                        if (img != null) {
879
                                img.flush();
880
                        }
881
                        System.gc();
882
                        img = newimg;
883
                        repaint();
884
                }
885

    
886
                public synchronized void paint (Graphics g) {
887
                        if (img == null) {
888
                                return;
889
                        }
890

    
891
                        // Calculate scaling
892
                        int maxWidth = getWidth() - 2*BORDER;
893
                        int maxHeight = getHeight() - 2*BORDER;
894
                        double widthRatio = 1.0 * maxWidth / img.getWidth();
895
                        double heightRatio = 1.0 * maxHeight / img.getHeight();
896
                        double scale = 0;
897
                        int newWidth = 0;
898
                        int newHeight = 0;
899
                        int x = 0;
900
                        int y = 0;
901

    
902
                        if (widthRatio > heightRatio) {         //height is the limiting factor
903
                                scale = heightRatio;
904
                                newHeight = maxHeight;
905
                                newWidth = (int) (img.getWidth() * scale);
906
                                y = BORDER;
907
                                x = (maxWidth - newWidth) / 2 + BORDER;
908
                        } else {        //width is the limiting factor
909
                                scale = widthRatio;
910
                                newWidth = maxWidth;
911
                                newHeight = (int) (img.getHeight() * scale);
912
                                x = BORDER;
913
                                y = (maxHeight - newHeight) / 2 + BORDER;
914
                        }
915

    
916
                        // Draw everything onto the buffer
917
                        buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
918
                        Graphics2D bufferedGraphics = (Graphics2D)buffer.getGraphics();
919
                        bufferedGraphics.setColor(Color.GRAY);
920
                        bufferedGraphics.fillRect(0, 0, this.getWidth(), this.getHeight());
921
                        Image imgScaled = img.getScaledInstance(newWidth, newHeight, Image.SCALE_FAST);
922
                        bufferedGraphics.drawImage(imgScaled, x, y, this);
923

    
924

    
925
                        // Draw Identifiers and battery levels
926
                        if (robotIcons != null) {
927
                                bufferedGraphics.setStroke(new BasicStroke(2));
928
                                Iterator <Map.Entry<Integer,RobotIcon>> it = robotIcons.entrySet().iterator();
929
                                while (it.hasNext()) {
930
                                        RobotIcon r = it.next().getValue();
931
                                        bufferedGraphics.setColor(r.color);
932
                                        // Identifier circle
933
                                        int px = (int) (x + r.x * scale);
934
                                        int py = (int) (y + r.y * scale);
935
                                        bufferedGraphics.drawOval(px-RADIUS, py-RADIUS, 2*r.RADIUS, 2*r.RADIUS);
936
                                        // Battery
937
                                        if (r.battery >= 0) {
938
                                            int pixels = r.battery * BATTERY_WIDTH / 160;
939
                                                bufferedGraphics.setColor(Color.YELLOW);
940
                                                bufferedGraphics.fillRect(px+20, py+20, pixels, BATTERY_HEIGHT);
941
                                                bufferedGraphics.setColor(Color.BLACK);
942
                                                bufferedGraphics.drawRect(px+20, py+20, BATTERY_WIDTH, BATTERY_HEIGHT);
943
                                        }
944
                                        // If the robot has a destination, draw the vector
945
                                        if (r.destx >= 0) {
946
                                                bufferedGraphics.drawLine(px, py, (int)(x + r.destx * scale), (int)(y + r.desty * scale));
947
                                        }
948
                                }
949
                        }
950

    
951
                        // Identify currently-selected robot
952
                        RobotIcon r = robotIcons.get(selectedBot);
953
                        if (r != null) {
954
                                int px = (int) (x + r.x * scale);
955
                                int py = (int) (y + r.y * scale);
956
                                bufferedGraphics.setColor(Color.BLACK);
957
                                bufferedGraphics.drawOval(px-RADIUS-6, py-RADIUS-6, 2*r.RADIUS+12, 2*r.RADIUS+12);
958
                        }
959

    
960
                        //Display buffered content
961
                        g.drawImage(buffer, 0, 0, this);
962
                }
963

    
964
                /*
965
                * Convert a click on the webcam panel to a coordinate that is consistent with the
966
                * original size of the image that the panel contains.
967
                */
968
                public Point convertClick (MouseEvent e) {
969
                        if (img == null) {
970
                                return new Point(e.getX(), e.getY());
971
                        }
972

    
973
                        // Calculate scaling
974
                        int clickx = e.getX();
975
                        int clicky = e.getY();
976
                        int maxWidth = getWidth() - 2*BORDER;
977
                        int maxHeight = getHeight() - 2*BORDER;
978
                        double widthRatio = 1.0 * maxWidth / img.getWidth();
979
                        double heightRatio = 1.0 * maxHeight / img.getHeight();
980
                        double scale = 0;
981
                        int newWidth = 0;
982
                        int newHeight = 0;
983
                        int px = 0;
984
                        int py = 0;
985

    
986
                        if (widthRatio > heightRatio) {         //height is the limiting factor
987
                                scale = heightRatio;
988
                                newHeight = maxHeight;
989
                                newWidth = (int) (img.getWidth() * scale);
990
                                py = clicky - BORDER;
991
                                px = clickx - BORDER - (maxWidth - newWidth) / 2;
992
                        } else {        //width is the limiting factor
993
                                scale = widthRatio;
994
                                newWidth = maxWidth;
995
                                newHeight = (int) (img.getHeight() * scale);
996
                                px = clickx - BORDER;
997
                                py = clicky - BORDER - (maxHeight - newHeight) / 2;
998
                        }
999
                        py = (int) (py / scale);
1000
                        px = (int) (px / scale);
1001
                        return new Point(px, py);
1002
                }
1003
        }
1004

    
1005
        /*
1006
        * WebcamLoader class
1007
        * Handles the loading of the webcam image.
1008
        */
1009
        class WebcamLoader extends Thread
1010
        {
1011
                final int WEBCAMLOADER_DELAY = 250;
1012
                final String IMAGE_PATH = "http://128.2.99.176/colonet.jpg";
1013

    
1014
                URL imagePath;
1015

    
1016
                MediaTracker mt;
1017
                BufferedImage image;
1018
                Random rand;
1019

    
1020
                public WebcamLoader (JApplet applet)
1021
                {
1022
                        super("ColonetWebcamLoader");
1023
                        mt = new MediaTracker(applet);
1024
                        ImageIO.setUseCache(false);
1025
                        rand = new Random();
1026
                }
1027

    
1028
                public void run ()
1029
                {
1030
                        while (true) {
1031
                                try {
1032
                                        Thread.sleep(WEBCAMLOADER_DELAY);
1033
                                        if (image != null)
1034
                                                image.flush();
1035
                                        System.gc();
1036
                                        try {
1037
                                                imagePath = new URL(IMAGE_PATH + "?rand=" + rand.nextInt(100000));
1038
                                        } catch (MalformedURLException e) {
1039
                                                System.out.println("Malformed URL: could not form URL from: [" + IMAGE_PATH + "]\n");
1040
                                        }
1041
                                        image = ImageIO.read(imagePath);
1042
                                        // The MediaTracker waitForID pauses the thread until the image is loaded.
1043
                                        // We don't want to display a half-downloaded image.
1044
                                        mt.addImage(image, 1);
1045
                                        mt.waitForID(1);
1046
                                        mt.removeImage(image);
1047
                                        // Save
1048
                                        panelWebcam.setImage(image);
1049
                                } catch (InterruptedException e) {
1050
                                        return;
1051
                                } catch (java.security.AccessControlException e) {
1052
                                        csi.warn("Could not load webcam.\n" + e);
1053
                                        return;
1054
                                } catch (IOException e) {
1055
                                        getInfoPanel().append("IOException while trying to load image.");
1056
                                }
1057
                        }
1058
                }
1059
        }
1060

    
1061
        /*
1062
        * VectorController class
1063
        * Manages robot motion control graphically
1064
        */
1065
        class VectorController extends GraphicsPanel implements MouseListener, MouseMotionListener {
1066
                int x, y, cx, cy;
1067
                final int WIDTH, HEIGHT;
1068
                final int SIDE;
1069
                final int BOT_SIZE = 70;
1070
        final int WHEEL_SIZE = 15;
1071

    
1072
                public VectorController (Image img) {
1073
                        super (img);
1074
                        WIDTH = img.getWidth(null);
1075
                        HEIGHT = img.getHeight(null);
1076
                        cx = WIDTH/2;
1077
                        cy = HEIGHT/2;
1078
                        x = cx;
1079
                        y = cy;
1080
                        if (WIDTH < HEIGHT) {
1081
                                SIDE = WIDTH;
1082
                        } else {
1083
                                SIDE = HEIGHT;
1084
                        }
1085
                        this.addMouseListener(this);
1086
                        this.addMouseMotionListener(this);
1087
                }
1088

    
1089
                public void setPoint (int x, int y) {
1090
                        if (isValidPoint(x, y)) {
1091
                                this.x = x;
1092
                                this.y = y;
1093
                        }
1094
                }
1095

    
1096
                public boolean isValidPoint (int x, int y) {
1097
                        double xsq = Math.pow(1.0*(x - cx)/(SIDE/2), 2);
1098
                        double ysq = Math.pow(1.0*(y - cy)/(SIDE/2), 2);
1099
                        return (xsq + ysq <= 1);
1100
                }
1101

    
1102
                public void notifyMouseEvent (MouseEvent e, boolean send) {
1103
                        if (!isValidPoint(e.getX(), e.getY())) {
1104
                                return;
1105
                        }
1106
                        setPoint(e.getX(), e.getY());
1107
                repaint();
1108
                        if (send) {
1109
                            Runnable r = new Runnable () {
1110
                                public void run () {
1111
                                    sendToServer();
1112
                                }
1113
                            };
1114
                                (new Thread(r)).start();
1115
                        }
1116
                }
1117

    
1118
                public void mouseExited(MouseEvent e) {
1119
                }
1120
                public void mouseEntered(MouseEvent e) {
1121
                }
1122
                public void mouseReleased(MouseEvent e) {
1123
                        this.notifyMouseEvent(e, true);
1124
                }
1125
                public void mouseClicked(MouseEvent e) {
1126
                        this.notifyMouseEvent(e, false);
1127
                }
1128
                public void mousePressed(MouseEvent e) {
1129
                }
1130
                public void mouseDragged(MouseEvent e) {
1131
                        vectorController.notifyMouseEvent(e, false);
1132
                }
1133
                public void mouseMoved(MouseEvent e) {
1134
                }
1135

    
1136
                public int getSpeed () {
1137
                        int dx = x - cx;
1138
                        int dy = y - cy;
1139
                        int s = (int) Math.sqrt( Math.pow(dx, 2) + Math.pow(dy, 2) );
1140
                        int maxspeed = SIDE/2;
1141
                        return s * 512 / SIDE;
1142
                }
1143

    
1144
                /**
1145
                * Returns the angle of the control vector in positive degrees west of north,
1146
                * or negative degrees east of north, whichever is less than or equal to
1147
                * 180 degrees total.
1148
                */
1149
                public int getAngle () {
1150
                        int dx = x - cx;
1151
                        int dy = cy - y;
1152
                        // find reference angle in radians
1153
                        double theta = Math.atan2(Math.abs(dx), Math.abs(dy));
1154
                        // transform to degrees
1155
                        theta = theta * 180 / Math.PI;
1156
                        // adjust for quadrant
1157
                        if (dx < 0 && dy < 0)
1158
                                theta = 90 + theta;
1159
                        else if (dx < 0 && dy >= 0)
1160
                                theta = 90 - theta;
1161
                        else if (dx >= 0 && dy < 0)
1162
                                theta = -90 - theta;
1163
                        else
1164
                                theta = -90 + theta;
1165
                        return (int) theta;
1166
                }
1167
                
1168
                public int getMotorL () {
1169
                    if (getSpeed() == 0)
1170
                        return 0;
1171
                    int dx = x - cx;
1172
                        int dy = (cy - y) * 255 / getSpeed();
1173
                        int val = 0;
1174
                    // Dependent on quadrant
1175
                        if (dx < 0 && dy < 0)
1176
                                val = -255;
1177
                        else if (dx < 0 && dy >= 0)
1178
                                val = dy * 1024 / SIDE - 255;
1179
                        else if (dx >= 0 && dy < 0)
1180
                                val = dy * 1024 / SIDE + 255;
1181
                        else
1182
                                val = 255;
1183
                        return val * getSpeed() / 255;
1184
                }
1185
                
1186
                public int getMotorR () {
1187
                    if (getSpeed() == 0)
1188
                        return 0;
1189
                    int dx = x - cx;
1190
                        int dy = (cy - y) * 255 / getSpeed();
1191
                        int val = 0;
1192
                    // Dependent on quadrant
1193
                        if (dx < 0 && dy < 0)
1194
                                val = dy * 1024 / SIDE + 255;
1195
                        else if (dx < 0 && dy >= 0)
1196
                                val = 255;
1197
                        else if (dx >= 0 && dy < 0)
1198
                                val = -255;
1199
                        else
1200
                                val = dy * 1024 / SIDE - 255;
1201
                        return val * getSpeed() / 255;
1202
                }
1203

    
1204
                public void paint (Graphics g) {
1205
                        // Clear image
1206
                        g.setColor(Color.BLACK);
1207
                        g.fillRect(0, 0, WIDTH, HEIGHT);
1208
                        ((Graphics2D)g).setStroke(new BasicStroke(1));
1209
                        
1210
                        // Motor indicators
1211
                        int motor1 = getMotorL() * BOT_SIZE / 512;
1212
                        int motor2 = getMotorR() * BOT_SIZE / 512;
1213
                        g.setColor(Color.YELLOW);
1214
                        if (motor1 < 0)
1215
                            g.fillRect(cx-BOT_SIZE/2 - WHEEL_SIZE, cy, WHEEL_SIZE, -motor1);
1216
                        else
1217
                            g.fillRect(cx-BOT_SIZE/2 - WHEEL_SIZE, cy-motor1, WHEEL_SIZE, motor1);
1218
                        if (motor2 < 0)
1219
                            g.fillRect(cx+BOT_SIZE/2, cy, WHEEL_SIZE, -motor2);
1220
                        else
1221
                            g.fillRect(cx+BOT_SIZE/2, cy-motor2, WHEEL_SIZE, motor2);
1222
                        
1223
                        // Watermark
1224
                        g.setColor(Color.GRAY);
1225
                        g.drawOval(cx-BOT_SIZE/2, cy-BOT_SIZE/2, BOT_SIZE, BOT_SIZE);
1226
                        g.drawRect(cx-BOT_SIZE/2 - WHEEL_SIZE, cy-BOT_SIZE/2, WHEEL_SIZE, BOT_SIZE);
1227
                        g.drawRect(cx+BOT_SIZE/2, cy-BOT_SIZE/2, WHEEL_SIZE, BOT_SIZE);
1228
                        
1229
                        // Targeting circle
1230
                        g.setColor(Color.RED);
1231
                        g.drawOval(cx-SIDE/2, cy-SIDE/2, SIDE, SIDE);
1232
                        ((Graphics2D)g).setStroke(new BasicStroke(2));
1233
                        
1234
                        // Vector Line
1235
                        g.setColor(Color.GREEN);
1236
                        g.drawLine(cx, cy, x, y);
1237
                        g.fillOval(x-3, y-3, 6, 6);
1238
                }
1239

    
1240
                public void setMaxForward () {
1241
                        setPoint(cx, cy - (SIDE/2) + 1);
1242
                }
1243

    
1244
                public void setMaxReverse () {
1245
                        setPoint(cx, cy + (SIDE/2) - 1);
1246
                }
1247

    
1248
                public void setMaxLeft () {
1249
                        setPoint(cx - (SIDE/2) + 1, cy);
1250
                }
1251

    
1252
                public void setMaxRight () {
1253
                        setPoint(cx + (SIDE/2) - 1, cy);
1254
                }
1255

    
1256
                public void setZero () {
1257
                        setPoint(cx, cy);
1258
                }
1259

    
1260
                public void sendToServer () {
1261
                    // Determine destination ID
1262
                        String dest = ColonetServerInterface.GLOBAL_DEST;
1263
                        if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex() > 0) {
1264
                                dest = (String)cmbRobotNum.getSelectedItem();
1265
                        }
1266

    
1267
                        if (csi == null)
1268
                            return;
1269

    
1270
                        String motor1_string;
1271
                        String motor2_string;
1272
                        int motor1 = getMotorL();
1273
                        int motor2 = getMotorR();
1274
                        
1275
                        if (motor1 > 0) {
1276
                            motor1_string = " 1 " + motor1;
1277
                        } else {
1278
                            motor1_string = " 0 " + (-motor1);
1279
                        }
1280
                        if (motor2 > 0) {
1281
                            motor2_string = " 1 " + motor2;
1282
                        } else {
1283
                            motor2_string = " 0 " + (-motor2);
1284
                        }
1285
                        
1286
                        csi.sendData(ColonetServerInterface.MOTOR1_SET + motor1_string, dest);
1287
                        csi.sendData(ColonetServerInterface.MOTOR2_SET + motor2_string, dest);
1288
                        
1289
                        /*
1290
                        // Directional commands
1291
                        if (x > cx && y == cy) {        //move right
1292
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 200", dest);
1293
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 200", dest);
1294
                        } else if (x < cx && y == cy) {         //move left
1295
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 200", dest);
1296
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 200", dest);
1297
                        } else if (x == cx && y > cy) {         //move forward
1298
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 0 225", dest);
1299
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 0 225", dest);
1300
                        } else if (x == cx && y < cy) {         //move backward
1301
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 225", dest);
1302
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 225", dest);
1303
                        } else if (x == cx && y == cy) {        //stop!
1304
                                csi.sendData(ColonetServerInterface.MOTOR2_SET + " 1 0", dest);
1305
                                csi.sendData(ColonetServerInterface.MOTOR1_SET + " 1 0", dest);
1306
                        }
1307
                        */
1308
                        
1309
                        /*
1310
                        // Atomic Directional commands
1311
                        if (x > cx && y == cy) {  //move right
1312
                                csi.sendData(ColonetServerInterface.MOVE_R, dest);
1313
                        } else if (x < cx && y == cy) {         //move left
1314
                                csi.sendData(ColonetServerInterface.MOVE_L, dest);
1315
                        } else if (x == cx && y > cy) {         //move forward
1316
                                csi.sendData(ColonetServerInterface.MOVE_F, dest);
1317
                        } else if (x == cx && y < cy) {         //move backward
1318
                                csi.sendData(ColonetServerInterface.MOVE_B, dest);
1319
                        } else if (x == cx && y == cy) { //stop
1320
                                csi.sendData(ColonetServerInterface.MOTORS_OFF, dest);
1321
                        }
1322
                        */
1323
                }
1324

    
1325
        }
1326

    
1327

    
1328

    
1329
}