【问题标题】:Java Graphics2D obtain rotated image bounding and new coordiinatesJava Graphics2D 获得旋转图像边界和新坐标
【发布时间】:2015-07-28 14:36:51
【问题描述】:

我在 Graphics2D 中有一个图像,我需要旋转它,然后获取图像角的新坐标和新边界框的尺寸。

我最初尝试使用图像本身,但我认为使用矩形(或多边形)更容易为自己提供更大的灵活性。我最初只是使用AffineTransform.rotate() 对图像执行旋转。但是,如果有一种方法可以单独平移每个角点,那会更简洁,这会给我 A1、B1、C1 和 D1 的值。 Graphics2D 中有没有办法旋转各个角?

我发现了几个与旋转矩形的边界框尺寸有关的问题,但我似乎无法让它们中的任何一个在 Java 中与 Graphics2D 一起工作。

【问题讨论】:

  • 您是否必须通过 Graphics2D 执行此操作,还是可以接受点的纯数学变换?
  • 我说的不是Graphics2D。但是,我与某种可以从 Java 访问的图形操作库联系在一起。我发现了很多纯数学变换,所以我正在寻找一个特定于实现的解决方案。

标签: java rotation graphics2d


【解决方案1】:

您只需自己旋转图像角即可。包java.awt.geom 提供了Point2D 和AffineTransform 类,通过对各个点应用旋转变换来做到这一点。旋转边界框的宽度和高度可以计算为最大和最大旋转 x 和 y 坐标之间的差,最小 x 和 y 坐标作为偏移量。

以下程序实现了这个算法,并以 30° 的步长显示了从 0° 到 360° 的几次旋转的结果:

package stackoverflow;

import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

/**
 * Demonstration of an implementation to rotate rectangles.
 * @author Franz D.
 */
public class ImageRotate
{
    /**
     * Rotates a rectangle with offset (0,0).
     * @param originalWidth original rectangle width
     * @param originalHeight original rectangle height
     * @param angleRadians rotation angle in radians
     * @param rotatedCorners output buffer for the four rotated corners
     * @return the bounding box of the rotated rectangle
     * @throws NullPointerException if {@code rotatedCorners == null}.
     * @throws ArrayIndexOutOfBoundsException if {@code rotatedCorners.length < 4}.
     */
    public static Rectangle2D rotateRectangle(int originalWidth, int originalHeight,
            double angleRadians,
            Point2D[] rotatedCorners) {
        // create original corner points
        Point2D a0 = new Point2D.Double(0, 0);
        Point2D b0 = new Point2D.Double(originalWidth, 0);
        Point2D c0 = new Point2D.Double(0, originalHeight);
        Point2D d0 = new Point2D.Double(originalWidth, originalHeight);
        Point2D[] originalCorners = { a0, b0, c0, d0 };

        // create affine rotation transform
        AffineTransform transform = AffineTransform.getRotateInstance(angleRadians);

        // transform original corners to rotated corners
        transform.transform(originalCorners, 0, rotatedCorners, 0, originalCorners.length);

        // determine rotated width and height as difference between maximum and
        // minimum rotated coordinates
        double minRotatedX = Double.POSITIVE_INFINITY;
        double maxRotatedX = Double.NEGATIVE_INFINITY;
        double minRotatedY = Double.POSITIVE_INFINITY;
        double maxRotatedY = Double.NEGATIVE_INFINITY;

        for (Point2D rotatedCorner: rotatedCorners) {
            minRotatedX = Math.min(minRotatedX, rotatedCorner.getX());
            maxRotatedX = Math.max(maxRotatedX, rotatedCorner.getX());
            minRotatedY = Math.min(minRotatedY, rotatedCorner.getY());
            maxRotatedY = Math.max(maxRotatedY, rotatedCorner.getY());
        }

        // the bounding box is the rectangle with minimum rotated X and Y as offset
        double rotatedWidth = maxRotatedX - minRotatedX;
        double rotatedHeight = maxRotatedY - minRotatedY;

        Rectangle2D rotatedBounds = new Rectangle2D.Double(
                minRotatedX, minRotatedY,
                rotatedWidth, rotatedHeight);

        return rotatedBounds;
    }

    /**
     * Simple test for {@link #rotateRectangle(int, int, double, java.awt.geom.Point2D[])}.
     * @param args ignored
     */
    public static void main(String[] args) {
        // setup original width
        int originalWidth = 500;
        int originalHeight = 400;

        // create buffer for rotated corners
        Point2D[] rotatedCorners = new Point2D[4];

        // rotate rectangle from 0° to 360° in 30° steps
        for (int angleDegrees = 0; angleDegrees < 360; angleDegrees += 30) {
            // convert angle to radians
            double angleRadians = Math.toRadians(angleDegrees);

            // rotate rectangle
            Rectangle2D rotatedBounds = rotateRectangle(
                    originalWidth, originalHeight,
                    angleRadians,
                    rotatedCorners);

            // dump results
            System.out.println("--- Rotate " + originalWidth + "x" + originalHeight + " by " + angleDegrees + "° ---");
            System.out.println("Bounds: " + rotatedBounds);
            for (Point2D rotatedCorner: rotatedCorners) {
                System.out.println("Corner " + rotatedCorner);
            }
        }
    }
}

如果你的图片没有放置在偏移量(0, 0),你可以简单地修改方法以将偏移量作为输入参数,并将偏移量坐标添加到原始点。

此外,此方法会围绕原点 (0, 0) 旋转图像(或矩形)。如果您需要其他旋转中心,AffineTransform 提供了 getRotateInstace() 的重载变体,它允许您指定旋转中心(在 API 文档中称为“锚点”)。

【讨论】:

    猜你喜欢
    • 2011-01-15
    • 1970-01-01
    • 1970-01-01
    • 2014-05-25
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    相关资源
    最近更新 更多