Короче говоря, я разрабатываю свой физический движок (ссылка: bitbucket.org/javaphysics/javaphysicsengine). Он поддерживает 1D, 2D, 3D и 4D физику и коллизии. (P.S. На данный момент коллизии не реализованы только для сфер и одиночных объектов). Движок бесплатный и можно адаптировать под свои нужды. Также его можно интегрировать с другими проектами, а визуализацию можно реализовать самостоятельно. Движок написан на Java.
СРАВНЕНИЯ
Критерий JavaPhysics Unity PhysX Box2D
1D/2D/3D/4D ✅ Все ✅ 3D /2D ✅2D
Атмосфера по высоте ✅ ❌ ❌
Гравитация по высоте ✅ ❌ ❌
Коллизии ⚠️ Частично ✅ Мощно ✅ Есть
Lift/Drag силы ✅ Все ⚠️Lift через Rigid ❌ Нет
Оптимизация ⚠️ 3 метода ✅ Мощная ✅ Есть
Real-Time игры ❌ ✅ Адаптировано ❌
Научные симуляции ✅ Точный ⚠️ Не очень точн ❌
Платформы ✅ На все IDE⚠️ PC/Telephone ⚠️ Хз
Простота ⚠️ Сложно ✅ Есть куча инфи ✅ Прост
Вот код если физику прям сейчас хотите в код вставить:
package lmtech.javaphysics.physics;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import lmtech.javaphysics.PhysicsOutOfRange;
import lmtech.javaphysics.math.Vector1D;
import lmtech.javaphysics.math.Vector2D;
import lmtech.javaphysics.math.Vector3D;
import lmtech.javaphysics.math.Vector4D;
/**
* The main class with JavaPhysics Core Module.
* <p>This class provided main physics and other methods to simulate realistic physics.</p>
*
* <p>In this class have a 16 methods for simulate physics. This physics engine realize a Aerodynamic, Air density, Gravity (changing at height), Atmosphere (changing at height) and Ballisitic trajectories with Drag/Lift forces</p>
* <p>JavaPhysics provided collisions, this class provided one-object 1D, 2D, 3D and 4D collisions. Main collisions in {@link PhysicsCollider Collision segment}</p>
*/
public class Physics {
/**
* Free falling acceleration (m/c²)
*/
public static final double GRAVITY = 9.80655; // Free falling acceleration (m/c²)
/**
* Speed of light
*/
public static final double C = 299792458; // Speed of light
/**
* Air density
*/
public static final double AIR_DENSITY = 1.225; // Air density
/**
* Temparature gradient (K/m)
*/
public static final double L = -0.0065; // Temparature gradient (K/m)
/**
* Temparature in sea level (K)
*/
public static final double T_0 = 288.15; // Temparature in sea level (K)
/**
* Molecular air mass (kg/mol)
*/
public static final double M = 0.0289644; // Molecular air mass (kg/mol)
/**
* Uniniversal gas static (J/(mol·K))
*/
public static final double R = 8.314; // Uniniversal gas static (J/(mol·K))
/**
* Gravitational constant (m³/kg·s²)
*/
public static final double G = 6.67430e-11; // Gravitational constant (m³/kg·s²)
/**
* Pressure in sea level (Pa)
*/
public static final double P0 = 101325; // Pressure in sea level (Pa)
/**
* Sea level density (kg/m³)
*/
private static final double SEA_LEVEL_DENSITY = 1.225; // kg/m³
/**
* Sea level temperature Kelvin
*/
private static final double SEA_LEVEL_TEMPERATURE = 288.15; // K
/**
* Air gas constant J/(kg·K)
*/
private static final double AIR_GAS_CONSTANT = 287.05; // J/(kg·K)
/**
* K/m (in tropesphere)
*/
private static final double TEMP_LAPSE_RATE_T = 0.0065; // K/m (in tropesphere)
/**
* K/m (in stratophere)
*/
private static final double TEMP_LAPSE_RATE_S = 0.0010; // K/m (in stratophere)
/**
* K/m (in mesosphere)
*/
private static final double TEMP_LAPSE_RATE_M = 0.0000; // K/m (in mesosphere)
/**
* Earth radius in meters
*/
public static final double EARTH_RADIUS = 6371000; // Earth radius in meters
/**
* Normalize angle from 0 to 360
* @param angle Angle to normalize
* @return Normalized angle
*/
public static double normalizeAngle(double angle) {
angle = angle % 360; // Range of -360 to 360
if (angle < 0) {
angle += 360; // If angle smaller than zero, add 360, for range from 0 to 360
}
return angle;
}
/**
* TEST
*/
public Physics() {}
/**
* Calculate air density on height
* <p>This method used accuraty-formula for calculate air density</p>
* <pre>
* 1st formula
* Th = S-T*h
* Th - Temparature at height
* S - Sea level temparature 288.15 Kelvin
* T - Temparature lapse rate 0.0065 Kelvin/m
* h - Height
*
* 2nd formula
* Ad = S*(Th/S)^(-G/(Ag*T))
* Ad - Air density
* S - Sea level temparature 288.15 Kelvin
* T - Temparature lapse rate 0.0065 Kelvin/m
* Th - Temparature at height
* G - Free-falling acceleration 9.81 m/c²
* Ag - Air gas constant 287.05 Joules/(kg·K)
* </pre>
* @param h Height (m)
* @return Air density (kg/m³)
* @throws PhysicsOutOfRange If height is negative, air density is uncorrect calculated and physics is breaked.
*/
public static double airDensityAtHeight(double h) throws PhysicsOutOfRange {
if (h < 0) throw new PhysicsOutOfRange("Height: " + h + " is negative. Air density cannot be calculated!");
double tempAtHeight;
double lapseRate;
// First, check for the first layer (up to 20 km)
if (h < 20000) {
tempAtHeight = SEA_LEVEL_TEMPERATURE - TEMP_LAPSE_RATE_T * h;
lapseRate = TEMP_LAPSE_RATE_T;
}
// Second, between 20-50 km (tropopause layer)
else if (h < 50000) {
double tropopauseTemp = SEA_LEVEL_TEMPERATURE - TEMP_LAPSE_RATE_T * 20000;
tempAtHeight = tropopauseTemp - TEMP_LAPSE_RATE_S * (h - 20000);
lapseRate = TEMP_LAPSE_RATE_S;
}
// Third, between 50-85 km (stratopause layer)
else if (h < 85000) {
double stratopauseTemp = (SEA_LEVEL_TEMPERATURE - TEMP_LAPSE_RATE_T * 20000) - TEMP_LAPSE_RATE_S * 30000;
tempAtHeight = stratopauseTemp - TEMP_LAPSE_RATE_M * (h - 50000);
lapseRate = TEMP_LAPSE_RATE_M;
} else {
// Above 85 km
return SEA_LEVEL_DENSITY * Math.exp(-h / 55000);
}
// If temperature at height is less than 0, set density to 0
if (tempAtHeight <= 0) return 0;
// Ensure that the computed density does not go to infinity
double exponent = (-GRAVITY / (AIR_GAS_CONSTANT * lapseRate)) * Math.log(tempAtHeight / SEA_LEVEL_TEMPERATURE);
if (exponent < -1000) return 0; // Prevent overflow to infinity
// Compute air density
return SEA_LEVEL_DENSITY * Math.pow(tempAtHeight / SEA_LEVEL_TEMPERATURE, exponent);
}
/**
* Calculate aerodynamic forces: lift and drag
* <p>This method used accuraty-formula for calculate aerodynamic force</p>
* <pre>
* 1st formula:
* Dp = 0.5*Ad*v^2
* Dp - Dynamic pressure
* Ad - Air density
* v - Velocity
*
* 2nd formula
* Lf = Dp*a*lC
* Lf - Lift force
* Dp - Dynamic pressure
* a - Cross-Sectional area (m²)
* lC - Lift coeficient
*
* 3d formula:
* Df = Dp*a*dC
* Df - Drag force
* a - Cross-Sectional area (m²)
* dC - Drag coeficient
* </pre>
* @param velocity Object velocity
* @param angleOfAttack Angle of attack
* @param height Height of pbject
* @param area Cross-Sectional area (m²)
* @param liftCoef Lift coeficient
* @param dragCoef Drag coeficient
* @return Vector2D x - lift force, y - drag force
* @throws lmtech.javaphysics.PhysicsOutOfRange If angle of attack smaller of zero of bigger of 360
*/
public static Vector2D calcAerodynamicForces(double velocity, double height, double angleOfAttack, double area, double liftCoef, double dragCoef) throws PhysicsOutOfRange {
if (angleOfAttack < 0 || angleOfAttack > 360) throw new PhysicsOutOfRange("Angle of attack out of range!");
double dynamicPressure = 0.5 * airDensityAtHeight(height) * velocity * velocity;
double lift = dynamicPressure * area * liftCoef;
double drag = dynamicPressure * area * dragCoef;
return new Vector2D(lift, drag);
}
/**
* Calculate drag force
* <pre>
* Formula:
* Df = 0.5*Ad*v^2*dC*a
* Df - Drag coeficient
* Ad - Air density
* v - Velocity
* dC - Drag coeficient
* a - Cross-Sectional area (m²)
* </pre>
* @param velocity Object velocity
* @param dragCoefficient Drag coeficient
* @param area Cross-Sectional area (m²)
* @param altitude Height of object (meters)
* @return Drag force
* @throws PhysicsOutOfRange If altitude is negative
*/
public static double calculateDragForce(double velocity, double dragCoefficient, double area, double altitude) throws PhysicsOutOfRange {
double airDensity = airDensityAtHeight(altitude);
return 0.5 * airDensity * velocity * velocity * dragCoefficient * area;
}
/**
* Calculate free falling acceleration (gravity) on height
* <pre>
* Formula:
* G = Gs*Er/((Er+h>-1)^2)
* G - Gravity
* Gs - Free-falling acceleration 9.81 m/c²
* Er - Earth radius 6371000 m
* h - Height
* >-1 This is a indicator of h small of 0 thr PhysicsOutOfRange(...)
* </pre>
* @param height Height (m)
* @return Free Falling Acceleration (m/c²)
* @throws PhysicsOutOfRange If height is negative, air density is uncorrect calculated and physics is breaked.
*/
public static double gravityAtHeight(double height) throws PhysicsOutOfRange {
if (height < 0) throw new PhysicsOutOfRange("Height: " + height + " is negative. Graivty force match not calculate!");
return GRAVITY * Math.pow(EARTH_RADIUS / (EARTH_RADIUS + height), 2);
}
/**
* Calculate falling speed of object with air density
* <pre>
* Formula:
* Fa = sqrt((2*m*G)/(Ad*Dc*a))*(1 - exp(-G*t/sqrt((2*m*G)/(Ad*Dc*a)))) small of C
* Fa - Falling acceleration
* m - Mass
* G - Gravity
* Ad - Air density
* Dc - Drag coeficient
* a - Cross-Sectional area
* C - Speed of light 299792458 m/s
* </pre>
* @param time Falling time seconds
* @param dragCoef Density coeficient
* @param area Cross-Sectional area (m²)
* @param mass Object mass (kg)
* @param height Falling height meters
* @return Vector1D with x is a falling speed (m/s)
* @throws lmtech.javaphysics.PhysicsOutOfRange If height is negative
*/
public static Vector1D calcFreeFallWithDrag(double time, double dragCoef, double area, double mass, double height) throws PhysicsOutOfRange {
double termVel = Math.sqrt((2 * mass * gravityAtHeight(height)) / (airDensityAtHeight(height) * dragCoef * area));
double temp = termVel * (1 - Math.exp(-gravityAtHeight(height) * time / termVel));
if (temp > C) {
temp = C;
}
return new Vector1D(temp);
}
/**
* Advanced version of {@link #calcProjectileMotionWithDrag(double, double, double, double, double, double, double, double) } with advanced aero-braking algoritm
* @param vel Object velocity (m/s)
* @param angle Angle of attack (deg)
* @param mass Object mass (kg)
* @param lC Lift force
* @param dC Drag force
* @param area Cross-Sectional area (m²)
* @param timeStep Time for one motion
* @param totalTime Time for object motion
* @param flatPos Position of ground
* @return Vector2D with object stop position
* @throws lmtech.javaphysics.PhysicsOutOfRange If y is negative
*/
public static Vector2D calcProjectileMotionAero(double vel, double angle, double mass, double lC, double dC, double area, double timeStep, double totalTime, double flatPos) throws PhysicsOutOfRange {
if (vel > C) return new Vector2D(0, 0);
angle = normalizeAngle(angle);
double vx = vel * Math.cos(Math.toRadians(angle));
double vy = vel * Math.sin(Math.toRadians(angle));
double x = 0, y = 0;
for (double t = 0; t < totalTime; t += timeStep) {
double speed = Math.sqrt(vx * vx + vy * vy);
Vector2D aF = calcAerodynamicForces(speed, y, angle, area, lC, dC);
double ax = (-aF.getX() / mass) * Math.cos(Math.toRadians(angle));
double ay = (-aF.getY() / mass) * Math.sin(Math.toRadians(angle)) - gravityAtHeight(y) + (aF.getX() / mass);
vx += ax * timeStep;
vy += ay * timeStep;
x += vx * timeStep;
y += vy * timeStep;
if (y <= flatPos) break; // Object has hit the ground
}
return new Vector2D(x, y);
}
/**
* Calculate projectile motion with air density and gravity
* @param velocity Velocity of object (m/s)
* @param angle Angle of object (deg)
* @param mass Object mass (kg)
* @param dragCoef Drag coeficient
* @param area Cross-Sectional area (m²)
* @param timeStep Value to calculate object falling
* @param totalTime Value to stop algoritm if t >= totalTime
* @param flatPos Pos to stop algoritm
* @return Returns two-direct vector ({@link Vector2D}) with object x, y coordinates
* @throws lmtech.javaphysics.PhysicsOutOfRange TEST
*/
public static Vector2D calcProjectileMotionWithDrag(
double velocity, double angle, double mass, double dragCoef, double area, double timeStep, double totalTime, double flatPos) throws PhysicsOutOfRange {
if (velocity > C) return new Vector2D(0, 0);
angle = normalizeAngle(angle);
double vx = velocity * Math.cos(Math.toRadians(angle));
double vy = velocity * Math.sin(Math.toRadians(angle));
double x = 0, y = 0;
ForkJoinPool optimize = new ForkJoinPool();
return optimize.invoke(new ProjTask(vx, vy, x, y, timeStep, totalTime, flatPos, dragCoef, area, mass));
}
/**
* Calculate projectile motion from change mass (example, rocket)
* @param velocity Object speed (m)
* @param mass0 Object mass (kg)
* @param massLossRate Mass lost rate
* @param timeStep Time for 1-st operation (s)
* @param totalTime Falling time (s)
* @param flatPos If object 'y' coordinate equals of smallest for flatPos, algoritm stop and return coords
* @param height Height of object to calculate gravity and air density
* @return Coords of object
* @throws lmtech.javaphysics.PhysicsOutOfRange TEST
*/
public static Vector3D calcMotionWithMassChange(
Vector3D velocity, double mass0, double massLossRate, double timeStep, double totalTime, double flatPos, double height) throws PhysicsOutOfRange {
if (velocity.x > C || velocity.y > C || velocity.z > C) return new Vector3D(0, 0, 0);
Vector3D pos = new Vector3D(0, 0, 0);
Vector3D gravity = new Vector3D(0, 0, -gravityAtHeight(height));
double mass = mass0;
ForkJoinPool forkJoinPool = new ForkJoinPool();
return forkJoinPool.invoke(new MassChangeTask(velocity, pos, gravity, mass, massLossRate, timeStep, totalTime, flatPos));
}
/**
* Calculate 3D motion with drag
* @param velocity Velocity
* @param mass0 Mass
* @param dragCoef Drag coeficient
* @param area Cross-Sectional Area
* @param timeStep Time for one operation
* @param totalTime Total calculations time
* @param flatPos Position of the ground
* @param height Height of object
* @return Vector3D with end coordinates
* @throws PhysicsOutOfRange TEST
*/
public static Vector3D calc3DMotionWithDrag(Vector3D velocity, double mass0, double dragCoef, double area, double timeStep, double totalTime, double flatPos, double height) throws PhysicsOutOfRange {
if (velocity.x > C || velocity.y > C || velocity.z > C) return new Vector3D(0, 0, 0);
Vector3D pos = new Vector3D(0, 0, 0);
Vector3D gravity = new Vector3D(0, 0, -gravityAtHeight(height));
ForkJoinPool forkJoinPool = new ForkJoinPool();
return forkJoinPool.invoke(new MotionWithDragTask(velocity, pos, gravity, mass0, dragCoef, area, timeStep, totalTime, flatPos));
}
/**
* Calculate relativistic effect of time diliation
* @param velocity Object speed (m/s)
* @return Time diliation coeficient
*/
public static double calculateRelativisticTimeDilation(double velocity) {
if (velocity > C) return 1 / Math.sqrt(1 - (C * C) / (C * C));
return 1 / Math.sqrt(1 - (velocity * velocity) / (C * C));
}
/**
* Calculate 4D motion with drag
* @param velocity Velocity
* @param mass0 Mass
* @param dragCoefficient Drag coeficient
* @param area Cross-Sectional Area
* @param timeStep Time for one operation
* @param totalTime Total calculations time
* @param flatPos Position of the ground
* @param height Height of object
* @return Vector3D with end coordinates
* @throws PhysicsOutOfRange TEST
*/
public static Vector4D calculate4DMotion(
Vector4D velocity, double mass0, double dragCoefficient, double area, double timeStep, double totalTime, double flatPos, double height) throws PhysicsOutOfRange {
if (velocity.x > C || velocity.y > C || velocity.z > C || velocity.w > C) return new Vector4D(0, 0, 0, 0);
Vector4D position = new Vector4D(0, 0, 0, 0);
Vector4D gravity = new Vector4D(0, 0, -gravityAtHeight(height), 0);
for (double t = 0; t < totalTime; t += timeStep) {
double speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z + velocity.w * velocity.w);
double dragForce = 0.5 * dragCoefficient * airDensityAtHeight(position.y) * area * speed * speed;
double mass = mass0 * (1 / calculateRelativisticTimeDilation(speed));
Vector4D acceleration = new Vector4D(
-dragForce * (velocity.x / speed) / mass,
-dragForce * (velocity.y / speed) / mass,
gravity.z - (dragForce * (velocity.z / speed) / mass),
-dragForce * (velocity.w / speed) / mass // W-coordinate density motion
);
velocity.x += acceleration.x * timeStep;
velocity.y += acceleration.y * timeStep;
velocity.z += acceleration.z * timeStep;
velocity.w += acceleration.w * timeStep;
position.x += velocity.x * timeStep;
position.y += velocity.y * timeStep;
position.z += velocity.z * timeStep;
position.w += velocity.w * timeStep;
if (position.z <= flatPos) break;
}
return position;
}
/* ----------------------------------- Collision segment ----------------------------------- */
/**
* Check collision with 1D objects
* @param v Object velocity
* @param m Object mass
* @param dC Drag coefficient
* @param a Cross-Sectional area
* @param tS Time step
* @param tT Total time
* @param sP Stop position
* @return Vector1D with collision coords
* @throws PhysicsOutOfRange If airDensity detect negative height
*/
public static Vector1D calcCollision1D(double v, double m, double dC, double a, double tS, double tT, double sP) throws PhysicsOutOfRange {
Vector1D pos = new Vector1D(0);
double vx = v;
for (double t = 0; t < tT; t += tS) {
double dF = calculateDragForce(vx, dC, a, pos.getX());
double ac = -dF / m;
vx += ac * tS;
pos.x += vx * tS;
if (pos.getX() <= sP) return pos;
}
return pos;
}
/**
* Check collision with 2D objects
* @param v Object velocity
* @param angle Angle
* @param m Object mass
* @param dC Drag coefficient
* @param a Cross-Sectional area
* @param tS Time step
* @param tT Total time
* @param sP Stop position
* @return Vector1D with collision coords
* @throws PhysicsOutOfRange If airDensity detect negative height
*/
public static Vector2D calcCollision2D(double v, double angle, double m, double dC, double a, double tS, double tT, double sP) throws PhysicsOutOfRange {
double vx = v * Math.cos(Math.toRadians(angle));
double vy = v * Math.sin(Math.toRadians(angle));
double x = 0, y = 0;
for (double t = 0; t < tT; t += tS) {
double dF = calculateDragForce(vx, dC, a, y);
double aX = -dF * (vx / Math.sqrt(vx * vx + vy * vy)) / m;
double aY = -gravityAtHeight(y) - (dF * (vy / Math.sqrt(vx * vx + vy * vy)) / m);
vx += aX * tS;
vy += aY * tS;
x += vx * tS;
y += vy * tS;
if (y <= sP) return new Vector2D(x, y);
}
return new Vector2D(x, y);
}
/**
* Check collision in 3D
* @param velocity Velocity
* @param angleX Angle in X
* @param angleY Angle in Y
* @param mass Mass
* @param dragCoefficient Drag coefficient
* @param area Cross-Sectional area
* @param timeStep Time for one operation
* @param totalTime Total time of calculations
* @param stopPosition Ground position
* @return Vector3D with end coordinates of object
* @throws PhysicsOutOfRange TEST
*/
public static Vector3D calcCollision3D(double velocity, double angleX, double angleY, double mass, double dragCoefficient, double area, double timeStep, double totalTime, double stopPosition) throws PhysicsOutOfRange {
double vx = velocity * Math.cos(Math.toRadians(angleX)) * Math.cos(Math.toRadians(angleY));
double vy = velocity * Math.sin(Math.toRadians(angleX)) * Math.cos(Math.toRadians(angleY));
double vz = velocity * Math.sin(Math.toRadians(angleY));
double x = 0, y = 0, z = 0;
for (double t = 0; t < totalTime; t += timeStep) {
double dF = calculateDragForce(vx, dragCoefficient, area, z);
double ax = -dF * (vx / Math.sqrt(vx * vx + vy * vy + vz * vz)) / mass;
double ay = -gravityAtHeight(z) - (dF * (vy / Math.sqrt(vx * vx + vy * vy + vz * vz)) / mass);
double az = -dF * (vz / Math.sqrt(vx * vx + vy * vy + vz * vz)) / mass;
vx += ax * timeStep;
vy += ay * timeStep;
vz += az * timeStep;
x += vx * timeStep;
y += vy * timeStep;
z += vz * timeStep;
if (z <= stopPosition) return new Vector3D(x, y, z);
}
return new Vector3D(x, y, z);
}
/**
* Check collision in 4D
* @param velocity Velocity
* @param angleX Angle in X
* @param angleY Angle in Y
* @param angleZ Angle in Z
* @param mass Mass
* @param dragCoefficient Drag coefficient
* @param area Cross-Sectional area
* @param timeStep Time for one operation
* @param totalTime Total time of calculations
* @param stopPosition Ground position
* @return Vector4D with end coordinates of object
* @throws PhysicsOutOfRange TEST
*/
public static Vector4D calcCollision4D(double velocity, double angleX, double angleY, double angleZ, double mass, double dragCoefficient, double area, double timeStep, double totalTime, double stopPosition) throws PhysicsOutOfRange {
double vx = velocity * Math.cos(Math.toRadians(angleX)) * Math.cos(Math.toRadians(angleY)) * Math.cos(Math.toRadians(angleZ));
double vy = velocity * Math.sin(Math.toRadians(angleX)) * Math.cos(Math.toRadians(angleY)) * Math.cos(Math.toRadians(angleZ));
double vz = velocity * Math.sin(Math.toRadians(angleY)) * Math.cos(Math.toRadians(angleZ));
double vw = velocity * Math.sin(Math.toRadians(angleZ));
double x = 0, y = 0, z = 0, w = 0;
for (double t = 0; t < totalTime; t += timeStep) {
double dragForce = calculateDragForce(vx, dragCoefficient, area, z);
double ax = -dragForce * (vx / Math.sqrt(vx * vx + vy * vy + vz * vz + vw * vw)) / mass;
double ay = -gravityAtHeight(z) - (dragForce * (vy / Math.sqrt(vx * vx + vy * vy + vz * vz + vw * vw)) / mass);
double az = -dragForce * (vz / Math.sqrt(vx * vx + vy * vy + vz * vz + vw * vw)) / mass;
double aw = -dragForce * (vw / Math.sqrt(vx * vx + vy * vy + vz * vz + vw * vw)) / mass;
vx += ax * timeStep;
vy += ay * timeStep;
vz += az * timeStep;
vw += aw * timeStep;
x += vx * timeStep;
y += vy * timeStep;
z += vz * timeStep;
w += vw * timeStep;
if (z <= stopPosition) {
return new Vector4D(x, y, z, w);
}
}
return new Vector4D(x, y, z, w);
}
static class ProjTask extends RecursiveTask<Vector2D> {
private double vx, vy, x, y, timeStep, totalTime, flatPos, dragCoef, area, mass;
public ProjTask(double vx, double vy, double x, double y, double timeStep, double totalTime, double flatPos, double dragCoef, double area, double mass) {
this.vx = vx;
this.vy = vy;
this.x = x;
this.y = y;
this.timeStep = timeStep;
this.totalTime = totalTime;
this.flatPos = flatPos;
this.dragCoef = dragCoef;
this.area = area;
this.mass = mass;
}
@Override
protected Vector2D compute() {
try {
for (double t = 0; t < totalTime; t += timeStep) {
double speed = Math.sqrt(vx * vx + vy * vy);
double dragF = 0.5 * dragCoef * airDensityAtHeight(y) * area * speed * speed;
double ax = -dragF * (vx / speed) / mass;
double ay = -gravityAtHeight(y) - (dragF * (vy / speed) / mass);
vx += ax * timeStep;
vy += ay * timeStep;
x += vx * timeStep;
y += vy * timeStep;
if (y <= flatPos) break; // Object falled and collided with flat
}
return new Vector2D(x, y);
} catch (PhysicsOutOfRange e) {
}
return new Vector2D(0, 0);
}
}
static class MassChangeTask extends RecursiveTask<Vector3D> {
private Vector3D velocity, pos, gravity;
private double mass, massLossRate, timeStep, totalTime, flatPos;
public MassChangeTask(Vector3D velocity, Vector3D pos, Vector3D gravity, double mass, double massLossRate, double timeStep, double totalTime, double flatPos) {
this.velocity = velocity;
this.pos = pos;
this.gravity = gravity;
this.mass = mass;
this.massLossRate = massLossRate;
this.timeStep = timeStep;
this.totalTime = totalTime;
this.flatPos = flatPos;
}
@Override
protected Vector3D compute() {
try {
for (double t = 0; t < totalTime; t += timeStep) {
if (mass <= 0) break;
double speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
double dragF = 0.5 * airDensityAtHeight(pos.y) * speed * speed;
Vector3D acc1 = new Vector3D(
-dragF * (velocity.x / speed) / mass,
-dragF * (velocity.y / speed) / mass,
gravity.z - (dragF * (velocity.z / speed) / mass)
);
Vector3D velMid = new Vector3D(
velocity.x + acc1.x * (timeStep / 2),
velocity.y + acc1.y * (timeStep / 2),
velocity.z + acc1.z * (timeStep / 2)
);
Vector3D acc2 = new Vector3D(
-dragF * (velMid.x / speed) / mass,
-dragF * (velMid.y / speed) / mass,
gravity.z - (dragF * (velMid.z / speed) / mass)
);
velocity.x += acc2.x * timeStep + velocity.x * (massLossRate / mass) * timeStep;
velocity.y += acc2.y * timeStep + velocity.y * (massLossRate / mass) * timeStep;
velocity.z += acc2.z * timeStep + velocity.z * (massLossRate / mass) * timeStep;
pos.x += velocity.x * timeStep;
pos.y += velocity.y * timeStep;
pos.z += velocity.z * timeStep;
mass -= massLossRate * timeStep;
if (pos.z <= flatPos) break;
}
return pos;
} catch (PhysicsOutOfRange e) {
e.printStackTrace();
}
return new Vector3D(0, 0, 0);
}
}
static class MotionWithDragTask extends RecursiveTask<Vector3D> {
private Vector3D velocity, pos, gravity;
private double mass0, dragCoef, area, timeStep, totalTime, flatPos;
public MotionWithDragTask(Vector3D velocity, Vector3D pos, Vector3D gravity, double mass0, double dragCoef, double area, double timeStep, double totalTime, double flatPos) {
this.velocity = velocity;
this.pos = pos;
this.gravity = gravity;
this.mass0 = mass0;
this.dragCoef = dragCoef;
this.area = area;
this.timeStep = timeStep;
this.totalTime = totalTime;
this.flatPos = flatPos;
}
@Override
protected Vector3D compute() {
try {
for (double t = 0; t < totalTime; t += timeStep) {
double speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
double dragF = 0.5 * dragCoef * airDensityAtHeight(pos.y) * area * speed * speed;
double mass = mass0 * (1 / calculateRelativisticTimeDilation(speed));
Vector3D acc1 = new Vector3D(
-dragF * (velocity.x / speed) / mass,
-dragF * (velocity.y / speed) / mass,
gravity.z - (dragF * (velocity.z / speed) / mass)
);
Vector3D velMid = new Vector3D(
velocity.x + acc1.x * (timeStep / 2),
velocity.y + acc1.y * (timeStep / 2),
velocity.z + acc1.z * (timeStep / 2)
);
Vector3D acc2 = new Vector3D(
-dragF * (velMid.x / speed) / mass,
-dragF * (velMid.y / speed) / mass,
gravity.z - (dragF * (velMid.z / speed) / mass)
);
velocity.x += acc2.x * timeStep;
velocity.y += acc2.y * timeStep;
velocity.z += acc2.z * timeStep;
pos.x += velocity.x * timeStep;
pos.y += velocity.y * timeStep;
pos.z += velocity.z * timeStep;
if (pos.z <= flatPos) break;
}
return pos;
} catch (PhysicsOutOfRange e) {
e.printStackTrace();
}
return new Vector3D(0, 0, 0);
}
}
}
0 комментариев
Добавить комментарий