AffineTransform.rotate() – 如何同时进行xlate,旋转和缩放?

我有以下代码(我的第一部分)想要绘制一个棋子上有一些棋子。

Image pieceImage = getImage(currentPiece); int pieceHeight = pieceImage.getHeight(null); double scale = (double)side/(double)pieceHeight; AffineTransform transform = new AffineTransform(); transform.setToTranslation(xPos, yPos); transform.scale(scale, scale); realGraphics.drawImage(pieceImage, transform, this); 

也就是说,它获得了棋子的图像和图像的高度,它将该图像的绘图转换为该片段所在的正方形,并将图像缩放到正方形的大小。

Llet说我想把黑色棋子旋转180度。 在某个地方,我希望有类似的东西:

 transform.rotate(Math.toRadians(180) /* ?, ? */); 

但是我无法弄清楚X和Y会放入什么。如果我什么也没放,那么这个图像很好地围绕着它的棋盘方块的0点旋转,将这个块倒置在广场的东北方向它应该是。 我已经猜到了x,y的各种其他组合,但没有运气。

我已经在使用平移把这个块放在正方形中,旋转变换需要另一个x,y围绕它旋转东西,但我不知道如何告诉变换旋转一个x,y并写入图像到不同的x,y。 有人可以帮助我使用旋转参数,还是指出一些能解释这些东西如何工作的东西? 我找到了一些不能解释它们是如何工作的事情的例子,到目前为止我还没有弄清楚如何根据我的情况改变它们……


主要编辑:添加工作代码。 对不起,我不知道如何发布图片,请替换自己的。

当我跑下面的时候,我得到一个2×2的棋盘,左上角有一辆车,右下角是骑士。

如果我进入SmallChessboardComponent并从第一个旋转变换语句中删除注释delims,我会将原始位置的车辆颠倒并且骑士不会出现。 如果我改为从第二个转换语句中删除注释,则根本不会显示任何一个。

我正在寻找一种方法将这些碎片倒置在他们无论如何都会出现的广场上。 我想把每一块都画在板上; 我不希望代码翻转电路板。

主程序:

 package main; import java.awt.BorderLayout; import javax.swing.JFrame; import directredraw.SmallChessboardComponent; public class SmallChessboardMain { private static void dbg (String message) { System.out.println(message); } public static void main(String[] args) { //Create the top-level container and add contents to it. final JFrame frame = new JFrame("Small Chessboard"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // create the chessboard itself and set it in the component SmallChessboard chessboard = new SmallChessboard(); // create the GUI component that will contain the chessboard SmallChessboardComponent chessboardComponent = new SmallChessboardComponent(); chessboardComponent.setBoard (chessboard); frame.getContentPane().add(chessboardComponent, BorderLayout.CENTER); // pack and display all this frame.pack(); frame.setVisible(true); } } 

棋盘类:

 package main; public class SmallChessboard { Piece [][] squares = new Piece[2][2]; public SmallChessboard() { squares[0][0] = new Piece(Piece.WHITECOLOR, Piece.ROOK); squares[1][1] = new Piece(Piece.WHITECOLOR, Piece.KNIGHT); } /** * get the piece at the given rank and file; null if * no piece exists there. */ public Piece getPiece(int rank, int file) { if (0 > rank || rank > 2 || 0 > file || file > 2) { return null; } else { return squares[rank][file]; } } } 

棋盘组件类:

 package directredraw; import java.awt.Color; import java.awt.Dimension; 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; import main.Piece; import main.PieceImages; import main.SmallChessboard; public class SmallChessboardComponent extends JPanel { private static final long serialVersionUID = 1L; Color whiteSquareColor = Color.yellow; Color blackSquareColor = Color.blue; private static void dbg (String msg) { System.out.println(msg); } private SmallChessboard chessboard = null; // currently playing with rotating images; this affine transform // should help AffineTransform rotationTransform = null; private final int DEFAULT_PREFERRED_SIDE = 400; int wholeSide = DEFAULT_PREFERRED_SIDE; int side = DEFAULT_PREFERRED_SIDE / 8; public void setBoard (SmallChessboard givenBoard) { chessboard = givenBoard; } /** * set either or both colors for this chessboard; if either of * the arguments are null, they do not change the existing color * setting. */ public void setColors (Color darkSquare, Color lightSquare) { if (darkSquare != null) { blackSquareColor = darkSquare; } if (lightSquare != null) { whiteSquareColor = lightSquare; } } /** * return the preferred size for this component.s */ public Dimension getPreferredSize() { return new Dimension(wholeSide, wholeSide); } /* * return the image object for the given piece */ private Image getImage(Piece piece) { return PieceImages.getPieceImage(this, piece); } public void paintComponent (Graphics graphics) { Graphics2D realGraphics = (Graphics2D) graphics; // the image container might have been stretched. // calculate the largest square held by the current container, // and then 1/2 of that size for an individual square. int wholeWidth = this.getWidth(); int wholeHeight = this.getHeight(); wholeSide = (wholeWidth / 2) * 2; if (wholeHeight < wholeWidth) { wholeSide = (wholeHeight / 2) * 2; } side = wholeSide / 2; Rectangle clip = realGraphics.getClipBounds(); boolean firstColumnWhite = false; // for each file on the board: // set whether top square is white // set background color according to white/black square // for (int fileIndex=0; fileIndex=0; rankIndex--) { currentColorWhite = !currentColorWhite; // x and y position of the top left corner of the square we're drawing, // and rect becomes the dimensions and position of the square itself. int xPos = fileIndex * side; int yPos = rankIndex * side; Rectangle rect = new Rectangle(xPos, yPos, side, side); // if this square intersects the clipping rectangle we're drawing, // then we'll draw the square and the piece on the square. if (rect.intersects(clip)) { // this puts down the correct color of square if (currentColorWhite) { realGraphics.setColor(whiteSquareColor); } else { realGraphics.setColor(blackSquareColor); } realGraphics.fillRect(xPos, yPos, side, side); // if there is a piece on this square and it isn't selected at the // moment, then draw it. Piece currentPiece = chessboard.getPiece(rankIndex, fileIndex); if (currentPiece != null) { Image pieceImage = getImage(currentPiece); int pieceHeight = pieceImage.getHeight(null); double scalePiece = (double)side/(double)pieceHeight; AffineTransform transform = new AffineTransform(); // transform.setToRotation(Math.toRadians(180)); transform.setToRotation(Math.toRadians(180), side/2, side/2); transform.scale(scalePiece, scalePiece); transform.translate(xPos/scalePiece, yPos/scalePiece); // if (currentPiece.isBlack()) // { // transform.translate(xPos + (side+2), yPos + (side+2)); // transform.rotate(Math.toRadians(180) /*, ,*/ ); // } // else // { // transform.translate(xPos, yPos); // } realGraphics.drawImage(pieceImage, transform, this); } } } } } } 

Piece.java

 package main; public class Piece { // piece types; the sum of the piece type and the // color gives a number unique to both type and color, // which is used for things like image indices. public static final int PAWN = 0; public static final int KNIGHT = 1; public static final int BISHOP = 2; public static final int ROOK = 3; public static final int QUEEN = 4; public static final int KING = 5; // one of these is the color of the current piece public static final int NOCOLOR = -1; // the sum of the piece type and the // color gives a number unique to both type and color, // which is used for things like image indices. public static final int BLACKCOLOR = 0; public static final int WHITECOLOR = 6; int color = NOCOLOR; int imageIndex; public Piece(int color, int pieceType) { // dbg -- all pieces are white rooks for now... this.color = color; imageIndex = color + pieceType; } /** * return the integer associated with this piece's color; */ int getPieceColor() { return color; } /** * return true if the piece is black */ public boolean isBlack() { return (color == BLACKCOLOR); } /** * set the color associated with this piece; constants * found in this class. */ public void setPieceColor(int givenColor) { color = givenColor; } /** * return the integer designated for the image used for this piece. */ int getImageIndex() { return imageIndex; } } 

和PieceImages.java

 package main; import java.awt.Component; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.net.URL; public class PieceImages { static Image images[] = null; private static void dbg (String msg) { System.out.println(msg); } public static Image getPieceImage (Component target, Piece piece) { if (images == null) try { MediaTracker tracker = new MediaTracker(target); images = new Image[12]; images[Piece.BLACKCOLOR + Piece.PAWN] = getImage(tracker, "bPawn.gif"); images[Piece.BLACKCOLOR + Piece.KNIGHT] = getImage(tracker, "bKnight.gif"); images[Piece.BLACKCOLOR + Piece.BISHOP] = getImage(tracker, "bBishop.gif"); images[Piece.BLACKCOLOR + Piece.ROOK] = getImage(tracker, "bRook.gif"); images[Piece.BLACKCOLOR + Piece.QUEEN] = getImage(tracker, "bQueen.gif"); images[Piece.BLACKCOLOR + Piece.KING] = getImage(tracker, "bKing.gif"); images[Piece.WHITECOLOR + Piece.PAWN] = getImage(tracker, "wPawn.gif"); images[Piece.WHITECOLOR + Piece.KNIGHT] = getImage(tracker, "wKnight.gif"); images[Piece.WHITECOLOR + Piece.BISHOP] = getImage(tracker, "wBishop.gif"); images[Piece.WHITECOLOR + Piece.ROOK] = getImage(tracker, "wRook.gif"); images[Piece.WHITECOLOR + Piece.QUEEN] = getImage(tracker, "wQueen.gif"); images[Piece.WHITECOLOR + Piece.KING] = getImage(tracker, "wKing.gif"); if (!tracker.waitForAll(10000)) { System.out.println("ERROR: not all piece main.images loaded"); } dbg("piece images loaded"); } catch (Exception xcp) { System.out.println("Error loading images"); xcp.printStackTrace(); } return images[piece.getImageIndex()]; } private static Image getImage(MediaTracker tracker, String file) { URL url = PieceImages.class.getResource("images/" + file); Image image = Toolkit.getDefaultToolkit().getImage(url); tracker.addImage(image, 1); return image; } } 

好的,这有点轻微。 示例代码仅适用于90度增量(它仅以这种方式设计),以较小的增量使用一些触发来计算图像宽度和高度(在某处可以得到答案;))

 public class ImagePane extends JPanel { private BufferedImage masterImage; private BufferedImage renderedImage; public ImagePane(BufferedImage image) { masterImage = image; applyRotation(0); } @Override public Dimension getPreferredSize() { return new Dimension(renderedImage.getWidth(), renderedImage.getHeight()); } @Override public Dimension getMinimumSize() { return getPreferredSize(); } protected int getVirtualAngle(int angle) { float fRotations = (float) angle / 360f; int rotations = (int) (fRotations - (fRotations / 1000)); int virtual = angle - (rotations * 360); if (virtual < 0) { virtual = 360 + virtual; } return virtual; } public void applyRotation(int angle) { // This will only work for angles of 90 degrees... // Normalize the angle to make sure it's only between 0-360 degrees int virtualAngle = getVirtualAngle(angle); Dimension size = new Dimension(masterImage.getWidth(), masterImage.getHeight()); int masterWidth = masterImage.getWidth(); int masterHeight = masterImage.getHeight(); double x = 0; //masterWidth / 2.0; double y = 0; //masterHeight / 2.0; switch (virtualAngle) { case 0: break; case 180: break; case 90: case 270: size = new Dimension(masterImage.getHeight(), masterImage.getWidth()); x = (masterHeight - masterWidth) / 2.0; y = (masterWidth - masterHeight) / 2.0; break; } renderedImage = new BufferedImage(size.width, size.height, masterImage.getTransparency()); Graphics2D g2d = renderedImage.createGraphics(); AffineTransform at = AffineTransform.getTranslateInstance(x, y); at.rotate(Math.toRadians(virtualAngle), masterWidth / 2.0, masterHeight / 2.0); g2d.drawImage(masterImage, at, null); g2d.dispose(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; int width = getWidth() - 1; int height = getHeight() - 1; int x = (width - renderedImage.getWidth()) / 2; int y = (height - renderedImage.getHeight()) / 2; g2d.drawImage(renderedImage, x, y, this); } } 

现在,您可以直接“翻转”图像,如果这对您更有效

 public class FlipPane extends JPanel { private BufferedImage masterImage; private BufferedImage renderedImage; public FlipPane(BufferedImage image) { masterImage = image; flipMaster(); } @Override public Dimension getPreferredSize() { return new Dimension(renderedImage.getWidth(), renderedImage.getHeight()); } @Override public Dimension getMinimumSize() { return getPreferredSize(); } protected void flipMaster() { renderedImage = new BufferedImage(masterImage.getWidth(), masterImage.getHeight(), masterImage.getTransparency()); Graphics2D g2d = renderedImage.createGraphics(); g2d.setTransform(AffineTransform.getScaleInstance(1, -1)); g2d.drawImage(masterImage, 0, -masterImage.getHeight(), this); g2d.dispose(); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; int width = getWidth() - 1; int height = getHeight() - 1; int x = (width - renderedImage.getWidth()) / 2; int y = (height - renderedImage.getHeight()) / 2; g2d.drawImage(renderedImage, x, y, this); } } 

这基本上导致:

图像旋转示例

原创| 180度旋转| 垂直反转......

现在,如果您将flipMaster方法更改为:

 g2d.setTransform(AffineTransform.getScaleInstance(-1, -1)); g2d.drawImage(masterImage, -masterImage.getWidth(), -masterImage.getHeight(), this); 

你将获得与180度旋转相同的效果;)

尝试在将其旋转到正确位置之前执行旋转。 只需重新排序转换,然后首先缩放,然后旋转(围绕图像的中心点),然后翻译:

 transform.scale(scale, scale); transform.rotate(Math.PI, pieceWidth / 2, pieceHeight /2); transform.translation(xPos, yPos); 

顺便说一下,棋盘上的黑棋子通常不会旋转。 🙂

更新

它以什么方式不起作用? 我提供的解决方案也与您的代码的不同之处在于,在翻译之前执行缩放。 您可以尝试旋转,平移,然后缩放。

我强烈建议您修改代码,以便最后执行翻译。 如果你这样做,一切都会变得复杂得多。 完成后,您只需缩放一次即可自动处理旋转。

 transform.scale(scale, scale); // or transform.scale(scale, -scale); to rotate transform.translate(xPos, yPos);