AffineTransform:从中心缩放形状

7

我正在尝试使用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());
        }
    }

但它不起作用.... 有什么建议吗?

我猜您是尝试追踪同心/内部矩形? - basszero
5个回答

8

我理解你在处理矩形时所说的意思。原因是最初计算平移的时候没有考虑到容器对象的大小。

请使用以下内容:

tr2.translate(
    (this.getWidth()/2) - (r.getWidth()*(zoom))/2,
    (this.getHeight()/2) - (r.getHeight()*(zoom))/2
);
tr2.scale(zoom,zoom);
g.setTransform(tr2);

这段代码的作用是将矩形平移至面板中心,然后再进行缩放。在我的测试中,它可以很好地工作。


7
假设缩放固定了矩形左上角的位置(我认为这是正确的,但我已经很久没有在Java中进行图形处理了),您需要将矩形朝相反方向平移以解决问题。
tr2.translate(
    r.getWidth()*(1-zoom)/2,
    r.getHeight()*(1-zoom)/2
);
tr2.scale(zoom,zoom);
g.setTransform(tr2);

所以你需要将矩形向左和向上移动宽度和高度变化的一半。


你的解决方案并不起作用,但它给了我一些新的想法,谢谢。 - Pierre
@mmyers:你得到了什么结果?我在工作中没有访问Java IDE,所以无法自行测试。我主要是依靠记忆工作的。 - Welbog
@Welbog:使用原始代码,所有正方形都起源于左上角。使用您的代码,它们逐渐向中间移动,但不够。 - Michael Myers
好的,明白了。你只需要在translate()之后移动scale(),它就可以完美地工作了。 - Michael Myers
抱歉,我太快了。这个居中的正方形是最特殊的情况。当它是屏幕上的任何矩形时,你的解决方案都不起作用。我再次尝试从中心移动形状,缩放和重新居中,但我仍然无法得到正确的解决方案... - Pierre

1

我刚刚在开发一个桌面应用程序,用于裁剪Brittney Spear的脸(D.A.Y.)。裁剪矩形必须围绕其中心点进行缩放:

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();
  });
 });
}

一般来说,该算法的工作原理如下:

  • 使用以下公式翻译矩形的 x 值:x + (width * (1 - zoomFactor) / 2)
  • 使用以下公式翻译矩形的 y 值:y + (height * (1 - zoomFactor) / 2)
  • 将新的宽度设置为:width * zoomFactor
  • 将新的高度设置为:height * zoomFactor

0

这涉及到一个叫做共轭变换的过程。

如果 S 是你想要进行的缩放,T 是将点 (0,0) 映射到将成为你缩放中心的点的变换,则完成该任务的变换是

T(S(inverse(T)))


0
(后来)这里有一个解决方案,可以在不需要面板尺寸的任何先前知识的情况下工作。
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());
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接