I have a system of vertices with lines connecting them. I measure the angle at each vertex by comparing itself and it's "next" point (the vertices are a doubly linked list).
var next = this.get("next"),
dX = next.get("x") - this.get("x"),
dY = next.get("y") - this.get("y"),
radians = Math.atan2(dY, dX);
When this angle between them hits some threshold, like +/- 2 degrees from a 45 degree... so like 47 degrees and we want to call it 45... I need to move this point to the x,y that would be dictated should it have been 45 degrees. This same thing applies to 135, 90, 180, etc.
I can detect the angle and whether we're within the snap-to-45 zone easy enough, and I know which angle we ought to set it to. What I don't know how to find is the x,y given that new angle.
if(CLOSE_ENOUGH_TO_SNAP) {
newAngle = Math.round(angle / 45) * 45;
this.set({
x: something,
y: something
});
}
So in the below image, this angle ought to snap to 90 and so I ought to be able to calculate a new x,y given that it's 90, not 92.
in psuedocode:
point dif = currentPt - previousPt
float distance = sqrt(dif.x * dif.x + dif.y * dif.y)
float newCurrentX = previousPt.x + distance * cos(newAngle)
floar newCurrentY = previousPt.y + distance * sin(newAngle)
However, if all the new angles are multiples of 45, you could avoid using sin and cos.
For a multiple of 90 degress (or zero degrees),
if (newAngle is 90) newCurrentY = previousPt.y + distance
else if (newAngle is 0) newCurentX = previousPt.x + distance,
etc.
for multiples of 45 degress:
else if (newAngle is 135) {
shift = distance * CONST_SIN_OF_45;
newCurrentX = previousPt.x - shift;
newCurrentY = previousPt.y + shift;
}
Related
I am using the Azure Face API to get the landmarks and rotation angle of a given face. The problem is that all of those points are 2d objects, and I need to rotate them in a 2d space using the yaw, roll and pitch angles of the face.
I have tried to rotate them in the roll angle using this function:
const rotatePoint = (pivotPoint, point, angle) => {
const { x: px, y: py } = pivotPoint;
const { x, y } = point;
var radians = (Math.PI / 180) * angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = cos * (x - px) + sin * (y - py) + px,
ny = cos * (y - py) - sin * (x - px) + py;
return { x: nx, y: ny };
};
Using the center of the FaceRectangle (here you can see it: https://learn.microsoft.com/es-es/azure/cognitive-services/face/images/face.detection.jpg) as pivot point. But I think that the pivot point will only work with a roll rotation. Just imagine a 3d object which is rotated in 3d dimensions. If you have the vertices of this object in a 2d plane, to fully remove the rotation you will need to rotate it in the 3 angles. Correct me if i'm wrong.
Is there any formula to rotate the 2d points in the 3 angles?
I have a circle and I need to know the level of a particular div. For example, I have divided a circle here into 4 pieces. My goal is to find out how many degrees the circled div is at. This so that I can change the color of the background. So for example when a div is between 0 and 90 degrees, the background color should be blue, and from 90 to 180 degrees green. Can this be calculated with javascript?
I myself had already experimented to calculate the difference between the points with the x position and the y position of an object, but unfortunately without success. that looked like this:
handleDrag = (e, ui) => {
var p1 = {
x: ui.x,
y: ui.y
};
var p2 = {
x: ui.x,
y: ui.y
};
// angle in radians
var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
// angle in degrees
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
console.log("graden:"+angleDeg);
}
Anyone have any advice?
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.
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.
I'm making a web page that includes a clock with an arrow in the center. When the user clicks on an hour, the arrow rotates to point to what he/she has clicked.
I'm using a jQuery image rotate plugin (jQueryRotate) to rotate the arrow.
Here is the current code to compute the number of degrees to rotate:
var numTiles = $("ul li").size(); // Number of tiles is however many are listed in the UL, which is 12
var sel = 0; // Default hour selection
var rot = 0; // Default rotation is at the top (0 degrees)
var gap = 360 / numTiles; // Degrees between each tile
function rotateArrow(num) {
rot = num * gap;
$("#arrow").rotateAnimation(rot);
sel = num;
}
When the user clicks one of the hours, it passes num as a value of 1 through 12.
It works fine, but the problem is that if the arrow is pointing to 1 o'clock, and the user clicks 11 o'clock, the arrow rotates clockwise 300 degrees, when it would make more sense to rotate 60 degrees counterclockwise.
So, how can I write an equation to take the current hour (num) and the hour clicked (sel), and output a value as a positive or negative number, which equals the number of degrees to rotate that is most efficient, rather than just rotate only in one direction?
Any advice is appreciated. Let me know if you have any questions. Thanks!
Basically the closest rotation will always be less than 180 degrees, so if your angle is greater than 180, just subtract 360 from it to get the negative angle. Taking your own example, if you end up with 300 degrees, subtract 360 to get -60 degrees.
So to add to your current line of code:
rot = num * gap;
all you need is:
if (rot > 180)
rot -= 360;
This does the rather boring job:
function diff(x, y) {
var a = (x * Math.PI / 180) - Math.PI;
var b = (y * Math.PI / 180) - Math.PI;
return Math.atan2(Math.sin(b - a), Math.cos(b - a)) * (180 / Math.PI);
}
It returns -180 to 180, depending on which rotation will be the shortest.
diff(360, 20)
> 19.999999999999993
diff(20, 360)
> -19.999999999999993
diff(0, 160)
> 160
diff(0, 190)
> -170