get point coordinates based on direction and distance (vector) - javascript

I need to find the coordinates of the second point. I know the angle between the points in radians and I also know the length of the vector.
I would really appreciate if someone could point me towards the solution.

Given L as the length of the vector and Ang the angle
x2 = x1 + Math.cos(Ang) * L
y2 = y1 + Math.sin(Ang) * L
Oops... I just noted the top to bottom orientation of the Y axis...
Konstantin Levin, you will need adapt slightly because the formulas above assume a typical trigonometric coordinates system. In your case the formulas should be:
x2 = x1 + Math.cos(Ang) * L // unchanged
y2 = y1 - Math.sin(Ang) * L // minus on the Sin
Also (what goes without saying, also goes in one says it...) the reference angle should be such that when y2 == y1 and x2 > x1, Ang should be zero, and it should increase as the second point is moved counter-clockwise around the first one.

Related

Calculate angle change after hitting a tilted wall

I'm making a game in javascript, where an object is supposed to bounce from walls. I really tried to get it to work myself, but it never works correctly.
Let's say theres a ball bouncing inside this cage (blue = 30°, brown = 60°);
The ball's coordinates are known. The angle of movement is known. The point of collision (P) coordinates are known. The angle of the wall is known. The ball's position is updating it's coordinates inside a setInterval function using this function:
function findNewPoint(x, y, angle, distance) {
var result = {};
result.x =(Math.cos(angle * Math.PI / 180) * distance + x);
result.y = (Math.sin(angle * Math.PI / 180) * distance + y);
return result;
So, upon colliding, there should be a function that properly changes the ball's angle. It's a very complicated problem it seems, because even if I know that the wall is 30°, its important to know from what side the ball is colliding into it. I tried using the "Reflection across a line in the plane" formula and also some vectors, but it never worked out for me. I'm not expecting a complete answer with code, if someone could suggest in what way this should be programmed, it would help aswell.
Edit:
Thanks for your tips guys, I realized what was causing the most confustion; if I select an angle on the canvas with my mouse, the starting coordinate(0,0) is in the bottom left corner. But since the canvas' starting coordinate is in the top left corner, this has to be considered.
Basically using this formula for calculating the angle:
function angle(cx, cy, ex, ey) {
var dy = ey - cy;
var dx = ex - cx;
var theta = Math.atan2(dy, dx);
theta *= 180 / Math.PI;
return theta;
}
if the ball moved from (50,50) to (100,100), the angle would be -45.
Now, this angle changes in the following way when hitting walls:
If im honest, I got these out of trial and error, am not really understanding why exactly 60 and 120.
It is not wise to use angle for moving ball and calculate Cos/Sin again and again. Instead use unit velocity direction vector with components vx, vy like this:
new_x = old_x + vx * Velocity_Magnitude * Time_Interval
Note that vx = Cos(angle), vy = Sin(angle), but with direction approach you seldom need to use trigonometric functions.
Tilted wall with angle Fi has normal
nx = -Sin(Fi)
ny = Cos(Fi)
To find reflection , you need to calculate dot product of velocity and normal
dot = vx * nx + vy * ny
Velocity after reflection transforms:
vnewx = v.x - 2 * dot * n.x
vnewy = v.y - 2 * dot * n.y
Use these values for further moving
(note that you can use both internal and external normal direction, because direction flip changes both components, and sign of 2 * dot * n.x remains the same)
Examples:
horizontal moving right
vx=1, vy=0
30 degrees wall has normal
nx=-1/2, ny=Sqrt(3)/2
dot = -1/2
vnewx = 1 - 2 * (-1/2) * (-1/2) = 1/2
vnewy = 0 - 2 * (-1/2) * Sqrt(3)/2 = Sqrt(3)/2
(velocity direction angle becomes 60 degrees)
horizontal moving left
vx=-1, vy=0
330 degrees wall (left bottom corner) has normal
nx=1/2, ny=Sqrt(3)/2
dot = -1/2
vnewx = -1 - 2 * (-1/2) * (1/2) = -1/2
vnewy = 0 - 2 * (-1/2) * (Sqrt(3)/2) = Sqrt(3)/2
(velocity direction angle becomes 120 degrees)
Here is a function that returns the angle of reflection given an angle of incidence and a surface angle (in degrees). It also ensures that the returned angle is between 0 and 359 degrees.
function angleReflect(incidenceAngle, surfaceAngle){
var a = surfaceAngle * 2 - incidenceAngle;
return a >= 360 ? a - 360 : a < 0 ? a + 360 : a;
}
Here's a demonstration, where the blue line is the angle of incidence, the purple line is the angle of reflection, and the black line is the surface.
If you're assuming that the ball behaves like light bouncing off a mirror, then the angle of incidence equals the angle of reflection.
So your board is 30° from 0° (straight up). The means the normal (perpendicular to the board at the point the ball hits ) is 300°. Say the ball arrives from 280°, it must leave at 320° as the difference between the angle of incidence and the normal and the angle of reflection and the normal must be equal.

Draw uniform quadratic curve

I'm trying to make a project where the user can draw arrows in a canvas and i need a curved line for that.
As you know one quadratic curve is represented by something like that:
M 65 100 Q 300, 100, 300, 20
Where the first two numbers(65, 100) represents the starting point coordinates, the last two (300,20) represents the ending point coordinates(arrow end).
I need to calculate the middle two numbers based on the first and second point, to make a nice looking curved line.
The first point will have the coordinates from mousedown and the second point from mouseup.
For now i'm using like this.
function addCurve(Ax, Ay, Bx, By){
canvas.add(new fabric.Path('M '+ Ax +' '+ Ay +' Q 100, 100, '+ Bx +', '+ By +'', { fill: '', stroke: 'red' }));
}
addCurve(100,0,200,0);
So, how to calculate the middle point coordinates to get an uniform curve?
I'm also using fabric.js in this project.
First start with the two end points
x1 = ? // start point
y1 = ?
x2 = ? // end point
y2 = ?
To get the mid point
mx = (x1 + x2) / 2;
my = (y1 + y2) / 2;
You will need the vector from first to second point
vx = x2 - x1;
vy = y2 - y1;
The line at 90deg (clockwise or right) from the start and end points is
px = -vy; // perpendicular
py = vx;
The line is the same length as the distance between the two points. The quadratic curve will extend out half the distance that the control point is from the line. So if we want the curve to be 1/4 out by length then half the p vector and add to mid point
cx = mx + px / 2; // get control point
cy = my + py / 2;
If you want the curve to bend the other way
cx = my - px / 2;
cy = my - py / 2;
Or you can write it with the curve amount as a var
var curveAmount = 0.25; // How far out the curve is compared to the line length
cx = my - px * (curveAmount * 2);
cy = my - py * (curveAmount * 2);
Make curveAmount bigger for more curve, smaller for less. Zero for no curve at all and negative to bend the other way.

get rotated top and left coordinates

I want to calculate the rotation of a specific point (top and left). It's a bit complicated. I know the original top and left. Then a scaling is added and then the rotation is calculated.
At the moment i do this. (orginal left:-350, orginal top: -10, f1_scale: 0.544444, rotation angle:-30deg)
function sin(x) {
return Math.sin(x / 180 * Math.PI);
}
function cos(x) {
return Math.cos(x / 180 * Math.PI);
}
function rotate(x, y, a) {
var x2 = cos(a) * x - sin(a) * y;
var y2 = sin(a) * x - cos(a) * y;
return [x2, y2];
}
var scaledLeft = -350 * f1_scale;
var scaledTop = -10 * f1_scale;
var rotateOut = rotate(scaledLeft, scaledTop,-30);
This works for the left (x) coordinate, but the y coordinate is way off.
Can someone see what i did wrong or did someone already tried this?
Thank you.
You need to understand math behind it. First, look at this image http://prntscr.com/amd2it where:
(x0, y0) are coordinates of starting point
(x1, y1) are coordinates after rotation
(p, q) are coordinates of point of rotation
In order to find (x1, y1), you need to know value of (p, q), as well as (x0, y0) and angle a. If we apply elementary geometry, we get this:
sin(a)( q - y0 ) = q - y1
y1 = q - sin(a)( q - y0 )
and
cos(a)( p - x0 ) = p - x1
x1 = p - cos(a)( p - x0 )
or you can use Pythagoras' theorem for second value.
When we understand this, I don't think it will be problem to translate it to code.

SVG: make a gradient to fill the whole shape for every angle given

Given an angle between 0° and 90°, generate a SVG gradient that fills entire rectangle.
SVG gradients accept two control points rather than angle. Here is the code of the first square on the picture above:
<linearGradient x1="0" y1="0" x2="1" y2="0.5">
The problem is that the gradient doesn’t cover the entire square. I want to extend the gradient just enough to fill the shape entirely so the red triangle would be not visible. Here is an interactive demo (tested in Chrome, Firefox and Safari) to give you a better idea.
Solution in JavaScript:
function angleToVector(angle) {
var od = Math.sqrt(2);
var op = Math.cos(Math.abs(Math.PI/4 - angle)) * od;
var x = op * Math.cos(angle);
var y = op * Math.sin(angle);
return {x: x, y: y};
}
For angle between -180° and 180°:
function angleToPoints(angle) {
var segment = Math.floor(angle / Math.PI * 2) + 2;
var diagonal = (1/2 * segment + 1/4) * Math.PI;
var op = Math.cos(Math.abs(diagonal - angle)) * Math.sqrt(2);
var x = op * Math.cos(angle);
var y = op * Math.sin(angle);
return {
x1: x < 0 ? 1 : 0,
y1: y < 0 ? 1 : 0,
x2: x >= 0 ? x : x + 1,
y2: y >= 0 ? y : y + 1
};
}
There might be a simpler solution for this.
So your question as I understand it is this: given a rectangle (whose top left corner is the origin O = (0, 0) and whose bottom right corner is D = (w, h)) and a line l through point O at angle a (with 0° <= a <= 90°), find the point P = (x2, y2) on l such that line DP makes a right angle with l.
If you draw the diagonal of the rectangle, OD, it completes a right triangle with the right angle at P. The angle of that diagonal is atan(h/w), and if you take the absolute difference of that from a (i.e. |atan(h/w) - a|), you'll get the angle in that right triangle at point O. Then you can take the cosine of that angle to get the distance between O and P along l as a proportion of the length of OD (the hypotenuse). You can multiply out the hypotenuse, and then just multiply that by cos(a) and sin(a) to get x2 and y2, respectively.
To summarize:
|OD| = sqrt(w*w + h*h)
|OP| = cos(|atan(h/w) - a|) * |OD|
x2 = |OP| * cos(a)
y2 = |OP| * sin(a)

Projecting points along the surface on a sphere into 2D

I have a number of objects that I am rendering in HTML/CSS/JavaScript. The objects all sit on the surface of an invisible sphere with radius R.
Additionally, the interaction with the user allows this invisible sphere to be rotated arbitrarily.
The obvious solution is spherical co-ordinates assigned to the objects (Theta, Phi, and fixed Radius), which is the converted to Cartesian 3D co-ordinates, and then I can either just drop the depth (Z), or apply some fancy perspective. I will worry about perspective later...
Since I'm working with graphics, X/Y is horizontal/vertical respectively, and Z is depth where +ve is sticking out of the screen and -ve is inside the monitor.
I have a JavaScript array of objects called objects[], each of which has a Theta and Phi. I assume that Theta is rotation about the Y axis, and Phi is rotation about the X axis, such that at Phi = 0 and Theta = 0, we are at (X,Y,Z) = (0,0,R);
Since I'm rotating the invisible sphere, I don't want to have to change the Theta and Phi of each individual objects, which would also just add to numerical instability. Instead, I store a global Theta and Phi which is associated with the rotation of the sphere itself.
Hence, the "effective" Theta and Phi of the points are the Theta and Phi of the points plus the global Theta and Phi.
According to Wikipedia, WolframAlpha, MathWorld, and many other resources, we can find the Cartesian co-ordinates from spherical co-ordinates in the following way:
z = r * sin(phi) * cos(theta);
y = r * sin(phi) * sin(theta);
x = r * cos(phi);
(I've swapped Theta and Phi from Wikipedia as I'm using them backwards, and my X/Y/Z co-ordinates are different too).
I'm not sure why, but when I render these objects they don't look right at all. If you imagine a point on the equator of a sphere with Theta = Pi/4, and you rotate the sphere about the Y axis, the point should only move up and down if projected onto 2D and no perspective transformations are used. However, this isn't at all what happens. The points move from the right to the left side of the screen. The whole thing looks all wrong.
Order matters. When you use your equations
z = r * sin(phi) * cos(theta);
y = r * sin(phi) * sin(theta);
x = r * cos(phi);
then you can interpret them as a rotation first by phi about y and second by theta about x (for appropriate choices of angle measurement directions):
(x1, y1, z1) = (r, 0, 0)
(x2, y2, z2) = (x1 * cos(phi) - z1 * sin(phi),
y1,
x1 * sin(phi) + z1 * cos(phi))
= (r * cos(phi), 0, r * sin(phi))
(x3, y3, z3) = (x2,
y2 * cos(-theta) - z2 * sin(-theta),
y2 * sin(-theta) + z2 * cos(-theta))
= (r * cos(phi),
r * sin(phi) * sin(theta),
r * sin(phi) * cos(theta))
When you simply add those angles, you end up with a wrong order: rotating first by phi1then by theta1 then by phi2 and then by theta2 about the different axes is not the same as rotating by phi1 + phi2 first and theta1 + theta2 afterwards. You're changing the order between theta1 and phi2, which breaks your 3D position.
Better use rotation matrices, quaternions, a library (like three.js) which encapsulates this for you, or make sure you properly combine euler angles.

Categories

Resources