Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (38.9 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
                                for (Map.Entry<Integer,RobotIcon> entry : robotIcons.entrySet()) {
649
                                        RobotIcon r = entry.getValue();
650
                                        r.destx = pt.x;
651
                                        r.desty = pt.y;
652
                                }
653
                                return;
654
                        }
655

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

    
672
                }
673
        }
674

    
675
        class KeyHandler extends Thread {
676
                KeyEvent e;
677

    
678
                public KeyHandler (KeyEvent event) {
679
                        super("KeyHandler");
680
                        this.e = event;
681
                }
682

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

    
704
        class ActionHandler extends Thread {
705
                ActionEvent e;
706

    
707
                public ActionHandler (ActionEvent event) {
708
                        super("ActionHandler");
709
                        this.e = event;
710
                }
711

    
712
                public void run () {
713
                        Object source = e.getSource();
714

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

    
776
                        } else if (source == btnCommand_ResumeTask) {
777

    
778
                        } else if (source == btnCommand_ChargeNow) {
779

    
780
                        } else if (source == btnCommand_StopCharging) {
781

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

    
799
                }
800
        }
801

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

    
813
                public void run () {
814
                        String line;
815
                        while (true) {
816
                                try {
817
                                        //request more data
818
                                        if (csi != null && csi.isReady()) {
819
                                                csi.sendPositionRequest();
820
                                                csi.sendXBeeIDRequest();
821
                                    for (Map.Entry<Integer,RobotIcon> entry : robotIcons.entrySet()) {
822
                                            RobotIcon r = entry.getValue();
823
                                            if (r.id >= 0) {
824
                                                        csi.sendBatteryRequest(r.id);
825
                                                        System.out.println("Sent battery request (" + r.id + ")");
826
                                                }
827
                                                }
828
                                        }
829
                                        Thread.sleep(DATAUPDATER_DELAY);
830
                                } catch (InterruptedException e) {
831
                                        return;
832
                                }
833
                        }
834
                }
835
        }
836

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

    
844
                public GraphicsPanel (Image img) {
845
                        this(img, true);
846
                }
847

    
848
                public GraphicsPanel (Image img, boolean isDoubleBuffered) {
849
                        super(isDoubleBuffered);
850
                        this.img = img;
851
                }
852

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

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

    
870
                public WebcamPanel () {
871
                        super(true);
872
                }
873

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

    
883
                public synchronized void paint (Graphics g) {
884
                        if (img == null) {
885
                                return;
886
                        }
887

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

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

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

    
921

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

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

    
956
                        //Display buffered content
957
                        g.drawImage(buffer, 0, 0, this);
958
                }
959

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

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

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

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

    
1010
                URL imagePath;
1011

    
1012
                MediaTracker mt;
1013
                BufferedImage image;
1014
                Random rand;
1015

    
1016
                public WebcamLoader (JApplet applet)
1017
                {
1018
                        super("ColonetWebcamLoader");
1019
                        mt = new MediaTracker(applet);
1020
                        ImageIO.setUseCache(false);
1021
                        rand = new Random();
1022
                }
1023

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

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

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

    
1085
                public void setPoint (int x, int y) {
1086
                        if (isValidPoint(x, y)) {
1087
                                this.x = x;
1088
                                this.y = y;
1089
                        }
1090
                }
1091

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

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

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

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

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

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

    
1236
                public void setMaxForward () {
1237
                        setPoint(cx, cy - (SIDE/2) + 1);
1238
                }
1239

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

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

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

    
1252
                public void setZero () {
1253
                        setPoint(cx, cy);
1254
                }
1255

    
1256
                public void sendToServer () {
1257
                    // Determine destination ID
1258
                        String dest = ColonetServerInterface.GLOBAL_DEST;
1259
                        if (cmbRobotNum != null && cmbRobotNum.getSelectedIndex() > 0) {
1260
                                dest = (String)cmbRobotNum.getSelectedItem();
1261
                        }
1262

    
1263
                        if (csi == null)
1264
                            return;
1265

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

    
1321
        }
1322

    
1323

    
1324

    
1325
}