In my project, I would like to draw a line from point X to point Y.
While I know the position of point X, I only know the angle and the distance of point Y.
So my problem is to get the coordinates of point Y by the angle (from point X) and the distance.
I am using JavaScript for this project and don't want to use any graphical library.
For example:
point X (10;20)
point Y (10° & 200px from point X)
It is probably pretty basic math, but I have no clue how to do it.
js> Math.cos(10*Math.PI/180) * 200 + 10
206.9615506024416
js> Math.sin(10*Math.PI/180) * 200 + 20
54.729635533386066
Y is at (207, 55).
Here is a code snippet that wraps #IgnacioVazquez-Abrams's answer into a function with an example of how to use it:
function findNewPoint(x, y, angle, distance) {
var result = {};
result.x = Math.round(Math.cos(angle * Math.PI / 180) * distance + x);
result.y = Math.round(Math.sin(angle * Math.PI / 180) * distance + y);
return result;
}
var newPoint = findNewPoint(10, 20, 10, 200);
console.log('newPoint:', newPoint);
Related
self.hitBall = function(ball, x, y) {
var angle = Math.atan2((x - ball.centerX), (y - ball.centerY));
ball.velocityY = (Math.sin(angle) * 10);
ball.velocityX = (Math.cos(angle) * 10);
};
So the function takes in the ball, which has a centerX variable and a centerY variabe. The x and y passed into the function is the x and y is the point the ball was hit. I want to make the ball travel in the direction it was hit from.
Not really sure why my code isn't working.. it's behaving very strangely and I'm not that good with trigonometry so I'm not really quite sure why it isn't working.
Two problems with your code:
Math.atan2() takes the arguments in (y, x) order. Most languages (Java, JavaScript, C, etc.) do this (except Microsoft Excel and some others, which use (x, y) order).
When you say "[make] the ball travel in the angle it was hit from", you want to subtract the hit point from the ball point. In other words, the vector is (ball.centerX - hitX, ball.centerY - hitY).
Thus, the solutions:
Solution 1:
var angle = Math.atan2((ball.centerY - y), (ball.centerX - x));
Solution 2 - do vector math without angles (equivalent calculation):
var dx = ball.centerX - x;
var dy = ball.centerY - y;
var norm = Math.sqrt(dx * dx + dy * dy);
ball.velocityX = (dx / norm) * 10;
ball.velocityY = (dy / norm) * 10;
Is there any way in which, in javascript, I can call a function with an x and y co-ord and a direction (angle in degrees) and it will return a set of new co-ords that has been 'moved' by 10px in the direction given from the original co-ords? I looked around but all I can find is ways to get the angle of two given co-ords.
This function returns an array [xCoord, yCoord] of the new coordinates:
function myFunction(xCoord, yCoord, angle, length) {
length = typeof length !== 'undefined' ? length : 10;
angle = angle * Math.PI / 180; // if you're using degrees instead of radians
return [length * Math.cos(angle) + xCoord, length * Math.sin(angle) + yCoord]
}
I just wanted to point out, that the answers of are not correct IMHO. I've created a JSFiddle showing that the correct implementation must be something like this:
function getRelativeVector(angle, length, xOffset, yOffset) {
angle = angle * Math.PI / 180;
return {
X:length * Math.sin(angle) + xOffset,
Y:length * Math.cos(angle) + yOffset
};
}
The other solutions shown here from #Audrius and #Markus are simply twisted in cos and sin. They are working for angles between 0 and 45 degrees only.
The formula would be:
X = length * sin(angle) + xLocation
Y = length * cos(angle) + yLocation
The shift in x coordinate is L*cos(a) and shift in y coordinate is L*sin(a), where a is the angle ("direction given") and L is 10 px in your case.
I'm working on a library for canvas, and I can't figure out how I should be doing rotations around the center of an object. Below is the function I'm using to render them currently and an example object I'm giving it.
I feel there is a better way to do the 4 if statements, but I can't figure out the math for it. Currently I am taking each "pixel" of the object and rotating it around the center, but I can't see room for expansion. What am I doing wrong?
//Rendering function
Display.prototype.renderObject = function(object, direction) {
if (typeof object.rotation !== 'number') object.rotation = 0;
for (x=0;x<object.bounds.x;x++) {
for (y=0;y<object.bounds.y;y++) {
rotation = 45;
if (x==0 && y==0) rotation += 0;
if (x==0 && y==1) rotation += 90;
if (x==1 && y==0) rotation += 270;
if (x==1 && y==1) rotation += 180;
display.drawRect(object.color[x][y],
(display.width/2) - (players[playerIndex].position.x * 16) + (object.position.x * 16) - (object.bounds.x * object.scale)/4 - (object.bounds.x/3 * object.scale * Math.cos((object.rotation+rotation)*(Math.PI/180))),
(display.height/2) + (players[playerIndex].position.y * 16) - (object.position.y * 16) - (object.bounds.y * object.scale)/4 - (object.bounds.y/3 * object.scale * Math.sin((object.rotation+rotation)*(Math.PI/180))),
object.scale, object.scale, object.rotation * (direction || 1));
}
}
};
// Example object
block = {
"color": [
["#FFF","#CCC"], // Some colors to make
["#999","#666"] // a shaded illusion
],
"position": {
"x": 0,
"y": 0
},
"bounds": {
"x": 2, // color[0].length
"y": 2 // color.length
},
"rotation": 0, // 0 to 360
"scale": 4 // real pixels per object pixel
}
// Example usage
Display.renderObject(block);
- edit -
Maybe I need to have it calculate where each pixel's center coordinates would be, then get the distance from that to the origin of the object and the rotation each pixel would be offset at.
If x = 0 and y = 0, then it's +45 degrees with sin and -45 degrees with cos+45 degrees with sin. If (object.bounds.x-1)/2 gives us the center coords for dealing with x, then Math.sqrt(Math.pow(x,2)+Math.pow(y,2)) gives us the radius for the color block from the center of the object. I'm not sure where to go from there.
I am not 100% sure of what you're asking, but if it is how to rotate points around the points' center you have to translate all your points so that you object to rotate is centered around origin or point [0, 0] if you like.
A rotation matrix always rotates around origin so there is no way around (no pun intended).
So before you rotate your points calculate a delta value that you apply before the rotation, rotate and then reverse the delta and apply again to get the object back with its offset relative to origin.
So first step is to calculate the delta to find out how much you need to translate the points to get them into center.
For a rectangle it is easy: it is its x and y position plus half of its width and height:
deltaX = x + width * 0.5;
deltaY = y + height * 0.5;
This value you then need to subtract to the points. How you apply this delta is up to you: you can do it in advance with each point or inject it directly into the formula.
Then rotate and when done you simply apply add the delta value to each point again.
Here is a shorter version of a rotation matrix based on my article here:
var a = rotation * Math.PI / 180; /// calculate angle once
x -= deltaX; /// apply pre-translation
y -= deltaY;
/// rotate and apply post-translation
nx = x * Math.cos(a) + y * Math.sin(a) + deltaX;
ny = y * -Math.sin(a) + x * Math.cos(a) + deltaY;
The ifs you're using seem to come from code that use this for optimizations of the angles; when you use 0, 90 etc. as cos and sin would produce 1 and 0 respectively. You are however not utilizing this optimization as you could simply swap x for y etc. when these cases occurs. However, you bind then to x and y position so I am not sure what you try to achieve here..
I would suggest you just remove them as you calculate and applies sin/cos anyways - you could instead cache the sin and cos and use those for all the points:
var angle = rotation * Math.PI / 180;
sin = Math.sin(angle),
cos = Math.cos(angle),
...calc deltas here...
...enter loop here, then for each point:...
x -= deltaX;
y -= deltaY;
nx = x * cos + y * sin + deltaX;
ny = y * -sin + x * cos + deltaY;
Now the cost is lower for each point and your calculations will perform faster.
Hope this helps.
I am not so familiar trigonometry, but I have only two points to rotate in 2D:
*nx, ny
. -
. -
. angle -
*cx,cy.................*x,y
cx, cy = rotation center
x,y = current x,y
nx, ny = new coordinates
How to calculate new points in a certain angle?
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return [nx, ny];
}
The first two parameters are the X and Y coordinates of the central point (the origin around which the second point will be rotated). The next two parameters are the coordinates of the point that we'll be rotating. The last parameter is the angle, in degrees.
As an example, we'll take the point (2, 1) and rotate it around the point (1, 1) by 90 degrees clockwise.
rotate(1, 1, 2, 1, 90);
// > [1, 0]
Three notes about this function:
For clockwise rotation, the last parameter angle should be positive. For counterclockwise rotation (like in the diagram you provided), it should be negative.
Note that even if you provide arguments that should yield a point whose coordinates are whole numbers -- i.e. rotating the point (5, 0) by 90 degrees about the origin (0, 0), which should yield (0, -5) -- JavaScript's rounding behavior means that either coordinate could still be a value that's frustratingly close to the expected whole number, but is still a float. For example:
rotate(0, 0, 5, 0, 90);
// > [3.061616997868383e-16, -5]
For this reason, both elements of the resulting array should be expected as a float. You can convert them to integers using Math.round(), Math.ceil(), or Math.floor() as needed.
Finally, note that this function assumes a Cartesian coordinate system, meaning that values on the Y axis become higher as you go "up" in the coordinate plane. In HTML / CSS, the Y axis is inverted -- values on the Y axis become higher as you move down the page.
First, translate the rotation center to the origin
Calculate the new coordinates (nx, ny)
Translate back to the original rotation center
Step 1
Your new points are
center: (0,0)
point: (x-cx, y-cy)
Step 2
nx = (x-cx)*cos(theta) - (y-cy)*sin(theta)
ny = (y-cy)*cos(theta) + (x-cx)*sin(theta)
Step 3
Translate back to original rotation center:
nx = (x-cx)*cos(theta) - (y-cy)*sin(theta) + cx
ny = (y-cy)*cos(theta) + (x-cx)*sin(theta) + cy
For deeper explanation, with some fancy diagrams, I recommend looking at this.
above accepted answer not work for me correctly, rotation are reversed , here is working function
/*
CX # Origin X
CY # Origin Y
X # Point X to be rotated
Y # Point Y to be rotated
anticlock_wise # to rotate point in clockwise direction or anticlockwise , default clockwise
return # {x,y}
*/
function rotate(cx, cy, x, y, angle,anticlock_wise = false) {
if(angle == 0){
return {x:parseFloat(x), y:parseFloat(y)};
}if(anticlock_wise){
var radians = (Math.PI / 180) * angle;
}else{
var radians = (Math.PI / -180) * angle;
}
var cos = Math.cos(radians);
var sin = Math.sin(radians);
var nx = (cos * (x - cx)) + (sin * (y - cy)) + cx;
var ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return {x:nx, y:ny};
}
According to Polar coordinate system artycle on Wikipedia:
x = r * cos(deg)
y = r * sin(deg)
r (radius) is equal to distance between Rotation Centre and Rotated Point
deg (degrees) is angle measured in degrees
I think it is better to use matrices for such operations.
Here is the example with gl-matrix (but you can use something like THREEJS as well).
import * as glm from 'gl-matrix';
const rotateVector = (() => {
const q = glm.quat.create();
// const m = glm.mat4.create(); // 2nd way
return (v: glm.vec3, point: glm.vec3, axis: glm.vec3, angle: number) => {
glm.quat.setAxisAngle(q, axis, angle);
// glm.mat4.fromRotation(m, angle, axis); // 2nd way
glm.vec3.sub(v, v, point);
glm.vec3.transformQuat(v, v, q);
// glm.vec3.transformMat4(v, v, m); // 2nd way
glm.vec3.add(v, v, point);
return v;
}
})();
In 2D case you need to rotate around z-axis:
rotateVector([x, y, 0], [cX, cY, 0], [0, 0, 1], angleInRadians);
I have a javascript Matrix class for affine transforms, and a function to set the rotation to an absolute number of radians, around a given center:
this.setRotation = function (radians, center) {
var cos = Math.cos(radians);
var sin = Math.sin(radians);
this.a = cos;
this.b = sin;
this.c = -sin;
this.d = cos;
this.tx += center.x - center.x * cos + center.y * sin;
this.ty += center.y - center.x * sin - center.y * cos;
}
I'm trying to rotate around the center of the object itself, so I'm passing in a center point of half the object's width, and half its height, so for a 100 x 100 object I'm passing in 50, 50.
If my object starts from a rotation of zero, this works fine:
... but if I rotate the shape again, or start with a rotation of other than zero, the tx and ty values end up wrong:
What's wrong with my formula above? Setting the rotation seems to be accurate, but not the tx and ty.
I have seen a few other questions on this subject, in particular this one, but nothing that has helped.
Update To add some numbers to this:
If I begin with a 100x100 rectangle, positioned at 100,100, then my initial matrix is: {Matrix: [a:1, b:0, c:0, d:1, tx:100, ty:100]}
To rotate this clockwise 45 degrees, I feed the above function 0.7853981633974483 (45 degrees in radians), and the center: {Point: [x:50, y: 50]}
This produces the following matrix:
{Matrix: [a:0.7071067812, b:0.7071067812, c:-0.7071067812, d:0.7071067812, tx:150, ty:79.28932188]} which is exactly right.
But if I then start with that matrix, and try to return it to zero, by feeding the function arguments of 0 and {Point: [x:70.71067812000001, y: 70.71067812000001]} (the center of the new, rotated shape), then the output is {Matrix: [a:1, b:0, c:0, d:1, tx:150, ty:79.28932188]}, which is the correct rotation but not the correct translation. I'm expecting to get {Matrix: [a:1, b:0, c:0, d:1, tx:100, ty:100]}
I've tried several other variants of the function, including using the center of the rectangle in the parent coordinate space 150,150 instead of the local center of 50,50, and replacing += with = as suggested below, but nothing seems to help. If I comment out the tx calculation then my shape rotates beautifully around it's origin, so the issue must be either with the tx/ty calculation, or with the center point that I'm passing in.
Does anyone have any further ideas?
Apart from possibly an incorrect sign (although that depends on the direction of your coordinate axes), I think the problem is simply that you're using += instead of = when you fill in the tx and ty portions of your affine matrix.
My problem was to do with getting the object back to the origin - removing the top left coordinates as well as half the height and width before rotating, then adding them back again.
I found it easier to use a rotate function than a setRotate function, and ended up with the following code:
// Matrix class functions:
this.rotate = function (radians) {
var cos = parseFloat(Math.cos(radians).toFixed(10));
var sin = parseFloat(Math.sin(radians).toFixed(10));
a = this.a,
b = this.b,
c = this.c,
d = this.d,
tx = this.tx,
ty = this.ty;
this.a = a * cos - b * sin;
this.b = a * sin + b * cos;
this.c = c * cos - d * sin;
this.d = c * sin + d * cos;
this.tx = tx * cos - ty * sin;
this.ty = tx * sin + ty * cos;
}
this.setRotation = function (radians) {
var rotation = this.rotation();
this.rotate(radians - rotation);
}
this.translate = function (tx, ty) {
this.tx += tx;
this.ty += ty;
}
// Called from outside the class
var transformedBounds = pe.Model.ReadTransformedBounds(selection[0]);
var itemTransform = pe.Model.ReadItemTransform(selection[0]);
// Cache the coordinates before translating them away:
var ox = transformedBounds.Left + (transformedBounds.Width / 2);
var oy = transformedBounds.Top + (transformedBounds.Height / 2);
itemTransform.translate(-ox, -oy);
// Rotate:
itemTransform.setRotation(radians);
// Restore the translation:
itemTransform.translate(ox, oy);
All of which is probably pretty obvious if you can actually do sums, but I post it here in case anyone has a day as dim as mine...