Java AffineTransform:从中心缩放形状
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/690871/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AffineTransform: scaling a Shape from its center
提问by Pierre
I'm trying to scale a rectangle from its center using AffineTransform. I'm sure the solution is obvious but I cannot make it work ! Here is what I've tested so far...
我正在尝试使用 AffineTransform 从其中心缩放一个矩形。我确信解决方案是显而易见的,但我无法让它发挥作用!这是我迄今为止测试过的......
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Test extends JPanel {
Test()
{
super(null);
setOpaque(true);
setBackground(Color.WHITE);
setPreferredSize(new Dimension(200,200));
}
@Override
protected void paintComponent(Graphics g1) {
super.paintComponent(g1);
Rectangle r= new Rectangle(5,5,getWidth()-10,getHeight()-10);
double cx= r.getCenterX();
double cy= r.getCenterY();
Graphics2D g=(Graphics2D)g1;
g.setColor(Color.BLACK);
AffineTransform old= g.getTransform();
for(double zoom=0.9; zoom>=0.5; zoom-=0.1)
{
AffineTransform tr2= new AffineTransform(old);
tr2.translate(-cx, -cy);
tr2.scale(zoom, zoom);
tr2.translate(cx/zoom,cy/zoom);
g.setTransform(tr2);
g.draw(r);
g.setTransform(old);
}
}
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, new Test());
}
}
But it doesn't work.... Any suggestion ?
但它不起作用....有什么建议吗?
采纳答案by Welbog
I see what you mean when you're dealing with rectangles. The reason is because the initial calculation for the translation didn't take into account the size of the container object.
当你处理矩形时,我明白你的意思。原因是翻译的初始计算没有考虑容器对象的大小。
Use this instead:
改用这个:
tr2.translate(
(this.getWidth()/2) - (r.getWidth()*(zoom))/2,
(this.getHeight()/2) - (r.getHeight()*(zoom))/2
);
tr2.scale(zoom,zoom);
g.setTransform(tr2);
What this is doing is translating the rectangle to the center of the panel before scaling it. In my tests it works just fine.
这样做是在缩放之前将矩形平移到面板的中心。在我的测试中它工作得很好。
回答by Welbog
Assuming scaling fixes the location of the top lefthand corner of the rectangle (which I think is right but it's been a long time since I've done graphics in Java), you need to translate the rectangle in the direction opposite to the scaling.
假设缩放修复了矩形左上角的位置(我认为这是正确的,但自从我用 Java 完成图形以来已经很长时间了),您需要在与缩放相反的方向上平移矩形。
tr2.translate(
r.getWidth()*(1-zoom)/2,
r.getHeight()*(1-zoom)/2
);
tr2.scale(zoom,zoom);
g.setTransform(tr2);
So you move the rectangle left and up half of the change in width and height.
因此,您将矩形向左移动,向上移动宽度和高度变化的一半。
回答by paulmurray
This involves a process called conjugating a transform.
这涉及称为共轭变换的过程。
If S is the scaling you want to do, and T is the transformation that takes point (0,0) to the point that is to be the center of your scaling, then the transform that does the job is
如果 S 是您想要做的缩放,而 T 是将点 (0,0) 带到要成为缩放中心的点的变换,那么完成这项工作的变换是
T(S(inverse(T)))
T(S(逆(T)))
回答by Pierre
(Later) Here is a solution working without any prior knowledge of the Dimension of the panel.
(稍后)这是一个解决方案,无需任何面板尺寸的先验知识。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Test extends JPanel
{
private static final long serialVersionUID = 1L;
private Test()
{
super(null);
setOpaque(true);
setBackground(Color.WHITE);
setPreferredSize(new Dimension(600,600));
}
@Override
protected void paintComponent(Graphics g1) {
super.paintComponent(g1);
Shape r= new Ellipse2D.Double(5,380,400,200);
double cx= r.getBounds2D().getCenterX();
double cy= r.getBounds2D().getCenterY();
Graphics2D g=(Graphics2D)g1;
g.setColor(Color.BLACK);
AffineTransform old= g.getTransform();
g.drawLine((int)cx-10, (int)cy, (int)cx+10, (int)cy);
g.drawLine((int)cx, (int)cy-10, (int)cx, (int)cy+10);
for(double zoom=1; zoom>=0.1; zoom-=0.1)
{
AffineTransform tr2 =AffineTransform.getTranslateInstance(-cx, -cy);
AffineTransform tr= AffineTransform.getScaleInstance(zoom,zoom);
tr.concatenate(tr2); tr2=tr;
tr =AffineTransform.getTranslateInstance(cx, cy);
tr.concatenate(tr2); tr2=tr;
tr= new AffineTransform(old);
tr.concatenate(tr2); tr2=tr;
g.setTransform(tr2);
g.draw(r);
g.setTransform(old);
}
}
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, new Test());
}
}
回答by Martin Erlic
I was just working on a desktop application to crop Brittney Spear's face (D.A.Y.) The cropping rectangle had to scale around its center point:
我只是在使用桌面应用程序来裁剪 Brittney Spear 的脸 (DAY) 裁剪矩形必须围绕其中心点缩放:
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
class ResizableRectangle extends Rectangle {
ResizableRectangle(double x, double y, double width, double height, Group group) {
super(x, y, width, height);
// Set scroll listener for crop selection
group.addEventHandler(ScrollEvent.SCROLL, event -> {
double zoomFactor = 1.10;
double deltaY = event.getDeltaY();
if (deltaY > 0) {
zoomFactor = 2.0 - zoomFactor;
}
super.setX(getX() + (super.getWidth() * (1 - zoomFactor) / 2)); // Set new X position
super.setWidth(getWidth() * zoomFactor); // Set new Width
super.setY(getY() + (super.getHeight() * (1 - zoomFactor) / 2)); // Set new Y position
super.setHeight(getHeight() * zoomFactor); // Set new Height
event.consume();
});
});
}
In general, the algorithm works like this:
一般来说,算法是这样工作的:
- Translate rectangle x-values with:
x + (width * (1 - zoomFactor) / 2)
- Translate y-values with:
y + (height * (1 - zoomFactor) / 2)
- Set new width to:
width * zoomFactor
- Set new height to:
height * zoomFactor
- 将矩形 x 值转换为:
x + (width * (1 - zoomFactor) / 2)
- 将 y 值转换为:
y + (height * (1 - zoomFactor) / 2)
- 将新宽度设置为:
width * zoomFactor
- 将新高度设置为:
height * zoomFactor