xref: /openbsd-src/gnu/usr.bin/perl/dist/Math-Complex/lib/Math/Trig.pm (revision f2a19305cfc49ea4d1a5feb55cd6c283c6f1e031)
1*f2a19305Safresh1#
2*f2a19305Safresh1# Trigonometric functions, mostly inherited from Math::Complex.
3*f2a19305Safresh1# -- Jarkko Hietaniemi, since April 1997
4*f2a19305Safresh1# -- Raphael Manfredi, September 1996 (indirectly: because of Math::Complex)
5*f2a19305Safresh1#
6*f2a19305Safresh1
7*f2a19305Safresh1package Math::Trig;
8*f2a19305Safresh1
9*f2a19305Safresh1{ use 5.006; }
10*f2a19305Safresh1use strict;
11*f2a19305Safresh1
12*f2a19305Safresh1use Math::Complex 1.59;
13*f2a19305Safresh1use Math::Complex qw(:trig :pi);
14*f2a19305Safresh1require Exporter;
15*f2a19305Safresh1
16*f2a19305Safresh1our @ISA = qw(Exporter);
17*f2a19305Safresh1
18*f2a19305Safresh1our $VERSION = 1.62;
19*f2a19305Safresh1
20*f2a19305Safresh1my @angcnv = qw(rad2deg rad2grad
21*f2a19305Safresh1		deg2rad deg2grad
22*f2a19305Safresh1		grad2rad grad2deg);
23*f2a19305Safresh1
24*f2a19305Safresh1my @areal = qw(asin_real acos_real);
25*f2a19305Safresh1
26*f2a19305Safresh1our @EXPORT = (@{$Math::Complex::EXPORT_TAGS{'trig'}},
27*f2a19305Safresh1	   @angcnv, @areal);
28*f2a19305Safresh1
29*f2a19305Safresh1my @rdlcnv = qw(cartesian_to_cylindrical
30*f2a19305Safresh1		cartesian_to_spherical
31*f2a19305Safresh1		cylindrical_to_cartesian
32*f2a19305Safresh1		cylindrical_to_spherical
33*f2a19305Safresh1		spherical_to_cartesian
34*f2a19305Safresh1		spherical_to_cylindrical);
35*f2a19305Safresh1
36*f2a19305Safresh1my @greatcircle = qw(
37*f2a19305Safresh1		     great_circle_distance
38*f2a19305Safresh1		     great_circle_direction
39*f2a19305Safresh1		     great_circle_bearing
40*f2a19305Safresh1		     great_circle_waypoint
41*f2a19305Safresh1		     great_circle_midpoint
42*f2a19305Safresh1		     great_circle_destination
43*f2a19305Safresh1		    );
44*f2a19305Safresh1
45*f2a19305Safresh1my @pi = qw(pi pi2 pi4 pip2 pip4);
46*f2a19305Safresh1
47*f2a19305Safresh1our @EXPORT_OK = (@rdlcnv, @greatcircle, @pi, 'Inf');
48*f2a19305Safresh1
49*f2a19305Safresh1# See e.g. the following pages:
50*f2a19305Safresh1# https://www.movable-type.co.uk/scripts/latlong.html
51*f2a19305Safresh1# https://edwilliams.org/avform.htm
52*f2a19305Safresh1# https://en.wikipedia.org/wiki/Great-circle_distance
53*f2a19305Safresh1
54*f2a19305Safresh1our %EXPORT_TAGS = ('radial' => [ @rdlcnv ],
55*f2a19305Safresh1	        'great_circle' => [ @greatcircle ],
56*f2a19305Safresh1	        'pi'     => [ @pi ]);
57*f2a19305Safresh1
58*f2a19305Safresh1sub _DR  () { pi2/360 }
59*f2a19305Safresh1sub _RD  () { 360/pi2 }
60*f2a19305Safresh1sub _DG  () { 400/360 }
61*f2a19305Safresh1sub _GD  () { 360/400 }
62*f2a19305Safresh1sub _RG  () { 400/pi2 }
63*f2a19305Safresh1sub _GR  () { pi2/400 }
64*f2a19305Safresh1
65*f2a19305Safresh1#
66*f2a19305Safresh1# Truncating remainder.
67*f2a19305Safresh1#
68*f2a19305Safresh1
69*f2a19305Safresh1sub _remt ($$) {
70*f2a19305Safresh1    # Oh yes, POSIX::fmod() would be faster. Possibly. If it is available.
71*f2a19305Safresh1    $_[0] - $_[1] * int($_[0] / $_[1]);
72*f2a19305Safresh1}
73*f2a19305Safresh1
74*f2a19305Safresh1#
75*f2a19305Safresh1# Angle conversions.
76*f2a19305Safresh1#
77*f2a19305Safresh1
78*f2a19305Safresh1sub rad2rad($)     { _remt($_[0], pi2) }
79*f2a19305Safresh1
80*f2a19305Safresh1sub deg2deg($)     { _remt($_[0], 360) }
81*f2a19305Safresh1
82*f2a19305Safresh1sub grad2grad($)   { _remt($_[0], 400) }
83*f2a19305Safresh1
84*f2a19305Safresh1sub rad2deg ($;$)  { my $d = _RD * $_[0]; $_[1] ? $d : deg2deg($d) }
85*f2a19305Safresh1
86*f2a19305Safresh1sub deg2rad ($;$)  { my $d = _DR * $_[0]; $_[1] ? $d : rad2rad($d) }
87*f2a19305Safresh1
88*f2a19305Safresh1sub grad2deg ($;$) { my $d = _GD * $_[0]; $_[1] ? $d : deg2deg($d) }
89*f2a19305Safresh1
90*f2a19305Safresh1sub deg2grad ($;$) { my $d = _DG * $_[0]; $_[1] ? $d : grad2grad($d) }
91*f2a19305Safresh1
92*f2a19305Safresh1sub rad2grad ($;$) { my $d = _RG * $_[0]; $_[1] ? $d : grad2grad($d) }
93*f2a19305Safresh1
94*f2a19305Safresh1sub grad2rad ($;$) { my $d = _GR * $_[0]; $_[1] ? $d : rad2rad($d) }
95*f2a19305Safresh1
96*f2a19305Safresh1#
97*f2a19305Safresh1# acos and asin functions which always return a real number
98*f2a19305Safresh1#
99*f2a19305Safresh1
100*f2a19305Safresh1sub acos_real {
101*f2a19305Safresh1    return 0  if $_[0] >=  1;
102*f2a19305Safresh1    return pi if $_[0] <= -1;
103*f2a19305Safresh1    return acos($_[0]);
104*f2a19305Safresh1}
105*f2a19305Safresh1
106*f2a19305Safresh1sub asin_real {
107*f2a19305Safresh1    return  &pip2 if $_[0] >=  1;
108*f2a19305Safresh1    return -&pip2 if $_[0] <= -1;
109*f2a19305Safresh1    return asin($_[0]);
110*f2a19305Safresh1}
111*f2a19305Safresh1
112*f2a19305Safresh1sub cartesian_to_spherical {
113*f2a19305Safresh1    my ( $x, $y, $z ) = @_;
114*f2a19305Safresh1
115*f2a19305Safresh1    my $rho = sqrt( $x * $x + $y * $y + $z * $z );
116*f2a19305Safresh1
117*f2a19305Safresh1    return ( $rho,
118*f2a19305Safresh1             atan2( $y, $x ),
119*f2a19305Safresh1             $rho ? acos_real( $z / $rho ) : 0 );
120*f2a19305Safresh1}
121*f2a19305Safresh1
122*f2a19305Safresh1sub spherical_to_cartesian {
123*f2a19305Safresh1    my ( $rho, $theta, $phi ) = @_;
124*f2a19305Safresh1
125*f2a19305Safresh1    return ( $rho * cos( $theta ) * sin( $phi ),
126*f2a19305Safresh1             $rho * sin( $theta ) * sin( $phi ),
127*f2a19305Safresh1             $rho * cos( $phi   ) );
128*f2a19305Safresh1}
129*f2a19305Safresh1
130*f2a19305Safresh1sub spherical_to_cylindrical {
131*f2a19305Safresh1    my ( $x, $y, $z ) = spherical_to_cartesian( @_ );
132*f2a19305Safresh1
133*f2a19305Safresh1    return ( sqrt( $x * $x + $y * $y ), $_[1], $z );
134*f2a19305Safresh1}
135*f2a19305Safresh1
136*f2a19305Safresh1sub cartesian_to_cylindrical {
137*f2a19305Safresh1    my ( $x, $y, $z ) = @_;
138*f2a19305Safresh1
139*f2a19305Safresh1    return ( sqrt( $x * $x + $y * $y ), atan2( $y, $x ), $z );
140*f2a19305Safresh1}
141*f2a19305Safresh1
142*f2a19305Safresh1sub cylindrical_to_cartesian {
143*f2a19305Safresh1    my ( $rho, $theta, $z ) = @_;
144*f2a19305Safresh1
145*f2a19305Safresh1    return ( $rho * cos( $theta ), $rho * sin( $theta ), $z );
146*f2a19305Safresh1}
147*f2a19305Safresh1
148*f2a19305Safresh1sub cylindrical_to_spherical {
149*f2a19305Safresh1    return ( cartesian_to_spherical( cylindrical_to_cartesian( @_ ) ) );
150*f2a19305Safresh1}
151*f2a19305Safresh1
152*f2a19305Safresh1sub great_circle_distance {
153*f2a19305Safresh1    my ( $theta0, $phi0, $theta1, $phi1, $rho ) = @_;
154*f2a19305Safresh1
155*f2a19305Safresh1    $rho = 1 unless defined $rho; # Default to the unit sphere.
156*f2a19305Safresh1
157*f2a19305Safresh1    my $dphi   = $phi1 - $phi0;
158*f2a19305Safresh1    my $dtheta = $theta1 - $theta0;
159*f2a19305Safresh1
160*f2a19305Safresh1    # A formula that is accurate for all distances is the following special
161*f2a19305Safresh1    # case of the Vincenty formula for an ellipsoid with equal major and minor
162*f2a19305Safresh1    # axes.  See
163*f2a19305Safresh1    # https://en.wikipedia.org/wiki/Great-circle_distance#Computational_formulas
164*f2a19305Safresh1
165*f2a19305Safresh1    my $c1 = sin($phi1) * sin($dtheta);
166*f2a19305Safresh1    my $c2 = sin($phi1) * cos($dtheta);
167*f2a19305Safresh1    my $c3 = sin($phi0) * cos($phi1) - cos($phi0) * $c2;
168*f2a19305Safresh1    my $c4 = cos($phi0) * cos($phi1) + sin($phi0) * $c2;
169*f2a19305Safresh1    return $rho * atan2(sqrt($c1 * $c1 + $c3 * $c3), $c4);
170*f2a19305Safresh1}
171*f2a19305Safresh1
172*f2a19305Safresh1sub great_circle_direction {
173*f2a19305Safresh1    my ( $theta0, $phi0, $theta1, $phi1 ) = @_;
174*f2a19305Safresh1
175*f2a19305Safresh1    my $lat0 = pip2 - $phi0;
176*f2a19305Safresh1    my $lat1 = pip2 - $phi1;
177*f2a19305Safresh1
178*f2a19305Safresh1    return rad2rad(pi2 -
179*f2a19305Safresh1	atan2(sin($theta0-$theta1) * cos($lat1),
180*f2a19305Safresh1		cos($lat0) * sin($lat1) -
181*f2a19305Safresh1		    sin($lat0) * cos($lat1) * cos($theta0-$theta1)));
182*f2a19305Safresh1}
183*f2a19305Safresh1
184*f2a19305Safresh1*great_circle_bearing         = \&great_circle_direction;
185*f2a19305Safresh1
186*f2a19305Safresh1sub great_circle_waypoint {
187*f2a19305Safresh1    my ( $theta0, $phi0, $theta1, $phi1, $point ) = @_;
188*f2a19305Safresh1
189*f2a19305Safresh1    $point = 0.5 unless defined $point;
190*f2a19305Safresh1
191*f2a19305Safresh1    my $d = great_circle_distance( $theta0, $phi0, $theta1, $phi1 );
192*f2a19305Safresh1
193*f2a19305Safresh1    return undef if $d == pi;
194*f2a19305Safresh1
195*f2a19305Safresh1    my $sd = sin($d);
196*f2a19305Safresh1
197*f2a19305Safresh1    return ($theta0, $phi0) if $sd == 0;
198*f2a19305Safresh1
199*f2a19305Safresh1    my $A = sin((1 - $point) * $d) / $sd;
200*f2a19305Safresh1    my $B = sin(     $point  * $d) / $sd;
201*f2a19305Safresh1
202*f2a19305Safresh1    my $lat0 = pip2 - $phi0;
203*f2a19305Safresh1    my $lat1 = pip2 - $phi1;
204*f2a19305Safresh1
205*f2a19305Safresh1    my $x = $A * cos($lat0) * cos($theta0) + $B * cos($lat1) * cos($theta1);
206*f2a19305Safresh1    my $y = $A * cos($lat0) * sin($theta0) + $B * cos($lat1) * sin($theta1);
207*f2a19305Safresh1    my $z = $A * sin($lat0)                + $B * sin($lat1);
208*f2a19305Safresh1
209*f2a19305Safresh1    my $theta = atan2($y, $x);
210*f2a19305Safresh1    my $phi   = acos_real($z);
211*f2a19305Safresh1
212*f2a19305Safresh1    return ($theta, $phi);
213*f2a19305Safresh1}
214*f2a19305Safresh1
215*f2a19305Safresh1sub great_circle_midpoint {
216*f2a19305Safresh1    great_circle_waypoint(@_[0..3], 0.5);
217*f2a19305Safresh1}
218*f2a19305Safresh1
219*f2a19305Safresh1sub great_circle_destination {
220*f2a19305Safresh1    my ( $theta0, $phi0, $dir0, $dst ) = @_;
221*f2a19305Safresh1
222*f2a19305Safresh1    my $lat0 = pip2 - $phi0;
223*f2a19305Safresh1
224*f2a19305Safresh1    my $phi1   = asin_real(sin($lat0)*cos($dst) +
225*f2a19305Safresh1			   cos($lat0)*sin($dst)*cos($dir0));
226*f2a19305Safresh1
227*f2a19305Safresh1    my $theta1 = $theta0 + atan2(sin($dir0)*sin($dst)*cos($lat0),
228*f2a19305Safresh1				 cos($dst)-sin($lat0)*sin($phi1));
229*f2a19305Safresh1
230*f2a19305Safresh1    my $dir1 = great_circle_bearing($theta1, $phi1, $theta0, $phi0) + pi;
231*f2a19305Safresh1
232*f2a19305Safresh1    $dir1 -= pi2 if $dir1 > pi2;
233*f2a19305Safresh1
234*f2a19305Safresh1    return ($theta1, $phi1, $dir1);
235*f2a19305Safresh1}
236*f2a19305Safresh1
237*f2a19305Safresh11;
238*f2a19305Safresh1
239*f2a19305Safresh1__END__
240*f2a19305Safresh1=pod
241*f2a19305Safresh1
242*f2a19305Safresh1=head1 NAME
243*f2a19305Safresh1
244*f2a19305Safresh1Math::Trig - trigonometric functions
245*f2a19305Safresh1
246*f2a19305Safresh1=head1 SYNOPSIS
247*f2a19305Safresh1
248*f2a19305Safresh1    use Math::Trig;
249*f2a19305Safresh1
250*f2a19305Safresh1    $x = tan(0.9);
251*f2a19305Safresh1    $y = acos(3.7);
252*f2a19305Safresh1    $z = asin(2.4);
253*f2a19305Safresh1
254*f2a19305Safresh1    $halfpi = pi/2;
255*f2a19305Safresh1
256*f2a19305Safresh1    $rad = deg2rad(120);
257*f2a19305Safresh1
258*f2a19305Safresh1    # Import constants pi2, pi4, pip2, pip4 (2*pi, 4*pi, pi/2, pi/4).
259*f2a19305Safresh1    use Math::Trig ':pi';
260*f2a19305Safresh1
261*f2a19305Safresh1    # Import the conversions between cartesian/spherical/cylindrical.
262*f2a19305Safresh1    use Math::Trig ':radial';
263*f2a19305Safresh1
264*f2a19305Safresh1        # Import the great circle formulas.
265*f2a19305Safresh1    use Math::Trig ':great_circle';
266*f2a19305Safresh1
267*f2a19305Safresh1=head1 DESCRIPTION
268*f2a19305Safresh1
269*f2a19305Safresh1C<Math::Trig> defines many trigonometric functions not defined by the
270*f2a19305Safresh1core Perl which defines only the C<sin()> and C<cos()>.  The constant
271*f2a19305Safresh1B<pi> is also defined as are a few convenience functions for angle
272*f2a19305Safresh1conversions, and I<great circle formulas> for spherical movement.
273*f2a19305Safresh1
274*f2a19305Safresh1=head1 TRIGONOMETRIC FUNCTIONS
275*f2a19305Safresh1
276*f2a19305Safresh1The tangent
277*f2a19305Safresh1
278*f2a19305Safresh1=over 4
279*f2a19305Safresh1
280*f2a19305Safresh1=item B<tan>
281*f2a19305Safresh1
282*f2a19305Safresh1=back
283*f2a19305Safresh1
284*f2a19305Safresh1The cofunctions of the sine, cosine, and tangent (cosec/csc and cotan/cot
285*f2a19305Safresh1are aliases)
286*f2a19305Safresh1
287*f2a19305Safresh1B<csc>, B<cosec>, B<sec>, B<sec>, B<cot>, B<cotan>
288*f2a19305Safresh1
289*f2a19305Safresh1The arcus (also known as the inverse) functions of the sine, cosine,
290*f2a19305Safresh1and tangent
291*f2a19305Safresh1
292*f2a19305Safresh1B<asin>, B<acos>, B<atan>
293*f2a19305Safresh1
294*f2a19305Safresh1The principal value of the arc tangent of y/x
295*f2a19305Safresh1
296*f2a19305Safresh1B<atan2>(y, x)
297*f2a19305Safresh1
298*f2a19305Safresh1The arcus cofunctions of the sine, cosine, and tangent (acosec/acsc
299*f2a19305Safresh1and acotan/acot are aliases).  Note that atan2(0, 0) is not well-defined.
300*f2a19305Safresh1
301*f2a19305Safresh1B<acsc>, B<acosec>, B<asec>, B<acot>, B<acotan>
302*f2a19305Safresh1
303*f2a19305Safresh1The hyperbolic sine, cosine, and tangent
304*f2a19305Safresh1
305*f2a19305Safresh1B<sinh>, B<cosh>, B<tanh>
306*f2a19305Safresh1
307*f2a19305Safresh1The cofunctions of the hyperbolic sine, cosine, and tangent (cosech/csch
308*f2a19305Safresh1and cotanh/coth are aliases)
309*f2a19305Safresh1
310*f2a19305Safresh1B<csch>, B<cosech>, B<sech>, B<coth>, B<cotanh>
311*f2a19305Safresh1
312*f2a19305Safresh1The area (also known as the inverse) functions of the hyperbolic
313*f2a19305Safresh1sine, cosine, and tangent
314*f2a19305Safresh1
315*f2a19305Safresh1B<asinh>, B<acosh>, B<atanh>
316*f2a19305Safresh1
317*f2a19305Safresh1The area cofunctions of the hyperbolic sine, cosine, and tangent
318*f2a19305Safresh1(acsch/acosech and acoth/acotanh are aliases)
319*f2a19305Safresh1
320*f2a19305Safresh1B<acsch>, B<acosech>, B<asech>, B<acoth>, B<acotanh>
321*f2a19305Safresh1
322*f2a19305Safresh1The trigonometric constant B<pi> and some of handy multiples
323*f2a19305Safresh1of it are also defined.
324*f2a19305Safresh1
325*f2a19305Safresh1B<pi, pi2, pi4, pip2, pip4>
326*f2a19305Safresh1
327*f2a19305Safresh1=head2 ERRORS DUE TO DIVISION BY ZERO
328*f2a19305Safresh1
329*f2a19305Safresh1The following functions
330*f2a19305Safresh1
331*f2a19305Safresh1    acoth
332*f2a19305Safresh1    acsc
333*f2a19305Safresh1    acsch
334*f2a19305Safresh1    asec
335*f2a19305Safresh1    asech
336*f2a19305Safresh1    atanh
337*f2a19305Safresh1    cot
338*f2a19305Safresh1    coth
339*f2a19305Safresh1    csc
340*f2a19305Safresh1    csch
341*f2a19305Safresh1    sec
342*f2a19305Safresh1    sech
343*f2a19305Safresh1    tan
344*f2a19305Safresh1    tanh
345*f2a19305Safresh1
346*f2a19305Safresh1cannot be computed for all arguments because that would mean dividing
347*f2a19305Safresh1by zero or taking logarithm of zero. These situations cause fatal
348*f2a19305Safresh1runtime errors looking like this
349*f2a19305Safresh1
350*f2a19305Safresh1    cot(0): Division by zero.
351*f2a19305Safresh1    (Because in the definition of cot(0), the divisor sin(0) is 0)
352*f2a19305Safresh1    Died at ...
353*f2a19305Safresh1
354*f2a19305Safresh1or
355*f2a19305Safresh1
356*f2a19305Safresh1    atanh(-1): Logarithm of zero.
357*f2a19305Safresh1    Died at...
358*f2a19305Safresh1
359*f2a19305Safresh1For the C<csc>, C<cot>, C<asec>, C<acsc>, C<acot>, C<csch>, C<coth>,
360*f2a19305Safresh1C<asech>, C<acsch>, the argument cannot be C<0> (zero).  For the
361*f2a19305Safresh1C<atanh>, C<acoth>, the argument cannot be C<1> (one).  For the
362*f2a19305Safresh1C<atanh>, C<acoth>, the argument cannot be C<-1> (minus one).  For the
363*f2a19305Safresh1C<tan>, C<sec>, C<tanh>, C<sech>, the argument cannot be I<pi/2 + k *
364*f2a19305Safresh1pi>, where I<k> is any integer.
365*f2a19305Safresh1
366*f2a19305Safresh1Note that atan2(0, 0) is not well-defined.
367*f2a19305Safresh1
368*f2a19305Safresh1=head2 SIMPLE (REAL) ARGUMENTS, COMPLEX RESULTS
369*f2a19305Safresh1
370*f2a19305Safresh1Please note that some of the trigonometric functions can break out
371*f2a19305Safresh1from the B<real axis> into the B<complex plane>. For example
372*f2a19305Safresh1C<asin(2)> has no definition for plain real numbers but it has
373*f2a19305Safresh1definition for complex numbers.
374*f2a19305Safresh1
375*f2a19305Safresh1In Perl terms this means that supplying the usual Perl numbers (also
376*f2a19305Safresh1known as scalars, please see L<perldata>) as input for the
377*f2a19305Safresh1trigonometric functions might produce as output results that no more
378*f2a19305Safresh1are simple real numbers: instead they are complex numbers.
379*f2a19305Safresh1
380*f2a19305Safresh1The C<Math::Trig> handles this by using the C<Math::Complex> package
381*f2a19305Safresh1which knows how to handle complex numbers, please see L<Math::Complex>
382*f2a19305Safresh1for more information. In practice you need not to worry about getting
383*f2a19305Safresh1complex numbers as results because the C<Math::Complex> takes care of
384*f2a19305Safresh1details like for example how to display complex numbers. For example:
385*f2a19305Safresh1
386*f2a19305Safresh1    print asin(2), "\n";
387*f2a19305Safresh1
388*f2a19305Safresh1should produce something like this (take or leave few last decimals):
389*f2a19305Safresh1
390*f2a19305Safresh1    1.5707963267949-1.31695789692482i
391*f2a19305Safresh1
392*f2a19305Safresh1That is, a complex number with the real part of approximately C<1.571>
393*f2a19305Safresh1and the imaginary part of approximately C<-1.317>.
394*f2a19305Safresh1
395*f2a19305Safresh1=head1 PLANE ANGLE CONVERSIONS
396*f2a19305Safresh1
397*f2a19305Safresh1(Plane, 2-dimensional) angles may be converted with the following functions.
398*f2a19305Safresh1
399*f2a19305Safresh1=over
400*f2a19305Safresh1
401*f2a19305Safresh1=item deg2rad
402*f2a19305Safresh1
403*f2a19305Safresh1    $radians  = deg2rad($degrees);
404*f2a19305Safresh1
405*f2a19305Safresh1=item grad2rad
406*f2a19305Safresh1
407*f2a19305Safresh1    $radians  = grad2rad($gradians);
408*f2a19305Safresh1
409*f2a19305Safresh1=item rad2deg
410*f2a19305Safresh1
411*f2a19305Safresh1    $degrees  = rad2deg($radians);
412*f2a19305Safresh1
413*f2a19305Safresh1=item grad2deg
414*f2a19305Safresh1
415*f2a19305Safresh1    $degrees  = grad2deg($gradians);
416*f2a19305Safresh1
417*f2a19305Safresh1=item deg2grad
418*f2a19305Safresh1
419*f2a19305Safresh1    $gradians = deg2grad($degrees);
420*f2a19305Safresh1
421*f2a19305Safresh1=item rad2grad
422*f2a19305Safresh1
423*f2a19305Safresh1    $gradians = rad2grad($radians);
424*f2a19305Safresh1
425*f2a19305Safresh1=back
426*f2a19305Safresh1
427*f2a19305Safresh1The full circle is 2 I<pi> radians or I<360> degrees or I<400> gradians.
428*f2a19305Safresh1The result is by default wrapped to be inside the [0, {2pi,360,400}] circle.
429*f2a19305Safresh1If you don't want this, supply a true second argument:
430*f2a19305Safresh1
431*f2a19305Safresh1    $zillions_of_radians  = deg2rad($zillions_of_degrees, 1);
432*f2a19305Safresh1    $negative_degrees     = rad2deg($negative_radians, 1);
433*f2a19305Safresh1
434*f2a19305Safresh1You can also do the wrapping explicitly by rad2rad(), deg2deg(), and
435*f2a19305Safresh1grad2grad().
436*f2a19305Safresh1
437*f2a19305Safresh1=over 4
438*f2a19305Safresh1
439*f2a19305Safresh1=item rad2rad
440*f2a19305Safresh1
441*f2a19305Safresh1    $radians_wrapped_by_2pi = rad2rad($radians);
442*f2a19305Safresh1
443*f2a19305Safresh1=item deg2deg
444*f2a19305Safresh1
445*f2a19305Safresh1    $degrees_wrapped_by_360 = deg2deg($degrees);
446*f2a19305Safresh1
447*f2a19305Safresh1=item grad2grad
448*f2a19305Safresh1
449*f2a19305Safresh1    $gradians_wrapped_by_400 = grad2grad($gradians);
450*f2a19305Safresh1
451*f2a19305Safresh1=back
452*f2a19305Safresh1
453*f2a19305Safresh1=head1 RADIAL COORDINATE CONVERSIONS
454*f2a19305Safresh1
455*f2a19305Safresh1B<Radial coordinate systems> are the B<spherical> and the B<cylindrical>
456*f2a19305Safresh1systems, explained shortly in more detail.
457*f2a19305Safresh1
458*f2a19305Safresh1You can import radial coordinate conversion functions by using the
459*f2a19305Safresh1C<:radial> tag:
460*f2a19305Safresh1
461*f2a19305Safresh1    use Math::Trig ':radial';
462*f2a19305Safresh1
463*f2a19305Safresh1    ($rho, $theta, $z)     = cartesian_to_cylindrical($x, $y, $z);
464*f2a19305Safresh1    ($rho, $theta, $phi)   = cartesian_to_spherical($x, $y, $z);
465*f2a19305Safresh1    ($x, $y, $z)           = cylindrical_to_cartesian($rho, $theta, $z);
466*f2a19305Safresh1    ($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);
467*f2a19305Safresh1    ($x, $y, $z)           = spherical_to_cartesian($rho, $theta, $phi);
468*f2a19305Safresh1    ($rho_c, $theta, $z)   = spherical_to_cylindrical($rho_s, $theta, $phi);
469*f2a19305Safresh1
470*f2a19305Safresh1B<All angles are in radians>.
471*f2a19305Safresh1
472*f2a19305Safresh1=head2 COORDINATE SYSTEMS
473*f2a19305Safresh1
474*f2a19305Safresh1B<Cartesian> coordinates are the usual rectangular I<(x, y, z)>-coordinates.
475*f2a19305Safresh1
476*f2a19305Safresh1Spherical coordinates, I<(rho, theta, phi)>, are three-dimensional
477*f2a19305Safresh1coordinates which define a point in three-dimensional space.  They are
478*f2a19305Safresh1based on a sphere surface.  The radius of the sphere is B<rho>, also
479*f2a19305Safresh1known as the I<radial> coordinate.  The angle in the I<xy>-plane
480*f2a19305Safresh1(around the I<z>-axis) is B<theta>, also known as the I<azimuthal>
481*f2a19305Safresh1coordinate.  The angle from the I<z>-axis is B<phi>, also known as the
482*f2a19305Safresh1I<polar> coordinate.  The North Pole is therefore I<rho, 0, 0>, and
483*f2a19305Safresh1the Gulf of Guinea (think of the missing big chunk of Africa) I<rho,
484*f2a19305Safresh10, pi/2>.  In geographical terms I<phi> is latitude (northward
485*f2a19305Safresh1positive, southward negative) and I<theta> is longitude (eastward
486*f2a19305Safresh1positive, westward negative).
487*f2a19305Safresh1
488*f2a19305Safresh1B<BEWARE>: some texts define I<theta> and I<phi> the other way round,
489*f2a19305Safresh1some texts define the I<phi> to start from the horizontal plane, some
490*f2a19305Safresh1texts use I<r> in place of I<rho>.
491*f2a19305Safresh1
492*f2a19305Safresh1Cylindrical coordinates, I<(rho, theta, z)>, are three-dimensional
493*f2a19305Safresh1coordinates which define a point in three-dimensional space.  They are
494*f2a19305Safresh1based on a cylinder surface.  The radius of the cylinder is B<rho>,
495*f2a19305Safresh1also known as the I<radial> coordinate.  The angle in the I<xy>-plane
496*f2a19305Safresh1(around the I<z>-axis) is B<theta>, also known as the I<azimuthal>
497*f2a19305Safresh1coordinate.  The third coordinate is the I<z>, pointing up from the
498*f2a19305Safresh1B<theta>-plane.
499*f2a19305Safresh1
500*f2a19305Safresh1=head2 3-D ANGLE CONVERSIONS
501*f2a19305Safresh1
502*f2a19305Safresh1Conversions to and from spherical and cylindrical coordinates are
503*f2a19305Safresh1available.  Please notice that the conversions are not necessarily
504*f2a19305Safresh1reversible because of the equalities like I<pi> angles being equal to
505*f2a19305Safresh1I<-pi> angles.
506*f2a19305Safresh1
507*f2a19305Safresh1=over 4
508*f2a19305Safresh1
509*f2a19305Safresh1=item cartesian_to_cylindrical
510*f2a19305Safresh1
511*f2a19305Safresh1    ($rho, $theta, $z) = cartesian_to_cylindrical($x, $y, $z);
512*f2a19305Safresh1
513*f2a19305Safresh1=item cartesian_to_spherical
514*f2a19305Safresh1
515*f2a19305Safresh1    ($rho, $theta, $phi) = cartesian_to_spherical($x, $y, $z);
516*f2a19305Safresh1
517*f2a19305Safresh1=item cylindrical_to_cartesian
518*f2a19305Safresh1
519*f2a19305Safresh1    ($x, $y, $z) = cylindrical_to_cartesian($rho, $theta, $z);
520*f2a19305Safresh1
521*f2a19305Safresh1=item cylindrical_to_spherical
522*f2a19305Safresh1
523*f2a19305Safresh1    ($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);
524*f2a19305Safresh1
525*f2a19305Safresh1Notice that when C<$z> is not 0 C<$rho_s> is not equal to C<$rho_c>.
526*f2a19305Safresh1
527*f2a19305Safresh1=item spherical_to_cartesian
528*f2a19305Safresh1
529*f2a19305Safresh1    ($x, $y, $z) = spherical_to_cartesian($rho, $theta, $phi);
530*f2a19305Safresh1
531*f2a19305Safresh1=item spherical_to_cylindrical
532*f2a19305Safresh1
533*f2a19305Safresh1    ($rho_c, $theta, $z) = spherical_to_cylindrical($rho_s, $theta, $phi);
534*f2a19305Safresh1
535*f2a19305Safresh1Notice that when C<$z> is not 0 C<$rho_c> is not equal to C<$rho_s>.
536*f2a19305Safresh1
537*f2a19305Safresh1=back
538*f2a19305Safresh1
539*f2a19305Safresh1=head1 GREAT CIRCLE DISTANCES AND DIRECTIONS
540*f2a19305Safresh1
541*f2a19305Safresh1A great circle is section of a circle that contains the circle
542*f2a19305Safresh1diameter: the shortest distance between two (non-antipodal) points on
543*f2a19305Safresh1the spherical surface goes along the great circle connecting those two
544*f2a19305Safresh1points.
545*f2a19305Safresh1
546*f2a19305Safresh1=head2 great_circle_distance
547*f2a19305Safresh1
548*f2a19305Safresh1Returns the great circle distance between two points on a sphere.
549*f2a19305Safresh1
550*f2a19305Safresh1    $distance = great_circle_distance($theta0, $phi0, $theta1, $phi1, [, $rho]);
551*f2a19305Safresh1
552*f2a19305Safresh1Where ($theta0, $phi0) and ($theta1, $phi1) are the spherical coordinates of
553*f2a19305Safresh1the two points, respectively. The distance is in C<$rho> units. The C<$rho>
554*f2a19305Safresh1is optional. It defaults to 1 (the unit sphere).
555*f2a19305Safresh1
556*f2a19305Safresh1If you are using geographic coordinates, latitude and longitude, you need to
557*f2a19305Safresh1adjust for the fact that latitude is zero at the equator increasing towards
558*f2a19305Safresh1the north and decreasing towards the south. Assuming ($lat0, $lon0) and
559*f2a19305Safresh1($lat1, $lon1) are the geographic coordinates in radians of the two points,
560*f2a19305Safresh1the distance can be computed with
561*f2a19305Safresh1
562*f2a19305Safresh1  $distance = great_circle_distance($lon0, pi/2 - $lat0,
563*f2a19305Safresh1                                    $lon1, pi/2 - $lat1, $rho);
564*f2a19305Safresh1
565*f2a19305Safresh1=head2 great_circle_direction
566*f2a19305Safresh1
567*f2a19305Safresh1The direction you must follow the great circle (also known as I<bearing>)
568*f2a19305Safresh1can be computed by the great_circle_direction() function:
569*f2a19305Safresh1
570*f2a19305Safresh1  use Math::Trig 'great_circle_direction';
571*f2a19305Safresh1
572*f2a19305Safresh1  $direction = great_circle_direction($theta0, $phi0, $theta1, $phi1);
573*f2a19305Safresh1
574*f2a19305Safresh1=head2 great_circle_bearing
575*f2a19305Safresh1
576*f2a19305Safresh1Alias 'great_circle_bearing' for 'great_circle_direction' is also available.
577*f2a19305Safresh1
578*f2a19305Safresh1  use Math::Trig 'great_circle_bearing';
579*f2a19305Safresh1
580*f2a19305Safresh1  $direction = great_circle_bearing($theta0, $phi0, $theta1, $phi1);
581*f2a19305Safresh1
582*f2a19305Safresh1The result of great_circle_direction is in radians, zero indicating
583*f2a19305Safresh1straight north, pi or -pi straight south, pi/2 straight west, and
584*f2a19305Safresh1-pi/2 straight east.
585*f2a19305Safresh1
586*f2a19305Safresh1=head2 great_circle_destination
587*f2a19305Safresh1
588*f2a19305Safresh1You can inversely compute the destination if you know the
589*f2a19305Safresh1starting point, direction, and distance:
590*f2a19305Safresh1
591*f2a19305Safresh1  use Math::Trig 'great_circle_destination';
592*f2a19305Safresh1
593*f2a19305Safresh1  # $diro is the original direction,
594*f2a19305Safresh1  # for example from great_circle_bearing().
595*f2a19305Safresh1  # $distance is the angular distance in radians,
596*f2a19305Safresh1  # for example from great_circle_distance().
597*f2a19305Safresh1  # $thetad and $phid are the destination coordinates,
598*f2a19305Safresh1  # $dird is the final direction at the destination.
599*f2a19305Safresh1
600*f2a19305Safresh1  ($thetad, $phid, $dird) =
601*f2a19305Safresh1    great_circle_destination($theta, $phi, $diro, $distance);
602*f2a19305Safresh1
603*f2a19305Safresh1or the midpoint if you know the end points:
604*f2a19305Safresh1
605*f2a19305Safresh1=head2 great_circle_midpoint
606*f2a19305Safresh1
607*f2a19305Safresh1  use Math::Trig 'great_circle_midpoint';
608*f2a19305Safresh1
609*f2a19305Safresh1  ($thetam, $phim) =
610*f2a19305Safresh1    great_circle_midpoint($theta0, $phi0, $theta1, $phi1);
611*f2a19305Safresh1
612*f2a19305Safresh1The great_circle_midpoint() is just a special case of
613*f2a19305Safresh1
614*f2a19305Safresh1=head2 great_circle_waypoint
615*f2a19305Safresh1
616*f2a19305Safresh1  use Math::Trig 'great_circle_waypoint';
617*f2a19305Safresh1
618*f2a19305Safresh1  ($thetai, $phii) =
619*f2a19305Safresh1    great_circle_waypoint($theta0, $phi0, $theta1, $phi1, $way);
620*f2a19305Safresh1
621*f2a19305Safresh1Where $way indicates the position of the waypoint along the great
622*f2a19305Safresh1circle arc through the starting point ($theta0, $phi0) and the end
623*f2a19305Safresh1point ($theta1, $phi1) relative to the distance from the starting
624*f2a19305Safresh1point to the end point. So $way = 0 gives the starting point, $way = 1
625*f2a19305Safresh1gives the end point, $way < 0 gives a point "behind" the starting
626*f2a19305Safresh1point, and $way > 1 gives a point beyond the end point. $way defaults
627*f2a19305Safresh1to 0.5 if not given.
628*f2a19305Safresh1
629*f2a19305Safresh1Note that antipodal points (where their distance is I<pi> radians) do
630*f2a19305Safresh1not have unique waypoints between them, and therefore C<undef> is
631*f2a19305Safresh1returned in such cases.  If the points are the same, so the distance
632*f2a19305Safresh1between them is zero, all waypoints are identical to the starting/end
633*f2a19305Safresh1point.
634*f2a19305Safresh1
635*f2a19305Safresh1The thetas, phis, direction, and distance in the above are all in
636*f2a19305Safresh1radians.
637*f2a19305Safresh1
638*f2a19305Safresh1You can import all the great circle formulas by
639*f2a19305Safresh1
640*f2a19305Safresh1  use Math::Trig ':great_circle';
641*f2a19305Safresh1
642*f2a19305Safresh1Notice that the resulting directions might be somewhat surprising if
643*f2a19305Safresh1you are looking at a flat worldmap: in such map projections the great
644*f2a19305Safresh1circles quite often do not look like the shortest routes --  but for
645*f2a19305Safresh1example the shortest possible routes from Europe or North America to
646*f2a19305Safresh1Asia do often cross the polar regions.  (The common Mercator projection
647*f2a19305Safresh1does B<not> show great circles as straight lines: straight lines in the
648*f2a19305Safresh1Mercator projection are lines of constant bearing.)
649*f2a19305Safresh1
650*f2a19305Safresh1=head1 EXAMPLES
651*f2a19305Safresh1
652*f2a19305Safresh1To calculate the distance between London (51.3N 0.5W) and Tokyo
653*f2a19305Safresh1(35.7N 139.8E) in kilometers:
654*f2a19305Safresh1
655*f2a19305Safresh1    use Math::Trig qw(great_circle_distance deg2rad);
656*f2a19305Safresh1
657*f2a19305Safresh1    # Notice the 90 - latitude: phi zero is at the North Pole.
658*f2a19305Safresh1    sub NESW { deg2rad($_[0]), deg2rad(90 - $_[1]) }
659*f2a19305Safresh1    my @L = NESW( -0.5, 51.3);
660*f2a19305Safresh1    my @T = NESW(139.8, 35.7);
661*f2a19305Safresh1    my $km = great_circle_distance(@L, @T, 6378); # About 9600 km.
662*f2a19305Safresh1
663*f2a19305Safresh1The direction you would have to go from London to Tokyo (in radians,
664*f2a19305Safresh1straight north being zero, straight east being pi/2).
665*f2a19305Safresh1
666*f2a19305Safresh1    use Math::Trig qw(great_circle_direction);
667*f2a19305Safresh1
668*f2a19305Safresh1    my $rad = great_circle_direction(@L, @T); # About 0.547 or 0.174 pi.
669*f2a19305Safresh1
670*f2a19305Safresh1The midpoint between London and Tokyo being
671*f2a19305Safresh1
672*f2a19305Safresh1    use Math::Trig qw(great_circle_midpoint rad2deg);
673*f2a19305Safresh1
674*f2a19305Safresh1    my @M = great_circle_midpoint(@L, @T);
675*f2a19305Safresh1    sub SWNE { rad2deg( $_[0] ), 90 - rad2deg( $_[1] ) }
676*f2a19305Safresh1    my @lonlat = SWNE(@M);
677*f2a19305Safresh1
678*f2a19305Safresh1or about 69 N 89 E, on the Putorana Plateau of Siberia.
679*f2a19305Safresh1
680*f2a19305Safresh1B<NOTE>: you B<cannot> get from A to B like this:
681*f2a19305Safresh1
682*f2a19305Safresh1   Dist = great_circle_distance(A, B)
683*f2a19305Safresh1   Dir  = great_circle_direction(A, B)
684*f2a19305Safresh1   C    = great_circle_destination(A, Dist, Dir)
685*f2a19305Safresh1
686*f2a19305Safresh1and expect C to be B, because the bearing constantly changes when
687*f2a19305Safresh1going from A to B (except in some special case like the meridians or
688*f2a19305Safresh1the circles of latitudes) and in great_circle_destination() one gives
689*f2a19305Safresh1a B<constant> bearing to follow.
690*f2a19305Safresh1
691*f2a19305Safresh1=head2 CAVEAT FOR GREAT CIRCLE FORMULAS
692*f2a19305Safresh1
693*f2a19305Safresh1The answers may be off by few percentages because of the irregular
694*f2a19305Safresh1(slightly aspherical) form of the Earth.  The errors are at worst
695*f2a19305Safresh1about 0.55%, but generally below 0.3%.
696*f2a19305Safresh1
697*f2a19305Safresh1=head2 Real-valued asin and acos
698*f2a19305Safresh1
699*f2a19305Safresh1For small inputs asin() and acos() may return complex numbers even
700*f2a19305Safresh1when real numbers would be enough and correct, this happens because of
701*f2a19305Safresh1floating-point inaccuracies.  You can see these inaccuracies for
702*f2a19305Safresh1example by trying theses:
703*f2a19305Safresh1
704*f2a19305Safresh1  print cos(1e-6)**2+sin(1e-6)**2 - 1,"\n";
705*f2a19305Safresh1  printf "%.20f", cos(1e-6)**2+sin(1e-6)**2,"\n";
706*f2a19305Safresh1
707*f2a19305Safresh1which will print something like this
708*f2a19305Safresh1
709*f2a19305Safresh1  -1.11022302462516e-16
710*f2a19305Safresh1  0.99999999999999988898
711*f2a19305Safresh1
712*f2a19305Safresh1even though the expected results are of course exactly zero and one.
713*f2a19305Safresh1The formulas used to compute asin() and acos() are quite sensitive to
714*f2a19305Safresh1this, and therefore they might accidentally slip into the complex
715*f2a19305Safresh1plane even when they should not.  To counter this there are two
716*f2a19305Safresh1interfaces that are guaranteed to return a real-valued output.
717*f2a19305Safresh1
718*f2a19305Safresh1=over 4
719*f2a19305Safresh1
720*f2a19305Safresh1=item asin_real
721*f2a19305Safresh1
722*f2a19305Safresh1    use Math::Trig qw(asin_real);
723*f2a19305Safresh1
724*f2a19305Safresh1    $real_angle = asin_real($input_sin);
725*f2a19305Safresh1
726*f2a19305Safresh1Return a real-valued arcus sine if the input is between [-1, 1],
727*f2a19305Safresh1B<inclusive> the endpoints.  For inputs greater than one, pi/2
728*f2a19305Safresh1is returned.  For inputs less than minus one, -pi/2 is returned.
729*f2a19305Safresh1
730*f2a19305Safresh1=item acos_real
731*f2a19305Safresh1
732*f2a19305Safresh1    use Math::Trig qw(acos_real);
733*f2a19305Safresh1
734*f2a19305Safresh1    $real_angle = acos_real($input_cos);
735*f2a19305Safresh1
736*f2a19305Safresh1Return a real-valued arcus cosine if the input is between [-1, 1],
737*f2a19305Safresh1B<inclusive> the endpoints.  For inputs greater than one, zero
738*f2a19305Safresh1is returned.  For inputs less than minus one, pi is returned.
739*f2a19305Safresh1
740*f2a19305Safresh1=back
741*f2a19305Safresh1
742*f2a19305Safresh1=head1 BUGS
743*f2a19305Safresh1
744*f2a19305Safresh1Saying C<use Math::Trig;> exports many mathematical routines in the
745*f2a19305Safresh1caller environment and even overrides some (C<sin>, C<cos>).  This is
746*f2a19305Safresh1construed as a feature by the Authors, actually... ;-)
747*f2a19305Safresh1
748*f2a19305Safresh1The code is not optimized for speed, especially because we use
749*f2a19305Safresh1C<Math::Complex> and thus go quite near complex numbers while doing
750*f2a19305Safresh1the computations even when the arguments are not. This, however,
751*f2a19305Safresh1cannot be completely avoided if we want things like C<asin(2)> to give
752*f2a19305Safresh1an answer instead of giving a fatal runtime error.
753*f2a19305Safresh1
754*f2a19305Safresh1Do not attempt navigation using these formulas.
755*f2a19305Safresh1
756*f2a19305Safresh1=head1 SEE ALSO
757*f2a19305Safresh1
758*f2a19305Safresh1L<Math::Complex>
759*f2a19305Safresh1
760*f2a19305Safresh1=head1 AUTHORS
761*f2a19305Safresh1
762*f2a19305Safresh1Jarkko Hietaniemi <F<jhi!at!iki.fi>>,
763*f2a19305Safresh1Raphael Manfredi <F<Raphael_Manfredi!at!pobox.com>>,
764*f2a19305Safresh1Zefram <zefram@fysh.org>
765*f2a19305Safresh1
766*f2a19305Safresh1=head1 LICENSE
767*f2a19305Safresh1
768*f2a19305Safresh1This library is free software; you can redistribute it and/or modify
769*f2a19305Safresh1it under the same terms as Perl itself.
770*f2a19305Safresh1
771*f2a19305Safresh1=cut
772*f2a19305Safresh1
773*f2a19305Safresh1# eof
774