java - 旋转形状并在原始位置绘制

标签 java swing geometry 2d

我试图在给定点绘制一个旋转的形状。举个例子,在下图中,红色矩形是在一个点上绘制的未旋转矩形,然后蓝色矩形在同一位置旋转绘制。蓝色矩形是我想要的结果。

我一直在试验和尝试不同的方法。目前,这是我用于图像的内容:

Point point = new Point(300, 300);
Dimension dim = new Dimension(200, 100);
double radians = Math.toRadians(30);
g.setColor(new java.awt.Color(1f, 0f, 0f, .5f));
g.fillRect(point.x, point.y, dim.width, dim.height);
translate(g, dim, radians);
g.rotate(radians, point.getX(), point.getY());
g.setColor(new java.awt.Color(0f, 0f, 1f, .5f));
g.fillRect(point.x, point.y, dim.width, dim.height);

private static void translate(Graphics2D g, Dimension dim, double radians) {
    if (radians > Math.toRadians(360)) {
        radians %= Math.toRadians(360);
    }
    
    int xOffsetX = 0;
    int xOffsetY = 0;
    int yOffsetX = 0;
    int yOffsetY = 0;
    if (radians > 0 && radians <= Math.toRadians(90)) {
        xOffsetY -= dim.getHeight();
    } else if (radians > Math.toRadians(90) && radians <= Math.toRadians(180)) {
        xOffsetX -= dim.getWidth();
        xOffsetY -= dim.getHeight();
        yOffsetY -= dim.getHeight();
    } else if (radians > Math.toRadians(180) && radians <= Math.toRadians(270)) {
        xOffsetX -= dim.getWidth();
        yOffsetX -= dim.getWidth();
        yOffsetY -= dim.getHeight();
    } else {
        yOffsetX -= dim.getWidth();
    }
    int x = rotateX(xOffsetX, xOffsetY, radians);
    int y = rotateY(yOffsetX, yOffsetY, radians);
    g.translate(x, y);
}

private static int rotateX(int x, int y, double radians) {
    if (x == 0 && y == 0) {
        return 0;
    }
    return (int) Math.round(x * Math.cos(radians) - y * Math.sin(radians));
}

private static int rotateY(int x, int y, double radians) {
    if (x == 0 && y == 0) {
        return 0;
    }
    return (int) Math.round(x * Math.sin(radians) + y * Math.cos(radians));
}

这适用于矩形,但不适用于其他类型的形状。我想弄清楚是否有一种方法可以针对每种类型的形状完成此操作。另请注意,该代码仅用于测试目的,其中有很多不良做法,例如多次调用 Math.toRadians。

最佳答案

是这样的吗?

enter image description here enter image description here enter image description here

可以先使用旋转变换来实现,然后以旋转形状的边界为基础,使用平移变换将其移回以满足最顶部的y和最左侧x 原始矩形的值。

请参阅 getImage() 方法以了解其一种实现方式。

int a = angleModel.getNumber().intValue();
AffineTransform rotateTransform = AffineTransform.getRotateInstance((a*2*Math.PI)/360d);
// rotate the original shape with no regard to the final bounds
Shape rotatedShape = rotateTransform.createTransformedShape(rectangle);
// get the bounds of the rotated shape
Rectangle2D rotatedRect = rotatedShape.getBounds2D();
// calculate the x,y offset needed to shift it to top/left bounds of original rectangle
double xOff = rectangle.getX()-rotatedRect.getX();
double yOff = rectangle.getY()-rotatedRect.getY();
AffineTransform translateTransform = AffineTransform.getTranslateInstance(xOff, yOff);
// shift the new shape to the top left of original rectangle
Shape rotateAndTranslateShape = translateTransform.createTransformedShape(rotatedShape);

完整的源代码如下:

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.EmptyBorder;

public class TransformedShape {

    private JComponent ui = null;
    JLabel output = new JLabel();
    JToolBar tools = new JToolBar("Tools");
    ChangeListener changeListener = (ChangeEvent e) -> {
        refresh();
    };
    int pad = 5;
    Rectangle2D.Double rectangle = new Rectangle2D.Double(pad,pad,200,100);
    SpinnerNumberModel angleModel = new SpinnerNumberModel(30, 0, 90, 1);

    public TransformedShape() {
        initUI();
    }

    private BufferedImage getImage() {
        int a = angleModel.getNumber().intValue();
        AffineTransform rotateTransform = AffineTransform.getRotateInstance((a*2*Math.PI)/360d);
        Shape rotatedShape = rotateTransform.createTransformedShape(rectangle);
        Rectangle2D rotatedRect = rotatedShape.getBounds2D();
        double xOff = rectangle.getX()-rotatedRect.getX();
        double yOff = rectangle.getY()-rotatedRect.getY();
        AffineTransform translateTransform = AffineTransform.getTranslateInstance(xOff, yOff);
        Shape rotateAndTranslateShape = translateTransform.createTransformedShape(rotatedShape);
        Area combinedShape = new Area(rotateAndTranslateShape);
        combinedShape.add(new Area(rectangle));
        Rectangle2D r = combinedShape.getBounds2D();
        BufferedImage bi = new BufferedImage((int)(r.getWidth()+(2*pad)), (int)(r.getHeight()+(2*pad)), BufferedImage.TYPE_INT_ARGB);

        Graphics2D g = bi.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        g.setColor(new Color(255,0,0,127));
        g.fill(rectangle);
        
        g.setColor(new Color(0,0,255,127));
        g.fill(rotateAndTranslateShape);
        
        g.dispose();
        
        return bi;
    }

    private void addModelToToolbar(String label, SpinnerNumberModel model) {
        tools.add(new JLabel(label));
        JSpinner spinner = new JSpinner(model);
        spinner.addChangeListener(changeListener);
        tools.add(spinner);
    }

    public final void initUI() {
        if (ui!=null) return;

        ui = new JPanel(new BorderLayout(4,4));
        ui.setBorder(new EmptyBorder(4,4,4,4));
        
        ui.add(output);
        
        ui.add(tools,BorderLayout.PAGE_START);

        addModelToToolbar("Angle", angleModel);
              
        refresh();
    }
    
    private void refresh() {
        output.setIcon(new ImageIcon(getImage()));
    }
    
    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            TransformedShape o = new TransformedShape();
            
            JFrame f = new JFrame(o.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);
            
            f.setContentPane(o.getUI());
            f.pack();
            f.setMinimumSize(f.getSize());
            
            f.setVisible(true);
        };
        SwingUtilities.invokeLater(r);
    }
}

关于java - 旋转形状并在原始位置绘制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67309013/

相关文章:

java - 在哪些领域使用 OSGI 有意义?

java - 主题切换后 Intellij 插件 JBTabbedPane UI 被替换

json - THREE.js JSONLoader回调

c# - Mongodb:如何检查一个点是否包含在多边形中?

algorithm - 修改 Delaunay 三角剖分的有效方法

java - EMV - SELECT 未获取 PDOL

java - 在 swing 应用程序中使用多种语言

java - Java中交替显示2个字符串

java - 如何验证 JTextField?

java - 如何使用JFilechooser和Jlabel查看图片