AffineTransform.rotate() - how do I xlate, rotate, and scale at the same time?

后端 未结 2 1036
闹比i
闹比i 2020-11-30 15:41

I have the following code which does (the first part of) what I want drawing a chessboard with some pieces on it.

              Image pieceImage = getImage(c         


        
相关标签:
2条回答
  • 2020-11-30 16:07

    Okay, this is a little slight of hand. The example code will only work for 90 degree increments (it was only designed this way), to do smaller increments you to use some trig to calculate the image width and height (there's a answer somewhere for that to ;))

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

    Now, you could simply "flip" the image vertically, if that works better for you

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

    This basically results in:

    Image rotation example

    Original | 180 degree rotation | Vertical inversion...

    Now, if you change the flipMaster method to read:

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

    You'll get the same effect as the 180 rotation ;)

    0 讨论(0)
  • 2020-11-30 16:21

    Try performing the rotation before translating it into the correct position. Simply reorder the transformations so that first you scale, then you rotate (around the center point of the image), and then you translate:

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

    By the way, the black pieces on a chess board usually aren't rotated. :)

    Update

    In what way does it not work? The solution I provided also also differs from your code in that scaling is performed before translating. You can try the rotating, translating, and then scaling.

    I strongly suggest that you modify your code so that you can perform the translation last. If you do this, everything will become a lot less complicated. Once you have done so, you only have to scale once to automatically take care of the rotation.

    transform.scale(scale, scale); // or transform.scale(scale, -scale); to rotate
    transform.translate(xPos, yPos);
    
    0 讨论(0)
提交回复
热议问题