1

次のコードは、チェス盤にいくつかの駒を描いて欲しいこと (の最初の部分) を行います。

              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) /* ?, ? */);

しかし、X と Y として何を入力すればよいかわかりません。何も入力しないと、チェス盤の正方形の 0,0 点を中心に画像がうまく回転し、その北東の正方形にピースが上下逆さまになります。それはあるはずです。x,y の他のさまざまな組み合わせを推測しましたが、まだ運がありません。

私はすでに翻訳を使用してピースを正しい正方形に配置しています。回転変換は、物事を回転させる別の x、y を必要としていますが、1 つの x、y を中心にピースを回転させて書き込むように変換に指示する方法がわかりません。画像を別の x、y にします。誰かが回転パラメーターを手伝ってくれたり、これらがどのように機能するかを説明してくれるものを教えてくれますか? それらがどのように機能するかを説明していないものの例を見つけましたが、これまでのところ、それらを自分の状況に変更する方法がわかりません...


主な編集: 作業コードの追加。申し訳ありませんが、画像を投稿する方法がわかりません。自分の画像に置き換えてください。

次のコマンドを実行すると、左上にルーク、右下にナイトの 2x2 チェス盤が表示されます。

SmallChessboardComponent に移動し、最初の回転変換ステートメントからコメント delims を削除すると、ルークが元の場所に逆さまになり、ナイトは表示されません。代わりに、2 番目の変換ステートメントからコメント 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);
                }
            }
          }
        }
    }
  }

ピース.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;
  }
}
4

2 に答える 2

4

さて、これはちょっとした手です。サンプル コードは 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 回転と同じ効果が得られます ;)

于 2012-08-11T03:54:23.317 に答える
2

正しい位置に移動する前に、回転を実行してみてください。変換を並べ替えて、最初に拡大縮小し、次に回転(画像の中心点を中心に)してから、次のように変換します。

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

ちなみに、チェス盤の黒い部分は通常回転していません。:)

アップデート

どのように機能しませんか?私が提供したソリューションも、変換前にスケーリングが実行されるという点でコードとは異なります。回転、平行移動、スケーリングを試すことができます。

最後に翻訳を実行できるように、コードを変更することを強くお勧めします。これを行うと、すべてがはるかに簡単になります。一度実行すると、回転を自動的に処理するために1回だけスケーリングする必要があります。

transform.scale(scale, scale); // or transform.scale(scale, -scale); to rotate
transform.translate(xPos, yPos);
于 2012-08-11T03:41:16.773 に答える