gpt4 book ai didi

java - Swing平移刻度更改顺序错位

转载 作者:太空宇宙 更新时间:2023-11-04 10:39:28 25 4
gpt4 key购买 nike

当使用 Java Swing 将平移操作围绕缩放操作进行拆分时,我发现了一些奇怪的情况。也许我做了一些愚蠢的事情,但我不确定在哪里。

在第一个版本中,我将图像居中,缩放,然后将其平移到所需的位置。在第二个版本中,我直接缩放图像,然后平移到所需的位置,以补偿非居中图像。这两个解决方案应该是等效的。另外,当考虑围绕一个点的旋转和另一个点的运动时,这一点也很重要。我的代码也可以做到这一点...但为什么这不起作用?

这是代码的两个版本。他们应该做完全相同的事情,但他们没有。以下是截图:

首先产生:screenshot1

第二个产品:screenshot2

我认为draw1中围绕缩放操作的两个平移操作应该等同于draw2中的缩放平移操作。

有什么建议吗?

MCVE:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.net.URL;

public class Asteroid extends JComponent implements ActionListener {

public static final Dimension FRAME_SIZE = new Dimension(640, 480);
public double x = 200;
public double y = 200;
public int radius = 40;
private AffineTransform bgTransfo;
private final BufferedImage im2;
private JCheckBox draw1Check = new JCheckBox("Draw 1", true);

Asteroid() {
BufferedImage img = null;
try {
img = ImageIO.read(new URL("/image/CWJdo.png"));
} catch (Exception e) {
e.printStackTrace();
}
im2 = img;
initUI();
}

private final void initUI() {
draw1Check.addActionListener(this);
JFrame frame = new JFrame("FrameDemo");
frame.add(BorderLayout.CENTER, this);
frame.add(BorderLayout.PAGE_START, draw1Check);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
}

public static void main(String[] args) {
Asteroid asteroid = new Asteroid();
}

@Override
public Dimension getPreferredSize() {
return FRAME_SIZE;
}

@Override
public void paintComponent(Graphics g0) {
Graphics2D g = (Graphics2D) g0;
g.setColor(Color.white);
g.fillRect(0, 0, 640, 480);
if (draw1Check.isSelected()) {
draw1(g);
} else {
draw2(g);
}
}

public void draw1(Graphics2D g) {//Draw method - draws asteroid
double imWidth = im2.getWidth();
double imHeight = im2.getHeight();
double stretchx = (2.0 * radius) / imWidth;
double stretchy = (2.0 * radius) / imHeight;

bgTransfo = new AffineTransform();
//centering
bgTransfo.translate(-imWidth / 2.0, -imHeight / 2.0);
//scaling
bgTransfo.scale(stretchx, stretchy);
//translation
bgTransfo.translate(x / stretchx, y / stretchy);

//draw correct position
g.setColor(Color.CYAN);
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius), (int) (2 * radius));

//draw sprite
g.drawImage(im2, bgTransfo, this);
}

public void draw2(Graphics2D g) {//Draw method - draws asteroid
double imWidth = im2.getWidth();
double imHeight = im2.getHeight();
double stretchx = (2.0 * radius) / imWidth;
double stretchy = (2.0 * radius) / imHeight;

bgTransfo = new AffineTransform();

//scale
bgTransfo.scale(stretchx, stretchy);

//translate and center
bgTransfo.translate((x - radius) / stretchx, (y - radius) / stretchy);

//draw correct position
g.setColor(Color.CYAN);
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius), (int) (2 * radius));

//draw sprite
g.drawImage(im2, bgTransfo, this);
}

@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
}

最佳答案

不确定这个问题是否仍然存在。无论如何,这是我的答案。

我认为理解这种行为的关键部分是 AffineTransform.concatenate 之间的区别和 AffineTransform.preConcatenate方法。问题是,最终的转换取决于应用子转换的顺序。引用 concatenate JavaDoc

Concatenates an AffineTransform Tx to this AffineTransform Cx in the most commonly useful way to provide a new user space that is mapped to the former user space by Tx. Cx is updated to perform the combined transformation. Transforming a point p by the updated transform Cx' is equivalent to first transforming p by Tx and then transforming the result by the original transform Cx like this: Cx'(p) = Cx(Tx(p))

将此与 preConcatenate 进行比较:

Concatenates an AffineTransform Tx to this AffineTransform Cx in a less commonly used way such that Tx modifies the coordinate transformation relative to the absolute pixel space rather than relative to the existing user space. Cx is updated to perform the combined transformation. Transforming a point p by the updated transform Cx' is equivalent to first transforming p by the original transform Cx and then transforming the result by Tx like this: Cx'(p) = Tx(Cx(p))

scaletranslate方法可以有效地连接。让我们在 draw1 方法中调用 3 个转换:C(中心)、S(缩放)和 T(平移)。所以你的复合变换实际上是C(S(T(p)))。特别是,这意味着 S 应用于 T 而不是应用于 C,因此您的 C 并未真正使图像居中。一个简单的修复方法是更改​​ SC 的顺序,但我认为更合适的修复方法是这样的:

public void draw3(Graphics2D g) {
//Draw method - draws asteroid
double imWidth = im2.getWidth();
double imHeight = im2.getHeight();
double stretchx = (2.0 * radius) / imWidth;
double stretchy = (2.0 * radius) / imHeight;

AffineTransform bgTransfo = new AffineTransform();

//translation
bgTransfo.translate(x, y);

//scaling
bgTransfo.scale(stretchx, stretchy);

//centering
bgTransfo.translate(-imWidth / 2.0, -imHeight / 2.0);

//draw correct position
g.setColor(Color.CYAN);
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius), (int) (2 * radius));

//draw sprite
g.drawImage(im2, bgTransfo, this);
}

我认为这种方法的一大优点是您不必使用stretchx/stretchy重新计算T

关于java - Swing平移刻度更改顺序错位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49156875/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com