User:Devon McCormick/PolarCartesianConversion
Basic Two-Dimensional Conversion
Here's how to convert between polar and cartesian (rectangular) co-ordinates (2-D only):
p2c=: +. @ r./ NB.* p2c: polar to cartesian (2D) co-ordinates c2p=: ({.,2p1&|@{:) @: *. @ j./ NB.* c2p: cartesian to polar (2D) co-ordinates
(thanks to John Randall for his help getting this correct.) The unusual spacing is to highlight the similarities between the expressions. The first part of the function "c2p" forces the angle to be in the range to since a polar co-ordinate allows multiple representations of the same point.
To better understand these phrases, you can look up real and imaginary parts, polar and conjugate verbs.
Naturally, these are inverses of each other:
c2p 1 1 1.4142136 0.78539816 NB. square root of 2, one-quarter pi p2c c2p 1 1 1 1
However, it might make more sense to work with the native J types for these, e.g.
1ar0.5 NB. radius 1, angle 0.5 radians 0.87758256j0.47942554 1.4142136ar0.78539816 1j1
The only advantage of using point pairs is that they are (potentially) generalizable to more than two dimensions - see Multi-Dimensional Conversion below.
These conversions appear to work in each of the four quadrants:
]pts=. 0 0-.~_1 0 1{~3 3#:i.3^2 _1 _1 _1 0 _1 1 0 _1 0 1 1 _1 1 0 1 1 c2p"1 pts 1.4142136 3.9269908 1 3.1415927 1.4142136 2.3561945 1 4.712389 1 1.5707963 1.4142136 5.4977871 1 0 1.4142136 0.78539816 p2c"1 c2p"1 pts _1 _1 _1 1.2246468e_16 _1 1 _1.8369702e_16 _1 6.123234e_17 1 1 _1 1 0 1 1 pts-:1e_12 roundNums p2c"1 c2p"1 pts NB. Round to dismiss floating-point imprecision 1
I had a problem with this initially until JR supplied the fix to c2p to ensure that any angle is mapped into the range to .
Example Use
We can use one of these functions if we want to pick points randomly and uniformly on the unit circle. The problem with a naïve approach whereby we pick random x-values, then derive the corresponding y-values from the equation for the circle (1 = x^2^ + y^2^ ), can be seen here.
(<./,>./) xs=. <:+:?2000$0 NB. Random X-values from _1 to 1 _0.99923839 0.99951104 ys=. ys*_1 1{~?2$~#ys=. 0 o. xs NB. Y-values with random signs 1 *./ . = (*:xs)+*:ys NB. Confirm that 1=(x^2)+y^2 1 'title Points on a Circle: Rectangular Generation;type point;pensize 3' plot xs;ys
Note the sparsity of points on the right and left poles of the circle, in the first picture below, because the uniform distribution of x-values fails to fill in the steep portion of the circle (where the Y-values change rapidly).
However, if we choose random points with polar co-ordinates and convert them to cartesian, we get a more uniform distribution as we can see in the second picture above:
'pxs pys'=. |:p2c"1 ] 1,._1p1+2p1*?2000$0 1 *./ . = (*:pxs)+*:pys NB. Confirm that 1=(x^2)+y^2 1 'title Points on a Circle: Polar Generation;type point;pensize 3' plot pxs;pys
However, even this second picture is a little spotty, so why not simply pick points evenly? This is easy to do using polar co-ordinates - the result is shown in the picture below:
'pxs pys'=. |:p2c"1 ] 1,._1p1+2p1*2000%~i.2000 NB. Uniform distribution 1 *./ . = (*:pxs)+*:pys NB. Confirm that 1=(x^2)+y^2 1 'title Points on a Circle: Uniform Polar;type point;pensize 3' plot pxs;pys
Multi-Dimensional Conversion
I'm sure there's a neater way to accomplish this without the explicit loop but at least this appears to be correct. To handle the multi-dimensional conversion, we can convert two dimensions at a time thusly:
NB.* c2pmd: cartesian to polar multi-dimensional coords. c2pmd=: 3 : 0 'rad ang'=. c2p 2{.y for_newd. 2}. y do. 'rad aa'=. c2p rad,newd ang=. ang,aa end. rad,ang ) NB.* p2cmd: polar to cartesian multi-dimensional coords. p2cmd=: 3 : 0 'c0 cc'=. p2c 0 _1{y for_newd. |.}.}:y do. 'c0 nxtc'=. p2c c0,newd cc=. nxtc,cc end. c0,cc )
I tested this on a few simple cases:
c2pmd 1 1 1 1.7320508 0.78539816 0.61547971 c2pmd 1 2 3 3.7416574 1.1071487 0.93027401 %:14 3.7416574 p2cmd c2pmd 1 1 1 1 1 1 p2cmd c2pmd 1 2 3 1 2 3 p2cmd c2pmd 1 _1 2 _2 1 _1 2 _2