Home  Contents

Clipping

In this part of the Java 2D tutorial, we will talk about clipping.

Clipping

Clipping is restricting of drawing to a certain area. This is done for effeciency reasons and to create various effects.

In the following example we will be clipping an image.

Clipping.java
package com.zetcode; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Ellipse2D; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; public class Clipping extends JPanel implements ActionListener { private int pos_x = 8; private int pos_y = 8; private int radius = 90; Timer timer; Image image; private double delta[] = { 3, 3 }; public Clipping() { image = new ImageIcon("bardejov.png").getImage(); timer = new Timer(15, this); timer.start(); } public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; RenderingHints rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); g2d.setClip(new Ellipse2D.Double(pos_x, pos_y, radius, radius)); g2d.drawImage(image, 5, 5, null); } public static void main(String[] args) { JFrame frame = new JFrame("Clipping"); frame.add(new Clipping()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(400, 300); frame.setLocationRelativeTo(null); frame.setVisible(true); } public void actionPerformed(ActionEvent e) { int w = getWidth(); int h = getHeight(); if (pos_x < 0) { delta[0] = Math.random() % 4 + 5; } else if (pos_x > w - radius) { delta[0] = -(Math.random() % 4 + 5); } if (pos_y < 0 ) { delta[1] = Math.random() % 4 + 5; } else if (pos_y > h - radius) { delta[1] = -(Math.random() % 4 + 5); } pos_x += delta[0]; pos_y += delta[1]; repaint(); } }

In this example, we will clip an image. A circle is moving on the screen and showing a part of the underlying image. This is as if we looked through a hole.

 g2d.setClip(new Ellipse2D.Double(pos_x, pos_y, radius, radius));

This is the key part of the code. Here we restrict drawing to a specific shape. In our case it is a circle.

 if (pos_x < 0) {
     delta[0] = Math.random() % 4 + 5;
 } else if (pos_x > w - radius) {
     delta[0] = -(Math.random() % 4 + 5);
 }

If the circle hits the left or the right side of the window, the direction of the circle movement changes randomly. Same for the top and bottom sides.


Clipping
Figure: Clipping

Clipping shapes

In the following example, we will be clipping two shapes. A rectangle and a circle.

ClippingShapes.java
package com.zetcode; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; public class ClippingShapes extends JPanel implements ActionListener { private Timer timer; private double rotate = 1; private int pos_x = 8; private int pos_y = 8; private int radius = 60; private double delta[] = { 1, 1 }; public ClippingShapes() { timer = new Timer(10, this); timer.start(); } public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); int w = getWidth(); int h = getHeight(); Rectangle rect1 = new Rectangle(0, 0, 200, 80); AffineTransform tx = new AffineTransform(); tx.rotate(Math.toRadians(rotate), w / 2, h / 2); tx.translate(w / 2 - 100, h / 2 - 40); Ellipse2D circle = new Ellipse2D.Double(pos_x, pos_y, radius, radius); step(); GeneralPath path = new GeneralPath(); path.append(tx.createTransformedShape(rect1), false); g2d.setColor(new Color(110, 110, 110)); g2d.clip(circle); g2d.clip(path); g2d.fill(circle); g2d.setClip(new Rectangle(0, 0, w, h)); g2d.draw(circle); g2d.draw(path); } public void step() { int w = getWidth(); int h = getHeight(); if (pos_x < 0) { delta[0] = 1; } else if (pos_x > w - radius) { delta[0] = -1; } if (pos_y < 0) { delta[1] = 1; } else if (pos_y > h - radius) { delta[1] = -1; } pos_x += delta[0]; pos_y += delta[1]; } public static void main(String[] args) { JFrame frame = new JFrame("Clipping shapes"); frame.add(new ClippingShapes()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(350, 300); frame.setLocationRelativeTo(null); frame.setVisible(true); } public void actionPerformed(ActionEvent e) { rotate += 1; repaint(); } }

In our example, we have a bouncing circle and a rotating rectangle. When these shapes overlap, the resulting area is filled with color.

 Rectangle rect1 = new Rectangle(0, 0, 200, 80);

 AffineTransform tx = new AffineTransform();
 tx.rotate(Math.toRadians(rotate), w / 2, h / 2);
 tx.translate(w / 2 - 100, h / 2 - 40);

The rectangle is being rotated. It is always positioned in the middle of the panel.

 GeneralPath path = new GeneralPath();
 path.append(tx.createTransformedShape(rect1), false);

Here we get the shape of the rotated rectangle.

 g2d.clip(circle);
 g2d.clip(path);

 g2d.fill(circle)

Here we restrict drawing to these two shapes. If they overlap, the interior of the resulting shape is filled with color.

 g2d.setClip(new Rectangle(0, 0, w, h));

We reset the clip areas, before we draw the shapes.


Clipping Shapes
Figure: Clipping Shapes