3 Commits

Author SHA1 Message Date
10eb2fbb0e Trying to make more efficient 2022-05-04 19:53:16 +02:00
bf9a6c6d43 Removed preCalc 2022-05-04 10:13:11 +02:00
1ab9c3650e Add .add() to Vector 2022-05-04 09:55:30 +02:00
4 changed files with 85 additions and 47 deletions

View File

@@ -4,7 +4,7 @@ import codedraw.CodeDraw;
* This class represents celestial bodies like stars, planets, asteroids, etc... * This class represents celestial bodies like stars, planets, asteroids, etc...
*/ */
public class Body { public class Body {
private final double mass; private double mass;
private Vector massCenter; // position of the mass center. private Vector massCenter; // position of the mass center.
private Vector currentMovement; private Vector currentMovement;
@@ -37,12 +37,14 @@ public class Body {
* Hint: see simulation loop in Simulation.java to find out how this is done. * Hint: see simulation loop in Simulation.java to find out how this is done.
*/ */
public Vector gravitationalForce(Body b) { public Vector gravitationalForce(Body b) {
Vector direction = b.massCenter.minus(massCenter); Vector direction = b.massCenter.minus(this.massCenter);
double distance = direction.length(); double distance = direction.length();
if (distance == 0) return new Vector(); if (distance == 0) return direction;
direction.normalize(); direction.normalize();
double force = Simulation.G * mass * b.mass / (distance * distance); double force = Simulation.G * this.mass * b.mass / (distance * distance);
return direction.times(force); direction.mul(force);
return direction;
} }
/** /**
@@ -83,6 +85,12 @@ public class Body {
return massCenter; return massCenter;
} }
public void update(Body b) {
double combinedMass = this.mass + b.mass;
this.massCenter = this.massCenter.times(this.mass / combinedMass).plus(b.massCenter.times(b.mass / combinedMass));
this.mass = combinedMass;
}
public boolean collidesWith(Body body) { public boolean collidesWith(Body body) {
return this.distanceTo(body) < this.radius() + body.radius(); return this.distanceTo(body) < this.radius() + body.radius();
} }

View File

@@ -36,12 +36,10 @@ public class Octree {
} }
} }
public void applyForces(Body[] bodies, double t) { public void applyForces(Body[] bodies, Vector[] forces, double t) {
if (root == null) return; if (root == null) return;
root.preCalc();
Vector[] forces = new Vector[bodies.length];
for (int i = 0; i < bodies.length; i++) { for (int i = 0; i < bodies.length; i++) {
forces[i] = root.getForcesOnBody(bodies[i], t); root.addForcesOnBody(bodies[i], forces[i], t);
} }
for (int i = 0; i < bodies.length; i++) { for (int i = 0; i < bodies.length; i++) {
bodies[i].move(forces[i]); bodies[i].move(forces[i]);
@@ -55,8 +53,8 @@ public class Octree {
} }
abstract class OctreeItem { abstract class OctreeItem {
protected Vector center; protected final Vector center;
protected double size; protected final double size;
protected Body pseudoBody; protected Body pseudoBody;
@@ -67,25 +65,34 @@ abstract class OctreeItem {
abstract protected OctreeNode add(Body body); abstract protected OctreeNode add(Body body);
abstract protected void preCalc();
abstract protected Vector getForcesOnBody(Body body, double t); abstract protected Vector getForcesOnBody(Body body, double t);
abstract protected void addForcesOnBody(Body body, Vector force, double t);
abstract protected void draw(CodeDraw cd); abstract protected void draw(CodeDraw cd);
} }
class OctreeNode extends OctreeItem { class OctreeNode extends OctreeItem {
private final OctreeItem[] children; private final OctreeItem[] children;
private final Vector p1;
private final Vector p2 ;
protected OctreeNode(Vector center, double size) { protected OctreeNode(Vector center, double size) {
super(center, size); super(center, size);
children = new OctreeItem[8]; children = new OctreeItem[8];
p1 = center.plus(new Vector(size / 2));
p2 = center.minus(new Vector(size / 2));
} }
@Override @Override
protected OctreeNode add(Body body) { protected OctreeNode add(Body body) {
int num = getOctantNum(body.massCenter()); int num = getOctantNum(body.massCenter());
if (num < 0) return this; if (num < 0) return this;
if (this.pseudoBody == null) {
this.pseudoBody = new Body(body);
} else {
this.pseudoBody.update(body);
}
OctreeItem oct = children[num]; OctreeItem oct = children[num];
if (oct == null) { if (oct == null) {
children[num] = new OctreeLeaf(getOctantCenter(num), size / 2, body); children[num] = new OctreeLeaf(getOctantCenter(num), size / 2, body);
@@ -96,35 +103,25 @@ class OctreeNode extends OctreeItem {
} }
@Override @Override
protected void preCalc() { protected Vector getForcesOnBody(Body body, double t) {
double mass = 0; Vector v = new Vector();
for (OctreeItem oct : children) { addForcesOnBody(body, v, t);
if (oct == null) continue; return v;
oct.preCalc();
mass += oct.pseudoBody.mass();
}
Vector massCenter = new Vector();
for (OctreeItem oct : children) {
if (oct == null) continue;
massCenter = massCenter.plus(oct.pseudoBody.massCenter().times(oct.pseudoBody.mass() / mass));
}
this.pseudoBody = new Body(mass, massCenter);
} }
@Override @Override
protected Vector getForcesOnBody(Body body, double t) { protected void addForcesOnBody(Body body, Vector force, double t) {
double r = pseudoBody.massCenter().distanceTo(body.massCenter()); double r = center.distanceTo(body.massCenter());
if (r == 0) { if (r == 0) {
return new Vector(); return;
} else if (size / r < t) { } else if (size / r < t) {
return body.gravitationalForce(pseudoBody); force.add(body.gravitationalForce(pseudoBody));
return;
} }
Vector force = new Vector();
for (OctreeItem child : children) { for (OctreeItem child : children) {
if (child == null) continue; if (child == null) continue;
force = force.plus(child.getForcesOnBody(body, t)); child.addForcesOnBody(body, force, t);
} }
return force;
} }
@Override @Override
@@ -133,10 +130,12 @@ class OctreeNode extends OctreeItem {
if (child == null) continue; if (child == null) continue;
child.draw(cd); child.draw(cd);
} }
/*
Vector p1 = center.minus(new Vector(size / 2)); Vector p1 = center.minus(new Vector(size / 2));
Vector p2 = new Vector(size).minus(new Vector(Simulation.SECTION_SIZE / 2)); Vector p2 = new Vector(size).minus(new Vector(Simulation.SECTION_SIZE / 2));
cd.setColor(Color.CYAN); cd.setColor(Color.CYAN);
cd.drawRectangle(p1.getScreenX(cd), p1.getScreenY(cd), p2.getScreenX(cd), p2.getScreenY(cd)); cd.drawRectangle(p1.getScreenX(cd), p1.getScreenY(cd), p2.getScreenX(cd), p2.getScreenY(cd));
*/
} }
private int getOctantNum(Vector bodyPos) { private int getOctantNum(Vector bodyPos) {
@@ -146,8 +145,6 @@ class OctreeNode extends OctreeItem {
} }
private boolean isInOctant(Vector pos) { private boolean isInOctant(Vector pos) {
Vector p1 = center.plus(new Vector(size / 2));
Vector p2 = center.minus(new Vector(size / 2));
return pos.getX() <= p1.getX() && pos.getY() <= p1.getY() && pos.getZ() <= p1.getZ() && return pos.getX() <= p1.getX() && pos.getY() <= p1.getY() && pos.getZ() <= p1.getZ() &&
pos.getX() >= p2.getX() && pos.getY() >= p2.getY() && pos.getZ() >= p2.getZ(); pos.getX() >= p2.getX() && pos.getY() >= p2.getY() && pos.getZ() >= p2.getZ();
} }
@@ -167,6 +164,7 @@ class OctreeLeaf extends OctreeItem {
public OctreeLeaf(Vector center, double size, Body body) { public OctreeLeaf(Vector center, double size, Body body) {
super(center, size); super(center, size);
this.body = body; this.body = body;
//this.pseudoBody = new Body(this.body);
} }
@Override @Override
@@ -175,20 +173,22 @@ class OctreeLeaf extends OctreeItem {
} }
@Override @Override
protected void preCalc() { protected Vector getForcesOnBody(Body body, double t) {
this.pseudoBody = new Body(this.body); return body.gravitationalForce(body);
} }
@Override @Override
protected Vector getForcesOnBody(Body body, double t) { protected void addForcesOnBody(Body body, Vector force, double t) {
return body.gravitationalForce(pseudoBody); force.add(getForcesOnBody(body, t));
} }
@Override @Override
protected void draw(CodeDraw cd) { protected void draw(CodeDraw cd) {
/*
Vector p1 = center.minus(new Vector(size / 2)); Vector p1 = center.minus(new Vector(size / 2));
Vector p2 = new Vector(size).minus(new Vector(Simulation.SECTION_SIZE / 2)); Vector p2 = new Vector(size).minus(new Vector(Simulation.SECTION_SIZE / 2));
cd.setColor(Color.GREEN); cd.setColor(Color.GREEN);
cd.drawRectangle(p1.getScreenX(cd), p1.getScreenY(cd), p2.getScreenX(cd), p2.getScreenY(cd)); cd.drawRectangle(p1.getScreenX(cd), p1.getScreenY(cd), p2.getScreenX(cd), p2.getScreenY(cd));
*/
} }
} }

View File

@@ -22,7 +22,7 @@ public class Simulation {
// set some system parameters // set some system parameters
public static final double SECTION_SIZE = 2 * AU; // the size of the square region in space public static final double SECTION_SIZE = 2 * AU; // the size of the square region in space
public static final int NUMBER_OF_BODIES = 22; public static final int NUMBER_OF_BODIES = 10000;
public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms public static final double OVERALL_SYSTEM_MASS = 20 * SUN_MASS; // kilograms
public static void main(String[] args) { public static void main(String[] args) {
@@ -48,6 +48,9 @@ public class Simulation {
} }
long seconds = 0; long seconds = 0;
Vector[] forces = new Vector[bodies.length];
for (int i = 0; i < forces.length; i++) forces[i] = new Vector();
while (true) { while (true) {
seconds++; seconds++;
@@ -62,13 +65,19 @@ public class Simulation {
} }
bodies = mergedBodies; bodies = mergedBodies;
*/ */
//long n1 = System.nanoTime();
Octree octree = new Octree(new Vector(0, 0, 0), SECTION_SIZE); Octree octree = new Octree(new Vector(0, 0, 0), SECTION_SIZE);
for (Body body : bodies) { for (Body body : bodies) {
octree.add(body); octree.add(body);
} }
octree.applyForces(bodies, 1); //long n2 = System.nanoTime();
for (Vector f : forces) f.reset();
octree.applyForces(bodies, forces, 1);
//long n3 = System.nanoTime();
if ((seconds % 3600) == 0) { //System.out.format("%8.3f µs, %8.3f µs\n", (n2 - n1) / 1000.0, (n3 - n2) / 1000.0);
if ((seconds % 60) == 0) {
cd.clear(Color.BLACK); cd.clear(Color.BLACK);
for (Body body : bodies) { for (Body body : bodies) {
body.draw(cd); body.draw(cd);

View File

@@ -45,6 +45,12 @@ public class Vector {
return new Vector(x + v.x, y + v.y, z + v.z); return new Vector(x + v.x, y + v.y, z + v.z);
} }
public void add(Vector v) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
}
/** /**
* Returns the product of this vector and 'd'. * Returns the product of this vector and 'd'.
*/ */
@@ -52,6 +58,18 @@ public class Vector {
return new Vector(x * d, y * d, z * d); return new Vector(x * d, y * d, z * d);
} }
public void mul(double d) {
this.x *= d;
this.y *= d;
this.z *= d;
}
public void div(double d) {
this.x /= d;
this.y /= d;
this.z /= d;
}
/** /**
* Returns the sum of this vector and -1*v. * Returns the sum of this vector and -1*v.
*/ */
@@ -74,7 +92,7 @@ public class Vector {
* Returns the length (norm) of this vector. * Returns the length (norm) of this vector.
*/ */
public double length() { public double length() {
return distanceTo(new Vector()); return Math.sqrt(x * x + y * y + z * z);
} }
/** /**
@@ -82,10 +100,13 @@ public class Vector {
* The direction and orientation of the vector is not affected. * The direction and orientation of the vector is not affected.
*/ */
public void normalize() { public void normalize() {
double length = length(); div(length());
x /= length; }
y /= length;
z /= length; public void reset() {
x = 0;
y = 0;
z = 0;
} }
public double getScreenX(CodeDraw cd) { public double getScreenX(CodeDraw cd) {