How do you compare radians in a circle? - javascript

I'm thinking of a wheel of fortune type of thing where you have to check if a marker lands on a slot. Visually, we can see 0, 2pi, 4pi, etc... are in the same position. How do I check if 0 is equal to 2pi/4pi programmatically? Assuming I have the radius as well, I thought, maybe I have to convert it to cartesian coordinates first and then compare it. However, is there a better way to do this?
Edit: Also, I should make clear that the mark can land anywhere in between a slot. For example, the marker could be anywhere in between 0 to pi/6.

Is this what you want?
var smallestEquivalentValueInRadians = originalValueInRadians % (2 * Math.PI);
If you want to compare, you can do:
a % (2 * Math.PI) === b % (2 * Math.PI)
% is the modulo operator, basically it subtracts the second operand from the first, as many times as it can (assuming you are dealing with positive numbers).
To cater for negative values:
function normalizeRadian(a) {
var circle = Math.PI * 2;
a = a % circle;
if (a < 0) {
a += circle;
}
return a;
}
Also when comparing floats, it's a good idea to have some "fuzzyness", since opperations on them can be imprecise.
function fuzzyEqual(a, b) {
var fuzz = 0.001;
return a < b + fuzz && a > b - fuzz;
}
So the complete solution is:
function fuzzyEqualRadians(a, b) {
return fuzzyEqual(normalizeRadian(a), normalizeRadian(b));
}

Related

Figuring out the value for PI

Let's say I have a function called bars()
bars () {
const bars = []
for (let i = 0; i < this.numberOfBars; i++) {
bars.push(Math.sqrt(this.numberOfBars * this.numberOfBars - i * i))
}
return bars
}
If I'm reducing the bars array to approximate PI, what should be on the right side of the arrow function?
PI = bars().reduce((a, b) =>
I tried adding the values and dividing by the number of bars, but I'm not getting anywhere near the approximation of Pi. I feel like there's a simple trick that I'm missing.
Your funcion seems to list lengths of "bars" in a quarter of a circle, so we have to add them all up (to have the area of the quarter of a circle), then multiply by 4 (because there is 4 quarter) and the divide by this.numberOfBars ^ 2 because area = π * r^2, but like we have to know the radius, it is better using a pure function :
// Your function rewritten as a pure one
const bars = numberOfBars => {
const bars = []
for (let i = 0; i < numberOfBars; i++) {
bars.push(Math.sqrt(numberOfBars * numberOfBars - i * i))
}
return bars
}
// Here we take 1000 bars as an example but in your case you replace it by this.numberOfBars
// Sum them all up, multiply by 4, divide by the square of the radius
const PI = bars(1000).reduce((g, c) => g + c) * 4 / Math.pow(1000, 2)
console.log(PI)
/** Approximates PI using geometry
* You get a better approximation using more bars and a smaller step size
*/
function approximatePI(numberOfBars, stepSize) {
const radius = numberOfBars * stepSize;
// Generate bars (areas of points on quarter circle)
let bars = [];
// You can think of i as some point along the x-axis
for (let i = 0; i < radius; i += stepSize) {
let height = Math.sqrt(radius*radius - i*i)
bars.push(height * stepSize);
}
// Add up all the areas of the bars
// (This is approximately the area of a quarter circle if stepSize is small enough)
const quarterArea = bars.reduce((a, b) => a + b);
// Calculate PI using area of circle formula
const PI = 4 * quarterArea / (radius*radius)
return PI;
}
console.log(`PI is approximately ${approximatePI(100_000, 0.001)}`);
There is no reason to push all terms to an array, then to reduce the array by addition. Just use an accumulator variable and add all terms to it.
Notice that the computation becomes less and less accurate the closer you get to the end of the radius. If you sum to half of the radius, you obtain r²(3√3+π)/24, from which you can draw π.
(Though in any case, this is one of the worst methods to evaluate π.)

Javascript: Set variable to either 1 or -1

I'm trying to get an object that moves in a different direction when you click on it, and each time you click on it it goes faster. I have it almost functioning, but I can't get the program to exclude 0 or do only -1 or 1; I can only do a random number between -1 and 1. This means that if it hits zero, it can't progress.
(The following code is built with a Javascript engine called "Crafty". Non-javascript parts are commented as best as I can.)
Crafty.init(400,320, document.getElementById('game')); // Creates canvas
// Create variables
var speed = 10;
var min = -1;
var max = 1;
// Create a 32px by 32px red box
var square = Crafty.e('2D, Canvas, Color, Mouse, Motion')
.attr({x: 50, y: 50, w: 32, h: 32})
.color('red')
// When the red box is clicked, move it in a random direction. Make it go faster each time.
.bind('Click', function(MouseEvent){
speed *= 2;
var vel = square.velocity();
var direction = ((Math.random() * (max - min)) + min);
vel.x;
vel.y;
vel.x = (speed *= direction);
vel.y = (speed *= direction);
});
Change to this line
var direction = (Math.random()) > .5 ? 1 : -1;
It really comes down to this line:
var direction = ((Math.random() * (max - min)) + min);
If you store the acceptable values (-1 and 1) in an array, you can make the random choose one of those based on the length of the array. By storing the values in an array, you not only make the process simpler, but it is extensible because you can always add new values later, if desired.
function getRandom(){
var acceptable = [-1, 1];
// Get a random number from 0 to 1 (the length of the array, 2, will never be reached)
var direction = Math.floor(Math.random() * acceptable.length);
console.log(acceptable[direction]); // Choose either array element 0 or element 1
}
// Run this code snippet a few times and you'll see that you only get -1 and 1
getRandom();
getRandom();
getRandom();
getRandom();
You can also remove the two lines declaring the max and min variables as they are no longer needed.

Calculate minimum value not between set of ranges

Given an array of circles (x,y,r values), I want to place a new point, such that it has a fixed/known Y-coordinate (shown as the horizontal line), and is as close as possible to the center BUT not within any of the existing circles. In the example images, the point in red would be the result.
Circles have a known radius and Y-axis attribute, so easy to calculate the points where they intersect the horizontal line at the known Y value. Efficiency is important, I don't want to have to try a bunch of X coords and test them all against each item in the circles array. Is there a way to work out this optimal X coordinate mathematically? Any help greatly appreciated. By the way, I'm writing it in javascript using the Raphael.js library (because its the only one that supports IE8) - but this is more of a logic problem so the language doesn't really matter.
I'd approach your problem as follows:
Initialize a set of intervals S, sorted by the X coordinate of the interval, to the empty set
For each circle c, calculate the interval of intersection Ic of c with with the X axis. If c does not intersect, go on to the next circle. Otherwise, test whether Ic overlaps with any interval(s) in S (this is quick because S is sorted); if so, remove all intersecting intervals from S, collapse Ic and all removed intervals into a new interval I'c and add I'c to S. If there are no intersections, add Ic to S.
Check whether any interval in S includes the center (again, fast because S is sorted). If so, select the interval endpoint closest to the center; if not, select the center as the closest point.
Basically the equation of a circle is (x - cx)2 + (y - cy)2 = r2. Therefore you can easily find the intersection points between the circle and X axis by substituting y with 0. After that you just have a simple quadratic equation to solve: x2 - 2cxx + cx2 + cy2 - r2 = 0 . For it you have 3 possible outcomes:
No intersection - the determinant will be irrational number (NaN in JavaScript), ignore this result;
One intersection - both solutions match, use [value, value];
Two intersections - both solutions are different, use [value1, value2].
Sort the newly calculated intersection intervals, than try merge them where it is possible. However take in mind that in every program language there approximation, therefore you need to define delta value for your dot approximation and take it into consideration when merging the intervals.
When the intervals are merged you can generate your x coordinates by subtracting/adding the same delta value to the beginning/end of every interval. And lastly from all points, the one closest to zero is your answer.
Here is an example with O(n log n) complexity that is oriented rather towards readability. I've used 1*10-10 for delta :
var circles = [
{x:0, y:0, r:1},
{x:2.5, y:0, r:1},
{x:-1, y:0.5, r:1},
{x:2, y:-0.5, r:1},
{x:-2, y:0, r:1},
{x:10, y:10, r:1}
];
console.log(getClosestPoint(circles, 1e-10));
function getClosestPoint(circles, delta)
{
var intervals = [],
len = circles.length,
i, result;
for (i = 0; i < len; i++)
{
result = getXIntersection(circles[i])
if (result)
{
intervals.push(result);
}
}
intervals = intervals.sort(function(a, b){
return a.from - b.from;
});
if (intervals.length <= 0) return 0;
intervals = mergeIntervals(intervals, delta);
var points = getClosestPoints(intervals, delta);
points = points.sort(function(a, b){
return Math.abs(a) - Math.abs(b);
});
return points[0];
}
function getXIntersection(circle)
{
var d = Math.sqrt(circle.r * circle.r - circle.y * circle.y);
return isNaN(d) ? null : {from: circle.x - d, to: circle.x + d};
}
function mergeIntervals(intervals, delta)
{
var curr = intervals[0],
result = [],
len = intervals.length, i;
for (i = 1 ; i < len ; i++)
{
if (intervals[i].from <= curr.to + delta)
{
curr.to = Math.max(curr.to, intervals[i].to);
} else {
result.push(curr);
curr = intervals[i];
}
}
result.push(curr);
return result;
}
function getClosestPoints(intervals, delta)
{
var result = [],
len = intervals.length, i;
for (i = 0 ; i < len ; i++)
{
result.push( intervals[i].from - delta );
result.push( intervals[i].to + delta );
}
return result;
}
create the intersect_segments array (normalizing at x=0 y=0)
sort intersectsegments by upperlimit and remove those with upperlimit<0
initialize point1 = 0 and segment = 0
loop while point1 is inside intersectsegment[segment]
4.1. increment point1 by uppper limit of intersectsegment[segment]
4.2. increment segment
sort intersectsegments by lowerlimit and remove those with loerlimit>0
initialize point2 = 0 and segment = 0
loop while point2 is inside intersectsegments[segment]
7.1. decrement point2 by lower limit of segment
7.2. decrement segment
the point is minimum absolute value of p1 and p2

Getting the closest point in a direction in JavaScript

Lets say I have a 2D coordinate system with lots of Rects on it. Take this as an example representation. I now want to get the nearest next element in a given direction. Lets use this image as an example:
S defines the element at which I currently am. If I press up I should now be at the closest element in upwards direction which is A. My current approach was something like this:
Distance = abs((S.x-A.x)+(S.y-A.y);
Angle = abs(atan2((A.y - S.y), (A.x - S.x)) * 180 / Math.PI);
Score = Distance + abs(DirectionAngle-Angle)
Then I choose the candidate based on the lowest score. Now there are multiple problems:
Iteration happens for ALL elements, not only those upwards. The elements are not considered if they're in the opposite direction but the elements to the left and right are still in the calculation.
If A for some reason extends 3 more pieces to the left it won't work anymore and B is selected.
So what I need is a solution to only iterate over elements in the direction AND a smart solution to only select the closest element and then stop and return the element.
Btw. the elements are actually divs so canvas is not an option.
Might this giant overkill example help?
You can find it here: http://jsfiddle.net/Icepickle/Cu88x/
where i first determine the position of the clicked element, get all elements matching a certain direction (check if the point is inside the rectangle)
var offset = helper.offset(element),
rect = new helper.simpleRect(offset.left - (3 * 20), offset.top - (3 * 20), 6 * 20, 6 * 20),
left = getElements(DIRECTION.LEFT, element, rect),
right = getElements(DIRECTION.RIGHT, element, rect),
up = getElements(DIRECTION.UP, element, rect),
down = getElements(DIRECTION.DOWN, element, rect);
and then calculate the distance between the elements that already match the direction (in case 2 are the same distance away, they also get highlighted as the closest):
function highlightClosest(arr, direction, rect) {
var i = 0, l = arr.length, min = 10000, el, minScoreElement = [], o, a, b, c;
for (i = 0; i < l; i++) {
el = arr[i];
o = helper.offset(el);
a = Math.abs(o.left - rect.center.left);
b = Math.abs(o.top - rect.center.top);
c = (a * a) + (b * b);
if (c < min) {
min = c;
minScoreElement = [el];
} else if (c == min) {
minScoreElement.push(el);
}
}
if (minScoreElement) {
for (i = 0; i < minScoreElement.length; i++) {
minScoreElement[i].className = direction;
}
}
}

Quadratic function for increment speedup of countup

I'm writing a jQuery plugin for fast-counting up to a value when a page loads. Since javascript can't run as fast as I want it to for larger numbers, I want to increase the increment step so that it completes within a given timeframe, so I'd need a quadratic function that passes through origo and has it's turning point at y = target counting value and x = target duration, but I can't get a grip on the math for doing this. Since both the number and the duration can change, I need to be able to calculate it in javascript aswell.
Hopefully someone can help me with this one!
Let's formalize the statement a bit.
We seek an equation of the form
y = a*x*x + b*x + c
where x is the time axis and y is a count axis. We know that one point on the curve is (0,0) and another point is (xf, yf) where xf is the final time and yf is the target count. Further, you wish for the derivative of this equation to be zero at (xf, yf).
y' = 2*a*x + b
So I have three equations and three unknowns:
(0,0) => 0 = c
(xf, yf) => yf = a*xf*xf + b*xf + c
y' = 0 # (xf, yf) => 0 = 2*a*xf + b
You should be able to solve it from there.
// Create a quadratic function that passes through origo and has a given extremum.
// x and y are the coordinates for the extremum.
// Returns a function that takes a number and returns a number.
var quadratic = function (x, y) {
var a = - (y / (x * x));
var b = (2 * y) / x;
return function (x) {
return a * x * x + b * x;
};
};

Categories