I am working on some logic for point-to-point spaceship travel across a cartesian map using force, acceleration and mass. The ship will accelerate and burn at 1G towards its destination, flip 180 degrees at the half-way mark, and decelerate at 1G to arrive at a relative stop at its destination.
The problem I am having is determining the (x, y) coordinate using the time traveled while the ship is either under acceleration or deceleration.
Here are the specs on the ship
:
ship = {
mass: 135000, // kg
force: 1324350, // Newtons
p: { x: -1, y: -5 } // (x,y) coordinates
}
dest: {
p: { x: 15, y: 30 } // (x,y) coordinates
}
For the first part of the problem I calculate the time to destination:
var timeToDestination = function(ship, dest) {
// calculate acceleration (F = ma)
var acceleration = ship.force / ship.mass; // ~9.81 (1G)
// calculate distance between 2 points (Math.sqrt((a - x)^2+(b - y)^2))
var totalDistance = Math.sqrt(
Math.pow(dest.p.x - ship.p.x, 2) +
Math.pow(dest.p.y - ship.p.y, 2)
); // 38.48376280978771
// multiply grid system to galactic scale
var actualDistance = totalDistance * 1e9; // 1 = 1Mkm (38,483,763km) Earth -> Venus
// determine the mid-point where ship should flip and burn to decelerate
var midPoint = actualDistance / 2;
// calculate acceleration + deceleration time by solving t for each: (Math.sqrt(2d/a))
return Math.sqrt( 2 * midPoint / acceleration ) * 2; // 125,266s or 34h or 1d 10h
}
The second part is a little trickier, getting the (x, y) coordinate after delta time. This is where I get stuck, but here is what I have so far:
var plotCurrentTimeDistance = function(ship, dest, time) {
// recalculate acceleration (F = ma)
var acc = ship.force / ship.mass; //~9.81m/s^2
// recalculate total distance
var distance = Math.sqrt(
Math.pow(dest.p.x - ship.p.x, 2) +
Math.pow(dest.p.y - ship.p.y, 2)
) * 1e9; // 38,483,762,810m
// get distance traveled (d = (1/2) at^2)
var traveled = (acc * Math.pow(time, 2)) / 2;
// get ratio of distance traveled to actualDistance
var ratio = traveled / distance;
// midpoint formula to test @ 50% time ((x+a)/2,(y+b)/2)
console.log({ x: (ship.p.x+dest.p.x)/2, y: (ship.p.y+dest.p.y)/2})
// get the point using this formula (((1−t)a+tx),((1−t)b+ty))
return {
x: (( 1 - ratio ) * ship.p.x) + (ratio * dest.p.x),
y: (( 1 - ratio ) * ship.p.y) + (ratio * dest.p.y)
};
}
@ 50% time, 62,633s point returns as (~7, ~12.5) which matches the midpoint formula which returns as (~7, ~12.5). However, any other distance/time you input will be wildly wrong. My guess is that acceleration is messing up the calculations but I can't figure out how to change the formula to make it work. Thank you for your time.
So thanks to @pingul I was able to get the answer using insights from his suggestions.
var ship = {
mass: 135000,
force: 1324350,
accel: 0,
nav: {
startPos: { x: 0, y: 0 },
endPos: { x: 0, y: 0 },
distanceToDest: 0,
distanceTraveled: 0,
departTime: 0,
timeToDest: 0,
arriveTime: 0,
startDeceleration: 0
}
};
var log = [];
var start = { x: -1, y: -5 };
var end = { x: 15, y: 30 };
var updateLog = function() {
document.getElementById('ship').textContent = JSON.stringify(ship, null, 2);
document.getElementById('pos').textContent = JSON.stringify(log, null, 2);
}
var plotCourse = function(ship, start, end) {
// calculate acceleration (F = ma)
var acceleration = ship.force / ship.mass; // ~9.81 (1G)
// calculate distance between 2 points (Math.sqrt((a - x)^2+(b - y)^2))
var totalDistance = Math.sqrt(
Math.pow(end.x - start.x, 2) +
Math.pow(end.y - start.y, 2)
); // 38.48376280978771
// multiply grid system to galactic scale
var actualDistance = totalDistance * 1e9; // 1 = 1Mkm (38,483,763km) Earth -> Venus
// determine the mid-point where ship should flip and burn to decelerate
var midpoint = actualDistance / 2;
// calculate acceleration + deceleration time by solving t for each: (Math.sqrt(2d/a))
var time = Math.sqrt( 2 * midpoint / acceleration ) * 2; // 125,266s or 34h or 1d 10h
// load data into ship nav
ship.nav = {
startPos: start,
endPos: end,
distanceToDest: actualDistance,
timeToDest: time,
startDeceleration: time / 2
}
ship.accel = acceleration
//log it
updateLog();
};
var goUnderway = function(ship) {
var arrivalEl = document.getElementById('arrivalTime');
// set depart and arrive times
var timeToDest = ship.nav.timeToDest * 1000; // convert to ms
ship.nav['departTime'] = moment().valueOf(); // returns now as unix ms
ship.nav['arriveTime'] = moment(ship.nav.departTime).add(timeToDest).valueOf();
//log it
arrivalEl.textContent = 'Your ship will arrive ' + moment(ship.nav.arriveTime).calendar();
updateLog();
};
var getPosition = function(ship, date) {
var currentTime = date ? moment(date).valueOf() : moment().valueOf() // unix ms
var elapsedTime = (currentTime - ship.nav.departTime) / 1000; // convert to s
var remainingTime = (ship.nav.arriveTime - currentTime) / 1000; // convert to s
var distanceAtMidpoint = 0;
var timeSinceMidpoint = 0;
var pos = { x: 0, y: 0 };
// calculate velocity from elapsed time
if (elapsedTime < ship.nav.startDeceleration) {
// if ship is accelerating use this function
ship.nav.distanceTraveled = 0 + ship.accel * Math.pow(elapsedTime, 2) / 2;
} else if (elapsedTime > ship.nav.startDeceleration) {
// else if ship is decelerating use this function
distanceAtMidpoint = 0 + ship.accel * Math.pow(ship.nav.startDeceleration, 2) / 2; // distance at midpoint
timeSinceMidpoint = elapsedTime - ship.nav.startDeceleration;
ship.nav.distanceTraveled = distanceAtMidpoint + ship.accel * Math.pow(timeSinceMidpoint, 2) / 2;
}
if (remainingTime <= 0) {
ship.force = ship.vel = ship.accel = 0;
pos = ship.nav.endPos;
} else {
// get ratio of distance traveled to actualDistance
var ratio = ship.nav.distanceTraveled / ship.nav.distanceToDest;
// get the point using this formula (((1−t)a+tx),((1−t)b+ty))
pos = {
x: (( 1 - ratio ) * start.x) + (ratio * end.x),
y: (( 1 - ratio ) * start.y) + (ratio * end.y)
};
}
log.push({
timestamp: moment(currentTime),
pos: pos
})
//log it
updateLog();
};
plotCourse(ship, start, end);
goUnderway(ship);
for (var i = 0; i < 35; i++) {
getPosition(ship, moment().add(i, 'hour'));
}
pre {
outline: 1px solid #ccc;
padding: 5px;
margin: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>
Ship: <span id="arrivalTime"></span>
<pre id="ship"></pre> Last Known Positions:
<pre id="pos"></pre>