Reading assignment for these notes: Petchel, chapter 8.
Here's a first program.
import java.applet.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;
public class CollisionTest extends Applet implements MouseListener,
MouseMotionListener
{
// the number of rectangles contained in our scene
private final int NUM_RECTS = 10;
// a list of rectangles
private LinkedList rectangles;
// an AlphaCompisite to show semi-transparent rectangles
private AlphaComposite alpha;
// the rectangle that is currently selected
private Rectangle2D pick;
public void init()
{
rectangles = new LinkedList();
pick = null;
// create an AlphaComposite with 50% transparency
alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
// create NUM_RECTS rectangles at random positions and add them
// to the list
Random r = new Random();
int width = (int)getSize().getWidth();
int height = (int)getSize().getHeight();
for(int i = 0; i < NUM_RECTS; i++)
{
rectangles.add(new Rectangle2D.Double
(
(double)( Math.abs(r.nextInt())%width),
(double)( Math.abs(r.nextInt())%height),
(double)(20+Math.abs(r.nextInt())%50),
(double)(20+Math.abs(r.nextInt())%50))
);
}
// don't forget to register the applet to listen for mouse events
addMouseListener(this);
addMouseMotionListener(this);
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
// tell our Graphics2D context to use transparency
g2d.setComposite(alpha);
// draw the rectangles
g2d.setPaint(Color.black);
for(int i = 0; i < NUM_RECTS; i++)
{
g2d.draw((Rectangle2D.Double)rectangles.get(i));
}
// if pick refers to a valid rectangle, test it for collisions
if(pick != null)
{
Rectangle2D rect;
g2d.setPaint(Color.red.darker());
for(int i = 0; i < NUM_RECTS; i++)
{
// get the ith rectangle in the list
rect = (Rectangle2D)rectangles.get(i);
// test for intersection-- note we shouldn't test
// pick against itself
if(pick != rect && pick.intersects(rect))
{
// fill collisions
g2d.fill(rect);
}
}
// fill the pick rectangle
g2d.setPaint(Color.blue.brighter());
g2d.fill(pick);
}
}
// methods inherited from the MouseListener interface
public void mouseClicked(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e)
{
// attempt to pick up a rectangle
if(pick == null)
{
Rectangle2D rect;
for(int i = 0; i < NUM_RECTS; i++)
{
rect = (Rectangle2D)rectangles.get(i);
// if the rectangle contains the mouse position,
// 'pick' it up
if(rect.contains(e.getPoint()))
{
pick = rect;
return;
}
}
}
}
public void mouseReleased(MouseEvent e)
{
// release the pick rectangle and repaint the scene
pick = null;
repaint();
}
// methods inherited from the MouseMotionListener interface
public void mouseDragged(MouseEvent e)
{
// if we have a picked rectangle, set its position to the
// current mouse position and repaint
if(pick != null)
{
pick.setRect(e.getX(),
e.getY(),
pick.getWidth(),
pick.getHeight());
repaint();
}
}
public void mouseMoved(MouseEvent e) { }
} // CollisionTest
What does it do? (Compile and run it). Here's another one:
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;
class BoundedImage extends Object
{
// the Image and bounding data for this container
private Image image;
private Rectangle2D bounds;
public BoundedImage(Image img, ImageObserver obs)
{
image = img;
// set the bounds to (0,0) with the width and height of
// the image data
bounds = new Rectangle2D.Double(0, 0,
image.getWidth(obs),
image.getHeight(obs));
}
public Rectangle2D getBounds2D()
{ return bounds;
}
public Image getImage()
{ return image;
}
public AffineTransform getTransform()
{ return AffineTransform.getTranslateInstance
(bounds.getX(),
bounds.getY());
}
public void moveTo(Point p)
{
bounds.setRect((double)p.x, (double)p.y,
bounds.getWidth(),
bounds.getHeight());
}
} // BoundedImage
public class BoundedImageTest extends Applet implements MouseListener,
MouseMotionListener
{
// global reference to the image filename for easy editing
private final String FILENAME = "simon.gif";
// the number of images contained in our scene
private final int NUM_IMAGES = 3;
// a list of BoundedImages
private LinkedList images;
// the BoundedImage that is currently selected
private BoundedImage pick;
// an AlphaCompisite to highlight collisions
private AlphaComposite alpha;
public void init()
{
images = new LinkedList();
pick = null;
// create NUM_IMAGES images at random positions and add them
// to the list
Random r = new Random();
int width = (int)getSize().getWidth();
int height = (int)getSize().getHeight();
// create a MediaTracker object so our images are fully loaded
// before being passed to the BoundedImage class
MediaTracker mt = new MediaTracker(this);
BoundedImage bi; // BoundedImage to add to the list
Image img; // a single Image
for(int i = 0; i < NUM_IMAGES; i++)
{
img = getImage(getCodeBase(), FILENAME);
mt.addImage(img, i);
try
{ mt.waitForID(i);
}
catch(InterruptedException e) { /* do nothing */ }
bi = new BoundedImage(img, this);
bi.moveTo
(new Point
(Math.abs
(r.nextInt())%width,
Math.abs(r.nextInt())%height)
);
images.add(bi);
}
// create an AlphaComposite with 40% transparency
alpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f);
// don't forget to register the applet to listen for mouse events
addMouseListener(this);
addMouseMotionListener(this);
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
// draw the images
BoundedImage bi;
for(int i = 0; i < NUM_IMAGES; i++)
{
bi = (BoundedImage)images.get(i);
g2d.drawImage(bi.getImage(), bi.getTransform(), this);
}
// if pick refers to a valid image, test it for collisions
if(pick != null)
{
for(int i = 0; i < NUM_IMAGES; i++)
{
// get the ith image in the list
bi = (BoundedImage)images.get(i);
// test for intersection
if(imageCollision(pick, bi))
{
// fill the bounding rectangle to highlight
// the collision
g2d.setComposite(alpha);
g2d.setPaint(Color.red.darker());
g2d.fill(bi.getBounds2D());
}
}
// draw and fill the pick rectangle
g2d.setPaint(Color.blue.brighter());
g2d.setComposite(alpha);
g2d.drawImage(pick.getImage(), pick.getTransform(), this);
g2d.fill(pick.getBounds2D());
}
}
// determines if two BoundedImages intersect (collide). this method
// will return false if i1 and i2 refer to the same object
private boolean imageCollision(BoundedImage i1, BoundedImage i2)
{
return (i1 == i2) ? false :
i1.getBounds2D().intersects(i2.getBounds2D());
}
// methods inherited from the MouseListener interface
public void mouseClicked(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mousePressed(MouseEvent e)
{
// attempt to pick up an image
if(pick == null)
{
BoundedImage bi;
for(int i = 0; i < NUM_IMAGES; i++)
{
bi = (BoundedImage)images.get(i);
// if the BoundedImage contains the mouse position,
// 'pick' it up
if(bi.getBounds2D().contains(e.getPoint()))
{
pick = bi;
return;
}
}
}
}
public void mouseReleased(MouseEvent e)
{
// release the pick image and repaint the scene
pick = null;
repaint();
}
// methods inherited from the MouseMotionListener interface
public void mouseDragged(MouseEvent e)
{
// if we have a picked image, set its position to the
// current mouse position and repaint
if(pick != null)
{
pick.moveTo(e.getPoint());
repaint();
}
}
public void mouseMoved(MouseEvent e) { }
} // BoundedImageTest
What does it do? (Please notice you need this: simon.gif)
How does it do what it does?
Here's a third program:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
public class AreaTest extends Applet
{
// an array of Area objects and an associated array of String
// geometry descriptions
private Area[] shapes;
private String[] ops;
public void init()
{
// create 4 Areas and Strings
shapes = new Area[4];
ops = new String[4];
// create two circles that overlap about the origin
Ellipse2D e1 = new Ellipse2D.Double(-0.125, 0.0, 0.5, 0.5);
Ellipse2D e2 = new Ellipse2D.Double(+0.125, 0.0, 0.5, 0.5);
// create a Union between the shapes
shapes[0] = new Area(e1);
shapes[0].add(new Area(e2));
ops[0] = "Union";
// Substract e2 from e1
shapes[1] = new Area(e1);
shapes[1].subtract(new Area(e2));
ops[1] = "Subtraction";
// create an Intersection between the shapes
shapes[2] = new Area(e1);
shapes[2].intersect(new Area(e2));
ops[2] = "Intersection";
// use the Exclusive OR operation between the shapes
shapes[3] = new Area(e1);
shapes[3].exclusiveOr(new Area(e2));
ops[3] = "XOR";
}
public void paint(Graphics g)
{
// cast the sent Graphics context to get a usable Graphics2D object
Graphics2D g2d = (Graphics2D)g;
// create a stroke to outline the shapes
g2d.setStroke(new BasicStroke(2.0f/100.0f));
// a Random object for creating random colors
Random r = new Random();
// render the shapes and the operation descriptions
for(int i = 0; i < 4; i++)
{
g2d.setTransform(new AffineTransform());
g2d.translate(50+(i*100), 40);
g2d.drawString(ops[i], 0, 70);
g2d.scale(100, 100);
g2d.setPaint(new Color(r.nextInt()));
g2d.fill(shapes[i]);
g2d.setPaint(Color.black);
g2d.draw(shapes[i]);
}
}
} // AreaTest
That's called additive geometry and I hope you like it. Here's something related:
import java.applet.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
public class ClipTest extends Applet implements ItemListener
{
// the Image and clip region to render
private Image image;
private Polygon clip;
// a Choice to display the Image and clip region
private Choice dropBox;
// indices for our drop box
private final int SHOW_IMAGE_ONLY = 0;
private final int SHOW_CLIP_ONLY = 1;
private final int SHOW_CLIPPED_IMAGE = 2;
public void init()
{
// load an image from file
MediaTracker mt = new MediaTracker(this);
image = getImage(getCodeBase(), "blabber.gif");
mt.addImage(image, 0);
try
{ mt.waitForID(0);
}
catch(InterruptedException e) { /* do nothing */ }
// create an 8-sided clip region about an anchor point; the
// anchor point will be located at the center of our Image
clip = new Polygon();
int anchor = image.getWidth(this)/2;
for(int i = 0; i < 8; i++)
{
clip.addPoint
(anchor+(int)(anchor*Math.cos(Math.toRadians(i*45))),
anchor+(int)(anchor*Math.sin(Math.toRadians(i*45))));
}
// add the drop box to the bottom of the container, along with the
// three render choices
setLayout(new BorderLayout());
dropBox = new Choice();
dropBox.add("Show Image");
dropBox.add("Show Clip Region");
dropBox.add("Show Clipped Image");
dropBox.addItemListener(this);
add(dropBox, BorderLayout.SOUTH);
}
public void paint(Graphics g)
{
// cast the sent Graphics context to get a usable Graphics2D object
Graphics2D g2d = (Graphics2D)g;
// set the transform to the identity transform
final AffineTransform at = new AffineTransform();
// render based on the current selection
switch(dropBox.getSelectedIndex())
{
case SHOW_IMAGE_ONLY:
{
// just draw the Image
g2d.drawImage(image, at, this);
break;
}
case SHOW_CLIP_ONLY:
{
// just draw the clipping region
g2d.setTransform(at);
g2d.draw(clip);
break;
}
case SHOW_CLIPPED_IMAGE:
{
// draw the Image with respect to the clipping region
g2d.setClip(clip);
g2d.drawImage(image, at, this);
break;
}
default:
{
// invalid index
System.out.println("Invalid Choice: " +
dropBox.getSelectedIndex());
break;
}
}
}
public void itemStateChanged(ItemEvent e)
{
// our drop box has changed-- redraw the scene
repaint();
}
} // ClipTest
Note that you need this (blabber.gif) Hope you like this stuff.
Here's another program:
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;
public class BufferedImageTest extends Applet
{
// a BufferedImage, along with its creation width and height
private BufferedImage image;
private final int BI_WIDTH = 100;
private final int BI_HEIGHT = 100;
// for generating random colors and screen positions
private java.util.Random random;
public void init()
{
random = new java.util.Random();
// create a (BI_WIDTH x BI_HEIGHT) buffered image
image = new BufferedImage(BI_WIDTH,
BI_HEIGHT,
BufferedImage.TYPE_INT_RGB);
// create a Graphics2D context for our BufferedImage. Remember
// this has nothing to do with our Applet's Graphics2D context
Graphics2D g2d = image.createGraphics();
// we will render some stripes to the BufferedImage
// the width and height of our stripes will be one-tenth
// the total width and height of the image
final int stripWidth = BI_WIDTH / 10;
final int stripHeight = BI_HEIGHT / 10;
// fill the image with a random color
g2d.setPaint(new Color(random.nextInt()));
g2d.fill(new Rectangle(0, 0, BI_WIDTH, BI_HEIGHT));
// render the vertical strips using a random color
g2d.setPaint(new Color(random.nextInt()));
int x = stripWidth / 2;
while(x < BI_WIDTH)
{
g2d.fill(new Rectangle(x, 0, stripWidth, BI_HEIGHT));
x += 2 * stripWidth;
}
// set a transparency channel for our stripes
g2d.setComposite
(AlphaComposite.getInstance
(AlphaComposite.SRC_OVER, 0.5f));
// render the horizontal strips using a random color
g2d.setPaint(new Color(random.nextInt()));
int y = stripHeight / 2;
while(y < BI_HEIGHT)
{
g2d.fill(new Rectangle(0, y, BI_WIDTH, stripHeight));
y += 2 * stripHeight;
}
// render a dark opaque outline around the perimeter of the image
g2d.setStroke(new BasicStroke(2.0f));
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
g2d.setPaint(Color.black);
g2d.draw(new Rectangle(0, 0, BI_WIDTH, BI_HEIGHT));
}
public void paint(Graphics g)
{
// cast the sent Graphics context to get a usable Graphics2D object
Graphics2D g2d = (Graphics2D)g;
// draw a bunch of images at random locations
for(int i = 0; i < 20; i++)
{
g2d.drawImage
(image,
AffineTransform.getTranslateInstance
(
random.nextInt()%getSize().getWidth(),
random.nextInt()%getSize().getHeight()
),
this
);
}
}
} // BITextureTest
The focus should be here on the internal mechanism of the program. Here's how we cann use image enhancement operations:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
public class BlurTest extends Applet implements ActionListener
{
// the original and blurred BufferedImages
private BufferedImage sourceImage;
private BufferedImage destImage;
// field for accepting a filename
private TextField input;
public void init()
{
// create a layout and add the textfield and "Ok" button
setLayout(new BorderLayout());
Panel p = new Panel();
input = new TextField("", 20);
p.add(input);
Button ok = new Button("Ok");
ok.addActionListener(this);
p.add(ok);
add(p, BorderLayout.SOUTH);
}
public void paint(Graphics g)
{
// cast the sent Graphics context to get a usable Graphics2D object
Graphics2D g2d = (Graphics2D)g;
// draw a friendly reminder to input a filename if the text
// field just contains white-space
if("".equals(input.getText().trim()))
{
g2d.drawString("Enter a filename to blur", 10, 50);
return;
}
// load the input image
MediaTracker mt = new MediaTracker(this);
Image img = getImage(getCodeBase(), input.getText());
mt.addImage(img, 0);
try
{
// wait until the image has loaded completely
// before continuing
mt.waitForID(0);
}
catch(InterruptedException e) { /* do nothing */ }
// our blur operation will require a BufferedImage object, so render
// the input image to a new BufferedImage object
sourceImage = new BufferedImage(img.getWidth(this),
img.getHeight(this),
BufferedImage.TYPE_INT_RGB);
sourceImage.createGraphics().drawImage(img, null, this);
// create the destination image
destImage = new BufferedImage(sourceImage.getWidth(this),
sourceImage.getHeight(this),
BufferedImage.TYPE_INT_RGB);
// blur the input image
blur(sourceImage, destImage, 0.1f, 3, 3);
// draw both the source and destination images
AffineTransform at = new AffineTransform();
int width = sourceImage.getWidth(this);
g2d.drawImage(sourceImage, at, this);
at.translate(width+20, 0);
g2d.drawImage(destImage, at, this);
}
// blurs an image using a ConvolveOp operation
public void blur(
BufferedImage sourceImage, // the input image data
BufferedImage destImage, // the output image data
float weight, // weight of the Kernel data
int width, // width of the Kernel
int height // height of the Kernel
)
{
// this will be the data array for our Kernel
float[] elements = new float[width*height];
// fill the array with the weight
java.util.Arrays.fill(elements, weight);
// use the array of elements and the
// width and height to create a Kernel
Kernel k = new Kernel(width, height, elements);
ConvolveOp blurOp = new ConvolveOp(k);
// blur the image
blurOp.filter(sourceImage, destImage);
}
public void actionPerformed(ActionEvent e)
{
// the "Ok" was pressed; update the changes
repaint();
}
} // BlurTest
Here are some more images:
You may or may not need these images now.
Can you use images from the web, directly, in the program above?
A290/A590