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