在 JPanel 中以笛卡尔坐标定义的中心形状

Center shape defined in Cartesian coordinates in JPanel

我有一个在笛卡尔坐标系中定义的形状(例如三角形),我想将该形状平移到 JPanel 的中心。我已经能够翻译 JPanel 的 0,0 方向,但我不知道如何根据 JPanel 的宽度和高度居中。我希望能够将边界矩形定义的任何形状居中。​​

int tPanelWidth = 200;
int tPanelHeight = 200;

// A triangle in lower right quadrant
Path2D tPath = new Path2D.Double();
tPath.moveTo(25,-25);
tPath.lineTo(50,-75);
tPath.lineTo(75,-25);
tPath.closePath();

// Determine translation distance to 0,0
double tX = Math.abs(Math.min(0,tPath.getBounds().getX()));
double tY = Math.abs(Math.min(0,tPath.getBounds().getY()));

AffineTransform tAt = new AffineTransform();
tAt.translate(tX,tY);
tPath.transform(tAt);

这使 JPanel 左上角的三角形倒置(不需要),有些符合预期。那么为了将三角形平移到中心,它应该在面板宽度和高度的一半左右?然后我将上面的更改为:

// tAt.translate(tX,tY);
tAt.translate(tX+(tPanelWidth/2),tY+(tPanelHeight/2));

现在三角形在JPanel的右下角,宽度和高度的一半太多了。然后我随机尝试 /4 并且它很接近,但不准确并且在数学上不正确或者至少没有意义。当 JPanel 不是方形时,它也不起作用。

那么,问题...

  • 有些坐标是负数(您已经补偿了那些)
  • 形状的原点不是 0x0,所以它是偏移量

所以,除了“负坐标”变换,你还需要应用“偏移”平移,这样形状的原点就变成了0x0,就像...

int midX = getWidth() / 2;
int midY = getHeight() / 2;

Rectangle pathBounds = tPath.getBounds();
// Because the x/y position may not be 0/0
int xDelta = pathBounds.x * -1;
int yDelta = pathBounds.y * -1;

int xPos = (midX - (pathBounds.width / 2)) + xDelta;
int yPos = (midY - (pathBounds.height / 2)) + yDelta;

可以产生类似...

(注意:我还渲染了形状的边界作为二次检查)

现在,显然,这只是专注于以形状边界为中心,您可能需要做一些额外的补偿,但这应该给您一个起点。

可运行示例...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public final class Main {
    public static void main(String[] args) {
        new Main();
    }

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Path2D tPath;

        public TestPane() {
            // A triangle in lower right quadrant
            tPath = new Path2D.Double();
            tPath.moveTo(25, -25);
            tPath.lineTo(50, -75);
            tPath.lineTo(75, -25);
            tPath.closePath();

            // Determine translation distance to 0,0
            double tX = Math.abs(Math.min(0, tPath.getBounds().getX()));
            double tY = Math.abs(Math.min(0, tPath.getBounds().getY()));

            AffineTransform tAt = new AffineTransform();
            tAt.translate(tX, tY);
            tPath.transform(tAt);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int midX = getWidth() / 2;
            int midY = getHeight() / 2;

            g2d.setColor(Color.RED);
            g2d.drawLine(0, midY, getWidth(), midY);
            g2d.drawLine(midX, 0, midX, getHeight());

            g2d.setColor(Color.BLACK);

            Rectangle pathBounds = tPath.getBounds();
            // Because the x/y position may not be 0/0
            int xDelta = pathBounds.x * -1;
            int yDelta = pathBounds.y * -1;

            int xPos = (midX - (pathBounds.width / 2)) + xDelta;
            int yPos = (midY - (pathBounds.height / 2)) + yDelta;

            g2d.translate(xPos, yPos);
            g2d.draw(tPath);
            g2d.draw(tPath.getBounds());
            g2d.dispose();
        }

    }
}

nb:我选择在绘画路径的上下文中修改形状,您可以将变换应用于形状本身,但这取决于您的要求,即:是否还有其他依赖是否在原始形状位置