Java/2D Graphics GUI/Clip
Содержание
Clip another area
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.TitledBorder;
public class ClipArea extends JFrame {
MyCanvas canvas;
JRadioButton clipButton, clipFurButton;
public ClipArea() {
super();
Container contentPane = getContentPane();
canvas = new MyCanvas();
contentPane.add(canvas);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(1, 2));
clipButton = new JRadioButton("Clip", true);
clipButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
canvas.clip = true;
canvas.clipFurther = false;
canvas.repaint();
}
});
clipFurButton = new JRadioButton("Clip Further");
clipFurButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
canvas.clipFurther = true;
canvas.repaint();
}
});
ButtonGroup group = new ButtonGroup();
group.add(clipButton);
group.add(clipFurButton);
panel.add(clipButton);
panel.add(clipFurButton);
contentPane.add(BorderLayout.SOUTH, panel);
// 4. Add a window listener to close the frame properly.
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
pack();
setVisible(true);
}
public static void main(String arg[]) {
new ClipArea();
}
}
class MyCanvas extends JPanel{
boolean clip = true;
boolean clipFurther = false;
MyCanvas() {
setSize(300, 300);
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
int w = getSize().width;
int h = getSize().height;
if (clip) {
Ellipse2D e = new Ellipse2D.Float(w / 4.0f, h / 4.0f, w / 2.0f,
h / 2.0f);
g2.setClip(e);
g2.setColor(Color.yellow);
g2.fillRect(0, 0, w, h);
}
if (clipFurther) {
Rectangle r = new Rectangle(w / 2, h / 2, w / 2, h / 2);
g2.clip(r);
g2.setColor(Color.green);
g2.fillRect(0, 0, w, h);
}
}
}
Clip Image
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class ClipImage extends JApplet implements Runnable {
private Image img;
private final double OINC[] = { 5.0, 3.0 };
private final double SINC[] = { 5.0, 5.0 };
private double x, y;
private double ix = OINC[0];
private double iy = OINC[1];
private double iw = SINC[0];
private double ih = SINC[1];
private double ew, eh; // ellipse width & height
private GeneralPath p = new GeneralPath();
private AffineTransform at = new AffineTransform();
private BasicStroke bs = new BasicStroke(20.0f);
private Arc2D arc = new Arc2D.Float();
private Ellipse2D ellipse = new Ellipse2D.Float();
private RoundRectangle2D roundRect = new RoundRectangle2D.Float();
private Rectangle2D rect = new Rectangle2D.Float();
private Color redBlend = new Color(255, 0, 0, 120);
private Color greenBlend = new Color(0, 255, 0, 120);
private Thread thread;
private BufferedImage offImg;
private int w, h;
private boolean newBufferedImage;
public void init() {
img = getImage(getURL("largejexpLogo.GIF"));
try {
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(img, 0);
tracker.waitForID(0);
} catch (Exception e) {
}
}
public void drawDemo(Graphics2D g2) {
if (newBufferedImage) {
x = Math.random() * w;
y = Math.random() * h;
ew = (Math.random() * w) / 2;
eh = (Math.random() * h) / 2;
}
x += ix;
y += iy;
ew += iw;
eh += ih;
if (ew > w / 2) {
ew = w / 2;
iw = Math.random() * -w / 16 - 1;
}
if (ew < w / 8) {
ew = w / 8;
iw = Math.random() * w / 16 + 1;
}
if (eh > h / 2) {
eh = h / 2;
ih = Math.random() * -h / 16 - 1;
}
if (eh < h / 8) {
eh = h / 8;
ih = Math.random() * h / 16 + 1;
}
if ((x + ew) > w) {
x = (w - ew) - 1;
ix = Math.random() * -w / 32 - 1;
}
if (x < 0) {
x = 2;
ix = Math.random() * w / 32 + 1;
}
if ((y + eh) > h) {
y = (h - eh) - 2;
iy = Math.random() * -h / 32 - 1;
}
if (y < 0) {
y = 2;
iy = Math.random() * h / 32 + 1;
}
ellipse.setFrame(x, y, ew, eh);
g2.setClip(ellipse);
rect.setRect(x + 5, y + 5, ew - 10, eh - 10);
g2.clip(rect);
g2.drawImage(img, 0, 0, w, h, this);
p.reset();
p.moveTo(-w / 2.0f, -h / 8.0f);
p.lineTo(+w / 2.0f, -h / 8.0f);
p.lineTo(-w / 4.0f, +h / 2.0f);
p.lineTo(+0.0f, -h / 2.0f);
p.lineTo(+w / 4.0f, +h / 2.0f);
p.closePath();
at.setToIdentity();
at.translate(w * .5f, h * .5f);
g2.transform(at);
g2.setStroke(bs);
g2.setPaint(redBlend);
g2.draw(p);
at.setToIdentity();
g2.setTransform(at);
g2.setPaint(greenBlend);
for (int yy = 0; yy < h; yy += 50) {
for (int xx = 0, i = 0; xx < w; i++, xx += 50) {
switch (i) {
case 0:
arc.setArc(xx, yy, 25, 25, 45, 270, Arc2D.PIE);
g2.fill(arc);
break;
case 1:
ellipse.setFrame(xx, yy, 25, 25);
g2.fill(ellipse);
break;
case 2:
roundRect.setRoundRect(xx, yy, 25, 25, 4, 4);
g2.fill(roundRect);
break;
case 3:
rect.setRect(xx, yy, 25, 25);
g2.fill(rect);
i = -1;
}
}
}
}
public Graphics2D createDemoGraphics2D(Graphics g) {
Graphics2D g2 = null;
if (offImg == null || offImg.getWidth() != w || offImg.getHeight() != h) {
offImg = (BufferedImage) createImage(w, h);
newBufferedImage = true;
}
if (offImg != null) {
g2 = offImg.createGraphics();
g2.setBackground(getBackground());
}
// .. set attributes ..
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
// .. clear canvas ..
g2.clearRect(0, 0, w, h);
return g2;
}
public void paint(Graphics g) {
w = getWidth();
h = getHeight();
if (w <= 0 || h <= 0)
return;
Graphics2D g2 = createDemoGraphics2D(g);
drawDemo(g2);
g2.dispose();
if (offImg != null && isShowing()) {
g.drawImage(offImg, 0, 0, this);
}
newBufferedImage = false;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
thread = null;
}
public void run() {
Thread me = Thread.currentThread();
while (thread == me && isShowing()) {
Graphics g = getGraphics();
paint(g);
g.dispose();
thread.yield();
}
thread = null;
}
protected URL getURL(String filename) {
URL codeBase = this.getCodeBase();
URL url = null;
try {
url = new URL(codeBase, filename);
} catch (java.net.MalformedURLException e) {
System.out.println("Couldn"t create image: "
+ "badly specified URL");
return null;
}
return url;
}
public static void main(String s[]) {
final ClipImage demo = new ClipImage();
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowDeiconified(WindowEvent e) {
demo.start();
}
public void windowIconified(WindowEvent e) {
demo.stop();
}
};
JFrame f = new JFrame("Java 2D Demo - ClipImage");
f.addWindowListener(l);
f.getContentPane().add("Center", demo);
f.setSize(new Dimension(400, 300));
f.show();
demo.start();
}
}
Clipping is restricting of drawing to a certain area.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
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 {
int x = 8, y = 8, radius = 90;
Timer timer;
Image image = new ImageIcon("yourImage.png").getImage();
double delta[] = { 3, 3 };
public Clipping() {
timer = new Timer(15, this);
timer.start();
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setClip(new Ellipse2D.Double(x, y, radius, radius));
g2d.drawImage(image, 5, 5, null);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new Clipping());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
int w = 400;
int h = 400;
if (x < 0) {
delta[0] = Math.random() % 4 + 5;
} else if (x > w - radius) {
delta[0] = -(Math.random() % 4 + 5);
}
if (y < 0) {
delta[1] = Math.random() % 4 + 5;
} else if (y > h - radius) {
delta[1] = -(Math.random() % 4 + 5);
}
x += delta[0];
y += delta[1];
repaint();
}
}
Clips the specified line to the given rectangle.
/*
* JFreeChart : a free chart library for the Java(tm) platform
*
*
* (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jfreechart/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------------
* LineUtilities.java
* ------------------
* (C) Copyright 2008, by Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* Changes
* -------
* 05-Nov-2008 : Version 1 (DG);
*
*/
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
/**
* Some utility methods for {@link Line2D} objects.
*
* @since 1.0.12
*/
public class LineUtilities {
/**
* Clips the specified line to the given rectangle.
*
* @param line the line (<code>null</code> not permitted).
* @param rect the clipping rectangle (<code>null</code> not permitted).
*
* @return <code>true</code> if the clipped line is visible, and
* <code>false</code> otherwise.
*/
public static boolean clipLine(Line2D line, Rectangle2D rect) {
double x1 = line.getX1();
double y1 = line.getY1();
double x2 = line.getX2();
double y2 = line.getY2();
double minX = rect.getMinX();
double maxX = rect.getMaxX();
double minY = rect.getMinY();
double maxY = rect.getMaxY();
int f1 = rect.outcode(x1, y1);
int f2 = rect.outcode(x2, y2);
while ((f1 | f2) != 0) {
if ((f1 & f2) != 0) {
return false;
}
double dx = (x2 - x1);
double dy = (y2 - y1);
// update (x1, y1), (x2, y2) and f1 and f2 using intersections
// then recheck
if (f1 != 0) {
// first point is outside, so we update it against one of the
// four sides then continue
if ((f1 & Rectangle2D.OUT_LEFT) == Rectangle2D.OUT_LEFT
&& dx != 0.0) {
y1 = y1 + (minX - x1) * dy / dx;
x1 = minX;
}
else if ((f1 & Rectangle2D.OUT_RIGHT) == Rectangle2D.OUT_RIGHT
&& dx != 0.0) {
y1 = y1 + (maxX - x1) * dy / dx;
x1 = maxX;
}
else if ((f1 & Rectangle2D.OUT_BOTTOM) == Rectangle2D.OUT_BOTTOM
&& dy != 0.0) {
x1 = x1 + (maxY - y1) * dx / dy;
y1 = maxY;
}
else if ((f1 & Rectangle2D.OUT_TOP) == Rectangle2D.OUT_TOP
&& dy != 0.0) {
x1 = x1 + (minY - y1) * dx / dy;
y1 = minY;
}
f1 = rect.outcode(x1, y1);
}
else if (f2 != 0) {
// second point is outside, so we update it against one of the
// four sides then continue
if ((f2 & Rectangle2D.OUT_LEFT) == Rectangle2D.OUT_LEFT
&& dx != 0.0) {
y2 = y2 + (minX - x2) * dy / dx;
x2 = minX;
}
else if ((f2 & Rectangle2D.OUT_RIGHT) == Rectangle2D.OUT_RIGHT
&& dx != 0.0) {
y2 = y2 + (maxX - x2) * dy / dx;
x2 = maxX;
}
else if ((f2 & Rectangle2D.OUT_BOTTOM) == Rectangle2D.OUT_BOTTOM
&& dy != 0.0) {
x2 = x2 + (maxY - y2) * dx / dy;
y2 = maxY;
}
else if ((f2 & Rectangle2D.OUT_TOP) == Rectangle2D.OUT_TOP
&& dy != 0.0) {
x2 = x2 + (minY - y2) * dx / dy;
y2 = minY;
}
f2 = rect.outcode(x2, y2);
}
}
line.setLine(x1, y1, x2, y2);
return true; // the line is visible - if it wasn"t, we"d have
// returned false from within the while loop above
}
}
Clip the area
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class ClipDemo extends JComponent {
private static Color red = new Color(255, 0, 0, 150);
private static Color green = new Color(0, 255, 0, 150);
private static Color blue = new Color(0, 0, 255, 150);
private static Font monoFont = new Font("Monospaced", Font.BOLD
| Font.ITALIC, 36);
private static Font sanFont = new Font("SanSerif", Font.PLAIN, 12);
private static Font serifFont = new Font("Serif", Font.BOLD, 24);
private static ImageIcon jexpLogo = new ImageIcon("jexpLogo.gif");
public void paintComponent(Graphics g) {
super.paintComponent(g);
// get damaged region
Rectangle clipRect = g.getClipBounds();
int clipx = clipRect.x;
int clipy = clipRect.y;
int clipw = clipRect.width;
int cliph = clipRect.height;
// fill damaged region only
g.setColor(Color.white);
g.fillRect(clipx, clipy, clipw, cliph);
if (clipx <= 240 && clipy <= 240) {
g.setColor(Color.yellow);
g.fillOval(0, 0, 240, 240);
System.out.println(" yellow Oval repainted.");
}
if (clipx + clipw >= 160 && clipx <= 400 && clipy + cliph >= 160
&& clipy <= 400) {
g.setColor(Color.magenta);
g.fillOval(160, 160, 240, 240);
System.out.println(" magenta Oval repainted.");
}
int iconWidth = jexpLogo.getIconWidth();
int iconHeight = jexpLogo.getIconHeight();
if (clipx + clipw >= 280 - (iconWidth / 2) && clipx <= (280 + (iconWidth / 2))
&& clipy + cliph >= 120 - (iconHeight / 2) && clipy <= (120 + (iconHeight / 2))) {
jexpLogo.paintIcon(this, g, 280 - (iconWidth / 2), 120 - (iconHeight / 2));
System.out.println(" logo below blue Rect repainted.");
}
if (clipx + clipw >= 120 - (iconWidth / 2) && clipx <= (120 + (iconWidth / 2))
&& clipy + cliph >= 280 - (iconHeight / 2) && clipy <= (280 + (iconHeight / 2))) {
jexpLogo.paintIcon(this, g, 120 - (iconWidth / 2), 280 - (iconHeight / 2));
System.out.println(" logo below red Rect repainted.");
}
if (clipx + clipw >= 60 && clipx <= 180 && clipy + cliph >= 220
&& clipy <= 340) {
g.setColor(red);
g.fillRect(60, 220, 120, 120);
System.out.println(" red Rect repainted.");
}
if (clipx + clipw > 140 && clipx < 260 && clipy + cliph > 140
&& clipy < 260) {
g.setColor(green);
g.fillOval(140, 140, 120, 120);
System.out.println(" green Oval repainted.");
}
if (clipx + clipw > 220 && clipx < 380 && clipy + cliph > 60
&& clipy < 180) {
g.setColor(blue);
g.fillRect(220, 60, 120, 120);
System.out.println(" blue Rect repainted.");
}
g.setColor(Color.black);
g.setFont(monoFont);
FontMetrics fm = g.getFontMetrics();
iconWidth = fm.stringWidth("Java Source");
iconHeight = fm.getAscent();
int d = fm.getDescent();
if (clipx + clipw > 120 - (iconWidth / 2) && clipx < (120 + (iconWidth / 2))
&& clipy + cliph > (120 + (iconHeight / 4)) - iconHeight
&& clipy < (120 + (iconHeight / 4)) + d) {
g.drawString("Java Source", 120 - (iconWidth / 2), 120 + (iconHeight / 4));
System.out.println(" Java Source repainted.");
}
g.setFont(sanFont);
fm = g.getFontMetrics();
iconWidth = fm.stringWidth("and");
iconHeight = fm.getAscent();
d = fm.getDescent();
if (clipx + clipw > 200 - (iconWidth / 2) && clipx < (200 + (iconWidth / 2))
&& clipy + cliph > (200 + (iconHeight / 4)) - iconHeight
&& clipy < (200 + (iconHeight / 4)) + d) {
g.drawString("and", 200 - (iconWidth / 2), 200 + (iconHeight / 4));
System.out.println(" and repainted.");
}
g.setFont(serifFont);
fm = g.getFontMetrics();
iconWidth = fm.stringWidth("Support.");
iconHeight = fm.getAscent();
d = fm.getDescent();
if (clipx + clipw > 280 - (iconWidth / 2) && clipx < (280 + (iconWidth / 2))
&& clipy + cliph > (280 + (iconHeight / 4)) - iconHeight
&& clipy < (280 + (iconHeight / 4)) + d) {
g.drawString("Support.", 280 - (iconWidth / 2), 280 + (iconHeight / 4));
System.out.println(" Support. repainted.");
}
}
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
public static void main(String args[]) {
JFrame mainFrame = new JFrame();
mainFrame.getContentPane().add(new ClipDemo());
mainFrame.pack();
mainFrame.setVisible(true);
}
}
Copy Area Performance
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/*
* CopyAreaPerformance.java
*
* Created on May 1, 2007, 4:24 PM
*
* Copyright (c) 2007, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the TimingFramework project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
*
* @author Chet
*/
public class CopyAreaPerformance extends JComponent implements KeyListener {
private static final int SMILEY_SIZE = 10;
private static final int PADDING = 2;
private static final int MIN_COLOR = 0;
private static final int CANVAS_W = SMILEY_SIZE * (256 - MIN_COLOR);
private static final int CANVAS_H = SMILEY_SIZE * (256 - MIN_COLOR);
private static final int SCROLL_SIZE = 100;
private int viewX = CANVAS_W / 2;
private int viewY = CANVAS_H / 2;
private boolean useCopyArea = false;
private boolean useClip = false;
int prevVX;
int prevVY;
/** Creates a new instance of CopyAreaPerformance */
public CopyAreaPerformance() {
setOpaque(true);
}
private void drawSmiley(Graphics g, Color faceColor, int x, int y) {
// fill face color
g.setColor(faceColor);
g.fillOval(x, y, SMILEY_SIZE, SMILEY_SIZE);
g.setColor(Color.BLACK);
// draw head
g.drawOval(x, y, SMILEY_SIZE, SMILEY_SIZE);
// draw smile
g.drawArc(x + (int) ((SMILEY_SIZE * .2)), (int) (y + (SMILEY_SIZE * .2)),
(int) (SMILEY_SIZE * .6), (int) (SMILEY_SIZE * .6), 200, 140);
// draw eyes
int eyeSize = Math.max(2, (int) (SMILEY_SIZE * .1));
g.fillOval(x + (int) ((SMILEY_SIZE * .5) - (SMILEY_SIZE * .1) - eyeSize), y
+ (int) (SMILEY_SIZE * .3), eyeSize, eyeSize);
g.fillOval(x + (int) ((SMILEY_SIZE * .5) + (SMILEY_SIZE * .1)), y + (int) (SMILEY_SIZE * .3),
eyeSize, eyeSize);
}
protected void paintComponent(Graphics g) {
long startTime = System.nanoTime();
// prevVX is set to -10000 when first enabled
if (useCopyArea && prevVX > -9999) {
// Most of this code determines the proper areas to copy and clip
int scrollX = viewX - prevVX;
int scrollY = viewY - prevVY;
int copyFromY, copyFromX;
int clipFromY, clipFromX;
if (scrollX == 0) {
// vertical scroll
if (scrollY < 0) {
copyFromY = 0;
clipFromY = 0;
} else {
copyFromY = scrollY;
clipFromY = getHeight() - scrollY;
}
// copy the old content, set the clip to the new area
g.copyArea(0, copyFromY, getWidth(), getHeight() - Math.abs(scrollY), 0, -scrollY);
g.setClip(0, clipFromY, getWidth(), Math.abs(scrollY));
} else {
// horizontal scroll
if (scrollX < 0) {
copyFromX = 0;
clipFromX = 0;
} else {
copyFromX = scrollX;
clipFromX = getWidth() - scrollX;
}
// copy the old content, set the clip to the new area
g.copyArea(copyFromX, 0, getWidth() - Math.abs(scrollX), getHeight(), -scrollX, 0);
g.setClip(clipFromX, 0, Math.abs(scrollX), getHeight());
}
}
// Track previous view position for next scrolling operation
prevVX = viewX;
prevVY = viewY;
// Get the clip in case we need it later
Rectangle clipRect = g.getClip().getBounds();
int clipL = (int) (clipRect.getX());
int clipT = (int) (clipRect.getY());
int clipR = (int) (clipRect.getMaxX());
int clipB = (int) (clipRect.getMaxY());
g.setColor(Color.WHITE);
g.fillRect(clipL, clipT, (int) clipRect.getWidth(), (int) clipRect.getHeight());
for (int column = 0; column < 256; ++column) {
int x = column * (SMILEY_SIZE + PADDING) - viewX;
if (useClip) {
if (x > clipR || (x + (SMILEY_SIZE + PADDING)) < clipL) {
// trivial reject; outside to the left or right
continue;
}
}
for (int row = 0; row < 256; ++row) {
int y = row * (SMILEY_SIZE + PADDING) - viewY;
if (useClip) {
if (y > clipB || (y + (SMILEY_SIZE + PADDING)) < clipT) {
// trivial reject; outside to the top or bottom
continue;
}
}
Color faceColor = new Color(column, row, 0);
drawSmiley(g, faceColor, x, y);
}
}
long stopTime = System.nanoTime();
System.out.println("Painted in " + ((stopTime - startTime) / 1000000) + " ms");
}
private void scroll(int scrollX, int scrollY) {
viewX += scrollX;
viewY += scrollY;
viewX = Math.max(viewX, 0);
viewX = Math.min(viewX, CANVAS_W - viewX);
viewY = Math.max(viewY, 0);
viewY = Math.min(viewY, CANVAS_H - viewY);
repaint();
}
// KeyListener methods
/**
* Arrow keys scroll the view around. The "c" key toggles clip area
* optimization. The "a" key toggles copyArea optimization.
*/
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
scroll(SCROLL_SIZE, 0);
} else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
scroll(-SCROLL_SIZE, 0);
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
scroll(0, -SCROLL_SIZE);
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
scroll(0, SCROLL_SIZE);
} else if (e.getKeyCode() == KeyEvent.VK_C) {
useClip = !useClip;
System.out.println("useClip = " + useClip);
} else if (e.getKeyCode() == KeyEvent.VK_A) {
useCopyArea = !useCopyArea;
prevVX = -10000;
System.out.println("useCopyArea = " + useCopyArea);
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
private static void createAndShowGUI() {
JFrame f = new JFrame("CopyAreaPerformance");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(600, 600);
CopyAreaPerformance component = new CopyAreaPerformance();
f.add(component);
f.addKeyListener(component);
f.setVisible(true);
}
public static void main(String args[]) {
Runnable doCreateAndShowGUI = new Runnable() {
public void run() {
createAndShowGUI();
}
};
SwingUtilities.invokeLater(doCreateAndShowGUI);
}
}
Represents a clipping rectangle in a prefuse Display
//revised from prefuse display;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.util.logging.Logger;
/**
* Represents a clipping rectangle in a prefuse <code>Display</code>.
*
* @author
*/
public class Clip {
private static final byte EMPTY = 0;
private static final byte INUSE = 1;
private static final byte INVALID = 2;
private double[] clip = new double[8];
private byte status = INVALID;
/**
* Reset the clip to an empty status.
*/
public void reset() {
status = EMPTY;
}
/**
* Invalidate the clip. In this state, the clip contents have no meaning.
*/
public void invalidate() {
status = INVALID;
}
/**
* Set the clip contents, and set the status to valid and in use.
* @param c the clip whose contents should be copied
*/
public void setClip(Clip c) {
status = INUSE;
System.arraycopy(c.clip, 0, clip, 0, clip.length);
}
/**
* Set the clip contents, and set the status to valid and in use.
* @param r the clip contents to copy
*/
public void setClip(Rectangle2D r) {
setClip(r.getX(),r.getY(),r.getWidth(),r.getHeight());
}
/**
* Set the clip contents, and set the status to valid and in use.
* @param x the minimum x-coordinate
* @param y the minimum y-coorindate
* @param w the clip width
* @param h the clip height
*/
public void setClip(double x, double y, double w, double h) {
status = INUSE;
clip[0] = x;
clip[1] = y;
clip[6] = x+w;
clip[7] = y+h;
}
/**
* Transform the clip contents. A new clip region will be created
* which is the bounding box of the transformed region.
* @param at the affine transform
*/
public void transform(AffineTransform at) {
// make the extra corner points valid
clip[2] = clip[0]; clip[3] = clip[7];
clip[4] = clip[6]; clip[5] = clip[1];
// transform the points
at.transform(clip,0,clip,0,4);
// make safe against rotation
double xmin = clip[0], ymin = clip[1];
double xmax = clip[6], ymax = clip[7];
for ( int i=0; i<7; i+=2 ) {
if ( clip[i] < xmin )
xmin = clip[i];
if ( clip[i] > xmax )
xmax = clip[i];
if ( clip[i+1] < ymin )
ymin = clip[i+1];
if ( clip[i+1] > ymax )
ymax = clip[i+1];
}
clip[0] = xmin; clip[1] = ymin;
clip[6] = xmax; clip[7] = ymax;
}
/**
* Limit the clip such that it fits within the specified region.
* @param x1 the minimum x-coordinate
* @param y1 the minimum y-coorindate
* @param x2 the maximum x-coordinate
* @param y2 the maximum y-coorindate
*/
public void limit(double x1, double y1, double x2, double y2) {
clip[0] = Math.max(clip[0],x1);
clip[1] = Math.max(clip[1],y1);
clip[6] = Math.min(clip[6],x2);
clip[7] = Math.min(clip[7],y2);
}
/**
* Indicates if this Clip intersects the given rectangle expanded
* by the additional margin pace.
* @param r the rectangle to test for intersect
* @param margin additional margin "bleed" to include in the intersection
* @return true if the clip intersects the expanded region, false otherwise
*/
public boolean intersects(Rectangle2D r, double margin) {
double tw = clip[6]-clip[0];
double th = clip[7]-clip[1];
double rw = r.getWidth();
double rh = r.getHeight();
if (rw < 0 || rh < 0 || tw < 0 || th < 0) {
return false;
}
double tx = clip[0];
double ty = clip[1];
double rx = r.getX()-margin;
double ry = r.getY()-margin;
rw += rx+2*margin;
rh += ry+2*margin;
tw += tx;
th += ty;
// overflow || intersect
return ((rw < rx || rw > tx) &&
(rh < ry || rh > ty) &&
(tw < tx || tw > rx) &&
(th < ty || th > ry));
}
/**
* Union this clip with another clip. As a result, this clip
* will become a bounding box around the two original clips.
* @param c the clip to union with
*/
public void union(Clip c) {
if ( status == INVALID )
return;
if ( status == EMPTY ) {
setClip(c);
status = INUSE;
return;
}
clip[0] = Math.min(clip[0], c.clip[0]);
clip[1] = Math.min(clip[1], c.clip[1]);
clip[6] = Math.max(clip[6], c.clip[6]);
clip[7] = Math.max(clip[7], c.clip[7]);
}
/**
* Union this clip with another region. As a result, this clip
* will become a bounding box around the two original regions.
* @param r the rectangle to union with
*/
public void union(Rectangle2D r) {
if ( status == INVALID )
return;
double minx = r.getMinX();
double miny = r.getMinY();
double maxx = r.getMaxX();
double maxy = r.getMaxY();
if ( Double.isNaN(minx) || Double.isNaN(miny) ||
Double.isNaN(maxx) || Double.isNaN(maxy) ) {
Logger.getLogger(getClass().getName()).warning(
"Union with invalid clip region: "+r);
return;
}
if ( status == EMPTY ) {
setClip(r);
status = INUSE;
return;
}
clip[0] = Math.min(clip[0], minx);
clip[1] = Math.min(clip[1], miny);
clip[6] = Math.max(clip[6], maxx);
clip[7] = Math.max(clip[7], maxy);
}
/**
* Union this clip with another region. As a result, this clip
* will become a bounding box around the two original regions.
* @param x the x-coordinate of the region to union with
* @param y the y-coordinate of the region to union with
* @param w the width of the region to union with
* @param h the height of the region to union with
*/
public void union(double x, double y, double w, double h) {
if ( status == INVALID )
return;
if ( status == EMPTY ) {
setClip(x,y,w,h);
status = INUSE;
return;
}
clip[0] = Math.min(clip[0], x);
clip[1] = Math.min(clip[1], y);
clip[6] = Math.max(clip[6], x+w);
clip[7] = Math.max(clip[7], y+h);
}
/**
* Intersect this clip with another region. As a result, this
* clip will become the intersecting area of the two regions.
* @param c the clip to intersect with
*/
public void intersection(Clip c) {
if ( status == INVALID )
return;
if ( status == EMPTY ) {
setClip(c);
status = INUSE;
return;
}
clip[0] = Math.max(clip[0], c.clip[0]);
clip[1] = Math.max(clip[1], c.clip[1]);
clip[6] = Math.min(clip[6], c.clip[6]);
clip[7] = Math.min(clip[7], c.clip[7]);
}
/**
* Intersect this clip with another region. As a result, this
* clip will become the intersecting area of the two regions.
* @param r the rectangle to intersect with
*/
public void intersection(Rectangle2D r) {
if ( status == INVALID )
return;
if ( status == EMPTY ) {
setClip(r);
status = INUSE;
return;
}
clip[0] = Math.max(clip[0], r.getMinX());
clip[1] = Math.max(clip[1], r.getMinY());
clip[6] = Math.min(clip[6], r.getMaxX());
clip[7] = Math.min(clip[7], r.getMaxY());
}
/**
* Intersect this clip with another region. As a result, this
* clip will become the intersecting area of the two regions.
* @param x the x-coordinate of the region to intersect with
* @param y the y-coordinate of the region to intersect with
* @param w the width of the region to intersect with
* @param h the height of the region to intersect with
*/
public void intersection(double x, double y, double w, double h) {
if ( status == INVALID )
return;
if ( status == EMPTY ) {
setClip(x,y,w,h);
status = INUSE;
return;
}
clip[0] = Math.max(clip[0], x);
clip[1] = Math.max(clip[1], y);
clip[6] = Math.min(clip[6], x+w);
clip[7] = Math.min(clip[7], y+h);
}
/**
* Minimally expand the clip such that each coordinate is an integer.
*/
public void expandToIntegerLimits() {
clip[0] = Math.floor(clip[0]);
clip[1] = Math.floor(clip[1]);
clip[6] = Math.ceil(clip[6]);
clip[7] = Math.ceil(clip[7]);
}
/**
* Expand the clip in all directions by the given value.
* @param b the value to expand by
*/
public void expand(double b) {
clip[0] -= b; clip[1] -= b;
clip[6] += b; clip[7] += b;
}
/**
* Grow the clip width and height by the given value. The minimum
* coordinates will be unchanged.
* @param b the value to grow the width and height by
*/
public void grow(double b) {
clip[6] += b; clip[7] += b;
}
/**
* Get the minimum x-coordinate.
* @return the minimum x-coordinate
*/
public double getMinX() {
return clip[0];
}
/**
* Get the minimum y-coordinate.
* @return the minimum y-coordinate
*/
public double getMinY() {
return clip[1];
}
/**
* Get the maximum x-coordinate.
* @return the maximum x-coordinate
*/
public double getMaxX() {
return clip[6];
}
/**
* Get the maximum y-coordinate.
* @return the maximum y-coordinate
*/
public double getMaxY() {
return clip[7];
}
/**
* Get the clip"s width
* @return the clip width
*/
public double getWidth() {
return clip[6]-clip[0];
}
/**
* Get the clip"s height
* @return the clip height
*/
public double getHeight() {
return clip[7]-clip[1];
}
/**
* Indicates if the clip is set to an empty status.
* @return true if the clip is set to empty, false otherwise
*/
public boolean isEmpty() {
return status==EMPTY;
}
/**
* Indicates if the clip is set to an invalid status.
* @return true if the clip is set to invalid, false otherwise
*/
public boolean isInvalid() {
return status==INVALID;
}
// ------------------------------------------------------------------------
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object o) {
if ( o instanceof Rectangle2D ) {
Rectangle2D r = (Rectangle2D)o;
return ( r.getMinX()==clip[0] && r.getMinY()==clip[1] &&
r.getMaxX()==clip[6] && r.getMaxY()==clip[7] );
} else if ( o instanceof Clip ) {
Clip r = (Clip)o;
if ( r.status == status ) {
if ( status == Clip.INUSE )
return ( r.clip[0]==clip[0] && r.clip[1]==clip[1] &&
r.clip[6]==clip[6] && r.clip[7]==clip[7] );
else
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer sb = new StringBuffer(20);
sb.append("Clip[");
switch (status) {
case INVALID:
sb.append("invalid");
break;
case EMPTY:
sb.append("empty");
break;
default:
sb.append(clip[0]).append(",");
sb.append(clip[1]).append(",");
sb.append(clip[6]).append(",");
sb.append(clip[7]);
}
sb.append("]");
return sb.toString();
}
} // end of class Clip
set Clip and get Clip
/*
* Java2DUtils.java
*
* Created on Aug 30, 2007, 11:40:18 AM
*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
//Revised from jaspersoft ireport designer
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.util.Stack;
/**
*
* @author gtoffoli
*/
public class Java2DUtils
{
private static Stack clipBoundsStack = new Stack();
private static Stack transforms = new Stack();
public static void setClip(Graphics g, int x, int y, int width, int height)
{
setClip(g, new Rectangle(x, y, width, height));
}
@SuppressWarnings("unchecked")
public static void setClip(Graphics g, Rectangle clipBounds)
{
Rectangle currentClipBounds;
clipBounds = new Rectangle(clipBounds);
clipBounds.width += 1;
clipBounds.height += 1;
currentClipBounds = g.getClipBounds();
if(currentClipBounds != null)
{
clipBounds = clipBounds.intersection(g.getClipBounds());
}
clipBoundsStack.push(currentClipBounds);
g.setClip(clipBounds);
}
public static void resetClip(Graphics g)
{
g.setClip((Shape) clipBoundsStack.pop());
}
@SuppressWarnings("unchecked")
public static void setTransform(Graphics2D g2, AffineTransform transform)
{
AffineTransform current;
current = g2.getTransform();
transforms.push(current);
g2.setTransform(transform);
}
public static void resetTransform(Graphics2D g2)
{
if(transforms.empty())
{
return;
}
g2.setTransform((AffineTransform) transforms.pop());
}
}
Setting the Clipping Area with a Shape
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new MyComponent());
frame.setSize(300, 300);
frame.setVisible(true);
}
}
class MyComponent extends JComponent {
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Shape shape = new java.awt.geom.Ellipse2D.Float(20, 20, 200,200);
g2d.setClip(shape);
int x = 0;
int y = 0;
g2d.drawImage(new ImageIcon("a.png").getImage(), x, y, this);
}
}