Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: create clipping region that has a hole?

Tags:

java

clipping

How do you define a clipping region (via Graphics2D.clip(Shape)) that has a hole in it?

for example: a Rectangle r1 minus another Rectangle r2 inside r1

I'm sure this has an easy answer, but I'm drawing a blank.

like image 895
Jason S Avatar asked Jun 08 '11 14:06

Jason S


3 Answers

Path2D.append() + EVEN_ODD winding rule appear to do the trick:

enter image description here

package com.example.test.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class HoleClipper extends JPanel
{
    @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        Rectangle2D r1 = getBounds();
        int margin = 50;
        Rectangle2D r2 = new Rectangle2D.Double(
                r1.getMinX()+margin,
                r1.getMinY()+margin,
                r1.getWidth()-2*margin,
                r1.getHeight()-2*margin);

        g2d.setColor(Color.YELLOW);
        g2d.fill(r1);

        Path2D p = new Path2D.Double(Path2D.WIND_EVEN_ODD);
        p.append(r1, false);
        p.append(r2, false);
        g2d.clip(p);

        int spacing = 10;
        g2d.setColor(Color.BLACK);
        for (double d = 0; d < r1.getWidth() + r1.getHeight(); d += spacing)
        {
            Line2D line = new Line2D.Double(0, d, d, 0);
            g2d.draw(line);
        }
    }

    public static void main(String[] args) {
        HoleClipper clipper = new HoleClipper();
        clipper.setPreferredSize(new Dimension(300, 200));

        JFrame frame = new JFrame("HoleClipper");
        frame.setContentPane(clipper);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}
like image 86
Jason S Avatar answered Nov 16 '22 08:11

Jason S


Looks like this is not supported by Graphics's setClip. As I read the documentation a rectangle is all that is supported:

public abstract void setClip(Shape clip)

Sets the current clipping area to an arbitrary clip shape. Not all objects that implement the Shape interface can be used to set the clip. The only Shape objects that are guaranteed to be supported are Shape objects that are obtained via the getClip method and via Rectangle objects. This method sets the user clip, which is independent of the clipping associated with device bounds and window visibility.

like image 2
jzd Avatar answered Nov 16 '22 06:11

jzd


The GeneralPath class is an implementation of Shape that can represent shapes with holes in them. You define multiple path segments, one representing the "outside", and one representing the "hole". Define the clipping region you want using GeneralPath, and then call clip().

like image 1
Ernest Friedman-Hill Avatar answered Nov 16 '22 08:11

Ernest Friedman-Hill