【问题标题】:Java rotating a Polgon deforms itJava旋转多边形使其变形
【发布时间】:2021-12-18 21:35:56
【问题描述】:

我写了一个方法,它随机生成多边形形状,然后在屏幕上旋转和移动。由于我想检测与这些形状的碰撞,因此我没有使用 Graphics2D 旋转它们,而是使用 AffineTransform 旋转它们。但由于某种原因,某些形状会被旋转弄乱,而其他形状则不受影响。以下是导致问题的形状之一的示例。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

public class Test extends JLabel{

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    private static final long serialVersionUID = 1L;

    Polygon poly;

    Point center;
    Point source[];
    Point dest[];

    JFrame jf;

    public Test() {

        init();
        createPolygon();

        Timer timer = new Timer(20, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rotatePoly();
                repaint();
            }});
        timer.start();
    }
    public void rotatePoly() {

        AffineTransform transf = AffineTransform.getRotateInstance(Math.toRadians(2), center.x, center.y);
        transf.transform(source, 0, dest, 0, source.length);

        poly = toPolygon(dest);

    }
    public Polygon toPolygon(Point[] points) {

        Polygon polygon = new Polygon();

        for (int i = 0; i < points.length; i++) {
            polygon.addPoint(points[i].x, points[i].y);
        }
        return polygon;
    }
    public void createPolygon() {

        Point points[] = new Point[7];

        points[0] = new Point(20, 97);
        points[1] = new Point(82, 70);
        points[2] = new Point(134, 70);
        points[3] = new Point(210, 88);
        points[4] = new Point(210, 106);
        points[5] = new Point(144, 125);
        points[6] = new Point(82, 125);

        source = points;
        dest = points;

        poly = toPolygon(points);

        center = new Point(poly.getBounds().x + poly.getBounds().width / 2, poly.getBounds().y + poly.getBounds().height / 2);

    }
    public void init() {

        setVisible(true);
        setSize(260, 260);

        jf = new JFrame();
        jf.setVisible(true);
        jf.setSize(260, 260);
        jf.setContentPane(new JLabel());
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLocation((screenSize.width / 2) - (getWidth() / 2), (screenSize.height / 2) - (getHeight() / 2));
        jf.add(this);

    }
    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);

        g2d.drawPolygon(poly);

    }
}

如果用以下几行替换这些点,则形状基本保持不变。下面的形状当然是对称的,但是旋转方法确实适用于其他随机生成的不均匀形状。

points[0] = new Point(10, 130);
points[1] = new Point(100, 10);
points[2] = new Point(160, 10);
points[3] = new Point(250, 100);
points[4] = new Point(250, 160);
points[5] = new Point(160, 250);
points[6] = new Point(100, 250);

【问题讨论】:

  • createPolygon() 中,源和目标设置为同一个数组。 AffineTransform::transform 的文档指出“但是,如果一个操作的目标 Point2D 对象与源数组更下方的另一操作的源 Point2D 对象是相同的对象,则该点中的原始坐标在它们可以被覆盖之前被覆盖。转换。”
  • @DavidConrad 好的,但我该如何改变呢?我刚刚尝试在源和目标上使用 points.copy() ,但这并没有更好的效果。当我只将 source 的值设置为 points 并让 dest 成为它时,它会引发 NullPointerException,而当我只将 source 的值设置为 points 但这次 set dest = new Point[source.length] 它会引发 ArrayStoreException。跨度>
  • 对不起,我从答案中看出这显然不是问题。
  • 不要为自定义绘画扩展 JLabel。相反,您应该扩展 JPanel 或 JComponent。您要绘制的“形状”也应包含在 ArrayList 中。然后paintComponent() 方法将遍历ArrayList 以绘制每个Shape。有关此方法的简单示例,请参阅:stackoverflow.com/questions/67443343/drag-a-painted-shape。这也将使您的“命中检测”逻辑更容易。

标签: java swing rotation polygon affinetransform


【解决方案1】:

这适用于您的 AffineTransform。它返回转换后的形状,而不是修改坐标。我也推荐:

  • JFrame.setLocationRelativeTo(null); 用于屏幕居中。
  • 使用 RenderingHints 并启用抗锯齿功能来平滑图形。
  • 由于 Polygon 实现了 Shape,因此需要重新输入一些位置。
class Text extends JLabel{

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    private static final long serialVersionUID = 1L;

    Shape poly;

    Point center;
    Point source[];
    Point dest[];

    JFrame jf;

    public static void main(String[] args) {
        new Text();
    }
    public Text() {

        init();
        createPolygon();

        Timer timer = new Timer(20, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rotatePoly();
                repaint();
            }});
        timer.start();
    }
    public void rotatePoly() {

        AffineTransform transf = 
        AffineTransform.getRotateInstance(Math.toRadians(2), center.x, center.y);
        poly = transf.createTransformedShape(poly);

    }
    public Shape toPolygon(Point[] points) {

        Polygon polygon = new Polygon();

        for (int i = 0; i < points.length; i++) {
            polygon.addPoint(points[i].x, points[i].y);
        }
        return polygon;
    }
    public void createPolygon() {

        Point points[] = new Point[7];

        points[0] = new Point(20, 97);
        points[1] = new Point(82, 70);
        points[2] = new Point(134, 70);
        points[3] = new Point(210, 88);
        points[4] = new Point(210, 106);
        points[5] = new Point(144, 125);
        points[6] = new Point(82, 125);

        source = points;
        dest = points;

        poly = toPolygon(points);

        center = new Point(poly.getBounds().x + poly.getBounds().width / 2, poly.getBounds().y + poly.getBounds().height / 2);

    }
    public void init() {

        setVisible(true);
        setSize(260, 260);

        jf = new JFrame();
        jf.setVisible(true);
        jf.setSize(260, 260);
        jf.setContentPane(new JLabel());
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLocation((screenSize.width / 2) - (getWidth() / 2), (screenSize.height / 2) - (getHeight() / 2));
        jf.add(this);

    }
    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);

        g2d.draw(poly);

    }
}

【讨论】:

  • 哦,我知道如何旋转图形上下文。但是,正如我的问题中提到的,我想检测与 poligon 的碰撞。我可以为此使用一个矩形,但是对于某些形状来说这不是很准确。因此,我决定使用多边形,以便能够使用 Polygon 类的 intersects() 方法。
  • @mousekip 好的,我用一些建议更新了我的答案。
  • 啊,谢谢你完美的工作。
【解决方案2】:

这个问题主要是由多边形使用整数坐标引起的。
不是在多边形本身中累积旋转,而是使用一个变量来保存角度,并在每次改变角度时根据原始多边形计算一个新的多边形。原来的多边形没有改变。

我尽量保持原代码1

package cfh.test.sf;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;

public class PolygonTest extends JLabel{

    public static void main(String[] args) {
        new PolygonTest();
    }
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    private static final long serialVersionUID = 1L;

    Polygon poly;
    Shape rotated;
    Point center;
    int angle = 0;

    JFrame jf;

    public PolygonTest() {

        init();
        createPolygon();

        Timer timer = new Timer(20, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rotatePoly();
                repaint();
            }});
        timer.start();
    }
    public void rotatePoly() {
        angle += 2;
        AffineTransform transf = AffineTransform.getRotateInstance(Math.toRadians(angle), center.x, center.y);
        rotated = transf.createTransformedShape(poly);
    }
    public Polygon toPolygon(Point[] points) {

        Polygon polygon = new Polygon();

        for (int i = 0; i < points.length; i++) {
            polygon.addPoint(points[i].x, points[i].y);
        }
        return polygon;
    }
    public void createPolygon() {

        Point points[] = new Point[7];

        points[0] = new Point(20, 97);
        points[1] = new Point(82, 70);
        points[2] = new Point(134, 70);
        points[3] = new Point(210, 88);
        points[4] = new Point(210, 106);
        points[5] = new Point(144, 125);
        points[6] = new Point(82, 125);

        poly = toPolygon(points);
        rotated = poly;

        center = new Point(poly.getBounds().x + poly.getBounds().width / 2, poly.getBounds().y + poly.getBounds().height / 2);

    }
    public void init() {

        setVisible(true);
        setSize(260, 260);

        jf = new JFrame();
        jf.setVisible(true);
        jf.setSize(260, 260);
        jf.setContentPane(new JLabel());
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLocation((screenSize.width / 2) - (getWidth() / 2), (screenSize.height / 2) - (getHeight() / 2));
        jf.add(this);

    }
    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(Color.RED);

        g2d.draw(rotated);

    }
}

1 - 我宁愿在 paintComponent 内创建旋转的形状,而不是在字段中添加额外的形状。不确定这是否与程序的其余部分(例如计算交点)冲突


替代方案,未经测试:使用Point2D.FloatPoint2D.Double 代替Point 作为坐标。

【讨论】:

  • 是的,我明白了,使用这种方法,您永久性地损坏多边形的风险为零。但是,由于之前的解决方案完美运行,由于我自己的懒惰,我现在不会更改我的代码。同样是的,我确实需要形状来通过 Shape 类的 intersects() 方法检测碰撞。不过谢谢你的回答,下次我做类似的事情肯定会有所帮助。
猜你喜欢
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多