【问题标题】:How to rotate an object around another moving object in java?如何在java中围绕另一个移动对象旋转一个对象?
【发布时间】:2018-04-12 02:42:56
【问题描述】:

我是 Java 的新手,想编写一个简单的太阳系统,其中月亮围绕地球旋转,地球围绕太阳旋转。 一切都很好,除了月亮不想正确移动:/ 因为地球偏离了月球的初始位置,所以月球的自转半径会随着该距离而增长。再一次,当地球接近月球惯性位置时,自转半径减小。 如果初始位置是(0;0),它可以工作,但月亮撞到太阳......

那么我怎样才能保持地球和月球之间的距离不变呢? 我正在使用 AffineTransforms,这是我的代码的 sn-p ;)

提前致谢!

Ellipse2D.Double MoonFrame = new Ellipse2D.Double(orbitEarth + orbitMoon - radiusMoon, -radiusMoon, radiusMoon*2, radiusMoon*2);

for (int i = 0; i < 360; i++)
  {
    theta += Math.PI/30;
    AffineTransform TransformMoon = AffineTransform.getRotateInstance(theta,TransformEarth.getTranslateX(),TransformEarth.getTranslateY());

    g2d.fill(TransformMond.createTransformedShape(MoonFrame));
  }

【问题讨论】:

  • 好吧,this is one idea
  • 你的基本问题是这个。 “给定一个围绕另一个对象的圆,如何根据与中心的给定角度在该圆上找到一个点?”现在,如果你能回答这个问题(在圆圈上找到点),那么你就有了问题的答案,尽管是在基本层面上。其余的都是微不足道的
  • 这是一个特别的 Swing 问题吗?

标签: java rotation affinetransform


【解决方案1】:

所以,你的基本问题归结为“我如何在圆上找到一个给定角度的点” ...说真的,就是这么简单

基于数小时的谷歌搜索和反复试验,我基本上或多或少地使用了以下内容。

protected Point pointOnCircle() {

    double rads = Math.toRadians(orbitAngle - 180); // Make 0 point out to the right...
    int fullLength = Math.round((outterRadius));

    // Calculate the outter point of the line
    int xPosy = Math.round((float) (Math.cos(rads) * fullLength));
    int yPosy = Math.round((float) (Math.sin(rads) * fullLength));

    return new Point(xPosy, yPosy);
}

其余的基本上归结为正确处理转换的复合性质,

基本上,这需要一个基础 Graphics 上下文,将平移应用到它(地球的位置)并创建另外两个上下文以应用额外的变换,一个用于地球,一个用于月球......

Graphics2D g2d = (Graphics2D) g.create();
int yPos = (getHeight() - size) / 2;
// Transform the offset
g2d.transform(AffineTransform.getTranslateInstance(xPos, yPos));

Graphics2D earthG = (Graphics2D) g2d.create();
// Rotate around the 0x0 point, this becomes the center point
earthG.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
// Draw the "earth" around the center point
earthG.drawRect(-(size / 2), -(size / 2), size, size);
earthG.dispose();

// Removes the last transformation
Graphics2D moonG = (Graphics2D) g2d.create();            
// Calclate the point on the circle - based on the outterRadius or
// distance from the center point of the earth
Point poc = pointOnCircle();
int moonSize = size / 2;
// This is only a visial guide used to show the position of the earth
//moonG.drawOval(-outterRadius, -outterRadius, outterRadius * 2, outterRadius * 2);
moonG.fillOval(poc.x - (moonSize / 2), poc.y - (moonSize / 2), moonSize, moonSize);
moonG.dispose();

g2d.dispose();

因为我知道这会让你摸不着头脑,所以一个可运行的例子......

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.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 double angle;
        private double orbitAngle;
        private int xPos = 0;
        private int size = 20;
        private int outterRadius = size * 2;
        private int delta = 2;

        public TestPane() {
            new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    xPos += delta;
                    if (xPos + size >= getWidth()) {
                        xPos = getWidth() - size;
                        delta *= -1;
                    } else if (xPos < 0) {
                        xPos = 0;
                        delta *= -1;
                    }
                    angle += 4;
                    orbitAngle -= 2;
                    repaint();
                }
            }).start();
        }

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

        protected Point pointOnCircle() {

            double rads = Math.toRadians(orbitAngle - 180); // Make 0 point out to the right...
            int fullLength = Math.round((outterRadius));

            // Calculate the outter point of the line
            int xPosy = Math.round((float) (Math.cos(rads) * fullLength));
            int yPosy = Math.round((float) (Math.sin(rads) * fullLength));

            return new Point(xPosy, yPosy);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int yPos = (getHeight() - size) / 2;
            // Transform the offset
            g2d.transform(AffineTransform.getTranslateInstance(xPos, yPos));

            Graphics2D earthG = (Graphics2D) g2d.create();
            // Rotate around the 0x0 point, this becomes the center point
            earthG.transform(AffineTransform.getRotateInstance(Math.toRadians(angle)));
            // Draw the "earth" around the center point
            earthG.drawRect(-(size / 2), -(size / 2), size, size);
            earthG.dispose();

            // Removes the last transformation
            Graphics2D moonG = (Graphics2D) g2d.create();            
            // Calclate the point on the circle - based on the outterRadius or
            // distance from the center point of the earth
            Point poc = pointOnCircle();
            int moonSize = size / 2;
            // This is only a visial guide used to show the position of the earth
            //moonG.drawOval(-outterRadius, -outterRadius, outterRadius * 2, outterRadius * 2);
            moonG.fillOval(poc.x - (moonSize / 2), poc.y - (moonSize / 2), moonSize, moonSize);
            moonG.dispose();

            g2d.dispose();
        }

    }

}

这会移动一个“地球”物体,该物体沿一个方向旋转,然后围绕它的月亮沿相反方向旋转

【讨论】:

  • 非常感谢。你的例子很有帮助。这样,很容易。
【解决方案2】:

您可以通过连接变换来简化数学运算。从最后一个转换到第一个转换,或使用preConcatenate 以更自然的顺序构建它们。

从简单变换组合复杂变换,例如通过从平移和旋转构建轨道变换:

// Earth transform.
// Set the orbital radius to 1/3rd the panel width
AffineTransform earthTx = AffineTransform.getTranslateInstance(getWidth() / 3, 0);
// Rotate
earthTx.preConcatenate(AffineTransform.getRotateInstance(angle));

然后可以在早期结果的基础上构建后期变换(例如绕地球运行的月球):

// Moon transform.
// Set the orbital radius to 1/10th the panel width
AffineTransform moonTx = AffineTransform.getTranslateInstance(getWidth() / 10, 0);
// Rotate
moonTx.preConcatenate(AffineTransform.getRotateInstance(angle));
// Add the earth transform 
moonTx.preConcatenate(earthTx);

完整示例:

public class Orbit {

    public static class OrbitPanel extends JComponent {
        int width;
        int height;

        public OrbitPanel(int width, int height) {
            this.width = width;
            this.height = height;
        }

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

        @Override
        public void paint(Graphics g) {
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // Clear the background.
            g2.setColor(getBackground());
            g2.fillRect(0, 0, getWidth(), getHeight());

            // Sun transform. Just centre it in the window.
            AffineTransform sunTx = AffineTransform.getTranslateInstance(getWidth() / 2, getHeight() / 2);

            // Draw the sun
            g2.setTransform(sunTx);
            drawBody(g2, 30, Color.YELLOW);

            // Orbital period.
            // One rotation every 10s.
            double percentRotation = System.currentTimeMillis() % 10000 / 10000.0;
            // To radians.
            double angle = Math.PI * 2 * percentRotation;

            // Earth transform.
            // Set the orbital radius to 1/3rd the panel width
            AffineTransform earthTx = AffineTransform.getTranslateInstance(getWidth() / 3, 0);
            // Rotate
            earthTx.preConcatenate(AffineTransform.getRotateInstance(angle));
            // Add the sun transform
            earthTx.preConcatenate(sunTx);

            // Draw the earth
            g2.setTransform(earthTx);
            drawBody(g2, 10, Color.BLUE);

            // Moon transform.
            // Set the orbital radius to 1/10th the panel width
            AffineTransform moonTx = AffineTransform.getTranslateInstance(getWidth() / 10, 0);
            // Rotate
            moonTx.preConcatenate(AffineTransform.getRotateInstance(angle));
            // Add the earth transform (already includes the sun transform)
            moonTx.preConcatenate(earthTx);

            // Draw the moon
            g2.setTransform(moonTx);
            drawBody(g2, 5, Color.DARK_GRAY);
        }

        private void drawBody(Graphics2D g2, int size, Color color) {
            g2.setColor(color);
            g2.fillOval(-size / 2, -size / 2, size, size);
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        JFrame frame = new JFrame("Orbit");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JComponent orbitPanel = new OrbitPanel(250, 250);
        frame.add(orbitPanel);
        frame.pack();
        frame.setVisible(true);

        while (true) {
            Thread.sleep(20);
            orbitPanel.repaint();
        }
    }
}

【讨论】:

  • 这很有帮助。非常感谢!
猜你喜欢
  • 2013-05-21
  • 2016-12-14
  • 2018-04-24
  • 1970-01-01
  • 2018-11-04
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多