xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Math/Trig.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gate#
2*0Sstevel@tonic-gate# Trigonometric functions, mostly inherited from Math::Complex.
3*0Sstevel@tonic-gate# -- Jarkko Hietaniemi, since April 1997
4*0Sstevel@tonic-gate# -- Raphael Manfredi, September 1996 (indirectly: because of Math::Complex)
5*0Sstevel@tonic-gate#
6*0Sstevel@tonic-gate
7*0Sstevel@tonic-gaterequire Exporter;
8*0Sstevel@tonic-gatepackage Math::Trig;
9*0Sstevel@tonic-gate
10*0Sstevel@tonic-gateuse 5.006;
11*0Sstevel@tonic-gateuse strict;
12*0Sstevel@tonic-gate
13*0Sstevel@tonic-gateuse Math::Complex qw(:trig);
14*0Sstevel@tonic-gate
15*0Sstevel@tonic-gateour($VERSION, $PACKAGE, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
16*0Sstevel@tonic-gate
17*0Sstevel@tonic-gate@ISA = qw(Exporter);
18*0Sstevel@tonic-gate
19*0Sstevel@tonic-gate$VERSION = 1.02;
20*0Sstevel@tonic-gate
21*0Sstevel@tonic-gatemy @angcnv = qw(rad2deg rad2grad
22*0Sstevel@tonic-gate		deg2rad deg2grad
23*0Sstevel@tonic-gate		grad2rad grad2deg);
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gate@EXPORT = (@{$Math::Complex::EXPORT_TAGS{'trig'}},
26*0Sstevel@tonic-gate	   @angcnv);
27*0Sstevel@tonic-gate
28*0Sstevel@tonic-gatemy @rdlcnv = qw(cartesian_to_cylindrical
29*0Sstevel@tonic-gate		cartesian_to_spherical
30*0Sstevel@tonic-gate		cylindrical_to_cartesian
31*0Sstevel@tonic-gate		cylindrical_to_spherical
32*0Sstevel@tonic-gate		spherical_to_cartesian
33*0Sstevel@tonic-gate		spherical_to_cylindrical);
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate@EXPORT_OK = (@rdlcnv, 'great_circle_distance', 'great_circle_direction');
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate%EXPORT_TAGS = ('radial' => [ @rdlcnv ]);
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gatesub pi2  () { 2 * pi }
40*0Sstevel@tonic-gatesub pip2 () { pi / 2 }
41*0Sstevel@tonic-gate
42*0Sstevel@tonic-gatesub DR  () { pi2/360 }
43*0Sstevel@tonic-gatesub RD  () { 360/pi2 }
44*0Sstevel@tonic-gatesub DG  () { 400/360 }
45*0Sstevel@tonic-gatesub GD  () { 360/400 }
46*0Sstevel@tonic-gatesub RG  () { 400/pi2 }
47*0Sstevel@tonic-gatesub GR  () { pi2/400 }
48*0Sstevel@tonic-gate
49*0Sstevel@tonic-gate#
50*0Sstevel@tonic-gate# Truncating remainder.
51*0Sstevel@tonic-gate#
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gatesub remt ($$) {
54*0Sstevel@tonic-gate    # Oh yes, POSIX::fmod() would be faster. Possibly. If it is available.
55*0Sstevel@tonic-gate    $_[0] - $_[1] * int($_[0] / $_[1]);
56*0Sstevel@tonic-gate}
57*0Sstevel@tonic-gate
58*0Sstevel@tonic-gate#
59*0Sstevel@tonic-gate# Angle conversions.
60*0Sstevel@tonic-gate#
61*0Sstevel@tonic-gate
62*0Sstevel@tonic-gatesub rad2rad($)     { remt($_[0], pi2) }
63*0Sstevel@tonic-gate
64*0Sstevel@tonic-gatesub deg2deg($)     { remt($_[0], 360) }
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gatesub grad2grad($)   { remt($_[0], 400) }
67*0Sstevel@tonic-gate
68*0Sstevel@tonic-gatesub rad2deg ($;$)  { my $d = RD * $_[0]; $_[1] ? $d : deg2deg($d) }
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gatesub deg2rad ($;$)  { my $d = DR * $_[0]; $_[1] ? $d : rad2rad($d) }
71*0Sstevel@tonic-gate
72*0Sstevel@tonic-gatesub grad2deg ($;$) { my $d = GD * $_[0]; $_[1] ? $d : deg2deg($d) }
73*0Sstevel@tonic-gate
74*0Sstevel@tonic-gatesub deg2grad ($;$) { my $d = DG * $_[0]; $_[1] ? $d : grad2grad($d) }
75*0Sstevel@tonic-gate
76*0Sstevel@tonic-gatesub rad2grad ($;$) { my $d = RG * $_[0]; $_[1] ? $d : grad2grad($d) }
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gatesub grad2rad ($;$) { my $d = GR * $_[0]; $_[1] ? $d : rad2rad($d) }
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gatesub cartesian_to_spherical {
81*0Sstevel@tonic-gate    my ( $x, $y, $z ) = @_;
82*0Sstevel@tonic-gate
83*0Sstevel@tonic-gate    my $rho = sqrt( $x * $x + $y * $y + $z * $z );
84*0Sstevel@tonic-gate
85*0Sstevel@tonic-gate    return ( $rho,
86*0Sstevel@tonic-gate             atan2( $y, $x ),
87*0Sstevel@tonic-gate             $rho ? acos( $z / $rho ) : 0 );
88*0Sstevel@tonic-gate}
89*0Sstevel@tonic-gate
90*0Sstevel@tonic-gatesub spherical_to_cartesian {
91*0Sstevel@tonic-gate    my ( $rho, $theta, $phi ) = @_;
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gate    return ( $rho * cos( $theta ) * sin( $phi ),
94*0Sstevel@tonic-gate             $rho * sin( $theta ) * sin( $phi ),
95*0Sstevel@tonic-gate             $rho * cos( $phi   ) );
96*0Sstevel@tonic-gate}
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gatesub spherical_to_cylindrical {
99*0Sstevel@tonic-gate    my ( $x, $y, $z ) = spherical_to_cartesian( @_ );
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate    return ( sqrt( $x * $x + $y * $y ), $_[1], $z );
102*0Sstevel@tonic-gate}
103*0Sstevel@tonic-gate
104*0Sstevel@tonic-gatesub cartesian_to_cylindrical {
105*0Sstevel@tonic-gate    my ( $x, $y, $z ) = @_;
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate    return ( sqrt( $x * $x + $y * $y ), atan2( $y, $x ), $z );
108*0Sstevel@tonic-gate}
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gatesub cylindrical_to_cartesian {
111*0Sstevel@tonic-gate    my ( $rho, $theta, $z ) = @_;
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate    return ( $rho * cos( $theta ), $rho * sin( $theta ), $z );
114*0Sstevel@tonic-gate}
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gatesub cylindrical_to_spherical {
117*0Sstevel@tonic-gate    return ( cartesian_to_spherical( cylindrical_to_cartesian( @_ ) ) );
118*0Sstevel@tonic-gate}
119*0Sstevel@tonic-gate
120*0Sstevel@tonic-gatesub great_circle_distance {
121*0Sstevel@tonic-gate    my ( $theta0, $phi0, $theta1, $phi1, $rho ) = @_;
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate    $rho = 1 unless defined $rho; # Default to the unit sphere.
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate    my $lat0 = pip2 - $phi0;
126*0Sstevel@tonic-gate    my $lat1 = pip2 - $phi1;
127*0Sstevel@tonic-gate
128*0Sstevel@tonic-gate    return $rho *
129*0Sstevel@tonic-gate        acos(cos( $lat0 ) * cos( $lat1 ) * cos( $theta0 - $theta1 ) +
130*0Sstevel@tonic-gate             sin( $lat0 ) * sin( $lat1 ) );
131*0Sstevel@tonic-gate}
132*0Sstevel@tonic-gate
133*0Sstevel@tonic-gatesub great_circle_direction {
134*0Sstevel@tonic-gate    my ( $theta0, $phi0, $theta1, $phi1 ) = @_;
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gate    my $distance = &great_circle_distance;
137*0Sstevel@tonic-gate
138*0Sstevel@tonic-gate    my $lat0 = pip2 - $phi0;
139*0Sstevel@tonic-gate    my $lat1 = pip2 - $phi1;
140*0Sstevel@tonic-gate
141*0Sstevel@tonic-gate    my $direction =
142*0Sstevel@tonic-gate	acos((sin($lat1) - sin($lat0) * cos($distance)) /
143*0Sstevel@tonic-gate	     (cos($lat0) * sin($distance)));
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate    $direction = pi2 - $direction
146*0Sstevel@tonic-gate	if sin($theta1 - $theta0) < 0;
147*0Sstevel@tonic-gate
148*0Sstevel@tonic-gate    return rad2rad($direction);
149*0Sstevel@tonic-gate}
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate1;
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate__END__
154*0Sstevel@tonic-gate=pod
155*0Sstevel@tonic-gate
156*0Sstevel@tonic-gate=head1 NAME
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gateMath::Trig - trigonometric functions
159*0Sstevel@tonic-gate
160*0Sstevel@tonic-gate=head1 SYNOPSIS
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate	use Math::Trig;
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate	$x = tan(0.9);
165*0Sstevel@tonic-gate	$y = acos(3.7);
166*0Sstevel@tonic-gate	$z = asin(2.4);
167*0Sstevel@tonic-gate
168*0Sstevel@tonic-gate	$halfpi = pi/2;
169*0Sstevel@tonic-gate
170*0Sstevel@tonic-gate	$rad = deg2rad(120);
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate=head1 DESCRIPTION
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gateC<Math::Trig> defines many trigonometric functions not defined by the
175*0Sstevel@tonic-gatecore Perl which defines only the C<sin()> and C<cos()>.  The constant
176*0Sstevel@tonic-gateB<pi> is also defined as are a few convenience functions for angle
177*0Sstevel@tonic-gateconversions.
178*0Sstevel@tonic-gate
179*0Sstevel@tonic-gate=head1 TRIGONOMETRIC FUNCTIONS
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gateThe tangent
182*0Sstevel@tonic-gate
183*0Sstevel@tonic-gate=over 4
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate=item B<tan>
186*0Sstevel@tonic-gate
187*0Sstevel@tonic-gate=back
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gateThe cofunctions of the sine, cosine, and tangent (cosec/csc and cotan/cot
190*0Sstevel@tonic-gateare aliases)
191*0Sstevel@tonic-gate
192*0Sstevel@tonic-gateB<csc>, B<cosec>, B<sec>, B<sec>, B<cot>, B<cotan>
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gateThe arcus (also known as the inverse) functions of the sine, cosine,
195*0Sstevel@tonic-gateand tangent
196*0Sstevel@tonic-gate
197*0Sstevel@tonic-gateB<asin>, B<acos>, B<atan>
198*0Sstevel@tonic-gate
199*0Sstevel@tonic-gateThe principal value of the arc tangent of y/x
200*0Sstevel@tonic-gate
201*0Sstevel@tonic-gateB<atan2>(y, x)
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gateThe arcus cofunctions of the sine, cosine, and tangent (acosec/acsc
204*0Sstevel@tonic-gateand acotan/acot are aliases)
205*0Sstevel@tonic-gate
206*0Sstevel@tonic-gateB<acsc>, B<acosec>, B<asec>, B<acot>, B<acotan>
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gateThe hyperbolic sine, cosine, and tangent
209*0Sstevel@tonic-gate
210*0Sstevel@tonic-gateB<sinh>, B<cosh>, B<tanh>
211*0Sstevel@tonic-gate
212*0Sstevel@tonic-gateThe cofunctions of the hyperbolic sine, cosine, and tangent (cosech/csch
213*0Sstevel@tonic-gateand cotanh/coth are aliases)
214*0Sstevel@tonic-gate
215*0Sstevel@tonic-gateB<csch>, B<cosech>, B<sech>, B<coth>, B<cotanh>
216*0Sstevel@tonic-gate
217*0Sstevel@tonic-gateThe arcus (also known as the inverse) functions of the hyperbolic
218*0Sstevel@tonic-gatesine, cosine, and tangent
219*0Sstevel@tonic-gate
220*0Sstevel@tonic-gateB<asinh>, B<acosh>, B<atanh>
221*0Sstevel@tonic-gate
222*0Sstevel@tonic-gateThe arcus cofunctions of the hyperbolic sine, cosine, and tangent
223*0Sstevel@tonic-gate(acsch/acosech and acoth/acotanh are aliases)
224*0Sstevel@tonic-gate
225*0Sstevel@tonic-gateB<acsch>, B<acosech>, B<asech>, B<acoth>, B<acotanh>
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gateThe trigonometric constant B<pi> is also defined.
228*0Sstevel@tonic-gate
229*0Sstevel@tonic-gate$pi2 = 2 * B<pi>;
230*0Sstevel@tonic-gate
231*0Sstevel@tonic-gate=head2 ERRORS DUE TO DIVISION BY ZERO
232*0Sstevel@tonic-gate
233*0Sstevel@tonic-gateThe following functions
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate	acoth
236*0Sstevel@tonic-gate	acsc
237*0Sstevel@tonic-gate	acsch
238*0Sstevel@tonic-gate	asec
239*0Sstevel@tonic-gate	asech
240*0Sstevel@tonic-gate	atanh
241*0Sstevel@tonic-gate	cot
242*0Sstevel@tonic-gate	coth
243*0Sstevel@tonic-gate	csc
244*0Sstevel@tonic-gate	csch
245*0Sstevel@tonic-gate	sec
246*0Sstevel@tonic-gate	sech
247*0Sstevel@tonic-gate	tan
248*0Sstevel@tonic-gate	tanh
249*0Sstevel@tonic-gate
250*0Sstevel@tonic-gatecannot be computed for all arguments because that would mean dividing
251*0Sstevel@tonic-gateby zero or taking logarithm of zero. These situations cause fatal
252*0Sstevel@tonic-gateruntime errors looking like this
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate	cot(0): Division by zero.
255*0Sstevel@tonic-gate	(Because in the definition of cot(0), the divisor sin(0) is 0)
256*0Sstevel@tonic-gate	Died at ...
257*0Sstevel@tonic-gate
258*0Sstevel@tonic-gateor
259*0Sstevel@tonic-gate
260*0Sstevel@tonic-gate	atanh(-1): Logarithm of zero.
261*0Sstevel@tonic-gate	Died at...
262*0Sstevel@tonic-gate
263*0Sstevel@tonic-gateFor the C<csc>, C<cot>, C<asec>, C<acsc>, C<acot>, C<csch>, C<coth>,
264*0Sstevel@tonic-gateC<asech>, C<acsch>, the argument cannot be C<0> (zero).  For the
265*0Sstevel@tonic-gateC<atanh>, C<acoth>, the argument cannot be C<1> (one).  For the
266*0Sstevel@tonic-gateC<atanh>, C<acoth>, the argument cannot be C<-1> (minus one).  For the
267*0Sstevel@tonic-gateC<tan>, C<sec>, C<tanh>, C<sech>, the argument cannot be I<pi/2 + k *
268*0Sstevel@tonic-gatepi>, where I<k> is any integer.
269*0Sstevel@tonic-gate
270*0Sstevel@tonic-gate=head2 SIMPLE (REAL) ARGUMENTS, COMPLEX RESULTS
271*0Sstevel@tonic-gate
272*0Sstevel@tonic-gatePlease note that some of the trigonometric functions can break out
273*0Sstevel@tonic-gatefrom the B<real axis> into the B<complex plane>. For example
274*0Sstevel@tonic-gateC<asin(2)> has no definition for plain real numbers but it has
275*0Sstevel@tonic-gatedefinition for complex numbers.
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gateIn Perl terms this means that supplying the usual Perl numbers (also
278*0Sstevel@tonic-gateknown as scalars, please see L<perldata>) as input for the
279*0Sstevel@tonic-gatetrigonometric functions might produce as output results that no more
280*0Sstevel@tonic-gateare simple real numbers: instead they are complex numbers.
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gateThe C<Math::Trig> handles this by using the C<Math::Complex> package
283*0Sstevel@tonic-gatewhich knows how to handle complex numbers, please see L<Math::Complex>
284*0Sstevel@tonic-gatefor more information. In practice you need not to worry about getting
285*0Sstevel@tonic-gatecomplex numbers as results because the C<Math::Complex> takes care of
286*0Sstevel@tonic-gatedetails like for example how to display complex numbers. For example:
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate	print asin(2), "\n";
289*0Sstevel@tonic-gate
290*0Sstevel@tonic-gateshould produce something like this (take or leave few last decimals):
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gate	1.5707963267949-1.31695789692482i
293*0Sstevel@tonic-gate
294*0Sstevel@tonic-gateThat is, a complex number with the real part of approximately C<1.571>
295*0Sstevel@tonic-gateand the imaginary part of approximately C<-1.317>.
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gate=head1 PLANE ANGLE CONVERSIONS
298*0Sstevel@tonic-gate
299*0Sstevel@tonic-gate(Plane, 2-dimensional) angles may be converted with the following functions.
300*0Sstevel@tonic-gate
301*0Sstevel@tonic-gate	$radians  = deg2rad($degrees);
302*0Sstevel@tonic-gate	$radians  = grad2rad($gradians);
303*0Sstevel@tonic-gate
304*0Sstevel@tonic-gate	$degrees  = rad2deg($radians);
305*0Sstevel@tonic-gate	$degrees  = grad2deg($gradians);
306*0Sstevel@tonic-gate
307*0Sstevel@tonic-gate	$gradians = deg2grad($degrees);
308*0Sstevel@tonic-gate	$gradians = rad2grad($radians);
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gateThe full circle is 2 I<pi> radians or I<360> degrees or I<400> gradians.
311*0Sstevel@tonic-gateThe result is by default wrapped to be inside the [0, {2pi,360,400}[ circle.
312*0Sstevel@tonic-gateIf you don't want this, supply a true second argument:
313*0Sstevel@tonic-gate
314*0Sstevel@tonic-gate	$zillions_of_radians  = deg2rad($zillions_of_degrees, 1);
315*0Sstevel@tonic-gate	$negative_degrees     = rad2deg($negative_radians, 1);
316*0Sstevel@tonic-gate
317*0Sstevel@tonic-gateYou can also do the wrapping explicitly by rad2rad(), deg2deg(), and
318*0Sstevel@tonic-gategrad2grad().
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate=head1 RADIAL COORDINATE CONVERSIONS
321*0Sstevel@tonic-gate
322*0Sstevel@tonic-gateB<Radial coordinate systems> are the B<spherical> and the B<cylindrical>
323*0Sstevel@tonic-gatesystems, explained shortly in more detail.
324*0Sstevel@tonic-gate
325*0Sstevel@tonic-gateYou can import radial coordinate conversion functions by using the
326*0Sstevel@tonic-gateC<:radial> tag:
327*0Sstevel@tonic-gate
328*0Sstevel@tonic-gate    use Math::Trig ':radial';
329*0Sstevel@tonic-gate
330*0Sstevel@tonic-gate    ($rho, $theta, $z)     = cartesian_to_cylindrical($x, $y, $z);
331*0Sstevel@tonic-gate    ($rho, $theta, $phi)   = cartesian_to_spherical($x, $y, $z);
332*0Sstevel@tonic-gate    ($x, $y, $z)           = cylindrical_to_cartesian($rho, $theta, $z);
333*0Sstevel@tonic-gate    ($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);
334*0Sstevel@tonic-gate    ($x, $y, $z)           = spherical_to_cartesian($rho, $theta, $phi);
335*0Sstevel@tonic-gate    ($rho_c, $theta, $z)   = spherical_to_cylindrical($rho_s, $theta, $phi);
336*0Sstevel@tonic-gate
337*0Sstevel@tonic-gateB<All angles are in radians>.
338*0Sstevel@tonic-gate
339*0Sstevel@tonic-gate=head2 COORDINATE SYSTEMS
340*0Sstevel@tonic-gate
341*0Sstevel@tonic-gateB<Cartesian> coordinates are the usual rectangular I<(x, y,
342*0Sstevel@tonic-gatez)>-coordinates.
343*0Sstevel@tonic-gate
344*0Sstevel@tonic-gateSpherical coordinates, I<(rho, theta, pi)>, are three-dimensional
345*0Sstevel@tonic-gatecoordinates which define a point in three-dimensional space.  They are
346*0Sstevel@tonic-gatebased on a sphere surface.  The radius of the sphere is B<rho>, also
347*0Sstevel@tonic-gateknown as the I<radial> coordinate.  The angle in the I<xy>-plane
348*0Sstevel@tonic-gate(around the I<z>-axis) is B<theta>, also known as the I<azimuthal>
349*0Sstevel@tonic-gatecoordinate.  The angle from the I<z>-axis is B<phi>, also known as the
350*0Sstevel@tonic-gateI<polar> coordinate.  The `North Pole' is therefore I<0, 0, rho>, and
351*0Sstevel@tonic-gatethe `Bay of Guinea' (think of the missing big chunk of Africa) I<0,
352*0Sstevel@tonic-gatepi/2, rho>.  In geographical terms I<phi> is latitude (northward
353*0Sstevel@tonic-gatepositive, southward negative) and I<theta> is longitude (eastward
354*0Sstevel@tonic-gatepositive, westward negative).
355*0Sstevel@tonic-gate
356*0Sstevel@tonic-gateB<BEWARE>: some texts define I<theta> and I<phi> the other way round,
357*0Sstevel@tonic-gatesome texts define the I<phi> to start from the horizontal plane, some
358*0Sstevel@tonic-gatetexts use I<r> in place of I<rho>.
359*0Sstevel@tonic-gate
360*0Sstevel@tonic-gateCylindrical coordinates, I<(rho, theta, z)>, are three-dimensional
361*0Sstevel@tonic-gatecoordinates which define a point in three-dimensional space.  They are
362*0Sstevel@tonic-gatebased on a cylinder surface.  The radius of the cylinder is B<rho>,
363*0Sstevel@tonic-gatealso known as the I<radial> coordinate.  The angle in the I<xy>-plane
364*0Sstevel@tonic-gate(around the I<z>-axis) is B<theta>, also known as the I<azimuthal>
365*0Sstevel@tonic-gatecoordinate.  The third coordinate is the I<z>, pointing up from the
366*0Sstevel@tonic-gateB<theta>-plane.
367*0Sstevel@tonic-gate
368*0Sstevel@tonic-gate=head2 3-D ANGLE CONVERSIONS
369*0Sstevel@tonic-gate
370*0Sstevel@tonic-gateConversions to and from spherical and cylindrical coordinates are
371*0Sstevel@tonic-gateavailable.  Please notice that the conversions are not necessarily
372*0Sstevel@tonic-gatereversible because of the equalities like I<pi> angles being equal to
373*0Sstevel@tonic-gateI<-pi> angles.
374*0Sstevel@tonic-gate
375*0Sstevel@tonic-gate=over 4
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate=item cartesian_to_cylindrical
378*0Sstevel@tonic-gate
379*0Sstevel@tonic-gate        ($rho, $theta, $z) = cartesian_to_cylindrical($x, $y, $z);
380*0Sstevel@tonic-gate
381*0Sstevel@tonic-gate=item cartesian_to_spherical
382*0Sstevel@tonic-gate
383*0Sstevel@tonic-gate        ($rho, $theta, $phi) = cartesian_to_spherical($x, $y, $z);
384*0Sstevel@tonic-gate
385*0Sstevel@tonic-gate=item cylindrical_to_cartesian
386*0Sstevel@tonic-gate
387*0Sstevel@tonic-gate        ($x, $y, $z) = cylindrical_to_cartesian($rho, $theta, $z);
388*0Sstevel@tonic-gate
389*0Sstevel@tonic-gate=item cylindrical_to_spherical
390*0Sstevel@tonic-gate
391*0Sstevel@tonic-gate        ($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);
392*0Sstevel@tonic-gate
393*0Sstevel@tonic-gateNotice that when C<$z> is not 0 C<$rho_s> is not equal to C<$rho_c>.
394*0Sstevel@tonic-gate
395*0Sstevel@tonic-gate=item spherical_to_cartesian
396*0Sstevel@tonic-gate
397*0Sstevel@tonic-gate        ($x, $y, $z) = spherical_to_cartesian($rho, $theta, $phi);
398*0Sstevel@tonic-gate
399*0Sstevel@tonic-gate=item spherical_to_cylindrical
400*0Sstevel@tonic-gate
401*0Sstevel@tonic-gate        ($rho_c, $theta, $z) = spherical_to_cylindrical($rho_s, $theta, $phi);
402*0Sstevel@tonic-gate
403*0Sstevel@tonic-gateNotice that when C<$z> is not 0 C<$rho_c> is not equal to C<$rho_s>.
404*0Sstevel@tonic-gate
405*0Sstevel@tonic-gate=back
406*0Sstevel@tonic-gate
407*0Sstevel@tonic-gate=head1 GREAT CIRCLE DISTANCES AND DIRECTIONS
408*0Sstevel@tonic-gate
409*0Sstevel@tonic-gateYou can compute spherical distances, called B<great circle distances>,
410*0Sstevel@tonic-gateby importing the great_circle_distance() function:
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate  use Math::Trig 'great_circle_distance';
413*0Sstevel@tonic-gate
414*0Sstevel@tonic-gate  $distance = great_circle_distance($theta0, $phi0, $theta1, $phi1, [, $rho]);
415*0Sstevel@tonic-gate
416*0Sstevel@tonic-gateThe I<great circle distance> is the shortest distance between two
417*0Sstevel@tonic-gatepoints on a sphere.  The distance is in C<$rho> units.  The C<$rho> is
418*0Sstevel@tonic-gateoptional, it defaults to 1 (the unit sphere), therefore the distance
419*0Sstevel@tonic-gatedefaults to radians.
420*0Sstevel@tonic-gate
421*0Sstevel@tonic-gateIf you think geographically the I<theta> are longitudes: zero at the
422*0Sstevel@tonic-gateGreenwhich meridian, eastward positive, westward negative--and the
423*0Sstevel@tonic-gateI<phi> are latitudes: zero at the North Pole, northward positive,
424*0Sstevel@tonic-gatesouthward negative.  B<NOTE>: this formula thinks in mathematics, not
425*0Sstevel@tonic-gategeographically: the I<phi> zero is at the North Pole, not at the
426*0Sstevel@tonic-gateEquator on the west coast of Africa (Bay of Guinea).  You need to
427*0Sstevel@tonic-gatesubtract your geographical coordinates from I<pi/2> (also known as 90
428*0Sstevel@tonic-gatedegrees).
429*0Sstevel@tonic-gate
430*0Sstevel@tonic-gate  $distance = great_circle_distance($lon0, pi/2 - $lat0,
431*0Sstevel@tonic-gate                                    $lon1, pi/2 - $lat1, $rho);
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gateThe direction you must follow the great circle can be computed by the
434*0Sstevel@tonic-gategreat_circle_direction() function:
435*0Sstevel@tonic-gate
436*0Sstevel@tonic-gate  use Math::Trig 'great_circle_direction';
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gate  $direction = great_circle_direction($theta0, $phi0, $theta1, $phi1);
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gateThe result is in radians, zero indicating straight north, pi or -pi
441*0Sstevel@tonic-gatestraight south, pi/2 straight west, and -pi/2 straight east.
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gateNotice that the resulting directions might be somewhat surprising if
444*0Sstevel@tonic-gateyou are looking at a flat worldmap: in such map projections the great
445*0Sstevel@tonic-gatecircles quite often do not look like the shortest routes-- but for
446*0Sstevel@tonic-gateexample the shortest possible routes from Europe or North America to
447*0Sstevel@tonic-gateAsia do often cross the polar regions.
448*0Sstevel@tonic-gate
449*0Sstevel@tonic-gate=head1 EXAMPLES
450*0Sstevel@tonic-gate
451*0Sstevel@tonic-gateTo calculate the distance between London (51.3N 0.5W) and Tokyo
452*0Sstevel@tonic-gate(35.7N 139.8E) in kilometers:
453*0Sstevel@tonic-gate
454*0Sstevel@tonic-gate        use Math::Trig qw(great_circle_distance deg2rad);
455*0Sstevel@tonic-gate
456*0Sstevel@tonic-gate        # Notice the 90 - latitude: phi zero is at the North Pole.
457*0Sstevel@tonic-gate	@L = (deg2rad(-0.5), deg2rad(90 - 51.3));
458*0Sstevel@tonic-gate        @T = (deg2rad(139.8),deg2rad(90 - 35.7));
459*0Sstevel@tonic-gate
460*0Sstevel@tonic-gate        $km = great_circle_distance(@L, @T, 6378);
461*0Sstevel@tonic-gate
462*0Sstevel@tonic-gateThe direction you would have to go from London to Tokyo
463*0Sstevel@tonic-gate
464*0Sstevel@tonic-gate        use Math::Trig qw(great_circle_direction);
465*0Sstevel@tonic-gate
466*0Sstevel@tonic-gate        $rad = great_circle_direction(@L, @T);
467*0Sstevel@tonic-gate
468*0Sstevel@tonic-gate=head2 CAVEAT FOR GREAT CIRCLE FORMULAS
469*0Sstevel@tonic-gate
470*0Sstevel@tonic-gateThe answers may be off by few percentages because of the irregular
471*0Sstevel@tonic-gate(slightly aspherical) form of the Earth.  The formula used for
472*0Sstevel@tonic-gategrear circle distances
473*0Sstevel@tonic-gate
474*0Sstevel@tonic-gate	lat0 = 90 degrees - phi0
475*0Sstevel@tonic-gate	lat1 = 90 degrees - phi1
476*0Sstevel@tonic-gate	d = R * arccos(cos(lat0) * cos(lat1) * cos(lon1 - lon01) +
477*0Sstevel@tonic-gate                       sin(lat0) * sin(lat1))
478*0Sstevel@tonic-gate
479*0Sstevel@tonic-gateis also somewhat unreliable for small distances (for locations
480*0Sstevel@tonic-gateseparated less than about five degrees) because it uses arc cosine
481*0Sstevel@tonic-gatewhich is rather ill-conditioned for values close to zero.
482*0Sstevel@tonic-gate
483*0Sstevel@tonic-gate=head1 BUGS
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gateSaying C<use Math::Trig;> exports many mathematical routines in the
486*0Sstevel@tonic-gatecaller environment and even overrides some (C<sin>, C<cos>).  This is
487*0Sstevel@tonic-gateconstrued as a feature by the Authors, actually... ;-)
488*0Sstevel@tonic-gate
489*0Sstevel@tonic-gateThe code is not optimized for speed, especially because we use
490*0Sstevel@tonic-gateC<Math::Complex> and thus go quite near complex numbers while doing
491*0Sstevel@tonic-gatethe computations even when the arguments are not. This, however,
492*0Sstevel@tonic-gatecannot be completely avoided if we want things like C<asin(2)> to give
493*0Sstevel@tonic-gatean answer instead of giving a fatal runtime error.
494*0Sstevel@tonic-gate
495*0Sstevel@tonic-gate=head1 AUTHORS
496*0Sstevel@tonic-gate
497*0Sstevel@tonic-gateJarkko Hietaniemi <F<jhi@iki.fi>> and
498*0Sstevel@tonic-gateRaphael Manfredi <F<Raphael_Manfredi@pobox.com>>.
499*0Sstevel@tonic-gate
500*0Sstevel@tonic-gate=cut
501*0Sstevel@tonic-gate
502*0Sstevel@tonic-gate# eof
503