JavaScript has an atan2 function, which can be used to find the angle of a vector given its y and x components (in that order). Using Math.atan(y/x)
, you have to deal with ugly edge cases:
x
is zero, meaning the angle is π/2 or -π/2 (that is, unless y
is zero too, in which case the angle can be anything).
y/x
eliminates the distinction between Q1/Q4 and Q3/Q2, meaning you have to see what quadrant the coordinate is in and add/subtract accordingly.
Math.atan2(y, x)
will take care of this for you. I think we should add this to Elm's Prelude next to atan
(I don't have time to put together a patch at the moment). By the way, Haskell has an atan2
function, too, and it works the same way.
Also, we can simplify part of the insideShape
function. Here is the current code:
var angle = 2 * Math.PI * theta;
var t = x === 0 ? (y > 0 ? Math.PI/2 : -Math.PI/2) - angle
: (Math.atan(y/x) + (x > 0 ? 0 : Math.PI)) - angle;
var r = Math.sqrt(x*x + y*y);
x = r * Math.cos(t);
y = r * Math.sin(t);
This appears to rotate x
and y
by -2π * theta
. It turns out there is a much nicer way to rotate vectors: apply a rotation matrix. We don't need atan
at all. The following formula rotates a vector "counter-clockwise" by θ:
x' = x*cos(θ) - y*sin(θ)
y' = x*sin(θ) + y*cos(θ)
When I say "counter-clockwise", I assume a coordinate system where x+ is right and y+ is up. On a computer screen, y+ is down, meaning this will actually rotate clockwise.
In general, when you have foo(bar¯¹(x)) (where foo and bar are trig functions), there's a good chance they cancel into something much nicer.