【问题标题】:AffineTransform: scaling a Shape from its centerAffineTransform:从中心缩放形状
【发布时间】:2010-10-16 00:10:50
【问题描述】:

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

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

【问题讨论】:

  • 我假设您正在尝试跟踪同心/内部矩形?

标签: java swing geometry shape affinetransform


【解决方案1】:

当您处理矩形时,我明白您的意思。原因是最初的翻译计算没有考虑容器对象的大小。

改用这个:

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

这样做是在缩放之前将矩形平移到面板的中心。在我的测试中,它工作得很好。

【讨论】:

    【解决方案2】:

    假设缩放固定矩形左上角的位置(我认为这是正确的,但自从我用 Java 完成图形以来已经很长时间了),您需要将矩形平移到与缩放。

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

    因此,您将矩形向左和向上移动宽度和高度变化的一半。

    【讨论】:

    • 你的解决方案不起作用,但它给了我一些新的想法,谢谢
    • @mmyers:你得到了什么结果?我在工作中无法访问 Java IDE,所以我无法自己测试它。我主要靠记忆工作。
    • @Welbog:在原始代码中,所有的正方形都起源于左上角。使用您的代码,它们会逐渐向中间移动,但还不够。
    • 啊,明白了。您所要做的就是在 translate() 之后移动 scale() ,它就可以完美地工作了。
    • 哎呀,对不起,我太快了。这个居中的正方形是最特殊的情况。当这是屏幕上任意位置的矩形时,您的解决方案不起作用。我再次尝试将形状从其中心、scake 和重新居中移动,但我仍然无法得到正确的解决方案......
    【解决方案3】:

    我正在开发一个桌面应用程序来裁剪 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

    【讨论】:

      【解决方案4】:

      这涉及一个称为共轭变换的过程。

      如果 S 是您想要进行的缩放,而 T 是将点 (0,0) 带到要成为缩放中心的点的变换,那么完成这项工作的变换是

      T(S(逆(T)))

      【讨论】:

        【解决方案5】:

        (稍后)这是一个无需事先了解面板尺寸的解决方案。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-24
          • 1970-01-01
          • 2018-07-08
          • 1970-01-01
          相关资源
          最近更新 更多