User:Devon McCormick/PolarCartesianConversion

From J Wiki
Jump to navigation Jump to search

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).

CirclePtsRect.png CirclePtsPolar.png

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

CirclePtsUniformPolar.png

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