Spring Semester 2003


Lecture Notes Twenty-Six: Help with Assignment Five
We start from a simple applet
import java.awt.*; 
import java.applet.*; 
import java.awt.event.*; 

public class One extends Applet implements MouseMotionListener {
    public void init() { 
	addMouseMotionListener(this);
    }
    public void paint(Graphics g) { } 
    public void mouseMoved(MouseEvent e) {
	int x = e.getX(), y = e.getY(); 
	System.out.println("Mouse moved at: (" + x + ", " + y + ")"); 
    } 
    public void mouseDragged(MouseEvent e) { } 
}
that gets delivered from a simple HTML file
<html>
  <head>
    <title>All eyes on the mouse!</title>
  </head>
<body>
  <applet code=One.class height=300 width=300>

  </applet>
</body>
</html> 
This, of course, only watches the mouse.

Let's add a visual indicator of where the mouse is.

This is our watching device:

import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x; 
	this.y = y;
	this.r = r; 
	this.R = R; 
	targetX = x + R; 
	targetY = y + R; 
    } 
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R); 
	g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r); 
    } 
} 
Use this device in the applet, and it stares at you:
import java.awt.*; 
import java.applet.*; 
import java.awt.event.*; 

public class One extends Applet implements MouseMotionListener {
    Device d = new Device(100, 100, 10, 30); 
    public void init() { 
	addMouseMotionListener(this);
    }
    public void paint(Graphics g) { 
	d.draw(g); 
    } 
    public void mouseMoved(MouseEvent e) {
	int x = e.getX(), y = e.getY(); 
	System.out.println("Mouse moved at: (" + x + ", " + y + ")"); 
    } 
    public void mouseDragged(MouseEvent e) { } 
} 
Now let's pass info from the mouse listener to the device:
And since we know the device changes state we need to repaint.

import java.awt.*; 
import java.applet.*; 
import java.awt.event.*; 

public class One extends Applet implements MouseMotionListener {
    Device d = new Device(100, 100, 10, 30); 
    public void init() { 
	addMouseMotionListener(this);
    }
    public void paint(Graphics g) { 
	d.draw(g); 
    } 
    public void mouseMoved(MouseEvent e) {
	int x = e.getX(), y = e.getY(); 
	// System.out.println("Mouse moved at: (" + x + ", " + y + ")"); 
	d.targetX = x;
	d.targetY = y; 
	repaint(); 
    } 
    public void mouseDragged(MouseEvent e) { } 
}
The device now monitors the mouse movement a little too closely.

For the time being that's OK.

Let's draw the line that connects the center of the circle with the mouse pointer.

import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	g.drawLine(xA, yA, xB, yB); 
    }
}
That looks like a rubber band.

Can we identify the place where the border crosses the rubber band?

Let's place a second circle there.

import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	g.drawLine(xA, yA, xB, yB); 
	double distance = Math.sqrt((xA - xB) * (xA - xB) + 
				    (yA - yB) * (yA - yB)); 
	double percent = R / distance; 

	int xC = (int) (percent * (xB - xA)) + xA; 
	int yC = (int) (percent * (yB - yA)) + yA;  

	g.fillOval(xC-4, yC-4, 8, 8); 

    }
}
The part in brown finds the coordinates, (xCyC) and the part in blue draws a small circle with a radius of 4 pixels centered in (xCyC). Here's a picture that tries to make this even clearer:
Let's make a change:
import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	// g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	g.drawLine(xA, yA, xB, yB); 
	double distance = Math.sqrt((xA - xB) * (xA - xB) + 
				    (yA - yB) * (yA - yB)); 
	double percent = R / distance; 

	int xC = (int) (percent * (xB - xA)) + xA; 
	int yC = (int) (percent * (yB - yA)) + yA;  

	g.fillOval(xC-r, yC-r, 2 * r, 2 * r); 

    }
}
That almost draws the small circle where needed.

We need to bring it inside along the line by r.

import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	// g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	g.drawLine(xA, yA, xB, yB); 
	double distance = Math.sqrt((xA - xB) * (xA - xB) + 
				    (yA - yB) * (yA - yB)); 
	double percent = (R - r)/ distance; 

	int xC = (int) (percent * (xB - xA)) + xA; 
	int yC = (int) (percent * (yB - yA)) + yA;  

	g.fillOval(xC-r, yC-r, 2 * r, 2 * r); 

    }
}
And we can give up on the rubber band:
import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	// g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	// g.drawLine(xA, yA, xB, yB); 
	double distance = Math.sqrt((xA - xB) * (xA - xB) + 
				    (yA - yB) * (yA - yB)); 
	double percent = (R - r)/ distance; 

	int xC = (int) (percent * (xB - xA)) + xA; 
	int yC = (int) (percent * (yB - yA)) + yA;  

	g.fillOval(xC-r, yC-r, 2 * r, 2 * r); 

    }
}
But if we are inside the larger circle we need to be on the mouse.

import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	// g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	// g.drawLine(xA, yA, xB, yB); 
	double distance = Math.sqrt((xA - xB) * (xA - xB) + 
				    (yA - yB) * (yA - yB)); 
	int xC, yC; 

	if (distance < R - r) { 
	    xC = targetX; yC = targetY; 
	} else { 
	    double percent = (R - r)/ distance;

	    xC = (int) (percent * (xB - xA)) + xA;
	    yC = (int) (percent * (yB - yA)) + yA;
	}

	g.fillOval(xC-r, yC-r, 2 * r, 2 * r); 

    }
}
Now all you have to do is use as many devices as needed:
import java.awt.*; 
import java.applet.*;
import java.awt.event.*;

public class One extends Applet implements MouseMotionListener {
    Device d1 = new Device( 50,  50, 10, 30),
	d2 = new Device(100, 100, 10, 30),
	d3 = new Device(150, 150, 10, 30),
	d4 = new Device(200, 200, 10, 30);

    public void init() { 
	addMouseMotionListener(this);
    }
    public void paint(Graphics g) {
	d1.draw(g);
	d2.draw(g);
	d3.draw(g);
	d4.draw(g);
    }

    public void mouseMoved(MouseEvent e) {
	int x = e.getX(), y = e.getY();
        // System.out.println("Mouse moved at: (" + x + ", " + y + ")"); 
	d1.targetX = x; d1.targetY = y; 
	d2.targetX = x; d2.targetY = y;
	d3.targetX = x; d3.targetY = y;
	d4.targetX = x; d4.targetY = y;
	repaint();
    }
    public void mouseDragged(MouseEvent e) { }
}
And things are easier to follow if we reactivate the rubber band:
import java.awt.*; 

public class Device {
    int x, y, r, R, targetX, targetY;
    public Device(int x, int y, int r, int R) {
	this.x = x;
	this.y = y;
	this.r = r;
	this.R = R;
	targetX = x + R;
	targetY = y + R;
    }
    public void draw(Graphics g) {
	g.drawOval(x, y, 2 * R, 2 * R);
	int xA = x + R, yA = y + R, xB = targetX, yB = targetY; 
	// g.fillOval(targetX - r, targetY - r, 2 * r, 2 * r);
	g.drawLine(xA, yA, xB, yB); 
	double distance = Math.sqrt((xA - xB) * (xA - xB) + 
				    (yA - yB) * (yA - yB)); 
	int xC, yC; 

	if (distance < R - r) { 
	    xC = targetX; yC = targetY; 
	} else { 
	    double percent = (R - r)/ distance;

	    xC = (int) (percent * (xB - xA)) + xA;
	    yC = (int) (percent * (yB - yA)) + yA;
	}

	g.fillOval(xC-r, yC-r, 2 * r, 2 * r); 

    }
}
And this is a test of what we have developed.


Last updated: Apr 11, 2003 by Adrian German for A201