CSCI A201/A597 and I210

Lecture Notes Twenty-Eight

Second semester 2000-2001


Help with the last assignment.
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 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).

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); 

    }
}
This is a test.


Last updated: April 18, 2001 by Adrian German for A201