Let\'s say that I have the coordinates of a line (25,35 45,65, 30,85 - It would be a two part line). I need to move a point (car) along that line at a constant distance ever
Hey, so you have the coordinates (25,35) (45,65) (30,85) for your 2 lines, The point you want to move is going to be placed at the first of these coordinates (25,35) and you want it to move towards the second coordinate (45,65) (the end of the first line segment).
The first step is to get the orientation in which the point is going to move, the orientation is the angle between the point position and the target position. To find this angle you can use the Math.atan2()
, passing in as the first argument the target position Y - the point position Y
, and as the second argument the target position X - the point position X
.
var Point = {X: 25, Y: 35};
var Target = {X:45, Y:65};
var Angle = Math.atan2(Target.Y - Point.Y, Target.X - Point.X);
Now get the Sine and Cosine of that angle, the Sine is the value to move along the Y axis, and the Cosine is how much to move on the X axis. Multiply the sine and cosine by the distance you want to move each frame.
var Per_Frame_Distance = 2;
var Sin = Math.sin(Angle) * Per_Frame_Distance;
var Cos = Math.cos(Angle) * Per_Frame_Distance;
Ok, what is left do to now is just setup the redraw method where you add the sine to the point's Y position and the cosine to the point's X position at each call. Check if the point has arrived to it's destination then do the same process to move towards the end of the second line segment.
Sometimes it's not so obvious how to translate a mathematical formula into a code. The following is an implementation of a function which moves a point specified distance along a line. It uses vector notation:
function travel(x, y, dx, x1, y1, x2, y2)
{
var point = new Vector(x, y),
begin = new Vector(x1, y1),
end = new Vector(x2, y2);
return end.sub(begin).norm().mul(dx).add(point);
}
class Vector
{
constructor(x = 0, y = 0) {
this.x = x;
this.y = y;
}
clone() {
return new this.constructor(this.x, this.y);
}
add(v) {
this.x += v.x;
this.y += v.y;
return this;
}
sub(v) {
this.x = this.x - v.x;
this.y = this.y - v.y;
return this;
}
mul(x) {
this.x *= x;
this.y *= x;
return this;
}
div(x) {
this.x /= x;
this.y /= x;
return this;
}
get mag() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
norm() {
var mag = this.mag;
if (mag > 0) {
this.div(mag);
}
return this;
}
}
And a version without Vector
class:
function travel(x, y, dx, x1, y1, x2, y2)
{
var a = {x: x2 - x1, y: y2 - y1},
mag = Math.sqrt(a.x*a.x + a.y*a.y);
if (mag == 0) {
a.x = a.y = 0;
}
else {
a.x = a.x/mag*dx;
a.y = a.y/mag*dx;
}
return {x: x + a.x, y: y + a.y};
}
Consider the line (25,35 45,65). The vector from the beginning to the end is (20, 30). To move a point (x,y) in that direction, we could just add that vector:
V = (20, 30) (x,y) => (x+20, y+30).
If we start at the beginning of the line, we'll arrive at the end. But that's too big a step. We want something smaller but in the same direction, so we multiply the vector by, say, 0.1:
V = (2, 3) (x,y) => (x+2, y+3) => (x+4, y+6) => ...
It's convenient to normalize, that is to make its length 1, which we do by dividing by its length:
V => V/|V| = (2,3)/sqrt(22 + 32) = (7.21, 10.82)
Then you can just multiply that by whatever step size you want.
8 years too late but someone may find this useful. This method is far faster given it doesn't uses stuff like atan, cos, sin and square root of which all are slow.
function getPositionAlongTheLine(x1, y1, x2, y2, percentage) {
return {x : x1 * (1.0 - percentage) + x2 * percentage, y : y1 * (1.0 - percentage) + y2 * percentage};
}
Pass percentage as value between 0 and 1 where 0 is start of the line and 1 being the end.
var xy = getPositionAlongTheLine(100, 200, 500, 666, 0.5);
console.log(xy.x, xy.y);