用Java模拟行星的运动

        这段时间都在寝室里自学Java,就想自己写个小程序玩一玩。同时,我也是个三体迷,就想着能不能用学的Java来模拟一下三体运动。这个程序算是我正式写模拟三体运动前的一个尝试。

一、程序分析

         首先来百度一番查一下太阳、水星、金星和地球的各种参数(非精确):

         1.太阳:

                    质量:2.0\times 10^{30}kg

          2.水星:

                     质量:3.3\times 10^{23}kg

                     轨道半径:5.9\times10^{10}m

                     公转速度:4.8\times10^{4}m/s

           3.金星

                     质量:4.9\times10^{24}kg

                     轨道半径:1.1\times10^{11}m

                     公转速度:3.5\times10^{4}m/s

             4.地球

                     质量:6\times10^{24}kg

                     轨道半径:1.5\times10^{11}m

                     公转速度:3.0\times10^{4}m/s

      模拟的方式,我采用了万有引力公式和牛顿运动定律的微分形式来模拟。这种方法误差和计算量都比较大,但对这种粗略的模拟,还是可以的。首先用万有引力公式计算出各个行星受到的太阳引力(行星之间的引力就忽略不计了,没必要,当然加上也是可以的),进而计算出每个行星的加速度。用一个变量time来表示时间微元,用每个行星当前的速度vector乘以time就得到行星位移的微元,然后再将行星速度vector更新为vector+行星的加速度乘以时间,再将行星的位置画出来。将这些过程写在一个循环体里,就可宜不断更新行星的位置了。

       这里面用到的vector,加速度等都是向量,Java并没有处理向量运算的类,需要自己写一个自定义类Vector2D。每个行星也都定义为自定义类Actor类的子类。绘制行星等在Univers类中。程序入口为Main类。

        包结构

  1. main包:Main类
  2. vector2D包:Vector2D类
  3. actor包:Actor类       
  4. univers包:Univers类                                 

 二、代码编写

        1.Vector2D类

package Vector2D;
import java.awt.Point;

public class Vector2D {
	public static Vector2D baseX = new Vector2D(1, 0);    //x方向的单位向量
	public static Vector2D baseY = new Vector2D(0, 1);    //y方向的单位向量
	private double x;			//向量的x坐标
	private double y;			//向量的y坐标
	private double model;		//向量的模
	private float theta;		//向量的辐角
	
	public Vector2D(double x,double y) {
		this.x = x;
		this.y = y;
		this.model = Math.sqrt(this.x*this.x+this.y*this.y);
		this.theta = (float) Math.atan(y/x);
	}
	
	
	public Vector2D(Point p1,Point p2) {
		x = p2.getX() - p1.getX();		
		y = p2.getY() - p1.getY();
		model = Math.sqrt(x*x+y*y);
		theta = (float) Math.atan(y/x);
	}

	public double getX() {
		return x;
	}
	
	public double getY() {
		return y;
	}
	
	public double getModel() {
		return model;
	}
	
	public double getTheta() {
		return theta;
	}
	
	//向量加法
	public Vector2D plus(Vector2D vector2D_2) {
		return new Vector2D(x+vector2D_2.getX(), 
				y+vector2D_2.getY());
	}
	//向量减法
	public Vector2D sub(Vector2D vector2D_2) {
		return new Vector2D(x-vector2D_2.getX(),
				y-vector2D_2.getY());
	}
	//求相反向量
	public Vector2D inverse() {
		return new Vector2D(-x,-y);
	}
	//数乘
	public Vector2D multi(double r) {
		return new Vector2D(r*x, r*y);
	}
	
	//向量点积
	public double dot(Vector2D vector2D) {
		return vector2D.x*this.x+vector2D.y*this.y;
	}
	//获得单位化向量
	public Vector2D normal() {
		return new Vector2D(x/model, 
				y/model);
	}

	//求垂直向量
	public Vector2D perp() {
		return new Vector2D(-y,x);
	}
	
    //向量旋转
	public Vector2D roatation(double theta) {
		double temp = x*Math.cos(theta)-y*Math.sin(theta);
		double newY = x*Math.sin(theta)+y*Math.cos(theta);
		return new Vector2D(temp, newY);
	}
	
	public String toString() {
		return String.format("("+x+","+y+")");
	}
}

        2.Actor类

package actor;

import java.awt.*;
import Vector2D.Vector2D;

public class Actor {
	public double mass;                //质量
	public Point position;             //点位置
	public Vector2D acceleration;       //加速度
	public Vector2D vector;               //速度
	public Vector2D displacement;        //位移
	public Vector2D force;                //受力
	
	public Actor(double mass,Point position) {
		this.mass = mass;
		this.position = position;
	}
	
	public void drawActor(Graphics g,int height,int width) {
		g.fillOval(position.x-width/2, position.y-height/2,height, width);
	}
}

3.Univers类

package univers;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.datatransfer.SystemFlavorMap;
import javax.swing.JPanel;
import Vector2D.Vector2D;
import actor.Actor;

public class Univers extends JPanel implements Runnable{
	private static double G = 6.67E-11;                        //万有引力常数
	private Point[] star = new Point[500];                     //背景的星星
	private Point origSun = new Point(319,239);                //太阳的位置
	private Point origEarth = new Point(469,239);              //地球的初始位置
	private Point origVenus = new Point(429,239);              //金星的初始位置
	private Point origMercury = new Point(378,239);            //水星的初始位置
	private Actor sun = new Actor(2E30,origSun);               //太阳
	private Actor earth = new Actor(6E24,origEarth);           //地球
	private Actor venus = new Actor(4.9E24, origVenus);        //金星
	private Actor mercury = new Actor(3.3E23, origMercury);    //水星
	private Vector2D earthPosition = new Vector2D(origSun,origEarth);     //地球的位置向量
	private	Vector2D venusPosition = new Vector2D(origSun, origVenus);    //金星的位置向量
	private	Vector2D mercuryPosition = new Vector2D(origSun, origMercury);//水星的位置向量        
	private Vector2D vectorEarth = new Vector2D(0, 3E4);        //地球当前速度
	private Vector2D vectorVenus = new Vector2D(0, -3.5E4);     //金星当前速度
	private Vector2D vectorMercury = new Vector2D(0,4.8E4);     //水星当前速度
	private long time = 1;

	public Univers2() {
		for(int i=0;i<500;i++) {
			int x=(int) (Math.random()*640);
			int y=(int) (Math.random()*480);
			star[i] = new Point(x,y);
		}
	}
	
	private void calculate() {
		mercuryCalculate();
		venusCalculate();
		earthCalculate();
	}
	
    //地球轨道的计算
	private void earthCalculate() {
		Vector2D delta_displacement = vectorEarth.multi(time*1e-9); //乘1e9是对长度缩放
		earthPosition = earthPosition.plus(delta_displacement);
		double current_acceleration = G*2.0e30/(earthPosition.getModel()*earthPosition.getModel()*1e18);
		earth.acceleration = earthPosition.normal().multi(-current_acceleration);
		vectorEarth = vectorEarth.plus(earth.acceleration.multi(time));
	}
	
    //金星轨道的计算
	private void venusCalculate() {
		Vector2D delta_displacement = vectorVenus.multi(time*1e-9); //乘1e9是对长度缩放
		venusPosition = venusPosition.plus(delta_displacement);
		double current_acceleration = G*2.0e30/(venusPosition.getModel()*venusPosition.getModel()*1e18);
		venus.acceleration = venusPosition.normal().multi(-current_acceleration);
		vectorVenus = vectorVenus.plus(venus.acceleration.multi(time));
	}
	//水星轨道的计算
	private void mercuryCalculate() {
		Vector2D delta_displacement = vectorMercury.multi(time*1e-9); //乘1e9是对长度缩放
		mercuryPosition = mercuryPosition.plus(delta_displacement);
		double current_acceleration = G*2.0e30/(mercuryPosition.getModel()*mercuryPosition.getModel()*1e18);
		mercury.acceleration = mercuryPosition.normal().multi(-current_acceleration);
		vectorMercury = vectorMercury.plus(mercury.acceleration.multi(time));
	}
	//绘制所有行星
	@Override
	public void paint(Graphics g) {
		// TODO 自动生成的方法存根
		super.paint(g);
		for(int i=0;i<500;i++) {                //让背景闪烁
            g.setColor(Color.white);
            if(Math.random()>0.5) {
				g.setColor(Color.gray);
			}
			g.fillOval(star[i].x,star[i].y,2,2);
		}
		g.setColor(Color.red);
		sun.drawActor(g,30,30);
		g.setColor(Color.gray);
		g.fillOval((int)(origSun.x+mercuryPosition.getX()-1),(int)(origSun.y-mercuryPosition.getY()-1), 6, 6);
		g.setColor(Color.yellow);
		g.fillOval((int)(origSun.x+venusPosition.getX()-1),(int)(origSun.y-venusPosition.getY()-1), 6,6);
		g.setColor(Color.blue);
		g.fillOval((int)(origSun.x+earthPosition.getX()-1), (int)(origSun.y-earthPosition.getY()-1),6, 6);

	}
	
	@Override
	public void run() {
		// TODO 自动生成的方法存根
		setBackground(Color.black);
		while(true) {
			repaint();
			calculate();
			time += 100;        //数字可以随便填
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			
		}
	}
}

        4.Main类

package main;

import java.awt.Container;
import javax.swing.JFrame;
import univers.Univers;
import univers.Univers;

public class Main extends JFrame{
	private Univers univers = new Univers();
	private Container container = getContentPane();
	private Thread renderThread = new Thread(univers);
	
	public Main() {
		setTitle("行星运动");
		setSize(640,480);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		container.add(univers);
		setVisible(true);
		renderThread.start();
	}
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		new Main();
	}

}

三、运行结果

灰色的为水星,黄色的为金星,蓝色的为地球,红色是太阳。

        

下篇文章来写三体运动的模拟。自学Java会遇到很多问题,如有问题还请多多指正。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BD8DDI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值