Java - 原地旋转图像
Java - rotate image in place
我有一个坦克大炮层,它应该向鼠标位置旋转,我用以下代码完成了:
double theta = Math.atan2(point.getY() - center.getY(), point.getX() - center.getX());
然后我相应地旋转图形对象的变换。这可行,但大炮围绕大炮的中心旋转。我希望大炮的底座在旋转发生时保持在原位。我已经尝试了很多不同的位置来旋转,但我找不到一个可以将其底座保持在适当位置的位置。我想我必须将旋转后的图形对象平移到大炮底座应该在的位置,但我不知道该怎么做。我的两层加农炮:
如您所见,底座(浅绿色部分)必须保持在原位。我怎样才能做到这一点?
您的公式只是显示了您如何计算角度 - 您的问题似乎是 'how to rotate an image around a specified point'。为此,我建议使用 AffineTransform
s(矩阵数学)。一个很好的起点是:http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html.
一些示例代码:
Graphics2D g; //<- you should have this in your code somewhere
AffineTransform at = new AffineTransform();
at.rotate(theta, centerX, centerY); //<- your question: rotate around specified point
g.setTransform(at); //<- tell the graphics to transform before painting
g.drawImage(...); //<- draws transformed image
如果您深入研究 AffineTransform.rotate(...)
,您会发现首先进行平移,然后进行旋转。第三个转换是具有负 x/y 值的翻译。
这是 sun 的旧代码:
public void rotate(double theta, double anchorx, double anchory) {
// REMIND: Simple for now - optimize later
translate(anchorx, anchory);
rotate(theta);
translate(-anchorx, -anchory);
}
使用矩阵非常强大,因为您可以组合平移、旋转、剪切、镜像等等。不仅在 2d 中,而且在 3d 中。也许你的坦克有一天会离开平坦的世界,成为一个体积模型...
好吧,假设炮塔和基地是分开的图像,并且炮塔和坦克的大小不一样(因为然后它变得复杂......更多然后它实际上是:P)
您可以使用 AffineTransform
并复合转换...
// This is the x/y position of the top, at the top/left point,
// I've placed it at the center of my screen, but you get the idea
double x = (getWidth() - base.getWidth()) / 2d;
double y = (getHeight() - base.getHeight()) / 2d;
// Translate the location to the x/y, this makes the top/left 0x0...
// much easier to deal with...
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
g2d.setTransform(at);
// Draw the base...
g2d.drawImage(base, 0, 0, this);
// Offset the turret, in my testing, this was 8x8 from the bases
// top/left
at.translate(8, 8);
if (targetPoint != null) {
// Calculate the delta between the mouse and the center point
// of the turret, this is in screen coordinates and not
// translated coordinates
double deltaX = (x + 8) - targetPoint.x;
double deltaY = (y + 8) - targetPoint.y;
// Calculate the rotation required to point at the mouse
// Had to apply an offset to allow for the default orientation
// of the tank...
double rotation = Math.atan2(deltaY, deltaX) + Math.toRadians(180d);
// Rotate around the anchor point of the turret
// Remember, we've translated so the top/left (0x0) is now the
// turrets default position
at.rotate(rotation, 4, 4);
}
// Transform the Graphics context
g2d.setTransform(at);
// Paint the turret
g2d.drawImage(turret, 0, 0, this);
}
g2d.dispose();
而且因为我努力了...
我的资产...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FollowMe {
public static void main(String[] args) {
new FollowMe();
}
public FollowMe() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point targetPoint;
private BufferedImage turret;
private BufferedImage base;
public TestPane() {
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
targetPoint = e.getPoint();
repaint();
}
});
try {
base = ImageIO.read(getClass().getResource("/Base.png"));
turret = ImageIO.read(getClass().getResource("/Turret.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
if (base != null) {
double x = (getWidth() - base.getWidth()) / 2d;
double y = (getHeight() - base.getHeight()) / 2d;
// Test line from center of tank to mouse poisition
if (targetPoint != null) {
g2d.draw(new Line2D.Double((x + 12), (y + 12), targetPoint.x, targetPoint.y));
}
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
g2d.setTransform(at);
g2d.drawImage(base, 0, 0, this);
at.translate(8, 8);
if (targetPoint != null) {
double deltaX = (x + 8) - targetPoint.x;
double deltaY = (y + 8) - targetPoint.y;
double rotation = Math.atan2(deltaY, deltaX) + Math.toRadians(180d);
at.rotate(rotation, 4, 4);
}
g2d.setTransform(at);
g2d.drawImage(turret, 0, 0, this);
}
g2d.dispose();
}
}
}
查看 Transforming Shapes, Text, and Images 了解更多详情
我有一个坦克大炮层,它应该向鼠标位置旋转,我用以下代码完成了:
double theta = Math.atan2(point.getY() - center.getY(), point.getX() - center.getX());
然后我相应地旋转图形对象的变换。这可行,但大炮围绕大炮的中心旋转。我希望大炮的底座在旋转发生时保持在原位。我已经尝试了很多不同的位置来旋转,但我找不到一个可以将其底座保持在适当位置的位置。我想我必须将旋转后的图形对象平移到大炮底座应该在的位置,但我不知道该怎么做。我的两层加农炮:
如您所见,底座(浅绿色部分)必须保持在原位。我怎样才能做到这一点?
您的公式只是显示了您如何计算角度 - 您的问题似乎是 'how to rotate an image around a specified point'。为此,我建议使用 AffineTransform
s(矩阵数学)。一个很好的起点是:http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html.
一些示例代码:
Graphics2D g; //<- you should have this in your code somewhere
AffineTransform at = new AffineTransform();
at.rotate(theta, centerX, centerY); //<- your question: rotate around specified point
g.setTransform(at); //<- tell the graphics to transform before painting
g.drawImage(...); //<- draws transformed image
如果您深入研究 AffineTransform.rotate(...)
,您会发现首先进行平移,然后进行旋转。第三个转换是具有负 x/y 值的翻译。
这是 sun 的旧代码:
public void rotate(double theta, double anchorx, double anchory) {
// REMIND: Simple for now - optimize later
translate(anchorx, anchory);
rotate(theta);
translate(-anchorx, -anchory);
}
使用矩阵非常强大,因为您可以组合平移、旋转、剪切、镜像等等。不仅在 2d 中,而且在 3d 中。也许你的坦克有一天会离开平坦的世界,成为一个体积模型...
好吧,假设炮塔和基地是分开的图像,并且炮塔和坦克的大小不一样(因为然后它变得复杂......更多然后它实际上是:P)
您可以使用 AffineTransform
并复合转换...
// This is the x/y position of the top, at the top/left point,
// I've placed it at the center of my screen, but you get the idea
double x = (getWidth() - base.getWidth()) / 2d;
double y = (getHeight() - base.getHeight()) / 2d;
// Translate the location to the x/y, this makes the top/left 0x0...
// much easier to deal with...
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
g2d.setTransform(at);
// Draw the base...
g2d.drawImage(base, 0, 0, this);
// Offset the turret, in my testing, this was 8x8 from the bases
// top/left
at.translate(8, 8);
if (targetPoint != null) {
// Calculate the delta between the mouse and the center point
// of the turret, this is in screen coordinates and not
// translated coordinates
double deltaX = (x + 8) - targetPoint.x;
double deltaY = (y + 8) - targetPoint.y;
// Calculate the rotation required to point at the mouse
// Had to apply an offset to allow for the default orientation
// of the tank...
double rotation = Math.atan2(deltaY, deltaX) + Math.toRadians(180d);
// Rotate around the anchor point of the turret
// Remember, we've translated so the top/left (0x0) is now the
// turrets default position
at.rotate(rotation, 4, 4);
}
// Transform the Graphics context
g2d.setTransform(at);
// Paint the turret
g2d.drawImage(turret, 0, 0, this);
}
g2d.dispose();
而且因为我努力了...
我的资产...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FollowMe {
public static void main(String[] args) {
new FollowMe();
}
public FollowMe() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Point targetPoint;
private BufferedImage turret;
private BufferedImage base;
public TestPane() {
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
targetPoint = e.getPoint();
repaint();
}
});
try {
base = ImageIO.read(getClass().getResource("/Base.png"));
turret = ImageIO.read(getClass().getResource("/Turret.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g.drawLine(getWidth() / 2, 0, getWidth() / 2, getHeight());
g.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2);
if (base != null) {
double x = (getWidth() - base.getWidth()) / 2d;
double y = (getHeight() - base.getHeight()) / 2d;
// Test line from center of tank to mouse poisition
if (targetPoint != null) {
g2d.draw(new Line2D.Double((x + 12), (y + 12), targetPoint.x, targetPoint.y));
}
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
g2d.setTransform(at);
g2d.drawImage(base, 0, 0, this);
at.translate(8, 8);
if (targetPoint != null) {
double deltaX = (x + 8) - targetPoint.x;
double deltaY = (y + 8) - targetPoint.y;
double rotation = Math.atan2(deltaY, deltaX) + Math.toRadians(180d);
at.rotate(rotation, 4, 4);
}
g2d.setTransform(at);
g2d.drawImage(turret, 0, 0, this);
}
g2d.dispose();
}
}
}
查看 Transforming Shapes, Text, and Images 了解更多详情