![]() |
![]() Java Take-Off Step Six: Geometry of Interaction (Rendering Shapes, Text, Images - Part Two) |
Here's a first program.
What does it do? (Compile and run it).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
Here's another one:
What does it do?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
(Please notice you need this: simon.gif)
How does it do what it does?
Here's a third program:
That's called additive geometry and I hope you like it.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
Here's something related:
Note that you need this (blabber.gif)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
Hope you like this stuff.
Here's another program:
The focus should be here on the internal mechanism of the 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
Here's how we cann use image enhancement operations:
Here are some more images: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
You may or may not need these images now.
Can you use images from the web, directly, in the program above?
T540