I'm going to be honest with you all. Since high school ended and I've had a year away from school a lot of the math has been faded out. I am creating this roulettewheel for the page I'm doing at the moment and now I have to calculate the winner from where the ball stops.
The ball has a position of
x = Math.cos(alpha) * radius;
y = Math.sin(alpha) * radius;
Where each slice of the wheel is drawn as following.
var slice = {startAngle: deg2rad(deg), stopAngle: deg2rad(deg+sliceDeg), deg: deg};
ctx.arc(centerX, centerY, width/2, slice.startAngle, slice.stopAngle);
Where the slices are drawn as following
function drawAll(){
ctx.clearRect(0, 0, width, width); //Clear the canvas
for(var i=0; i < locations.length; i++){
drawSlice(deg, color[i]);
deg += sliceDeg;
}
}
So what I am basically trying to understand is how I am to check whether in which of the slices bounds the ball is when it stops. My thesis is that I have to check it as following.
If the angle of the ball(alpha) is within the angle created by slices[i].startAngle and -||-.stopAngle. Get that slice and alert this item. Where I am lost is basically when I am to compare the radians that the slice is represented with the x and y position that the ball is represented with. All help is greatly appreciated.
You can use the function Math.atan2(y, x) to convert cartesian coordinates back into radians.
For instance, Math.atan2(1, 1) yields 0.7853981633974483, which is 45 degrees.
You may need to fiddle with the signs of y and x, if the results seem wrong.
The ball angle is given by
atan2(Y - Cx, X - Cy)
in radians. If the angle is negative, add 2π to be in range [0, 2π).
Then floor(Angle / sliceRad) tells you the slice index.
Related
I am trying to move an object smoothly from point A to point B using HTML canvas and regular javascript.
Point A is a set of coordinates
Point B is in the case the cursor location.
I made a jsfiddle of what I have so far: https://jsfiddle.net/as9fhmw8/
while(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
ctx.save();
ctx.beginPath();
ctx.translate(projectile.x, projectile.y);
ctx.arc(0,0,5,0,2*Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.stroke();
ctx.restore();
if(projectile.mouseX > projectile.x && projectile.mouseY < projectile.y)
{
var stepsize = (projectile.mouseX - projectile.x) / (projectile.y - projectile.mouseY);
projectile.x += (stepsize + 1);
}
if(projectile.mouseY < projectile.y)
{
var stepsize = (projectile.y - projectile.mouseY) / (projectile.mouseX - projectile.x);
projectile.y -= (stepsize + 1);
}
}
Essentially what I can't figure out to do is to make the while loop slower (so that it appears animated in stead of just going through every iteration and showing the result).
I also can't figure out how to prevent the Arc from duplicating so that it creates a line that is permanent, instead of appearing to move from point a to point b.
Smooth animation here is really about determining how far to move your object for each iteration of the loop.
There is a little math involved here, but it's not too bad.
Velocity
Velocity in your case is just the speed at which your particles travel in any given direction over a period of time. If you want your particle to travel 200px over the course of 4 seconds, then the velocity would be 50px / second.
With this information, you can easily determine how many pixels to move (animate) a particle given some arbitrary length of time.
pixels = pixelsPerSecond * seconds
This is great to know how many pixels to move, but doesn't translate into individual X and Y coordinates. That's where vectors come in.
Vectors
A vector in mathematics is a measurement of both direction and magnitude. For our purposes, it's like combining our velocity with an angle (47°).
One of the great properties of vectors is it can be broken down into it's individual X and Y components (for 2-Dimensional space).
So if we wanted to move our particle at 50px / second at a 47° angle, we could calculate a vector for that like so:
function Vector(magnitude, angle){
var angleRadians = (angle * Math.PI) / 180;
this.magnitudeX = magnitude * Math.cos(angleRadians);
this.magnitudeY = magnitude * Math.sin(angleRadians);
}
var moveVector = new Vector(50, 47);
The wonderful thing about this is that these values can simply be added to any set of X and Y coordinates to move them based on your velocity calculation.
Mouse Move Vector
Modeling your objects in this way has the added benefit of making things nice and mathematically consistent. The distance between your particle and the mouse is just another vector.
We can back calculate both the distance and angle using a little bit more math. Remember that guy Pythagoras? Turns out he was pretty smart.
function distanceAndAngleBetweenTwoPoints(x1, y1, x2, y2){
var x = x2 - x1,
y = y2 - y1;
return {
// x^2 + y^2 = r^2
distance: Math.sqrt(x * x + y * y),
// convert from radians to degrees
angle: Math.atan2(y, x) * 180 / Math.PI
}
}
var mouseCoords = getMouseCoords();
var data = distanceAndAngleBetweenTwoPoints(particle.x, particle.y, mouse.x, mouse.y);
//Spread movement out over three seconds
var velocity = data.distance / 3;
var toMouseVector = new Vector(velocity, data.angle);
Smoothly Animating
Animating your stuff around the screen in a way that isn't jerky means doing the following:
Run your animation loop as fast as possible
Determine how much time has passed since last time
Move each item based on elapsed time.
Re-paint the screen
For the animation loop, I would use the requestAnimationFrame API instead of setInterval as it will have better overall performance.
Clearing The Screen
Also when you re-paint the screen, just draw a big rectangle over the entire thing in whatever background color you want before re-drawing your items.
ctx.globalCompositeOperation = "source-over";
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
Putting It All Together
Here is a Fiddle demonstrating all these techniques: https://jsfiddle.net/jwcarroll/2r69j1ok/3/
Here's an image to demonstrate the question:
Let's say I have Point A at [0,0], and Point B at [50, 30]. I want to find the coordinates of Point X, along a circle of radius 15, with an origin at Point A, which is also on a line between Point A and Point B.
Pointers on the best method to do this?
Since this has been tagged JavaScript, here's a simple implementation:
// disclaimer: code written in browser
function Point2D(x, y) {
this.x = x;
this.y = y;
}
function findCircleInteresction(center, radius, target) {
var vector = new Point2D(target.x - center.x, target.y - target.y);
var length = Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2));
var normal = new Point2D(vector.x / length, vector.y / length);
var result = new Point2D(center.x + (normal.x * radius), center.y + (normal.y * radius));
return result;
}
findCircleInteresction(new Point2D(0, 0), 15, new Point2D(50, 30));
Point2D is just a class to make objects with x and y properties.
findCircleInteresction takes three parameters:
- center the center of the circle
- radius the radius of the circle
- target a point outside the circle
In findCircleInteresction:
- calculate the vector between the center and the target
- get the length of the resulting vector
- compute the normal (normalized) of the vector
- find the point where the vector intersects with the circle by adding the center of the circle plus the normalized vector components multiplied by the radius of the circle
This code could be heavily optimized and it's untested but I think it illustrated the idea.
You would want to think of this as two overlapping triangles, one with sides Bx-Ax and By-Ay. What you want is to find the coordinates of X, which would specifically be a triangle with sides Xx-Ax and Xy-Ay but with known hypotenuse R, which is your radius of the circle. Notice that the angle for both triangles are equal in respect to the x-coordinates-axis.
So to get the angle of the triangle, take the arctan(By-Ay/Bx-Ax) Now with that angle, call it T, you can solve for the smaller legs with your know radius R.
To get the x coordinate you would take Rcos(T)
To get the y coordinate you would take Rsin(T)
Bringing it all together you have that Xx = Rcos(T) and Xy = Rsin(T)
If you are not willing to use a Math library, which this method would use, you can use ratio's (as Pointy commented)
I'm kinda confused with this one.
I have an object and I know it's velocities on axis x and y. My problem is how to determine the angle at which it's moving.
function Object(){
this.velocity = {x: 5, y: 1};
}
Basically I Know that a vector's direction is x_projectioncos(deg) + y_projectionsin(deg), but I don't know how to get those projections since I only have the velocity, as I said I'm really confused.
#EDIT:
in addition to the accepted answer, here's what I did to get a full 360 degree spectrum
var addDeg = 0;
if(obj.velocity.x<0)
addDeg = obj.velocity.y>=0 ? 180 : 270;
else if(obj.velocity.y<=0) addDeg = 360;
deg = Math.abs(Math.abs(Math.atan(obj.velocity.y/obj.velocity.x)*180/Math.PI)-addDeg)
I don't know how to get those projections since I only have the
velocity
Actually, what you seem to be missing is that you already have the projections. That's what x and y are.
x is speed * cos(angle)
y is speed * sin(angle)
So y/x = sin(angle)/cos(angle) which is tan(angle) so angle=arctan(y/x).
That's the angle rotating anti-clockwise starting from the x axis (with x pointing right and y pointing up).
Find the angle between that vector and (1,0) (Right horizontal positive direction).
The math is:
A = (5,1)
B = (1,0)
A.B = |A||B|cos(angle) -> angle = arccos((|A||B|)/(A.B))
Dot product, check geometric definition
Edit:
Another option is to use the cross product formula:
|AxB| = |A||B|sin(angle) -> angle = arcsin((|A||B|)/(|AxB|))
It will give you the angle you need.
There is an easier way to get full 360 degrees. What you're looking for, is Math.atan2:
deg = Math.atan2(obj.velocity.y,obj.velocity.x)*180/Math.PI;
I'm working on some coordinates function to my canvas in HTML5, and I want to make a function which can move an object by degrees.
My dream is to make a function which works like this:
box.x=10;
box.y=10;
// now the box has the coordinates (10,10)
moveTheBoxWithThisAmountOfDistance=10;
degreesToMoveTheBox=90;
box.moveByDegrees(moveTheBoxWithThisAmountOfDistance,degreesToMoveTheBox);
// now the box.x would be 20 and box.y wouldn't be changed because
// we only move it to the right (directional 90 degrees)
I hope this makes any sense!
So my question is:
How does the mathematical expression look like when I have to turn a degree into to coordinates?
You use sin and cos to convert an angle and a distance into coordinates:
function moveByDegrees(distance, angle) {
var rad = angle * Math.pi / 180;
this.x += Math.cos(rad) * distance;
this.y += Math.sin(rad) * distance;
}
That's it: http://en.wikipedia.org/wiki/Rotation_matrix , all the math is described :)
Also beware that if you need multiple sequential rotations (i.e. you do continuous animation), it's better to recompute x' and y' from initial ones and not just previous. Not doing so will result in rounding errors accumulation, and after some thousand rotations the result will become too rough.
I'm sorry to say that Math really isn't my strong suit. Normally I can get by, but this has got me totally stumped.
I'm trying to code up a quiz results screen in HTML/CSS/Javascript.
On my interface, I have a semicircle (the right hemisphere of a target).
I have a range of 'scores' (integers out of 100 - so 50, 80, 90 etc.).
I need to plot these points on the semicircle to be n% away from the centre, where n is the value of each score - the higher the score, the closer to the centre of the target the point will appear.
I know how wide my semicircle is, and have already handled the conversion of the % values so that the higher ones appear closer to the centre while the lower ones appear further out.
What I can't wrap my head around is plotting these points on a line that travels out from the centre point (x = 0, y = target height/2) of the target at a random angle (so the points don't overlap).
Any suggestions are gratefully received!
Do you have an example of what you want this to look like? It sounds like you want to divide up the circle into N slices where N is the number of points you need to display, then plot the points along each of those radii. So you might have something like:
Edit: code was rotating about the origin, not the circle specified
var scores = [];
//...
//assume scores is an array of distances from the center of the circle
var points = [];
var interval = 2 * Math.PI / N;
var angle;
for (var i = 0; i < N; i++) {
angle = interval * i;
//assume (cx, cy) are the coordinates of the center of your circle
points.push({
x: scores[i] * Math.cos(angle) + cx,
y: scores[i] * Math.sin(angle) + cy
});
}
Then you can plot points however you see fit.
After much headscratching, I managed to arrive at this solution (with the help of a colleague who's much, much better at this kind of thing than me):
(arr_result is an array containing IDs and scores - scores are percentages of 100)
for (var i = 0; i < arr_result.length; i++){
var angle = angleArray[i]; // this is an array of angles (randomised) - points around the edge of the semicircle
var radius = 150; // width of the semicircle
var deadZone = 25 // to make matters complicated, the circle has a 'dead zone' in the centre which we want to discount
var maxScore = 100
var score = parseInt(arr_result[i]['score'], 10)
var alpha = angle * Math.PI
var distance = (maxScore-score)/maxScore*(radius-deadZone) + deadZone
var x = distance * Math.sin(alpha)
var y = radius + distance * Math.cos(alpha)
$('#marker_' + arr_result[i]['id'], templateCode).css({ // target a specific marker and move it using jQuery
'left' : pointX,
'top': pointY
});
}
I've omitted the code for generating the array of angles and randomising that array - that's only needed for presentational purposes so the markers don't overlap.
I also do some weird things with the co-ordinates before I move the markers (again, this has been omitted) as I want the point to be at the bottom-centre of the marker rather than the top-left.