1########################################################################
2##
3## Copyright (C) 2000-2021 The Octave Project Developers
4##
5## See the file COPYRIGHT.md in the top-level directory of this
6## distribution or <https://octave.org/copyright/>.
7##
8## This file is part of Octave.
9##
10## Octave is free software: you can redistribute it and/or modify it
11## under the terms of the GNU General Public License as published by
12## the Free Software Foundation, either version 3 of the License, or
13## (at your option) any later version.
14##
15## Octave is distributed in the hope that it will be useful, but
16## WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with Octave; see the file COPYING.  If not, see
22## <https://www.gnu.org/licenses/>.
23##
24########################################################################
25
26## -*- texinfo -*-
27## @deftypefn  {} {[@var{theta}, @var{r}] =} cart2pol (@var{x}, @var{y})
28## @deftypefnx {} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{x}, @var{y}, @var{z})
29## @deftypefnx {} {[@var{theta}, @var{r}] =} cart2pol (@var{C})
30## @deftypefnx {} {[@var{theta}, @var{r}, @var{z}] =} cart2pol (@var{C})
31## @deftypefnx {} {@var{P} =} cart2pol (@dots{})
32##
33## Transform Cartesian coordinates to polar or cylindrical coordinates.
34##
35## The inputs @var{x}, @var{y} (, and @var{z}) must be the same shape, or
36## scalar.  If called with a single matrix argument then each row of @var{C}
37## represents the Cartesian coordinate (@var{x}, @var{y} (, @var{z})).
38##
39## @var{theta} describes the angle relative to the positive x-axis.
40##
41## @var{r} is the distance to the z-axis @w{(0, 0, z)}.
42##
43## If only a single return argument is requested then return a matrix @var{P}
44## where each row represents one polar/(cylindrical) coordinate
45## (@var{theta}, @var{phi} (, @var{z})).
46## @seealso{pol2cart, cart2sph, sph2cart}
47## @end deftypefn
48
49function [theta, r, z] = cart2pol (x, y, z = [])
50
51  if (nargin < 1 || nargin > 3)
52    print_usage ();
53  endif
54
55  if (nargin == 1)
56    if (! (isnumeric (x) && ismatrix (x)
57           && (columns (x) == 2 || columns (x) == 3)))
58      error ("cart2pol: matrix input must have 2 or 3 columns [X, Y (, Z)]");
59    endif
60    if (columns (x) == 3)
61      z = x(:,3);
62    endif
63    y = x(:,2);
64    x = x(:,1);
65  elseif (nargin == 2)
66    if (! isnumeric (x) || ! isnumeric (y))
67      error ("cart2pol: X, Y must be numeric arrays of the same size, or scalar");
68    endif
69    [err, x, y] = common_size (x, y);
70    if (err)
71      error ("cart2pol: X, Y must be numeric arrays of the same size, or scalar");
72    endif
73  elseif (nargin == 3)
74    if (! isnumeric (x) || ! isnumeric (y) || ! isnumeric (z))
75      error ("cart2pol: X, Y, Z must be numeric arrays of the same size, or scalar");
76    endif
77    [err, x, y, z] = common_size (x, y, z);
78    if (err)
79      error ("cart2pol: X, Y, Z must be numeric arrays of the same size, or scalar");
80    endif
81  endif
82
83  theta = atan2 (y, x);
84  r = sqrt (x .^ 2 + y .^ 2);
85
86  if (nargout <= 1)
87    if (isempty (z))
88      theta = [theta(:), r(:)];
89    else
90      theta = [theta(:), r(:), z(:)];
91    endif
92  endif
93
94endfunction
95
96
97%!test
98%! x = [0, 1, 2];
99%! y = 0;
100%! [t, r] = cart2pol (x, y);
101%! assert (t, [0, 0, 0]);
102%! assert (r, x);
103
104%!test
105%! x = [0, 1, 2];
106%! y = [0, 1, 2];
107%! P = cart2pol (x, y);
108%! assert (P(:,1), [0; pi/4; pi/4], sqrt (eps));
109%! assert (P(:,2), sqrt (2)*[0; 1; 2], sqrt (eps));
110
111%!test
112%! x = [0, 1, 2];
113%! y = [0, 1, 2];
114%! z = [0, 1, 2];
115%! [t, r, z2] = cart2pol (x, y, z);
116%! assert (t, [0, pi/4, pi/4], sqrt (eps));
117%! assert (r, sqrt (2)*[0, 1, 2], sqrt (eps));
118%! assert (z2, z);
119
120%!test
121%! x = [0, 1, 2];
122%! y = 0;
123%! z = 0;
124%! [t, r, z2] = cart2pol (x, y, z);
125%! assert (t, [0, 0, 0], eps);
126%! assert (r, x, eps);
127%! assert (z2, [0, 0, 0]);
128
129%!test
130%! x = 0;
131%! y = [0, 1, 2];
132%! z = 0;
133%! [t, r, z2] = cart2pol (x, y, z);
134%! assert (t, [0, 1, 1]*pi/2, eps);
135%! assert (r, y, eps);
136%! assert (z2, [0, 0, 0]);
137
138%!test
139%! x = 0;
140%! y = 0;
141%! z = [0, 1, 2];
142%! [t, r, z2] = cart2pol (x, y, z);
143%! assert (t, [0, 0, 0]);
144%! assert (r, [0, 0, 0]);
145%! assert (z2, z);
146
147%!test
148%! C = [0, 0; 1, 1; 2, 2];
149%! P = [0, 0; pi/4, sqrt(2); pi/4, 2*sqrt(2)];
150%! assert (cart2pol (C), P, sqrt (eps));
151
152%!test
153%! C = [0, 0, 0; 1, 1, 1; 2, 2, 2];
154%! P = [0, 0, 0; pi/4, sqrt(2), 1; pi/4, 2*sqrt(2), 2];
155%! assert (cart2pol (C), P, sqrt (eps));
156
157%!test
158%! x = zeros (1, 1, 1, 2);
159%! x(1, 1, 1, 2) = sqrt (2);
160%! y = x;
161%! [t, r] = cart2pol (x, y);
162%! T = zeros (1, 1, 1, 2);
163%! T(1, 1, 1, 2) = pi/4;
164%! R = zeros (1, 1, 1, 2);
165%! R(1, 1, 1, 2) = 2;
166%! assert (t, T, eps);
167%! assert (r, R, eps);
168
169%!test
170%! [x, y, Z] = meshgrid ([0, 1], [0, 1], [0, 1]);
171%! [t, r, z] = cart2pol (x, y, Z);
172%! T(:, :, 1) = [0, 0; pi/2, pi/4];
173%! T(:, :, 2) = T(:, :, 1);
174%! R = sqrt (x.^2 + y.^2);
175%! assert (t, T, eps);
176%! assert (r, R, eps);
177%! assert (z, Z);
178
179## Test input validation
180%!error cart2pol ()
181%!error cart2pol (1,2,3,4)
182%!error <matrix input must have 2 or 3 columns> cart2pol ({1,2,3})
183%!error <matrix input must have 2 or 3 columns> cart2pol (ones (3,3,2))
184%!error <matrix input must have 2 or 3 columns> cart2pol ([1])
185%!error <matrix input must have 2 or 3 columns> cart2pol ([1,2,3,4])
186%!error <numeric arrays of the same size> cart2pol ({1,2,3}, [1,2,3])
187%!error <numeric arrays of the same size> cart2pol ([1,2,3], {1,2,3})
188%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), ones (3,2,3))
189%!error <numeric arrays of the same size> cart2pol ({1,2,3}, [1,2,3], [1,2,3])
190%!error <numeric arrays of the same size> cart2pol ([1,2,3], {1,2,3}, [1,2,3])
191%!error <numeric arrays of the same size> cart2pol ([1,2,3], [1,2,3], {1,2,3})
192%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), 1, ones (3,2,3))
193%!error <numeric arrays of the same size> cart2pol (ones (3,3,3), ones (3,2,3), 1)
194