Java/2D Graphics GUI/Transform
Содержание
- 1 AffineTransform demo
- 2 Coordinate Demo
- 3 Create an complex shape by rotating an ellipse.
- 4 Creates and returns a translated shape.
- 5 Line transformation, rotation, shear,scale
- 6 Perform shearing: use share() method.
- 7 Resizes or translates a Shape
- 8 Rotates a shape about the specified coordinates.
- 9 Rotating a Drawn Image
- 10 Rotating a Shape with AffineTransform
- 11 Rotating image using Java 2D AffineTransform class
- 12 Rotation and coordinate translation
- 13 Scaling a Drawn Image
- 14 Scaling an object
- 15 Scaling a Shape with AffineTransform
- 16 Shearing a Drawn Image
- 17 Shearing a Shape with AffineTransform
- 18 Transform Demo
- 19 Transforme Rotation demo
- 20 Transform Rotation Translation
- 21 Transform Scale
- 22 Transform Shear
- 23 Transform Translated Rotation
- 24 Transform Translation
- 25 Transform Translation and Rotation
- 26 Translating a Drawn Image
- 27 Translating a Shape with AffineTransform
AffineTransform demo
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class AffineTransformApp extends JFrame {
DisplayPanel displayPanel;
JComboBox scaleXval, scaleYval, shearXval, shearYval;
String[] scaleValues = { "0.10", "0.25", "0.50", "0.75", "1.00", "1.25",
"1.50", "1.75", "2.00" };
String[] shearValues = { "0.00", "0.25", "0.50", "0.75", "1.00" };
public AffineTransformApp() {
super();
Container container = getContentPane();
displayPanel = new DisplayPanel();
container.add(displayPanel);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(2, 4, 5, 5));
scaleXval = new JComboBox(scaleValues);
scaleXval.setSelectedItem("1.00");
scaleXval.addActionListener(new ComboBoxListener());
scaleYval = new JComboBox(scaleValues);
scaleYval.setSelectedItem("1.00");
scaleYval.addActionListener(new ComboBoxListener());
shearXval = new JComboBox(shearValues);
shearXval.setSelectedItem("0.00");
shearXval.addActionListener(new ComboBoxListener());
shearYval = new JComboBox(shearValues);
shearYval.setSelectedItem("0.00");
shearYval.addActionListener(new ComboBoxListener());
panel.add(new JLabel("Scale X value:"));
panel.add(scaleXval);
panel.add(new JLabel("Scale Y value:"));
panel.add(scaleYval);
panel.add(new JLabel("Shear X value:"));
panel.add(shearXval);
panel.add(new JLabel("Shear Y value:"));
panel.add(shearYval);
container.add(BorderLayout.SOUTH, panel);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setSize(displayPanel.getWidth(), displayPanel.getHeight() + 10);
setVisible(true);
}
public static void main(String arg[]) {
new AffineTransformApp();
}
class ComboBoxListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JComboBox temp = (JComboBox) e.getSource();
if (temp == scaleXval) {
displayPanel.scalex = Double.parseDouble((String) temp
.getSelectedItem());
displayPanel.applyValue(true, false);
displayPanel.applyFilter();
displayPanel.repaint();
} else if (temp == scaleYval) {
displayPanel.scaley = Double.parseDouble((String) temp
.getSelectedItem());
displayPanel.applyValue(true, false);
displayPanel.applyFilter();
displayPanel.repaint();
} else if (temp == shearXval) {
displayPanel.shearx = Double.parseDouble((String) temp
.getSelectedItem());
displayPanel.applyValue(false, true);
displayPanel.applyFilter();
displayPanel.repaint();
} else if (temp == shearYval) {
displayPanel.sheary = Double.parseDouble((String) temp
.getSelectedItem());
displayPanel.applyValue(false, true);
displayPanel.applyFilter();
displayPanel.repaint();
}
}
}
}
class DisplayPanel extends JLabel {
Image displayImage;
BufferedImage biSrc, biDest;
BufferedImage bi;
Graphics2D big;
AffineTransform transform;
double scalex = 1.0;
double scaley = 1.0;
double shearx = 1.0;
double sheary = 1.0;
DisplayPanel() {
setBackground(Color.black);
loadImage();
setSize(displayImage.getWidth(this), displayImage.getWidth(this)); // panel
createBufferedImages();
transform = new AffineTransform();
}
public void loadImage() {
displayImage = Toolkit.getDefaultToolkit().getImage(
"largejexpLogo.jpg");
MediaTracker mt = new MediaTracker(this);
mt.addImage(displayImage, 1);
try {
mt.waitForAll();
} catch (Exception e) {
System.out.println("Exception while loading.");
}
if (displayImage.getWidth(this) == -1) {
System.out.println(" Missing .jpg file");
System.exit(0);
}
}
public void createBufferedImages() {
biSrc = new BufferedImage(displayImage.getWidth(this), displayImage
.getHeight(this), BufferedImage.TYPE_INT_RGB);
big = biSrc.createGraphics();
big.drawImage(displayImage, 0, 0, this);
bi = biSrc;
biDest = new BufferedImage(displayImage.getWidth(this), displayImage
.getHeight(this), BufferedImage.TYPE_INT_RGB);
}
public void applyValue(boolean scale, boolean shear) {
if (scale) {
transform.setToScale(scalex, scaley);
scale = false;
} else if (shear) {
transform.setToShear(shearx, sheary);
shear = false;
}
}
public void applyFilter() {
AffineTransformOp op = new AffineTransformOp(transform, null);
Graphics2D biDestG2D = biDest.createGraphics();
biDestG2D
.clearRect(0, 0, biDest.getWidth(this), biDest.getHeight(this));
op.filter(biSrc, biDest);
bi = biDest;
}
public void reset() {
big.setColor(Color.black);
big.clearRect(0, 0, bi.getWidth(this), bi.getHeight(this));
big.drawImage(displayImage, 0, 0, this);
}
public void update(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
paintComponent(g);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(bi, 0, 0, this);
}
}
Coordinate Demo
/*
* Copyright (c) 2006 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:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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 Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/* CoordinatesDemo.java is a 1.4 application that requires no other files. */
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.event.MouseInputListener;
/*
* This displays a framed area. As the user moves the cursor over the area, a
* label displays the cursor"s location. When the user clicks, the area displays
* a 7x7 dot at the click location.
*/
public class CoordinatesDemo {
private JLabel label;
private Point clickPoint, cursorPoint;
private void buildUI(Container container) {
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
CoordinateArea coordinateArea = new CoordinateArea(this);
container.add(coordinateArea);
label = new JLabel();
resetLabel();
container.add(label);
//Align the left edges of the components.
coordinateArea.setAlignmentX(Component.LEFT_ALIGNMENT);
label.setAlignmentX(Component.LEFT_ALIGNMENT); //redundant
}
public void updateCursorLocation(int x, int y) {
if (x < 0 || y < 0) {
cursorPoint = null;
updateLabel();
return;
}
if (cursorPoint == null) {
cursorPoint = new Point();
}
cursorPoint.x = x;
cursorPoint.y = y;
updateLabel();
}
public void updateClickPoint(Point p) {
clickPoint = p;
updateLabel();
}
public void resetLabel() {
cursorPoint = null;
updateLabel();
}
protected void updateLabel() {
String text = "";
if ((clickPoint == null) && (cursorPoint == null)) {
text = "Click or move the cursor within the framed area.";
} else {
if (clickPoint != null) {
text += "The last click was at (" + clickPoint.x + ", "
+ clickPoint.y + "). ";
}
if (cursorPoint != null) {
text += "The cursor is at (" + cursorPoint.x + ", "
+ cursorPoint.y + "). ";
}
}
label.setText(text);
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
//Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
//Create and set up the window.
JFrame frame = new JFrame("CoordinatesDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the content pane.
CoordinatesDemo controller = new CoordinatesDemo();
controller.buildUI(frame.getContentPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application"s GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static class CoordinateArea extends JComponent implements
MouseInputListener {
Point point = null;
CoordinatesDemo controller;
Dimension preferredSize = new Dimension(400, 75);
Color gridColor;
public CoordinateArea(CoordinatesDemo controller) {
this.controller = controller;
//Add a border of 5 pixels at the left and bottom,
//and 1 pixel at the top and right.
setBorder(BorderFactory.createMatteBorder(1, 5, 5, 1, Color.RED));
addMouseListener(this);
addMouseMotionListener(this);
setBackground(Color.WHITE);
setOpaque(true);
}
public Dimension getPreferredSize() {
return preferredSize;
}
protected void paintComponent(Graphics g) {
//Paint background if we"re opaque.
if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
//Paint 20x20 grid.
g.setColor(Color.GRAY);
drawGrid(g, 20);
//If user has chosen a point, paint a small dot on top.
if (point != null) {
g.setColor(getForeground());
g.fillRect(point.x - 3, point.y - 3, 7, 7);
}
}
//Draws a 20x20 grid using the current color.
private void drawGrid(Graphics g, int gridSpace) {
Insets insets = getInsets();
int firstX = insets.left;
int firstY = insets.top;
int lastX = getWidth() - insets.right;
int lastY = getHeight() - insets.bottom;
//Draw vertical lines.
int x = firstX;
while (x < lastX) {
g.drawLine(x, firstY, x, lastY);
x += gridSpace;
}
//Draw horizontal lines.
int y = firstY;
while (y < lastY) {
g.drawLine(firstX, y, lastX, y);
y += gridSpace;
}
}
//Methods required by the MouseInputListener interface.
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (point == null) {
point = new Point(x, y);
} else {
point.x = x;
point.y = y;
}
controller.updateClickPoint(point);
repaint();
}
public void mouseMoved(MouseEvent e) {
controller.updateCursorLocation(e.getX(), e.getY());
}
public void mouseExited(MouseEvent e) {
controller.resetLabel();
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
}
}
}
Create an complex shape by rotating an ellipse.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RotateTransformed extends JPanel {
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Ellipse2D e = new Ellipse2D.Double(0, 0, 80, 130);
for (double i = 0; i < 360; i += 5) {
AffineTransform at = AffineTransform.getTranslateInstance(400 / 2, 400 / 2);
at.rotate(Math.toRadians(i));
g2.draw(at.createTransformedShape(e));
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new RotateTransformed());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
Creates and returns a translated shape.
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/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.]
*
* -------------------
* ShapeUtilities.java
* -------------------
* (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
*
* Changes
* -------
* 13-Aug-2003 : Version 1 (DG);
* 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
* 13-May-2004 : Added new shape creation methods (DG);
* 30-Sep-2004 : Added createLineRegion() method (DG);
* Moved drawRotatedShape() method from RefineryUtilities class
* to this class (DG);
* 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
* 26-Oct-2004 : Added a method to test the equality of two Line2D
* instances (DG);
* 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
* methods (DG);
* 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
* 07-Jan-2005 : Minor Javadoc fix (DG);
* 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
* 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
* method (DG);
* 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
* 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
* instances (DG);
* 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
*
*/
import java.awt.Shape;
import java.awt.geom.AffineTransform;
/**
* Utility methods for {@link Shape} objects.
*
* @author David Gilbert
*/
public class Main {
/**
* Creates and returns a translated shape.
*
* @param shape the shape (<code>null</code> not permitted).
* @param transX the x translation (in Java2D space).
* @param transY the y translation (in Java2D space).
*
* @return The translated shape.
*/
public static Shape createTranslatedShape(final Shape shape,
final double transX,
final double transY) {
if (shape == null) {
throw new IllegalArgumentException("Null "shape" argument.");
}
final AffineTransform transform = AffineTransform.getTranslateInstance(
transX, transY);
return transform.createTransformedShape(shape);
}
}
Line transformation, rotation, shear,scale
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class House extends JPanel {
MyCanvas canvas;
JSlider sliderTransX, sliderTransY, sliderRotateTheta, sliderRotateX,
sliderRotateY, sliderScaleX, sliderScaleY, sliderWidth;
double transX = 0.0;
double transY = 0.0;
double rotateTheta = 0.0;
double rotateX = 150.0;
double rotateY = 150.0;
double scaleX = 1.0;
double scaleY = 1.0;
float width = 1.0f;
public House() {
super(new BorderLayout());
JPanel controlPanel = new JPanel(new GridLayout(3, 3));
add(controlPanel, BorderLayout.NORTH);
controlPanel.add(new JLabel("Translate(dx,dy): "));
sliderTransX = setSlider(controlPanel, JSlider.HORIZONTAL, 0, 300, 150,
100, 50);
sliderTransY = setSlider(controlPanel, JSlider.HORIZONTAL, 0, 300, 150,
100, 50);
// To control rotation
controlPanel.add(new JLabel("Rotate(Theta,ox,oy): "));
sliderRotateTheta = setSlider(controlPanel, JSlider.HORIZONTAL, 0, 360,
0, 90, 45);
JPanel subPanel = new JPanel();
subPanel.setLayout(new GridLayout(1, 2));
sliderRotateX = setSlider(subPanel, JSlider.HORIZONTAL, 0, 300, 150,
150, 50);
sliderRotateY = setSlider(subPanel, JSlider.HORIZONTAL, 0, 300, 150,
150, 50);
controlPanel.add(subPanel);
// To control scaling
controlPanel.add(new JLabel("Scale(sx,sy)x10E-2:"));
sliderScaleX = setSlider(controlPanel, JSlider.HORIZONTAL, 0, 200, 100,
100, 10);
sliderScaleY = setSlider(controlPanel, JSlider.HORIZONTAL, 0, 200, 100,
100, 10);
// To control width of line segments
JLabel label4 = new JLabel("Width Control:", JLabel.RIGHT);
sliderWidth = new JSlider(JSlider.HORIZONTAL, 0, 20, 1);
sliderWidth.setPaintTicks(true);
sliderWidth.setMajorTickSpacing(5);
sliderWidth.setMinorTickSpacing(1);
sliderWidth.setPaintLabels(true);
sliderWidth.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
width = sliderWidth.getValue();
canvas.repaint();
}
});
JPanel widthPanel = new JPanel();
widthPanel.setLayout(new GridLayout(1, 2));
widthPanel.add(label4);
widthPanel.add(sliderWidth);
add(widthPanel, BorderLayout.SOUTH);
canvas = new MyCanvas();
add(canvas, "Center");
}
public JSlider setSlider(JPanel panel, int orientation, int minimumValue,
int maximumValue, int initValue, int majorTickSpacing,
int minorTickSpacing) {
JSlider slider = new JSlider(orientation, minimumValue, maximumValue,
initValue);
slider.setPaintTicks(true);
slider.setMajorTickSpacing(majorTickSpacing);
slider.setMinorTickSpacing(minorTickSpacing);
slider.setPaintLabels(true);
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider tempSlider = (JSlider) e.getSource();
if (tempSlider.equals(sliderTransX)) {
transX = sliderTransX.getValue() - 150.0;
canvas.repaint();
} else if (tempSlider.equals(sliderTransY)) {
transY = sliderTransY.getValue() - 150.0;
canvas.repaint();
} else if (tempSlider.equals(sliderRotateTheta)) {
rotateTheta = sliderRotateTheta.getValue() * Math.PI / 180;
canvas.repaint();
} else if (tempSlider.equals(sliderRotateX)) {
rotateX = sliderRotateX.getValue();
canvas.repaint();
} else if (tempSlider.equals(sliderRotateY)) {
rotateY = sliderRotateY.getValue();
canvas.repaint();
} else if (tempSlider.equals(sliderScaleX)) {
if (sliderScaleX.getValue() != 0.0) {
scaleX = sliderScaleX.getValue() / 100.0;
canvas.repaint();
}
} else if (tempSlider.equals(sliderScaleY)) {
if (sliderScaleY.getValue() != 0.0) {
scaleY = sliderScaleY.getValue() / 100.0;
canvas.repaint();
}
}
}
});
panel.add(slider);
return slider;
}
class MyCanvas extends Canvas {
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.translate(transX, transY);
g2D.rotate(rotateTheta, rotateX, rotateY);
g2D.scale(scaleX, scaleY);
BasicStroke stroke = new BasicStroke(width);
g2D.setStroke(stroke);
drawHome(g2D);
}
public void drawHome(Graphics2D g2D) {
Line2D line1 = new Line2D.Float(100f, 200f, 200f, 200f);
Line2D line2 = new Line2D.Float(100f, 200f, 100f, 100f);
Line2D line3 = new Line2D.Float(100f, 100f, 150f, 50f);
Line2D line4 = new Line2D.Float(150f, 50f, 200f, 100f);
Line2D line5 = new Line2D.Float(200f, 100f, 200f, 200f);
Line2D line6 = new Line2D.Float(140f, 200f, 140f, 150f);
Line2D line7 = new Line2D.Float(140f, 150f, 160f, 150f);
Line2D line8 = new Line2D.Float(160f, 150f, 160f, 200f);
g2D.draw(line1);
g2D.draw(line2);
g2D.draw(line3);
g2D.draw(line4);
g2D.draw(line5);
g2D.draw(line6);
g2D.draw(line7);
g2D.draw(line8);
}
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new House());
f.setDefaultCloseOperation(1);
f.setSize(700, 550);
f.setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Shear extends JPanel {
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
AffineTransform tx1 = new AffineTransform();
tx1.translate(50, 90);
g2d.setTransform(tx1);
g2d.setColor(Color.green);
g2d.drawRect(0, 0, 80, 50);
AffineTransform tx2 = new AffineTransform();
tx2.translate(50, 90);
tx2.shear(0, 1);
g2d.setTransform(tx2);
g2d.setColor(Color.blue);
g2d.draw(new Rectangle(0, 0, 80, 50));
}
public static void main(String[] args) {
JFrame frame = new JFrame("Shearing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Shear());
frame.setSize(330, 270);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Resizes or translates a Shape
/**
*
* JFreeReport : a free Java reporting library
*
*
* Project Info: http://reporting.pentaho.org/
*
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*
* 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., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* ShapeTransform.java
* ------------
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*/
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Dimension2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;
/**
* Utility class, which resizes or translates a Shape. The class contains
* special handlers for Rectangles and Lines.
*
* @author Thomas Morgner
*/
public final strictfp class ShapeTransform {
// some constants for the cohenen-algorithmus
/**
* Flag for point lying left of clipping area.
*/
public static final int LEFT = 0x01;
/**
* Flag for point lying between horizontal bounds of area.
*/
public static final int H_CENTER = 0x02;
/**
* Flag for point lying right of clipping area.
*/
public static final int RIGHT = 0x04;
/**
* Flag for point lying "below" clipping area.
*/
public static final int BELOW = 0x10;
/**
* Flag for point lying between vertical bounds of clipping area.
*/
public static final int V_CENTER = 0x20;
/**
* Flag for point lying "above" clipping area.
*/
public static final int ABOVE = 0x40;
/** A simple way to handle rounding errors. */
private static final double DELTA = 0.000001;
/**
* Mask for points which are inside.
*/
public static final int INSIDE = H_CENTER | V_CENTER;
/**
* Mask for points which are outside.
*/
public static final int OUTSIDE = LEFT | RIGHT | BELOW | ABOVE;
/**
* Default constructor.
*/
private ShapeTransform() {
}
/**
* Resizes a line. Instead of creating a GeneralPath (as AffineTransform"s
* scale would do) we modify the line itself.
*
* @param line
* the line that should be scaled
* @param width
* the new width of the line bounds
* @param height
* the new height of the line bounds
* @return the scale Line2D object.
*/
private static Line2D resizeLine(final Line2D line, final double width, final double height) {
final Line2D newLine = getNormalizedLine(line);
final Point2D p1 = newLine.getP1();
final Point2D p2 = newLine.getP2();
final double normPointX = (p1.getX() - p2.getX());
final double normPointY = (p1.getY() - p2.getY());
final double scaleX = (normPointX == 0) ? 1 : width / Math.abs(normPointX);
final double scaleY = (normPointY == 0) ? 1 : height / Math.abs(normPointY);
p2.setLocation((p2.getX() - p1.getX()) * scaleX + p1.getX(), (p2.getY() - p1.getY()) * scaleY
+ p1.getY());
newLine.setLine(p1, p2);
return newLine;
}
/**
* Normalize the line; the point with the lowest X is the primary point, if
* both points have the same X, that point with the lowest Y value wins.
*
* @param line
* the original line
* @return the normalized line
*/
private static Line2D getNormalizedLine(final Line2D line) {
final Line2D lineClone = (Line2D) line.clone();
final Point2D p1 = line.getP1();
final Point2D p2 = line.getP2();
if (p1.getX() < p2.getX()) {
return lineClone;
}
if (p1.getX() > p2.getX()) {
lineClone.setLine(p2, p1);
return lineClone;
}
if (p1.getY() < p2.getY()) {
return lineClone;
}
lineClone.setLine(p2, p1);
return lineClone;
}
/**
* Resizes a shape, so that the shape has the given width and height, but the
* origin of the shape does not change. <p/> Unlike the AffineTransform, this
* method tries to preserve the Shape"s Type.
*
* @param s
* the shape
* @param width
* the new width
* @param height
* the new height
* @return the resized shape.
*/
public static Shape resizeShape(final Shape s, final float width, final float height) {
if (s instanceof Line2D) {
return resizeLine((Line2D) s, width, height);
}
if (s instanceof RectangularShape) {
return resizeRect((RectangularShape) s, width, height);
}
return transformShape(s, true, false, new Dimension((int) width, (int) height));
}
/**
* Resizes a rectangle. This works for real rectangles and produces funny
* results for RoundRects etc ..
*
* @param rectangularShape
* the rectangle
* @param width
* the new width of the rectangle
* @param height
* the new height of the rectangle.
* @return the resized rectangle.
*/
public static Shape resizeRect(final RectangularShape rectangularShape, final double width,
final double height) {
final RectangularShape retval = (RectangularShape) rectangularShape.clone();
retval.setFrame(retval.getX(), retval.getY(), width, height);
return retval;
}
/**
* Translates the given shape. The shape is translated to the origin supplied
* in <code>point</code>. If scaling is requested, the shape will also be
* scaled using an AffineTransform.
*
* @param s
* the shape that should be transformed
* @param scale
* true, if the shape should be scaled, false otherwise
* @param keepAR
* true, if the scaled shape should keep the aspect ratio
* @param width
* the target width.
* @param height
* the target height.
* @return the transformed shape
*/
public static Shape transformShape(final Shape s, final boolean scale, final boolean keepAR,
final double width, final double height) {
/**
* Always scale to the maximum bounds ...
*/
if (scale) {
final Rectangle2D boundsShape = s.getBounds2D();
final double w = boundsShape.getWidth();
final double h = boundsShape.getHeight();
double scaleX = 1;
if (w != 0) {
scaleX = width / w;
}
double scaleY = 1;
if (h != 0) {
scaleY = height / h;
}
if (scaleX != 1 || scaleY != 1) {
if (s instanceof RectangularShape) {
return ShapeTransform.resizeRect((RectangularShape) s, w * scaleX, h * scaleY);
}
if (s instanceof Line2D) {
return ShapeTransform.resizeLine((Line2D) s, w * scaleX, h * scaleY);
}
if (keepAR) {
final double scaleFact = Math.min(scaleX, scaleY);
return performDefaultTransformation(s, scaleFact, scaleFact);
} else {
return performDefaultTransformation(s, scaleX, scaleY);
}
}
}
return s;
}
/**
* Translates the given shape. The shape is translated to the origin supplied
* in <code>point</code>. If scaling is requested, the shape will also be
* scaled using an AffineTransform.
*
* @param s
* the shape that should be transformed
* @param scale
* true, if the shape should be scaled, false otherwise
* @param keepAR
* true, if the scaled shape should keep the aspect ratio
* @param dim
* the target dimension.
* @return the transformed shape
*/
public static Shape transformShape(final Shape s, final boolean scale, final boolean keepAR,
final Dimension2D dim) {
return transformShape(s, scale, keepAR, dim.getWidth(), dim.getHeight());
}
/**
* Clips the given shape to the given bounds. If the shape is a Line2D, manual
* clipping is performed, as the built in Area does not handle lines.
*
* @param s
* the shape to be clipped
* @param bounds
* the bounds to which the shape should be clipped
* @return the clipped shape.
*/
public static Shape performCliping(final Shape s, final Rectangle2D bounds) {
if (s instanceof Line2D) {
final Line2D line = (Line2D) s;
final Point2D[] clipped = getClipped(line.getX1(), line.getY1(), line.getX2(), line.getY2(),
-DELTA, DELTA + bounds.getWidth(), -DELTA, DELTA + bounds.getHeight());
if (clipped == null) {
return new GeneralPath();
}
return new Line2D.Float(clipped[0], clipped[1]);
}
final Rectangle2D boundsCorrected = bounds.getBounds2D();
boundsCorrected.setRect(-DELTA, -DELTA, DELTA + boundsCorrected.getWidth(), DELTA
+ boundsCorrected.getHeight());
final Area a = new Area(boundsCorrected);
if (a.isEmpty()) {
// don"t clip ... Area does not like lines
// operations with lines always result in an empty Bounds:(0,0,0,0) area
return new GeneralPath();
}
final Area clipArea = new Area(s);
a.intersect(clipArea);
return a;
}
/**
* Scales a given shape. The shape is first normalized, then scaled and
* finally brought back into its original position.
*
* @param shape
* the shape to be scaled
* @param scaleX
* the horizontal scaling factor
* @param scaleY
* the vertical scaling factor
* @return the scaled shape
*/
private static Shape performDefaultTransformation(final Shape shape, final double scaleX,
final double scaleY) {
/**
* Apply the normalisation shape transform ... bring the shape to pos (0,0)
*/
final Rectangle2D bounds = shape.getBounds2D();
AffineTransform af = AffineTransform.getTranslateInstance(0 - bounds.getX(), 0 - bounds.getY());
// apply normalisation translation ...
Shape s = af.createTransformedShape(shape);
af = AffineTransform.getScaleInstance(scaleX, scaleY);
// apply scaling ...
s = af.createTransformedShape(s);
// now retranslate the shape to its original position ...
af = AffineTransform.getTranslateInstance(bounds.getX(), bounds.getY());
return af.createTransformedShape(s);
}
/**
* Translates a given shape. Special care is taken to preserve the shape"s
* original class, if the shape is a rectangle or a line.
*
* @param s
* the shape
* @param x
* the x coordinate where the shape is translated to
* @param y
* the y coordinate where the shape is translated to
* @return the translated shape
*/
public static Shape translateShape(final Shape s, final double x, final double y) {
if (s instanceof RectangularShape) {
final RectangularShape rect = (RectangularShape) s;
final RectangularShape retval = (RectangularShape) rect.clone();
retval.setFrame(retval.getX() + x, retval.getY() + y, retval.getWidth(), retval.getHeight());
return retval;
}
if (s instanceof Line2D) {
final Line2D line = (Line2D) s;
final Line2D retval = (Line2D) line.clone();
retval
.setLine(retval.getX1() + x, retval.getY1() + y, retval.getX2() + x, retval.getY2() + y);
return retval;
}
final AffineTransform af = AffineTransform.getTranslateInstance(x, y);
return af.createTransformedShape(s);
}
/**
* Calculate the clipping points of a line with a rectangle.
*
* @param x1
* starting x of line
* @param y1
* starting y of line
* @param x2
* ending x of line
* @param y2
* ending y of line
* @param xmin
* lower left x of rectangle
* @param xmax
* upper right x of rectangle
* @param ymin
* lower left y of rectangle
* @param ymax
* upper right y of rectangle
* @return <code>null</code> (does not clip) or array of two points
*/
public static Point2D[] getClipped(final double x1, final double y1, final double x2,
final double y2, final double xmin, final double xmax, final double ymin, final double ymax) {
int mask1 = 0; // position mask for first point
if (x1 < xmin) {
mask1 |= LEFT;
} else if (x1 > xmax) {
mask1 |= RIGHT;
} else {
mask1 |= H_CENTER;
}
if (y1 < ymin) {
// btw: I know that in AWT y runs from down but I more used to
// y pointing up and it makes no difference for the algorithms
mask1 |= BELOW;
} else if (y1 > ymax) {
mask1 |= ABOVE;
} else {
mask1 |= V_CENTER;
}
int mask2 = 0; // position mask for second point
if (x2 < xmin) {
mask2 |= LEFT;
} else if (x2 > xmax) {
mask2 |= RIGHT;
} else {
mask2 |= H_CENTER;
}
if (y2 < ymin) {
mask2 |= BELOW;
} else if (y2 > ymax) {
mask2 |= ABOVE;
} else {
mask2 |= V_CENTER;
}
final int mask = mask1 | mask2;
if ((mask & OUTSIDE) == 0) {
// fine. everything"s internal
final Point2D[] ret = new Point2D[2];
ret[0] = new Point2D.Double(x1, y1);
ret[1] = new Point2D.Double(x2, y2);
return ret;
} else if ((mask & (H_CENTER | LEFT)) == 0 || // everything"s right
(mask & (H_CENTER | RIGHT)) == 0 || // everything"s left
(mask & (V_CENTER | BELOW)) == 0 || // everything"s above
(mask & (V_CENTER | ABOVE)) == 0) { // everything"s below
// nothing to do
return null;
} else {
// need clipping
return getClipped(x1, y1, mask1, x2, y2, mask2, xmin, xmax, ymin, ymax);
}
}
/**
* Calculate the clipping points of a line with a rectangle.
*
* @param x1
* starting x of line
* @param y1
* starting y of line
* @param mask1
* clipping info mask for starting point
* @param x2
* ending x of line
* @param y2
* ending y of line
* @param mask2
* clipping info mask for ending point
* @param xmin
* lower left x of rectangle
* @param ymin
* lower left y of rectangle
* @param xmax
* upper right x of rectangle
* @param ymax
* upper right y of rectangle
* @return <code>null</code> (does not clip) or array of two points
*/
private static Point2D[] getClipped(final double x1, final double y1, final int mask1,
final double x2, final double y2, final int mask2, final double xmin, final double xmax,
final double ymin, final double ymax) {
final int mask = mask1 ^ mask2;
Point2D p1 = null;
if (mask1 == INSIDE) {
// point 1 is internal
p1 = new Point2D.Double(x1, y1);
if (mask == 0) {
// both masks are the same, so the second point is inside, too
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = new Point2D.Double(x2, y2);
return ret;
}
} else if (mask2 == INSIDE) {
// point 2 is internal
p1 = new Point2D.Double(x2, y2);
}
if ((mask & LEFT) != 0) {
// System.out.println("Trying left");
// try to calculate intersection with left line
final Point2D p = intersect(x1, y1, x2, y2, xmin, ymin, xmin, ymax);
if (p != null) {
if (p1 == null) {
p1 = p;
} else {
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = p;
return ret;
}
}
}
if ((mask & RIGHT) != 0) {
// System.out.println("Trying right");
// try to calculate intersection with left line
final Point2D p = intersect(x1, y1, x2, y2, xmax, ymin, xmax, ymax);
if (p != null) {
if (p1 == null) {
p1 = p;
} else {
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = p;
return ret;
}
}
}
if (mask1 == (LEFT | BELOW) || mask1 == (RIGHT | BELOW)) {
// for exactly these two special cases use different sequence!
if ((mask & ABOVE) != 0) {
// System.out.println("Trying top");
// try to calculate intersection with lower line
final Point2D p = intersect(x1, y1, x2, y2, xmin, ymax, xmax, ymax);
if (p != null) {
if (p1 == null) {
p1 = p;
} else {
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = p;
return ret;
}
}
}
if ((mask & BELOW) != 0) {
// System.out.println("Trying bottom");
// try to calculate intersection with lower line
final Point2D p = intersect(x1, y1, x2, y2, xmin, ymin, xmax, ymin);
if (p != null && p1 != null) {
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = p;
return ret;
}
}
} else {
if ((mask & BELOW) != 0) {
// System.out.println("Trying bottom");
// try to calculate intersection with lower line
final Point2D p = intersect(x1, y1, x2, y2, xmin, ymin, xmax, ymin);
if (p != null) {
if (p1 == null) {
p1 = p;
} else {
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = p;
return ret;
}
}
}
if ((mask & ABOVE) != 0) {
// System.out.println("Trying top");
// try to calculate intersection with lower line
final Point2D p = intersect(x1, y1, x2, y2, xmin, ymax, xmax, ymax);
if (p != null && p1 != null) {
final Point2D[] ret = new Point2D[2];
ret[0] = p1;
ret[1] = p;
return ret;
}
}
}
// no (or not enough) intersections found
return null;
}
/**
* Intersect two lines.
*
* @param x11
* starting x of 1st line
* @param y11
* starting y of 1st line
* @param x12
* ending x of 1st line
* @param y12
* ending y of 1st line
* @param x21
* starting x of 2nd line
* @param y21
* starting y of 2nd line
* @param x22
* ending x of 2nd line
* @param y22
* ending y of 2nd line
* @return intersection point or <code>null</code>
*/
private static Point2D intersect(final double x11, final double y11, final double x12,
final double y12, final double x21, final double y21, final double x22, final double y22) {
final double dx1 = x12 - x11;
final double dy1 = y12 - y11;
final double dx2 = x22 - x21;
final double dy2 = y22 - y21;
final double det = (dx2 * dy1 - dy2 * dx1);
if (det != 0.0) {
final double mu = ((x11 - x21) * dy1 - (y11 - y21) * dx1) / det;
if (mu >= 0.0 && mu <= 1.0) {
return new Point2D.Double(x21 + mu * dx2, y21 + mu * dy2);
}
}
return null;
}
}
Rotates a shape about the specified coordinates.
/*
* JCommon : a free general purpose class library for the Java(tm) platform
*
*
* (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jcommon/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.]
*
* -------------------
* ShapeUtilities.java
* -------------------
* (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): -;
*
* $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
*
* Changes
* -------
* 13-Aug-2003 : Version 1 (DG);
* 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
* 13-May-2004 : Added new shape creation methods (DG);
* 30-Sep-2004 : Added createLineRegion() method (DG);
* Moved drawRotatedShape() method from RefineryUtilities class
* to this class (DG);
* 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
* 26-Oct-2004 : Added a method to test the equality of two Line2D
* instances (DG);
* 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
* methods (DG);
* 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
* 07-Jan-2005 : Minor Javadoc fix (DG);
* 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
* 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
* method (DG);
* 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
* 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
* instances (DG);
* 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
*
*/
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
/**
* Utility methods for {@link Shape} objects.
*
* @author David Gilbert
*/
public class Main {
/**
* Rotates a shape about the specified coordinates.
*
* @param base the shape (<code>null</code> permitted, returns
* <code>null</code>).
* @param angle the angle (in radians).
* @param x the x coordinate for the rotation point (in Java2D space).
* @param y the y coordinate for the rotation point (in Java2D space).
*
* @return the rotated shape.
*/
public static Shape rotateShape(final Shape base, final double angle,
final float x, final float y) {
if (base == null) {
return null;
}
final AffineTransform rotate = AffineTransform.getRotateInstance(
angle, x, y);
final Shape result = rotate.createTransformedShape(base);
return result;
}
}
Rotating a Drawn Image
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
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;
AffineTransform tx = new AffineTransform();
double radians = -Math.PI / 4;
tx.rotate(radians);
g2d.setTransform(tx);
g2d.drawImage(new ImageIcon("a.png").getImage(), tx, this);
}
}
Rotating a Shape with AffineTransform
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
public class BasicShapes {
public static void main(String[] args) {
AffineTransform tx = new AffineTransform();
tx.rotate(0.5);
Rectangle shape = new Rectangle(1, 1, 1, 1);
Shape newShape = tx.createTransformedShape(shape);
}
}
Rotating image using Java 2D AffineTransform class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import javax.swing.JPanel;
class ImagePanel extends JPanel {
int offset = 5;
private Image image;
private int angle;
private int w, h;
private AffineTransform transform;
public ImagePanel(Image i) {
image = i;
w = image.getWidth(this);
h = image.getHeight(this);
transform = new AffineTransform();
}
public void paintComponent(Graphics grp) {
Rectangle rect = this.getBounds();
Graphics2D g2d = (Graphics2D) grp;
transform.setToTranslation((rect.width - w) / 2,
(rect.height - h) / 2);
transform.rotate(Math.toRadians(angle), w / 2,
h / 2);
g2d.drawImage(image, transform, this);
}
public void rotate() {
angle -= offset;
if (angle <= 0) {
angle = 360;
}
repaint();
}
}
Rotation and coordinate translation
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Rotate extends JPanel {
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(150, 150, 150));
g2d.fillRect(20, 20, 80, 50);
g2d.translate(180, -150);
g2d.rotate(Math.PI / 4);
g2d.fillRect(20, 20, 80, 50);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Rotation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Rotate());
frame.setSize(300, 200);
frame.setVisible(true);
}
}
Scaling a Drawn Image
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
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;
AffineTransform tx = new AffineTransform();
double scalex = .5;
double scaley = 1;
tx.scale(scalex, scaley);
g2d.setTransform(tx);
g2d.drawImage(new ImageIcon("a.png").getImage(), tx, this);
}
}
Scaling an object
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Scale extends JPanel {
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(150, 150, 150));
g2d.fillRect(0, 0, 80, 50);
AffineTransform tx1 = new AffineTransform();
tx1.translate(110, 20);
tx1.scale(0.5, 0.5);
g2d.setTransform(tx1);
g2d.fillRect(0, 0, 80, 50);
AffineTransform tx2 = new AffineTransform();
tx2.translate(200, 20);
tx2.scale(1.5, 1.5);
g2d.setTransform(tx2);
g2d.fillRect(0, 0, 80, 50);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Scaling");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Scale());
frame.setSize(330, 160);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Scaling a Shape with AffineTransform
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
public class BasicShapes {
public static void main(String[] args) {
AffineTransform tx = new AffineTransform();
tx.scale(1, 1);
Rectangle shape = new Rectangle(1, 1, 1, 1);
Shape newShape = tx.createTransformedShape(shape);
}
}
Shearing a Drawn Image
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
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;
AffineTransform tx = new AffineTransform();
double shiftx = .1;
double shifty = .3;
tx.shear(shiftx, shifty);
g2d.setTransform(tx);
g2d.drawImage(new ImageIcon("a.png").getImage(), tx, this);
}
}
Shearing a Shape with AffineTransform
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
public class BasicShapes {
public static void main(String[] args) {
AffineTransform tx = new AffineTransform();
tx.shear(1, 1);
Rectangle shape = new Rectangle(1, 1, 1, 1);
Shape newShape = tx.createTransformedShape(shape);
}
}
Transform Demo
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TransformDemo extends JPanel {
public void init() {
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle rect = new Rectangle(5,5,200,200);
int w = getSize().width;
int h = getSize().height;
AffineTransform saveXform = g2.getTransform();
AffineTransform toCenterAt = new AffineTransform();
toCenterAt.translate(w / 2 - (rect.width / 2), h / 2 - (rect.height / 2));
g2.transform(toCenterAt);
g2.fill(rect);
g2.transform(saveXform);
}
public static void main(String s[]) {
JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
TransformDemo p = new TransformDemo();
f.getContentPane().add("Center", p);
p.init();
f.pack();
f.setSize(new Dimension(300, 300));
f.show();
}
}
Transforme Rotation demo
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformersRotation extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformersRotation() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
g2.transform(AffineTransform.getRotateInstance(-Math.PI / 6));
// Draw the "new" shapes in dashed.
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformersRotation());
f.setSize(350, 200);
f.show();
}
}
Transform Rotation Translation
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformersRotationTranslation extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformersRotationTranslation() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
AffineTransform rat = new AffineTransform();
rat.setToRotation(Math.PI / 6);
rat.translate(100, 100);
g2.transform(rat);
// Draw the "new" shapes in dashed.
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformersRotationTranslation());
f.setSize(350, 450);
f.show();
}
}
Transform Scale
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformScale extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformScale() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
g2.transform(AffineTransform.getScaleInstance(3, 3));
// Draw the "new" shapes in dashed.
g2.transform(AffineTransform.getTranslateInstance(75, 75));
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformScale());
f.setSize(650, 550);
f.show();
}
}
Transform Shear
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformShear extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformShear() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
AffineTransform sat = AffineTransform.getTranslateInstance(150, 0);
sat.shear(-.5, 0);
g2.transform(sat);
// Draw the "new" shapes in dashed.
g2.transform(AffineTransform.getTranslateInstance(75, 75));
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformShear());
f.setSize(450, 350);
f.show();
}
}
Transform Translated Rotation
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformTranslatedRotation extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformTranslatedRotation() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
float cm = 72 / 2.54f;
g2.transform(AffineTransform.getRotateInstance(-Math.PI / 6, 3 * cm, 2 * cm));
// Draw the "new" shapes in dashed.
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformTranslatedRotation());
f.setSize(450, 350);
f.show();
}
}
Transform Translation
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformTranslation extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformTranslation() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
g2.transform(AffineTransform.getTranslateInstance(150, 0));
// Draw the "new" shapes in dashed.
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformTranslation());
f.setSize(450, 350);
f.show();
}
}
Transform Translation and Rotation
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class TransformTransRotation extends JComponent {
Shape axes, shape;
int length = 54, arrowLength = 4, tickSize = 4;
public TransformTransRotation() {
axes = createAxes();
shape = createShape();
}
protected Shape createAxes() {
GeneralPath path = new GeneralPath();
// Axes.
path.moveTo(-length, 0);
path.lineTo(length, 0);
path.moveTo(0, -length);
path.lineTo(0, length);
// Arrows.
path.moveTo(length - arrowLength, -arrowLength);
path.lineTo(length, 0);
path.lineTo(length - arrowLength, arrowLength);
path.moveTo(-arrowLength, length - arrowLength);
path.lineTo(0, length);
path.lineTo(arrowLength, length - arrowLength);
// Half-centimeter tick marks
float cm = 72 / 2.54f;
float lengthCentimeter = length / cm;
for (float i = 0.5f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize / 2);
path.lineTo(tick, tickSize / 2);
path.moveTo(-tick, -tickSize / 2);
path.lineTo(-tick, tickSize / 2);
path.moveTo(-tickSize / 2, tick);
path.lineTo(tickSize / 2, tick);
path.moveTo(-tickSize / 2, -tick);
path.lineTo(tickSize / 2, -tick);
}
// Full-centimeter tick marks
for (float i = 1.0f; i < lengthCentimeter; i += 1.0f) {
float tick = i * cm;
path.moveTo(tick, -tickSize);
path.lineTo(tick, tickSize);
path.moveTo(-tick, -tickSize);
path.lineTo(-tick, tickSize);
path.moveTo(-tickSize, tick);
path.lineTo(tickSize, tick);
path.moveTo(-tickSize, -tick);
path.lineTo(tickSize, -tick);
}
return path;
}
protected Shape createShape() {
float cm = 72 / 2.54f;
return new Rectangle2D.Float(cm, cm, 2 * cm, cm);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// Use antialiasing.
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Move the origin to 75, 75.
AffineTransform at = AffineTransform.getTranslateInstance(75, 75);
g2.transform(at);
// Draw the shapes in their original locations.
g2.setPaint(Color.black);
g2.draw(axes);
g2.draw(shape);
// Transform the Graphics2D.
AffineTransform rat = new AffineTransform();
rat.setToTranslation(100, 0);
rat.rotate(Math.PI / 6);
g2.transform(rat);
// Draw the "new" shapes in dashed.
Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 3, 1 }, 0);
g2.setStroke(stroke);
g2.draw(axes);
g2.draw(shape);
}
public static void main(String[] a) {
JFrame f = new JFrame();
f.getContentPane().add(new TransformTransRotation());
f.setSize(450, 350);
f.show();
}
}
Translating a Drawn Image
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
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;
AffineTransform tx = new AffineTransform();
double x = 50;
double y = 50;
tx.translate(x, y);
g2d.setTransform(tx);
g2d.drawImage(new ImageIcon("a.png").getImage(), tx, this);
}
}
Translating a Shape with AffineTransform
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
public class BasicShapes {
public static void main(String[] args) {
AffineTransform tx = new AffineTransform();
tx.translate(1, 10);
Rectangle shape = new Rectangle(1, 1, 1, 1);
Shape newShape = tx.createTransformedShape(shape);
}
}