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?
Related
I've seen this function floating around:
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
It works fine for my purposes - determining the absolute X, Y coordinates for the given angle on a circle having centerX, centerY and radius. It works for 360, 0, 180 — all valid SVG values.
Geometry is not my strong suit, but I have not found, nor am I able to write, a function which takes a similar description of the circle, and X, Y coordinates on its circumference (e.g. as output by polarToCartesian), and returns an answer corresponding to angleInDegrees, with no fudging. I am looking for a pair of functions with a 1->1 correspondence.
Math.atan2(Y-centerY, X-centerX) * 180 / Math.PI
gives you angle of point X,Y relative to center.
Note that in your formula (angleInDegrees-90) causes X/Y exchange (like you count angles from vertical axis). If you need this, add 90 to result.
Also atan2 domain is -Pi..Pi (-180..180). If you need only positive angles, add 360 if result is negative.
Seems you need this result:
(Math.atan2(Y-centerY, X-centerX) * 180 / Math.PI + 450) % 360
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 the xy coordinates from before and during a drag event, this.x and this.y```` are the current coordinates,this.lastXandthis.lastY``` are the origin.
What I need to do is given a radian of the source element, determine which mouse coordinate to use, IE if the angle is 0 then the x coordinates is used to give a "distance" if the degrees are 90 then the y coordinates are used
if the radian is 0.785398 then both x and y would need to be used.
I have the following code for one axis, but this only flips the y coordinates
let leftPosition;
if (this.walls[this.dragItem.wall].angle < Math.PI / 2) {
leftPosition = Math.round((-(this.y - this.lastY) / this.scale + this.dragItem.origin.left));
} else {
leftPosition = Math.round(((this.y - this.lastY) / this.scale + this.dragItem.origin.left));
}
I have an example here https://engine.owuk.co.uk
what I need to do is have the radian dictate what x or y coordinate is used to control the drag of the item by calculating the leftPosition, I have been loosing my mind trying to get this to work :(
The Math.sin and Math.cos is what you need, here is an example
<canvas id="c" width=300 height=150></canvas>
<script>
const ctx = document.getElementById('c').getContext('2d');
function drawShape(size, angle, numPoints, color) {
ctx.beginPath();
for (j = 0; j < numPoints; j++) {
a = angle * Math.PI / 180
x = size * Math.sin(a)
y = size * Math.cos(a)
ctx.lineTo(x, y);
angle += 360 / numPoints
}
ctx.fillStyle = color;
ctx.fill();
}
ctx.translate(80, 80);
drawShape(55, 0, 7, "green");
drawShape(45, 0, 5, "red");
drawShape(35, 0, 3, "blue");
ctx.translate(160, 0);
drawShape(55, 15, 7, "green");
drawShape(45, 35, 5, "red");
drawShape(35, 25, 3, "blue");
</script>
Here is a theoretical answer to your problem.
In the simplest way, you have an object within a segment that has to move relative to the position of the mouse, but constrained by the segment's vector.
Here is a visual representation:
So with the mouse at the red arrow, the blue circle needs to move to the light blue.
(the shortest distance between a line and a point)
How do we do that?
Let's add everything we can to that image:
The segment and the mouse form a triangle and we can calculate the length of all sides of that triangle.
The distance between two points is an easy Pythagorean calculation:
https://ncalculators.com/geometry/length-between-two-points-calculator.htm
Then we need the height of the triangle where the base is our segment:
https://tutors.com/math-tutors/geometry-help/how-to-find-the-height-of-a-triangle
That will give us the distance from our mouse to the segment, and we do know the angle by adding the angle of the segment + 90 degrees (or PI/2 in radians) that is all that we need to calculate the position of our light blue circle.
Of course, we will need to also add some min/max math to not exceed the boundaries of the segment, but if you made it this far that should be easy pickings.
I was able to make the solution to my issue
let position;
const sin = Math.sin(this.walls[this.dragItem.wall].angle);
const cos = Math.cos(this.walls[this.dragItem.wall].angle);
position = Math.round(((this.x - this.lastX) / this.scale * cos + (this.y - this.lastY) / this.scale * sin) + this.dragItem.origin.left);
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;
}
So on my canvas I have a large ellipse, and when the user clicks on the canvas a small ellipse should be created on the edge of the large ellipse in the direction of where the click was. The angles are off, and I'm not very confident in the calculations, plus I think the fact that this coordinate system has y increasing when it goes down is screwing it up. Can anyone help me get the desired result?
HTML
<html>
<head>
<script src='processing-1.4.1.min.js'></script>
<script src='jquery-1.9.1.min.js'></script>
</head>
<body>
<canvas id="gamecanvas" data-processing-sources="canvas.pde"></canvas>
</body>
<script>
var gamecanvas = document.getElementById("gamecanvas");
var projectiles = [];
$("#gamecanvas").click(function(e) {
var x = e.clientX - gamecanvas.offsetLeft;
var y = e.clientY - gamecanvas.offsetTop;
var pindex = projectiles.length;
projectiles[pindex] = [];
projectiles[pindex]['angle'] = Math.atan2(y - 200, x - 300) * 180 / Math.PI;
projectiles[pindex]['x'] = 300 + 10 * Math.cos(projectiles[pindex]['angle']);
projectiles[pindex]['y'] = 200 + 10 * Math.sin(projectiles[pindex]['angle']);
});
</script>
</html>
Processing.js Canvas Sketch (Reference)
void draw() {
size(600,400);
background(255,255,255);
fill(#FF0000);
ellipse(300,200,15,15);
for(i = 0;i < projectiles.length;i++) {
ellipse(projectiles[i]['x'],projectiles[i]['y'],2,2);
}
}
You mix radians and degrees here. The JavaScript Math functions that deals with angles needs radian values:
From MDN:
The atan2 method returns a numeric value between -pi and pi
representing the angle theta of an (x,y) point. This is the
counterclockwise angle, measured in radians, between the positive X
axis, and the point (x,y).
And for Math.cos and Math.sin:
A number given in unit of radians.
so you could try with this instead:
/// keep radians, don't convert to degrees
projectiles[pindex]['angle'] = Math.atan2(y - 200, x - 300); // * 180 / Math.PI;
projectiles[pindex]['x'] = 300 + 10 * Math.cos(projectiles[pindex]['angle']);
projectiles[pindex]['y'] = 200 + 10 * Math.sin(projectiles[pindex]['angle']);
Unless you want to keep degrees which in case you need to do this:
projectiles[pindex]['angle'] = Math.atan2(y - 200, x - 300) * 180 / Math.PI;
/// convert degrees back to radians
projectiles[pindex]['x'] =
300 + 10 * Math.cos(projectiles[pindex]['angle'] * Math.PI / 180);
projectiles[pindex]['y'] =
200 + 10 * Math.sin(projectiles[pindex]['angle'] * Math.PI / 180);