当前位置: 首页 > 知识库问答 >
问题:

affineTransform.rotate()-如何同时进行xlate、旋转和缩放?

太叔志文
2023-03-14

我有下面的代码,它做(第一部分)什么我想画一个棋盘上有一些棋子。

              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);

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

假设我想把黑色的部分旋转180度。我希望在某个地方有这样的东西:

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

如果我进入SmallChessboardComponent并从第一个rotation transform语句中删除注释delims,我将rook颠倒在原来的位置,而knight不会出现。相反,如果我从第二个transform语句中删除注释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<8; fileIndex++)
        { boolean currentColorWhite = firstColumnWhite;
          firstColumnWhite = !firstColumnWhite;

          // draw the board and all the pieces
          int rankIndex = 2;
          for (rankIndex=2; rankIndex>=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);
                }
            }
          }
        }
    }
  }
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;
  }

}
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;
  }
}

共有1个答案

傅朝
2023-03-14

好吧,这是手的一点轻微。示例代码只适用于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);
    }
}

这基本上导致:

g2d.setTransform(AffineTransform.getScaleInstance(-1, -1));
g2d.drawImage(masterImage, -masterImage.getWidth(), -masterImage.getHeight(), this);
 类似资料:
  • 我有一个被JScrollPane包围的JPanel。该JPanel用于显示图像。我需要提供zoomIn、zoomOut、顺时针旋转和逆时针旋转等功能。所有这些功能单独运行良好。对于缩放,我称之为图形对象的缩放。它发生在从左上到右下的基础上。对于旋转,我重置比例,然后平移、旋转 因此,问题是当面板坐标更改时,图像的坐标不会改变。有人可以帮助我更改图像的坐标吗?

  • 选择要变换的文字 您可以像对其他对象一样,对文字进行旋转、镜像、比例缩放和倾斜。但是,您选择文字的方式会影响变换结果: 要变换文字及其边框路径,请选择文字对象,然后使用旋转工具旋转对象和文本。 要只变换边框路径(而不变换它所包含的文字),请使用选择工具选择文字对象并进行拖移。 旋转文字路径(左图)与旋转文字和路径(右图)的对比图 另请参阅 第 197 页的 “变换对象 ” 调整文字缩放比例 您可以

  • 选择要变换的文字 您可以像对其他对象一样,对文字进行旋转、镜像、比例缩放和倾斜。但是,您选择文字的方式会影响变换结果: 要变换文字及其边框路径,请选择文字对象,然后使用旋转工具旋转对象和文本。 要只变换边框路径(而不变换它所包含的文字),请使用选择工具选择文字对象并进行拖移。旋转文字路径(左图)与旋转文字和路径(右图)的对比图 调整文字缩放比例 您可以相对字符的原始宽度和高度,指定文字高度和宽度的

  • 问题内容: 我有一个SCN节点,已将其转换为所需的旋转和角度。 现在,我想在新的X轴上无限旋转它,但是我似乎无法使其旋转360度,只是稍微移动了一点。 请注意,我从先前的问题中找到了旋转代码,它可以按预期工作,但是如果我想在转换后的节点上旋转,则不会。 编辑:转换代码: 问题答案: 回答您的评论,也可能回答您的问题。一旦安装了.dae文件,就可以按照以下示例访问节点: 如果需要查找这些节点的名称,

  • 我有不同维度的文档图像,我希望能够有效地缩放和旋转他们在以下方式(标准的“旋转”和“缩放”逻辑)。我怎么做? 一幅图像是H像素高,W像素宽。最初,它应该缩放到600像素宽。在每次旋转时,面板的宽度和高度应该互换,缩放图像应该旋转90度。在每次缩放时,图像应按因子“比例”缩放。 以下是我到目前为止在...得到的BufferedImage会缩放和旋转,但不会平移(旋转90度后位于面板顶部的中心):

  • 问题内容: 通过梳理后SVG规范和指南,如这个和这个,我仍然在努力理解究竟是如何链接转换工作。 精选相关报价 当将transform属性应用于SVG元素时,该元素将获得使用中的当前用户坐标系的“副本”。 和: 当转换链接在一起时,最重要的是要意识到,就像HTML元素转换一样,每个转换都将在坐标系被先前的转换转换后应用于坐标系。 和: 例如,如果要对元素应用旋转,然后进行平移,则平移将根据新的坐标系